119std::vector<std::string> valsToStringVec(
JSONNode const &node)
121 std::vector<std::string> out;
124 out.push_back(elem.val());
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 out.
add(*args,
true);
317void collectParameterStepWidthCandidatesFromModelConfigs(
RooWorkspace const &workspace,
RooArgSet &candidates,
326 addIfPresent(candidates, mc->GetParametersOfInterest());
327 addIfPresent(candidates, mc->GetNuisanceParameters());
329 addIfPresent(excluded, mc->GetObservables());
330 addIfPresent(excluded, mc->GetGlobalObservables());
331 addIfPresent(excluded, mc->GetConditionalObservables());
335void collectParameterStepWidthCandidatesFromPdfs(std::vector<RooAbsPdf *>
const &pdfs,
336 std::vector<RooAbsData *>
const &
data,
RooArgSet &candidates,
342 std::unique_ptr<RooArgSet> pdfObs{pdf->
getObservables(*dataset->get())};
343 observables.
add(*pdfObs,
true);
346 if (observables.
empty()) {
352 candidates.
add(params,
true);
353 excluded.
add(observables,
true);
357void exportParameterStepWidths(
RooWorkspace const &workspace, std::vector<RooAbsPdf *>
const &pdfs,
358 std::vector<RooAbsData *>
const &
data,
JSONNode &rootnode)
363 collectParameterStepWidthCandidatesFromModelConfigs(workspace, candidates, excluded);
364 collectParameterStepWidthCandidatesFromPdfs(pdfs,
data, candidates, excluded);
368 JSONNode *parameterStepWidthsNode =
nullptr;
370 if (excluded.
find(*arg)) {
375 if (!var || !var->hasError()) {
379 if (!parameterStepWidthsNode) {
380 parameterStepWidthsNode = &rootnode[
"misc"][
"minimization"][
"parameter_stepwidths"].
set_seq();
384 stepWidthNode[
"step_width"] << var->getError();
390 auto const *parameterStepWidthsNode = rootnode.
find(
"misc",
"minimization",
"parameter_stepwidths");
391 if (!parameterStepWidthsNode) {
394 if (!parameterStepWidthsNode->is_seq()) {
400 if (!stepWidthNode.is_map() || !stepWidthNode.has_child(
"name") || !stepWidthNode.has_child(
"step_width")) {
410 "RooFitHS3: skipping parameter_stepwidths entry for unknown or non-real variable '" +
name +
"'.");
414 var->
setError(stepWidthNode.find(
"step_width")->val_double());
421 std::stringstream expression;
422 std::string classname(
ex.tclass->GetName());
423 size_t colon = classname.find_last_of(
':');
424 expression << (colon < classname.size() ? classname.substr(colon + 1) : classname);
427 for (
auto k :
ex.arguments) {
428 expression << (first ?
"::" +
name +
"(" :
",");
430 if (k ==
"true" || k ==
"false") {
431 expression << (k ==
"true" ?
"1" :
"0");
433 std::stringstream errMsg;
434 errMsg <<
"node '" <<
name <<
"' is missing key '" << k <<
"'";
436 }
else if (p[k].is_seq()) {
437 bool firstInner =
true;
440 expression << (firstInner ?
"" :
",") << arg->
GetName();
446 expression << p[k].val();
450 return expression.str();
463std::vector<std::vector<int>> generateBinIndices(
const RooArgSet &vars)
465 std::vector<std::vector<int>> combinations;
466 std::vector<int> vars_numbins;
467 vars_numbins.reserve(vars.
size());
469 vars_numbins.push_back(absv->getBins());
471 std::vector<int> curr_comb(vars.
size());
472 ::genIndicesHelper(combinations, curr_comb, vars_numbins, 0);
476template <
typename... Keys_t>
477JSONNode const *findRooFitInternal(
JSONNode const &node, Keys_t
const &...keys)
479 return node.
find(
"misc",
"ROOT_internal", keys...);
491bool isLiteralConstVar(
RooAbsArg const &arg)
493 bool isRooConstVar =
dynamic_cast<RooConstVar const *
>(&arg);
494 return isRooConstVar && isNumber(arg.
GetName());
509 if (isLiteralConstVar(*arg)) {
515 auto initializeNode = [&]() {
533 if (it.first ==
"factory_tag" || it.first ==
"PROD_TERM_TYPE")
536 (*node)[
"dict"].set_map()[it.first] << it.second;
542 if (
attr ==
"SnapShot_ExtRefClone" ||
attr ==
"RooRealConstant_Factory_Object")
545 (*node)[
"tags"].set_seq().append_child() <<
attr;
565 for (
const auto &p : node[
"axes"].children()) {
570 std::stringstream errMsg;
571 errMsg <<
"The observable \"" <<
name <<
"\" could not be found in the workspace!";
594 std::string
const &
type = p[
"type"].
val();
595 if (
type ==
"binned") {
598 }
else if (
type ==
"unbinned") {
601 getObservables(workspace, p, varlist);
604 auto &coords = p[
"entries"];
605 if (!coords.is_seq()) {
608 std::vector<double> weightVals;
610 auto &weights = p[
"weights"];
611 if (coords.num_children() != weights.num_children()) {
614 for (
auto const &weight : weights.children()) {
615 weightVals.push_back(weight.val_double());
619 for (
auto const &point : coords.children()) {
620 if (!point.is_seq()) {
621 std::stringstream errMsg;
622 errMsg <<
"coordinate point '" << i <<
"' is not a list!";
625 if (point.num_children() != varlist.
size()) {
629 for (
auto const &pointj : point.children()) {
631 v->setVal(pointj.val_double());
634 if (weightVals.size() > 0) {
635 data->add(vars, weightVals[i]);
644 std::stringstream ss;
645 ss <<
"RooJSONFactoryWSTool() failed to create dataset " <<
name << std::endl;
667 const std::vector<std::unique_ptr<RooAbsData>> &datasets)
671 JSONNode const *mcAuxNode = findRooFitInternal(rootnode,
"ModelConfigs", analysisName);
673 JSONNode const *mcNameNode = mcAuxNode ? mcAuxNode->
find(
"mcName") :
nullptr;
674 std::string mcname = mcNameNode ? mcNameNode->
val() : analysisName;
675 if (workspace.
obj(mcname))
680 mc->SetWS(workspace);
684 throw std::runtime_error(
"likelihood node not found!");
686 if (!nllNode->has_child(
"distributions")) {
687 throw std::runtime_error(
"likelihood node has no distributions attached!");
689 if (!nllNode->has_child(
"data")) {
690 throw std::runtime_error(
"likelihood node has no data attached!");
692 std::vector<std::string> nllDistNames = valsToStringVec((*nllNode)[
"distributions"]);
694 for (
auto &nameNode : (*nllNode)[
"aux_distributions"].children()) {
695 if (
RooAbsArg *extConstraint = workspace.
arg(nameNode.val())) {
696 extConstraints.
add(*extConstraint);
700 for (
auto &nameNode : (*nllNode)[
"data"].children()) {
702 for (
const auto &
d : datasets) {
703 if (
d->GetName() == nameNode.val()) {
705 observables.
add(*
d->get(),
true);
708 if (nameNode.val() !=
"0" && !found)
709 throw std::runtime_error(
"dataset '" + nameNode.val() +
"' cannot be found!");
712 JSONNode const *pdfNameNode = mcAuxNode ? mcAuxNode->
find(
"pdfName") :
nullptr;
713 std::string
const pdfName = pdfNameNode ? pdfNameNode->
val() :
"simPdf";
719 if (nllDistNames.size() == 1) {
721 pdf = workspace.
pdf(nllDistNames[0]);
724 std::string simPdfName = analysisName +
"_simPdf";
725 std::string indexCatName = analysisName +
"_categoryIndex";
726 RooCategory indexCat{indexCatName.c_str(), indexCatName.c_str()};
727 std::map<std::string, RooAbsPdf *> pdfMap;
728 for (std::size_t i = 0; i < nllDistNames.size(); ++i) {
729 indexCat.defineType(nllDistNames[i], i);
730 pdfMap[nllDistNames[i]] = workspace.
pdf(nllDistNames[i]);
732 RooSimultaneous simPdf{simPdfName.c_str(), simPdfName.c_str(), pdfMap, indexCat};
740 if (!extConstraints.
empty())
741 mc->SetExternalConstraints(extConstraints);
743 auto readArgSet = [&](std::string
const &
name) {
745 for (
auto const &
child : analysisNode[
name].children()) {
751 mc->SetParametersOfInterest(readArgSet(
"parameters_of_interest"));
752 mc->SetObservables(observables);
763 for (
auto &domain : analysisNode[
"domains"].children()) {
765 if (!thisDomain || !thisDomain->has_child(
"axes"))
767 for (
auto &var : (*thisDomain)[
"axes"].children()) {
770 domainPars.
add(*wsvar);
776 for (
const auto &p : pars) {
777 if (mc->GetParametersOfInterest()->find(*p))
779 if (p->isConstant() && !mainPars.
find(*p) && domainPars.
find(*p)) {
781 }
else if (domainPars.
find(*p)) {
786 mc->SetGlobalObservables(globs);
787 mc->SetNuisanceParameters(nps);
790 if (
auto found = mcAuxNode->
find(
"combined_data_name")) {
796 mc->SetSnapshot(*workspace.
getSnapshot(analysisNode[
"init"].
val().c_str()));
802 auto *combinedPdfInfoNode = findRooFitInternal(rootnode,
"combined_distributions");
805 if (combinedPdfInfoNode ==
nullptr) {
809 for (
auto &info : combinedPdfInfoNode->children()) {
812 std::string combinedName = info.key();
813 std::string indexCatName = info[
"index_cat"].val();
814 std::vector<std::string> labels = valsToStringVec(info[
"labels"]);
815 std::vector<int> indices;
816 std::vector<std::string> pdfNames = valsToStringVec(info[
"distributions"]);
817 for (
auto &
n : info[
"indices"].children()) {
818 indices.push_back(
n.val_int());
821 RooCategory indexCat{indexCatName.c_str(), indexCatName.c_str()};
822 std::map<std::string, RooAbsPdf *> pdfMap;
824 for (std::size_t iChannel = 0; iChannel < labels.size(); ++iChannel) {
825 indexCat.defineType(labels[iChannel], indices[iChannel]);
826 pdfMap[labels[iChannel]] = ws.
pdf(pdfNames[iChannel]);
829 RooSimultaneous simPdf{combinedName.c_str(), combinedName.c_str(), pdfMap, indexCat};
834void combineDatasets(
const JSONNode &rootnode, std::vector<std::unique_ptr<RooAbsData>> &datasets)
836 auto *combinedDataInfoNode = findRooFitInternal(rootnode,
"combined_datasets");
839 if (combinedDataInfoNode ==
nullptr) {
843 for (
auto &info : combinedDataInfoNode->children()) {
846 std::string combinedName = info.key();
847 std::string indexCatName = info[
"index_cat"].val();
848 std::vector<std::string> labels = valsToStringVec(info[
"labels"]);
849 std::vector<int> indices;
850 for (
auto &
n : info[
"indices"].children()) {
851 indices.push_back(
n.val_int());
853 if (indices.size() != labels.size()) {
858 std::map<std::string, std::unique_ptr<RooAbsData>> dsMap;
859 RooCategory indexCat{indexCatName.c_str(), indexCatName.c_str()};
861 for (std::size_t iChannel = 0; iChannel < labels.size(); ++iChannel) {
862 auto componentName = combinedName +
"_" + labels[iChannel];
865 std::unique_ptr<RooAbsData> &component = *std::find_if(
866 datasets.begin(), datasets.end(), [&](
auto &
d) { return d && d->GetName() == componentName; });
869 allVars.add(*component->get(),
true);
870 dsMap.insert({labels[iChannel], std::move(component)});
871 indexCat.defineType(labels[iChannel], indices[iChannel]);
874 auto combined = std::make_unique<RooDataSet>(combinedName, combinedName, allVars,
RooFit::Import(dsMap),
876 datasets.emplace_back(std::move(combined));
881void sortByName(T &coll)
883 std::sort(coll.begin(), coll.end(), [](
auto &
l,
auto &
r) { return strcmp(l->GetName(), r->GetName()) < 0; });
900 if (isLiteralConstVar(*arg)) {
908 error(
"unable to stream collection " + std::string(coll.
GetName()) +
" to " + node.
key());
951 if (str.empty() || !(std::isalpha(str[0]) || str[0] ==
'_')) {
958 if (!(std::isalnum(
c) ||
c ==
'_')) {
972 std::stringstream ss;
973 ss <<
"RooJSONFactoryWSTool() name '" <<
name <<
"' is not valid!" << std::endl
974 <<
"Sanitize names by setting RooJSONFactoryWSTool::allowSanitizeNames = True." << std::endl;
992 return appendNamedChild(rootNode[
"parameter_points"],
"default_values")[
"parameters"];
1001 if (
const auto &node = vars->find(objname)) {
1029 if (isNumber(objname))
1062 if (cv && strcmp(cv->GetName(),
TString::Format(
"%g", cv->getVal()).Data()) == 0) {
1069 var[
"value"] << cv->getVal();
1070 var[
"const"] <<
true;
1072 var[
"value"] << rrv->getVal();
1073 if (rrv->isConstant() && storeConstant) {
1074 var[
"const"] << rrv->isConstant();
1076 var[
"min"] << rrv->getMin();
1077 var[
"max"] << rrv->getMax();
1079 if (rrv->getBins() != 100 && storeBins) {
1080 var[
"nbins"] << rrv->getBins();
1106 const std::string &formula)
1108 std::string newname = std::string(original->
GetName()) + suffix;
1110 trafo_node[
"type"] <<
"generic_function";
1133 if (exportedObjectNames.find(
name) != exportedObjectNames.end())
1136 exportedObjectNames.insert(
name);
1143 std::vector<std::string> channelNames;
1144 for (
auto const &item : simPdf->indexCat()) {
1145 channelNames.push_back(item.first);
1149 auto &
child = infoNode[simPdf->GetName()].set_map();
1150 child[
"index_cat"] << simPdf->indexCat().GetName();
1152 child[
"distributions"].set_seq();
1153 for (
auto const &item : simPdf->indexCat()) {
1154 child[
"distributions"].append_child() << simPdf->getPdf(item.first.c_str())->GetName();
1166 auto &collectionNode = (*_rootnodeOutput)[
dynamic_cast<RooAbsPdf const *
>(&func) ?
"distributions" :
"functions"];
1175 auto it = exporters.find(cl);
1176 if (it != exporters.end()) {
1177 for (
auto &exp : it->second) {
1180 if (!exp->exportObject(
this, &func, elem)) {
1186 elem[
"name"] <<
name;
1190 if (exp->autoExportDependants()) {
1203 const auto &dict = exportKeys.find(cl);
1204 if (dict == exportKeys.end()) {
1205 std::cerr <<
"unable to export class '" << cl->
GetName() <<
"' - no export keys available!\n"
1206 <<
"there are several possible reasons for this:\n"
1207 <<
" 1. " << cl->
GetName() <<
" is a custom class that you or some package you are using added.\n"
1209 <<
" is a ROOT class that nobody ever bothered to write a serialization definition for.\n"
1210 <<
" 3. something is wrong with your setup, e.g. you might have called "
1211 "RooFit::JSONIO::clearExportKeys() and/or never successfully read a file defining these "
1212 "keys with RooFit::JSONIO::loadExportKeys(filename)\n"
1213 <<
"either way, please make sure that:\n"
1214 <<
" 3: you are reading a file with export keys - call RooFit::JSONIO::printExportKeys() to "
1215 "see what is available\n"
1216 <<
" 2 & 1: you might need to write a serialization definition yourself. check "
1217 "https://root.cern/doc/master/group__roofit__dev__docs__hs3.html to "
1218 "see how to do this!\n";
1222 elem[
"type"] << dict->second.type;
1226 for (
size_t i = 0; i < nprox; ++i) {
1232 std::string pname(p->
name());
1233 if (pname[0] ==
'!')
1236 auto k = dict->second.proxies.find(pname);
1237 if (k == dict->second.proxies.end()) {
1238 std::cerr <<
"failed to find key matching proxy '" << pname <<
"' for type '" << dict->second.type
1239 <<
"', encountered in '" << func.
GetName() <<
"', skipping" << std::endl;
1244 if (k->second.empty())
1251 if (isLiteralConstVar(*
r->absArg())) {
1254 elem[k->second] <<
r->absArg()->GetName();
1262 std::cerr <<
"unable to locate server of " << func.
GetName() << std::endl;
1300 std::stringstream ss;
1301 ss <<
"RooJSONFactoryWSTool() function node " +
name +
" is not a map!";
1305 std::string prefix = genPrefix(p,
true);
1306 if (!prefix.empty())
1309 std::stringstream ss;
1310 ss <<
"RooJSONFactoryWSTool() no type given for function '" <<
name <<
"', skipping." << std::endl;
1315 std::string functype(p[
"type"].val());
1318 if (!importAllDependants) {
1323 auto it = importers.find(functype);
1325 if (it != importers.end()) {
1326 for (
auto &imp : it->second) {
1328 ok = imp->importArg(
this, p);
1329 }
catch (
const std::exception &
e) {
1330 std::stringstream ss;
1331 const auto *ptr = imp.get();
1332 ss <<
"RooJSONFactoryWSTool() failed. The importer " <<
typeid(*ptr).name()
1333 <<
" emitted and error: " <<
e.what() << std::endl;
1341 auto expr = factoryExpressions.find(functype);
1342 if (expr != factoryExpressions.end()) {
1343 std::string expression = ::generate(expr->second, p,
this);
1345 std::stringstream ss;
1346 ss <<
"RooJSONFactoryWSTool() failed to create " << expr->second.tclass->GetName() <<
" '" <<
name
1347 <<
"', skipping. expression was\n"
1348 << expression << std::endl;
1352 std::stringstream ss;
1353 ss <<
"RooJSONFactoryWSTool() no handling for type '" << functype <<
"' implemented, skipping."
1355 <<
"there are several possible reasons for this:\n"
1356 <<
" 1. " << functype <<
" is a custom type that is not available in RooFit.\n"
1357 <<
" 2. " << functype
1358 <<
" is a ROOT class that nobody ever bothered to write a deserialization definition for.\n"
1359 <<
" 3. something is wrong with your setup, e.g. you might have called "
1360 "RooFit::JSONIO::clearFactoryExpressions() and/or never successfully read a file defining "
1361 "these expressions with RooFit::JSONIO::loadFactoryExpressions(filename)\n"
1362 <<
"either way, please make sure that:\n"
1363 <<
" 3: you are reading a file with factory expressions - call "
1364 "RooFit::JSONIO::printFactoryExpressions() "
1365 "to see what is available\n"
1366 <<
" 2 & 1: you might need to write a deserialization definition yourself. check "
1367 "https://root.cern/doc/master/group__roofit__dev__docs__hs3.html to see "
1376 std::stringstream err;
1377 err <<
"something went wrong importing function '" <<
name <<
"'.";
1411 auto &observablesNode = output[
"axes"].
set_seq();
1414 std::string
name = var->GetName();
1417 obsNode[
"name"] <<
name;
1418 if (var->getBinning().isUniform()) {
1419 obsNode[
"min"] << var->getMin();
1420 obsNode[
"max"] << var->getMax();
1421 obsNode[
"nbins"] << var->getBins();
1423 auto &edges = obsNode[
"edges"];
1425 double val = var->getBinning().binLow(0);
1427 for (
int i = 0; i < var->getBinning().numBins(); ++i) {
1428 val = var->getBinning().binHigh(i);
1429 edges.append_child() << val;
1451 for (std::size_t i = 0; i <
n; ++i) {
1452 double w = contents[i];
1476std::string makeValidNameOrError(std::string
const &in)
1478 if (!std::isalpha(in[0])) {
1483 oocoutW(
nullptr, IO) <<
"RooFitHS3: changed '" << in <<
"' to '" << out <<
"' to become a valid name";
1492 auto &labels = node[
"labels"].
set_seq();
1493 auto &indices = node[
"indices"].
set_seq();
1495 for (
auto const &item : cat) {
1496 labels.append_child() << makeValidNameOrError(item.first);
1497 indices.append_child() << item.second;
1519 " has several category observables!");
1541 auto *combinedPdfInfoNode = findRooFitInternal(*
_rootnodeOutput,
"combined_distributions");
1542 if (combinedPdfInfoNode) {
1543 for (
auto &info : combinedPdfInfoNode->children()) {
1544 if (info[
"index_cat"].val() == cat->
GetName()) {
1554 std::vector<std::unique_ptr<RooAbsData>> dataList{simPdf ?
data.split(*simPdf,
true) :
data.split(*cat,
true)};
1556 for (std::unique_ptr<RooAbsData>
const &absData : dataList) {
1557 std::string catName(absData->GetName());
1558 std::string dataName = makeValidNameOrError(catName);
1559 absData->SetName((std::string(
data.GetName()) +
"_" + dataName).c_str());
1560 datamap.
components[catName] = absData->GetName();
1584 " has several category observables!");
1602 if (
auto weightVar = variables.find(
"weightVar")) {
1603 variables.remove(*weightVar);
1608 output[
"type"] <<
"binned";
1612 return exportHisto(variables, dh->numEntries(), dh->weightArray(), output);
1621 if (
data.isWeighted() && variables.size() == 1) {
1622 bool isBinnedData =
false;
1623 auto &
x =
static_cast<RooRealVar const &
>(*variables[0]);
1624 std::vector<double> contents;
1626 for (; i <
data.numEntries(); ++i) {
1628 if (
x.getBin() != i)
1630 contents.push_back(
data.weight());
1632 if (i ==
x.getBins())
1633 isBinnedData =
true;
1635 output[
"type"] <<
"binned";
1639 return exportHisto(variables,
data.numEntries(), contents.data(), output);
1644 output[
"type"] <<
"unbinned";
1646 auto &coords = output[
"entries"].
set_seq();
1647 std::vector<double> weightVals;
1648 bool hasNonUnityWeights =
false;
1649 for (
int i = 0; i <
data.numEntries(); ++i) {
1651 coords.append_child().fill_seq(variables, [](
auto x) {
return static_cast<RooRealVar *
>(
x)->getVal(); });
1652 std::string datasetName =
data.GetName();
1653 if (
data.isWeighted()) {
1654 weightVals.push_back(
data.weight());
1655 if (
data.weight() != 1.)
1656 hasNonUnityWeights =
true;
1659 if (
data.isWeighted() && hasNonUnityWeights) {
1660 output[
"weights"].
fill_seq(weightVals);
1677 for (
JSONNode const &node : topNode[
"axes"].children()) {
1678 if (node.has_child(
"edges")) {
1679 std::vector<double> edges;
1680 for (
auto const &bound : node[
"edges"].children()) {
1681 edges.push_back(bound.val_double());
1683 auto obs = std::make_unique<RooRealVar>(node[
"name"].val().c_str(), node[
"name"].val().c_str(), edges[0],
1684 edges[edges.size() - 1]);
1685 RooBinning bins(obs->getMin(), obs->getMax());
1686 for (
auto b : edges) {
1689 obs->setBinning(bins);
1692 auto obs = std::make_unique<RooRealVar>(node[
"name"].val().c_str(), node[
"name"].val().c_str(),
1693 node[
"min"].val_double(), node[
"max"].val_double());
1694 obs->setBins(node[
"nbins"].val_int());
1713std::unique_ptr<RooDataHist>
1716 if (!
n.has_child(
"contents"))
1719 JSONNode const &contents =
n[
"contents"];
1725 if (
n.has_child(
"errors")) {
1726 errors = &
n[
"errors"];
1731 auto bins = generateBinIndices(vars);
1733 std::stringstream errMsg;
1734 errMsg <<
"inconsistent bin numbers: contents=" << contents.
num_children() <<
", bins=" << bins.size();
1737 auto dh = std::make_unique<RooDataHist>(
name,
name, vars);
1738 std::vector<double> contentVals;
1740 for (
auto const &cont : contents.
children()) {
1741 contentVals.push_back(cont.val_double());
1743 std::vector<double> errorVals;
1746 for (
auto const &err : errors->
children()) {
1747 errorVals.push_back(err.val_double());
1750 for (
size_t ibin = 0; ibin < bins.size(); ++ibin) {
1751 const double err = errors ? errorVals[ibin] : -1;
1752 dh->set(ibin, contentVals[ibin], err);
1775 std::stringstream ss;
1776 ss <<
"RooJSONFactoryWSTool() node '" <<
name <<
"' is not a map, skipping.";
1777 oocoutE(
nullptr, InputArguments) << ss.str() << std::endl;
1783 if (attrNode->has_child(
"is_const_var") && (*attrNode)[
"is_const_var"].val_int() == 1) {
1804 if (
JSONNode const *varsNode = getVariablesNode(
n)) {
1805 for (
const auto &p : varsNode->children()) {
1809 if (
auto seq =
n.find(
"functions")) {
1810 for (
const auto &p : seq->children()) {
1814 if (
auto seq =
n.find(
"distributions")) {
1815 for (
const auto &p : seq->children()) {
1822 const std::vector<CombinedData> &combDataSets,
1823 const std::vector<RooAbsData *> &singleDataSets)
1828 for (std::size_t i = 0; i < std::max(combDataSets.size(), std::size_t(1)); ++i) {
1829 const bool hasdata = i < combDataSets.size();
1830 if (hasdata && !matches(combDataSets.at(i), simpdf))
1833 std::string analysisName(simpdf->GetName());
1835 analysisName +=
"_" + combDataSets[i].name;
1842 for (
auto *
data : singleDataSets) {
1844 std::map<std::string, std::string> mapping;
1845 mapping[pdf->GetName()] =
data->GetName();
1850 if (founddata == 0) {
1857 std::string
const &analysisName,
1858 std::map<std::string, std::string>
const *dataComponents)
1864 auto &domains = analysisNode[
"domains"].
set_seq();
1866 analysisNode[
"likelihood"] << analysisName;
1869 nllNode[
"distributions"].set_seq();
1870 nllNode[
"data"].set_seq();
1872 if (dataComponents) {
1875 for (
auto const &item : simPdf->indexCat()) {
1876 const auto &dataComp = dataComponents->find(item.first);
1877 nllNode[
"distributions"].append_child() << simPdf->getPdf(item.first)->GetName();
1878 nllNode[
"data"].append_child() << dataComp->second;
1881 for (
auto it : *dataComponents) {
1882 nllNode[
"distributions"].append_child() << it.first;
1883 nllNode[
"data"].append_child() << it.second;
1887 nllNode[
"distributions"].append_child() << pdf->GetName();
1888 nllNode[
"data"].append_child() << 0;
1892 auto &extConstrNode = nllNode[
"aux_distributions"];
1893 extConstrNode.set_seq();
1895 extConstrNode.append_child() << constr->GetName();
1899 auto writeList = [&](
const char *
name,
RooArgSet const *args) {
1900 if (!args || !args->size())
1903 std::vector<std::string> names;
1904 names.reserve(args->size());
1906 names.push_back(arg->GetName());
1907 std::sort(names.begin(), names.end());
1913 auto &domainsNode = rootnode[
"domains"];
1915 auto writeProductDomain = [&](
const char *suffix,
RooArgSet const *args) {
1916 if (!args || args->empty())
1918 const std::string domainName = analysisName + suffix;
1919 domains.append_child() << domainName;
1931 auto &modelConfigAux =
getRooFitInternal(rootnode,
"ModelConfigs", analysisName);
1932 modelConfigAux.set_map();
1933 modelConfigAux[
"pdfName"] << pdf->GetName();
1934 modelConfigAux[
"mcName"] << mc.
GetName();
1948 _domains = std::make_unique<RooFit::JSONIO::Detail::Domains>();
1953 std::vector<RooAbsPdf *> allpdfs;
1955 if (!arg->hasClients()) {
1956 if (
auto *pdf =
dynamic_cast<RooAbsPdf *
>(arg)) {
1957 allpdfs.push_back(pdf);
1961 sortByName(allpdfs);
1962 std::set<std::string> exportedObjectNames;
1966 std::vector<RooAbsReal *> allfuncs;
1967 for (
auto &arg :
_workspace.allFunctions()) {
1968 if (!arg->hasClients()) {
1969 if (
auto *func =
dynamic_cast<RooAbsReal *
>(arg)) {
1970 allfuncs.push_back(func);
1974 sortByName(allfuncs);
1979 exportAttributes(arg,
n);
1983 std::vector<RooAbsData *> alldata;
1985 alldata.push_back(
d);
1987 sortByName(alldata);
1989 std::vector<RooAbsData *> singleData;
1990 std::vector<RooJSONFactoryWSTool::CombinedData> combData;
1991 for (
auto &
d : alldata) {
1993 if (!
data.components.empty())
1994 combData.push_back(
data);
1996 singleData.push_back(
d);
1999 for (
auto &
d : alldata) {
2010 exportParameterStepWidths(
_workspace, allpdfs, alldata,
n);
2018 bool do_export =
false;
2019 for (
const auto &pdf : allpdfs) {
2020 if (pdf->dependsOn(*arg)) {
2026 snapshotSorted.
add(*arg);
2029 snapshotSorted.
sort();
2030 std::string
name(snsh->GetName());
2031 if (
name !=
"default_values") {
2050 std::stringstream ss(s);
2062 std::stringstream ss(s);
2073 std::stringstream ss;
2085 std::stringstream ss;
2100 auto &metadata =
n[
"metadata"].set_map();
2107 std::string versionName =
gROOT->GetVersion();
2110 std::replace(versionName.begin(), versionName.end(),
'/',
'.');
2111 rootInfo[
"version"] << versionName;
2139 std::ofstream out(
filename.c_str());
2168 std::ofstream out(
filename.c_str());
2179 if (
auto seq = attrNode->find(
"tags")) {
2180 for (
auto &
a : seq->children()) {
2181 if (
a.val() == attrib)
2191 auto &tags = (*node)[
"tags"];
2201 if (
auto dict = attrNode->find(
"dict")) {
2202 if (
auto *
a = dict->find(attrib)) {
2210 const std::string &
value)
2213 auto &dict = (*node)[
"dict"];
2215 dict[attrib] <<
value;
2231 auto metadata =
n.find(
"metadata");
2232 if (!metadata || !metadata->find(
"hs3_version")) {
2233 std::stringstream ss;
2234 ss <<
"The HS3 version is missing in the JSON!\n"
2235 <<
"Please include the HS3 version in the metadata field, e.g.:\n"
2236 <<
" \"metadata\" :\n"
2243 _domains = std::make_unique<RooFit::JSONIO::Detail::Domains>();
2244 if (
auto domains =
n.find(
"domains")) {
2261 if (
auto seq =
n.find(
"functions")) {
2262 if (seq->is_seq()) {
2264 for (
const auto &p : seq->children()) {
2269 if (
auto seq =
n.find(
"distributions")) {
2270 if (seq->is_seq()) {
2272 for (
const auto &p : seq->children()) {
2280 if (
auto paramPointsNode =
n.find(
"parameter_points")) {
2281 for (
const auto &snsh : paramPointsNode->children()) {
2286 for (
const auto &var : snsh[
"parameters"].children()) {
2288 configureVariable(*
_domains, var, *rrv);
2302 importAttributes(arg, elem);
2312 std::vector<std::unique_ptr<RooAbsData>> datasets;
2313 if (
auto dataNode =
n.find(
"data")) {
2314 for (
const auto &p : dataNode->children()) {
2321 if (
auto analysesNode =
n.find(
"analyses")) {
2329 for (
auto const &
d : datasets) {
2332 for (
auto const &obs : *
d->get()) {
2333 if (
auto *rrv =
dynamic_cast<RooRealVar *
>(obs)) {
2334 _workspace.var(rrv->GetName())->setBinning(rrv->getBinning());
2356 JSONNode const &rootnode = tree->rootnode();
2358 if (this->
workspace()->getSnapshot(
"default_values")) {
2361 importParameterStepWidths(*this->
workspace(), rootnode);
2374 std::ifstream infile(
filename.c_str());
2375 if (!infile.is_open())
2390 JSONNode const &rootnode = tree->rootnode();
2392 importParameterStepWidths(*this->
workspace(), rootnode);
2405 std::ifstream infile(
filename.c_str());
2406 if (!infile.is_open())
2417 bool isVariable =
true;
2418 if (
n.find(
"type")) {
2431 std::unique_ptr<RooFit::Detail::JSONTree> tree =
varJSONString(elementNode);
2433 _domains = std::make_unique<RooFit::JSONIO::Detail::Domains>();
2434 if (
auto domains =
n.find(
"domains"))
2440 JSONNode const *varsNode = getVariablesNode(
n);
2441 const auto &p = varsNode->
child(0);
2444 auto paramPointsNode =
n.find(
"parameter_points");
2445 const auto &snsh = paramPointsNode->child(0);
2448 const auto &var = snsh[
"parameters"].child(0);
2450 configureVariable(*
_domains, var, *rrv);
2458 importAttributes(arg, elem);
2487 throw std::runtime_error(s);
2500 for (
char c : str) {
2505 case '(':
result +=
'_';
break;
2510 case '.':
result +=
"_dot_";
break;
2511 case '@':
result +=
"at";
break;
2512 case '-':
result +=
"minus";
break;
2513 case '/':
result +=
"_div_";
break;
2528 if (onlyModelConfig) {
2537 for (
auto *pdf : ws.
allPdfs()) {
2538 if (!pdf->hasClients()) {
2544 if (!func->hasClients()) {
2563 auto *snshSet =
dynamic_cast<RooArgSet *
>(snsh);
2565 tmpWS.
saveSnapshot(snshSet->GetName(), *snshSet,
true);
2579 auto sanitizeIfNeeded = [](
auto const &list) {
2580 for (
auto *obj : list) {
2586 sanitizeIfNeeded(tmpWS.
allVars());
2588 sanitizeIfNeeded(tmpWS.
allPdfs());
2596 for (
auto *obj : *
data->get()) {
2603 for (
auto *obj : *
data->get()) {
2609 auto *snsh =
dynamic_cast<RooArgSet *
>(snshObj);
2611 std::cerr <<
"Warning: found snapshot that is not a RooArgSet, skipping\n";
2621 for (
auto *arg : *snsh) {
2631 if (
auto *named =
dynamic_cast<TNamed *
>(obj)) {
2632 named->SetName(
sanitizeName(named->GetName()).c_str());
2634 std::cerr <<
"Warning: object " << obj->GetName() <<
" is not TNamed, cannot rename.\n";
2645 for (
auto *obs : mc->GetObservables()->get()) {
2650 for (
auto *poi : mc->GetParametersOfInterest()->get()) {
2655 for (
auto *nuis : mc->GetNuisanceParameters()->get()) {
2660 for (
auto *glob : mc->GetGlobalObservables()->get()) {
2667 std::string wsName = std::string{ws.
GetName()} +
"_sanitized";
2669 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)
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 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 filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void w
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void 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 WindowAttributes_t attr
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
static std::unique_ptr< JSONTree > create()
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...
RooFit::OwningPtr< RooArgSet > getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
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.
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.
void setError(double value)
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