Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
JSONFactories_HistFactory.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
15#include <RooFitHS3/JSONIO.h>
17
22#include <RooConstVar.h>
23#include <RooRealVar.h>
24#include <RooDataHist.h>
25#include <RooHistFunc.h>
26#include <RooRealSumPdf.h>
27#include <RooBinWidthFunction.h>
28#include <RooProdPdf.h>
29#include <RooPoisson.h>
30#include <RooLognormal.h>
31#include <RooGaussian.h>
32#include <RooBinning.h>
33#include <RooProduct.h>
34#include <RooWorkspace.h>
35
36#include "static_execute.h"
37#include "JSONIOUtils.h"
38
40
41namespace {
42
43inline void writeAxis(JSONNode &axis, RooRealVar const &obs)
44{
45 auto &binning = obs.getBinning();
46 if (binning.isUniform()) {
47 axis["nbins"] << obs.numBins();
48 axis["min"] << obs.getMin();
49 axis["max"] << obs.getMax();
50 } else {
51 auto &bounds = axis["bounds"];
52 bounds.set_seq();
53 double val = binning.binLow(0);
54 bounds.append_child() << val;
55 for (int i = 0; i < binning.numBins(); ++i) {
56 val = binning.binHigh(i);
57 bounds.append_child() << val;
58 }
59 }
60}
61
62double round_prec(double d, int nSig)
63{
64 if (d == 0.0)
65 return 0.0;
66 int ndigits = std::floor(std::log10(std::abs(d))) + 1 - nSig;
67 double sf = std::pow(10, ndigits);
68 if (std::abs(d / sf) < 2)
69 ndigits--;
70 return sf * std::round(d / sf);
71}
72
73// To avoid repeating the same string literals that can potentially get out of
74// sync.
75namespace Literals {
76constexpr auto staterror = "staterror";
77}
78
79void erasePrefix(std::string &str, std::string_view prefix)
80{
81 if (startsWith(str, prefix)) {
82 str.erase(0, prefix.size());
83 }
84}
85
86void eraseSuffix(std::string &str, std::string_view suffix)
87{
88 if (endsWith(str, suffix)) {
89 str.erase(str.size() - suffix.size());
90 }
91}
92
93template <class Coll>
94void sortByName(Coll &coll)
95{
96 std::sort(coll.begin(), coll.end(), [](auto &l, auto &r) { return l.name < r.name; });
97}
98
99template <class T>
100T *findClient(RooAbsArg *gamma)
101{
102 for (const auto &client : gamma->clients()) {
103 if (auto casted = dynamic_cast<T *>(client)) {
104 return casted;
105 } else {
106 T *c = findClient<T>(client);
107 if (c)
108 return c;
109 }
110 }
111 return nullptr;
112}
113
114RooAbsPdf *findConstraint(RooAbsArg *g)
115{
116 RooPoisson *constraint_p = findClient<RooPoisson>(g);
117 if (constraint_p)
118 return constraint_p;
119 RooGaussian *constraint_g = findClient<RooGaussian>(g);
120 if (constraint_g)
121 return constraint_g;
122 RooLognormal *constraint_l = findClient<RooLognormal>(g);
123 if (constraint_l)
124 return constraint_l;
125 return nullptr;
126}
127
128std::string toString(TClass *c)
129{
130 if (!c) {
131 return "Const";
132 }
133 if (c == RooPoisson::Class()) {
134 return "Poisson";
135 }
136 if (c == RooGaussian::Class()) {
137 return "Gauss";
138 }
139 if (c == RooLognormal::Class()) {
140 return "Lognormal";
141 }
142 return "unknown";
143}
144
145using namespace RooStats::HistFactory::Detail;
146
147RooRealVar &createNominal(RooWorkspace &ws, std::string const &parname, double val, double min, double max)
148{
149 RooRealVar &nom = getOrCreate<RooRealVar>(ws, "nom_" + parname, val, min, max);
150 nom.setConstant(true);
151 nom.setAttribute("globs");
152 return nom;
153}
154
155/// Get the conventional name of the constraint pdf for a constrained
156/// parameter.
157std::string constraintName(std::string const &sysname)
158{
159 return sysname + "_constraint";
160}
161
162RooAbsPdf &getConstraint(RooWorkspace &ws, const std::string &sysname, const std::string &pname)
163{
164 return getOrCreate<RooGaussian>(ws, constraintName(sysname), *ws.var(pname), *ws.var("nom_" + pname),
165 RooFit::RooConst(1.));
166}
167
168void setMCStatGammaRanges(RooArgList const &gammas, std::vector<double> const &errs, double statErrThresh)
169{
170 // Set a reasonable range for gamma and set constant NPs which are below the
171 // MC stat threshold, and remove them from the np list.
172 for (size_t i = 0; i < errs.size(); ++i) {
173 auto g = static_cast<RooRealVar *>(gammas.at(i));
174 g->setMax(1 + 5 * errs[i]);
175 g->setError(errs[i]);
176 if (errs[i] < statErrThresh) {
177 g->setConstant(true); // all negative errs are set constant
178 }
179 }
180}
181
182ParamHistFunc &createPHF(const std::string &sysname, const std::string &phfname, const std::vector<double> &vals,
183 RooJSONFactoryWSTool &tool, RooArgList &constraints, const RooArgSet &observables,
184 const std::string &constraintType, RooArgList &gammas, double gamma_min, double gamma_max)
185{
186 RooWorkspace &ws = *tool.workspace();
187
188 gammas.add(ParamHistFunc::createParamSet(ws, ("gamma_" + sysname).c_str(), observables, gamma_min, gamma_max));
189 auto &phf = tool.wsEmplace<ParamHistFunc>(phfname, observables, gammas);
190 for (size_t i = 0; i < gammas.size(); ++i) {
191 RooRealVar *v = dynamic_cast<RooRealVar *>(&gammas[i]);
192 if (!v)
193 continue;
194 std::string basename = v->GetName();
195 v->setConstant(false);
196 if (constraintType == "Const" || vals[i] == 0.) {
197 v->setConstant(true);
198 } else if (constraintType == "Gauss") {
199 auto &nom = createNominal(ws, basename, 1.0, 0, std::max(10., gamma_max));
200 auto &sigma = tool.wsEmplace<RooConstVar>(basename + "_sigma", vals[i]);
201 constraints.add(tool.wsEmplace<RooGaussian>(constraintName(basename), nom, *v, sigma), true);
202 } else if (constraintType == "Poisson") {
203 double tau_float = vals[i];
204 auto &tau = tool.wsEmplace<RooConstVar>(basename + "_tau", tau_float);
205 auto &nom = createNominal(ws, basename, tau_float, 0, RooNumber::infinity());
206 auto &prod = tool.wsEmplace<RooProduct>(basename + "_poisMean", *v, tau);
207 auto &pois = tool.wsEmplace<RooPoisson>(constraintName(basename), nom, prod);
208 pois.setNoRounding(true);
209 constraints.add(pois, true);
210 } else {
211 RooJSONFactoryWSTool::error("unknown constraint type " + constraintType);
212 }
213 }
214 for (auto &g : gammas) {
215 for (auto client : g->clients()) {
216 if (dynamic_cast<RooAbsPdf *>(client) && !constraints.find(*client)) {
217 constraints.add(*client);
218 }
219 }
220 }
221
222 return phf;
223}
224
225bool hasStaterror(const JSONNode &comp)
226{
227 if (!comp.has_child("modifiers"))
228 return false;
229 for (const auto &mod : comp["modifiers"].children()) {
230 if (mod["type"].val() == ::Literals::staterror)
231 return true;
232 }
233 return false;
234}
235
236bool importHistSample(RooJSONFactoryWSTool &tool, RooDataHist &dh, RooArgSet const &varlist,
237 RooAbsArg const *mcStatObject, const std::string &fprefix, const JSONNode &p,
238 RooArgList &constraints)
239{
240 RooWorkspace &ws = *tool.workspace();
241
242 std::string name = RooJSONFactoryWSTool::name(p);
243 std::string prefixedName = fprefix + "_" + name;
244
245 if (!p.has_child("data")) {
246 RooJSONFactoryWSTool::error("sample '" + name + "' does not define a 'data' key");
247 }
248
249 auto &hf = tool.wsEmplace<RooHistFunc>("hist_" + prefixedName, varlist, dh);
251
252 RooArgList shapeElems;
253 RooArgList normElems;
254
255 shapeElems.add(tool.wsEmplace<RooBinWidthFunction>(prefixedName + "_binWidth", hf, true));
256
257 if (hasStaterror(p)) {
258 shapeElems.add(*mcStatObject);
259 }
260
261 if (p.has_child("modifiers")) {
262 RooArgList overall_nps;
263 std::vector<double> overall_low;
264 std::vector<double> overall_high;
265
266 RooArgList histNps;
267 RooArgList histoLo;
268 RooArgList histoHi;
269
270 for (const auto &mod : p["modifiers"].children()) {
271 std::string const &modtype = mod["type"].val();
272 std::string const &sysname = RooJSONFactoryWSTool::name(mod);
273 if (modtype == "staterror") {
274 // this is dealt with at a different place, ignore it for now
275 } else if (modtype == "normfactor") {
276 normElems.add(getOrCreate<RooRealVar>(ws, sysname, 1., -3, 5));
277 if (auto constrInfo = mod.find("constraint_name")) {
278 constraints.add(*tool.request<RooAbsReal>(constrInfo->val(), name));
279 }
280 } else if (modtype == "normsys") {
281 auto *parameter = mod.find("parameter");
282 std::string parname(parameter ? parameter->val() : "alpha_" + sysname);
283 createNominal(ws, parname, 0.0, -10, 10);
284 overall_nps.add(getOrCreate<RooRealVar>(ws, parname, 0., -5, 5));
285 auto &data = mod["data"];
286 // the below contains a a hack to cut off variations that go below 0
287 // this is needed because with interpolation code 4, which is the default, interpolation is done in
288 // log-space. hence, values <= 0 result in NaN which propagate throughout the model and cause evaluations to
289 // fail if you know a nicer way to solve this, please go ahead and fix the lines below
290 overall_low.push_back(data["lo"].val_double() > 0 ? data["lo"].val_double()
291 : std::numeric_limits<double>::epsilon());
292 overall_high.push_back(data["hi"].val_double() > 0 ? data["hi"].val_double()
293 : std::numeric_limits<double>::epsilon());
294 constraints.add(getConstraint(ws, sysname, parname));
295 } else if (modtype == "histosys") {
296 auto *parameter = mod.find("parameter");
297 std::string parname(parameter ? parameter->val() : "alpha_" + sysname);
298 createNominal(ws, parname, 0.0, -10, 10);
299 histNps.add(getOrCreate<RooRealVar>(ws, parname, 0., -5, 5));
300 auto &data = mod["data"];
301 histoLo.add(tool.wsEmplace<RooHistFunc>(
302 sysname + "Low_" + prefixedName, varlist,
303 RooJSONFactoryWSTool::readBinnedData(data["lo"], sysname + "Low_" + prefixedName, varlist)));
304 histoHi.add(tool.wsEmplace<RooHistFunc>(
305 sysname + "High_" + prefixedName, varlist,
306 RooJSONFactoryWSTool::readBinnedData(data["hi"], sysname + "High_" + prefixedName, varlist)));
307 constraints.add(getConstraint(ws, sysname, parname));
308 } else if (modtype == "shapesys") {
309 std::string funcName = prefixedName + "_" + sysname + "_" + prefixedName + "_ShapeSys";
310 std::vector<double> vals;
311 for (const auto &v : mod["data"]["vals"].children()) {
312 vals.push_back(v.val_double());
313 }
314 RooArgList gammas;
315 std::string constraint(mod["constraint"].val());
316 shapeElems.add(createPHF(sysname, funcName, vals, tool, constraints, varlist, constraint, gammas, 0, 1000));
317 } else if (modtype == "custom") {
318 RooAbsReal *obj = ws.function(sysname);
319 if (!obj) {
320 RooJSONFactoryWSTool::error("unable to find custom modifier '" + sysname + "'");
321 }
322 if (obj->dependsOn(varlist)) {
323 shapeElems.add(*obj);
324 } else {
325 normElems.add(*obj);
326 }
327 } else {
328 RooJSONFactoryWSTool::error("modifier '" + sysname + "' of unknown type '" + modtype + "'");
329 }
330 }
331
332 if (!overall_nps.empty()) {
333 auto &v = tool.wsEmplace<RooStats::HistFactory::FlexibleInterpVar>("overallSys_" + prefixedName, overall_nps,
334 1., overall_low, overall_high);
335 v.setAllInterpCodes(4); // default HistFactory interpCode
336 normElems.add(v);
337 }
338 if (!histNps.empty()) {
339 auto &v = tool.wsEmplace<PiecewiseInterpolation>("histoSys_" + prefixedName, hf, histoLo, histoHi, histNps);
341 v.setAllInterpCodes(4); // default interpCode for HistFactory
342 shapeElems.add(v);
343 } else {
344 shapeElems.add(hf);
345 }
346 }
347
348 tool.wsEmplace<RooProduct>(prefixedName + "_shapes", shapeElems);
349 if (!normElems.empty()) {
350 tool.wsEmplace<RooProduct>(prefixedName + "_scaleFactors", normElems);
351 } else {
352 ws.factory("RooConstVar::" + prefixedName + "_scaleFactors(1.)");
353 }
354
355 return true;
356}
357
358class HistFactoryImporter : public RooFit::JSONIO::Importer {
359public:
360 bool importArg(RooJSONFactoryWSTool *tool, const JSONNode &p) const override
361 {
362 RooWorkspace &ws = *tool->workspace();
363
364 std::string name = RooJSONFactoryWSTool::name(p);
365 if (!p.has_child("samples")) {
366 RooJSONFactoryWSTool::error("no samples in '" + name + "', skipping.");
367 }
368 double statErrThresh = 0;
369 std::string statErrType = "Poisson";
370 if (p.has_child(::Literals::staterror)) {
371 auto &staterr = p[::Literals::staterror];
372 if (staterr.has_child("relThreshold"))
373 statErrThresh = staterr["relThreshold"].val_double();
374 if (staterr.has_child("constraint"))
375 statErrType = staterr["constraint"].val();
376 }
377 std::vector<double> sumW;
378 std::vector<double> sumW2;
379 RooArgSet observables;
380 for (auto const &obsNode : p["axes"].children()) {
381 if (obsNode.has_child("bounds")) {
382 std::vector<double> bounds;
383 for (auto const &bound : obsNode["bounds"].children()) {
384 bounds.push_back(bound.val_double());
385 }
386 RooRealVar &obs = getOrCreate<RooRealVar>(ws, obsNode["name"].val(), bounds[0], bounds[bounds.size() - 1]);
387 RooBinning bins(obs.getMin(), obs.getMax());
388 ;
389 for (auto b : bounds) {
390 bins.addBoundary(b);
391 }
392 obs.setBinning(bins);
393 observables.add(obs);
394 } else {
395 RooRealVar &obs = getOrCreate<RooRealVar>(ws, obsNode["name"].val(), obsNode["min"].val_double(),
396 obsNode["max"].val_double());
397 obs.setBins(obsNode["nbins"].val_int());
398 observables.add(obs);
399 }
400 }
401
402 std::string fprefix = name;
403
404 std::vector<std::unique_ptr<RooDataHist>> data;
405 for (const auto &comp : p["samples"].children()) {
406 std::unique_ptr<RooDataHist> dh = RooJSONFactoryWSTool::readBinnedData(
407 comp["data"], fprefix + "_" + RooJSONFactoryWSTool::name(comp) + "_dataHist", observables);
408 size_t nbins = dh->numEntries();
409
410 if (hasStaterror(comp)) {
411 if (sumW.empty()) {
412 sumW.resize(nbins);
413 sumW2.resize(nbins);
414 }
415 for (size_t i = 0; i < nbins; ++i) {
416 sumW[i] += dh->weight(i);
417 sumW2[i] += dh->weightSquared(i);
418 }
419 }
420 data.emplace_back(std::move(dh));
421 }
422
423 RooAbsArg *mcStatObject = nullptr;
424 RooArgList constraints;
425 if (!sumW.empty()) {
426 std::string phfName = name;
427 erasePrefix(phfName, "model_");
428
429 std::vector<double> vals(sumW.size());
430 std::vector<double> errs(sumW.size());
431
432 for (size_t i = 0; i < sumW.size(); ++i) {
433 errs[i] = std::sqrt(sumW2[i]) / sumW[i];
434 if (statErrType == "Gauss") {
435 vals[i] = std::max(errs[i], 0.); // avoid negative sigma. This NP will be set constant anyway later
436 } else if (statErrType == "Poisson") {
437 vals[i] = sumW[i] * sumW[i] / sumW2[i];
438 }
439 }
440
441 RooArgList gammas;
442 mcStatObject = &createPHF("stat_" + phfName, "mc_stat_" + phfName, vals, *tool, constraints, observables,
443 statErrType, gammas, 0, 10);
444 setMCStatGammaRanges(gammas, errs, statErrThresh);
445 }
446
447 int idx = 0;
449 RooArgList coefs;
450 for (const auto &comp : p["samples"].children()) {
451 importHistSample(*tool, *data[idx], observables, mcStatObject, fprefix, comp, constraints);
452 ++idx;
453
454 std::string const &compName = RooJSONFactoryWSTool::name(comp);
455 funcs.add(*tool->request<RooAbsReal>(fprefix + "_" + compName + "_shapes", name));
456 coefs.add(*tool->request<RooAbsReal>(fprefix + "_" + compName + "_scaleFactors", name));
457 }
458
459 if (constraints.empty()) {
460 auto &sum = tool->wsEmplace<RooRealSumPdf>(name, funcs, coefs, true);
461 sum.setAttribute("BinnedLikelihood");
462 } else {
463 std::string sumName = name + "_model";
464 erasePrefix(sumName, "model_");
465 auto &sum = tool->wsEmplace<RooRealSumPdf>(sumName, funcs, coefs, true);
466 sum.SetTitle(name.c_str());
467 sum.setAttribute("BinnedLikelihood");
468 tool->wsEmplace<RooProdPdf>(name, constraints, RooFit::Conditional(sum, observables));
469 }
470 return true;
471 }
472};
473
474class FlexibleInterpVarStreamer : public RooFit::JSONIO::Exporter {
475public:
476 std::string const &key() const override
477 {
478 static const std::string keystring = "interpolation0d";
479 return keystring;
480 }
481 bool exportObject(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem) const override
482 {
483 auto fip = static_cast<const RooStats::HistFactory::FlexibleInterpVar *>(func);
484 elem["type"] << key();
485 RooJSONFactoryWSTool::fillSeq(elem["vars"], fip->variables());
486 elem["interpolationCodes"].fill_seq(fip->interpolationCodes());
487 elem["nom"] << fip->nominal();
488 elem["high"].fill_seq(fip->high());
489 elem["low"].fill_seq(fip->low());
490 return true;
491 }
492};
493
494class PiecewiseInterpolationStreamer : public RooFit::JSONIO::Exporter {
495public:
496 std::string const &key() const override
497 {
498 static const std::string keystring = "interpolation";
499 return keystring;
500 }
501 bool exportObject(RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem) const override
502 {
503 const PiecewiseInterpolation *pip = static_cast<const PiecewiseInterpolation *>(func);
504 elem["type"] << key();
505 elem["interpolationCodes"].fill_seq(pip->interpolationCodes());
506 elem["positiveDefinite"] << pip->positiveDefinite();
507 RooJSONFactoryWSTool::fillSeq(elem["vars"], pip->paramList());
508 elem["nom"] << pip->nominalHist()->GetName();
509 RooJSONFactoryWSTool::fillSeq(elem["high"], pip->highList());
510 RooJSONFactoryWSTool::fillSeq(elem["low"], pip->lowList());
511 return true;
512 }
513};
514
515class PiecewiseInterpolationFactory : public RooFit::JSONIO::Importer {
516public:
517 bool importArg(RooJSONFactoryWSTool *tool, const JSONNode &p) const override
518 {
519 std::string name(RooJSONFactoryWSTool::name(p));
520
521 RooArgList vars{tool->requestArgList<RooRealVar>(p, "vars")};
522
523 auto &pip = tool->wsEmplace<PiecewiseInterpolation>(name, *tool->requestArg<RooAbsReal>(p, "nom"),
524 tool->requestArgList<RooAbsReal>(p, "low"),
525 tool->requestArgList<RooAbsReal>(p, "high"), vars);
526
527 pip.setPositiveDefinite(p["positiveDefinite"].val_bool());
528
529 if (p.has_child("interpolationCodes")) {
530 std::size_t i = 0;
531 for (auto const &node : p["interpolationCodes"].children()) {
532 pip.setInterpCode(*static_cast<RooAbsReal *>(vars.at(i)), node.val_int(), true);
533 ++i;
534 }
535 }
536
537 return true;
538 }
539};
540
541class FlexibleInterpVarFactory : public RooFit::JSONIO::Importer {
542public:
543 bool importArg(RooJSONFactoryWSTool *tool, const JSONNode &p) const override
544 {
545 std::string name(RooJSONFactoryWSTool::name(p));
546 if (!p.has_child("high")) {
547 RooJSONFactoryWSTool::error("no high variations of '" + name + "'");
548 }
549 if (!p.has_child("low")) {
550 RooJSONFactoryWSTool::error("no low variations of '" + name + "'");
551 }
552 if (!p.has_child("nom")) {
553 RooJSONFactoryWSTool::error("no nominal variation of '" + name + "'");
554 }
555
556 double nom(p["nom"].val_double());
557
558 RooArgList vars{tool->requestArgList<RooRealVar>(p, "vars")};
559
560 std::vector<double> high;
561 high << p["high"];
562
563 std::vector<double> low;
564 low << p["low"];
565
566 if (vars.size() != low.size() || vars.size() != high.size()) {
567 RooJSONFactoryWSTool::error("FlexibleInterpVar '" + name +
568 "' has non-matching lengths of 'vars', 'high' and 'low'!");
569 }
570
571 auto &fip = tool->wsEmplace<RooStats::HistFactory::FlexibleInterpVar>(name, vars, nom, low, high);
572
573 if (p.has_child("interpolationCodes")) {
574 size_t i = 0;
575 for (auto const &node : p["interpolationCodes"].children()) {
576 fip.setInterpCode(*static_cast<RooAbsReal *>(vars.at(i)), node.val_int());
577 ++i;
578 }
579 }
580
581 return true;
582 }
583};
584
585void collectElements(RooArgSet &elems, RooAbsArg *arg)
586{
587 if (auto prod = dynamic_cast<RooProduct *>(arg)) {
588 for (const auto &e : prod->components()) {
589 collectElements(elems, e);
590 }
591 } else {
592 elems.add(*arg);
593 }
594}
595
596struct NormFactor {
597 std::string name;
598 RooAbsArg const *param = nullptr;
599 RooAbsPdf const *constraint = nullptr;
600 NormFactor(RooAbsArg const &par, RooAbsPdf const *constr = nullptr)
601 : name{par.GetName()}, param{&par}, constraint{constr}
602 {
603 }
604};
605
606struct NormSys {
607 std::string name;
608 RooAbsArg const *param = nullptr;
609 double low;
610 double high;
611 TClass *constraint = RooGaussian::Class();
612 NormSys(const std::string &n, RooAbsArg *const p, double h, double l, TClass *c)
613 : name(n), param(p), low(l), high(h), constraint(c)
614 {
615 }
616};
617struct HistoSys {
618 std::string name;
619 RooAbsArg const *param = nullptr;
620 std::vector<double> low;
621 std::vector<double> high;
622 TClass *constraint = RooGaussian::Class();
623 HistoSys(const std::string &n, RooAbsArg *const p, RooHistFunc *l, RooHistFunc *h, TClass *c)
624 : name(n), param(p), constraint(c)
625 {
626 low.assign(l->dataHist().weightArray(), l->dataHist().weightArray() + l->dataHist().numEntries());
627 high.assign(h->dataHist().weightArray(), h->dataHist().weightArray() + h->dataHist().numEntries());
628 }
629};
630struct ShapeSys {
631 std::string name;
632 std::vector<double> constraints;
633 TClass *constraint = nullptr;
634 ShapeSys(const std::string &n) : name{n} {}
635};
636struct Sample {
637 std::string name;
638 std::vector<double> hist;
639 std::vector<double> histError;
640 std::vector<NormFactor> normfactors;
641 std::vector<NormSys> normsys;
642 std::vector<HistoSys> histosys;
643 std::vector<ShapeSys> shapesys;
644 std::vector<RooAbsReal *> otherElements;
645 bool useBarlowBeestonLight = false;
646 TClass *barlowBeestonLightConstraint = RooPoisson::Class();
647 Sample(const std::string &n) : name{n} {}
648};
649
650void addNormFactor(RooRealVar const *par, Sample &sample, RooWorkspace *ws)
651{
652 std::string parname = par->GetName();
653 bool isConstrained = false;
654 for (RooAbsArg const *pdf : ws->allPdfs()) {
655 if (auto gauss = dynamic_cast<RooGaussian const *>(pdf)) {
656 if (parname == gauss->getX().GetName()) {
657 sample.normfactors.emplace_back(*par, gauss);
658 isConstrained = true;
659 }
660 }
661 }
662 if (!isConstrained)
663 sample.normfactors.emplace_back(*par);
664}
665
666bool tryExportHistFactory(RooJSONFactoryWSTool *tool, const std::string &pdfname, const RooRealSumPdf *sumpdf,
667 JSONNode &elem)
668{
669 RooWorkspace *ws = tool->workspace();
670 RooArgSet customModifiers;
671
672 if (!sumpdf)
673 return false;
674
675 std::string chname = pdfname;
676 erasePrefix(chname, "model_");
677 eraseSuffix(chname, "_model");
678
679 for (RooAbsArg *sample : sumpdf->funcList()) {
680 if (!dynamic_cast<RooProduct *>(sample) && !dynamic_cast<RooRealSumPdf *>(sample)) {
681 return false;
682 }
683 }
684
685 std::map<int, double> tot_yield;
686 std::map<int, double> tot_yield2;
687 std::map<int, double> rel_errors;
688 RooArgSet const *varSet = nullptr;
689 long unsigned int nBins = 0;
690
691 std::vector<Sample> samples;
692
693 for (size_t sampleidx = 0; sampleidx < sumpdf->funcList().size(); ++sampleidx) {
694 PiecewiseInterpolation *pip = nullptr;
696 std::vector<ParamHistFunc *> phfs;
697
698 const auto func = sumpdf->funcList().at(sampleidx);
699 Sample sample(func->GetName());
700 erasePrefix(sample.name, "L_x_");
701 eraseSuffix(sample.name, "_shapes");
702 eraseSuffix(sample.name, "_" + chname);
703 erasePrefix(sample.name, pdfname + "_");
704 RooArgSet elems;
705 collectElements(elems, func);
706 collectElements(elems, sumpdf->coefList().at(sampleidx));
707
708 auto updateObservables = [&](RooDataHist const &dataHist) {
709 if (varSet == nullptr) {
710 varSet = dataHist.get();
711 nBins = dataHist.numEntries();
712 }
713 if (sample.hist.empty()) {
714 auto *w = dataHist.weightArray();
715 sample.hist.assign(w, w + dataHist.numEntries());
716 }
717 };
718
719 for (RooAbsArg *e : elems) {
720 if (auto constVar = dynamic_cast<RooConstVar *>(e)) {
721 if (constVar->getVal() != 1.) {
722 sample.normfactors.emplace_back(*e);
723 }
724 } else if (auto par = dynamic_cast<RooRealVar *>(e)) {
725 addNormFactor(par, sample, ws);
726 } else if (auto hf = dynamic_cast<const RooHistFunc *>(e)) {
727 updateObservables(hf->dataHist());
728 } else if (auto phf = dynamic_cast<ParamHistFunc *>(e)) {
729 phfs.push_back(phf);
730 } else if (!fip && (fip = dynamic_cast<RooStats::HistFactory::FlexibleInterpVar *>(e))) {
731 } else if (!pip && (pip = dynamic_cast<PiecewiseInterpolation *>(e))) {
732 } else if (auto real = dynamic_cast<RooAbsReal *>(e)) {
733 if (!dynamic_cast<RooBinWidthFunction *>(real)) {
734 sample.otherElements.push_back(real);
735 }
736 }
737 }
738
739 // see if we can get the observables
740 if (pip) {
741 if (auto nh = dynamic_cast<RooHistFunc const *>(pip->nominalHist())) {
742 updateObservables(nh->dataHist());
743 }
744 }
745
746 // sort and configure norms
747 sortByName(sample.normfactors);
748
749 // sort and configure the normsys
750 if (fip) {
751 for (size_t i = 0; i < fip->variables().size(); ++i) {
752 RooAbsArg *var = fip->variables().at(i);
753 std::string sysname(var->GetName());
754 erasePrefix(sysname, "alpha_");
755 sample.normsys.emplace_back(sysname, var, fip->high()[i], fip->low()[i], findConstraint(var)->IsA());
756 }
757 sortByName(sample.normsys);
758 }
759
760 // sort and configure the histosys
761 if (pip) {
762 for (size_t i = 0; i < pip->paramList().size(); ++i) {
763 RooAbsArg *var = pip->paramList().at(i);
764 std::string sysname(var->GetName());
765 erasePrefix(sysname, "alpha_");
766 if (auto lo = dynamic_cast<RooHistFunc *>(pip->lowList().at(i))) {
767 if (auto hi = dynamic_cast<RooHistFunc *>(pip->highList().at(i))) {
768 sample.histosys.emplace_back(sysname, var, lo, hi, findConstraint(var)->IsA());
769 }
770 }
771 }
772 sortByName(sample.histosys);
773 }
774
775 for (ParamHistFunc *phf : phfs) {
776 if (startsWith(std::string(phf->GetName()), "mc_stat_")) { // MC stat uncertainty
777 int idx = 0;
778 for (const auto &g : phf->paramList()) {
779 ++idx;
780 RooAbsPdf *constraint = findConstraint(g);
781 if (tot_yield.find(idx) == tot_yield.end()) {
782 tot_yield[idx] = 0;
783 tot_yield2[idx] = 0;
784 }
785 tot_yield[idx] += sample.hist[idx - 1];
786 tot_yield2[idx] += (sample.hist[idx - 1] * sample.hist[idx - 1]);
787 if (constraint) {
788 sample.barlowBeestonLightConstraint = constraint->IsA();
789 if (RooPoisson *constraint_p = dynamic_cast<RooPoisson *>(constraint)) {
790 double erel = 1. / std::sqrt(constraint_p->getX().getVal());
791 rel_errors[idx] = erel;
792 } else if (RooGaussian *constraint_g = dynamic_cast<RooGaussian *>(constraint)) {
793 double erel = constraint_g->getSigma().getVal() / constraint_g->getMean().getVal();
794 rel_errors[idx] = erel;
795 } else {
797 "currently, only RooPoisson and RooGaussian are supported as constraint types");
798 }
799 }
800 }
801 sample.useBarlowBeestonLight = true;
802 } else { // other ShapeSys
803 ShapeSys sys(phf->GetName());
804 erasePrefix(sys.name, "model_" + chname + "_");
805 erasePrefix(sys.name, chname + "_");
806 erasePrefix(sys.name, sample.name + "_");
807 eraseSuffix(sys.name, "_ShapeSys");
808 eraseSuffix(sys.name, "_" + sample.name);
809 eraseSuffix(sys.name, "_model_" + chname);
810 eraseSuffix(sys.name, "_" + chname);
811 eraseSuffix(sys.name, "_" + sample.name);
812
813 for (const auto &g : phf->paramList()) {
814 RooAbsPdf *constraint = findConstraint(g);
815 if (!constraint)
816 constraint = ws->pdf(constraintName(g->GetName()));
817 if (!constraint && !g->isConstant())
818 RooJSONFactoryWSTool::error("cannot find constraint for " + std::string(g->GetName()));
819 else if (!constraint) {
820 sys.constraints.push_back(0.0);
821 } else if (auto constraint_p = dynamic_cast<RooPoisson *>(constraint)) {
822 sys.constraints.push_back(constraint_p->getX().getVal());
823 if (!sys.constraint) {
824 sys.constraint = RooPoisson::Class();
825 }
826 } else if (auto constraint_g = dynamic_cast<RooGaussian *>(constraint)) {
827 sys.constraints.push_back(constraint_g->getSigma().getVal() / constraint_g->getMean().getVal());
828 if (!sys.constraint) {
829 sys.constraint = RooGaussian::Class();
830 }
831 }
832 }
833 sample.shapesys.emplace_back(std::move(sys));
834 }
835 }
836 sortByName(sample.shapesys);
837
838 // add the sample
839 samples.emplace_back(std::move(sample));
840 }
841
842 sortByName(samples);
843
844 for (auto &sample : samples) {
845 if (sample.hist.empty()) {
846 return false;
847 }
848 if (sample.useBarlowBeestonLight) {
849 sample.histError.resize(sample.hist.size());
850 for (auto bin : rel_errors) {
851 // reverse engineering the correct partial error
852 // the (arbitrary) convention used here is that all samples should have the same relative error
853 const int i = bin.first;
854 const double relerr_tot = bin.second;
855 const double count = sample.hist[i - 1];
856 // this reconstruction is inherently unprecise, so we truncate it at some decimal places to make sure that
857 // we don't carry around too many useless digits
858 sample.histError[i - 1] = round_prec(relerr_tot * tot_yield[i] / std::sqrt(tot_yield2[i]) * count, 7);
859 }
860 }
861 }
862
863 bool observablesWritten = false;
864 for (const auto &sample : samples) {
865
866 elem["type"] << "histfactory_dist";
867
868 auto &s = RooJSONFactoryWSTool::appendNamedChild(elem["samples"], sample.name);
869
870 auto &modifiers = s["modifiers"];
871
872 for (const auto &nf : sample.normfactors) {
873 auto &mod = RooJSONFactoryWSTool::appendNamedChild(modifiers, nf.name);
874 mod["parameter"] << nf.param->GetName();
875 mod["type"] << "normfactor";
876 if (nf.constraint) {
877 mod["constraint_name"] << nf.constraint->GetName();
878 tool->queueExport(*nf.constraint);
879 }
880 }
881
882 for (const auto &sys : sample.normsys) {
883 auto &mod = RooJSONFactoryWSTool::appendNamedChild(modifiers, sys.name);
884 mod["type"] << "normsys";
885 mod["parameter"] << sys.param->GetName();
886 mod["constraint"] << toString(sys.constraint);
887 auto &data = mod["data"].set_map();
888 data["lo"] << sys.low;
889 data["hi"] << sys.high;
890 }
891
892 for (const auto &sys : sample.histosys) {
893 auto &mod = RooJSONFactoryWSTool::appendNamedChild(modifiers, sys.name);
894 mod["type"] << "histosys";
895 mod["parameter"] << sys.param->GetName();
896 mod["constraint"] << toString(sys.constraint);
897 auto &data = mod["data"].set_map();
898 if (nBins != sys.low.size() || nBins != sys.high.size()) {
899 std::stringstream ss;
900 ss << "inconsistent binning: " << nBins << " bins expected, but " << sys.low.size() << "/"
901 << sys.high.size() << " found in nominal histogram errors!";
902 RooJSONFactoryWSTool::error(ss.str().c_str());
903 }
904 RooJSONFactoryWSTool::exportArray(nBins, sys.low.data(), data["lo"].set_map()["contents"]);
905 RooJSONFactoryWSTool::exportArray(nBins, sys.high.data(), data["hi"].set_map()["contents"]);
906 }
907
908 for (const auto &sys : sample.shapesys) {
909 auto &mod = RooJSONFactoryWSTool::appendNamedChild(modifiers, sys.name);
910 mod["type"] << "shapesys";
911 mod["constraint"] << toString(sys.constraint);
912 if (sys.constraint) {
913 auto &data = mod["data"].set_map();
914 auto &vals = data["vals"];
915 vals.fill_seq(sys.constraints);
916 }
917 }
918
919 for (const auto &other : sample.otherElements) {
920 auto &mod = RooJSONFactoryWSTool::appendNamedChild(modifiers, other->GetName());
921 customModifiers.add(*other);
922 mod["type"] << "custom";
923 }
924
925 if (sample.useBarlowBeestonLight) {
926 auto &mod = RooJSONFactoryWSTool::appendNamedChild(modifiers, ::Literals::staterror);
927 mod["type"] << ::Literals::staterror;
928 mod["constraint"] << toString(sample.barlowBeestonLightConstraint);
929 }
930
931 if (!observablesWritten) {
932 auto &output = elem["axes"].set_seq();
933 for (auto *obs : static_range_cast<RooRealVar *>(*varSet)) {
934 auto &out = output.append_child().set_map();
935 out["name"] << obs->GetName();
936 writeAxis(out, *obs);
937 }
938 observablesWritten = true;
939 }
940 auto &dataNode = s["data"].set_map();
941 if (nBins != sample.hist.size()) {
942 std::stringstream ss;
943 ss << "inconsistent binning: " << nBins << " bins expected, but " << sample.hist.size()
944 << " found in nominal histogram!";
945 RooJSONFactoryWSTool::error(ss.str().c_str());
946 }
947 RooJSONFactoryWSTool::exportArray(nBins, sample.hist.data(), dataNode["contents"]);
948 if (!sample.histError.empty()) {
949 if (nBins != sample.histError.size()) {
950 std::stringstream ss;
951 ss << "inconsistent binning: " << nBins << " bins expected, but " << sample.histError.size()
952 << " found in nominal histogram errors!";
953 RooJSONFactoryWSTool::error(ss.str().c_str());
954 }
955 RooJSONFactoryWSTool::exportArray(nBins, sample.histError.data(), dataNode["errors"]);
956 }
957 }
958
959 // Export all the custom modifiers
960 for (RooAbsArg *modifier : customModifiers) {
961 tool->queueExport(*modifier);
962 }
963
964 // Export all model parameters
965 RooArgSet parameters;
966 sumpdf->getParameters(varSet, parameters);
967 for (RooAbsArg *param : parameters) {
968 // This should exclude the global observables
969 if (!startsWith(std::string{param->GetName()}, "nom_")) {
970 tool->queueExport(*param);
971 }
972 }
973
974 return true;
975}
976
977class HistFactoryStreamer_ProdPdf : public RooFit::JSONIO::Exporter {
978public:
979 bool autoExportDependants() const override { return false; }
980 bool tryExport(RooJSONFactoryWSTool *tool, const RooProdPdf *prodpdf, JSONNode &elem) const
981 {
982 RooRealSumPdf *sumpdf = nullptr;
983 for (RooAbsArg *v : prodpdf->pdfList()) {
984 sumpdf = dynamic_cast<RooRealSumPdf *>(v);
985 }
986 return tryExportHistFactory(tool, prodpdf->GetName(), sumpdf, elem);
987 }
988 std::string const &key() const override
989 {
990 static const std::string keystring = "histfactory_dist";
991 return keystring;
992 }
993 bool exportObject(RooJSONFactoryWSTool *tool, const RooAbsArg *p, JSONNode &elem) const override
994 {
995 return tryExport(tool, static_cast<const RooProdPdf *>(p), elem);
996 }
997};
998
999class HistFactoryStreamer_SumPdf : public RooFit::JSONIO::Exporter {
1000public:
1001 bool autoExportDependants() const override { return false; }
1002 bool tryExport(RooJSONFactoryWSTool *tool, const RooRealSumPdf *sumpdf, JSONNode &elem) const
1003 {
1004 return tryExportHistFactory(tool, sumpdf->GetName(), sumpdf, elem);
1005 }
1006 std::string const &key() const override
1007 {
1008 static const std::string keystring = "histfactory_dist";
1009 return keystring;
1010 }
1011 bool exportObject(RooJSONFactoryWSTool *tool, const RooAbsArg *p, JSONNode &elem) const override
1012 {
1013 return tryExport(tool, static_cast<const RooRealSumPdf *>(p), elem);
1014 }
1015};
1016
1017STATIC_EXECUTE([]() {
1018 using namespace RooFit::JSONIO;
1019
1020 registerImporter<HistFactoryImporter>("histfactory_dist", true);
1021 registerImporter<PiecewiseInterpolationFactory>("interpolation", true);
1022 registerImporter<FlexibleInterpVarFactory>("interpolation0d", true);
1023 registerExporter<FlexibleInterpVarStreamer>(RooStats::HistFactory::FlexibleInterpVar::Class(), true);
1024 registerExporter<PiecewiseInterpolationStreamer>(PiecewiseInterpolation::Class(), true);
1025 registerExporter<HistFactoryStreamer_ProdPdf>(RooProdPdf::Class(), true);
1026 registerExporter<HistFactoryStreamer_SumPdf>(RooRealSumPdf::Class(), true);
1027});
1028
1029} // namespace
bool startsWith(std::string_view str, std::string_view prefix)
bool endsWith(std::string_view str, std::string_view suffix)
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
#define g(i)
Definition RSha256.hxx:105
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
ROOT::RRangeCast< T, false, Range_t > static_range_cast(Range_t &&coll)
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void funcs
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t modifier
char name[80]
Definition TGX11.cxx:110
#define hi
TClass * IsA() const override
Definition TStringLong.h:20
A class which maps the current values of a RooRealVar (or a set of RooRealVars) to one of a number of...
static RooArgList createParamSet(RooWorkspace &w, const std::string &, const RooArgList &Vars)
Create the list of RooRealVar parameters which represent the height of the histogram bins.
The PiecewiseInterpolation is a class that can morph distributions into each other,...
const RooArgList & highList() const
const RooAbsReal * nominalHist() const
Return pointer to the nominal hist function.
void setInterpCode(RooAbsReal &param, int code, bool silent=false)
static TClass * Class()
const RooArgList & lowList() const
void setPositiveDefinite(bool flag=true)
const RooArgList & paramList() const
const std::vector< int > & interpolationCodes() const
RooAbsArg is the common abstract base class for objects that represent a value and a "shape" in RooFi...
Definition RooAbsArg.h:74
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.
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
void setAttribute(const Text_t *name, bool value=true)
Set (default) or clear a named boolean attribute of this object.
Storage_t const & get() const
Const access to the underlying stl container.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
RooAbsArg * find(const char *name) const
Find object with given name in list.
TClass * IsA() const override
Definition RooAbsPdf.h:409
Int_t numBins(const char *rangeName=nullptr) const override
void setConstant(bool value=true)
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition RooAbsReal.h:62
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:91
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition RooArgList.h:110
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
RooBinWidthFunction is a class that returns the bin width (or volume) given a RooHistFunc.
Class RooBinning is an implements RooAbsBinning in terms of an array of boundary values,...
Definition RooBinning.h:27
RooConstVar represent a constant real-valued object.
Definition RooConstVar.h:26
The RooDataHist is a container class to hold N-dimensional binned data.
Definition RooDataHist.h:39
void fill_seq(Collection const &coll)
virtual JSONNode & set_map()=0
virtual JSONNode & append_child()=0
virtual JSONNode & set_seq()=0
virtual bool has_child(std::string const &) const =0
virtual bool autoExportDependants() const
Definition JSONIO.h:58
virtual std::string const & key() const =0
virtual bool exportObject(RooJSONFactoryWSTool *, const RooAbsArg *, RooFit::Detail::JSONNode &) const
Definition JSONIO.h:59
virtual bool importArg(RooJSONFactoryWSTool *tool, const RooFit::Detail::JSONNode &node) const
Definition JSONIO.h:37
Plain Gaussian p.d.f.
Definition RooGaussian.h:24
static TClass * Class()
RooAbsReal const & getMean() const
Get the mean parameter.
Definition RooGaussian.h:45
RooAbsReal const & getSigma() const
Get the sigma parameter.
Definition RooGaussian.h:48
RooHistFunc implements a real-valued function sampled from a multidimensional histogram.
Definition RooHistFunc.h:31
When using RooFit, statistical models can be conveniently handled and stored as a RooWorkspace.
T * requestArg(const RooFit::Detail::JSONNode &node, const std::string &key)
T * request(const std::string &objname, const std::string &requestAuthor)
static std::unique_ptr< RooDataHist > readBinnedData(const RooFit::Detail::JSONNode &n, const std::string &namecomp)
static void fillSeq(RooFit::Detail::JSONNode &node, RooAbsCollection const &coll)
static RooFit::Detail::JSONNode & appendNamedChild(RooFit::Detail::JSONNode &node, std::string const &name)
static void exportArray(std::size_t n, double const *contents, RooFit::Detail::JSONNode &output)
void queueExport(RooAbsArg const &arg)
RooArgList requestArgList(const RooFit::Detail::JSONNode &node, const std::string &seqName)
static void error(const char *s)
Obj_t & wsEmplace(RooStringView name, Args_t &&...args)
static std::string name(const RooFit::Detail::JSONNode &n)
RooFit Lognormal PDF.
static TClass * Class()
static constexpr double infinity()
Return internal infinity representation.
Definition RooNumber.h:24
Poisson pdf.
Definition RooPoisson.h:19
RooAbsReal const & getX() const
Get the x variable.
Definition RooPoisson.h:39
static TClass * Class()
RooProdPdf is an efficient implementation of a product of PDFs of the form.
Definition RooProdPdf.h:33
static TClass * Class()
A RooProduct represents the product of a given set of RooAbsReal objects.
Definition RooProduct.h:29
The class RooRealSumPdf implements a PDF constructed from a sum of functions:
const RooArgList & funcList() const
static TClass * Class()
const RooArgList & coefList() const
RooRealVar represents a variable that can be changed from the outside.
Definition RooRealVar.h:40
const RooAbsBinning & getBinning(const char *name=nullptr, bool verbose=true, bool createOnTheFly=false) const override
Return binning definition with name.
void setBinning(const RooAbsBinning &binning, const char *name=nullptr)
Add given binning under name 'name' with this variable.
void setBins(Int_t nBins, const char *name=nullptr)
Create a uniform binning under name 'name' for this variable.
void setMax(const char *name, double value)
Set maximum of name range to given value.
void setInterpCode(RooAbsReal &param, int code)
const std::vector< double > & high() const
const std::vector< double > & low() const
const RooListProxy & variables() const
Const getters.
Configuration for a constrained, coherent shape variation of affected samples.
Configuration for an un- constrained overall systematic to scale sample normalisations.
Definition Systematics.h:62
Constrained bin-by-bin variation of affected histogram.
The RooWorkspace is a persistable container for RooFit projects.
RooAbsPdf * pdf(RooStringView name) const
Retrieve p.d.f (RooAbsPdf) with given name. A null pointer is returned if not found.
RooAbsReal * function(RooStringView name) const
Retrieve function (RooAbsReal) with given name. Note that all RooAbsPdfs are also RooAbsReals....
RooFactoryWSTool & factory()
Return instance to factory tool.
RooRealVar * var(RooStringView name) const
Retrieve real-valued variable (RooRealVar) with given name. A null pointer is returned if not found.
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:164
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
RooCmdArg Conditional(const RooArgSet &pdfSet, const RooArgSet &depSet, bool depsAreCond=false)
RooConstVar & RooConst(double val)
const Double_t sigma
const Int_t n
Definition legend1.C:16
double gamma(double x)
double T(double x)
#define STATIC_EXECUTE(MY_FUNC)
TLine l
Definition textangle.C:4
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2345
double epsilon
Definition triangle.c:618
static void output()