Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
JSONFactories_RooFitCore.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * Carsten D. Burgard, DESY/ATLAS, Dec 2021
5 *
6 * Copyright (c) 2022, CERN
7 *
8 * Redistribution and use in source and binary forms,
9 * with or without modification, are permitted according to the terms
10 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
11 */
12
14
15#include <RooAbsCachedPdf.h>
16#include <RooAddPdf.h>
17#include <RooAddModel.h>
18#include <RooBinning.h>
19#include <RooBinSamplingPdf.h>
20#include <RooBinWidthFunction.h>
21#include <RooCategory.h>
22#include <RooDataHist.h>
23#include <RooDecay.h>
24#include <RooDerivative.h>
25#include <RooExponential.h>
26#include <RooExtendPdf.h>
27#include <RooFFTConvPdf.h>
29#include <RooFitHS3/JSONIO.h>
30#include <RooFormulaVar.h>
31#include <RooGenericPdf.h>
32#include <RooHistFunc.h>
33#include <RooHistPdf.h>
34#include <RooLegacyExpPoly.h>
35#include <RooLognormal.h>
36#include <RooMultiVarGaussian.h>
38#include <RooAddition.h>
39#include <RooProduct.h>
40#include <RooProdPdf.h>
41#include <RooPoisson.h>
42#include <RooPolynomial.h>
43#include <RooPolyVar.h>
44#include <RooAbsRealLValue.h>
45#include <RooRealSumFunc.h>
46#include <RooRealSumPdf.h>
47#include <RooRealVar.h>
48#include <RooResolutionModel.h>
49#include <RooTFnBinding.h>
50#include <RooTruthModel.h>
51#include <RooGaussModel.h>
52#include <RooWrapperPdf.h>
53#include <RooWorkspace.h>
54#include <RooRealIntegral.h>
55#include <RooSpline.h>
56#include <RooUniformBinning.h>
57#include <TSpline.h>
58
59#include <TF1.h>
60#include <TH1.h>
61
62#include "JSONIOUtils.h"
63
64#include "static_execute.h"
65
66#include <algorithm>
67#include <cctype>
68#include <cmath>
69#include <limits>
70#include <memory>
71#include <set>
72#include <string_view>
73#include <vector>
74
76
77///////////////////////////////////////////////////////////////////////////////////////////////////////
78// individually implemented importers
79///////////////////////////////////////////////////////////////////////////////////////////////////////
80
81namespace {
82bool isReservedExpressionIdentifier(const std::string &arg)
83{
84 return arg == "PI" || arg == "EULER" || arg == "TMath";
85}
86
87/**
88 * Extracts arguments from a mathematical expression.
89 *
90 * This function takes a string representing a mathematical
91 * expression and extracts the arguments from it. The arguments are
92 * defined as sequences of characters that do not contain digits,
93 * spaces, or parentheses, and that start with a letter. Function
94 * calls such as "exp( ... )", identified as being followed by an
95 * opening parenthesis, are not treated as arguments. The extracted
96 * arguments are returned as a vector of strings.
97 *
98 * @param expr A string representing a mathematical expression.
99 * @return A set of unique strings representing the extracted arguments.
100 */
101std::set<std::string> extractArguments(std::string expr)
102{
103 // Get rid of whitespaces
104 expr.erase(std::remove_if(expr.begin(), expr.end(), [](unsigned char c) { return std::isspace(c); }), expr.end());
105
106 std::set<std::string> arguments;
107 size_t startidx = expr.size();
108 for (size_t i = 0; i < expr.size(); ++i) {
109 if (startidx >= expr.size()) {
110 if (isalpha(expr[i])) {
111 startidx = i;
112 // check this character is not part of scientific notation, e.g. 2e-5
114 // if it is, we ignore this character
115 startidx = expr.size();
116 }
117 }
118 } else {
119 if (!isdigit(expr[i]) && !isalpha(expr[i]) && expr[i] != '_') {
120 if (expr[i] == '(') {
121 startidx = expr.size();
122 continue;
123 }
124 std::string arg(expr.substr(startidx, i - startidx));
125 startidx = expr.size();
127 arguments.insert(arg);
128 }
129 }
130 }
131 }
132 if (startidx < expr.size()) {
133 std::string arg(expr.substr(startidx));
135 arguments.insert(arg);
136 }
137 }
138 return arguments;
139}
140
141void replaceIdentifier(TString &expr, std::string_view identifier, std::string_view replacement)
142{
143 std::string in(expr.Data());
144 std::string out;
145 out.reserve(in.size());
146
147 for (std::size_t pos = 0; pos < in.size();) {
148 const bool matches = in.compare(pos, identifier.size(), identifier) == 0;
149 const bool beforeIdentifier =
150 pos > 0 && (std::isalnum(static_cast<unsigned char>(in[pos - 1])) || in[pos - 1] == '_');
151 const std::size_t end = pos + identifier.size();
152 const bool afterIdentifier =
153 end < in.size() && (std::isalnum(static_cast<unsigned char>(in[end])) || in[end] == '_');
154 if (matches && !beforeIdentifier && !afterIdentifier) {
155 out.append(replacement);
156 pos = end;
157 } else {
158 out.push_back(in[pos]);
159 ++pos;
160 }
161 }
162
163 expr = out.c_str();
164}
165
167{
168 replaceIdentifier(expr, "PI", "TMath::Pi()");
169 replaceIdentifier(expr, "EULER", "TMath::E()");
170}
171
172int readPositiveInteger(const JSONNode &node, const std::string &context)
173{
174 // Read through val_double() so an integer encoded as a JSON float (e.g. 1e6,
175 // whose textual form is "1e+06") is accepted like elsewhere in HS3, while
176 // fractional, non-finite, out-of-range or non-numeric values are rejected.
177 const double value = node.is_number() ? node.val_double() : std::numeric_limits<double>::quiet_NaN();
178 if (!std::isfinite(value) || value < 1.0 || value != std::floor(value) ||
179 value > static_cast<double>(std::numeric_limits<int>::max())) {
180 RooJSONFactoryWSTool::error("\"nbins\" in " + context + " must be a positive integer");
181 }
182 return static_cast<int>(value);
183}
184
185std::unique_ptr<RooAbsBinning>
186readFormulaAxisBinning(const JSONNode &axis, const std::string &axisName, const std::string &formulaName)
187{
188 const std::string context = "axis '" + axisName + "' of generic formula '" + formulaName + "'";
189 const bool hasEdges = axis.has_child("edges");
190 const bool hasMin = axis.has_child("min");
191 const bool hasMax = axis.has_child("max");
192 const bool hasNBins = axis.has_child("nbins");
193
194 if (hasEdges && (hasMin || hasMax || hasNBins)) {
195 RooJSONFactoryWSTool::error(context + " must use either \"edges\" or \"min\"/\"max\"/\"nbins\"");
196 }
197
198 if (hasEdges) {
199 const JSONNode &edgesNode = axis["edges"];
200 if (!edgesNode.is_seq()) {
201 RooJSONFactoryWSTool::error("\"edges\" in " + context + " must be a sequence");
202 }
203
204 std::vector<double> edges;
205 edges.reserve(edgesNode.num_children());
206 for (const JSONNode &edgeNode : edgesNode.children()) {
207 if (!edgeNode.is_number()) {
208 RooJSONFactoryWSTool::error("\"edges\" in " + context + " must contain only finite values");
209 }
210 const double edge = edgeNode.val_double();
211 if (!std::isfinite(edge)) {
212 RooJSONFactoryWSTool::error("\"edges\" in " + context + " must contain only finite values");
213 }
214 if (!edges.empty() && edge <= edges.back()) {
215 RooJSONFactoryWSTool::error("\"edges\" in " + context + " must be strictly increasing");
216 }
217 edges.push_back(edge);
218 }
219 if (edges.size() < 2) {
220 RooJSONFactoryWSTool::error("\"edges\" in " + context + " must contain at least two values");
221 }
222 return std::make_unique<RooBinning>(static_cast<int>(edges.size() - 1), edges.data());
223 }
224
225 if (!hasMin || !hasMax || !hasNBins) {
226 RooJSONFactoryWSTool::error(context + " must define \"min\", \"max\", and \"nbins\"");
227 }
228
229 if (!axis["min"].is_number() || !axis["max"].is_number()) {
230 RooJSONFactoryWSTool::error("\"min\" and \"max\" in " + context + " must be finite and increasing");
231 }
232 const double min = axis["min"].val_double();
233 const double max = axis["max"].val_double();
234 if (!std::isfinite(min) || !std::isfinite(max) || max <= min) {
235 RooJSONFactoryWSTool::error("\"min\" and \"max\" in " + context + " must be finite and increasing");
236 }
237 return std::make_unique<RooUniformBinning>(min, max, readPositiveInteger(axis["nbins"], context));
238}
239
240template <class RooArg_t>
241void importFormulaBinnings(RooArg_t &arg, const JSONNode &node)
242{
243 if (!node.has_child("axes")) {
244 return;
245 }
246
247 const JSONNode &axes = node["axes"];
248 if (!axes.is_seq()) {
249 RooJSONFactoryWSTool::error("\"axes\" in generic formula '" + std::string(arg.GetName()) +
250 "' must be a sequence");
251 }
252
253 std::set<std::string> axisNames;
254 for (const JSONNode &axis : axes.children()) {
255 if (!axis.is_map() || !axis.has_child("name")) {
256 RooJSONFactoryWSTool::error("each axis in generic formula '" + std::string(arg.GetName()) +
257 "' must be a map with a \"name\"");
258 }
259 const std::string axisName = axis["name"].val();
260 if (!axisNames.insert(axisName).second) {
261 RooJSONFactoryWSTool::error("duplicate axis '" + axisName + "' in generic formula '" + arg.GetName() + "'");
262 }
263
264 auto *observable = dynamic_cast<RooAbsRealLValue *>(arg.getParameter(axisName.c_str()));
265 if (!observable) {
267 "axis '" + axisName + "' is not a real-valued formula variable of generic formula '" + arg.GetName() + "'");
268 }
269
270 std::unique_ptr<RooAbsBinning> binning = readFormulaAxisBinning(axis, axisName, arg.GetName());
271 arg.setBinning(*observable, *binning, /*checkFlatness=*/false);
272 }
273}
274
275template <class RooArg_t>
277{
278 std::string name(RooJSONFactoryWSTool::name(p));
279 if (!p.has_child("expression")) {
280 RooJSONFactoryWSTool::error("no expression given for '" + name + "'");
281 }
282 TString formula(p["expression"].val());
284 RooArgList dependents;
285 for (const auto &d : extractArguments(formula.Data())) {
286 dependents.add(*tool->request<RooAbsReal>(d, name));
287 }
288 RooArg_t arg{name.c_str(), formula, dependents};
290 tool->wsImport(arg);
291 return true;
292}
293
294// Fast-path importers for RooProduct, RooAddition, and RooProdPdf that
295// bypass the generic factory-expression mechanism. The default path
296// generates a string expression and passes it to gROOT->ProcessLineFast(),
297// which invokes the Cling JIT for every single call. For workspaces with
298// thousands of product/sum nodes (a common shape for HistFactory models)
299// that JIT cost dominates JSON import time. Constructing the RooFit object
300// directly here keeps the work O(N) of cheap C++ calls.
302{
303 std::string name(RooJSONFactoryWSTool::name(p));
304 tool->wsEmplace<RooProduct>(name, tool->requestArgList<RooAbsReal>(p, "factors"));
305 return true;
306}
307
309{
310 std::string name(RooJSONFactoryWSTool::name(p));
311 tool->wsEmplace<RooProdPdf>(name, tool->requestArgList<RooAbsPdf>(p, "factors"));
312 return true;
313}
314
316{
317 std::string name(RooJSONFactoryWSTool::name(p));
318 tool->wsEmplace<RooAddition>(name, tool->requestArgList<RooAbsReal>(p, "summands"));
319 return true;
320}
321
323{
324 std::string name(RooJSONFactoryWSTool::name(p));
325 if (!tool->requestArgList<RooAbsReal>(p, "coefficients").empty()) {
326 tool->wsEmplace<RooAddPdf>(name, tool->requestArgList<RooAbsPdf>(p, "summands"),
327 tool->requestArgList<RooAbsReal>(p, "coefficients"));
328 return true;
329 }
330 tool->wsEmplace<RooAddPdf>(name, tool->requestArgList<RooAbsPdf>(p, "summands"));
331 return true;
332}
333
335{
336 std::string name(RooJSONFactoryWSTool::name(p));
337 tool->wsEmplace<RooAddModel>(name, tool->requestArgList<RooAbsPdf>(p, "summands"),
338 tool->requestArgList<RooAbsReal>(p, "coefficients"));
339 return true;
340}
341
342template <bool DivideByBinWidth>
344{
345 std::string name(RooJSONFactoryWSTool::name(p));
346 RooHistFunc *hf = dynamic_cast<RooHistFunc *>(tool->request<RooAbsReal>(p["histogram"].val(), name));
347 if (!hf) {
348 RooJSONFactoryWSTool::error("histogram '" + p["histogram"].val() + "' of '" + name + "' is not a RooHistFunc");
349 }
351 return true;
352}
353
355{
356 std::string name(RooJSONFactoryWSTool::name(p));
357
358 RooAbsPdf *pdf = tool->requestArg<RooAbsPdf>(p, "pdf");
359 RooRealVar *obs = tool->requestArg<RooRealVar>(p, "observable");
360
361 if (!pdf->dependsOn(*obs)) {
362 RooJSONFactoryWSTool::error(std::string("pdf '") + pdf->GetName() + "' does not depend on observable '" +
363 obs->GetName() + "' as indicated by parent RooBinSamplingPdf '" + name +
364 "', please check!");
365 }
366
367 if (!p.has_child("epsilon")) {
368 RooJSONFactoryWSTool::error("no epsilon given in '" + name + "'");
369 }
370 double epsilon(p["epsilon"].val_double());
371
372 tool->wsEmplace<RooBinSamplingPdf>(name, *obs, *pdf, epsilon);
373
374 return true;
375}
376
378{
379 std::string name(RooJSONFactoryWSTool::name(p));
380
381 bool extended = false;
382 if (p.has_child("extended") && p["extended"].val_bool()) {
383 extended = true;
384 }
385 tool->wsEmplace<RooRealSumPdf>(name, tool->requestArgList<RooAbsReal>(p, "samples"),
386 tool->requestArgList<RooAbsReal>(p, "coefficients"), extended);
387 return true;
388}
389
391{
392 std::string name(RooJSONFactoryWSTool::name(p));
393 tool->wsEmplace<RooRealSumFunc>(name, tool->requestArgList<RooAbsReal>(p, "samples"),
394 tool->requestArgList<RooAbsReal>(p, "coefficients"));
395 return true;
396}
397
398template <class RooArg_t>
400{
401 std::string name(RooJSONFactoryWSTool::name(p));
402 if (!p.has_child("coefficients")) {
403 RooJSONFactoryWSTool::error("no coefficients given in '" + name + "'");
404 }
405 RooAbsReal *x = tool->requestArg<RooAbsReal>(p, "x");
406 RooArgList coefs;
407 int order = 0;
408 int lowestOrder = 0;
409 for (const auto &coef : p["coefficients"].children()) {
410 // As long as the coefficients match the default coefficients in
411 // RooFit, we don't have to instantiate RooFit objects but can
412 // increase the lowestOrder flag.
413 if (order == 0 && (coef.val() == "1.0" || coef.val() == "1")) {
414 ++lowestOrder;
415 } else if (coefs.empty() && (coef.val() == "0.0" || coef.val() == "0")) {
416 ++lowestOrder;
417 } else {
418 coefs.add(*tool->request<RooAbsReal>(coef.val(), name));
419 }
420 ++order;
421 }
422
423 tool->wsEmplace<RooArg_t>(name, *x, coefs, lowestOrder);
424 return true;
425}
426
428{
429 std::string name(RooJSONFactoryWSTool::name(p));
430 RooAbsReal *x = tool->requestArg<RooAbsReal>(p, "x");
431 RooAbsReal *mean = tool->requestArg<RooAbsReal>(p, "mean");
432 tool->wsEmplace<RooPoisson>(name, *x, *mean, !p["integer"].val_bool());
433 return true;
434}
435
437{
438 std::string name(RooJSONFactoryWSTool::name(p));
439 RooRealVar *t = tool->requestArg<RooRealVar>(p, "t");
440 RooAbsReal *tau = tool->requestArg<RooAbsReal>(p, "tau");
441 RooResolutionModel *model = dynamic_cast<RooResolutionModel *>(tool->requestArg<RooAbsPdf>(p, "resolutionModel"));
442 if (!model) {
443 RooJSONFactoryWSTool::error("resolutionModel of '" + name + "' is not a RooResolutionModel");
444 }
445 RooDecay::DecayType decayType = static_cast<RooDecay::DecayType>(p["decayType"].val_int());
446 tool->wsEmplace<RooDecay>(name, *t, *tau, *model, decayType);
447 return true;
448}
449
451{
452 std::string name(RooJSONFactoryWSTool::name(p));
453 RooRealVar *x = tool->requestArg<RooRealVar>(p, "x");
454 tool->wsEmplace<RooTruthModel>(name, *x);
455 return true;
456}
457
459{
460 std::string name(RooJSONFactoryWSTool::name(p));
461 RooRealVar *x = tool->requestArg<RooRealVar>(p, "x");
462 RooRealVar *mean = tool->requestArg<RooRealVar>(p, "mean");
463 RooRealVar *sigma = tool->requestArg<RooRealVar>(p, "sigma");
464 tool->wsEmplace<RooGaussModel>(name, *x, *mean, *sigma);
465 return true;
466}
467
469{
470 std::string name(RooJSONFactoryWSTool::name(p));
471 RooAbsReal *func = tool->requestArg<RooAbsReal>(p, "integrand");
472 auto vars = tool->requestArgList<RooAbsReal>(p, "variables");
474 RooArgSet const *normSetPtr = nullptr;
475 if (p.has_child("normalization")) {
476 normSet.add(tool->requestArgSet<RooAbsReal>(p, "normalization"));
478 }
479 std::string domain;
480 bool hasDomain = p.has_child("domain");
481 if (hasDomain) {
482 domain = p["domain"].val();
483 }
484 // todo: at some point, take care of integrator configurations
485 tool->wsEmplace<RooRealIntegral>(name, *func, vars, normSetPtr, static_cast<RooNumIntConfig *>(nullptr),
486 hasDomain ? domain.c_str() : nullptr);
487 return true;
488}
489
491{
492 std::string name(RooJSONFactoryWSTool::name(p));
493 RooAbsReal *func = tool->requestArg<RooAbsReal>(p, "function");
494 RooRealVar *x = tool->requestArg<RooRealVar>(p, "x");
495 Int_t order = p["order"].val_int();
496 double eps = p["eps"].val_double();
497 if (p.has_child("normalization")) {
499 normSet.add(tool->requestArgSet<RooAbsReal>(p, "normalization"));
500 tool->wsEmplace<RooDerivative>(name, *func, *x, normSet, order, eps);
501 return true;
502 }
503 tool->wsEmplace<RooDerivative>(name, *func, *x, order, eps);
504 return true;
505}
506
508{
509 std::string name(RooJSONFactoryWSTool::name(p));
510 RooRealVar *convVar = tool->requestArg<RooRealVar>(p, "conv_var");
511 Int_t order = p["ipOrder"].val_int();
512 RooAbsPdf *pdf1 = tool->requestArg<RooAbsPdf>(p, "pdf1");
513 RooAbsPdf *pdf2 = tool->requestArg<RooAbsPdf>(p, "pdf2");
514 if (p.has_child("conv_func")) {
515 RooAbsReal *convFunc = tool->requestArg<RooAbsReal>(p, "conv_func");
516 tool->wsEmplace<RooFFTConvPdf>(name, *convFunc, *convVar, *pdf1, *pdf2, order);
517 return true;
518 }
519 tool->wsEmplace<RooFFTConvPdf>(name, *convVar, *pdf1, *pdf2, order);
520 return true;
521}
522
524{
525 std::string name(RooJSONFactoryWSTool::name(p));
526 RooAbsPdf *pdf = tool->requestArg<RooAbsPdf>(p, "pdf");
527 RooAbsReal *norm = tool->requestArg<RooAbsReal>(p, "norm");
528 if (p.has_child("range")) {
529 std::string rangeName = p["range"].val();
530 tool->wsEmplace<RooExtendPdf>(name, *pdf, *norm, rangeName.c_str());
531 return true;
532 }
533 tool->wsEmplace<RooExtendPdf>(name, *pdf, *norm);
534 return true;
535}
536
538{
539 std::string name(RooJSONFactoryWSTool::name(p));
540 RooAbsReal *x = tool->requestArg<RooAbsReal>(p, "x");
541
542 // Same mechanism to undo the parameter transformation as in the
543 // importExponential() function (see comments in that function for more info).
544 const std::string muName = p["mu"].val();
545 const std::string sigmaName = p["sigma"].val();
546 const bool isTransformed = endsWith(muName, "_lognormal_log");
547 const std::string suffixToRemove = isTransformed ? "_lognormal_log" : "";
550
551 tool->wsEmplace<RooLognormal>(name, *x, *mu, *sigma, !isTransformed);
552
553 return true;
554}
555
557{
558 std::string name(RooJSONFactoryWSTool::name(p));
559 RooAbsReal *x = tool->requestArg<RooAbsReal>(p, "x");
560
561 // If the parameter name ends with the "_exponential_inverted" suffix,
562 // this means that it was exported from a RooFit object where the
563 // parameter first needed to be transformed on export to match the HS3
564 // specification. But when re-importing such a parameter, we can simply
565 // skip the transformation and use the original RooFit parameter without
566 // the suffix.
567 //
568 // A concrete example: take the following RooFit pdf in the factory language:
569 //
570 // "Exponential::exponential_1(x[0, 10], c[-0.1])"
571 //
572 // It defines en exponential exp(c * x). However, in HS3 the exponential
573 // is defined as exp(-c * x), to RooFit would export these dictionaries
574 // to the JSON:
575 //
576 // {
577 // "name": "exponential_1", // HS3 exponential_dist with transformed parameter
578 // "type": "exponential_dist",
579 // "x": "x",
580 // "c": "c_exponential_inverted"
581 // },
582 // {
583 // "name": "c_exponential_inverted", // transformation function created on-the-fly on export
584 // "type": "generic_function",
585 // "expression": "-c"
586 // }
587 //
588 // On import, we can directly take the non-transformed parameter, which is
589 // we check for the suffix and optionally remove it from the requested
590 // name next:
591
592 const std::string constParamName = p["c"].val();
593 const bool isInverted = endsWith(constParamName, "_exponential_inverted");
594 const std::string suffixToRemove = isInverted ? "_exponential_inverted" : "";
596
597 tool->wsEmplace<RooExponential>(name, *x, *c, !isInverted);
598
599 return true;
600}
601
603{
604 std::string name(RooJSONFactoryWSTool::name(p));
605 bool has_cov = p.has_child("covariances");
606 bool has_corr = p.has_child("correlations") && p.has_child("standard_deviations");
607 if (!has_cov && !has_corr) {
608 RooJSONFactoryWSTool::error("no covariances or correlations+standard_deviations given in '" + name + "'");
609 }
610
612
613 if (has_cov) {
614 int n = p["covariances"].num_children();
615 int i = 0;
616 covmat.ResizeTo(n, n);
617 for (const auto &row : p["covariances"].children()) {
618 int j = 0;
619 for (const auto &val : row.children()) {
620 covmat(i, j) = val.val_double();
621 ++j;
622 }
623 ++i;
624 }
625 } else {
626 std::vector<double> variances;
627 for (const auto &v : p["standard_deviations"].children()) {
628 variances.push_back(v.val_double());
629 }
630 covmat.ResizeTo(variances.size(), variances.size());
631 int i = 0;
632 for (const auto &row : p["correlations"].children()) {
633 int j = 0;
634 for (const auto &val : row.children()) {
635 covmat(i, j) = val.val_double() * variances[i] * variances[j];
636 ++j;
637 }
638 ++i;
639 }
640 }
641 tool->wsEmplace<RooMultiVarGaussian>(name, tool->requestArgList<RooAbsReal>(p, "x"),
642 tool->requestArgList<RooAbsReal>(p, "mean"), covmat);
643 return true;
644}
645
646RooArgList readBinning(const JSONNode &topNode, const RooArgList &varList)
647{
648 // Temporary map from variable name → RooRealVar
649 std::map<std::string, std::unique_ptr<RooRealVar>> varMap;
650
651 // Build variables from JSON
652 for (const JSONNode &node : topNode["axes"].children()) {
653 const std::string name = node["name"].val();
654 std::unique_ptr<RooRealVar> obs;
655
656 if (node.has_child("edges")) {
657 std::vector<double> edges;
658 for (const auto &bound : node["edges"].children()) {
659 edges.push_back(bound.val_double());
660 }
661 obs = std::make_unique<RooRealVar>(name.c_str(), name.c_str(), edges.front(), edges.back());
662 RooBinning bins(obs->getMin(), obs->getMax());
663 for (auto b : edges)
664 bins.addBoundary(b);
665 obs->setBinning(bins);
666 } else {
667 obs = std::make_unique<RooRealVar>(name.c_str(), name.c_str(), node["min"].val_double(),
668 node["max"].val_double());
669 obs->setBins(node["nbins"].val_int());
670 }
671
672 varMap[name] = std::move(obs);
673 }
674
675 // Now build the final list following the order in varList
676 RooArgList vars;
677 for (auto *refVar : dynamic_range_cast<RooRealVar *>(varList)) {
678 if (!refVar)
679 continue;
680
681 auto it = varMap.find(refVar->GetName());
682 if (it != varMap.end()) {
683 vars.addOwned(std::move(it->second)); // preserve ownership
684 }
685 }
686 return vars;
687}
688
690{
691 if (!p.has_child("parameters")) {
692 return false;
693 }
694 std::string name(RooJSONFactoryWSTool::name(p));
695 RooArgList varList = tool->requestArgList<RooRealVar>(p, "variables");
696 if (!p.has_child("axes")) {
697 std::stringstream ss;
698 ss << "No axes given in '" << name << "'"
699 << ". Using default binning (uniform; nbins=100). If needed, export the Workspace to JSON with a newer "
700 << "Root version that supports custom ParamHistFunc binnings(>=6.38.00)." << std::endl;
702 tool->wsEmplace<ParamHistFunc>(name, varList, tool->requestArgList<RooAbsReal>(p, "parameters"));
703 return true;
704 }
705 tool->wsEmplace<ParamHistFunc>(name, readBinning(p, varList), tool->requestArgList<RooAbsReal>(p, "parameters"));
706 return true;
707}
708
710{
711 const std::string name(RooJSONFactoryWSTool::name(p));
712
713 // Mandatory fields
714 if (!p.has_child("x")) {
715 RooJSONFactoryWSTool::error("no x given in '" + name + "'");
716 }
717 if (!p.has_child("x0") || !p.has_child("y0")) {
718 RooJSONFactoryWSTool::error("no x0/y0 given in '" + name + "'");
719 }
720
721 RooAbsReal *x = tool->requestArg<RooAbsReal>(p, "x");
722
723 // Optional fields (defaults follow RooSpline ctor defaults)
724 std::string algo = p.has_child("interpolation") ? p["interpolation"].val() : "poly3";
725 int order = 0;
726 if (algo == "poly3")
727 order = 3;
728 else if (algo == "poly5")
729 order = 5;
730 else {
731 RooJSONFactoryWSTool::error("unsupported algo '" + algo + "' for RooSpline in '" + name +
732 "': allowed are 'poly3' and 'poly5'");
733 }
734 const bool logx = p.has_child("logx") ? p["logx"].val_bool() : false;
735 const bool logy = p.has_child("logy") ? p["logy"].val_bool() : false;
736
737 // Read knots
738 std::vector<double> x0;
739 std::vector<double> y0;
740 x0.reserve(p["x0"].num_children());
741 y0.reserve(p["y0"].num_children());
742
743 for (const auto &v : p["x0"].children())
744 x0.push_back(v.val_double());
745 for (const auto &v : p["y0"].children())
746 y0.push_back(v.val_double());
747
748 if (x0.size() != y0.size()) {
749 RooJSONFactoryWSTool::error("x0/y0 size mismatch in '" + name + "': x0 has " + std::to_string(x0.size()) +
750 ", y0 has " + std::to_string(y0.size()));
751 }
752 if (x0.size() < 2) {
753 RooJSONFactoryWSTool::error("need at least 2 knots in '" + name + "'");
754 }
755
756 // Construct RooSpline(name,title, x, x0, y0, order, logx, logy)
757 tool->wsEmplace<::RooSpline>(name.c_str(), *x, std::span<const double>(x0.data(), x0.size()),
758 std::span<const double>(y0.data(), y0.size()), order, logx, logy);
759
760 return true;
761}
762
763///////////////////////////////////////////////////////////////////////////////////////////////////////
764// specialized exporter implementations
765///////////////////////////////////////////////////////////////////////////////////////////////////////
766template <class RooArg_t>
767bool exportAddPdf(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
768{
769 const RooArg_t *pdf = static_cast<const RooArg_t *>(func);
770 elem["type"] << key;
771 RooJSONFactoryWSTool::fillSeq(elem["summands"], pdf->pdfList());
772 RooJSONFactoryWSTool::fillSeq(elem["coefficients"], pdf->coefList());
773 elem["extended"] << (pdf->extendMode() != RooArg_t::CanNotBeExtended);
774 return true;
775}
776
777bool exportRealSumPdf(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
778{
779 const RooRealSumPdf *pdf = static_cast<const RooRealSumPdf *>(func);
780 elem["type"] << key;
781 RooJSONFactoryWSTool::fillSeq(elem["samples"], pdf->funcList());
782 RooJSONFactoryWSTool::fillSeq(elem["coefficients"], pdf->coefList());
783 elem["extended"] << (pdf->extendMode() != RooAbsPdf::CanNotBeExtended);
784 return true;
785}
786
787bool exportRealSumFunc(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
788{
789 const RooRealSumFunc *pdf = static_cast<const RooRealSumFunc *>(func);
790 elem["type"] << key;
791 RooJSONFactoryWSTool::fillSeq(elem["samples"], pdf->funcList());
792 RooJSONFactoryWSTool::fillSeq(elem["coefficients"], pdf->coefList());
793 return true;
794}
795
796template <class RooArg_t>
797bool exportHist(RooJSONFactoryWSTool *tool, const RooAbsArg *func, JSONNode &elem, std::string const &key)
798{
799 const RooArg_t *hf = static_cast<const RooArg_t *>(func);
800 elem["type"] << key;
801 RooDataHist const &dh = hf->dataHist();
802 tool->exportHisto(*dh.get(), dh.numEntries(), dh.weightArray(), elem["data"].set_map());
803 return true;
804}
805
806template <class RooArg_t>
808{
809 std::string name(RooJSONFactoryWSTool::name(p));
810 if (!p.has_child("data")) {
811 return false;
812 }
813 std::unique_ptr<RooDataHist> dataHist =
815 tool->wsEmplace<RooArg_t>(name, *dataHist->get(), *dataHist);
816 return true;
817}
818
819bool exportBinSamplingPdf(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
820{
821 const RooBinSamplingPdf *pdf = static_cast<const RooBinSamplingPdf *>(func);
822 elem["type"] << key;
823 elem["pdf"] << pdf->pdf().GetName();
824 elem["observable"] << pdf->observable().GetName();
825 elem["epsilon"] << pdf->epsilon();
826 return true;
827}
828
829bool exportBinWidthFunction(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &)
830{
831 const RooBinWidthFunction *pdf = static_cast<const RooBinWidthFunction *>(func);
832 elem["type"] << (pdf->divideByBinWidth() ? "inverse_binvolume" : "binvolume");
833 elem["histogram"] << pdf->histFunc().GetName();
834 return true;
835}
836
838{
839 // Plain substring replacement would also hit longer identifiers that
840 // share a prefix (e.g. "TMath::Tan" in "TMath::TanH", or "TMath::Pi" in
841 // "TMath::PiOver2"), corrupting the exported expression. Identifiers
842 // without a replacement are kept as-is.
843 replaceIdentifier(expr, "TMath::Exp", "exp");
844 replaceIdentifier(expr, "TMath::Min", "min");
845 replaceIdentifier(expr, "TMath::Max", "max");
846 replaceIdentifier(expr, "TMath::Log", "log");
847 replaceIdentifier(expr, "TMath::Log10", "log10");
848 replaceIdentifier(expr, "TMath::Cos", "cos");
849 replaceIdentifier(expr, "TMath::CosH", "cosh");
850 replaceIdentifier(expr, "TMath::Sin", "sin");
851 replaceIdentifier(expr, "TMath::SinH", "sinh");
852 replaceIdentifier(expr, "TMath::Sqrt", "sqrt");
853 replaceIdentifier(expr, "TMath::Power", "pow");
854 replaceIdentifier(expr, "TMath::Erf", "erf");
855 replaceIdentifier(expr, "TMath::Erfc", "erfc");
856 replaceIdentifier(expr, "TMath::Floor", "floor");
857 replaceIdentifier(expr, "TMath::Ceil", "ceil");
858 replaceIdentifier(expr, "TMath::Abs", "abs");
859 replaceIdentifier(expr, "TMath::Tan", "tan");
860 replaceIdentifier(expr, "TMath::TanH", "tanh");
861 replaceIdentifier(expr, "TMath::ASin", "asin");
862 replaceIdentifier(expr, "TMath::ACos", "acos");
863 replaceIdentifier(expr, "TMath::ATan", "atan");
864 replaceIdentifier(expr, "TMath::ATan2", "atan2");
865 replaceIdentifier(expr, "TMath::Pi()", "PI");
866 replaceIdentifier(expr, "TMath::E()", "EULER");
867}
868
869template <class RooArg_t>
870bool exportFormulaArg(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
871{
872 const RooArg_t *pdf = static_cast<const RooArg_t *>(func);
873 elem["type"] << key;
874 TString expression(pdf->expression());
875 cleanExpression(expression);
876 // If the tokens follow the "x[#]" convention, the square braces enclosing each number
877 // ensures that there is a unique mapping between the token and parameter name
878 // If the tokens follow the "@#" convention, the numbers are not enclosed by braces.
879 // So there may be tokens with numbers whose lower place value forms a subset string of ones with a higher place
880 // value, e.g. "@1" is a subset of "@10". So the names of these parameters must be applied descending from the
881 // highest place value in order to ensure each parameter name is uniquely applied to its token.
882 for (size_t idx = pdf->nParameters(); idx--;) {
883 const RooAbsArg *par = pdf->getParameter(idx);
884 expression.ReplaceAll(("x[" + std::to_string(idx) + "]").c_str(), par->GetName());
885 expression.ReplaceAll(("@" + std::to_string(idx)).c_str(), par->GetName());
886 }
887 elem["expression"] << expression.Data();
888
889 for (const RooAbsArg *dependent : pdf->dependents()) {
890 auto const *observable = dynamic_cast<const RooAbsRealLValue *>(dependent);
891 if (!observable) {
892 continue;
893 }
894 const RooAbsBinning *binning = pdf->getBinning(*observable);
895 if (!binning) {
896 continue;
897 }
898
899 auto &axes = elem["axes"];
900 if (!axes.is_seq()) {
901 axes.set_seq();
902 }
903 auto &axis = axes.append_child().set_map();
904 axis["name"] << observable->GetName();
905 writeAxisBinning(axis, *binning);
906 }
907 return true;
908}
909
910// Write the "x" reference and the coefficient list for polynomial-like
911// pdfs/funcs, including the implicit defaults below "lowestOrder" so that the
912// output is self-documenting.
913template <class Pdf>
914void writePolynomialBody(const Pdf *pdf, JSONNode &elem)
915{
916 elem["x"] << pdf->x().GetName();
917 auto &coefs = elem["coefficients"].set_seq();
918 for (int i = 0; i < pdf->lowestOrder(); ++i) {
919 coefs.append_child() << (i == 0 ? 1.0 : 0.0);
920 }
921 for (const auto &coef : pdf->coefList()) {
922 coefs.append_child() << coef->GetName();
923 }
924}
925
926template <class RooArg_t>
927bool exportPolynomial(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
928{
929 elem["type"] << key;
930 writePolynomialBody(static_cast<const RooArg_t *>(func), elem);
931 return true;
932}
933
934bool exportPoisson(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
935{
936 auto *pdf = static_cast<const RooPoisson *>(func);
937 elem["type"] << key;
938 elem["x"] << pdf->getX().GetName();
939 elem["mean"] << pdf->getMean().GetName();
940 elem["integer"] << !pdf->getNoRounding();
941 return true;
942}
943
944bool exportDecay(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
945{
946 auto *pdf = static_cast<const RooDecay *>(func);
947 elem["type"] << key;
948 elem["t"] << pdf->getT().GetName();
949 elem["tau"] << pdf->getTau().GetName();
950 elem["resolutionModel"] << pdf->getModel().GetName();
951 elem["decayType"] << pdf->getDecayType();
952
953 return true;
954}
955
956bool exportTruthModel(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
957{
958 auto *pdf = static_cast<const RooTruthModel *>(func);
959 elem["type"] << key;
960 elem["x"] << pdf->convVar().GetName();
961
962 return true;
963}
964
965bool exportGaussModel(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
966{
967 auto *pdf = static_cast<const RooGaussModel *>(func);
968 elem["type"] << key;
969 elem["x"] << pdf->convVar().GetName();
970 elem["mean"] << pdf->getMean().GetName();
971 elem["sigma"] << pdf->getSigma().GetName();
972 return true;
973}
974
975bool exportLogNormal(RooJSONFactoryWSTool *tool, const RooAbsArg *func, JSONNode &elem, std::string const &key)
976{
977 auto *pdf = static_cast<const RooLognormal *>(func);
978
979 elem["type"] << key;
980 elem["x"] << pdf->getX().GetName();
981
982 auto &m0 = pdf->getMedian();
983 auto &k = pdf->getShapeK();
984
985 if (pdf->useStandardParametrization()) {
986 elem["mu"] << m0.GetName();
987 elem["sigma"] << k.GetName();
988 } else {
989 elem["mu"] << tool->exportTransformed(&m0, "_lognormal_log", "log(%s)");
990 elem["sigma"] << tool->exportTransformed(&k, "_lognormal_log", "log(%s)");
991 }
992
993 return true;
994}
995
996bool exportExponential(RooJSONFactoryWSTool *tool, const RooAbsArg *func, JSONNode &elem, std::string const &key)
997{
998 auto *pdf = static_cast<const RooExponential *>(func);
999 elem["type"] << key;
1000 elem["x"] << pdf->variable().GetName();
1001 auto &c = pdf->coefficient();
1002 if (pdf->negateCoefficient()) {
1003 elem["c"] << c.GetName();
1004 } else {
1005 elem["c"] << tool->exportTransformed(&c, "_exponential_inverted", "-%s");
1006 }
1007
1008 return true;
1009}
1010
1011bool exportMultiVarGaussian(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
1012{
1013 auto *pdf = static_cast<const RooMultiVarGaussian *>(func);
1014 elem["type"] << key;
1015 RooJSONFactoryWSTool::fillSeq(elem["x"], pdf->xVec());
1016 RooJSONFactoryWSTool::fillSeq(elem["mean"], pdf->muVec());
1017 elem["covariances"].fill_mat(pdf->covarianceMatrix());
1018 return true;
1019}
1020
1021bool exportTFnBinding(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
1022{
1023 auto *pdf = static_cast<const RooTFnBinding *>(func);
1024 elem["type"] << key;
1025
1026 TString formula(pdf->function().GetExpFormula());
1027 formula.ReplaceAll("x", pdf->observables()[0].GetName());
1028 formula.ReplaceAll("y", pdf->observables()[1].GetName());
1029 formula.ReplaceAll("z", pdf->observables()[2].GetName());
1030 for (size_t i = 0; i < pdf->parameters().size(); ++i) {
1031 TString pname(TString::Format("[%d]", (int)i));
1032 formula.ReplaceAll(pname, pdf->parameters()[i].GetName());
1033 }
1034 elem["expression"] << formula.Data();
1035 return true;
1036}
1037
1038bool exportDerivative(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
1039{
1040 auto *pdf = static_cast<const RooDerivative *>(func);
1041 elem["type"] << key;
1042 elem["x"] << pdf->getX().GetName();
1043 elem["function"] << pdf->getFunc().GetName();
1044 if (!pdf->getNset().empty()) {
1045 RooJSONFactoryWSTool::fillSeq(elem["normalization"], pdf->getNset());
1046 }
1047 elem["order"] << pdf->order();
1048 elem["eps"] << pdf->eps();
1049 return true;
1050}
1051
1052bool exportRealIntegral(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
1053{
1054 auto *integral = static_cast<const RooRealIntegral *>(func);
1055 elem["type"] << key;
1056 std::string integrand = integral->integrand().GetName();
1057 elem["integrand"] << integrand;
1058 if (integral->intRange()) {
1059 elem["domain"] << integral->intRange();
1060 }
1061 RooJSONFactoryWSTool::fillSeq(elem["variables"], integral->intVars());
1062 if (RooArgSet const *funcNormSet = integral->funcNormSet()) {
1063 RooJSONFactoryWSTool::fillSeq(elem["normalization"], *funcNormSet);
1064 }
1065 return true;
1066}
1067
1068bool exportFFTConvPdf(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
1069{
1070 auto *pdf = static_cast<const RooFFTConvPdf *>(func);
1071 elem["type"] << key;
1072 if (auto convFunc = pdf->getPdfConvVar()) {
1073 elem["conv_func"] << convFunc->GetName();
1074 }
1075 elem["conv_var"] << pdf->getConvVar().GetName();
1076 elem["pdf1"] << pdf->getPdf1().GetName();
1077 elem["pdf2"] << pdf->getPdf2().GetName();
1078 elem["ipOrder"] << pdf->getInterpolationOrder();
1079 return true;
1080}
1081
1082bool exportExtendPdf(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
1083{
1084 auto *pdf = static_cast<const RooExtendPdf *>(func);
1085 elem["type"] << key;
1086 if (auto rangeName = pdf->getRangeName()) {
1087 elem["range"] << rangeName->GetName();
1088 }
1089 elem["pdf"] << pdf->pdf().GetName();
1090 elem["norm"] << pdf->getN().GetName();
1091 return true;
1092}
1093
1094bool exportParamHistFunc(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
1095{
1096 auto *pdf = static_cast<const ParamHistFunc *>(func);
1097 elem["type"] << key;
1098 RooJSONFactoryWSTool::fillSeq(elem["variables"], pdf->dataVars());
1099 RooJSONFactoryWSTool::fillSeq(elem["parameters"], pdf->paramList());
1100 auto &observablesNode = elem["axes"].set_seq();
1101 // axes have to be ordered to get consistent bin indices
1102 for (auto *var : static_range_cast<RooRealVar *>(pdf->dataVars())) {
1103 RooJSONFactoryWSTool::exportAxis(observablesNode.append_child().set_map(), *var);
1104 }
1105 return true;
1106}
1107
1108bool exportSpline(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem, std::string const &key)
1109{
1110 auto const *rs = static_cast<RooSpline const *>(func);
1111
1112 elem["type"] << key;
1113
1114 // Independent variable
1115 elem["x"] << rs->x().GetName();
1116
1117 // Spline configuration
1118 // Canonical algo for RooSpline
1119 elem["interpolation"] << (rs->order() == 5 ? "poly5" : "poly3");
1120 elem["logx"] << rs->logx();
1121 elem["logy"] << rs->logy();
1122
1123 // Serialize knots as primitive arrays
1124 TSpline const &sp = rs->spline();
1125 auto &x0 = elem["x0"].set_seq();
1126 auto &y0 = elem["y0"].set_seq();
1127
1128 const int np = sp.GetNp();
1129 for (int i = 0; i < np; ++i) {
1130 double xk = 0.0, yk = 0.0;
1131 sp.GetKnot(i, xk, yk);
1132 x0.append_child() << xk;
1133 y0.append_child() << yk;
1134 }
1135
1136 return true;
1137}
1138
1140{
1141 if (node["type"].val() != "density_function_dist")
1142 return false;
1143
1144 auto name = RooJSONFactoryWSTool::name(node);
1145 auto *func = tool->requestArg<RooAbsReal>(node, "function");
1146
1147 bool selfNormalized = false;
1148
1149 if (auto sn = node.find("selfNormalized"))
1150 selfNormalized = sn->val_bool();
1151
1152 tool->wsEmplace<RooWrapperPdf>(name, *func, selfNormalized);
1153 return true;
1154}
1155
1156bool exportWrapperPdf(RooJSONFactoryWSTool *, const RooAbsArg *arg, JSONNode &node, std::string const &key)
1157{
1158 auto const *pdf = dynamic_cast<RooWrapperPdf const *>(arg);
1159 if (!pdf)
1160 return false;
1161
1162 node["type"] << key;
1163
1164 // Proxy name in RooWrapperPdf is "_func" / "func" depending on accessor/proxy export.
1165 // Prefer a public accessor if one exists; otherwise inspect proxies as below.
1166 auto const *funcProxy = dynamic_cast<RooRealProxy const *>(pdf->getProxy(0));
1167 if (!funcProxy || !funcProxy->absArg())
1168 return false;
1169
1170 node["function"] << funcProxy->absArg()->GetName();
1171 if (pdf->selfNormalized())
1172 node["selfnormalized"] << true;
1173
1174 return true;
1175}
1176
1177///////////////////////////////////////////////////////////////////////////////////////////////////////
1178// instantiate all importers and exporters
1179///////////////////////////////////////////////////////////////////////////////////////////////////////
1180
1181// Adapters that wrap the plain import/export functions above into the
1182// RooFit::JSONIO::Importer/Exporter interface. The exporter also owns the HS3
1183// type key, which is passed at registration time.
1184template <auto Func>
1185class FuncImporter : public RooFit::JSONIO::Importer {
1186public:
1187 bool importArg(RooJSONFactoryWSTool *tool, const JSONNode &p) const override { return Func(tool, p); }
1188};
1189
1190template <auto Func>
1191class FuncExporter : public RooFit::JSONIO::Exporter {
1192public:
1193 FuncExporter(std::string key) : _key{std::move(key)} {}
1194 std::string const &key() const override { return _key; }
1195 bool exportObject(RooJSONFactoryWSTool *tool, const RooAbsArg *func, JSONNode &elem) const override
1196 {
1197 return Func(tool, func, elem, _key);
1198 }
1199
1200private:
1201 const std::string _key;
1202};
1203
1204template <auto Func>
1205void registerImporter(const std::string &key, bool topPriority = true)
1206{
1208}
1209
1210template <auto Func>
1211void registerExporter(TClass const *cl, std::string key, bool topPriority = true)
1212{
1213 RooFit::JSONIO::registerExporter(cl, std::make_unique<FuncExporter<Func>>(std::move(key)), topPriority);
1214}
1215
1216STATIC_EXECUTE([]() {
1217 registerImporter<importWrapperPdf>("density_function_dist");
1218 registerImporter<importExtendPdf>("rate_extended_dist");
1219 registerImporter<importProduct>("product", false);
1220 registerImporter<importProdPdf>("product_dist", false);
1222 registerImporter<importAddPdf>("mixture_dist", false);
1223 registerImporter<importAddModel>("mixture_resolution_model", false);
1224 registerImporter<importBinSamplingPdf>("binsampling_dist", false);
1226 registerImporter<importBinWidthFunction<true>>("inverse_binvolume", false);
1227 registerImporter<importPolynomial<RooLegacyExpPoly>>("legacy_exp_poly_dist", false);
1228 registerImporter<importExponential>("exponential_dist", false);
1230 registerImporter<importFormulaArg<RooFormulaVar>>("generic_function", false);
1232 registerImporter<importHist<RooHistFunc>>("histogram", false);
1234 registerImporter<importHist<RooHistPdf>>("histogram_dist", false);
1235 registerImporter<importLogNormal>("lognormal_dist", false);
1236 registerImporter<importMultiVarGaussian>("multivariate_normal_dist", false);
1237 registerImporter<importPoisson>("poisson_dist", false);
1238 registerImporter<importDecay>("decay_dist", false);
1239 registerImporter<importTruthModel>("delta_resolution_model", false);
1240 registerImporter<importGaussModel>("gauss_resolution_model", false);
1241 registerImporter<importPolynomial<RooPolynomial>>("polynomial_dist", false);
1243 registerImporter<importRealSumPdf>("weighted_sum_dist", false);
1244 registerImporter<importRealSumFunc>("weighted_sum", false);
1245 registerImporter<importRealIntegral>("integral", false);
1246 registerImporter<importDerivative>("derivative", false);
1247 registerImporter<importFFTConvPdf>("fft_convolution_dist", false);
1248 registerImporter<importExtendPdf>("extend_pdf", false);
1250 registerImporter<importSpline>("spline", false);
1251
1252 registerExporter<exportWrapperPdf>(RooWrapperPdf::Class(), "density_function_dist");
1254 registerExporter<exportAddPdf<RooAddModel>>(RooAddModel::Class(), "mixture_resolution_model", false);
1258 registerExporter<exportExponential>(RooExponential::Class(), "exponential_dist", false);
1263 registerExporter<exportLogNormal>(RooLognormal::Class(), "lognormal_dist", false);
1264 registerExporter<exportMultiVarGaussian>(RooMultiVarGaussian::Class(), "multivariate_normal_dist", false);
1265 registerExporter<exportPoisson>(RooPoisson::Class(), "poisson_dist", false);
1266 registerExporter<exportDecay>(RooDecay::Class(), "decay_dist", false);
1267 registerExporter<exportTruthModel>(RooTruthModel::Class(), "delta_resolution_model", false);
1268 registerExporter<exportGaussModel>(RooGaussModel::Class(), "gauss_resolution_model", false);
1272 registerExporter<exportRealSumPdf>(RooRealSumPdf::Class(), "weighted_sum_dist", false);
1273 registerExporter<exportTFnBinding>(RooTFnBinding::Class(), "generic_function", false);
1276 registerExporter<exportFFTConvPdf>(RooFFTConvPdf::Class(), "fft_convolution_dist", false);
1277 registerExporter<exportExtendPdf>(RooExtendPdf::Class(), "rate_extended_dist", false);
1280});
1281
1282} // namespace
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)
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
ROOT::RRangeCast< T, true, Range_t > dynamic_range_cast(Range_t &&coll)
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
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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
char name[80]
Definition TGX11.cxx:148
A class which maps the current values of a RooRealVar (or a set of RooRealVars) to one of a number of...
static TClass * Class()
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
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 bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
@ CanNotBeExtended
Definition RooAbsPdf.h:208
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...
Definition RooAbsReal.h:63
RooAddModel is an efficient implementation of a sum of PDFs of the form.
Definition RooAddModel.h:27
static TClass * Class()
Efficient implementation of a sum of PDFs of the form.
Definition RooAddPdf.h:33
static TClass * Class()
Calculates the sum of a set of RooAbsReal terms, or when constructed with two sets,...
Definition RooAddition.h:27
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
The RooBinSamplingPdf is supposed to be used as an adapter between a continuous PDF and a binned dist...
static TClass * Class()
double epsilon() const
const RooAbsPdf & pdf() const
const RooAbsReal & observable() const
Returns the bin width (or volume) given a RooHistFunc.
const RooHistFunc & histFunc() const
static TClass * Class()
Implements a RooAbsBinning in terms of an array of boundary values, posing no constraints on the choi...
Definition RooBinning.h:27
Container class to hold N-dimensional binned data.
Definition RooDataHist.h:40
Single or double sided decay function that can be analytically convolved with any RooResolutionModel ...
Definition RooDecay.h:22
static TClass * Class()
Represents the first, second, or third order derivative of any RooAbsReal as calculated (numerically)...
static TClass * Class()
Exponential PDF.
static TClass * Class()
RooExtendPdf is a wrapper around an existing PDF that adds a parameteric extended likelihood term to ...
static TClass * Class()
PDF for the numerical (FFT) convolution of two PDFs.
static TClass * Class()
virtual std::string val() const =0
virtual double val_double() const
virtual JSONNode & append_child()=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 bool is_number() const
static TClass * Class()
Class RooGaussModel implements a RooResolutionModel that models a Gaussian distribution.
static TClass * Class()
static TClass * Class()
A real-valued function sampled from a multidimensional histogram.
Definition RooHistFunc.h:31
static TClass * Class()
static TClass * Class()
When using RooFit, statistical models can be conveniently handled and stored as a RooWorkspace.
static void fillSeq(RooFit::Detail::JSONNode &node, RooAbsCollection const &coll, size_t nMax=-1)
static std::unique_ptr< RooDataHist > readBinnedData(const RooFit::Detail::JSONNode &n, const std::string &namecomp, RooArgSet const &vars)
Read binned data from the JSONNode and create a RooDataHist object.
static void exportAxis(RooFit::Detail::JSONNode &obsNode, RooRealVar const &var)
Export the name and binning of a RooRealVar to a JSONNode.
static void error(const char *s)
Writes an error message to the RooFit message service and throws a runtime_error.
static std::string name(const RooFit::Detail::JSONNode &n)
static std::ostream & warning(const std::string &s)
Writes a warning message to the RooFit message service.
static RooArgSet readAxes(const RooFit::Detail::JSONNode &node)
Read axes from the JSONNode and create a RooArgSet representing them.
static TClass * Class()
RooFit Lognormal PDF.
static TClass * Class()
Multivariate Gaussian p.d.f.
static TClass * Class()
Holds the configuration parameters of the various numeric integrators used by RooRealIntegral.
Poisson pdf.
Definition RooPoisson.h:19
static TClass * Class()
static TClass * Class()
static TClass * Class()
Efficient implementation of a product of PDFs of the form.
Definition RooProdPdf.h:36
Represents the product of a given set of RooAbsReal objects.
Definition RooProduct.h:29
Performs hybrid numerical/analytical integrals of RooAbsReal objects.
static TClass * Class()
const RooArgList & coefList() const
const RooArgList & funcList() const
static TClass * Class()
Implements a PDF constructed from a sum of functions:
const RooArgList & funcList() const
static TClass * Class()
ExtendMode extendMode() const override
Returns ability of PDF to provide extended likelihood terms.
const RooArgList & coefList() const
Variable that can be changed from the outside.
Definition RooRealVar.h:37
RooResolutionModel is the base class for PDFs that represent a resolution model that can be convolute...
A RooFit class for creating spline functions.
Definition RooSpline.h:27
static TClass * Class()
Use TF1, TF2, TF3 functions as RooFit objects.
static TClass * Class()
Implements a RooResolution model that corresponds to a delta function.
static TClass * Class()
The RooWrapperPdf is a class that can be used to convert a function into a PDF.
static TClass * Class()
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
static Bool_t IsScientificNotation(const TString &formula, int ipos)
Definition TFormula.cxx:383
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Base class for spline implementation containing the Draw/Paint methods.
Definition TSpline.h:31
Basic string class.
Definition TString.h:138
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2459
const Double_t sigma
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
static bool registerImporter(const std::string &key, bool topPriority=true)
Definition JSONIO.h:85
bool registerImporter(const std::string &key, std::unique_ptr< const Importer > f, bool topPriority=true)
Definition JSONIO.cxx:122
static bool registerExporter(const TClass *key, bool topPriority=true)
Definition JSONIO.h:90
bool registerExporter(const TClass *key, std::unique_ptr< const Exporter > f, bool topPriority=true)
Definition JSONIO.cxx:129
#define STATIC_EXECUTE(MY_FUNC)