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