119std::vector<std::string> valsToStringVec(
JSONNode const &node)
121 std::vector<std::string> out;
124 out.push_back(elem.val());
142 return data.components.size() == pdf->
indexCat().
size();
156 std::vector<double> edges;
162 Var(
int n) : nbins(
n), min(0), max(
n) {}
175bool isNumber(
const std::string &str)
177 bool seen_digit =
false;
178 bool seen_dot =
false;
180 bool after_e =
false;
181 bool sign_allowed =
true;
183 for (
size_t i = 0; i < str.size(); ++i) {
186 if (std::isdigit(
c)) {
188 sign_allowed =
false;
189 }
else if ((
c ==
'+' ||
c ==
'-') && sign_allowed) {
191 sign_allowed =
false;
192 }
else if (
c ==
'.' && !seen_dot && !after_e) {
194 sign_allowed =
false;
195 }
else if ((
c ==
'e' ||
c ==
'E') && seen_digit && !seen_e) {
227 if (
auto n = p.
find(
"value"))
228 v.setVal(
n->val_double());
230 if (
auto n = p.
find(
"nbins"))
231 v.setBins(
n->val_int());
232 if (
auto n = p.
find(
"relErr"))
233 v.setError(
v.getVal() *
n->val_double());
234 if (
auto n = p.
find(
"err"))
235 v.setError(
n->val_double());
236 if (
auto n = p.
find(
"const")) {
237 v.setConstant(
n->val_bool());
239 v.setConstant(
false);
245 auto paramPointsNode = rootNode.
find(
"parameter_points");
246 if (!paramPointsNode)
251 return &((*out)[
"parameters"]);
254std::string genPrefix(
const JSONNode &p,
bool trailing_underscore)
259 if (
auto node = p.
find(
"namespaces")) {
260 for (
const auto &ns : node->
children()) {
266 if (trailing_underscore && !prefix.empty())
272void genIndicesHelper(std::vector<std::vector<int>> &combinations, std::vector<int> &curr_comb,
273 const std::vector<int> &vars_numbins,
size_t curridx)
275 if (curridx == vars_numbins.size()) {
277 combinations.emplace_back(curr_comb);
279 for (
int i = 0; i < vars_numbins[curridx]; ++i) {
280 curr_comb[curridx] = i;
281 ::genIndicesHelper(combinations, curr_comb, vars_numbins, curridx + 1);
298 if (
auto seq = node.
find(
"dict")) {
299 for (
const auto &attr : seq->children()) {
303 if (
auto seq = node.
find(
"tags")) {
304 for (
const auto &attr : seq->children()) {
313 std::stringstream expression;
314 std::string classname(
ex.tclass->GetName());
315 size_t colon = classname.find_last_of(
':');
316 expression << (colon < classname.size() ? classname.substr(colon + 1) : classname);
319 for (
auto k :
ex.arguments) {
320 expression << (first ?
"::" +
name +
"(" :
",");
322 if (k ==
"true" || k ==
"false") {
323 expression << (k ==
"true" ?
"1" :
"0");
325 std::stringstream errMsg;
326 errMsg <<
"node '" <<
name <<
"' is missing key '" << k <<
"'";
328 }
else if (p[k].is_seq()) {
329 bool firstInner =
true;
332 expression << (firstInner ?
"" :
",") << arg->
GetName();
338 expression << p[k].val();
342 return expression.str();
355std::vector<std::vector<int>> generateBinIndices(
const RooArgSet &vars)
357 std::vector<std::vector<int>> combinations;
358 std::vector<int> vars_numbins;
359 vars_numbins.reserve(vars.
size());
361 vars_numbins.push_back(absv->getBins());
363 std::vector<int> curr_comb(vars.
size());
364 ::genIndicesHelper(combinations, curr_comb, vars_numbins, 0);
368template <
typename... Keys_t>
369JSONNode const *findRooFitInternal(
JSONNode const &node, Keys_t
const &...keys)
371 return node.
find(
"misc",
"ROOT_internal", keys...);
383bool isLiteralConstVar(
RooAbsArg const &arg)
385 bool isRooConstVar =
dynamic_cast<RooConstVar const *
>(&arg);
386 return isRooConstVar && isNumber(arg.
GetName());
401 if (isLiteralConstVar(*arg)) {
407 auto initializeNode = [&]() {
425 if (it.first ==
"factory_tag" || it.first ==
"PROD_TERM_TYPE")
428 (*node)[
"dict"].set_map()[it.first] << it.second;
434 if (attr ==
"SnapShot_ExtRefClone" || attr ==
"RooRealConstant_Factory_Object")
437 (*node)[
"tags"].set_seq().append_child() << attr;
457 for (
const auto &p : node[
"axes"].children()) {
462 std::stringstream errMsg;
463 errMsg <<
"The observable \"" <<
name <<
"\" could not be found in the workspace!";
486 std::string
const &type = p[
"type"].
val();
487 if (type ==
"binned") {
490 }
else if (type ==
"unbinned") {
493 getObservables(workspace, p, varlist);
496 auto &coords = p[
"entries"];
497 if (!coords.is_seq()) {
500 std::vector<double> weightVals;
502 auto &weights = p[
"weights"];
503 if (coords.num_children() != weights.num_children()) {
506 for (
auto const &weight : weights.children()) {
507 weightVals.push_back(weight.val_double());
511 for (
auto const &point : coords.children()) {
512 if (!point.is_seq()) {
513 std::stringstream errMsg;
514 errMsg <<
"coordinate point '" << i <<
"' is not a list!";
517 if (point.num_children() != varlist.
size()) {
521 for (
auto const &pointj : point.children()) {
523 v->setVal(pointj.val_double());
526 if (weightVals.size() > 0) {
527 data->add(vars, weightVals[i]);
536 std::stringstream ss;
537 ss <<
"RooJSONFactoryWSTool() failed to create dataset " <<
name << std::endl;
559 const std::vector<std::unique_ptr<RooAbsData>> &datasets)
563 JSONNode const *mcAuxNode = findRooFitInternal(rootnode,
"ModelConfigs", analysisName);
565 JSONNode const *mcNameNode = mcAuxNode ? mcAuxNode->
find(
"mcName") :
nullptr;
566 std::string mcname = mcNameNode ? mcNameNode->
val() : analysisName;
567 if (workspace.
obj(mcname))
572 mc->SetWS(workspace);
576 throw std::runtime_error(
"likelihood node not found!");
578 if (!nllNode->has_child(
"distributions")) {
579 throw std::runtime_error(
"likelihood node has no distributions attached!");
581 if (!nllNode->has_child(
"data")) {
582 throw std::runtime_error(
"likelihood node has no data attached!");
584 std::vector<std::string> nllDistNames = valsToStringVec((*nllNode)[
"distributions"]);
586 for (
auto &nameNode : (*nllNode)[
"aux_distributions"].children()) {
587 if (
RooAbsArg *extConstraint = workspace.
arg(nameNode.val())) {
588 extConstraints.
add(*extConstraint);
592 for (
auto &nameNode : (*nllNode)[
"data"].children()) {
594 for (
const auto &
d : datasets) {
595 if (
d->GetName() == nameNode.val()) {
597 observables.
add(*
d->get());
600 if (nameNode.val() !=
"0" && !found)
601 throw std::runtime_error(
"dataset '" + nameNode.val() +
"' cannot be found!");
604 JSONNode const *pdfNameNode = mcAuxNode ? mcAuxNode->
find(
"pdfName") :
nullptr;
605 std::string
const pdfName = pdfNameNode ? pdfNameNode->
val() :
"simPdf";
611 if (nllDistNames.size() == 1) {
613 pdf = workspace.
pdf(nllDistNames[0]);
616 std::string simPdfName = analysisName +
"_simPdf";
617 std::string indexCatName = analysisName +
"_categoryIndex";
618 RooCategory indexCat{indexCatName.c_str(), indexCatName.c_str()};
619 std::map<std::string, RooAbsPdf *> pdfMap;
620 for (std::size_t i = 0; i < nllDistNames.size(); ++i) {
622 pdfMap[nllDistNames[i]] = workspace.
pdf(nllDistNames[i]);
624 RooSimultaneous simPdf{simPdfName.c_str(), simPdfName.c_str(), pdfMap, indexCat};
632 if (!extConstraints.
empty())
633 mc->SetExternalConstraints(extConstraints);
635 auto readArgSet = [&](std::string
const &
name) {
637 for (
auto const &child : analysisNode[
name].children()) {
638 out.
add(*workspace.
arg(child.val()));
643 mc->SetParametersOfInterest(readArgSet(
"parameters_of_interest"));
644 mc->SetObservables(observables);
655 for (
auto &domain : analysisNode[
"domains"].children()) {
657 if (!thisDomain || !thisDomain->has_child(
"axes"))
659 for (
auto &var : (*thisDomain)[
"axes"].children()) {
662 domainPars.
add(*wsvar);
668 for (
const auto &p : pars) {
669 if (mc->GetParametersOfInterest()->find(*p))
671 if (p->isConstant() && !mainPars.
find(*p) && domainPars.
find(*p)) {
673 }
else if (domainPars.
find(*p)) {
678 mc->SetGlobalObservables(globs);
679 mc->SetNuisanceParameters(nps);
682 if (
auto found = mcAuxNode->
find(
"combined_data_name")) {
688 mc->SetSnapshot(*workspace.
getSnapshot(analysisNode[
"init"].
val().c_str()));
694 auto *combinedPdfInfoNode = findRooFitInternal(rootnode,
"combined_distributions");
697 if (combinedPdfInfoNode ==
nullptr) {
701 for (
auto &info : combinedPdfInfoNode->children()) {
704 std::string combinedName = info.key();
705 std::string indexCatName = info[
"index_cat"].val();
706 std::vector<std::string> labels = valsToStringVec(info[
"labels"]);
707 std::vector<int> indices;
708 std::vector<std::string> pdfNames = valsToStringVec(info[
"distributions"]);
709 for (
auto &
n : info[
"indices"].children()) {
710 indices.push_back(
n.val_int());
713 RooCategory indexCat{indexCatName.c_str(), indexCatName.c_str()};
714 std::map<std::string, RooAbsPdf *> pdfMap;
716 for (std::size_t iChannel = 0; iChannel < labels.size(); ++iChannel) {
717 indexCat.
defineType(labels[iChannel], indices[iChannel]);
718 pdfMap[labels[iChannel]] = ws.
pdf(pdfNames[iChannel]);
721 RooSimultaneous simPdf{combinedName.c_str(), combinedName.c_str(), pdfMap, indexCat};
726void combineDatasets(
const JSONNode &rootnode, std::vector<std::unique_ptr<RooAbsData>> &datasets)
728 auto *combinedDataInfoNode = findRooFitInternal(rootnode,
"combined_datasets");
731 if (combinedDataInfoNode ==
nullptr) {
735 for (
auto &info : combinedDataInfoNode->children()) {
738 std::string combinedName = info.key();
739 std::string indexCatName = info[
"index_cat"].val();
740 std::vector<std::string> labels = valsToStringVec(info[
"labels"]);
741 std::vector<int> indices;
742 for (
auto &
n : info[
"indices"].children()) {
743 indices.push_back(
n.val_int());
745 if (indices.size() != labels.size()) {
750 std::map<std::string, std::unique_ptr<RooAbsData>> dsMap;
751 RooCategory indexCat{indexCatName.c_str(), indexCatName.c_str()};
753 for (std::size_t iChannel = 0; iChannel < labels.size(); ++iChannel) {
754 auto componentName = combinedName +
"_" + labels[iChannel];
757 std::unique_ptr<RooAbsData> &component = *std::find_if(
758 datasets.begin(), datasets.end(), [&](
auto &
d) { return d && d->GetName() == componentName; });
761 allVars.
add(*component->get());
762 dsMap.insert({labels[iChannel], std::move(component)});
763 indexCat.
defineType(labels[iChannel], indices[iChannel]);
766 auto combined = std::make_unique<RooDataSet>(combinedName, combinedName, allVars,
RooFit::Import(dsMap),
768 datasets.emplace_back(std::move(combined));
773void sortByName(T &coll)
775 std::sort(coll.begin(), coll.end(), [](
auto &
l,
auto &
r) { return strcmp(l->GetName(), r->GetName()) < 0; });
792 if (isLiteralConstVar(*arg)) {
800 error(
"unable to stream collection " + std::string(coll.
GetName()) +
" to " + node.
key());
812 if (isLiteralConstVar(*arg)) {
820 error(
"unable to stream collection " + std::string(coll.
GetName()) +
" to " + node.
key());
830 child[
"name"] <<
name;
844 if (child[
"name"].val() ==
name)
863 if (str.empty() || !(std::isalpha(str[0]) || str[0] ==
'_')) {
870 if (!(std::isalnum(
c) ||
c ==
'_')) {
884 std::stringstream ss;
885 ss <<
"RooJSONFactoryWSTool() name '" <<
name <<
"' is not valid!" << std::endl
886 <<
"Sanitize names by setting RooJSONFactoryWSTool::allowSanitizeNames = True." << std::endl;
904 return appendNamedChild(rootNode[
"parameter_points"],
"default_values")[
"parameters"];
913 if (
const auto &node = vars->find(objname)) {
927 if (
const auto &distributionsNode =
_rootnodeInput->find(
"distributions")) {
928 if (
const auto &child =
findNamedChild(*distributionsNode, objname)) {
942 if (isNumber(objname))
948 if (
const auto &functionNode =
_rootnodeInput->find(
"functions")) {
976 if (cv && strcmp(cv->GetName(),
TString::Format(
"%g", cv->getVal()).Data()) == 0) {
983 var[
"value"] << cv->getVal();
984 var[
"const"] <<
true;
986 var[
"value"] << rrv->getVal();
987 if (rrv->isConstant() && storeConstant) {
988 var[
"const"] << rrv->isConstant();
990 var[
"min"] << rrv->getMin();
991 var[
"max"] << rrv->getMax();
993 if (rrv->getBins() != 100 && storeBins) {
994 var[
"nbins"] << rrv->getBins();
1020 const std::string &formula)
1022 std::string newname = std::string(original->
GetName()) + suffix;
1024 trafo_node[
"type"] <<
"generic_function";
1047 if (exportedObjectNames.find(
name) != exportedObjectNames.end())
1050 exportedObjectNames.insert(
name);
1057 std::vector<std::string> channelNames;
1058 for (
auto const &item : simPdf->indexCat()) {
1059 channelNames.push_back(item.first);
1063 auto &child = infoNode[simPdf->GetName()].
set_map();
1064 child[
"index_cat"] << simPdf->indexCat().GetName();
1066 child[
"distributions"].set_seq();
1067 for (
auto const &item : simPdf->indexCat()) {
1068 child[
"distributions"].append_child() << simPdf->getPdf(item.first.c_str())->GetName();
1080 auto &collectionNode = (*_rootnodeOutput)[
dynamic_cast<RooAbsPdf const *
>(&func) ?
"distributions" :
"functions"];
1089 auto it = exporters.find(cl);
1090 if (it != exporters.end()) {
1091 for (
auto &exp : it->second) {
1094 if (!exp->exportObject(
this, &func, elem)) {
1100 elem[
"name"] <<
name;
1104 if (exp->autoExportDependants()) {
1117 const auto &dict = exportKeys.find(cl);
1118 if (dict == exportKeys.end()) {
1119 std::cerr <<
"unable to export class '" << cl->
GetName() <<
"' - no export keys available!\n"
1120 <<
"there are several possible reasons for this:\n"
1121 <<
" 1. " << cl->
GetName() <<
" is a custom class that you or some package you are using added.\n"
1123 <<
" is a ROOT class that nobody ever bothered to write a serialization definition for.\n"
1124 <<
" 3. something is wrong with your setup, e.g. you might have called "
1125 "RooFit::JSONIO::clearExportKeys() and/or never successfully read a file defining these "
1126 "keys with RooFit::JSONIO::loadExportKeys(filename)\n"
1127 <<
"either way, please make sure that:\n"
1128 <<
" 3: you are reading a file with export keys - call RooFit::JSONIO::printExportKeys() to "
1129 "see what is available\n"
1130 <<
" 2 & 1: you might need to write a serialization definition yourself. check "
1131 "https://root.cern/doc/master/group__roofit__dev__docs__hs3.html to "
1132 "see how to do this!\n";
1136 elem[
"type"] << dict->second.type;
1140 for (
size_t i = 0; i < nprox; ++i) {
1146 std::string pname(p->
name());
1147 if (pname[0] ==
'!')
1150 auto k = dict->second.proxies.find(pname);
1151 if (k == dict->second.proxies.end()) {
1152 std::cerr <<
"failed to find key matching proxy '" << pname <<
"' for type '" << dict->second.type
1153 <<
"', encountered in '" << func.
GetName() <<
"', skipping" << std::endl;
1158 if (k->second.empty())
1165 if (isLiteralConstVar(*
r->absArg())) {
1168 elem[k->second] <<
r->absArg()->GetName();
1176 std::cerr <<
"unable to locate server of " << func.
GetName() << std::endl;
1214 std::stringstream ss;
1215 ss <<
"RooJSONFactoryWSTool() function node " +
name +
" is not a map!";
1219 std::string prefix = genPrefix(p,
true);
1220 if (!prefix.empty())
1223 std::stringstream ss;
1224 ss <<
"RooJSONFactoryWSTool() no type given for function '" <<
name <<
"', skipping." << std::endl;
1229 std::string functype(p[
"type"].val());
1232 if (!importAllDependants) {
1237 auto it = importers.find(functype);
1239 if (it != importers.end()) {
1240 for (
auto &imp : it->second) {
1242 ok = imp->importArg(
this, p);
1243 }
catch (
const std::exception &
e) {
1244 std::stringstream ss;
1245 const auto *ptr = imp.get();
1246 ss <<
"RooJSONFactoryWSTool() failed. The importer " <<
typeid(*ptr).name()
1247 <<
" emitted and error: " <<
e.what() << std::endl;
1255 auto expr = factoryExpressions.find(functype);
1256 if (expr != factoryExpressions.end()) {
1257 std::string expression = ::generate(expr->second, p,
this);
1259 std::stringstream ss;
1260 ss <<
"RooJSONFactoryWSTool() failed to create " << expr->second.tclass->GetName() <<
" '" <<
name
1261 <<
"', skipping. expression was\n"
1262 << expression << std::endl;
1266 std::stringstream ss;
1267 ss <<
"RooJSONFactoryWSTool() no handling for type '" << functype <<
"' implemented, skipping."
1269 <<
"there are several possible reasons for this:\n"
1270 <<
" 1. " << functype <<
" is a custom type that is not available in RooFit.\n"
1271 <<
" 2. " << functype
1272 <<
" is a ROOT class that nobody ever bothered to write a deserialization definition for.\n"
1273 <<
" 3. something is wrong with your setup, e.g. you might have called "
1274 "RooFit::JSONIO::clearFactoryExpressions() and/or never successfully read a file defining "
1275 "these expressions with RooFit::JSONIO::loadFactoryExpressions(filename)\n"
1276 <<
"either way, please make sure that:\n"
1277 <<
" 3: you are reading a file with factory expressions - call "
1278 "RooFit::JSONIO::printFactoryExpressions() "
1279 "to see what is available\n"
1280 <<
" 2 & 1: you might need to write a deserialization definition yourself. check "
1281 "https://root.cern/doc/master/group__roofit__dev__docs__hs3.html to see "
1290 std::stringstream
err;
1291 err <<
"something went wrong importing function '" <<
name <<
"'.";
1325 auto &observablesNode = output[
"axes"].
set_seq();
1328 std::string
name = var->GetName();
1331 obsNode[
"name"] <<
name;
1332 if (var->getBinning().isUniform()) {
1333 obsNode[
"min"] << var->getMin();
1334 obsNode[
"max"] << var->getMax();
1335 obsNode[
"nbins"] << var->getBins();
1337 auto &edges = obsNode[
"edges"];
1339 double val = var->getBinning().binLow(0);
1341 for (
int i = 0; i < var->getBinning().numBins(); ++i) {
1342 val = var->getBinning().binHigh(i);
1343 edges.append_child() << val;
1365 for (std::size_t i = 0; i <
n; ++i) {
1366 double w = contents[i];
1388 auto &labels = node[
"labels"].
set_seq();
1389 auto &indices = node[
"indices"].
set_seq();
1391 for (
auto const &item : cat) {
1393 if (std::isalpha(item.first[0])) {
1395 if (label != item.first) {
1396 oocoutW(
nullptr, IO) <<
"RooFitHS3: changed '" << item.first <<
"' to '" << label
1397 <<
"' to become a valid name";
1401 "' to make a valid name!");
1404 labels.append_child() << label;
1405 indices.append_child() << item.second;
1427 " has several category observables!");
1440 datamap.
name = data.GetName();
1444 child[
"index_cat"] << cat->
GetName();
1449 auto *combinedPdfInfoNode = findRooFitInternal(*
_rootnodeOutput,
"combined_distributions");
1450 if (combinedPdfInfoNode) {
1451 for (
auto &info : combinedPdfInfoNode->children()) {
1452 if (info[
"index_cat"].val() == cat->
GetName()) {
1462 std::vector<std::unique_ptr<RooAbsData>> dataList{simPdf ? data.split(*simPdf,
true) : data.split(*cat,
true)};
1464 for (std::unique_ptr<RooAbsData>
const &absData : dataList) {
1465 std::string catName(absData->GetName());
1466 std::string dataName;
1467 if (std::isalpha(catName[0])) {
1469 if (dataName != catName) {
1470 oocoutW(
nullptr, IO) <<
"RooFitHS3: changed '" << catName <<
"' to '" << dataName
1471 <<
"' to become a valid name";
1475 "' to make a valid name!");
1478 absData->SetName((std::string(data.GetName()) +
"_" + dataName).c_str());
1479 datamap.
components[catName] = absData->GetName();
1503 " has several category observables!");
1521 if (
auto weightVar = variables.find(
"weightVar")) {
1522 variables.remove(*weightVar);
1526 if (
auto dh =
dynamic_cast<RooDataHist const *
>(&data)) {
1527 output[
"type"] <<
"binned";
1531 return exportHisto(variables, dh->numEntries(), dh->weightArray(), output);
1540 if (data.isWeighted() && variables.size() == 1) {
1541 bool isBinnedData =
false;
1542 auto &
x =
static_cast<RooRealVar const &
>(*variables[0]);
1543 std::vector<double> contents;
1545 for (; i < data.numEntries(); ++i) {
1547 if (
x.getBin() != i)
1549 contents.push_back(data.weight());
1551 if (i ==
x.getBins())
1552 isBinnedData =
true;
1554 output[
"type"] <<
"binned";
1558 return exportHisto(variables, data.numEntries(), contents.data(), output);
1563 output[
"type"] <<
"unbinned";
1565 auto &coords = output[
"entries"].
set_seq();
1566 std::vector<double> weightVals;
1567 bool hasNonUnityWeights =
false;
1568 for (
int i = 0; i < data.numEntries(); ++i) {
1570 coords.append_child().fill_seq(variables, [](
auto x) {
return static_cast<RooRealVar *
>(
x)->getVal(); });
1571 std::string datasetName = data.GetName();
1572 if (data.isWeighted()) {
1573 weightVals.push_back(data.weight());
1574 if (data.weight() != 1.)
1575 hasNonUnityWeights =
true;
1578 if (data.isWeighted() && hasNonUnityWeights) {
1579 output[
"weights"].
fill_seq(weightVals);
1596 for (
JSONNode const &node : topNode[
"axes"].children()) {
1597 if (node.has_child(
"edges")) {
1598 std::vector<double> edges;
1599 for (
auto const &bound : node[
"edges"].children()) {
1600 edges.push_back(bound.val_double());
1602 auto obs = std::make_unique<RooRealVar>(node[
"name"].val().c_str(), node[
"name"].val().c_str(), edges[0],
1603 edges[edges.size() - 1]);
1604 RooBinning bins(obs->getMin(), obs->getMax());
1605 for (
auto b : edges) {
1608 obs->setBinning(bins);
1611 auto obs = std::make_unique<RooRealVar>(node[
"name"].val().c_str(), node[
"name"].val().c_str(),
1612 node[
"min"].val_double(), node[
"max"].val_double());
1613 obs->setBins(node[
"nbins"].val_int());
1632std::unique_ptr<RooDataHist>
1635 if (!
n.has_child(
"contents"))
1638 JSONNode const &contents =
n[
"contents"];
1644 if (
n.has_child(
"errors")) {
1645 errors = &
n[
"errors"];
1650 auto bins = generateBinIndices(vars);
1652 std::stringstream errMsg;
1653 errMsg <<
"inconsistent bin numbers: contents=" << contents.
num_children() <<
", bins=" << bins.size();
1656 auto dh = std::make_unique<RooDataHist>(
name,
name, vars);
1657 std::vector<double> contentVals;
1659 for (
auto const &cont : contents.
children()) {
1660 contentVals.push_back(cont.val_double());
1662 std::vector<double> errorVals;
1666 errorVals.push_back(
err.val_double());
1669 for (
size_t ibin = 0; ibin < bins.size(); ++ibin) {
1670 const double err = errors ? errorVals[ibin] : -1;
1671 dh->set(ibin, contentVals[ibin],
err);
1694 std::stringstream ss;
1695 ss <<
"RooJSONFactoryWSTool() node '" <<
name <<
"' is not a map, skipping.";
1696 oocoutE(
nullptr, InputArguments) << ss.str() << std::endl;
1702 if (attrNode->has_child(
"is_const_var") && (*attrNode)[
"is_const_var"].val_int() == 1) {
1723 if (
JSONNode const *varsNode = getVariablesNode(
n)) {
1724 for (
const auto &p : varsNode->children()) {
1728 if (
auto seq =
n.find(
"functions")) {
1729 for (
const auto &p : seq->children()) {
1733 if (
auto seq =
n.find(
"distributions")) {
1734 for (
const auto &p : seq->children()) {
1741 const std::vector<CombinedData> &combDataSets,
1742 const std::vector<RooAbsData *> &singleDataSets)
1747 for (std::size_t i = 0; i < std::max(combDataSets.size(), std::size_t(1)); ++i) {
1748 const bool hasdata = i < combDataSets.size();
1749 if (hasdata && !matches(combDataSets.at(i), simpdf))
1752 std::string analysisName(simpdf->GetName());
1754 analysisName +=
"_" + combDataSets[i].name;
1761 for (
auto *data : singleDataSets) {
1762 if (observables.
equals(*(data->get()))) {
1763 std::map<std::string, std::string> mapping;
1764 mapping[pdf->GetName()] = data->GetName();
1769 if (founddata == 0) {
1776 std::string
const &analysisName,
1777 std::map<std::string, std::string>
const *dataComponents)
1783 auto &domains = analysisNode[
"domains"].
set_seq();
1785 analysisNode[
"likelihood"] << analysisName;
1788 nllNode[
"distributions"].set_seq();
1789 nllNode[
"data"].set_seq();
1791 if (dataComponents) {
1794 for (
auto const &item : simPdf->indexCat()) {
1795 const auto &dataComp = dataComponents->find(item.first);
1796 nllNode[
"distributions"].append_child() << simPdf->getPdf(item.first)->GetName();
1797 nllNode[
"data"].append_child() << dataComp->second;
1800 for (
auto it : *dataComponents) {
1801 nllNode[
"distributions"].append_child() << it.first;
1802 nllNode[
"data"].append_child() << it.second;
1806 nllNode[
"distributions"].append_child() << pdf->GetName();
1807 nllNode[
"data"].append_child() << 0;
1811 auto &extConstrNode = nllNode[
"aux_distributions"];
1812 extConstrNode.set_seq();
1814 extConstrNode.append_child() << constr->GetName();
1818 auto writeList = [&](
const char *
name,
RooArgSet const *args) {
1819 if (!args || !args->size())
1822 std::vector<std::string> names;
1823 names.reserve(args->size());
1825 names.push_back(arg->GetName());
1826 std::sort(names.begin(), names.end());
1832 auto &domainsNode = rootnode[
"domains"];
1834 auto writeProductDomain = [&](
const char *suffix,
RooArgSet const *args) {
1835 if (!args || args->empty())
1837 const std::string domainName = analysisName + suffix;
1838 domains.append_child() << domainName;
1850 auto &modelConfigAux =
getRooFitInternal(rootnode,
"ModelConfigs", analysisName);
1851 modelConfigAux.set_map();
1852 modelConfigAux[
"pdfName"] << pdf->GetName();
1853 modelConfigAux[
"mcName"] << mc.
GetName();
1867 _domains = std::make_unique<RooFit::JSONIO::Detail::Domains>();
1872 std::vector<RooAbsPdf *> allpdfs;
1874 if (!arg->hasClients()) {
1875 if (
auto *pdf =
dynamic_cast<RooAbsPdf *
>(arg)) {
1876 allpdfs.push_back(pdf);
1880 sortByName(allpdfs);
1881 std::set<std::string> exportedObjectNames;
1885 std::vector<RooAbsReal *> allfuncs;
1886 for (
auto &arg :
_workspace.allFunctions()) {
1887 if (!arg->hasClients()) {
1888 if (
auto *func =
dynamic_cast<RooAbsReal *
>(arg)) {
1889 allfuncs.push_back(func);
1893 sortByName(allfuncs);
1898 exportAttributes(arg,
n);
1902 std::vector<RooAbsData *> alldata;
1904 alldata.push_back(
d);
1906 sortByName(alldata);
1908 std::vector<RooAbsData *> singleData;
1909 std::vector<RooJSONFactoryWSTool::CombinedData> combData;
1910 for (
auto &
d : alldata) {
1912 if (!data.components.empty())
1913 combData.push_back(data);
1915 singleData.push_back(
d);
1918 for (
auto &
d : alldata) {
1935 bool do_export =
false;
1936 for (
const auto &pdf : allpdfs) {
1937 if (pdf->dependsOn(*arg)) {
1943 snapshotSorted.
add(*arg);
1946 snapshotSorted.
sort();
1947 std::string
name(snsh->GetName());
1948 if (
name !=
"default_values") {
1967 std::stringstream ss(s);
1979 std::stringstream ss(s);
1990 std::stringstream ss;
2002 std::stringstream ss;
2017 auto &metadata =
n[
"metadata"].set_map();
2024 std::string versionName =
gROOT->GetVersion();
2027 std::replace(versionName.begin(), versionName.end(),
'/',
'.');
2028 rootInfo[
"version"] << versionName;
2056 std::ofstream out(filename.c_str());
2057 if (!out.is_open()) {
2058 std::stringstream ss;
2059 ss <<
"RooJSONFactoryWSTool() invalid output file '" << filename <<
"'." << std::endl;
2089 std::ofstream out(filename.c_str());
2090 if (!out.is_open()) {
2091 std::stringstream ss;
2092 ss <<
"RooJSONFactoryWSTool() invalid output file '" << filename <<
"'." << std::endl;
2104 if (
auto seq = attrNode->find(
"tags")) {
2105 for (
auto &
a : seq->children()) {
2106 if (
a.val() == attrib)
2116 auto &tags = (*node)[
"tags"];
2126 if (
auto dict = attrNode->find(
"dict")) {
2127 if (
auto *
a = dict->find(attrib)) {
2135 const std::string &value)
2138 auto &dict = (*node)[
"dict"];
2140 dict[attrib] << value;
2156 auto metadata =
n.find(
"metadata");
2157 if (!metadata || !metadata->find(
"hs3_version")) {
2158 std::stringstream ss;
2159 ss <<
"The HS3 version is missing in the JSON!\n"
2160 <<
"Please include the HS3 version in the metadata field, e.g.:\n"
2161 <<
" \"metadata\" :\n"
2168 _domains = std::make_unique<RooFit::JSONIO::Detail::Domains>();
2169 if (
auto domains =
n.find(
"domains")) {
2180 if (
auto paramPointsNode =
n.find(
"parameter_points")) {
2181 for (
const auto &snsh : paramPointsNode->children()) {
2186 for (
const auto &var : snsh[
"parameters"].children()) {
2188 configureVariable(*
_domains, var, *rrv);
2202 importAttributes(arg, elem);
2212 std::vector<std::unique_ptr<RooAbsData>> datasets;
2213 if (
auto dataNode =
n.find(
"data")) {
2214 for (
const auto &p : dataNode->children()) {
2221 if (
auto analysesNode =
n.find(
"analyses")) {
2229 for (
auto const &
d : datasets) {
2232 for (
auto const &obs : *
d->get()) {
2233 if (
auto *rrv =
dynamic_cast<RooRealVar *
>(obs)) {
2234 _workspace.var(rrv->GetName())->setBinning(rrv->getBinning());
2255 if (this->
workspace()->getSnapshot(
"default_values")) {
2270 std::ifstream infile(filename.c_str());
2271 if (!infile.is_open()) {
2272 std::stringstream ss;
2273 ss <<
"RooJSONFactoryWSTool() invalid input file '" << filename <<
"'." << std::endl;
2303 std::ifstream infile(filename.c_str());
2304 if (!infile.is_open()) {
2305 std::stringstream ss;
2306 ss <<
"RooJSONFactoryWSTool() invalid input file '" << filename <<
"'." << std::endl;
2319 bool isVariable =
true;
2320 if (
n.find(
"type")) {
2333 std::unique_ptr<RooFit::Detail::JSONTree> tree =
varJSONString(elementNode);
2335 _domains = std::make_unique<RooFit::JSONIO::Detail::Domains>();
2336 if (
auto domains =
n.find(
"domains"))
2342 JSONNode const *varsNode = getVariablesNode(
n);
2343 const auto &p = varsNode->
child(0);
2346 auto paramPointsNode =
n.find(
"parameter_points");
2347 const auto &snsh = paramPointsNode->child(0);
2350 const auto &var = snsh[
"parameters"].child(0);
2352 configureVariable(*
_domains, var, *rrv);
2360 importAttributes(arg, elem);
2389 throw std::runtime_error(s);
2402 for (
char c : str) {
2407 case '(': result +=
'_';
break;
2412 case '.': result +=
"_dot_";
break;
2413 case '@': result +=
"at";
break;
2414 case '-': result +=
"minus";
break;
2415 case '/': result +=
"_div_";
break;
2417 default: result +=
c;
break;
2430 if (onlyModelConfig) {
2439 for (
auto *pdf : ws.
allPdfs()) {
2440 if (!pdf->hasClients()) {
2446 if (!func->hasClients()) {
2452 for (
auto *data : ws.
allData()) {
2465 auto *snshSet =
dynamic_cast<RooArgSet *
>(snsh);
2467 tmpWS.
saveSnapshot(snshSet->GetName(), *snshSet,
true);
2481 auto sanitizeIfNeeded = [](
auto const &list) {
2482 for (
auto *obj : list) {
2488 sanitizeIfNeeded(tmpWS.
allVars());
2490 sanitizeIfNeeded(tmpWS.
allPdfs());
2493 for (
auto *data : tmpWS.
allData()) {
2498 for (
auto *obj : *data->get()) {
2505 for (
auto *obj : *data->get()) {
2511 auto *snsh =
dynamic_cast<RooArgSet *
>(snshObj);
2513 std::cerr <<
"Warning: found snapshot that is not a RooArgSet, skipping\n";
2523 for (
auto *arg : *snsh) {
2533 if (
auto *named =
dynamic_cast<TNamed *
>(obj)) {
2534 named->SetName(
sanitizeName(named->GetName()).c_str());
2536 std::cerr <<
"Warning: object " << obj->GetName() <<
" is not TNamed, cannot rename.\n";
2547 for (
auto *obs : mc->GetObservables()->get()) {
2552 for (
auto *poi : mc->GetParametersOfInterest()->get()) {
2557 for (
auto *nuis : mc->GetNuisanceParameters()->get()) {
2562 for (
auto *glob : mc->GetGlobalObservables()->get()) {
2569 std::string wsName = std::string{ws.
GetName()} +
"_sanitized";
2571 newWS.
SetName(wsName.c_str());
std::unique_ptr< RooFit::Detail::JSONTree > varJSONString(const JSONNode &treeRoot)
ROOT::RRangeCast< T, false, Range_t > static_range_cast(Range_t &&coll)
double toDouble(const char *s)
Common abstract base class for objects that represent a value and a "shape" in RooFit.
TClass * IsA() const override
void setStringAttribute(const Text_t *key, const Text_t *value)
Associate string 'value' to this object under key 'key'.
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...
const std::set< std::string > & attributes() const
const RefCountList_t & servers() const
List of all servers of this object.
const std::map< std::string, std::string > & stringAttributes() const
Int_t numProxies() const
Return the number of registered proxies.
void setAttribute(const Text_t *name, bool value=true)
Set (default) or clear a named boolean attribute of this object.
RooAbsProxy * getProxy(Int_t index) const
Return the nth proxy from the proxy list.
A space to attach TBranches.
std::size_t size() const
Number of states defined.
Abstract container object that can hold multiple RooAbsArg objects.
bool equals(const RooAbsCollection &otherColl) const
Check if this and other collection have identically-named contents.
const char * GetName() const override
Returns name of object.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
void sort(bool reverse=false)
Sort collection using std::sort and name comparison.
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for binned and unbinned datasets.
Abstract interface for all probability density functions.
std::unique_ptr< RooArgSet > getAllConstraints(const RooArgSet &observables, RooArgSet &constrainedParams, bool stripDisconnected=true) const
This helper function finds and collects all constraints terms of all component p.d....
Abstract interface for proxy classes.
virtual const char * name() const
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.
Abstract interface for RooAbsArg proxy classes.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Implements a RooAbsBinning in terms of an array of boundary values, posing no constraints on the choi...
bool addBoundary(double boundary)
Add bin boundary at given value.
Object to represent discrete states.
bool defineType(const std::string &label)
Define a state with given name.
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 children_view children()
virtual size_t num_children() const =0
virtual JSONNode & child(size_t pos)=0
virtual JSONNode & set_seq()=0
virtual bool is_seq() const =0
virtual bool is_map() const =0
virtual bool has_child(std::string const &) const =0
virtual std::string key() const =0
JSONNode const * find(std::string const &key) const
static std::unique_ptr< JSONTree > create()
void readVariable(const RooRealVar &)
void writeJSON(RooFit::Detail::JSONNode &) const
void writeVariable(RooRealVar &) const
std::ostream & log(const RooAbsArg *self, RooFit::MsgLevel level, RooFit::MsgTopic facility, bool forceSkipPrefix=false)
Log error message associated with RooAbsArg object self at given level and topic.
static RooMsgService & instance()
Return reference to singleton instance.
Variable that can be changed from the outside.
Facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
const RooAbsCategoryLValue & indexCat() const
const RooArgSet * GetGlobalObservables() const
get RooArgSet for global observables (return nullptr if not existing)
const RooArgSet * GetParametersOfInterest() const
get RooArgSet containing the parameter of interest (return nullptr if not existing)
const RooArgSet * GetNuisanceParameters() const
get RooArgSet containing the nuisance parameters (return nullptr if not existing)
const RooArgSet * GetObservables() const
get RooArgSet for observables (return nullptr if not existing)
const RooArgSet * GetExternalConstraints() const
get RooArgSet for global observables (return nullptr if not existing)
RooAbsPdf * GetPdf() const
get model PDF (return nullptr if pdf has not been specified or does not exist)
Persistable container for RooFit projects.
TObject * obj(RooStringView name) const
Return any type of object (RooAbsArg, RooAbsData or generic object) with given name).
const RooArgSet * getSnapshot(const char *name) const
Return the RooArgSet containing a snapshot of variables contained in the workspace.
RooAbsPdf * pdf(RooStringView name) const
Retrieve p.d.f (RooAbsPdf) with given name. A null pointer is returned if not found.
RooArgSet allVars() const
Return set with all variable objects.
RooArgSet allResolutionModels() const
Return set with all resolution model objects.
bool saveSnapshot(RooStringView, const char *paramNames)
Save snapshot of values and attributes (including "Constant") of given parameters.
RooArgSet allPdfs() const
Return set with all probability density function objects.
std::list< RooAbsData * > allData() const
Return list of all dataset in the workspace.
RooLinkedList const & getSnapshots() const
std::list< TObject * > allGenericObjects() const
Return list of all generic objects in the workspace.
RooAbsArg * arg(RooStringView name) const
Return RooAbsArg with given name. A null pointer is returned if none is found.
RooArgSet allFunctions() const
Return set with all function objects.
RooRealVar * var(RooStringView name) const
Retrieve real-valued variable (RooRealVar) with given name. A null pointer is returned if not found.
std::list< RooAbsData * > allEmbeddedData() const
Return list of all dataset in the workspace.
bool loadSnapshot(const char *name)
Load the values and attributes of the parameters in the snapshot saved with the given name.
bool import(const RooAbsArg &arg, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}, const RooCmdArg &arg9={})
Import a RooAbsArg object, e.g.
TClass instances represent classes, structs and namespaces in the ROOT type system.
The TNamed class is the base class for all named ROOT classes.
const char * GetName() const override
Returns name of object.
virtual void SetName(const char *name)
Set the name of the TNamed.
Mother of all ROOT objects.
const char * Data() const
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
RooCmdArg RecycleConflictNodes(bool flag=true)
RooConstVar & RooConst(double val)
RooCmdArg Silence(bool flag=true)
RooCmdArg Index(RooCategory &icat)
RooCmdArg WeightVar(const char *name="weight", bool reinterpretAsWeight=false)
RooCmdArg Import(const char *state, TH1 &histo)
std::string makeValidVarName(std::string const &in)
ImportExpressionMap & importExpressions()
ExportKeysMap & exportKeys()
RooStats::ModelConfig ModelConfig