ROOT   Reference Guide
Searching...
No Matches
RooRealSumPdf.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8 * *
9 * Copyright (c) 2000-2005, Regents of the University of California *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
15 *****************************************************************************/
16
17//////////////////////////////////////////////////////////////////////////////
18/** \class RooRealSumPdf
19 \ingroup Roofitcore
20
21
22Implements a PDF constructed from a sum of functions:
23\f[
24 \mathrm{PDF}(x) = \frac{ \sum_{i=1}^{n-1} \mathrm{coef}_i * \mathrm{func}_i(x) + \left[ 1 - \sum_{i=1}^{n-1} \mathrm{coef}_i \right] * \mathrm{func}_n(x) }
25 {\sum_{i=1}^{n-1} \mathrm{coef}_i * \int \mathrm{func}_i(x)dx + \left[ 1 - \sum_{i=1}^{n-1} \mathrm{coef}_i \right] * \int \mathrm{func}_n(x) dx }
26\f]
27
28where \f$\mathrm{coef}_i\f$ and \f$\mathrm{func}_i\f$ are RooAbsReal objects, and \f$x \f$ is the collection of dependents.
29In the present version \f$\mathrm{coef}_i\f$ may not depend on \f$x \f$, but this limitation could be removed should the need arise.
30
31If the number of coefficients is one less than the number of functions, the PDF is assumed to be normalised. Due to this additional constraint,
32\f$\mathrm{coef}_n\f$ is computed from the other coefficients.
33
34### Extending the PDF
35If an \f$n^\mathrm{th} \f$ coefficient is provided, the PDF **can** be used as an extended PDF, *i.e.* the total number of events will be measured in addition
36to the fractions of the various functions. **This requires setting the last argument of the constructor to true.**
37\note For the RooAddPdf, the extension happens automatically.
38
39### Difference to RooAddPdf / RooRealSumFunc
40- RooAddPdf is a PDF of PDFs, *i.e.* its components need to be normalised and non-negative.
41- RooRealSumPdf is a PDF of functions, *i.e.*, its components can be negative, but their sum cannot be. The normalisation
42 is computed automatically, unless the PDF is extended (see above).
43- RooRealSumFunc is a sum of functions. It is neither normalised, nor need it be positive.
44
45*/
46
47#include "RooRealSumPdf.h"
48
49#include "RooNormalizedPdf.h"
50#include "RooRealIntegral.h"
51#include "RooRealProxy.h"
52#include "RooRealVar.h"
53#include "RooMsgService.h"
54#include "RooNaNPacker.h"
55
56#include <TError.h>
57
58#include <algorithm>
59#include <memory>
60#include <stdexcept>
61
62using std::list, std::endl, std::ostream;
63
65
67
68////////////////////////////////////////////////////////////////////////////////
69/// Default constructor
70/// coverity[UNINIT_CTOR]
71
72RooRealSumPdf::RooRealSumPdf() : _normIntMgr(this, 10) {}
73
74////////////////////////////////////////////////////////////////////////////////
75/// Constructor with name and title
76
77RooRealSumPdf::RooRealSumPdf(const char *name, const char *title) :
78 RooAbsPdf(name,title),
79 _normIntMgr(this,10),
80 _funcList("!funcList","List of functions",this),
81 _coefList("!coefList","List of coefficients",this),
82 _extended(false)
83{
84}
85
86////////////////////////////////////////////////////////////////////////////////
87/// Construct p.d.f consisting of \f$\mathrm{coef}_1 * \mathrm{func}_1 + (1-\mathrm{coef}_1) * \mathrm{func}_2 \f$.
88/// The input coefficients and functions are allowed to be negative
89/// but the resulting sum is not, which is enforced at runtime.
90
91RooRealSumPdf::RooRealSumPdf(const char *name, const char *title,
92 RooAbsReal& func1, RooAbsReal& func2, RooAbsReal& coef1) :
93 RooRealSumPdf(name, title)
94{
95 // Special constructor with two functions and one coefficient
96
100
101}
102
103
104////////////////////////////////////////////////////////////////////////////////
105/// Constructor for a PDF from a list of functions and coefficients.
106/// It implements
107/// \f[
108/// \sum_i \mathrm{coef}_i \cdot \mathrm{func}_i,
109/// \f]
110/// if \f$N_\mathrm{coef} = N_\mathrm{func} \f$. With extended=true, the coefficients can take any values. With extended=false,
111/// there is the danger of getting a degenerate minimisation problem because a PDF has to be normalised, which needs one degree
112/// of freedom less.
113///
114/// A plain (normalised) PDF can therefore be implemented with one less coefficient. RooFit then computes
115/// \f[
116/// \sum_i^{N-1} \mathrm{coef}_i \cdot \mathrm{func}_i + (1 - \sum_i \mathrm{coef}_i ) \cdot \mathrm{func}_N,
117/// \f]
118/// if \f$N_\mathrm{coef} = N_\mathrm{func} - 1 \f$.
119///
120/// All coefficients and functions are allowed to be negative
121/// but the sum (*i.e.* the PDF) is not, which is enforced at runtime.
122///
123/// \param name Name of the PDF
124/// \param title Title (for plotting)
125/// \param inFuncList List of functions to sum
126/// \param inCoefList List of coefficients
127/// \param extended Interpret as extended PDF (requires equal number of functions and coefficients)
128
129RooRealSumPdf::RooRealSumPdf(const char *name, const char *title, const RooArgList &inFuncList,
130 const RooArgList &inCoefList, bool extended)
131 : RooRealSumPdf(name, title)
132{
133 setExtended(extended);
134
135 RooRealSumPdf::initializeFuncsAndCoefs(*this, inFuncList, inCoefList, _funcList, _coefList);
136}
137
138
140 const RooArgList& inFuncList, const RooArgList& inCoefList,
141 RooArgList& funcList, RooArgList& coefList)
142{
143 const std::string className = caller.ClassName();
144 const std::string constructorName = className + "::" + className;
145
146 if (!(inFuncList.size()==inCoefList.size()+1 || inFuncList.size()==inCoefList.size())) {
147 oocoutE(&caller, InputArguments) << constructorName << "(" << caller.GetName()
148 << ") number of pdfs and coefficients inconsistent, must have Nfunc=Ncoef or Nfunc=Ncoef+1" << std::endl;
149 throw std::invalid_argument(className + ": Number of PDFs and coefficients is inconsistent.");
150 }
151
152 // Constructor with N functions and N or N-1 coefs
153 for (unsigned int i = 0; i < inCoefList.size(); ++i) {
154 const auto& func = inFuncList[i];
155 const auto& coef = inCoefList[i];
156
157 if (!dynamic_cast<const RooAbsReal*>(&coef)) {
158 oocoutW(&caller, InputArguments) << constructorName << "(" << caller.GetName() << ") coefficient " << coef.GetName() << " is not of type RooAbsReal, ignored" << std::endl ;
159 continue ;
160 }
161 if (!dynamic_cast<const RooAbsReal*>(&func)) {
162 oocoutW(&caller, InputArguments) << constructorName << "(" << caller.GetName() << ") func " << func.GetName() << " is not of type RooAbsReal, ignored" << std::endl ;
163 continue ;
164 }
167 }
168
169 if (inFuncList.size() == inCoefList.size() + 1) {
170 const auto& func = inFuncList[inFuncList.size()-1];
171 if (!dynamic_cast<const RooAbsReal*>(&func)) {
172 oocoutE(&caller, InputArguments) << constructorName << "(" << caller.GetName() << ") last func " << func.GetName() << " is not of type RooAbsReal, fatal error" << std::endl ;
173 throw std::invalid_argument(className + ": Function passed as is not of type RooAbsReal.");
174 }
176 }
177
178}
179
180
181
182
183////////////////////////////////////////////////////////////////////////////////
184/// Copy constructor
185
187 RooAbsPdf(other,name),
188 _normIntMgr(other._normIntMgr,this),
189 _funcList("!funcList",this,other._funcList),
190 _coefList("!coefList",this,other._coefList),
191 _extended(other._extended),
192 _doFloor(other._doFloor)
193{
194
195}
196
197////////////////////////////////////////////////////////////////////////////////
198
200{
202}
203
204
206 RooArgList const& funcList,
207 RooArgList const& coefList,
208 bool doFloor,
209 bool & hasWarnedBefore)
210{
211 // Do running sum of coef/func pairs, calculate lastCoef.
212 double value = 0;
213 double sumCoeff = 0.;
214 for (unsigned int i = 0; i < funcList.size(); ++i) {
215 const auto func = static_cast<RooAbsReal*>(&funcList[i]);
216 const auto coef = static_cast<RooAbsReal*>(i < coefList.size() ? &coefList[i] : nullptr);
217 const double coefVal = coef != nullptr ? coef->getVal() : (1. - sumCoeff);
218
219 // Warn about degeneration of last coefficient
220 if (coef == nullptr && (coefVal < 0 || coefVal > 1.)) {
221 if (!hasWarnedBefore) {
222 oocoutW(&caller, Eval) << caller.ClassName() << "::evaluate(" << caller.GetName()
223 << ") WARNING: sum of FUNC coefficients not in range [0-1], value="
224 << sumCoeff << ". This means that the PDF is not properly normalised."
225 << " If the PDF was meant to be extended, provide as many coefficients as functions." << std::endl;
226 hasWarnedBefore = true;
227 }
228 // Signal that we are in an undefined region:
229 value = RooNaNPacker::packFloatIntoNaN(100.f * (coefVal < 0. ? -coefVal : coefVal - 1.));
230 }
231
232 if (func->isSelectedComp()) {
233 value += func->getVal() * coefVal;
234 }
235
236 sumCoeff += coefVal;
237 }
238
239 // Introduce floor if so requested
240 return value < 0 && doFloor ? 0.0 : value;
241}
242
243////////////////////////////////////////////////////////////////////////////////
244/// Calculate the current value
245
247{
249}
250
251
253{
254 std::span<double> output = ctx.output();
255 std::size_t nEvents = output.size();
256
257 // Do running sum of coef/func pairs, calculate lastCoef.
258 std::fill(output.begin(), output.end(), 0.);
259
260 double sumCoeff = 0.;
261 for (unsigned int i = 0; i < _funcList.size(); ++i) {
262 const auto func = static_cast<RooAbsReal*>(&_funcList[i]);
263 const auto coef = static_cast<RooAbsReal*>(i < _coefList.size() ? &_coefList[i] : nullptr);
264 const double coefVal = coef != nullptr ? ctx.at(coef)[0] : (1. - sumCoeff);
265
266 if (func->isSelectedComp()) {
267 auto funcValues = ctx.at(func);
268 if(funcValues.size() == 1) {
269 for (unsigned int j = 0; j < nEvents; ++j) {
270 output[j] += funcValues[0] * coefVal;
271 }
272 } else {
273 for (unsigned int j = 0; j < nEvents; ++j) {
274 output[j] += funcValues[j] * coefVal;
275 }
276 }
277 }
278
279 // Warn about degeneration of last coefficient
280 if (coef == nullptr && (coefVal < 0 || coefVal > 1.)) {
281 if (!_haveWarned) {
282 coutW(Eval) << "RooRealSumPdf::doEval(" << GetName()
283 << ") WARNING: sum of FUNC coefficients not in range [0-1], value="
284 << sumCoeff << ". This means that the PDF is not properly normalised. If the PDF was meant to be extended, provide as many coefficients as functions." << endl ;
285 _haveWarned = true;
286 }
287 // Signal that we are in an undefined region by handing back one NaN.
288 output[0] = RooNaNPacker::packFloatIntoNaN(100.f * (coefVal < 0. ? -coefVal : coefVal - 1.));
289 }
290
291 sumCoeff += coefVal;
292 }
293
294 // Introduce floor if so requested
295 if (_doFloor || _doFloorGlobal) {
296 for (unsigned int j = 0; j < nEvents; ++j) {
297 output[j] = std::max(0., output[j]);
298 }
299 }
300}
301
303 RooArgList const &funcList, RooArgList const &coefList, bool normalize)
304{
305 bool noLastCoeff = funcList.size() != coefList.size();
306
307 std::string const &funcName = ctx.buildArg(funcList);
308 std::string const &coeffName = ctx.buildArg(coefList);
309 std::string const &coeffSize = std::to_string(coefList.size());
310
311 std::string sum = ctx.getTmpVarName();
312 std::string coeffSum = ctx.getTmpVarName();
313 ctx.addToCodeBody(klass, "double " + sum + " = 0;\ndouble " + coeffSum + "= 0;\n");
314
315 std::string iterator = "i_" + ctx.getTmpVarName();
316 std::string subscriptExpr = "[" + iterator + "]";
317
318 std::string code = "for(int " + iterator + " = 0; " + iterator + " < " + coeffSize + "; " + iterator + "++) {\n" +
319 sum + " += " + funcName + subscriptExpr + " * " + coeffName + subscriptExpr + ";\n";
320 code += coeffSum + " += " + coeffName + subscriptExpr + ";\n";
321 code += "}\n";
322
323 if (noLastCoeff) {
324 code += sum + " += " + funcName + "[" + coeffSize + "]" + " * (1 - " + coeffSum + ");\n";
325 } else if (normalize) {
326 code += sum + " /= " + coeffSum + ";\n";
327 }
329
330 return sum;
331}
332
334{
335 ctx.addResult(this, translateImpl(ctx, this, _funcList, _coefList));
336}
337
339 RooArgList const& funcList, RooArgList const& coefList)
340{
341 bool ret(false) ;
342
343 for (unsigned int i=0; i < coefList.size(); ++i) {
344 const auto& coef = coefList[i];
345 const auto& func = funcList[i];
346
347 if (func.observableOverlaps(nset, coef)) {
348 oocoutE(&caller, InputArguments) << caller.ClassName() << "::checkObservables(" << caller.GetName()
349 << "): ERROR: coefficient " << coef.GetName()
350 << " and FUNC " << func.GetName() << " have one or more observables in common" << std::endl;
351 ret = true ;
352 }
353 if (coef.dependsOn(*nset)) {
354 oocoutE(&caller, InputArguments) << caller.ClassName() << "::checkObservables(" << caller.GetName()
355 << "): ERROR coefficient " << coef.GetName()
356 << " depends on one or more of the following observables" ; nset->Print("1") ;
357 ret = true ;
358 }
359 }
360
361 return ret ;
362}
363
364
365////////////////////////////////////////////////////////////////////////////////
366/// Check if FUNC is valid for given normalization set.
367/// Coefficient and FUNC must be non-overlapping, but func-coefficient
368/// pairs may overlap each other.
369///
370/// In the present implementation, coefficients may not be observables or derive
371/// from observables.
372
374{
375 return checkObservables(*this, nset, _funcList, _coefList);
376}
377
378
379////////////////////////////////////////////////////////////////////////////////
380/// Advertise that all integrals can be handled internally.
381
383 const RooArgSet* normSet2, const char* rangeName) const
384{
385 return getAnalyticalIntegralWN(*this, _normIntMgr, _funcList, _coefList, allVars, analVars, normSet2, rangeName);
386}
387
388
390 RooArgList const& funcList, RooArgList const& /*coefList*/,
391 RooArgSet& allVars, RooArgSet& analVars,
392 const RooArgSet* normSet2, const char* rangeName)
393{
394 // Handle trivial no-integration scenario
395 if (allVars.empty()) return 0 ;
396 if (caller.getForceNumInt()) return 0 ;
397
398 // Select subset of allVars that are actual dependents
400 std::unique_ptr<RooArgSet> normSet;
401 if(normSet2) {
402 normSet = std::make_unique<RooArgSet>();
403 caller.getObservables(normSet2, *normSet);
404 }
405
406
407 // Check if this configuration was created before
408 Int_t sterileIdx(-1) ;
409 auto* cache = static_cast<CacheElem*>(normIntMgr.getObj(normSet.get(),&analVars,&sterileIdx,RooNameReg::ptr(rangeName)));
410 if (cache) {
411 //cout << "RooRealSumPdf("<<this<<")::getAnalyticalIntegralWN:"<<GetName()<<"("<<allVars<<","<<analVars<<","<<(normSet2?*normSet2:RooArgSet())<<","<<(rangeName?rangeName:"<none>") << " -> " << _normIntMgr.lastIndex()+1 << " (cached)" << endl;
412 return normIntMgr.lastIndex()+1 ;
413 }
414
415 // Create new cache element
416 cache = new CacheElem ;
417
418 // Make list of function projection and normalization integrals
419 for (const auto elm : funcList) {
420 const auto func = static_cast<RooAbsReal*>(elm);
421
422 std::unique_ptr<RooAbsReal> funcInt{func->createIntegral(analVars,rangeName)};
423 if(auto funcRealInt = dynamic_cast<RooRealIntegral*>(funcInt.get())) funcRealInt->setAllowComponentSelection(true);
425 if (normSet && !normSet->empty()) {
427 }
428 }
429
430 // Store cache element
431 Int_t code = normIntMgr.setObj(normSet.get(),&analVars,(RooAbsCacheElement*)cache,RooNameReg::ptr(rangeName)) ;
432
433 //cout << "RooRealSumPdf("<<this<<")::getAnalyticalIntegralWN:"<<GetName()<<"("<<allVars<<","<<analVars<<","<<(normSet2?*normSet2:RooArgSet())<<","<<(rangeName?rangeName:"<none>") << " -> " << code+1 << endl;
434 return code+1 ;
435}
436
437
438
439
440////////////////////////////////////////////////////////////////////////////////
441/// Implement analytical integrations by deferring integration of component
442/// functions to integrators of components.
443
444double RooRealSumPdf::analyticalIntegralWN(Int_t code, const RooArgSet* normSet2, const char* rangeName) const
445{
446 return analyticalIntegralWN(*this, _normIntMgr, _funcList, _coefList, code, normSet2, rangeName, _haveWarned);
447}
448
450 RooArgList const& funcList, RooArgList const& coefList,
451 Int_t code, const RooArgSet* normSet2, const char* rangeName,
452 bool hasWarnedBefore)
453{
454 // Handle trivial passthrough scenario
455 if (code==0) return caller.getVal(normSet2) ;
456
457
458 // WVE needs adaptation for rangeName feature
459 auto* cache = static_cast<CacheElem*>(normIntMgr.getObjByIndex(code-1));
460 if (cache==nullptr) { // revive the (sterilized) cache
461 //cout << "RooRealSumPdf("<<this<<")::analyticalIntegralWN:"<<GetName()<<"("<<code<<","<<(normSet2?*normSet2:RooArgSet())<<","<<(rangeName?rangeName:"<none>") << ": reviving cache "<< endl;
462 RooArgSet vars;
463 caller.getParameters(nullptr, vars);
464 RooArgSet iset = normIntMgr.selectFromSet2(vars, code-1);
465 RooArgSet nset = normIntMgr.selectFromSet1(vars, code-1);
466 RooArgSet dummy;
467 Int_t code2 = caller.getAnalyticalIntegralWN(iset,dummy,&nset,rangeName);
468 R__ASSERT(code==code2); // must have revived the right (sterilized) slot...
469 cache = static_cast<CacheElem*>(normIntMgr.getObjByIndex(code-1)) ;
470 R__ASSERT(cache!=nullptr);
471 }
472
473 double value(0) ;
474
475 // N funcs, N-1 coefficients
476 double lastCoef(1) ;
477 auto funcIt = funcList.begin();
478 auto funcIntIt = cache->_funcIntList.begin();
479 for (const auto coefArg : coefList) {
480 assert(funcIt != funcList.end());
481 const auto coef = static_cast<const RooAbsReal*>(coefArg);
482 const auto func = static_cast<const RooAbsReal*>(*funcIt++);
483 const auto funcInt = static_cast<RooAbsReal*>(*funcIntIt++);
484
485 double coefVal = coef->getVal(normSet2) ;
486 if (coefVal) {
487 assert(func);
488 if (normSet2 ==nullptr || func->isSelectedComp()) {
489 assert(funcInt);
490 value += funcInt->getVal()*coefVal ;
491 }
492 lastCoef -= coef->getVal(normSet2) ;
493 }
494 }
495
496 const bool haveLastCoef = funcList.size() == coefList.size();
497
498 if (!haveLastCoef) {
499 // Add last func with correct coefficient
500 const auto func = static_cast<const RooAbsReal*>(*funcIt);
501 const auto funcInt = static_cast<RooAbsReal*>(*funcIntIt);
502 assert(func);
503
504 if (normSet2 ==nullptr || func->isSelectedComp()) {
505 assert(funcInt);
506 value += funcInt->getVal()*lastCoef ;
507 }
508
509 // Warn about coefficient degeneration
510 if (!hasWarnedBefore && (lastCoef<0 || lastCoef>1)) {
511 oocoutW(&caller, Eval) << caller.ClassName() << "::evaluate(" << caller.GetName()
512 << " WARNING: sum of FUNC coefficients not in range [0-1], value="
513 << 1-lastCoef << endl ;
514 }
515 }
516
517 double normVal(1) ;
518 if (normSet2 && !normSet2->empty()) {
519 normVal = 0 ;
520
521 // N funcs, N-1 coefficients
522 auto funcNormIter = cache->_funcNormList.begin();
523 for (const auto coefAsArg : coefList) {
524 auto coef = static_cast<RooAbsReal*>(coefAsArg);
525 auto funcNorm = static_cast<RooAbsReal*>(*funcNormIter++);
526
527 double coefVal = coef->getVal(normSet2);
528 if (coefVal) {
529 assert(funcNorm);
530 normVal += funcNorm->getVal()*coefVal ;
531 }
532 }
533
534 // Add last func with correct coefficient
535 if (!haveLastCoef) {
536 auto funcNorm = static_cast<RooAbsReal*>(*funcNormIter);
537 assert(funcNorm);
538
539 normVal += funcNorm->getVal()*lastCoef;
540 }
541 }
542
543 return value / normVal;
544}
545
546
547////////////////////////////////////////////////////////////////////////////////
548
550{
551 double n = getNorm(nset) ;
552 if (n<0) {
553 logEvalError("Expected number of events is negative") ;
554 }
555 return n ;
556}
557
558
559////////////////////////////////////////////////////////////////////////////////
560
561std::list<double>* RooRealSumPdf::binBoundaries(RooAbsRealLValue& obs, double xlo, double xhi) const
562{
563 return binBoundaries(_funcList, obs, xlo, xhi);
564}
565
566
567std::list<double>* RooRealSumPdf::binBoundaries(RooArgList const& funcList, RooAbsRealLValue& obs, double xlo, double xhi)
568{
569 std::list<double>* sumBinB = nullptr;
570 bool needClean(false) ;
571
572 // Loop over components pdf
573 for (auto * func : static_range_cast<RooAbsReal*>(funcList)) {
574
575 list<double>* funcBinB = func->binBoundaries(obs,xlo,xhi) ;
576
577 // Process hint
578 if (funcBinB) {
579 if (!sumBinB) {
580 // If this is the first hint, then just save it
581 sumBinB = funcBinB ;
582 } else {
583
584 std::list<double>* newSumBinB = new list<double>(sumBinB->size()+funcBinB->size()) ;
585
586 // Merge hints into temporary array
587 merge(funcBinB->begin(),funcBinB->end(),sumBinB->begin(),sumBinB->end(),newSumBinB->begin()) ;
588
589 // Copy merged array without duplicates to new sumBinBArrau
590 delete sumBinB ;
591 delete funcBinB ;
592 sumBinB = newSumBinB ;
593 needClean = true ;
594 }
595 }
596 }
597
598 // Remove consecutive duplicates
599 if (needClean) {
600 list<double>::iterator new_end = unique(sumBinB->begin(),sumBinB->end()) ;
601 sumBinB->erase(new_end,sumBinB->end()) ;
602 }
603
604 return sumBinB ;
605}
606
607
608
609/// Check if all components that depend on obs are binned.
611{
612 return isBinnedDistribution(_funcList, obs);
613}
614
615
617{
618 for (auto* func : static_range_cast<RooAbsReal*>(funcList)) {
619
620 if (func->dependsOn(obs) && !func->isBinnedDistribution(obs)) {
621 return false ;
622 }
623 }
624
625 return true ;
626}
627
628
629
630////////////////////////////////////////////////////////////////////////////////
631
632std::list<double>* RooRealSumPdf::plotSamplingHint(RooAbsRealLValue& obs, double xlo, double xhi) const
633{
634 return plotSamplingHint(_funcList, obs, xlo, xhi);
635}
636
637std::list<double>* RooRealSumPdf::plotSamplingHint(RooArgList const& funcList, RooAbsRealLValue& obs, double xlo, double xhi)
638{
639 std::list<double>* sumHint = nullptr;
640 bool needClean(false) ;
641
642 // Loop over components pdf
643 for (const auto elm : funcList) {
644 auto func = static_cast<RooAbsReal*>(elm);
645
646 list<double>* funcHint = func->plotSamplingHint(obs,xlo,xhi) ;
647
648 // Process hint
649 if (funcHint) {
650 if (!sumHint) {
651
652 // If this is the first hint, then just save it
653 sumHint = funcHint ;
654
655 } else {
656
657 auto* newSumHint = new std::list<double>(sumHint->size()+funcHint->size()) ;
658
659 // the lists must be sorted before merging them
660 funcHint->sort();
661 sumHint->sort();
662 // Merge hints into temporary array
663 merge(funcHint->begin(),funcHint->end(),sumHint->begin(),sumHint->end(),newSumHint->begin()) ;
664
665 // Copy merged array without duplicates to new sumHintArrau
666 delete sumHint ;
667 sumHint = newSumHint ;
668 needClean = true ;
669 }
670 }
671 }
672
673 // Remove consecutive duplicates
674 if (needClean) {
675 sumHint->erase(std::unique(sumHint->begin(),sumHint->end()), sumHint->end()) ;
676 }
677
678 return sumHint ;
679}
680
681
682
683
684////////////////////////////////////////////////////////////////////////////////
685/// Label OK'ed components of a RooRealSumPdf with cache-and-track
686
688{
689 setCacheAndTrackHints(_funcList, trackNodes);
690}
691
692
694{
695 for (const auto sarg : funcList) {
696 if (sarg->canNodeBeCached()==Always) {
698 //cout << "tracking node RealSumPdf component " << sarg->ClassName() << "::" << sarg->GetName() << endl ;
699 }
700 }
701}
702
703
704////////////////////////////////////////////////////////////////////////////////
705/// Customized printing of arguments of a RooRealSumPdf to more intuitively reflect the contents of the
706/// product operator construction
707
708void RooRealSumPdf::printMetaArgs(ostream& os) const
709{
711}
712
713
714void RooRealSumPdf::printMetaArgs(RooArgList const& funcList, RooArgList const& coefList, ostream& os)
715{
716
717 bool first(true) ;
718
719 if (!coefList.empty()) {
720 auto funcIter = funcList.begin();
721
722 for (const auto coef : coefList) {
723 if (!first) {
724 os << " + " ;
725 } else {
726 first = false ;
727 }
728 const auto func = *(funcIter++);
729 os << coef->GetName() << " * " << func->GetName();
730 }
731
732 if (funcIter != funcList.end()) {
733 os << " + [%] * " << (*funcIter)->GetName() ;
734 }
735 } else {
736
737 for (const auto func : funcList) {
738 if (!first) {
739 os << " + " ;
740 } else {
741 first = false ;
742 }
743 os << func->GetName() ;
744 }
745 }
746
747 os << " " ;
748}
749
750std::unique_ptr<RooAbsArg>
752{
753 if (normSet.empty() || selfNormalized()) {
754 return RooAbsPdf::compileForNormSet({}, ctx);
755 }
756 std::unique_ptr<RooAbsPdf> pdfClone(static_cast<RooAbsPdf *>(this->Clone()));
757
758 if (ctx.likelihoodMode() && pdfClone->getAttribute("BinnedLikelihood")) {
759
760 // This has to be done before compiling the servers, such that the
761 // RooBinWidthFunctions know to disable themselves.
762 ctx.setBinnedLikelihoodMode(true);
763
764 ctx.markAsCompiled(*pdfClone);
765 ctx.compileServers(*pdfClone, {});
766
767 pdfClone->setAttribute("BinnedLikelihoodActive");
768 // If this is a binned likelihood, we're flagging it in the context.
769 // Then, the RooBinWidthFunctions know that they should not put
770 // themselves in the computation graph. Like this, the pdf values can
771 // directly be interpreted as yields, without multiplying them with the
772 // bin widths again in the NLL. However, the NLL class has to be careful
773 // to only skip the bin with multiplication when there actually were
774 // RooBinWidthFunctions! This is not the case for old workspace before
775 // ROOT 6.26. Therefore, we use the "BinnedLikelihoodActiveYields"
776 // attribute to let the NLL know what it should do.
777 if (ctx.binWidthFuncFlag()) {
778 pdfClone->setAttribute("BinnedLikelihoodActiveYields");
779 }
780 return pdfClone;
781 }
782
783 ctx.compileServers(*pdfClone, {});
784
785 RooArgSet depList;
786 pdfClone->getObservables(&normSet, depList);
787
788 auto newArg = std::make_unique<RooNormalizedPdf>(*pdfClone, depList);
789
790 // The direct servers are this pdf and the normalization integral, which
791 // don't need to be compiled further.
792 for (RooAbsArg *server : newArg->servers()) {
793 ctx.markAsCompiled(*server);
794 }
795 ctx.markAsCompiled(*newArg);
797 return newArg;
798}
799
800std::unique_ptr<RooAbsReal> RooRealSumPdf::createExpectedEventsFunc(const RooArgSet *nset) const
801{
802 if (nset == nullptr)
803 return nullptr;
804 return std::unique_ptr<RooAbsReal>{createIntegral(*nset, *getIntegratorConfig(), normRange())};
805}
#define oocoutW(o, a)
#define coutW(a)
#define oocoutE(o, a)
#define ClassImp(name)
Definition Rtypes.h:377
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:79
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
RooFit::OwningPtr< RooArgSet > getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:91
Abstract base class for objects to be stored in RooAbsCache cache manager objects.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
const_iterator end() const
Storage_t::size_type size() const
const_iterator begin() const
void Print(Option_t *options=nullptr) const override
This method must be overridden when a class wants to print itself.
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
double getNorm(const RooArgSet &nset) const
Get normalisation term needed to normalise the raw values returned by getVal().
Definition RooAbsPdf.h:196
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
@ CanBeExtended
Definition RooAbsPdf.h:213
@ CanNotBeExtended
Definition RooAbsPdf.h:213
const char * normRange() const
Definition RooAbsPdf.h:251
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:59
RooFit::OwningPtr< RooAbsReal > createIntegral(const RooArgSet &iset, const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}) const
Create an object that represents the integral of the function over one or more observables listed in ...
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:103
virtual Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &analVars, const RooArgSet *normSet, const char *rangeName=nullptr) const
Variant of getAnalyticalIntegral that is also passed the normalization set that should be applied to ...
bool getForceNumInt() const
Definition RooAbsReal.h:174
void logEvalError(const char *message, const char *serverValueString=nullptr) const
Log evaluation error message.
const RooNumIntConfig * getIntegratorConfig() const
Return the numeric integration configuration used for this object.
virtual std::list< double > * plotSamplingHint(RooAbsRealLValue &obs, double xlo, double xhi) const
Interface for returning an optional hint for initial sampling points when constructing a curve projec...
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
Int_t setObj(const RooArgSet *nset, T *obj, const TNamed *isetRangeName=nullptr)
Setter function without integration set.
RooArgSet selectFromSet1(RooArgSet const &argSet, int index) const
Create RooArgSet containing the objects that are both in the cached set 1 with a given index and an i...
T * getObjByIndex(Int_t index) const
Retrieve payload object by slot index.
RooArgSet selectFromSet2(RooArgSet const &argSet, int index) const
Create RooArgSet containing the objects that are both in the cached set 2 with a given index and an i...
Int_t lastIndex() const
Return index of slot used in last get or set operation.
T * getObj(const RooArgSet *nset, Int_t *sterileIndex=nullptr, const TNamed *isetRangeName=nullptr)
Getter function without integration set.
bool add(const RooAbsArg &var, bool valueServer, bool shapeServer, bool silent)
Overloaded RooCollection_t::add() method insert object into set and registers object as server to own...
A class to maintain the context for squashing of RooFit models into code.
void addResult(RooAbsArg const *key, std::string const &value)
A function to save an expression that includes/depends on the result of the input node.
void addToCodeBody(RooAbsArg const *klass, std::string const &in)
Adds the input string to the squashed code body.
std::string getTmpVarName() const
Get a unique variable name to be used in the generated code.
std::string buildArg(RooAbsCollection const &x)
Function to save a RooListProxy as an array in the squashed code.
void markAsCompiled(RooAbsArg &arg) const
void compileServers(RooAbsArg &arg, RooArgSet const &normSet)
std::span< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
std::span< double > output()
static const TNamed * ptr(const char *stringPtr)
Return a unique TNamed pointer for given C++ string.
Implementation of a RooCacheManager<RooAbsCacheElement> that specializes in the storage of cache elem...
Performs hybrid numerical/analytical integrals of RooAbsReal objects.
Implements a PDF constructed from a sum of functions:
void setCacheAndTrackHints(RooArgSet &) override
Label OK'ed components of a RooRealSumPdf with cache-and-track.
static bool _doFloorGlobal
Global flag for introducing floor at zero in pdf.
bool _doFloor
Introduce floor at zero in pdf.
std::unique_ptr< RooAbsReal > createExpectedEventsFunc(const RooArgSet *nset) const override
Returns an object that represents the expected number of events for a given normalization set,...
bool checkObservables(const RooArgSet *nset) const override
Check if FUNC is valid for given normalization set.
void setExtended(bool extended)
const RooArgList & funcList() const
RooObjCacheManager _normIntMgr
! The integration cache manager
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
std::list< double > * plotSamplingHint(RooAbsRealLValue &, double, double) const override
Interface for returning an optional hint for initial sampling points when constructing a curve projec...
double evaluate() const override
Calculate the current value.
ExtendMode extendMode() const override
Returns ability of PDF to provide extended likelihood terms.
RooListProxy _coefList
List of coefficients.
bool selfNormalized() const override
Shows if a PDF is self-normalized, which means that no attempt is made to add a normalization term.
RooListProxy _funcList
List of component FUNCs.
std::list< double > * binBoundaries(RooAbsRealLValue &, double, double) const override
Retrieve bin boundaries if this distribution is binned in obs.
RooRealSumPdf()
Default constructor coverity[UNINIT_CTOR].
void printMetaArgs(std::ostream &os) const override
Customized printing of arguments of a RooRealSumPdf to more intuitively reflect the contents of the p...
Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &numVars, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Advertise that all integrals can be handled internally.
double expectedEvents(const RooArgSet *nset) const override
Return expected number of events for extended likelihood calculation, which is the sum of all coeffic...
void doEval(RooFit::EvalContext &) const override
Base function for computing multiple values of a RooAbsReal.
double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Implement analytical integrations by deferring integration of component functions to integrators of c...
static std::string translateImpl(RooFit::Detail::CodeSquashContext &ctx, RooAbsArg const *klass, RooArgList const &funcList, RooArgList const &coefList, bool normalize=false)
void translate(RooFit::Detail::CodeSquashContext &ctx) const override
This function defines a translation for each RooAbsReal based object that can be used to express the ...
static void initializeFuncsAndCoefs(RooAbsReal const &caller, const RooArgList &inFuncList, const RooArgList &inCoefList, RooArgList &funcList, RooArgList &coefList)
const RooArgList & coefList() const
bool _extended
Allow use as extended p.d.f.
bool isBinnedDistribution(const RooArgSet &obs) const override
Check if all components that depend on obs are binned.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:207
const Int_t n
Definition legend1.C:16
__roodevice__ static __roohost__ double packFloatIntoNaN(float payload)
Pack float into mantissa of a NaN.
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2345
static void output()