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);
341struct LegacyInterpolationDefault {
342 bool allowed =
false;
346int interpolationCode(
const JSONNode &
modifier,
const std::optional<Interpolation> &defaultInterpolation,
347 InterpolationClass interpolationClass,
const std::string &context,
348 LegacyInterpolationDefault &legacyDefault)
350 const auto toCode = [&](
const Interpolation &interpolation) {
351 return codeFromInterpolation(interpolation, interpolationClass, context);
354 if (
const auto *interpolationNode =
modifier.find(
"interpolation")) {
355 if (interpolationNode->is_map()) {
356 return toCode(readInterpolation(*interpolationNode, context));
358 const int legacyCode = readLegacyInterpolationCode(*interpolationNode, context);
359 const Interpolation interpolation = interpolationFromCode(legacyCode, interpolationClass, context);
360 return toCode(interpolation);
362 if (defaultInterpolation) {
363 return toCode(*defaultInterpolation);
367 if (!legacyDefault.allowed) {
374 if (!legacyDefault.warned) {
376 " is not given, and the channel has no \"default_interpolation\". Using the "
377 "implicit default of older RooFit versions (code 4), which is deprecated.");
378 legacyDefault.warned =
true;
383void erasePrefix(std::string &str, std::string_view prefix)
386 str.erase(0, prefix.size());
390bool eraseSuffix(std::string &str, std::string_view suffix)
393 str.erase(str.size() - suffix.size());
401void sortByName(Coll &coll)
403 std::sort(coll.begin(), coll.end(), [](
auto &
l,
auto &
r) { return l.name < r.name; });
409 for (
const auto &client :
gamma->clients()) {
410 if (
auto casted =
dynamic_cast<T *
>(client)) {
413 T *
c = findClient<T>(client);
425 if (
auto *constraint = findClient<RooPoisson>(
g))
427 if (
auto *constraint = findClient<RooGaussian>(
g))
429 return findClient<RooLognormal>(
g);
432inline std::string defaultGammaName(std::string
const &sysname, std::size_t i)
434 return "gamma_" + sysname +
"_bin_" + std::to_string(i);
438void exportGammaParameters(
JSONNode &mod, std::vector<RooAbsReal *>
const ¶ms)
440 std::vector<std::string> paramNames;
442 paramNames.emplace_back(param->GetName());
444 mod[
"parameters"].
fill_seq(paramNames);
447RooRealVar &createNominal(
RooWorkspace &ws, std::string
const &parname,
double val,
double min,
double max)
449 RooRealVar &nom = getOrCreate<RooRealVar>(ws,
"nom_" + parname, val, min, max);
456std::string constraintName(std::string
const ¶mName)
458 return paramName +
"Constraint";
461bool isLegacyConstraintType(std::string
const &
value)
469 if (
auto *constraint = tool.
workspace()->
pdf(constraintName)) {
476 if (err.
child() != constraintName) {
485 std::string
const &constraintType)
487 if (constraintType ==
"Gauss") {
489 return getOrCreate<RooGaussian>(*tool.
workspace(), constraintName(param.
GetName()), param,
495 "' is a known constraint type, but it cannot be resolved in this context");
498ParamHistFunc &createPHF(
const std::string &phfname, std::string
const &sysname,
499 const std::vector<std::string> &parnames,
const std::vector<double> &vals,
501 const std::string &constraintType,
double gammaMin,
double gammaMax,
double minSigma,
502 bool createConstraints =
true)
506 size_t n = std::max(vals.size(), parnames.size());
508 for (std::size_t i = 0; i <
n; ++i) {
509 const std::string
name = parnames.empty() ? defaultGammaName(sysname, i) : parnames[i];
514 gammas.
add(getOrCreate<RooRealVar>(ws,
name, 1., gammaMin, gammaMax));
519 if (vals.size() > 0) {
520 if (!createConstraints) {
522 }
else if (constraintType !=
"Const") {
523 if (constraintType ==
"LogNormal" || constraintType ==
"Lognormal") {
525 "' for the gamma parameters of '" + sysname +
526 "', supported are \"Poisson\" and \"Gauss\"");
530 for (
auto const &term : constraintsInfo.constraints) {
532 constraints.
add(*ws.
pdf(term->GetName()));
536 gamma->setConstant(
true);
548 for (
const auto &mod : comp[
"modifiers"].children()) {
549 if (mod[
"type"].val() == ::Literals::staterror)
559 JSONNode const *constrName = mod.
find(
"constraint_name");
561 auto constraint_name = constrName->
val();
562 auto constraint = findNamedConstraint(tool, constraint_name, sample);
567 if (
auto gauss =
dynamic_cast<RooGaussian *const
>(constraint)) {
568 param.
setError(gauss->getSigma().getVal());
573 if (
auto constr = mod.
find(
"constraint")) {
574 std::string constraintValue = constr->val();
575 if (
auto *constraint = findNamedConstraint(tool, constraintValue, sample)) {
576 if (
auto gauss =
dynamic_cast<RooGaussian *const
>(constraint)) {
577 param.
setError(gauss->getSigma().getVal());
582 if (isLegacyConstraintType(constraintValue)) {
583 return createLegacyConstraint(tool, mod, param, constraintValue);
588 "': this looks like a legacy workspace where the 'constraint' field is neither a "
589 "constraint pdf name nor a supported legacy constraint type");
592 std::string constraint_type =
"Gauss";
593 if (
auto constrType = mod.
find(
"constraint_type")) {
594 constraint_type = constrType->val();
596 if (isLegacyConstraintType(constraint_type)) {
597 return createLegacyConstraint(tool, mod, param, constraint_type);
601bool hasConstraint(
const JSONNode &mod)
609 std::string
const &sample,
bool &warnedUnconstrained,
RooArgSet &constraints)
612 if (!warnedUnconstrained) {
614 "' has no constraint, so its parameter '" + param.
GetName() +
615 "' is unconstrained. Older RooFit versions implied a unit Gaussian. Other "
616 "modifiers of this channel are not reported.");
617 warnedUnconstrained =
true;
622 constraints.
add(getOrCreateConstraint(tool, mod, param, sample));
630 std::string(constraint.
GetName()));
638 if (
auto const *tau =
dynamic_cast<RooConstVar const *
>(arg)) {
639 return tau->getVal();
644 if (
auto const *real =
dynamic_cast<RooAbsReal const *
>(arg)) {
645 if (real->isConstant() ||
endsWith(std::string(real->GetName()),
"_tau")) {
646 return real->getVal();
652 std::string(constraint.
GetName()));
653 return std::numeric_limits<double>::quiet_NaN();
660 if (
auto constraintP =
dynamic_cast<RooPoisson const *
>(&constraint)) {
661 return 1. / std::sqrt(poissonTau(*constraintP, gamma));
663 if (
auto constraintG =
dynamic_cast<RooGaussian const *
>(&constraint)) {
664 return constraintG->getSigma().getVal() / constraintG->getMean().getVal();
667 return std::numeric_limits<double>::quiet_NaN();
672 const std::optional<Interpolation> &defaultInterpolation,
673 LegacyInterpolationDefault &legacyInterpolationDefault,
bool &warnedUnconstrained,
679 std::string prefixedName = fprefix +
"_" + sampleName;
681 std::string channelName = fprefix;
682 erasePrefix(channelName,
"model_");
684 if (!
p.has_child(
"data")) {
696 if (findStaterror(
p)) {
697 shapeElems.
add(*mcStatObject);
700 if (
p.has_child(
"modifiers")) {
702 std::vector<double> overall_low;
703 std::vector<double> overall_high;
704 std::vector<int> overall_interp;
709 std::vector<int> histoInterp;
712 for (
const auto &mod :
p[
"modifiers"].children()) {
713 std::string
const &modtype = mod[
"type"].
val();
714 std::string
const &sysname =
717 : (mod.
has_child(
"parameter") ? mod[
"parameter"].
val() :
"syst_" + std::to_string(idx));
719 if (modtype ==
"staterror") {
721 }
else if (modtype ==
"normfactor") {
723 auto *parameter = mod.
find(
"parameter");
724 RooRealVar &constrParam = getOrCreate<RooRealVar>(ws, parameter ? parameter->val() : sysname, 1., -3, 5);
726 normElems.
add(constrParam);
727 if (hasConstraint(mod)) {
729 constraints.
add(getOrCreateConstraint(tool, mod, constrParam, sampleName));
731 }
else if (modtype ==
"normsys") {
732 auto *parameter = mod.
find(
"parameter");
733 std::string parname(parameter ? parameter->val() :
"alpha_" + sysname);
734 auto &par = getOrCreate<RooRealVar>(ws, parname, 0., -5, 5);
735 overall_nps.
add(par);
736 auto &
data = mod[
"data"];
737 const std::string context =
"interpolation for normsys modifier '" + sysname +
"' in sample '" +
738 sampleName +
"' of channel '" + channelName +
"'";
739 const int interp = interpolationCode(mod, defaultInterpolation, InterpolationClass::Flexible, context,
740 legacyInterpolationDefault);
741 double low =
data[
"lo"].val_double();
742 double high =
data[
"hi"].val_double();
748 if (interp == 4 && low <= 0)
749 low = std::numeric_limits<double>::epsilon();
750 if (interp == 4 && high <= 0)
751 high = std::numeric_limits<double>::epsilon();
753 overall_low.push_back(low);
754 overall_high.push_back(high);
755 overall_interp.push_back(interp);
757 addSysConstraint(tool, mod, par, sysname, sampleName, warnedUnconstrained, constraints);
758 }
else if (modtype ==
"histosys") {
759 auto *parameter = mod.
find(
"parameter");
760 std::string parname(parameter ? parameter->val() :
"alpha_" + sysname);
761 auto &par = getOrCreate<RooRealVar>(ws, parname, 0., -5, 5);
763 auto &
data = mod[
"data"];
765 sysname +
"Low_" + prefixedName, varlist,
768 sysname +
"High_" + prefixedName, varlist,
770 const std::string context =
"interpolation for histosys modifier '" + sysname +
"' in sample '" +
771 sampleName +
"' of channel '" + channelName +
"'";
772 histoInterp.push_back(interpolationCode(mod, defaultInterpolation, InterpolationClass::Piecewise, context,
773 legacyInterpolationDefault));
774 addSysConstraint(tool, mod, par, sysname, sampleName, warnedUnconstrained, constraints);
775 }
else if (modtype ==
"shapesys" || modtype ==
"shapefactor") {
776 std::string funcName = channelName +
"_" + sysname +
"_ShapeSys";
778 std::vector<double> vals;
779 if (mod[
"data"].has_child(
"vals")) {
780 for (
const auto &
v : mod[
"data"][
"vals"].children()) {
781 vals.push_back(
v.val_double());
784 std::vector<std::string> parnames;
785 for (
const auto &
v : mod[
"parameters"].children()) {
786 parnames.push_back(
v.val());
788 if (vals.empty() && parnames.empty()) {
790 "' with neither values nor parameters!");
792 std::string constraint =
"unknown";
793 std::vector<RooAbsPdf *> constraintPdfs;
794 bool const hasConstraintList = mod.
has_child(
"constraints");
795 if (hasConstraintList) {
796 for (
const auto &
v : mod[
"constraints"].children()) {
798 constraintPdfs.push_back(
nullptr);
800 std::string constraintName =
v.val();
801 auto *constraintPdf = findNamedConstraint(tool, constraintName, sampleName);
802 if (!constraintPdf) {
806 constraintPdfs.push_back(constraintPdf);
809 std::size_t
const nGammas = std::max(vals.size(), parnames.size());
810 if (constraintPdfs.size() != nGammas) {
811 std::stringstream ss;
813 <<
" constraints, but " << nGammas <<
" parameters";
816 }
else if (mod.
has_child(
"constraint_type")) {
817 constraint = mod[
"constraint_type"].
val();
818 }
else if (mod.
has_child(
"constraint")) {
819 std::string constraintValue = mod[
"constraint"].
val();
820 if (isLegacyConstraintType(constraintValue)) {
821 constraint = constraintValue;
825 "': this looks like a legacy workspace where the 'constraint' field is "
826 "not a supported legacy constraint type");
829 shapeElems.
add(createPHF(funcName, sysname, parnames, vals, tool, constraints, varlist, constraint,
831 !hasConstraintList));
832 for (
auto *constraintPdf : constraintPdfs) {
834 constraints.
add(*constraintPdf);
837 }
else if (modtype ==
"custom") {
843 shapeElems.
add(*obj);
852 std::string interpName = sampleName +
"_" + channelName +
"_epsilon";
853 if (!overall_nps.
empty()) {
855 overall_high, overall_interp);
858 if (!histNps.
empty()) {
869 if (!normElems.
empty()) {
872 ws.
factory(
"RooConstVar::" + prefixedName +
"_scaleFactors(1.)");
883 if (!
p.has_child(
"samples")) {
886 double statErrThresh = 0;
887 std::string statErrType =
"Poisson";
888 std::optional<Interpolation> defaultInterpolation;
889 if (
p.has_child(
"default_interpolation")) {
890 defaultInterpolation =
891 readInterpolation(
p[
"default_interpolation"],
"default_interpolation of channel '" +
name +
"'");
893 if (
p.has_child(::Literals::staterror)) {
894 auto &staterr =
p[::Literals::staterror];
895 if (staterr.has_child(
"relThreshold"))
896 statErrThresh = staterr[
"relThreshold"].val_double();
897 if (staterr.has_child(
"constraint_type"))
898 statErrType = staterr[
"constraint_type"].val();
900 std::vector<double> sumW;
901 std::vector<double> sumW2;
902 std::vector<std::string> gammaParnames;
903 std::string modifierStatErrType;
906 std::string fprefix =
name;
908 std::vector<std::unique_ptr<RooDataHist>>
data;
909 for (
const auto &comp :
p[
"samples"].children()) {
912 size_t nbins = dh->numEntries();
914 if (
const JSONNode *staterror = findStaterror(comp)) {
919 for (
size_t i = 0; i < nbins; ++i) {
920 sumW[i] += dh->weight(i);
921 sumW2[i] += dh->weightSquared(i);
923 if (gammaParnames.empty()) {
924 if (
auto staterrorParams = staterror->find(
"parameters")) {
925 for (
const auto &
v : staterrorParams->children()) {
926 gammaParnames.push_back(
v.val());
931 if (modifierStatErrType.empty()) {
933 auto constraint = staterror->find(
"constraint");
935 constraint = staterror->find(
"constraint_type");
938 modifierStatErrType = constraint->val();
939 if (modifierStatErrType !=
"Poisson" && modifierStatErrType !=
"Gauss") {
941 "' of the staterror modifier in channel '" +
name +
942 "', supported are \"Poisson\" and \"Gauss\"");
947 data.emplace_back(std::move(dh));
950 if (!modifierStatErrType.empty()) {
951 statErrType = modifierStatErrType;
957 std::string channelName =
name;
958 erasePrefix(channelName,
"model_");
960 std::vector<double> errs(sumW.size());
961 for (
size_t i = 0; i < sumW.size(); ++i) {
966 errs[i] = std::sqrt(sumW2[i]) / sumW[i];
968 errs[i] = std::max(errs[i], 0.);
972 &createPHF(
"mc_stat_" + channelName,
"stat_" + channelName, gammaParnames, errs, *tool, constraints,
976 LegacyInterpolationDefault legacyInterpolationDefault;
978 bool warnedUnconstrained =
false;
983 for (
const auto &comp :
p[
"samples"].children()) {
984 importHistSample(*tool, *
data[idx], observables, mcStatObject, fprefix, comp, defaultInterpolation,
985 legacyInterpolationDefault, warnedUnconstrained, constraints);
993 if (constraints.
empty()) {
996 std::string sumName =
name +
"_model";
997 erasePrefix(sumName,
"model_");
1008 std::string
const &key()
const override
1010 static const std::string keystring =
"interpolation0d";
1017 if (fip->low().size() != nParameters || fip->high().size() != nParameters ||
1018 fip->interpolationCodes().size() != nParameters) {
1020 "' has non-matching parameter, variation, and interpolation lengths");
1022 elem[
"type"] << key();
1023 writeInterpolations(elem[
"interpolations"], fip->interpolationCodes(), InterpolationClass::Flexible,
1024 "FlexibleInterpVar '" + std::string{fip->GetName()} +
"'");
1026 elem[
"nom"] << fip->nominal();
1027 elem[
"high"].
fill_seq(fip->high(), fip->variables().size());
1028 elem[
"low"].
fill_seq(fip->low(), fip->variables().size());
1035 std::string
const &key()
const override
1037 static const std::string keystring =
"interpolation";
1047 "' has non-matching parameter, variation, and interpolation lengths");
1049 elem[
"type"] << key();
1050 writeInterpolations(elem[
"interpolations"], pip->
interpolationCodes(), InterpolationClass::Piecewise,
1051 "PiecewiseInterpolation '" + std::string{pip->GetName()} +
"'");
1070 if (vars.size() != low.size() || vars.size() != high.size()) {
1072 "' has non-matching lengths of 'vars', 'high' and 'low'");
1074 const std::vector<int> codes =
1075 readInterpolations(
p, vars.size(), InterpolationClass::Piecewise,
"PiecewiseInterpolation '" +
name +
"'");
1091 if (!
p.has_child(
"high")) {
1094 if (!
p.has_child(
"low")) {
1097 if (!
p.has_child(
"nom")) {
1101 double nom(
p[
"nom"].val_double());
1105 std::vector<double> high;
1108 std::vector<double> low;
1111 if (vars.size() != low.size() || vars.size() != high.size()) {
1113 "' has non-matching lengths of 'vars', 'high' and 'low'!");
1115 const std::vector<int> codes =
1116 readInterpolations(
p, vars.size(), InterpolationClass::Flexible,
"FlexibleInterpVar '" +
name +
"'");
1129 :
name{par.
GetName()}, param{&par}, constraint{constr}
1135 std::string
name =
"";
1139 Interpolation interpolation = multiplicativePolynomialExponential;
1143 :
name(
n), param(
p), low(
l), high(
h), interpolation(std::move(i)), constraint(
c)
1151 std::vector<double> low;
1152 std::vector<double> high;
1153 Interpolation interpolation = additivePolynomialLinear;
1157 :
name(
n), param(
p), interpolation(std::move(i)), constraint(
c)
1159 low.assign(
l->dataHist().weightArray(),
l->dataHist().weightArray() +
l->dataHist().numEntries());
1160 high.assign(
h->dataHist().weightArray(),
h->dataHist().weightArray() +
h->dataHist().numEntries());
1165 std::vector<double> constraints;
1166 std::vector<RooAbsPdf const *> constraintPdfs;
1167 std::vector<RooAbsReal *> parameters;
1171struct GenericElement {
1177std::string stripOuterParens(
const std::string &s)
1180 size_t end = s.size();
1182 while (start < end && s[start] ==
'(' && s[end - 1] ==
')') {
1184 bool balanced =
true;
1185 for (
size_t i = start; i < end - 1; ++i) {
1188 else if (s[i] ==
')')
1190 if (depth == 0 && i < end - 1) {
1202 return s.substr(start, end - start);
1205std::vector<std::string> splitTopLevelProduct(
const std::string &expr)
1207 std::vector<std::string> parts;
1210 bool foundTopLevelStar =
false;
1212 for (
size_t i = 0; i < expr.size(); ++i) {
1216 }
else if (
c ==
')') {
1218 }
else if (
c ==
'*' && depth == 0) {
1219 foundTopLevelStar =
true;
1220 std::string sub = expr.substr(start, i - start);
1221 parts.push_back(stripOuterParens(sub));
1226 if (!foundTopLevelStar) {
1230 std::string sub = expr.substr(start);
1231 parts.push_back(stripOuterParens(sub));
1235NormSys parseOverallModifierFormula(
const std::string &s,
RooFormulaVar *formula)
1237 static const std::regex pattern(
1238 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*$)");
1244 if (std::regex_match(s, match, pattern)) {
1245 if (match[1].str() ==
"-") {
1249 std::string token2 = match[2].str();
1250 std::string token3 = match[4].str();
1257 auto *constr2 = findConstraint(
v2);
1258 auto *constr3 = findConstraint(
v3);
1260 if (constr2 && !p3) {
1263 sys.high = 1.0 + sign *
toDouble(token3);
1264 sys.low = 1.0 - sign *
toDouble(token3);
1265 }
else if (!p2 && constr3) {
1268 sys.high = 1.0 + sign *
toDouble(token2);
1269 sys.low = 1.0 - sign *
toDouble(token2);
1270 }
else if (constr2 && p3 && !constr3) {
1271 sys.name =
v2->GetName();
1273 sys.high = 1.0 + sign * p3->
getVal();
1274 sys.low = 1.0 - sign * p3->
getVal();
1275 }
else if (p2 && !constr2 && constr3) {
1276 sys.name =
v3->GetName();
1278 sys.high = 1.0 + sign * p2->
getVal();
1279 sys.low = 1.0 - sign * p2->
getVal();
1283 sys.constraint = constr2 ? constr2 : constr3;
1286 sys.interpolation = multiplicativePiecewiseExponential;
1288 erasePrefix(sys.name,
"alpha_");
1295 if (
auto prod =
dynamic_cast<RooProduct *
>(arg)) {
1296 for (
const auto &
e : prod->components()) {
1297 collectElements(elems,
e);
1306 for (
auto *var : list) {
1316 std::vector<double> hist;
1317 std::vector<double> histError;
1318 std::vector<NormFactor> normfactors;
1319 std::vector<NormSys> normsys;
1320 std::vector<HistoSys> histosys;
1321 std::vector<ShapeSys> shapesys;
1322 std::vector<GenericElement> tmpElements;
1323 std::vector<GenericElement> otherElements;
1324 bool useBarlowBeestonLight =
false;
1325 std::vector<RooAbsReal *> staterrorParameters;
1331 std::string parname = par->
GetName();
1332 bool isConstrained =
false;
1333 for (
RooAbsArg const *pdf : ws->allPdfs()) {
1334 if (
auto gauss =
dynamic_cast<RooGaussian const *
>(pdf)) {
1335 if (parname == gauss->getX().GetName()) {
1336 sample.normfactors.emplace_back(*par, gauss);
1337 isConstrained =
true;
1342 sample.normfactors.emplace_back(*par);
1347 std::vector<Sample> samples;
1348 std::map<int, double> tot_yield;
1349 std::map<int, double> tot_yield2;
1350 std::map<int, double> rel_errors;
1351 std::string statErrorConstraintType;
1353 long unsigned int nBins = 0;
1362 channel.name = pdfname;
1363 erasePrefix(channel.name,
"model_");
1364 eraseSuffix(channel.name,
"_model");
1366 for (
size_t sampleidx = 0; sampleidx < sumpdf->
funcList().
size(); ++sampleidx) {
1368 std::vector<ParamHistFunc *> phfs;
1370 const auto func = sumpdf->
funcList().
at(sampleidx);
1372 erasePrefix(sample.name,
"L_x_");
1373 eraseSuffix(sample.name,
"_shapes");
1374 eraseSuffix(sample.name,
"_" + channel.name);
1375 erasePrefix(sample.name, pdfname +
"_");
1377 auto updateObservables = [&](
RooDataHist const &dataHist) {
1378 if (channel.varSet ==
nullptr) {
1379 channel.varSet = dataHist.get();
1380 channel.nBins = dataHist.numEntries();
1382 if (sample.hist.empty()) {
1383 auto *
w = dataHist.weightArray();
1384 sample.hist.assign(
w,
w + dataHist.numEntries());
1387 auto processElements = [&](
const auto &elements,
auto &&self) ->
void {
1397 }
else if (
auto constVar =
dynamic_cast<RooConstVar *
>(
e)) {
1398 if (constVar->getVal() != 1.) {
1399 sample.normfactors.emplace_back(*constVar);
1401 }
else if (
auto par =
dynamic_cast<RooRealVar *
>(
e)) {
1402 addNormFactor(par, sample, ws);
1403 }
else if (
auto hf =
dynamic_cast<const RooHistFunc *
>(
e)) {
1404 updateObservables(hf->dataHist());
1406 phfs.push_back(phf);
1410 for (
size_t i = 0; i < fip->variables().size(); ++i) {
1412 std::string sysname(var->
GetName());
1413 erasePrefix(sysname,
"alpha_");
1415 const auto *constraint = findConstraint(var);
1416 const std::string context =
"normsys modifier '" + sysname +
"' in sample '" + sample.name +
1417 "' of channel '" + channel.name +
"'";
1418 sample.normsys.emplace_back(
1419 sysname, var, fip->high()[i], fip->low()[i],
1420 interpolationFromCode(fip->interpolationCodes()[i], InterpolationClass::Flexible, context),
1431 expression.ReplaceAll((
"x[" + std::to_string(i) +
"]").c_str(),
p->
GetName());
1432 expression.ReplaceAll((
"@" + std::to_string(i)).c_str(),
p->
GetName());
1434 auto components = splitTopLevelProduct(expression.Data());
1435 if (components.size() == 0) {
1437 sample.otherElements.push_back(formula);
1440 std::vector<RooAbsArg *> realComponents;
1442 for (
auto &comp : components) {
1446 realComponents.push_back(part);
1450 auto normsys = parseOverallModifierFormula(comp, formula);
1451 if (normsys.param) {
1452 sample.normsys.emplace_back(std::move(normsys));
1457 std::string
name = std::string(formula->
GetName()) +
"_part" + std::to_string(idx);
1460 sample.tmpElements.push_back({var});
1462 self(realComponents, self);
1464 }
else if (
auto real =
dynamic_cast<RooAbsReal *
>(
e)) {
1465 sample.otherElements.push_back(real);
1471 collectElements(elems, func);
1472 collectElements(elems, sumpdf->
coefList().
at(sampleidx));
1473 processElements(elems, processElements);
1478 updateObservables(nh->dataHist());
1483 sortByName(sample.normfactors);
1484 sortByName(sample.normsys);
1490 std::string sysname(var->
GetName());
1491 erasePrefix(sysname,
"alpha_");
1495 const auto *constraint = findConstraint(var);
1496 const std::string context =
"histosys modifier '" + sysname +
"' in sample '" + sample.name +
1497 "' of channel '" + channel.name +
"'";
1498 sample.histosys.emplace_back(
1499 sysname, var, lo,
hi,
1500 interpolationFromCode(pip->
interpolationCodes()[i], InterpolationClass::Piecewise, context),
1505 sortByName(sample.histosys);
1509 if (
startsWith(std::string(phf->GetName()),
"mc_stat_")) {
1511 for (
const auto &
g : phf->paramList()) {
1512 sample.staterrorParameters.push_back(
static_cast<RooRealVar *
>(
g));
1515 channel.tot_yield[idx] += sample.hist[idx - 1];
1516 channel.tot_yield2[idx] += (sample.hist[idx - 1] * sample.hist[idx - 1]);
1518 channel.rel_errors[idx] = constraintRelError(*constraint, *
g);
1519 channel.statErrorConstraintType =
dynamic_cast<RooPoisson *
>(constraint) ?
"Poisson" :
"Gauss";
1522 sample.useBarlowBeestonLight =
true;
1525 erasePrefix(sys.name, channel.name +
"_");
1526 bool isshapesys = eraseSuffix(sys.name,
"_ShapeSys") || eraseSuffix(sys.name,
"_shapeSys");
1527 bool isshapefactor = eraseSuffix(sys.name,
"_ShapeFactor") || eraseSuffix(sys.name,
"_shapeFactor");
1529 for (
const auto &
g : phf->paramList()) {
1530 sys.parameters.push_back(
static_cast<RooRealVar *
>(
g));
1533 constraint = findConstraint(
g);
1535 constraint = ws->
pdf(constraintName(
g->GetName()));
1536 if (!constraint && !
g->isConstant()) {
1539 }
else if (!isshapefactor) {
1543 sys.constraints.push_back(0.0);
1544 sys.constraintPdfs.push_back(
nullptr);
1546 sys.constraints.push_back(constraintRelError(*constraint, *
g));
1547 sys.constraintPdfs.push_back(constraint);
1550 sample.shapesys.emplace_back(std::move(sys));
1553 sortByName(sample.shapesys);
1556 channel.samples.emplace_back(std::move(sample));
1559 sortByName(channel.samples);
1571[[noreturn]]
void duplicateModifierError(
const Channel &channel,
const Sample &sample, std::string_view
type,
1572 std::string_view
name, std::string_view reason)
1574 std::stringstream ss;
1575 ss <<
"cannot combine duplicate modifier '" <<
name <<
"' of type '" <<
type <<
"' in sample '" << sample.name
1576 <<
"' of channel '" << channel.name <<
"': " << reason;
1580void warnDuplicateModifiersCombined(
const Channel &channel,
const Sample &sample, std::string_view
type,
1581 std::string_view
name, std::size_t count)
1583 std::stringstream ss;
1584 ss <<
"combined " << count <<
" duplicate modifiers named '" <<
name <<
"' of type '" <<
type <<
"' in sample '"
1585 << sample.name <<
"' of channel '" << channel.name <<
"'";
1594bool normSysSupportsMultiplicativeMerge(
const Interpolation &interpolation)
1596 return interpolation == multiplicativePiecewiseExponential || interpolation == multiplicativePolynomialExponential;
1602template <
class Modifiers,
class CombineFn>
1603void mergeDuplicateModifiers(
const Channel &channel,
const Sample &sample, Modifiers &modifiers, std::string_view
type,
1606 Modifiers mergedModifiers;
1607 mergedModifiers.reserve(modifiers.size());
1609 for (std::size_t begin = 0; begin < modifiers.size();) {
1610 std::size_t end = begin + 1;
1611 while (end < modifiers.size() && modifiers[end].name == modifiers[begin].name) {
1615 auto merged = modifiers[begin];
1616 for (std::size_t i = begin + 1; i < end; ++i) {
1617 const auto &
modifier = modifiers[i];
1618 if (!hasSameMetadata(merged.constraint,
modifier.constraint)) {
1619 duplicateModifierError(channel, sample,
type, merged.name,
"constraint metadata differs");
1621 if (!hasSameMetadata(merged.param,
modifier.param)) {
1622 duplicateModifierError(channel, sample,
type, merged.name,
"parameter metadata differs");
1624 if (merged.interpolation !=
modifier.interpolation) {
1625 duplicateModifierError(channel, sample,
type, merged.name,
"interpolation behaviours differ");
1630 if (end - begin > 1) {
1631 warnDuplicateModifiersCombined(channel, sample,
type, merged.name, end - begin);
1633 mergedModifiers.emplace_back(std::move(merged));
1637 modifiers = std::move(mergedModifiers);
1640void mergeDuplicateNormSys(
const Channel &channel,
Sample &sample)
1642 mergeDuplicateModifiers(channel, sample, sample.normsys,
"normsys", [&](NormSys &merged,
const NormSys &
modifier) {
1643 if (!normSysSupportsMultiplicativeMerge(merged.interpolation)) {
1644 duplicateModifierError(channel, sample,
"normsys", merged.name,
1645 "multiplicative combination is only valid for log-space interpolation");
1652void mergeDuplicateHistoSys(
const Channel &channel,
Sample &sample)
1654 const std::size_t nBins = sample.hist.size();
1655 mergeDuplicateModifiers(
1657 if (merged.interpolation != additivePolynomialLinear) {
1658 duplicateModifierError(channel, sample,
"histosys", merged.name,
1659 "this interpolation cannot currently be combined for duplicate histosys "
1662 if (merged.low.size() != nBins || merged.high.size() != nBins ||
modifier.low.size() != nBins ||
1664 duplicateModifierError(channel, sample,
"histosys", merged.name,
"histogram binning differs");
1666 for (std::size_t bin = 0; bin < nBins; ++bin) {
1667 merged.low[bin] +=
modifier.low[bin] - sample.hist[bin];
1668 merged.high[bin] +=
modifier.high[bin] - sample.hist[bin];
1673void ensureUniqueModifiers(
const Channel &channel,
const Sample &sample)
1675 std::set<std::pair<std::string, std::string>> seen;
1676 auto add = [&](std::string
type,
const std::string &
name) {
1677 if (!seen.emplace(
type,
name).second) {
1678 duplicateModifierError(channel, sample,
type,
name,
1679 "this modifier type cannot be combined without changing its meaning");
1683 for (
const auto &
modifier : sample.normfactors)
1685 for (
const auto &
modifier : sample.normsys)
1687 for (
const auto &
modifier : sample.histosys)
1689 for (
const auto &
modifier : sample.shapesys)
1691 for (
const auto &
modifier : sample.otherElements)
1693 for (
const auto &
modifier : sample.tmpElements)
1695 if (sample.useBarlowBeestonLight)
1696 add(::Literals::staterror, ::Literals::staterror);
1699void canonicalizeModifiers(
Channel &channel)
1701 for (
auto &sample : channel.samples) {
1702 mergeDuplicateNormSys(channel, sample);
1703 mergeDuplicateHistoSys(channel, sample);
1704 ensureUniqueModifiers(channel, sample);
1708void configureStatError(
Channel &channel)
1710 for (
auto &sample : channel.samples) {
1711 if (sample.useBarlowBeestonLight) {
1712 sample.histError.resize(sample.hist.size());
1713 for (
auto bin : channel.rel_errors) {
1716 const int i = bin.first;
1717 const double relerr_tot = bin.second;
1718 const double count = sample.hist[i - 1];
1721 sample.histError[i - 1] =
1722 round_prec(relerr_tot * channel.tot_yield[i] / std::sqrt(channel.tot_yield2[i]) * count, 7);
1728std::optional<Interpolation> defaultInterpolation(
const Channel &channel)
1730 std::map<Interpolation, std::size_t> counts;
1731 for (
const auto &sample : channel.samples) {
1732 for (
const auto &
modifier : sample.normsys) {
1735 for (
const auto &
modifier : sample.histosys) {
1739 if (counts.empty()) {
1740 return std::nullopt;
1743 auto best = counts.begin();
1744 for (
auto current = std::next(counts.begin()); current != counts.end(); ++current) {
1745 if (current->second > best->second ||
1746 (current->second == best->second && current->first == multiplicativePolynomialExponential &&
1747 best->first != multiplicativePolynomialExponential)) {
1758 auto writeConstraint = [](
JSONNode &mod,
auto const &sys) {
1759 if (sys.constraint) {
1760 mod[
"constraint"] << sys.constraint->GetName();
1766 mod[
"name"] <<
name;
1767 mod[
"type"] <<
type;
1771 elem[
"type"] <<
"histfactory_dist";
1773 if (!channel.statErrorConstraintType.empty()) {
1774 elem[::Literals::staterror].
set_map()[
"constraint_type"] << channel.statErrorConstraintType;
1776 const auto channelDefaultInterpolation = defaultInterpolation(channel);
1777 if (channelDefaultInterpolation) {
1778 writeInterpolation(elem[
"default_interpolation"], *channelDefaultInterpolation);
1781 bool observablesWritten =
false;
1782 for (
const auto &sample : channel.samples) {
1786 auto &modifiers = s[
"modifiers"];
1789 for (
const auto &nf : sample.normfactors) {
1792 mod[
"name"] << nf.name;
1793 mod[
"parameter"] << nf.param->GetName();
1794 mod[
"type"] <<
"normfactor";
1795 if (nf.constraint) {
1796 mod[
"constraint"] << nf.constraint->GetName();
1801 for (
const auto &sys : sample.normsys) {
1802 auto &mod = addModifier(modifiers, sys.name,
"normsys");
1803 mod[
"parameter"] << sys.param->GetName();
1804 if (!channelDefaultInterpolation || sys.interpolation != *channelDefaultInterpolation) {
1805 writeInterpolation(mod[
"interpolation"], sys.interpolation);
1807 writeConstraint(mod, sys);
1809 data[
"lo"] << sys.low;
1810 data[
"hi"] << sys.high;
1813 for (
const auto &sys : sample.histosys) {
1814 auto &mod = addModifier(modifiers, sys.name,
"histosys");
1815 mod[
"parameter"] << sys.param->GetName();
1816 if (!channelDefaultInterpolation || sys.interpolation != *channelDefaultInterpolation) {
1817 writeInterpolation(mod[
"interpolation"], sys.interpolation);
1819 writeConstraint(mod, sys);
1821 if (channel.nBins != sys.low.size() || channel.nBins != sys.high.size()) {
1823 " bins expected, but " + std::to_string(sys.low.size()) +
"/" +
1824 std::to_string(sys.high.size()) +
" found in nominal histogram errors!");
1830 for (
const auto &sys : sample.shapesys) {
1831 auto &mod = addModifier(modifiers, sys.name,
"shapesys");
1832 exportGammaParameters(mod, sys.parameters);
1833 if (std::any_of(sys.constraintPdfs.begin(), sys.constraintPdfs.end(),
1834 [](
auto *pdf) { return pdf != nullptr; })) {
1835 auto &constraintNames = mod[
"constraints"].
set_seq();
1836 for (
auto *constraint : sys.constraintPdfs) {
1840 constraintNames.append_child().set_null();
1847 for (
const auto &other : sample.otherElements) {
1848 addModifier(modifiers, other.name,
"custom");
1850 for (
const auto &other : sample.tmpElements) {
1851 addModifier(modifiers, other.name,
"custom");
1854 if (sample.useBarlowBeestonLight) {
1855 auto &mod = addModifier(modifiers, ::Literals::staterror, ::Literals::staterror);
1856 exportGammaParameters(mod, sample.staterrorParameters);
1857 if (!channel.statErrorConstraintType.empty()) {
1858 mod[
"constraint"] << channel.statErrorConstraintType;
1862 if (!observablesWritten) {
1863 auto &output = elem[
"axes"].
set_seq();
1867 observablesWritten =
true;
1869 auto &dataNode = s[
"data"].set_map();
1870 if (channel.nBins != sample.hist.size()) {
1872 std::to_string(sample.hist.size()) +
" found in nominal histogram!");
1875 if (!sample.histError.empty()) {
1876 if (channel.nBins != sample.histError.size()) {
1878 " bins expected, but " + std::to_string(sample.histError.size()) +
1879 " found in nominal histogram errors!");
1888std::vector<RooAbsPdf *> findLostConstraints(
const Channel &channel,
const std::vector<RooAbsPdf *> &constraints)
1891 std::set<const RooAbsReal *> vars;
1892 for (
const auto &sample : channel.samples) {
1893 for (
const auto &nf : sample.normfactors) {
1894 vars.insert(nf.param);
1896 for (
const auto &sys : sample.normsys) {
1897 vars.insert(sys.param);
1900 for (
const auto &sys : sample.histosys) {
1901 vars.insert(sys.param);
1903 for (
const auto &sys : sample.shapesys) {
1904 for (
const auto &par : sys.parameters) {
1908 if (sample.useBarlowBeestonLight) {
1909 for (
const auto &par : sample.staterrorParameters) {
1916 std::vector<RooAbsPdf *> lostConstraints;
1917 for (
auto *pdf : constraints) {
1918 bool related =
false;
1919 for (
const auto *var : vars) {
1920 if (pdf->dependsOn(*var)) {
1925 lostConstraints.push_back(pdf);
1929 return lostConstraints;
1934void checkUnconstrainedModifiers(
const Channel &channel,
const std::vector<RooAbsPdf *> &constraints)
1936 auto check = [&](
auto const &modifiers) {
1937 for (
auto const &sys : modifiers) {
1938 if (sys.constraint || sys.param->isConstant()) {
1941 if (!
dynamic_cast<RooRealVar const *
>(sys.param)) {
1943 ": functions are not supported as parameters of this modifier");
1945 for (
RooAbsPdf const *pdf : constraints) {
1946 if (pdf->dependsOn(*sys.param)) {
1948 ": the constraint term '" + pdf->GetName() +
"' is not supported");
1953 for (
const auto &sample : channel.samples) {
1954 check(sample.normsys);
1955 check(sample.histosys);
1960 std::vector<RooAbsPdf *> constraints,
JSONNode &elem)
1967 for (
RooAbsArg *sample : sumpdf->funcList()) {
1973 auto channel = readChannel(tool, pdfname, sumpdf);
1976 if (channel.samples.size() == 0)
1978 for (
auto &sample : channel.samples) {
1979 if (sample.hist.empty()) {
1984 canonicalizeModifiers(channel);
1985 checkUnconstrainedModifiers(channel, constraints);
1988 configureStatError(channel);
1990 auto lostConstraints = findLostConstraints(channel, constraints);
1992 for (
const auto *constraint : lostConstraints) {
1994 "losing constraint term '" + std::string(constraint->
GetName()) +
1995 "', implicit constraints are not supported by HS3 yet! The term will appear in the HS3 file, but will not be "
1996 "picked up when creating a likelihood from it! You will have to add it manually as an external constraint.");
2001 auto queueConstraints = [&](
auto const &modifiers) {
2008 for (
const auto &sample : channel.samples) {
2009 queueConstraints(sample.normfactors);
2010 queueConstraints(sample.normsys);
2011 queueConstraints(sample.histosys);
2012 for (
auto &
modifier : sample.shapesys) {
2013 for (
auto *constraint :
modifier.constraintPdfs) {
2022 for (
const auto &sample : channel.samples) {
2023 for (
auto &
modifier : sample.otherElements) {
2026 for (
auto &
modifier : sample.tmpElements) {
2041 return exportChannel(tool, channel, elem);
2046 bool autoExportDependants()
const override {
return false; }
2049 std::vector<RooAbsPdf *> constraints;
2059 constraints.push_back(pdf);
2065 bool ok = tryExportHistFactory(tool, prodpdf->
GetName(), sumpdf, constraints, elem);
2068 std::string
const &key()
const override
2070 static const std::string keystring =
"histfactory_dist";
2075 return tryExport(tool,
static_cast<const RooProdPdf *
>(
p), elem);
2081 bool autoExportDependants()
const override {
return false; }
2084 std::vector<RooAbsPdf *> constraints;
2085 return tryExportHistFactory(tool, sumpdf->
GetName(), sumpdf, constraints, elem);
2087 std::string
const &key()
const override
2089 static const std::string keystring =
"histfactory_dist";
2094 return tryExport(tool,
static_cast<const RooRealSumPdf *
>(
p), elem);
2101 registerImporter<HistFactoryImporter>(
"histfactory_dist",
true);
2102 registerImporter<PiecewiseInterpolationFactory>(
"interpolation",
true);
2103 registerImporter<FlexibleInterpVarFactory>(
"interpolation0d",
true);
bool isHS3VersionBefore(std::string const &version, int major, int minor)
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
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)