71#include <initializer_list>
84bool isReservedExpressionIdentifier(
const std::string &arg)
86 return arg ==
"PI" || arg ==
"EULER" || arg ==
"TMath";
103std::set<std::string> extractArguments(std::string expr)
106 expr.erase(std::remove_if(expr.begin(), expr.end(), [](
unsigned char c) { return std::isspace(c); }), expr.end());
108 std::set<std::string> arguments;
109 size_t startidx = expr.size();
110 for (
size_t i = 0; i < expr.size(); ++i) {
111 if (startidx >= expr.size()) {
112 if (isalpha(expr[i])) {
117 startidx = expr.size();
121 if (!isdigit(expr[i]) && !isalpha(expr[i]) && expr[i] !=
'_') {
122 if (expr[i] ==
'(') {
123 startidx = expr.size();
126 std::string arg(expr.substr(startidx, i - startidx));
127 startidx = expr.size();
128 if (!isReservedExpressionIdentifier(arg)) {
129 arguments.insert(arg);
134 if (startidx < expr.size()) {
135 std::string arg(expr.substr(startidx));
136 if (!isReservedExpressionIdentifier(arg)) {
137 arguments.insert(arg);
143void replaceIdentifier(
TString &expr, std::string_view identifier, std::string_view replacement)
145 std::string in(expr.
Data());
147 out.reserve(in.size());
149 for (std::size_t pos = 0; pos < in.size();) {
150 const bool matches = in.compare(pos, identifier.size(), identifier) == 0;
151 const bool beforeIdentifier =
152 pos > 0 && (std::isalnum(
static_cast<unsigned char>(in[pos - 1])) || in[pos - 1] ==
'_');
153 const std::size_t end = pos + identifier.size();
154 const bool afterIdentifier =
155 end < in.size() && (std::isalnum(
static_cast<unsigned char>(in[end])) || in[end] ==
'_');
156 if (matches && !beforeIdentifier && !afterIdentifier) {
157 out.append(replacement);
160 out.push_back(in[pos]);
168bool isIdentifierChar(
char c)
170 return std::isalnum(
static_cast<unsigned char>(
c)) ||
c ==
'_';
173std::string trimmed(std::string
const &str)
175 const auto begin = str.find_first_not_of(
" \t\n");
176 if (begin == std::string::npos) {
179 return str.substr(begin, str.find_last_not_of(
" \t\n") - begin + 1);
183std::size_t findClosingBracket(std::string
const &str, std::size_t open)
186 for (std::size_t i = open; i < str.size(); ++i) {
187 if (str[i] ==
'(' || str[i] ==
'[') {
189 }
else if ((str[i] ==
')' || str[i] ==
']') && --depth == 0) {
193 return std::string::npos;
197std::vector<std::string> splitTopLevelCommas(std::string
const &str)
199 std::vector<std::string> parts;
201 std::size_t start = 0;
202 for (std::size_t i = 0; i < str.size(); ++i) {
203 if (str[i] ==
'(' || str[i] ==
'[') {
205 }
else if (str[i] ==
')' || str[i] ==
']') {
207 }
else if (str[i] ==
',' && depth == 0) {
208 parts.push_back(str.substr(start, i - start));
212 parts.push_back(str.substr(start));
217std::string stripEnclosingParentheses(std::string str)
220 while (str.size() >= 2 && str.front() ==
'(' && findClosingBracket(str, 0) == str.size() - 1) {
221 str = trimmed(str.substr(1, str.size() - 2));
228std::string ifElseToTernary(std::string
const &expr)
230 static const std::string keyword =
"ifelse";
233 while (pos < expr.size()) {
234 const std::size_t found = expr.find(keyword, pos);
235 if (found == std::string::npos) {
238 const std::size_t
open = expr.find_first_not_of(
" \t", found + keyword.size());
240 (found == 0 || !isIdentifierChar(expr[found - 1])) && open != std::string::npos && expr[open] ==
'(';
241 const std::size_t
close = isCall ? findClosingBracket(expr, open) : std::string::npos;
242 const auto args =
close != std::string::npos ? splitTopLevelCommas(expr.substr(open + 1, close - open - 1))
243 : std::vector<std::string>{};
244 if (args.size() != 3) {
245 out += expr.substr(pos, found + keyword.size() - pos);
246 pos = found + keyword.size();
249 out += expr.substr(pos, found - pos);
250 out +=
"((" + ifElseToTernary(trimmed(args[0])) +
")?(" + ifElseToTernary(trimmed(args[1])) +
"):(" +
251 ifElseToTernary(trimmed(args[2])) +
"))";
254 return out + expr.substr(pos);
257void translateImportedExpression(
TString &expr)
259 replaceIdentifier(expr,
"PI",
"TMath::Pi()");
260 replaceIdentifier(expr,
"EULER",
"TMath::E()");
261 if (std::string(expr.
Data()).find(
"ifelse") != std::string::npos) {
262 expr = ifElseToTernary(expr.
Data()).c_str();
266int readPositiveInteger(
const JSONNode &node,
const std::string &context)
273 value >
static_cast<double>(std::numeric_limits<int>::max())) {
276 return static_cast<int>(
value);
279std::unique_ptr<RooAbsBinning>
280readFormulaAxisBinning(
const JSONNode &axis,
const std::string &axisName,
const std::string &formulaName)
282 const std::string context =
"axis '" + axisName +
"' of generic formula '" + formulaName +
"'";
283 const bool hasEdges = axis.
has_child(
"edges");
284 const bool hasMin = axis.
has_child(
"min");
285 const bool hasMax = axis.
has_child(
"max");
286 const bool hasNBins = axis.
has_child(
"nbins");
288 if (hasEdges && hasNBins) {
293 const JSONNode &edgesNode = axis[
"edges"];
294 if (!edgesNode.
is_seq()) {
298 std::vector<double> edges;
300 for (
const JSONNode &edgeNode : edgesNode.children()) {
301 if (!edgeNode.is_number()) {
304 const double edge = edgeNode.val_double();
305 if (!std::isfinite(edge)) {
308 if (!edges.empty() && edge <= edges.back()) {
311 edges.push_back(edge);
313 if (edges.size() < 2) {
318 if ((hasMin && (!axis[
"min"].is_number() || axis[
"min"].val_double() != edges.front())) ||
319 (hasMax && (!axis[
"max"].is_number() || axis[
"max"].val_double() != edges.back()))) {
322 return std::make_unique<RooBinning>(
static_cast<int>(edges.size() - 1), edges.data());
325 if (!hasMin || !hasMax || !hasNBins) {
329 if (!axis[
"min"].is_number() || !axis[
"max"].is_number()) {
334 if (!std::isfinite(min) || !std::isfinite(max) || max <= min) {
337 return std::make_unique<RooUniformBinning>(min, max, readPositiveInteger(axis[
"nbins"], context));
340template <
class RooArg_t>
341void importFormulaBinnings(RooArg_t &arg,
const JSONNode &node)
347 const JSONNode &axes = node[
"axes"];
350 "' must be a sequence");
353 std::set<std::string> axisNames;
354 for (
const JSONNode &axis : axes.children()) {
357 "' must be a map with a \"name\"");
359 const std::string axisName = axis[
"name"].
val();
360 if (!axisNames.insert(axisName).second) {
364 auto *observable =
dynamic_cast<RooAbsRealLValue *
>(arg.getParameter(axisName.c_str()));
367 "axis '" + axisName +
"' is not a real-valued formula variable of generic formula '" + arg.GetName() +
"'");
370 std::unique_ptr<RooAbsBinning> binning = readFormulaAxisBinning(axis, axisName, arg.GetName());
371 arg.setBinning(*observable, *binning,
false);
375template <
class RooArg_t>
379 if (!
p.has_child(
"expression")) {
382 TString formula(
p[
"expression"].val());
383 translateImportedExpression(formula);
385 for (
const auto &
d : extractArguments(formula.Data())) {
388 RooArg_t arg{
name.c_str(), formula, dependents};
389 importFormulaBinnings(arg,
p);
425 if (
p.has_child(
"extended")) {
428 const bool extended =
p[
"extended"].val_bool();
429 const std::size_t nSummands =
p.has_child(
"summands") ?
p[
"summands"].num_children() : 0;
430 const std::size_t nCoefficients =
p.has_child(
"coefficients") ?
p[
"coefficients"].num_children() : 0;
431 const std::string counts =
432 std::to_string(nCoefficients) +
" coefficients for " + std::to_string(nSummands) +
" summands";
433 if (extended && nCoefficients > 0 && nCoefficients + 1 == nSummands) {
435 ", which defines a non-extended mixture");
437 if (!extended && nCoefficients == 0 && nSummands > 0) {
439 ", which defines an extended mixture of extended distributions");
441 if (!extended && nCoefficients == nSummands) {
443 "RooFit can use it as extended because it has one coefficient per summand. " +
444 "Don't use the extended likelihood term when fitting it.");
464template <
bool Div
ideByBinW
idth>
485 obs->GetName() +
"' as indicated by parent RooBinSamplingPdf '" +
name +
489 if (!
p.has_child(
"epsilon")) {
492 double epsilon(
p[
"epsilon"].val_double());
499template <
class RooArg_t>
505 if constexpr (std::is_same_v<RooArg_t, RooRealSumPdf>) {
506 const bool extended =
p.has_child(
"extended") &&
p[
"extended"].val_bool();
514template <
class RooArg_t>
518 if (!
p.has_child(
"coefficients")) {
525 for (
const auto &coef :
p[
"coefficients"].children()) {
529 if (order == 0 && (coef.val() ==
"1.0" || coef.val() ==
"1")) {
531 }
else if (coefs.empty() && (coef.val() ==
"0.0" || coef.val() ==
"0")) {
592 if (
p.has_child(
"normalization")) {
594 normSetPtr = &normSet;
597 bool hasDomain =
p.has_child(
"domain");
599 domain =
p[
"domain"].val();
603 hasDomain ? domain.c_str() :
nullptr);
612 Int_t order =
p[
"order"].val_int();
613 double eps =
p[
"eps"].val_double();
614 if (
p.has_child(
"normalization")) {
628 Int_t order =
p[
"ipOrder"].val_int();
631 if (
p.has_child(
"conv_func")) {
646 if (
p.has_child(
"range")) {
647 std::string rangeName =
p[
"range"].val();
662 const std::string muName =
p[
"mu"].val();
663 const std::string sigmaName =
p[
"sigma"].val();
664 const bool isTransformed =
endsWith(muName,
"_lognormal_log");
665 const std::string suffixToRemove = isTransformed ?
"_lognormal_log" :
"";
710 const std::string constParamName =
p[
"c"].val();
711 const bool isInverted =
endsWith(constParamName,
"_exponential_inverted");
712 const std::string suffixToRemove = isInverted ?
"_exponential_inverted" :
"";
723 bool has_cov =
p.has_child(
"covariances");
724 bool has_corr =
p.has_child(
"correlations") &&
p.has_child(
"standard_deviations");
725 if (!has_cov && !has_corr) {
732 auto checkSquare = [&](
const char *key, std::size_t
n) {
733 if (
p[key].num_children() !=
n) {
737 for (
const auto &row :
p[key].children()) {
738 if (!row.is_seq() || row.num_children() !=
n) {
745 int n =
p[
"covariances"].num_children();
746 checkSquare(
"covariances",
n);
749 for (
const auto &row :
p[
"covariances"].children()) {
751 for (
const auto &val : row.children()) {
752 covmat(i, j) = val.val_double();
758 std::vector<double> variances;
759 variances <<
p[
"standard_deviations"];
760 checkSquare(
"correlations", variances.size());
761 covmat.
ResizeTo(variances.size(), variances.size());
763 for (
const auto &row :
p[
"correlations"].children()) {
765 for (
const auto &val : row.children()) {
766 covmat(i, j) = val.val_double() * variances[i] * variances[j];
792 if (!
p.has_child(
"parameters")) {
797 if (!
p.has_child(
"axes")) {
798 std::stringstream ss;
799 ss <<
"No axes given in '" <<
name <<
"'"
800 <<
". Using default binning (uniform; nbins=100). If needed, export the Workspace to JSON with a newer "
801 <<
"Root version that supports custom ParamHistFunc binnings(>=6.38.00)." << std::endl;
815 if (!
p.has_child(
"x")) {
818 if (!
p.has_child(
"x0") || !
p.has_child(
"y0")) {
825 std::string algo =
p.has_child(
"interpolation") ?
p[
"interpolation"].val() :
"poly3";
827 if (algo ==
"poly3") {
829 }
else if (algo ==
"poly5") {
833 "': allowed are 'poly3' and 'poly5'");
835 const bool logx =
p.has_child(
"logx") ?
p[
"logx"].val_bool() :
false;
836 const bool logy =
p.has_child(
"logy") ?
p[
"logy"].val_bool() :
false;
839 std::vector<double> x0;
840 std::vector<double> y0;
844 if (x0.size() != y0.size()) {
846 ", y0 has " + std::to_string(y0.size()));
854 std::span<const double>(y0.data(), y0.size()), order, logx, logy);
863 DeprecatedKeyImporter(std::string key, std::string replacement)
864 : _key{std::move(key)}, _replacement{std::move(replacement)}
871 _replacement +
"\" instead.");
878 const std::string _key;
879 const std::string _replacement;
880 mutable bool _warned =
false;
885constexpr const char *tailKeys[] = {
"alpha_L",
"n_L",
"alpha_R",
"n_R"};
887bool hasAny(
const JSONNode &
p, std::initializer_list<const char *> keys)
889 for (
const char *key : keys) {
890 if (
p.has_child(key)) {
897bool hasDoubleSidedKeys(
const JSONNode &
p)
899 return hasAny(
p, {
"alpha_L",
"n_L",
"alpha_R",
"n_R",
"sigma_L",
"sigma_R"});
907 const std::string context =
type +
" '" +
name +
"'";
909 const bool asymmetricTails = hasAny(
p, {
"alpha_L",
"n_L",
"alpha_R",
"n_R"});
910 const bool symmetricTails = hasAny(
p, {
"alpha",
"n"});
911 if (symmetricTails && !symmetricShorthand) {
913 "\"n_L\", \"alpha_R\" and \"n_R\"");
915 if (symmetricTails && asymmetricTails) {
917 " must not combine \"alpha\"/\"n\" with \"alpha_L\"/\"n_L\"/\"alpha_R\"/\"n_R\"");
919 if (asymmetricTails || !symmetricTails) {
920 for (
const char *key : tailKeys) {
921 if (!
p.has_child(key)) {
923 "\": \"alpha_L\", \"n_L\", \"alpha_R\" and \"n_R\" are all required");
926 }
else if (!
p.has_child(
"alpha") || !
p.has_child(
"n")) {
930 const bool asymmetricWidths = hasAny(
p, {
"sigma_L",
"sigma_R"});
931 if (asymmetricWidths &&
p.has_child(
"sigma")) {
934 if (asymmetricWidths && !(
p.has_child(
"sigma_L") &&
p.has_child(
"sigma_R"))) {
937 if (!asymmetricWidths && !
p.has_child(
"sigma")) {
961 if (!CrystalBall::hasDoubleSidedKeys(
p)) {
966 "\"alpha_R\", \"n_R\", \"sigma_L\" or \"sigma_R\" is deprecated, please use "
967 "\"crystalball_doublesided_dist\" for the double-sided Crystal Ball.");
970 CrystalBall::importDoubleSided(tool,
p,
"crystalball_dist",
true);
975 mutable bool _warned =
false;
980 CrystalBall::importDoubleSided(tool,
p,
"crystalball_doublesided_dist",
false);
990 auto const *constVar =
dynamic_cast<RooConstVar const *
>(&arg);
991 std::istringstream stream(arg.
GetName());
993 if (constVar && (stream >>
value) && stream.eof()) {
994 node << constVar->getVal();
1006 writeReference(elem[
"m"], pdf->x());
1007 writeReference(elem[
"m0"], pdf->x0());
1008 if (!pdf->alphaR() || !pdf->nR()) {
1009 elem[
"type"] <<
"crystalball_dist";
1010 writeReference(elem[
"sigma"], pdf->sigmaL());
1011 writeReference(elem[
"alpha"], pdf->alphaL());
1012 writeReference(elem[
"n"], pdf->nL());
1015 elem[
"type"] << key;
1016 if (&pdf->sigmaL() == &pdf->sigmaR()) {
1017 writeReference(elem[
"sigma"], pdf->sigmaL());
1019 writeReference(elem[
"sigma_L"], pdf->sigmaL());
1020 writeReference(elem[
"sigma_R"], pdf->sigmaR());
1022 writeReference(elem[
"alpha_L"], pdf->alphaL());
1023 writeReference(elem[
"n_L"], pdf->nL());
1024 writeReference(elem[
"alpha_R"], *pdf->alphaR());
1025 writeReference(elem[
"n_R"], *pdf->nR());
1029template <
class RooArg_t>
1032 const RooArg_t *pdf =
static_cast<const RooArg_t *
>(func);
1033 elem[
"type"] << key;
1036 elem[
"extended"] << (pdf->extendMode() != RooArg_t::CanNotBeExtended);
1040template <
class RooArg_t>
1043 auto const *pdf =
static_cast<const RooArg_t *
>(func);
1044 elem[
"type"] << key;
1047 if constexpr (std::is_same_v<RooArg_t, RooRealSumPdf>) {
1053template <
class RooArg_t>
1056 const RooArg_t *hf =
static_cast<const RooArg_t *
>(func);
1057 elem[
"type"] << key;
1063template <
class RooArg_t>
1067 if (!
p.has_child(
"data")) {
1070 std::unique_ptr<RooDataHist> dataHist =
1072 tool->
wsEmplace<RooArg_t>(
name, *dataHist->get(), *dataHist);
1079 elem[
"type"] << key;
1082 elem[
"epsilon"] << pdf->
epsilon();
1089 elem[
"type"] << (pdf->
divideByBinWidth() ?
"inverse_binvolume" :
"binvolume");
1094void cleanExpression(
TString &expr)
1100 replaceIdentifier(expr,
"TMath::Exp",
"exp");
1101 replaceIdentifier(expr,
"TMath::Min",
"min");
1102 replaceIdentifier(expr,
"TMath::Max",
"max");
1103 replaceIdentifier(expr,
"TMath::Log",
"log");
1104 replaceIdentifier(expr,
"TMath::Log10",
"log10");
1105 replaceIdentifier(expr,
"TMath::Cos",
"cos");
1106 replaceIdentifier(expr,
"TMath::CosH",
"cosh");
1107 replaceIdentifier(expr,
"TMath::Sin",
"sin");
1108 replaceIdentifier(expr,
"TMath::SinH",
"sinh");
1109 replaceIdentifier(expr,
"TMath::Sqrt",
"sqrt");
1110 replaceIdentifier(expr,
"TMath::Power",
"pow");
1111 replaceIdentifier(expr,
"TMath::Erf",
"erf");
1112 replaceIdentifier(expr,
"TMath::Erfc",
"erfc");
1113 replaceIdentifier(expr,
"TMath::Floor",
"floor");
1114 replaceIdentifier(expr,
"TMath::Ceil",
"ceil");
1115 replaceIdentifier(expr,
"TMath::Abs",
"abs");
1116 replaceIdentifier(expr,
"TMath::Tan",
"tan");
1117 replaceIdentifier(expr,
"TMath::TanH",
"tanh");
1118 replaceIdentifier(expr,
"TMath::ASin",
"asin");
1119 replaceIdentifier(expr,
"TMath::ACos",
"acos");
1120 replaceIdentifier(expr,
"TMath::ATan",
"atan");
1121 replaceIdentifier(expr,
"TMath::ATan2",
"atan2");
1122 replaceIdentifier(expr,
"TMath::Pi()",
"PI");
1123 replaceIdentifier(expr,
"TMath::E()",
"EULER");
1126bool ternariesToIfElse(std::string
const &in, std::string &out);
1129bool ternaryPartToIfElse(std::string
const &in, std::string &out)
1132 std::size_t question = std::string::npos;
1134 for (std::size_t i = 0; i < in.size() && question == std::string::npos; ++i) {
1135 const char c = in[i];
1136 if (
c ==
'(' ||
c ==
'[') {
1138 }
else if (
c ==
')' ||
c ==
']') {
1140 }
else if (
c ==
':' && i + 1 < in.size() && in[i + 1] ==
':') {
1142 }
else if (depth == 0 &&
c ==
':') {
1144 }
else if (depth == 0 &&
c ==
'?') {
1146 }
else if (depth == 0 &&
c ==
',') {
1151 if (question == std::string::npos) {
1154 for (std::size_t i = 0; i < in.size(); ++i) {
1155 if (in[i] ==
')' || in[i] ==
']') {
1158 if (in[i] !=
'(' && in[i] !=
'[') {
1162 const std::size_t
close = findClosingBracket(in, i);
1163 if (close == std::string::npos) {
1166 const std::string inner = in.substr(i + 1, close - i - 1);
1167 std::string innerOut;
1168 if (!ternariesToIfElse(inner, innerOut)) {
1172 const std::string before = trimmed(in.substr(0, i));
1173 const bool isGrouping = in[i] ==
'(' && (before.empty() || !isIdentifierChar(before.back()));
1174 if (isGrouping && innerOut != trimmed(inner) &&
startsWith(innerOut,
"ifelse(") &&
1175 findClosingBracket(innerOut, std::string(
"ifelse").
size()) == innerOut.size() - 1) {
1178 out += in[i] + innerOut + in[
close];
1186 std::size_t colon = std::string::npos;
1189 for (std::size_t i = question + 1; i < in.size() && colon == std::string::npos; ++i) {
1190 const char c = in[i];
1191 if (
c ==
'(' ||
c ==
'[') {
1193 }
else if (
c ==
')' ||
c ==
']') {
1195 }
else if (
c ==
':' && i + 1 < in.size() && in[i + 1] ==
':') {
1197 }
else if (depth == 0 &&
c ==
'?') {
1199 }
else if (depth == 0 &&
c ==
':') {
1207 if (colon == std::string::npos) {
1211 std::string condition;
1213 std::string ifFalse;
1214 if (!ternaryPartToIfElse(stripEnclosingParentheses(in.substr(0, question)), condition) ||
1215 !ternaryPartToIfElse(stripEnclosingParentheses(in.substr(question + 1, colon - question - 1)), ifTrue) ||
1216 !ternaryPartToIfElse(stripEnclosingParentheses(in.substr(colon + 1)), ifFalse)) {
1219 if (condition.empty() || ifTrue.empty() || ifFalse.empty()) {
1222 out =
"ifelse(" + condition +
"," + ifTrue +
"," + ifFalse +
")";
1228bool ternariesToIfElse(std::string
const &in, std::string &out)
1232 for (std::string
const &part : splitTopLevelCommas(in)) {
1233 std::string partOut;
1234 if (!ternaryPartToIfElse(part, partOut)) {
1237 out += (first ?
"" :
",") + partOut;
1243template <
class RooArg_t>
1246 const RooArg_t *pdf =
static_cast<const RooArg_t *
>(func);
1247 elem[
"type"] << key;
1248 TString expression(pdf->expression());
1249 cleanExpression(expression);
1256 for (
size_t idx = pdf->nParameters(); idx--;) {
1257 const RooAbsArg *par = pdf->getParameter(idx);
1258 expression.ReplaceAll((
"x[" + std::to_string(idx) +
"]").c_str(), par->
GetName());
1259 expression.ReplaceAll((
"@" + std::to_string(idx)).c_str(), par->
GetName());
1261 if (expression.Contains(
"?")) {
1262 std::string rewritten;
1263 if (ternariesToIfElse(expression.Data(), rewritten)) {
1264 expression = rewritten.c_str();
1267 "expression of '") +
1268 func->
GetName() +
"' to ifelse(), exporting the expression unchanged.");
1271 elem[
"expression"] << expression.Data();
1273 for (
const RooAbsArg *dependent : pdf->dependents()) {
1274 auto const *observable =
dynamic_cast<const RooAbsRealLValue *
>(dependent);
1278 const RooAbsBinning *binning = pdf->getBinning(*observable);
1283 auto &axes = elem[
"axes"];
1284 if (!axes.is_seq()) {
1287 auto &axis = axes.append_child().set_map();
1288 axis[
"name"] << observable->GetName();
1297template <
class RooArg_t>
1300 auto const *pdf =
static_cast<const RooArg_t *
>(func);
1301 elem[
"type"] << key;
1302 elem[
"x"] << pdf->x().GetName();
1303 auto &coefs = elem[
"coefficients"].
set_seq();
1304 for (
int i = 0; i < pdf->lowestOrder(); ++i) {
1307 for (
const auto &coef : pdf->coefList()) {
1315 auto *pdf =
static_cast<const RooPoisson *
>(func);
1316 elem[
"type"] << key;
1317 elem[
"x"] << pdf->getX().GetName();
1318 elem[
"mean"] << pdf->getMean().GetName();
1319 elem[
"integer"] << !pdf->getNoRounding();
1329 auto *pdf =
static_cast<const RooDecay *
>(func);
1330 elem[
"type"] << key;
1331 elem[
"t"] << pdf->getT().GetName();
1332 elem[
"tau"] << pdf->getTau().GetName();
1333 elem[
"resolutionModel"] << pdf->getModel().GetName();
1334 elem[
"decayType"] << pdf->getDecayType();
1346 elem[
"type"] << key;
1347 elem[
"x"] << pdf->convVar().GetName();
1355 elem[
"type"] << key;
1356 elem[
"x"] << pdf->convVar().GetName();
1357 elem[
"mean"] << pdf->getMean().GetName();
1358 elem[
"sigma"] << pdf->getSigma().GetName();
1366 elem[
"type"] << key;
1367 elem[
"x"] << pdf->getX().GetName();
1369 auto &m0 = pdf->getMedian();
1370 auto &k = pdf->getShapeK();
1372 if (pdf->useStandardParametrization()) {
1373 elem[
"mu"] << m0.GetName();
1374 elem[
"sigma"] << k.GetName();
1386 elem[
"type"] << key;
1387 elem[
"x"] << pdf->variable().GetName();
1388 auto &
c = pdf->coefficient();
1389 if (pdf->negateCoefficient()) {
1390 elem[
"c"] <<
c.GetName();
1401 elem[
"type"] << key;
1404 elem[
"covariances"].
fill_mat(pdf->covarianceMatrix());
1411 elem[
"type"] << key;
1413 TString formula(pdf->function().GetExpFormula());
1414 formula.ReplaceAll(
"x", pdf->observables()[0].GetName());
1415 formula.ReplaceAll(
"y", pdf->observables()[1].GetName());
1416 formula.ReplaceAll(
"z", pdf->observables()[2].GetName());
1417 for (
size_t i = 0; i < pdf->parameters().
size(); ++i) {
1419 formula.ReplaceAll(pname, pdf->parameters()[i].GetName());
1421 elem[
"expression"] << formula.Data();
1428 elem[
"type"] << key;
1429 elem[
"x"] << pdf->getX().GetName();
1430 elem[
"function"] << pdf->getFunc().GetName();
1431 if (!pdf->getNset().empty()) {
1434 elem[
"order"] << pdf->order();
1435 elem[
"eps"] << pdf->eps();
1442 elem[
"type"] << key;
1443 std::string integrand = integral->integrand().GetName();
1444 elem[
"integrand"] << integrand;
1445 if (integral->intRange()) {
1446 elem[
"domain"] << integral->intRange();
1449 if (
RooArgSet const *funcNormSet = integral->funcNormSet()) {
1458 elem[
"type"] << key;
1459 if (
auto convFunc = pdf->getPdfConvVar()) {
1460 elem[
"conv_func"] << convFunc->GetName();
1462 elem[
"conv_var"] << pdf->getConvVar().GetName();
1463 elem[
"pdf1"] << pdf->getPdf1().GetName();
1464 elem[
"pdf2"] << pdf->getPdf2().GetName();
1465 elem[
"ipOrder"] << pdf->getInterpolationOrder();
1472 elem[
"type"] << key;
1473 if (
auto rangeName = pdf->getRangeName()) {
1474 elem[
"range"] << rangeName->GetName();
1476 elem[
"dist"] << pdf->pdf().GetName();
1477 elem[
"rate"] << pdf->getN().GetName();
1484 elem[
"type"] << key;
1487 auto &observablesNode = elem[
"axes"].
set_seq();
1497 auto const *rs =
static_cast<RooSpline const *
>(func);
1499 elem[
"type"] << key;
1502 elem[
"x"] << rs->x().GetName();
1506 elem[
"interpolation"] << (rs->order() == 5 ?
"poly5" :
"poly3");
1507 elem[
"logx"] << rs->logx();
1508 elem[
"logy"] << rs->logy();
1511 TSpline const &sp = rs->spline();
1512 auto &x0 = elem[
"x0"].
set_seq();
1513 auto &y0 = elem[
"y0"].
set_seq();
1516 for (
int i = 0; i <
np; ++i) {
1520 x0.append_child() << xk;
1521 y0.append_child() << yk;
1529 if (node[
"type"].val() !=
"density_function_dist")
1535 bool selfNormalized =
false;
1537 auto sn = node.find(
"self_normalized");
1540 sn = node.find(
"selfnormalized");
1542 selfNormalized = sn->val_bool();
1554 node[
"type"] << key;
1558 auto const *funcProxy =
dynamic_cast<RooRealProxy const *
>(pdf->getProxy(0));
1559 if (!funcProxy || !funcProxy->absArg())
1562 node[
"function"] << funcProxy->absArg()->GetName();
1563 if (pdf->selfNormalized())
1564 node[
"self_normalized"] <<
true;
1585 FuncExporter(std::string key,
bool autoExportDependants)
1586 : _key{std::move(key)}, _autoExportDependants{autoExportDependants}
1589 std::string
const &key()
const override {
return _key; }
1590 bool autoExportDependants()
const override {
return _autoExportDependants; }
1593 return Func(tool, func, elem, _key);
1597 const std::string _key;
1598 const bool _autoExportDependants;
1608void registerExporter(
TClass const *cl, std::string key,
bool topPriority =
true,
bool autoExportDependants =
true)
1615 registerImporter<importWrapperPdf>(
"density_function_dist");
1616 registerImporter<importExtendPdf>(
"rate_extended_dist");
1618 registerImporter<importCrystalBallDoubleSided>(
"crystalball_doublesided_dist");
1621 std::make_unique<DeprecatedKeyImporter>(
"binsampling",
"binsampling_dist"));
1623 "mixture_resolution_model", std::make_unique<DeprecatedKeyImporter>(
"mixture_resolution_model",
"mixture_model"));
1625 "delta_resolution_model",
"truth_model_function"));
1627 "gauss_resolution_model",
"gauss_model_function"));
1628 registerImporter<importProduct>(
"product",
false);
1629 registerImporter<importProdPdf>(
"product_dist",
false);
1630 registerImporter<importAddition>(
"sum",
false);
1631 registerImporter<importAddPdf>(
"mixture_dist",
false);
1632 registerImporter<importAddModel>(
"mixture_model",
false);
1633 registerImporter<importAddModel>(
"mixture_resolution_model",
false);
1634 registerImporter<importBinSamplingPdf>(
"binsampling_dist",
false);
1635 registerImporter<importBinSamplingPdf>(
"binsampling",
false);
1636 registerImporter<importBinWidthFunction<false>>(
"binvolume",
false);
1637 registerImporter<importBinWidthFunction<true>>(
"inverse_binvolume",
false);
1638 registerImporter<importPolynomial<RooLegacyExpPoly>>(
"legacy_exp_poly_dist",
false);
1639 registerImporter<importExponential>(
"exponential_dist",
false);
1640 registerImporter<importFormulaArg<RooFormulaVar>>(
"generic",
false);
1641 registerImporter<importFormulaArg<RooFormulaVar>>(
"generic_function",
false);
1642 registerImporter<importFormulaArg<RooGenericPdf>>(
"generic_dist",
false);
1643 registerImporter<importHist<RooHistFunc>>(
"histogram",
false);
1644 registerImporter<importHist<RooHistFunc>>(
"step",
false);
1645 registerImporter<importHist<RooHistPdf>>(
"histogram_dist",
false);
1646 registerImporter<importLogNormal>(
"lognormal_dist",
false);
1647 registerImporter<importMultiVarGaussian>(
"multivariate_normal_dist",
false);
1648 registerImporter<importPoisson>(
"poisson_dist",
false);
1649 registerImporter<importDecay>(
"decay_dist",
false);
1650 registerImporter<importTruthModel>(
"truth_model_function",
false);
1651 registerImporter<importTruthModel>(
"delta_resolution_model",
false);
1652 registerImporter<importGaussModel>(
"gauss_model_function",
false);
1653 registerImporter<importGaussModel>(
"gauss_resolution_model",
false);
1654 registerImporter<importPolynomial<RooPolynomial>>(
"polynomial_dist",
false);
1655 registerImporter<importPolynomial<RooPolyVar>>(
"polynomial",
false);
1656 registerImporter<importRealSum<RooRealSumPdf>>(
"weighted_sum_dist",
false);
1657 registerImporter<importRealSum<RooRealSumFunc>>(
"weighted_sum",
false);
1658 registerImporter<importRealIntegral>(
"integral",
false);
1659 registerImporter<importDerivative>(
"derivative",
false);
1660 registerImporter<importFFTConvPdf>(
"fft_convolution_dist",
false);
1661 registerImporter<importExtendPdf>(
"extend_pdf",
false);
1662 registerImporter<importParamHistFunc>(
"step",
false);
1663 registerImporter<importSpline>(
"spline",
false);
1666 registerExporter<exportAddPdf<RooAddPdf>>(
RooAddPdf::Class(),
"mixture_dist",
false);
1667 registerExporter<exportAddPdf<RooAddModel>>(
RooAddModel::Class(),
"mixture_model",
false);
1669 registerExporter<exportCrystalBall>(
RooCrystalBall::Class(),
"crystalball_doublesided_dist",
false);
1671 registerExporter<exportPolynomial<RooLegacyExpPoly>>(
RooLegacyExpPoly::Class(),
"legacy_exp_poly_dist",
false);
1674 registerExporter<exportFormulaArg<RooGenericPdf>>(
RooGenericPdf::Class(),
"generic_dist",
false);
1676 registerExporter<exportHist<RooHistPdf>>(
RooHistPdf::Class(),
"histogram_dist",
false);
1680 registerExporter<exportDecay>(
RooDecay::Class(),
"decay_dist",
false,
false);
1683 registerExporter<exportPolynomial<RooPolynomial>>(
RooPolynomial::Class(),
"polynomial_dist",
false);
1684 registerExporter<exportPolynomial<RooPolyVar>>(
RooPolyVar::Class(),
"polynomial",
false);
1686 registerExporter<exportRealSum<RooRealSumPdf>>(
RooRealSumPdf::Class(),
"weighted_sum_dist",
false);
bool startsWith(std::string_view str, std::string_view prefix)
bool endsWith(std::string_view str, std::string_view suffix)
std::string removeSuffix(std::string_view str, std::string_view suffix)
void writeAxisBinning(JSONNode &node, const RooAbsBinning &binning)
ROOT::RRangeCast< T, false, Range_t > static_range_cast(Range_t &&coll)
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 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 np
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 Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
A class which maps the current values of a RooRealVar (or a set of RooRealVars) to one of a number of...
Common abstract base class for objects that represent a value and a "shape" in RooFit.
bool dependsOn(const RooAbsCollection &serverList, const RooAbsArg *ignoreArg=nullptr, bool valueOnly=false) const
Test whether we depend on (ie, are served by) any object in the specified collection.
Abstract base class for RooRealVar binning definitions.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
virtual RooAbsArg * addClone(const RooAbsArg &var, bool silent=false)
Add a clone of the specified argument to list.
RooAbsArg * find(const char *name) const
Find object with given name in list.
virtual Int_t numEntries() const
Return number of entries in dataset, i.e., count unweighted entries.
Abstract interface for all probability density functions.
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
Abstract base class for objects that represent a real value and implements functionality common to al...
RooAddModel is an efficient implementation of a sum of PDFs of the form.
Efficient implementation of a sum of PDFs of the form.
Calculates the sum of a set of RooAbsReal terms, or when constructed with two sets,...
RooArgList is a container object that can hold multiple RooAbsArg objects.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
The RooBinSamplingPdf is supposed to be used as an adapter between a continuous PDF and a binned dist...
const RooAbsPdf & pdf() const
const RooAbsReal & observable() const
Returns the bin width (or volume) given a RooHistFunc.
bool divideByBinWidth() const
const RooHistFunc & histFunc() const
Represents a constant real-valued object.
PDF implementing the generalized Asymmetrical Double-Sided Crystall Ball line shape.
Container class to hold N-dimensional binned data.
double const * weightArray() const
const RooArgSet * get() const override
Get bin centre of current bin.
Single or double sided decay function that can be analytically convolved with any RooResolutionModel ...
Represents the first, second, or third order derivative of any RooAbsReal as calculated (numerically)...
RooExtendPdf is a wrapper around an existing PDF that adds a parameteric extended likelihood term to ...
PDF for the numerical (FFT) convolution of two PDFs.
double val_double() const
JSONNode & append_child()
size_t num_children() const
void fill_mat(Matrix const &mat)
bool has_child(std::string const &) const
Class RooGaussModel implements a RooResolutionModel that models a Gaussian distribution.
A real-valued function sampled from a multidimensional histogram.
Multivariate Gaussian p.d.f.
Holds the configuration parameters of the various numeric integrators used by RooRealIntegral.
Efficient implementation of a product of PDFs of the form.
Represents the product of a given set of RooAbsReal objects.
Performs hybrid numerical/analytical integrals of RooAbsReal objects.
Implements a PDF constructed from a sum of functions:
Variable that can be changed from the outside.
RooResolutionModel is the base class for PDFs that represent a resolution model that can be convolute...
A RooFit class for creating spline functions.
Use TF1, TF2, TF3 functions as RooFit objects.
Implements a RooResolution model that corresponds to a delta function.
The RooWrapperPdf is a class that can be used to convert a function into a PDF.
TClass instances represent classes, structs and namespaces in the ROOT type system.
TMatrixTBase< Element > & ResizeTo(Int_t nrows, Int_t ncols, Int_t=-1) override
Set size of the matrix to nrows x ncols New dynamic elements are created, the overlapping part of the...
const char * GetName() const override
Returns name of object.
Base class for spline implementation containing the Draw/Paint methods.
virtual void GetKnot(Int_t i, Double_t &x, Double_t &y) const =0
virtual Int_t GetNp() const
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.
static bool registerImporter(const std::string &key, bool topPriority=true)
bool registerImporter(const std::string &key, std::unique_ptr< const Importer > f, bool topPriority=true)
static bool registerExporter(const TClass *key, bool topPriority=true)
bool registerExporter(const TClass *key, std::unique_ptr< const Exporter > f, bool topPriority=true)
#define STATIC_EXECUTE(MY_FUNC)