38struct InterpolationCodes {
44constexpr int kUnrepresentable = -1;
47constexpr InterpolationCodes interpolationTable[]{
57int codeForClass(InterpolationCodes
const &row, InterpolationClass interpolationClass)
74 for (
auto const &row : interpolationTable) {
75 const int rowCode = codeForClass(row, interpolationClass);
76 if (rowCode != kUnrepresentable && rowCode == code) {
77 return row.descriptor;
85 for (
auto const &row : interpolationTable) {
86 const int rowCode = codeForClass(row, interpolationClass);
87 if (rowCode != kUnrepresentable && row.descriptor == interpolation) {
96 return std::any_of(diagnostics.begin(), diagnostics.end(),
97 [](
Diagnostic const &
d) { return d.severity == Diagnostic::Severity::Error; });
100std::string Cursor::path()
const
113 out +=
"[" + std::to_string(
_index) +
"]";
115 out +=
"(" +
_node[
"name"].
val() +
")";
120void Cursor::error(std::string
const &message)
const
125void Cursor::warning(std::string
const &message)
const
130std::size_t Cursor::numErrors()
const
133 [](
Diagnostic const &
d) { return d.severity == Diagnostic::Severity::Error; });
144 _seen.emplace_back(key);
157 const std::string key =
child.key();
166 if (
c.node().is_container() ||
c.node().is_null()) {
167 c.error(
"must be a string");
170 out =
c.node().val();
175 if (!
c.node().is_number()) {
176 c.error(
"must be a number");
179 out =
c.node().val_double();
185 const double value =
c.node().is_number() ?
c.node().val_double() : 0.5;
186 if (
value != std::floor(
value) || std::abs(
value) >
static_cast<double>(std::numeric_limits<int>::max())) {
187 c.error(
"must be an integer");
190 out =
static_cast<int>(
value);
195 if (
c.node().is_container() ||
c.node().is_null()) {
196 c.error(
"must be a boolean");
200 out =
c.node().val_bool();
201 }
catch (std::exception
const &) {
202 c.error(
"must be a boolean");
209 auto readNumber = [&](
int &number) {
210 const std::size_t begin = pos;
211 while (pos < version.size() && std::isdigit(
static_cast<unsigned char>(version[pos]))) {
215 if (pos == begin || pos - begin > 9) {
218 number = std::stoi(version.substr(begin, pos - begin));
222 if (!readNumber(parsed.
major) || pos >= version.size() || version[pos] !=
'.') {
226 if (!readNumber(parsed.
minor)) {
229 if (pos < version.size() && version[pos] ==
'.') {
231 if (!readNumber(parsed.
patch)) {
242void readBound(Reader &ar,
const char *key, std::optional<double> &out,
double valueIfNull)
247 Cursor c{ar.cursor().node()[key], ar.cursor(), key};
248 if (
c.node().is_null()) {
256constexpr double infinity = std::numeric_limits<double>::infinity();
259void readEdges(Reader &ar, std::string
const &axisName, std::vector<double> &edges)
261 Cursor c{ar.cursor().node()[
"edges"], ar.cursor(),
"edges"};
262 const std::string context =
"\"edges\" of axis '" + axisName +
"' must ";
263 if (!
c.node().is_seq()) {
264 c.error(context +
"be a list");
268 for (std::size_t i = 1; i < edges.size(); ++i) {
269 if (!(edges[i] > edges[i - 1])) {
270 c.error(context +
"be strictly ascending");
274 if (edges.size() < 2) {
275 c.error(context +
"contain at least two values");
284 ar(
"version",
p.version);
289 ar(
"name", axis.
name);
292 for (
const char *key : {
"min",
"max",
"nbins",
"edges",
"categories"}) {
295 "\", which exclude each other");
302 readBound(ar,
"min", axis.
min, -infinity);
303 readBound(ar,
"max", axis.
max, infinity);
304 if (ar.
has(
"edges")) {
307 ar(
"edges", binning.
edges);
308 if (!binning.
edges.empty()) {
316 axis.
binning = std::move(binning);
317 }
else if (ar.
has(
"nbins")) {
319 ar(
"nbins", binning.
nbins);
320 if (binning.
nbins != 0) {
328 ar(
"name", axis.
name);
329 readBound(ar,
"min", axis.
min, -infinity);
330 readBound(ar,
"max", axis.
max, infinity);
335 ar(
"name", axis.
name);
336 if (ar.
has(
"edges")) {
339 if (binning.
edges.size() >= 2) {
344 std::optional<double> min;
345 std::optional<double> max;
348 if ((min && *min != axis.
min) || (max && *max != axis.
max)) {
349 ar.
cursor().
error(
"\"min\" and \"max\" of axis '" + axis.
name +
"' must agree with the \"edges\"");
351 if (ar.
has(
"nbins")) {
352 ar.
cursor().
error(
"axis '" + axis.
name +
"' must not have both \"edges\" and \"nbins\"");
354 axis.
binning = std::move(binning);
360 ar(
"nbins", binning.
nbins);
366 ar(
"name", axis.
name);
373template <
class ContinuousAxis_t>
374void readAxis(
Cursor const &
c, std::variant<ContinuousAxis_t, CategoricalAxis> &out)
376 if (!
c.node().is_map()) {
377 c.error(
"must be a struct");
382 if (reader.has(
"categories") && !(std::is_same_v<ContinuousAxis_t, DomainAxis> && reader.has(
fixedValueKey))) {
383 CategoricalAxis axis;
385 out = std::move(axis);
387 ContinuousAxis_t axis;
389 out = std::move(axis);
412 ar(
"name", domain.
name);
414 if (ar.
has(
"type")) {
417 if (
type !=
"product_domain") {
418 ar.
cursor().
error(
"only domains of type \"product_domain\" are currently supported!");
426 if (!
c.node().is_map()) {
427 c.error(
"must be a struct");
432 if (ar.has(
"value")) {
433 Cursor crsr{ar.cursor().
node()[
"value"], ar.cursor(),
"value"};
434 if (crsr.node().is_number()) {
435 p.value = crsr.node().val_double();
439 p.value = std::move(label);
442 std::optional<bool> isConst;
443 ar(
"const", isConst);
444 p.isConst = isConst.value_or(
false);
446 ar(
"relErr",
p.relError);
447 ar(
"nbins",
p.nbins);
452 ar(
"name", point.
name);
458 ar(
"value",
data.value);
459 ar(
"uncertainty",
data.uncertainty);
466 ar(
"weights",
data.weights);
467 data.hasEntriesUncertainties = ar.
has(
"entries_uncertainties");
469 if (!ar.
has(
"entries")) {
470 ar.
cursor().
error(
"does not define the required component \"entries\"");
474 if (!entries.node().is_seq()) {
475 entries.
error(
"key 'entries' is not a list!");
478 if (
data.weights &&
data.weights->size() != entries.node().num_children()) {
479 ar.
cursor().
error(
"inconsistent number of entries and weights!");
482 data.entries.reserve(entries.node().num_children() *
data.axes.size());
483 std::size_t iRow = 0;
484 for (
JSONNode const &row : entries.node().children()) {
485 Cursor rowCursor{row, entries, iRow};
487 rowCursor.
error(
"coordinate point '" + std::to_string(iRow) +
"' is not a list!");
490 if (row.num_children() !=
data.axes.size()) {
491 rowCursor.error(
"inconsistent number of entries and observables!");
494 std::size_t iAxis = 0;
497 if (
auto const *category = std::get_if<CategoricalAxis>(&
data.axes[iAxis])) {
500 auto found = std::find(category->categories.begin(), category->categories.end(), label);
501 if (found == category->categories.end()) {
502 valueCursor.error(
"'" + label +
"' is not a category of the axis '" + category->name +
"'");
505 data.entries.push_back(
static_cast<double>(std::distance(category->categories.begin(), found)));
507 double coordinate = 0.0;
509 data.entries.push_back(coordinate);
519 if (ar.
has(
"type")) {
522 if (
type !=
"gaussian_uncertainty") {
526 ar(
"sigma", uncertainty.
sigma);
527 if (ar.
has(
"correlation")) {
530 if (
c.node().is_seq()) {
532 }
else if (!
c.node().is_number() ||
c.node().val_double() != 0.0) {
533 c.error(
"must be a matrix or 0");
541 ar(
"contents",
data.contents);
542 ar(
"uncertainty",
data.uncertainty);
544 if (ar.
has(
"errors")) {
546 if (!errors.node().is_seq()) {
547 errors.
error(
"errors are not in list form");
548 }
else if (!
data.uncertainty) {
549 data.uncertainty.emplace();
557 if (!
c.node().is_map()) {
558 c.error(
"must be a struct");
562 ar(
"name", out.
name);
565 if (
type ==
"binned") {
568 out.
body = std::move(body);
569 }
else if (
type ==
"unbinned") {
572 out.
body = std::move(body);
573 }
else if (
type ==
"point") {
576 out.
body = std::move(body);
577 }
else if (ar.has(
"type")) {
578 c.error(
"unknown type of dataset '" +
type +
"'");
584 ar(
"name", likelihood.
name);
587 std::vector<DistributionRef> distributions;
588 ar(
"distributions", distributions);
589 if (!ar.
has(
"data")) {
590 ar.
cursor().
error(
"does not define the required component \"data\"");
594 if (!
data.node().is_seq()) {
595 data.error(
"must be an array");
598 if (
data.node().num_children() != distributions.size()) {
599 ar.
cursor().
error(
"\"distributions\" and \"data\" must have the same length");
602 likelihood.
terms.reserve(distributions.size());
608 if (node.is_number() || (!node.is_container() && !node.is_null() && node.val() ==
"0")) {
609 term.
data = node.is_number() ? node.val_double() : 0.0;
613 term.
data = std::move(ref);
615 likelihood.
terms.push_back(std::move(term));
622 ar(
"name", analysis.
name);
626 auto isLegacy = [&](
const char *key,
const char *legacyKey) {
627 if (ar.
has(key) || !ar.
has(legacyKey)) {
630 ar.
cursor().
warning(std::string(
"the key \"") + legacyKey +
"\" of analysis '" + analysis.
name +
631 "' is deprecated, please use \"" + key +
"\" instead.");
634 ar.
list(isLegacy(
"parameters_of_interest",
"parameter_of_interest") ?
"parameter_of_interest"
635 :
"parameters_of_interest",
637 if (!isLegacy(
"domains",
"domain")) {
642 analysis.
domains.emplace_back();
643 ar(
"domain", analysis.
domains.back());
645 ar(
"init", analysis.
init);
646 ar(
"prior", analysis.
prior);
652std::optional<InterpolationType> interpolationTypeFromString(std::string
const &str)
662std::optional<InterpolationFunction> interpolationFunctionFromString(std::string
const &str)
705 c.error(
"must be a struct with components 'type', 'in', and 'out'");
708 for (
const char *component : {
"type",
"in",
"out"}) {
710 c.error(std::string(
"does not define the required '") + component +
"' component");
714 JSONNode const &typeNode = node[
"type"];
715 JSONNode const &inNode = node[
"in"];
716 JSONNode const &outNode = node[
"out"];
718 c.error(
"components 'type' and 'in' must be strings");
722 auto type = interpolationTypeFromString(typeNode.
val());
724 c.error(
"has unknown interpolation type '" + typeNode.
val() +
"'");
727 auto in = interpolationFunctionFromString(inNode.
val());
729 c.error(
"has unknown interpolation function '" + inNode.
val() +
"'");
738 c.error(
"component 'out' must be a string or null");
741 out.
out = interpolationFunctionFromString(outNode.
val());
743 c.error(
"has unknown extrapolation function '" + outNode.
val() +
"'");
748 for (
const char *component : {
"type",
"in",
"out"}) {
749 reader.
has(component);
758std::optional<ConstraintType> readConstraintType(
Cursor const &
c)
767 c.error(
"unknown constraint type '" +
value +
"', supported are \"Gauss\", \"Poisson\" and \"LogNormal\"");
771void readConstraint(Reader &ar,
Constraint &out)
773 if (ar.has(
"constraints")) {
774 Cursor c{ar.cursor().node()[
"constraints"], ar.cursor(),
"constraints"};
775 if (!
c.node().is_seq() ||
c.node().num_children() != 1) {
776 c.error(
"must be an array with one entry");
781 out = Unconstrained{};
786 out = std::move(pdf);
787 }
else if (ar.has(
"constraint_name")) {
789 ar(
"constraint_name", pdf.pdf);
790 out = std::move(pdf);
791 }
else if (ar.has(
"constraint")) {
792 if (
auto type = readConstraintType(
Cursor{ar.cursor().node()[
"constraint"], ar.cursor(),
"constraint"})) {
800 if (ar.has(
"constraints")) {
801 GammaConstraintPdfs constraints;
802 Cursor c{ar.cursor().node()[
"constraints"], ar.cursor(),
"constraints"};
803 if (!
c.node().is_seq()) {
804 c.error(
"must be an array");
808 for (
JSONNode const &item :
c.node().children()) {
809 constraints.pdfs.emplace_back();
811 constraints.pdfs.back().emplace();
816 out = std::move(constraints);
817 }
else if (ar.has(
"constraint")) {
818 Cursor c{ar.cursor().node()[
"constraint"], ar.cursor(),
"constraint"};
820 if (!
c.node().is_container() && !
c.node().is_null() &&
c.node().val() ==
"Const") {
821 out = ConstantGammas{};
822 }
else if (
auto type = readConstraintType(
c)) {
833 std::optional<std::string> optionalName;
834 ar(
"name", optionalName);
835 name = optionalName.value_or(
"");
841 if (!ar.
has(
"parameters")) {
842 ar(
"parameter", parameter);
846 if (!
c.node().is_seq() ||
c.node().num_children() != 1) {
847 c.
error(
"must be an array with one entry");
857 readConstraint(ar,
m.constraint);
868 readConstraint(ar,
m.constraint);
869 ar(
"interpolation",
m.interpolation);
875 ar(
"errors", variation.
errors);
886 readConstraint(ar,
m.constraint);
887 ar(
"interpolation",
m.interpolation);
893 if (ar.
has(
"parameter")) {
895 ar(
"parameter",
m.name);
897 ar.
list(
"parameters",
m.parameters);
898 if (ar.
has(
"data")) {
901 readGammaConstraint(ar,
m.constraint);
907 ar.
list(
"parameters",
m.parameters);
908 readGammaConstraint(ar,
m.constraint);
918 if (!
c.node().is_map()) {
919 c.error(
"must be a struct");
929 if (
type ==
"normfactor") {
931 }
else if (
type ==
"normsys") {
933 }
else if (
type ==
"histosys") {
935 }
else if (
type ==
"shapesys" ||
type ==
"shapefactor") {
937 }
else if (
type ==
"staterror") {
939 }
else if (
type ==
"custom") {
941 }
else if (ar.has(
"type")) {
943 if (ar.has(
"name")) {
946 c.error(
"modifier '" +
name +
"' of unknown type '" +
type +
"'");
952 ar(
"name", sample.
name);
962 std::optional<double> relThreshold;
963 ar(
"relThreshold", relThreshold);
967 std::optional<bool> impliedPoissonErrors;
968 ar(
"implied_poisson_errors", impliedPoissonErrors);
974 ar(
"axes", dist.axes);
975 ar(
"default_interpolation", dist.defaultInterpolation);
976 ar(
"samples", dist.samples);
977 if (ar.
has(
"staterror")) {
984void readDistribution(
Cursor const &
c, Distribution &out, ParseOptions
const &options)
986 if (!
c.node().is_map()) {
987 c.error(
"must be a struct");
991 ar(
"name", out.name);
994 if (options.typedHistFactory &&
type ==
"histfactory_dist") {
995 HistFactoryDist body;
997 out.body = std::move(body);
999 out.body = GenericObject{
type, &
c.node()};
1002 ar.has(
child.key().c_str());
1011 if (!
c.node().is_map()) {
1012 c.error(
"must be a struct");
1016 ar(
"name", out.
name);
1021 ar.has(
child.key().c_str());
1027 if (ar.
has(
"dict")) {
1029 if (!dict.node().is_map()) {
1030 dict.
error(
"must be a struct");
1033 for (
JSONNode const &item : dict.node().children()) {
1038 if (ar.
has(
"is_const_var")) {
1040 ar(
"is_const_var", isConstVar);
1048 ar(
"labels", info.
labels);
1052 ar.
cursor().
error(
"mismatch in number of labels, indices and distributions!");
1059 ar(
"labels", info.
labels);
1062 ar.
cursor().
error(
"mismatch in number of indices and labels!");
1068 ar(
"mcName", info.
mcName);
1075template <
class Map_t>
1076void readMap(Reader &ar,
const char *key, Map_t &out)
1081 Cursor c{ar.cursor().node()[key], ar.cursor(), key};
1082 if (
c.node().is_null()) {
1085 if (!
c.node().is_map()) {
1086 c.error(
"must be a struct");
1089 for (
JSONNode const &item :
c.node().children()) {
1090 const std::string itemKey = item.
key();
1097void readStepWidths(
Cursor const &misc, std::vector<StepWidth> &out)
1099 JSONNode const *node = misc.node().find(
"minimization",
"parameter_stepwidths");
1104 misc.warning(
"minimization.parameter_stepwidths is not a sequence, skipping.");
1107 for (
JSONNode const &item : node->children()) {
1109 !item[
"step_width"].is_number() || item[
"name"].is_container() || item[
"name"].is_null()) {
1110 misc.warning(
"skipping malformed parameter_stepwidths entry.");
1113 out.push_back({item[
"name"].
val(), item[
"step_width"].val_double()});
1117void readMisc(
Cursor const &root, RooFitInternal &out)
1119 if (!root.node().has_child(
"misc")) {
1122 Cursor misc{root.node()[
"misc"], root,
"misc"};
1123 if (!misc.node().is_map()) {
1126 readStepWidths(misc, out.stepWidths);
1127 if (!misc.node().has_child(
"ROOT_internal")) {
1130 Cursor internal{misc.node()[
"ROOT_internal"], misc,
"ROOT_internal"};
1131 if (!internal.node().is_map()) {
1134 Reader ar{internal};
1135 readMap(ar,
"attributes", out.attributes);
1136 readMap(ar,
"combined_distributions", out.combinedDistributions);
1137 readMap(ar,
"combined_datasets", out.combinedDatasets);
1138 readMap(ar,
"ModelConfigs", out.modelConfigs);
1139 readMap(ar,
"histfactory_constraints", out.channelConstraints);
1142void readMetadata(
Cursor const &root, Metadata &out, ParseOptions
const &options)
1144 JSONNode const *metadata = root.node().find(
"metadata");
1145 JSONNode const *versionNode = metadata ? metadata->
find(
"hs3_version") :
nullptr;
1147 if (options.requireMetadata) {
1148 std::stringstream ss;
1149 ss <<
"The HS3 version is missing in the JSON!\n"
1150 <<
"Please include the HS3 version in the metadata field, e.g.:\n"
1151 <<
" \"metadata\" :\n"
1155 root.error(ss.str());
1159 Cursor metadataCursor{*metadata, root,
"metadata"};
1160 Cursor versionCursor{*versionNode, metadataCursor,
"hs3_version"};
1162 versionCursor.error(std::string(
"The HS3 version in the metadata must be a string, e.g. \"") +
supportedVersion +
1166 out.hs3Version = versionNode->
val();
1171 versionCursor.warning(
"cannot parse hs3_version '" + out.hs3Version +
1172 "', expected a string of the form \"MAJOR.MINOR\".");
1173 }
else if (supported < Version{out.version.major, out.version.minor}) {
1174 versionCursor.warning(
"the document has hs3_version '" + out.hs3Version +
1175 "', which is newer than the version supported by this RooFit ('" +
supportedVersion +
1176 "'). Some content might not be imported correctly.");
1179 Reader ar{metadataCursor};
1180 ar.has(
"hs3_version");
1181 ar.list(
"packages", out.packages);
1182 ar.list(
"authors", out.authors);
1183 ar.list(
"publications", out.publications);
1184 ar(
"description", out.description);
1201 if (ar.has(
"distributions") && !root[
"distributions"].
is_null()) {
1202 Cursor distributions{root[
"distributions"],
cursor,
"distributions"};
1203 if (!distributions.node().is_seq()) {
1204 distributions.error(
"must be an array");
1207 doc.
distributions.reserve(distributions.node().num_children());
1208 for (
JSONNode const &item : distributions.node().children()) {
1216 ar.list(
"data", doc.
data);
1218 ar.list(
"domains", doc.
domains);
1229 if (!distribution.
is_map()) {
1230 cursor.error(
"must be a struct");
1242 if (
c.node().is_number()) {
1243 out =
c.node().val_double();
1253 c.error(
"must be a structured interpolation or a legacy integer code");
1254 return std::nullopt;
1256 const std::string
value = node.
val();
1260 c.error(
"has invalid legacy interpolation code '" +
value +
"'");
1261 return std::nullopt;
1264 if (!interpolation) {
1265 c.error(std::string(
"has unsupported ") +
1269 return interpolation;
1276void readInterpolations(Reader &ar, std::size_t nParameters, InterpolationClass interpolationClass,
1277 std::vector<Interpolation> &out)
1280 if (ar.has(
"interpolations")) {
1281 Cursor c{ar.cursor().node()[
"interpolations"], ar.cursor(),
"interpolations"};
1282 const std::size_t errorsBefore =
c.numErrors();
1283 std::vector<Interpolation> interpolations;
1285 const std::size_t
size = interpolations.size();
1286 if (
c.numErrors() != errorsBefore) {
1289 if (nParameters == 0 ?
size != 0 :
size != 1 &&
size != nParameters) {
1290 c.error(
"component 'interpolations' must contain either one descriptor or one descriptor per parameter (got " +
1291 std::to_string(
size) +
" for " + std::to_string(nParameters) +
" parameters)");
1292 }
else if (
size == 1) {
1293 out.assign(nParameters, interpolations.front());
1295 out = std::move(interpolations);
1299 if (!ar.has(
"interpolationCodes")) {
1302 Cursor c{ar.cursor().node()[
"interpolationCodes"], ar.cursor(),
"interpolationCodes"};
1303 if (!
c.node().is_seq() ||
c.node().num_children() != nParameters) {
1304 c.error(
"legacy component 'interpolationCodes' must contain one code per parameter (got " +
1305 std::to_string(
c.node().is_seq() ?
c.node().num_children() : 0) +
" for " + std::to_string(nParameters) +
1312 out[i] = *interpolation;
1319template <
class Function_t,
class Fn>
1320Function_t parseInterpolated(
JSONNode const &node,
Diagnostics &diagnostics, InterpolationClass interpolationClass,
1326 cursor.error(
"must be a struct");
1329 const std::size_t errorsBefore =
cursor.numErrors();
1333 ar(
"nom", out.nominal);
1334 ar(
"vars", out.parameters);
1335 ar(
"high", out.high);
1337 readOthers(ar, out);
1338 if (
cursor.numErrors() == errorsBefore &&
1339 (out.high.size() != out.parameters.size() || out.low.size() != out.parameters.size())) {
1340 cursor.error(
"has non-matching lengths of 'vars', 'high' and 'low'");
1342 readInterpolations(ar, out.parameters.size(), interpolationClass, out.interpolations);
1350 std::vector<BinnedAxis> out;
1357 return parseInterpolated<InterpolatedFunction>(
constexpr const char * fixedValueKey
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
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 cursor
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 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 child
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 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
bool is_container() const
size_t num_children() const
JSONNode const * find(std::string const &key) const
bool has_child(std::string const &) const
JSONNode & child(size_t pos)
An HS3 document. It is move-only, because generic objects refer to the JSON tree that the document wa...
std::vector< HS3::Analysis > analyses
std::vector< HS3::Data > data
std::vector< HS3::Likelihood > likelihoods
std::vector< HS3::Function > functions
std::vector< HS3::ParameterPoint > parameterPoints
HS3::RooFitInternal rooFit
std::vector< HS3::Domain > domains
std::vector< HS3::Distribution > distributions
A position in the JSON tree.
std::size_t numErrors() const
void warning(std::string const &message) const
Detail::JSONNode const & node() const
Diagnostics & _diagnostics
Detail::JSONNode const & _node
void error(std::string const &message) const
Reads the components of a struct.
~Reader()
Reports the components that were not read, unless reading the struct gave an error.
Reader(Cursor const &cursor)
bool has(const char *key)
Whether the struct has a component. Checking for a component counts as reading it.
std::vector< std::string > _seen
void nested(const char *key, Fn &&fn)
Read the components of a struct that is nested in a component.
std::size_t _nErrorsBefore
Cursor const & cursor() const
void list(const char *key, std::vector< T > &field)
Read an array that can be omitted, which is equivalent to an empty one.
Types that represent an HS3 document.
std::variant< std::string, double > NameOrNumber
A name, or a number for a constant.
HistFactoryDist parseHistFactoryDist(Detail::JSONNode const &distribution, Diagnostics &diagnostics)
Reads a HistFactory distribution that doesn't come with a document.
std::variant< NormFactor, NormSys, HistoSys, ShapeSys, StatError, CustomModifier > Modifier
constexpr auto supportedVersion
InterpolationClass
The RooFit classes that implement the interpolations, which encode them with integer codes.
constexpr Interpolation multiplicativePolynomialExponential
void readValue(Cursor const &c, std::string &out)
constexpr Interpolation additivePolynomialLinear
void readModifierName(Reader &ar, std::string &name)
void readParameter(Reader &ar, ParameterRef ¶meter)
void describe(Reader &ar, Package &p)
ConstraintType
The constraint types that older documents named, for which RooFit creates the constraint terms.
std::optional< Interpolation > interpolationFromCode(int code, InterpolationClass interpolationClass)
The interpolation for an integer code, or nothing if the class doesn't support the code.
char const * toString(InterpolationType type)
InterpolatedNumber parseInterpolatedNumber(Detail::JSONNode const &node, Diagnostics &diagnostics)
std::optional< Interpolation > readInterpolationCode(Cursor const &c, InterpolationClass interpolationClass)
Reads an integer interpolation code, as older versions of RooFit wrote them.
InterpolatedFunction parseInterpolatedFunction(Detail::JSONNode const &node, Diagnostics &diagnostics)
Reads the functions "interpolation" and "interpolation0d", which don't come with a document.
std::optional< int > codeFromInterpolation(Interpolation const &interpolation, InterpolationClass interpolationClass)
The integer code of an interpolation, or nothing if the class can't represent the interpolation.
constexpr Interpolation multiplicativePolynomialLinear
bool hasErrors(Diagnostics const &diagnostics)
Whether there is a diagnostic with error severity.
constexpr Interpolation multiplicativePiecewiseExponential
std::vector< Diagnostic > Diagnostics
std::variant< Unconstrained, ConstraintType, ConstantGammas, GammaConstraintPdfs > GammaConstraint
bool parseVersion(std::string const &version, Version &out)
Reads the leading "MAJOR.MINOR" and the optional ".PATCH" of an HS3 version string.
std::variant< Unconstrained, ConstraintType, ConstraintPdf > Constraint
std::vector< BinnedAxis > parseBinnedAxes(Detail::JSONNode const &axes, Diagnostics &diagnostics)
Reads the axes of binned data that doesn't come with a document.
constexpr Interpolation additiveQuadraticLinear
constexpr Interpolation additivePiecewiseLinear
HS3Document parseDocument(Detail::JSONNode const &root, Diagnostics &diagnostics, ParseOptions const &options={})
Reads a document.
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
std::optional< DistributionRef > prior
std::optional< ParameterPointRef > init
std::vector< DomainRef > domains
std::vector< ParameterRef > parametersOfInterest
bool isConstVar
How ROOT versions before HS3 0.3 marked named RooConstVars.
std::vector< std::string > tags
std::map< std::string, std::string > dict
std::vector< std::string > categories
std::vector< int > indices
std::vector< std::string > labels
std::vector< std::string > labels
std::vector< DistributionRef > distributions
std::vector< int > indices
The axis of point data or unbinned data, which can't have a binning.
std::optional< double > max
std::optional< double > min
Multiplies the sample with a function of the document.
std::variant< PointData, UnbinnedData, BinnedData > body
std::optional< double > min
std::optional< double > max
std::optional< Binning > binning
std::optional< double > fixedValue
std::vector< std::variant< DomainAxis, CategoricalAxis > > axes
std::vector< double > edges
std::vector< std::vector< double > > correlation
Empty if there is no correlation.
std::vector< double > sigma
Detail::JSONNode const * node
std::vector< double > contents
std::optional< std::vector< double > > errors
Not in the standard, but older versions of RooFit read them.
The function "interpolation" of RooFit, implemented by PiecewiseInterpolation: a nominal function plu...
The function "interpolation0d" of RooFit, implemented by FlexibleInterpVar: a nominal value plus the ...
How a modifier of a HistFactory distribution interpolates and extrapolates its effect.
std::optional< InterpolationFunction > out
If not set, the function inside the bounds is used outside as well.
DistributionRef distribution
std::variant< DataRef, double > data
std::vector< DistributionRef > auxDistributions
std::vector< LikelihoodTerm > terms
std::optional< std::string > pdfName
std::optional< std::string > mcName
std::optional< std::string > combinedDataName
std::vector< ParameterValue > parameters
Options for upgradeDocument() and parseDocument().
A name that says what it refers to, so that for example a DataRef can't be used as a DomainRef.
std::vector< double > contents
std::optional< std::vector< double > > errors
std::vector< Modifier > modifiers
Scales each bin by its own parameter. The modifier type "shapesys" is a deprecated alias of "shapefac...
Settings of the staterror modifiers that apply to the whole channel. This is a RooFit extension.
bool impliedPoissonErrors
Samples without "errors" have Poisson uncertainties, as in documents before HS3 0....
GammaConstraint constraint
Scales each bin by a parameter, that is constrained by the statistical uncertainty of all samples tha...