Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooProdPdf.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 *
10 * and Stanford University. All rights reserved. *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17/**
18\file RooProdPdf.cxx
19\class RooProdPdf
20\ingroup Roofitcore
21
22Efficient implementation of a product of PDFs of the form
23\f[ \prod_{i=1}^{N} \mathrm{PDF}_i (x, \ldots) \f]
24
25PDFs may share observables. If that is the case any irreducible subset
26of PDFs that share observables will be normalised with explicit numeric
27integration as any built-in normalisation will no longer be valid.
28
29Alternatively, products using conditional PDFs can be defined, *e.g.*
30
31\f[ F(x|y) \cdot G(y), \f]
32
33meaning a PDF \f$ F(x) \f$ **given** \f$ y \f$ and a PDF \f$ G(y) \f$.
34In this construction, \f$ F \f$ is only
35normalised w.r.t \f$ x\f$, and \f$ G \f$ is normalised w.r.t \f$ y \f$. The product in this construction
36is properly normalised.
37
38If exactly one of the component PDFs supports extended likelihood fits, the
39product will also be usable in extended mode, returning the number of expected
40events from the extendable component PDF. The extendable component does not
41have to appear in any specific place in the list.
42**/
43
44#include "RooProdPdf.h"
45#include "RooBatchCompute.h"
46#include "RooRealProxy.h"
47#include "RooProdGenContext.h"
48#include "RooGenProdProj.h"
49#include "RooProduct.h"
50#include "RooNameReg.h"
51#include "RooMsgService.h"
52#include "RooFormulaVar.h"
53#include "RooRealVar.h"
54#include "RooAddition.h"
55#include "RooGlobalFunc.h"
56#include "RooConstVar.h"
57#include "RooWorkspace.h"
58#include "RooRangeBoolean.h"
59#include "RooCustomizer.h"
60#include "RooRealIntegral.h"
61#include "RooTrace.h"
62#include "RooFitImplHelpers.h"
63#include "strtok.h"
64
65#include <ROOT/StringUtils.hxx>
66
67#include <algorithm>
68#include <array>
69#include <cstring>
70#include <sstream>
71
72#ifndef _WIN32
73#include <strings.h>
74#endif
75
76using std::endl, std::string, std::vector, std::list, std::ostream, std::map, std::ostringstream;
77
78
79
80////////////////////////////////////////////////////////////////////////////////
81/// Default constructor
82
84 _cacheMgr(this,10)
85{
86 // Default constructor
88}
89
90
91////////////////////////////////////////////////////////////////////////////////
92/// Constructor with 2 PDFs (most frequent use case).
93///
94/// The optional cutOff parameter can be used as a speed optimization if
95/// one or more of the PDF have sizable regions with very small values,
96/// which would pull the entire product of PDFs to zero in those regions.
97///
98/// After each PDF multiplication, the running product is compared with
99/// the cutOff parameter. If the running product is smaller than the
100/// cutOff value, the product series is terminated and remaining PDFs
101/// are not evaluated.
102///
103/// There is no magic value of the cutOff, the user should experiment
104/// to find the appropriate balance between speed and precision.
105/// If a cutoff is specified, the PDFs most likely to be small should
106/// be put first in the product. The default cutOff value is zero.
107///
108
109RooProdPdf::RooProdPdf(const char *name, const char *title,
110 RooAbsPdf& pdf1, RooAbsPdf& pdf2, double cutOff) :
111 RooAbsPdf(name,title),
112 _cacheMgr(this,10),
113 _cutOff(cutOff),
114 _pdfList("!pdfs","List of PDFs",this)
115{
116 _pdfList.add(pdf1) ;
117 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>("nset")) ;
118 if (pdf1.canBeExtended()) {
119 _extendedIndex = _pdfList.index(&pdf1) ;
120 }
121
122 _pdfList.add(pdf2) ;
123 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>("nset")) ;
124
125 if (pdf2.canBeExtended()) {
126 if (_extendedIndex>=0) {
127 // Protect against multiple extended terms
128 coutW(InputArguments) << "RooProdPdf::RooProdPdf(" << GetName()
129 << ") multiple components with extended terms detected,"
130 << " product will not be extendable." << std::endl ;
131 _extendedIndex=-1 ;
132 } else {
134 }
135 }
137}
138
139
140
141////////////////////////////////////////////////////////////////////////////////
142/// Constructor from a list of PDFs.
143///
144/// The optional cutOff parameter can be used as a speed optimization if
145/// one or more of the PDF have sizable regions with very small values,
146/// which would pull the entire product of PDFs to zero in those regions.
147///
148/// After each PDF multiplication, the running product is compared with
149/// the cutOff parameter. If the running product is smaller than the
150/// cutOff value, the product series is terminated and remaining PDFs
151/// are not evaluated.
152///
153/// There is no magic value of the cutOff, the user should experiment
154/// to find the appropriate balance between speed and precision.
155/// If a cutoff is specified, the PDFs most likely to be small should
156/// be put first in the product. The default cutOff value is zero.
157
158RooProdPdf::RooProdPdf(const char* name, const char* title, const RooArgList& inPdfList, double cutOff) :
159 RooAbsPdf(name,title),
160 _cacheMgr(this,10),
161 _cutOff(cutOff),
162 _pdfList("!pdfs","List of PDFs",this)
163{
166}
167
168
169
170////////////////////////////////////////////////////////////////////////////////
171/// Constructor from named argument list.
172/// \param[in] name Name used by RooFit
173/// \param[in] title Title used for plotting
174/// \param[in] fullPdfSet Set of "regular" PDFs that are normalised over all their observables
175/// \param[in] arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 Optional arguments according to table below.
176///
177/// <table>
178/// <tr><th> Argument <th> Description
179/// <tr><td> `Conditional(pdfSet,depSet,depsAreCond=false)` <td> Add PDF to product with condition that it
180/// only be normalized over specified observables. Any remaining observables will be conditional observables.
181/// (Setting `depsAreCond` to true inverts this, so the observables in depSet will be the conditional observables.)
182/// </table>
183///
184/// For example, given a PDF \f$ F(x,y) \f$ and \f$ G(y) \f$,
185///
186/// `RooProdPdf("P", "P", G, Conditional(F,x))` will construct a 2-dimensional PDF as follows:
187/// \f[
188/// P(x,y) = \frac{G(y)}{\int_y G(y)} \cdot \frac{F(x,y)}{\int_x F(x,y)},
189/// \f]
190///
191/// which is a well normalised and properly defined PDF, but different from
192/// \f[
193/// P'(x,y) = \frac{F(x,y) \cdot G(y)}{\int_x\int_y F(x,y) \cdot G(y)}.
194/// \f]
195///
196/// In the former case, the \f$ y \f$ distribution of \f$ P \f$ is identical to that of \f$ G \f$, while
197/// \f$ F \f$ only is used to determine the correlation between \f$ X \f$ and \f$ Y \f$. In the latter
198/// case, the \f$ Y \f$ distribution is defined by the product of \f$ F \f$ and \f$ G \f$.
199///
200/// This \f$ P(x,y) \f$ construction is analogous to generating events from \f$ F(x,y) \f$ with
201/// a prototype dataset sampled from \f$ G(y) \f$.
202
203RooProdPdf::RooProdPdf(const char* name, const char* title, const RooArgSet& fullPdfSet,
204 const RooCmdArg& arg1, const RooCmdArg& arg2,
205 const RooCmdArg& arg3, const RooCmdArg& arg4,
206 const RooCmdArg& arg5, const RooCmdArg& arg6,
207 const RooCmdArg& arg7, const RooCmdArg& arg8) :
208 RooAbsPdf(name,title),
209 _cacheMgr(this,10),
210 _pdfList("!pdfs","List of PDFs",this)
211{
213 l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
214 l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
215 l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
216 l.Add((TObject*)&arg7) ; l.Add((TObject*)&arg8) ;
217
220}
221
222
223
224////////////////////////////////////////////////////////////////////////////////
225/// Constructor from named argument list
226
227RooProdPdf::RooProdPdf(const char* name, const char* title,
228 const RooCmdArg& arg1, const RooCmdArg& arg2,
229 const RooCmdArg& arg3, const RooCmdArg& arg4,
230 const RooCmdArg& arg5, const RooCmdArg& arg6,
231 const RooCmdArg& arg7, const RooCmdArg& arg8) :
232 RooAbsPdf(name,title),
233 _cacheMgr(this,10),
234 _pdfList("!pdfList","List of PDFs",this)
235{
237 l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
238 l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
239 l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
240 l.Add((TObject*)&arg7) ; l.Add((TObject*)&arg8) ;
241
244}
245
246
247
248////////////////////////////////////////////////////////////////////////////////
249/// Internal constructor from list of named arguments
250
251RooProdPdf::RooProdPdf(const char* name, const char* title, const RooArgSet& fullPdfSet, const RooLinkedList& cmdArgList) :
252 RooAbsPdf(name,title),
253 _cacheMgr(this,10),
254 _pdfList("!pdfs","List of PDFs",this)
255{
258}
259
260
261
262////////////////////////////////////////////////////////////////////////////////
263/// Copy constructor
264
267 _cacheMgr(other._cacheMgr,this),
268 _genCode(other._genCode),
269 _cutOff(other._cutOff),
270 _pdfList("!pdfs",this,other._pdfList),
271 _extendedIndex(other._extendedIndex),
272 _useDefaultGen(other._useDefaultGen),
273 _refRangeName(other._refRangeName),
274 _selfNorm(other._selfNorm),
275 _defNormSet(other._defNormSet)
276{
277 // Clone contents of normalizarion set list
278 for(auto const& nset : other._pdfNSetList) {
279 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>(nset->GetName()));
280 nset->snapshot(*_pdfNSetList.back());
281 }
283}
284
285
286
287////////////////////////////////////////////////////////////////////////////////
288/// Initialize RooProdPdf configuration from given list of RooCmdArg configuration arguments
289/// and set of 'regular' p.d.f.s in product
290
292{
293 Int_t numExtended(0) ;
294
295 // Process set of full PDFS
296 for(auto const* pdf : static_range_cast<RooAbsPdf*>(fullPdfSet)) {
297 _pdfList.add(*pdf) ;
298 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>("nset")) ;
299
300 if (pdf->canBeExtended()) {
302 numExtended++ ;
303 }
304
305 }
306
307 // Process list of conditional PDFs
308 for(auto * carg : static_range_cast<RooCmdArg*>(l)) {
309
310 if (0 == strcmp(carg->GetName(), "Conditional")) {
311
312 Int_t argType = carg->getInt(0) ;
313 auto pdfSet = static_cast<RooArgSet const*>(carg->getSet(0));
314 auto normSet = static_cast<RooArgSet const*>(carg->getSet(1));
315
318
319 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>(0 == argType ? "nset" : "cset"));
320 normSet->snapshot(*_pdfNSetList.back());
321
322 if (thePdf->canBeExtended()) {
324 numExtended++ ;
325 }
326
327 }
328
329 } else if (0 != strlen(carg->GetName())) {
330 coutW(InputArguments) << "Unknown arg: " << carg->GetName() << std::endl ;
331 }
332 }
333
334 // Protect against multiple extended terms
335 if (numExtended>1) {
336 coutW(InputArguments) << "RooProdPdf::RooProdPdf(" << GetName()
337 << ") WARNING: multiple components with extended terms detected,"
338 << " product will not be extendable." << std::endl ;
339 _extendedIndex = -1 ;
340 }
341
342
343}
344
345
346
347////////////////////////////////////////////////////////////////////////////////
348/// Destructor
349
354
355
357 int code ;
358 auto cache = static_cast<CacheElem*>(_cacheMgr.getObj(nset, nullptr, &code)) ;
359
360 // If cache doesn't have our configuration, recalculate here
361 if (!cache) {
362 code = getPartIntList(nset, nullptr) ;
363 cache = static_cast<CacheElem*>(_cacheMgr.getObj(nset, nullptr, &code)) ;
364 }
365 return cache;
366}
367
368
369////////////////////////////////////////////////////////////////////////////////
370/// Calculate current value of object
371
373{
375}
376
377
378
379////////////////////////////////////////////////////////////////////////////////
380/// Calculate running product of pdfs terms, using the supplied
381/// normalization set in 'normSetList' for each component
382
383double RooProdPdf::calculate(const RooProdPdf::CacheElem& cache, bool /*verbose*/) const
384{
385 if (cache._isRearranged) {
386 if (dologD(Eval)) {
387 cxcoutD(Eval) << "RooProdPdf::calculate(" << GetName() << ") rearranged product calculation"
388 << " calculate: num = " << cache._rearrangedNum->GetName() << " = " << cache._rearrangedNum->getVal() << std::endl ;
389// cache._rearrangedNum->printComponentTree("",0,5) ;
390 cxcoutD(Eval) << "calculate: den = " << cache._rearrangedDen->GetName() << " = " << cache._rearrangedDen->getVal() << std::endl ;
391// cache._rearrangedDen->printComponentTree("",0,5) ;
392 }
393
394 return cache._rearrangedNum->getVal() / cache._rearrangedDen->getVal();
395 } else {
396
397 double value = 1.0;
398 assert(cache._normList.size() == cache._partList.size());
399 for (std::size_t i = 0; i < cache._partList.size(); ++i) {
400 const auto& partInt = static_cast<const RooAbsReal&>(cache._partList[i]);
401 const auto normSet = cache._normList[i].get();
402
403 const double piVal = partInt.getVal(!normSet->empty() ? normSet : nullptr);
404 value *= piVal ;
405 if (value <= _cutOff) break;
406 }
407
408 return value ;
409 }
410}
411
412namespace {
413
414template<class T>
415void eraseNullptrs(std::vector<T*>& v) {
416 v.erase(std::remove_if(v.begin(), v.end(), [](T* x){ return x == nullptr; } ), v.end());
417}
418
419void removeCommon(std::vector<RooAbsArg*> &v, std::span<RooAbsArg * const> other) {
420
421 for (auto const& arg : other) {
422 auto namePtrMatch = [&arg](const RooAbsArg* elm) {
423 return elm != nullptr && elm->namePtr() == arg->namePtr();
424 };
425
426 auto found = std::find_if(v.begin(), v.end(), namePtrMatch);
427 if(found != v.end()) {
428 *found = nullptr;
429 }
430 }
432}
433
434void addCommon(std::vector<RooAbsArg*> &v, std::vector<RooAbsArg*> const& o1, std::vector<RooAbsArg*> const& o2) {
435
436 for (auto const& arg : o1) {
437 auto namePtrMatch = [&arg](const RooAbsArg* elm) {
438 return elm->namePtr() == arg->namePtr();
439 };
440
441 if(std::find_if(o2.begin(), o2.end(), namePtrMatch) != o2.end()) {
442 v.push_back(arg);
443 }
444 }
445}
446
447bool isRangeIdentical(RooArgSet const &observables, TString const &normRange, TNamed *refRangeName)
448{
449 // FK: Here the refRange should be compared to normRange, if it's set, and to the normObs range if it's not set
450 const char *range = normRange.Length() > 0 ? normRange.Data() : nullptr;
451 const char *refRange = RooNameReg::str(refRangeName);
452 for (auto const *normObs : static_range_cast<RooRealVar *>(observables)) {
453 if (normObs->getMin(range) != normObs->getMin(refRange) || normObs->getMax(range) != normObs->getMax(refRange))
454 return false;
455 }
456 return true;
457}
458
459}
460
461
462////////////////////////////////////////////////////////////////////////////////
463/// Factorize product in irreducible terms for given choice of integration/normalization
464
466{
467 // List of all term dependents: normalization and imported
468 std::vector<RooArgSet> depAllList;
469 std::vector<RooArgSet> depIntNoNormList;
470
471 // Setup lists for factorization terms and their dependents
472 RooArgSet* term(nullptr);
473 RooArgSet* termIntDeps(nullptr);
475
476 std::vector<RooAbsArg*> pdfIntNoNormDeps;
477 std::vector<RooAbsArg*> pdfIntSet;
478 std::vector<RooAbsArg*> pdfNSet;
479 std::vector<RooAbsArg*> pdfCSet;
480 std::vector<RooAbsArg*> pdfNormDeps; // Dependents to be normalized for the PDF
481 std::vector<RooAbsArg*> pdfAllDeps; // All dependents of this PDF
482
483 // Loop over the PDFs
484 for(std::size_t iPdf = 0; iPdf < _pdfList.size(); ++iPdf) {
485 RooAbsPdf& pdf = static_cast<RooAbsPdf&>(_pdfList[iPdf]);
487
488 pdfNSet.clear();
489 pdfCSet.clear();
490
491 // Make iterator over tree leaf node list to get the observables.
492 // This code is borrowed from RooAbsPdf::getObservables().
493 // RooAbsArg::treeNodeServer list is relatively expensive, so we only do it
494 // once and use it in a lambda function.
495 RooArgSet pdfLeafList("leafNodeServerList") ;
496 pdf.treeNodeServerList(&pdfLeafList,nullptr,false,true,true) ;
498 std::vector<RooAbsArg*> & out,
499 const RooArgSet& dataList) {
500 for (const auto arg : pdfLeafList) {
501 if (arg->dependsOnValue(dataList) && arg->isLValue()) {
502 out.push_back(arg) ;
503 }
504 }
505 };
506
507 // Reduce pdfNSet to actual dependents
508 if (0 == strcmp("cset", pdfNSetOrig.GetName())) {
511 pdfCSet = pdfNSetOrig.get();
512 } else {
513 // Interpret at NSet
515 }
516
517
518 pdfNormDeps.clear();
519 pdfAllDeps.clear();
520
521 // Make list of all dependents of this PDF
523
524
525 // Make list of normalization dependents for this PDF;
526 if (!pdfNSet.empty()) {
527 // PDF is conditional
529 } else {
530 // PDF is regular
532 }
533
534 pdfIntSet.clear();
536
537 // WVE if we have no norm deps, conditional observables should be taken out of pdfIntSet
538 if (pdfNormDeps.empty() && !pdfCSet.empty()) {
540 }
541
542 pdfIntNoNormDeps.clear();
545
546 // Check if this PDF has dependents overlapping with one of the existing terms
547 bool done = false;
548 int j = 0;
549 auto lIter = factorized.terms.begin();
550 auto ldIter = factorized.norms.begin();
551 for(;lIter != factorized.terms.end(); (++lIter, ++ldIter, ++j)) {
552 RooArgSet *termNormDeps = static_cast<RooArgSet*>(*ldIter);
553 term = static_cast<RooArgSet*>(*lIter);
554 // PDF should be added to existing term if
555 // 1) It has overlapping normalization dependents with any other PDF in existing term
556 // 2) It has overlapping dependents of any class for which integration is requested
557 // 3) If normalization happens over multiple ranges, and those ranges are both defined
558 // in either observable
559
560 bool normOverlap = termNormDeps->overlaps(pdfNormDeps.begin(), pdfNormDeps.end());
561 //bool intOverlap = pdfIntSet->overlaps(*termAllDeps);
562
563 if (normOverlap) {
564 term->add(pdf);
565 termNormDeps->add(pdfNormDeps.begin(), pdfNormDeps.end(), false);
566 depAllList[j].add(pdfAllDeps.begin(), pdfAllDeps.end(), false);
567 if (termIntDeps) {
568 termIntDeps->add(pdfIntSet.begin(), pdfIntSet.end(), false);
569 }
570 if (termIntNoNormDeps) {
572 }
574 done = true;
575 }
576 }
577
578 // If not, create a new term
579 if (!done) {
580 if (!(pdfNormDeps.empty() && pdfAllDeps.empty() &&
581 pdfIntSet.empty()) || normSet.empty()) {
582 term = new RooArgSet("term");
583 RooArgSet *termNormDeps = new RooArgSet("termNormDeps");
584 depAllList.emplace_back(pdfAllDeps.begin(), pdfAllDeps.end(), "termAllDeps");
585 termIntDeps = new RooArgSet(pdfIntSet.begin(), pdfIntSet.end(), "termIntDeps");
586 depIntNoNormList.emplace_back(pdfIntNoNormDeps.begin(), pdfIntNoNormDeps.end(), "termIntNoNormDeps");
588
589 term->add(pdf);
590 termNormDeps->add(pdfNormDeps.begin(), pdfNormDeps.end(), false);
591
592 factorized.terms.Add(term);
593 factorized.norms.Add(termNormDeps);
594 factorized.ints.Add(termIntDeps);
595 }
596 }
597
598 }
599
600 // Loop over list of terms again to determine 'imported' observables
601 int i = 0;
603 auto lIter = factorized.terms.begin();
604 auto ldIter = factorized.norms.begin();
605 for(;lIter != factorized.terms.end(); (++lIter, ++ldIter, ++i)) {
606 normDeps = static_cast<RooArgSet*>(*ldIter);
607 term = static_cast<RooArgSet*>(*lIter);
608 // Make list of wholly imported dependents
610 impDeps.remove(*normDeps, true, true);
611 auto snap = new RooArgSet;
612 impDeps.snapshot(*snap);
613 factorized.imps.Add(snap);
614
615 // Make list of cross dependents (term is self contained for these dependents,
616 // but components import dependents from other components)
617 auto crossDeps = std::unique_ptr<RooAbsCollection>{depIntNoNormList[i].selectCommon(*normDeps)};
618 snap = new RooArgSet;
619 crossDeps->snapshot(*snap);
620 factorized.cross.Add(snap);
621 }
622}
623
624
625
626
627////////////////////////////////////////////////////////////////////////////////
628/// Return list of (partial) integrals of product terms for integration
629/// of p.d.f over observables iset while normalization over observables nset.
630/// Also return list of normalization sets to be used to evaluate
631/// each component in the list correctly.
632
634{
635 // Check if this configuration was created before
636 Int_t sterileIdx(-1);
637
638 if (static_cast<CacheElem*>(_cacheMgr.getObj(nset,iset,&sterileIdx,isetRangeName))) {
639 return _cacheMgr.lastIndex();
640 }
641
642 std::unique_ptr<CacheElem> cache = createCacheElem(nset, iset, isetRangeName);
643
644 // Store the partial integral list and return the assigned code
645 return _cacheMgr.setObj(nset, iset, cache.release(), RooNameReg::ptr(isetRangeName));
646}
647
648
649
650std::unique_ptr<RooProdPdf::CacheElem> RooProdPdf::createCacheElem(const RooArgSet* nset,
651 const RooArgSet* iset,
652 const char* isetRangeName) const
653{
654 // Create containers for partial integral components to be generated
655 auto cache = std::make_unique<CacheElem>();
656
657 // Factorize the product in irreducible terms for this nset
659
660 // Normalization set used for factorization
661 RooArgSet factNset(nset ? (*nset) : _defNormSet);
662
664
665 // Group irriducible terms that need to be (partially) integrated together
666 std::list<std::vector<RooArgSet*>> groupedList;
669
670 // Loop over groups
671 // Find groups of type F(x|y), i.e. termImpSet!=0, construct ratio object
672 std::map<std::string, RooArgSet> ratioTerms;
673 for (auto const& group : groupedList) {
674 if (1 == group.size()) {
675 RooArgSet* term = group[0];
676
677 Int_t termIdx = factorized.terms.IndexOf(term);
678 RooArgSet *norm=static_cast<RooArgSet*>(factorized.norms.At(termIdx));
679 RooArgSet *imps=static_cast<RooArgSet*>(factorized.imps.At(termIdx));
681 RooArgSet termImpSet(*imps);
682
683 if (!termImpSet.empty() && nullptr != _refRangeName) {
684
685 // WVE we can skip this if the ref range is equal to the normalization range
686 // LM : avoid making integral ratio if range is the same. Why was not included ??? (same at line 857)
689 std::ostringstream str; termImpSet.printValue(str);
690 ratioTerms[str.str()].addOwned(std::move(ratio));
691 }
692 }
693
694 } else {
695 for (auto const& term : group) {
696
697 Int_t termIdx = factorized.terms.IndexOf(term);
698 RooArgSet *norm=static_cast<RooArgSet*>(factorized.norms.At(termIdx));
699 RooArgSet *imps=static_cast<RooArgSet*>(factorized.imps.At(termIdx));
701 RooArgSet termImpSet(*imps);
702
703 if (!termImpSet.empty() && nullptr != _refRangeName) {
704
705 // WVE we can skip this if the ref range is equal to the normalization range
708 std::ostringstream str; termImpSet.printValue(str);
709 ratioTerms[str.str()].addOwned(std::move(ratio));
710 }
711 }
712 }
713 }
714
715 }
716
717 // Find groups with y as termNSet
718 // Replace G(y) with (G(y),ratio)
719 for (auto const& group : groupedList) {
720 for (auto const& term : group) {
721 Int_t termIdx = factorized.terms.IndexOf(term);
722 RooArgSet *norm = static_cast<RooArgSet*>(factorized.norms.At(termIdx));
723 RooArgSet *imps = static_cast<RooArgSet*>(factorized.imps.At(termIdx));
725 RooArgSet termImpSet(*imps);
726
727 // If termNset matches index of ratioTerms, insert ratio here
728 ostringstream str; termNSet.printValue(str);
729 if (!ratioTerms[str.str()].empty()) {
730 term->add(ratioTerms[str.str()]);
731 cache->_ownedList.addOwned(std::move(ratioTerms[str.str()]));
732 }
733 }
734 }
735
736 for (auto const& group : groupedList) {
737 if (1 == group.size()) {
738 RooArgSet* term = group[0];
739
740 Int_t termIdx = factorized.terms.IndexOf(term);
741 RooArgSet *norm = factorized.termNormDeps(termIdx);
742 RooArgSet *integ = factorized.termIntDeps(termIdx);
743 RooArgSet *xdeps = factorized.termCrossDeps(termIdx);
744 RooArgSet *imps = factorized.termImpDeps(termIdx);
745
746 // Take list of normalization, integrated dependents, and
747 // cross-imported integrated dependents from factorization algorithm
751 RooArgSet termImpSet{*imps};
752
753 // Add prefab term to partIntList.
755 if (func.x0) {
756 cache->_partList.add(*func.x0);
757 if (func.isOwned) cache->_ownedList.addOwned(std::unique_ptr<RooAbsArg>{func.x0});
758
759 cache->_normList.emplace_back(std::make_unique<RooArgSet>());
760 norm->snapshot(*cache->_normList.back(), false);
761
762 cache->_numList.addOwned(std::move(func.x1));
763 cache->_denList.addOwned(std::move(func.x2));
764 }
765 } else {
770 for (auto const &term : group) {
771 Int_t termIdx = factorized.terms.IndexOf(term);
772 RooArgSet *norm = factorized.termNormDeps(termIdx);
773 RooArgSet *integ = factorized.termIntDeps(termIdx);
774 RooArgSet *xdeps = factorized.termCrossDeps(termIdx);
775 RooArgSet *imps = factorized.termImpDeps(termIdx);
776
780 RooArgSet termImpSet{*imps};
781
782 // Remove outer integration dependents from termISet
783 termISet.remove(outerIntDeps, true, true);
784
785 auto func = processProductTerm(nset, iset, isetRangeName, term, termNSet, termISet, true);
786 if (func.x0) {
787 compTermSet.add(*func.x0);
788 if (func.isOwned) cache->_ownedList.addOwned(std::unique_ptr<RooAbsArg>{func.x0});
789 compTermNorm.add(*norm, false);
790
791 compTermNum.add(*func.x1.release());
792 compTermDen.add(*func.x2.release());
793
794 }
795 }
796
797 // WVE THIS NEEDS TO BE REARRANGED
798
799 // compTermset is set van partial integrals to be multiplied
800 // prodtmp = product (compTermSet)
801 // inttmp = int ( prodtmp ) d (outerIntDeps) _range_isetRangeName
802
803 const std::string prodname = makeRGPPName("SPECPROD", compTermSet, outerIntDeps, RooArgSet(), isetRangeName);
804 auto prodtmp = std::make_unique<RooProduct>(prodname.c_str(), prodname.c_str(), compTermSet);
805
806 const std::string intname = makeRGPPName("SPECINT", compTermSet, outerIntDeps, RooArgSet(), isetRangeName);
807 auto inttmp = std::make_unique<RooRealIntegral>(intname.c_str(), intname.c_str(), *prodtmp, outerIntDeps, nullptr, nullptr, isetRangeName);
808 inttmp->setStringAttribute("PROD_TERM_TYPE", "SPECINT");
809
810 cache->_partList.add(*inttmp);
811
812 // Product of numerator terms
813 const string prodname_num = makeRGPPName("SPECPROD_NUM", compTermNum, RooArgSet(), RooArgSet(), nullptr);
814 auto prodtmp_num = std::make_unique<RooProduct>(prodname_num.c_str(), prodname_num.c_str(), compTermNum);
815 prodtmp_num->addOwnedComponents(compTermNum);
816
817 // Product of denominator terms
818 const string prodname_den = makeRGPPName("SPECPROD_DEN", compTermDen, RooArgSet(), RooArgSet(), nullptr);
819 auto prodtmp_den = std::make_unique<RooProduct>(prodname_den.c_str(), prodname_den.c_str(), compTermDen);
820 prodtmp_den->addOwnedComponents(compTermDen);
821
822 // Ratio
823 std::string name = Form("SPEC_RATIO(%s,%s)", prodname_num.c_str(), prodname_den.c_str());
824 auto ndr = std::make_unique<RooFormulaVar>(name.c_str(), "@0/@1", RooArgList(*prodtmp_num, *prodtmp_den));
825
826 // Integral of ratio
827 std::unique_ptr<RooAbsReal> numtmp{ndr->createIntegral(outerIntDeps,isetRangeName)};
828 numtmp->addOwnedComponents(std::move(ndr));
829
830 cache->_ownedList.addOwned(std::move(prodtmp));
831 cache->_ownedList.addOwned(std::move(inttmp));
832 cache->_ownedList.addOwned(std::move(prodtmp_num));
833 cache->_ownedList.addOwned(std::move(prodtmp_den));
834 cache->_numList.addOwned(std::move(numtmp));
835 cache->_denList.addOwned(std::unique_ptr<RooAbsArg>{static_cast<RooAbsArg*>(RooFit::RooConst(1).clone("1"))});
836 cache->_normList.emplace_back(std::make_unique<RooArgSet>());
837 compTermNorm.snapshot(*cache->_normList.back(), false);
838 }
839 }
840
841 // Need to rearrange product in case of multiple ranges
842 if (_normRange.Contains(",")) {
843 rearrangeProduct(*cache);
844 }
845
846 return cache;
847}
848
849
851{
852 // We own contents of all lists filled by factorizeProduct()
853 terms.Delete();
854 ints.Delete();
855 imps.Delete();
856 norms.Delete();
857 cross.Delete();
858}
859
860
861////////////////////////////////////////////////////////////////////////////////
862/// For single normalization ranges
863
864std::unique_ptr<RooAbsReal> RooProdPdf::makeCondPdfRatioCorr(RooAbsReal& pdf, const RooArgSet& termNset, const RooArgSet& /*termImpSet*/, const char* normRangeTmp, const char* refRange) const
865{
866 std::unique_ptr<RooAbsReal> ratio_num{pdf.createIntegral(termNset,normRangeTmp)};
867 std::unique_ptr<RooAbsReal> ratio_den{pdf.createIntegral(termNset,refRange)};
868 auto ratio = std::make_unique<RooFormulaVar>(Form("ratio(%s,%s)",ratio_num->GetName(),ratio_den->GetName()),"@0/@1",
870
871 ratio->addOwnedComponents(std::move(ratio_num));
872 ratio->addOwnedComponents(std::move(ratio_den));
873 ratio->setAttribute("RATIO_TERM") ;
874 return ratio ;
875}
876
877
878
879
880////////////////////////////////////////////////////////////////////////////////
881
883{
885
886 std::vector<std::string> rangeComps = ROOT::Split(_normRange.Data(), ",", /*skipEmpty=*/true);
887
888 std::map<std::string,RooArgSet> denListList ;
890 string specIntRange ;
891
892 for (std::size_t i = 0; i < cache._partList.size(); i++) {
893
894 RooAbsReal *part = static_cast<RooAbsReal*>(cache._partList.at(i));
895 RooAbsReal *num = static_cast<RooAbsReal*>(cache._numList.at(i));
896 RooAbsReal *den = static_cast<RooAbsReal*>(cache._denList.at(i));
897 i++;
898
899
900 RooFormulaVar* ratio(nullptr) ;
902
903 if (string("SPECINT")==part->getStringAttribute("PROD_TERM_TYPE")) {
904
905 RooRealIntegral* orig = static_cast<RooRealIntegral*>(num);
906 auto specratio = static_cast<RooFormulaVar const*>(&orig->integrand()) ;
907 RooProduct* func = static_cast<RooProduct*>(specratio->getParameter(0)) ;
908
909 std::unique_ptr<RooArgSet> components{orig->getComponents()};
910 for(RooAbsArg * carg : *components) {
911 if (carg->getAttribute("RATIO_TERM")) {
912 ratio = static_cast<RooFormulaVar*>(carg) ;
913 break ;
914 }
915 }
916
917 if (ratio) {
918 RooCustomizer cust(*func,"blah") ;
919 cust.replaceArg(*ratio,RooFit::RooConst(1)) ;
920 nomList.add(*cust.build()) ;
921 } else {
922 nomList.add(*func) ;
923 }
924
925
926 } else {
927
928 // Find the ratio term
929 RooAbsReal* func = num;
930 // If top level object is integral, navigate to integrand
932 func = const_cast<RooAbsReal*>(&static_cast<RooRealIntegral*>(func)->integrand());
933 }
934 if (func->InheritsFrom(RooProduct::Class())) {
935 for(RooAbsArg * arg : static_cast<RooProduct*>(func)->components()) {
936 if (arg->getAttribute("RATIO_TERM")) {
937 ratio = static_cast<RooFormulaVar*>(arg) ;
938 } else {
939 origNumTerm.add(*arg) ;
940 }
941 }
942 }
943
944 if (ratio) {
945 nomList.add(origNumTerm) ;
946 } else {
947 nomList.add(*num) ;
948 }
949
950 }
951
952 for (auto iter = rangeComps.begin() ; iter != rangeComps.end() ; ++iter) {
953 // If denominator is an integral, make a clone with the integration range adjusted to
954 // the selected component of the normalization integral
955
956 if (string("SPECINT")==part->getStringAttribute("PROD_TERM_TYPE")) {
957
958 RooRealIntegral* orig = static_cast<RooRealIntegral*>(num);
959 auto specRatio = static_cast<RooFormulaVar const*>(&orig->integrand()) ;
960 specIntDeps.add(orig->intVars()) ;
961 if (orig->intRange()) {
962 specIntRange = orig->intRange() ;
963 }
964 //RooProduct* numtmp = (RooProduct*) specRatio->getParameter(0) ;
965 RooProduct* dentmp = static_cast<RooProduct*>(specRatio->getParameter(1)) ;
966
967 for (auto* parg : static_range_cast<RooAbsReal*>(dentmp->components())) {
968 if (ratio && parg->dependsOn(*ratio)) {
969 // Make specialize ratio instance
970 std::unique_ptr<RooAbsReal> specializedRatio{specializeRatio(*(RooFormulaVar*)ratio,iter->c_str())};
971
972 // Replace generic ratio with specialized ratio
973 RooAbsArg *partCust(nullptr) ;
974 if (parg->InheritsFrom(RooAddition::Class())) {
975
976
977
978 RooAddition* tmpadd = static_cast<RooAddition*>(parg) ;
979
980 RooCustomizer cust(*tmpadd->list1().first(), ("blah_" + *iter).c_str());
981 cust.replaceArg(*ratio,*specializedRatio) ;
982 partCust = cust.build() ;
983
984 } else {
985 RooCustomizer cust(*parg, ("blah_" + *iter).c_str());
986 cust.replaceArg(*ratio, *specializedRatio);
987 partCust = cust.build();
988 }
989
990 // Print customized denominator
991
992 std::unique_ptr<RooAbsReal> specializedPartCust{specializeIntegral(*static_cast<RooAbsReal*>(partCust),iter->c_str())};
993
994 // Finally divide again by ratio
995 string name = Form("%s_divided_by_ratio",specializedPartCust->GetName()) ;
996 auto specIntFinal = std::make_unique<RooFormulaVar>(name.c_str(),"@0/@1",RooArgList(*specializedPartCust,*specializedRatio)) ;
997 specIntFinal->addOwnedComponents(std::move(specializedPartCust));
998 specIntFinal->addOwnedComponents(std::move(specializedRatio));
999
1000 denListList[*iter].addOwned(std::move(specIntFinal));
1001 } else {
1002
1003 denListList[*iter].addOwned(specializeIntegral(*parg,iter->c_str()));
1004
1005 }
1006 }
1007 } else {
1008
1009 if (ratio) {
1010
1011 std::unique_ptr<RooAbsReal> specRatio{specializeRatio(*(RooFormulaVar*)ratio,iter->c_str())};
1012
1013 // If integral is 'Int r(y)*g(y) dy ' then divide a posteriori by r(y)
1014
1016 tmp.add(*specRatio) ;
1017 const string pname = makeRGPPName("PROD",tmp,RooArgSet(),RooArgSet(),nullptr) ;
1018 auto specDenProd = std::make_unique<RooProduct>(pname.c_str(),pname.c_str(),tmp) ;
1019 std::unique_ptr<RooAbsReal> specInt;
1020
1021 if (den->InheritsFrom(RooRealIntegral::Class())) {
1022 specInt = std::unique_ptr<RooAbsReal>{specDenProd->createIntegral((static_cast<RooRealIntegral*>(den))->intVars(),iter->c_str())};
1023 specInt->addOwnedComponents(std::move(specDenProd));
1024 } else if (den->InheritsFrom(RooAddition::Class())) {
1025 RooAddition* orig = static_cast<RooAddition*>(den) ;
1026 RooRealIntegral* origInt = static_cast<RooRealIntegral*>(orig->list1().first()) ;
1027 specInt = std::unique_ptr<RooAbsReal>{specDenProd->createIntegral(origInt->intVars(),iter->c_str())};
1028 specInt->addOwnedComponents(std::move(specDenProd));
1029 } else {
1030 throw string("this should not happen") ;
1031 }
1032
1033 //RooAbsReal* specInt = specializeIntegral(*den,iter->c_str()) ;
1034 string name = Form("%s_divided_by_ratio",specInt->GetName()) ;
1035 auto specIntFinal = std::make_unique<RooFormulaVar>(name.c_str(),"@0/@1",RooArgList(*specInt,*specRatio)) ;
1036 specIntFinal->addOwnedComponents(std::move(specInt));
1037 specIntFinal->addOwnedComponents(std::move(specRatio));
1038 denListList[*iter].addOwned(std::move(specIntFinal));
1039 } else {
1040 denListList[*iter].addOwned(specializeIntegral(*den,iter->c_str()));
1041 }
1042
1043 }
1044 }
1045
1046 }
1047
1048 // Do not rearrange terms if numerator and denominator are effectively empty
1049 if (nomList.empty()) {
1050 return ;
1051 }
1052
1053 string name = std::string{GetName()} + "_numerator";
1054 // WVE FIX THIS (2)
1055
1056 std::unique_ptr<RooAbsReal> numerator = std::make_unique<RooProduct>(name.c_str(),name.c_str(),nomList) ;
1057
1059 for (map<string,RooArgSet>::iterator iter = denListList.begin() ; iter != denListList.end() ; ++iter) {
1060 name = Form("%s_denominator_comp_%s",GetName(),iter->first.c_str()) ;
1061 // WVE FIX THIS (2)
1062 RooProduct* prod_comp = new RooProduct(name.c_str(),name.c_str(),iter->second) ;
1063 prod_comp->addOwnedComponents(std::move(iter->second));
1064 products.add(*prod_comp) ;
1065 }
1066 name = Form("%s_denominator_sum",GetName()) ;
1067 RooAbsReal* norm = new RooAddition(name.c_str(),name.c_str(),products) ;
1068 norm->addOwnedComponents(products) ;
1069
1070 if (!specIntDeps.empty()) {
1071 // Apply posterior integration required for SPECINT case
1072
1073 string namesr = Form("SPEC_RATIO(%s,%s)",numerator->GetName(),norm->GetName()) ;
1074 RooFormulaVar* ndr = new RooFormulaVar(namesr.c_str(),"@0/@1",RooArgList(*numerator,*norm)) ;
1075 ndr->addOwnedComponents(std::move(numerator));
1076
1077 // Integral of ratio
1078 numerator = std::unique_ptr<RooAbsReal>{ndr->createIntegral(specIntDeps,specIntRange.c_str())};
1079
1080 norm = static_cast<RooAbsReal*>(RooFit::RooConst(1).Clone()) ;
1081 }
1082
1083
1084
1085 // WVE DEBUG
1086 //RooMsgService::instance().debugWorkspace()->import(RooArgSet(*numerator,*norm)) ;
1087
1088 cache._rearrangedNum = std::move(numerator);
1089 cache._rearrangedDen.reset(norm);
1090 cache._isRearranged = true ;
1091
1092}
1093
1094
1095////////////////////////////////////////////////////////////////////////////////
1096
1097std::unique_ptr<RooAbsReal> RooProdPdf::specializeRatio(RooFormulaVar& input, const char* targetRangeName) const
1098{
1099 RooRealIntegral* numint = static_cast<RooRealIntegral*>(input.getParameter(0)) ;
1100 RooRealIntegral* denint = static_cast<RooRealIntegral*>(input.getParameter(1)) ;
1101
1102 std::unique_ptr<RooAbsReal> numint_spec{specializeIntegral(*numint,targetRangeName)};
1103
1104 std::unique_ptr<RooAbsReal> ret = std::make_unique<RooFormulaVar>(Form("ratio(%s,%s)",numint_spec->GetName(),denint->GetName()),"@0/@1",RooArgList(*numint_spec,*denint)) ;
1105 ret->addOwnedComponents(std::move(numint_spec));
1106
1107 return ret;
1108}
1109
1110
1111
1112////////////////////////////////////////////////////////////////////////////////
1113
1114std::unique_ptr<RooAbsReal> RooProdPdf::specializeIntegral(RooAbsReal& input, const char* targetRangeName) const
1115{
1116 if (input.InheritsFrom(RooRealIntegral::Class())) {
1117
1118 // If input is integral, recreate integral but override integration range to be targetRangeName
1119 RooRealIntegral* orig = static_cast<RooRealIntegral*>(&input) ;
1120 return std::unique_ptr<RooAbsReal>{orig->integrand().createIntegral(orig->intVars(),targetRangeName)};
1121
1122 } else if (input.InheritsFrom(RooAddition::Class())) {
1123
1124 // If input is sum of integrals, recreate integral from first component of set, but override integration range to be targetRangeName
1125 RooAddition* orig = static_cast<RooAddition*>(&input) ;
1126 RooRealIntegral* origInt = static_cast<RooRealIntegral*>(orig->list1().first()) ;
1127 return std::unique_ptr<RooAbsReal>{origInt->integrand().createIntegral(origInt->intVars(),targetRangeName)};
1128 }
1129
1130 std::stringstream errMsg;
1131 errMsg << "specializeIntegral: unknown input type " << input.ClassName() << "::" << input.GetName();
1132 throw std::runtime_error(errMsg.str());
1133}
1134
1135
1136////////////////////////////////////////////////////////////////////////////////
1137/// Group product into terms that can be calculated independently
1138
1139void RooProdPdf::groupProductTerms(std::list<std::vector<RooArgSet*>>& groupedTerms, RooArgSet& outerIntDeps,
1140 Factorized const &factorized) const
1141{
1142 // Start out with each term in its own group
1143 for(auto * term : static_range_cast<RooArgSet*>(factorized.terms)) {
1144 groupedTerms.emplace_back();
1145 groupedTerms.back().emplace_back(term) ;
1146 }
1147
1148 // Make list of imported dependents that occur in any term
1151 allImpDeps.add(*impDeps,false) ;
1152 }
1153
1154 // Make list of integrated dependents that occur in any term
1157 allIntDeps.add(*intDeps,false) ;
1158 }
1159
1160 outerIntDeps.removeAll() ;
1161 outerIntDeps.add(*std::unique_ptr<RooArgSet>{allIntDeps.selectCommon(allImpDeps)});
1162
1163 // Now iteratively merge groups that should be (partially) integrated together
1165
1166 // Collect groups that feature this dependent
1167 std::vector<RooArgSet*>* newGroup = nullptr ;
1168
1169 // Loop over groups
1170 bool needMerge = false ;
1171 auto group = groupedTerms.begin();
1172 auto nGroups = groupedTerms.size();
1173 for (size_t iGroup = 0; iGroup < nGroups; ++iGroup) {
1174
1175 // See if any term in this group depends in any ay on outerDepInt
1176 for (auto const& term2 : *group) {
1177
1178 Int_t termIdx = factorized.terms.IndexOf(term2) ;
1179 if (factorized.termNormDeps(termIdx)->contains(*outerIntDep) ||
1180 factorized.termIntDeps(termIdx)->contains(*outerIntDep) ||
1181 factorized.termImpDeps(termIdx)->contains(*outerIntDep)) {
1182 needMerge = true ;
1183 }
1184
1185 }
1186
1187 if (needMerge) {
1188 // Create composite group if not yet existing
1189 if (newGroup==nullptr) {
1190 groupedTerms.emplace_back() ;
1191 newGroup = &groupedTerms.back() ;
1192 }
1193
1194 // Add terms of this group to new term
1195 for (auto& term2 : *group) {
1196 newGroup->emplace_back(term2) ;
1197 }
1198
1199 // Remove this non-owning group from list
1200 group = groupedTerms.erase(group);
1201 } else {
1202 ++group;
1203 }
1204 }
1205
1206 }
1207}
1208
1209
1210
1211////////////////////////////////////////////////////////////////////////////////
1212/// Calculate integrals of factorized product terms over observables iset while normalized
1213/// to observables in nset.
1214
1216 const RooArgSet* term,const RooArgSet& termNSet, const RooArgSet& termISet,
1217 bool forceWrap) const
1218{
1220
1221 // CASE I: factorizing term: term is integrated over all normalizing observables
1222 // -----------------------------------------------------------------------------
1223 // Check if all observbales of this term are integrated. If so the term cancels
1224 if (!termNSet.empty() && termNSet.size()==termISet.size() && isetRangeName==nullptr) {
1225 // Term factorizes
1226 return ret ;
1227 }
1228
1229 // CASE II: Dropped terms: if term is entirely unnormalized, it should be dropped
1230 // ------------------------------------------------------------------------------
1231 if (nset && termNSet.empty()) {
1232 // Drop terms that are not asked to be normalized
1233 return ret ;
1234 }
1235
1236 if (iset && !termISet.empty()) {
1237 if (term->size()==1) {
1238
1239 // CASE IIIa: Normalized and partially integrated single PDF term
1240 //---------------------------------------------------------------
1241
1242 RooAbsPdf* pdf = static_cast<RooAbsPdf*>(term->first()) ;
1243
1244 ret.x0 = std::unique_ptr<RooAbsReal>{pdf->createIntegral(termISet,termNSet,isetRangeName)}.release();
1245 ret.x0->setOperMode(operMode()) ;
1246 ret.x0->setStringAttribute("PROD_TERM_TYPE","IIIa") ;
1247
1248 ret.isOwned=true ;
1249
1250 // Split mode results
1251 ret.x1 = std::unique_ptr<RooAbsReal>{pdf->createIntegral(termISet,isetRangeName)};
1252 ret.x2 = std::unique_ptr<RooAbsReal>{pdf->createIntegral(termNSet,normRange())};
1253
1254 return ret ;
1255
1256 } else {
1257
1258 // CASE IIIb: Normalized and partially integrated composite PDF term
1259 //---------------------------------------------------------------
1260
1261 // Use auxiliary class RooGenProdProj to calculate this term
1262 const std::string name = makeRGPPName("GENPROJ_",*term,termISet,termNSet,isetRangeName) ;
1263 ret.x0 = new RooGenProdProj(name.c_str(),name.c_str(),*term,termISet,termNSet,isetRangeName) ;
1264 ret.x0->setStringAttribute("PROD_TERM_TYPE","IIIb") ;
1265 ret.x0->setOperMode(operMode()) ;
1266
1267 ret.isOwned=true ;
1268
1269 const std::string name1 = makeRGPPName("PROD",*term,RooArgSet(),RooArgSet(),nullptr) ;
1270
1271 // WVE FIX THIS
1272 RooProduct* tmp_prod = new RooProduct(name1.c_str(),name1.c_str(),*term) ;
1273
1274 ret.x1 = std::unique_ptr<RooAbsReal>{tmp_prod->createIntegral(termISet,isetRangeName)};
1275 ret.x2 = std::unique_ptr<RooAbsReal>{tmp_prod->createIntegral(termNSet,normRange())};
1276
1277 return ret ;
1278 }
1279 }
1280
1281 // CASE IVa: Normalized non-integrated composite PDF term
1282 // -------------------------------------------------------
1283 if (nset && !nset->empty() && term->size()>1) {
1284 // Composite term needs normalized integration
1285
1286 const std::string name = makeRGPPName("GENPROJ_",*term,termISet,termNSet,isetRangeName) ;
1287 ret.x0 = new RooGenProdProj(name.c_str(),name.c_str(),*term,termISet,termNSet,isetRangeName,normRange()) ;
1288 ret.x0->setExpensiveObjectCache(expensiveObjectCache()) ;
1289
1290 ret.x0->setStringAttribute("PROD_TERM_TYPE","IVa") ;
1291 ret.x0->setOperMode(operMode()) ;
1292
1293 ret.isOwned=true ;
1294
1295 const std::string name1 = makeRGPPName("PROD",*term,RooArgSet(),RooArgSet(),nullptr) ;
1296
1297 // WVE FIX THIS
1298 RooProduct* tmp_prod = new RooProduct(name1.c_str(),name1.c_str(),*term) ;
1299
1300 ret.x1 = std::unique_ptr<RooAbsReal>{tmp_prod->createIntegral(termISet,isetRangeName)};
1301 ret.x2 = std::unique_ptr<RooAbsReal>{tmp_prod->createIntegral(termNSet,normRange())};
1302
1303 return ret ;
1304 }
1305
1306 // CASE IVb: Normalized, non-integrated single PDF term
1307 // -----------------------------------------------------
1308 for (auto* pdf : static_range_cast<RooAbsPdf*>(*term)) {
1309
1310 ret.isOwned = false;
1311 RooAbsReal *ret0 = pdf;
1312
1313 if (forceWrap) {
1314 ret.isOwned = true;
1315 // Construct representative name of normalization wrapper
1316 std::string name = pdf->GetName() + ("_NORM[" + RooHelpers::getColonSeparatedNameString(termNSet, ','));
1317 name += normRange() ? ('|' + std::string{normRange()} + ']') : "]";
1318 ret0 = new RooRealIntegral(name.c_str(),name.c_str(),*pdf,RooArgSet(),&termNSet);
1319 }
1320
1321 ret0->setStringAttribute("PROD_TERM_TYPE","IVb") ;
1322 ret.x0 = ret0;
1323 ret.x1 = std::unique_ptr<RooAbsReal>{pdf->createIntegral(RooArgSet())};
1324 ret.x2 = std::unique_ptr<RooAbsReal>{pdf->createIntegral(termNSet,normRange())};
1325 return ret;
1326 }
1327
1328 coutE(Eval) << "RooProdPdf::processProductTerm(" << GetName() << ") unidentified term!!!" << std::endl ;
1329 return ret ;
1330}
1331
1332
1333
1334
1335////////////////////////////////////////////////////////////////////////////////
1336/// Make an appropriate automatic name for a RooGenProdProj object in getPartIntList()
1337
1338std::string RooProdPdf::makeRGPPName(const char* pfx, const RooArgSet& term, const RooArgSet& iset,
1339 const RooArgSet& nset, const char* isetRangeName) const
1340{
1341 // Make an appropriate automatic name for a RooGenProdProj object in getPartIntList()
1342
1343 std::ostringstream os;
1344 os << pfx;
1345 os << "[";
1346
1347 // Encode component names
1348 bool first(true) ;
1349 for (auto const* pdf : static_range_cast<RooAbsPdf*>(term)) {
1350 if (!first) os << "_X_";
1351 first = false;
1352 os << pdf->GetName();
1353 }
1354 os << "]" << integralNameSuffix(iset,&nset,isetRangeName,true);
1355
1356 return os.str();
1357}
1358
1359
1360
1361////////////////////////////////////////////////////////////////////////////////
1362/// Force RooRealIntegral to offer all observables for internal integration
1363
1365{
1366 return true ;
1367}
1368
1369
1370
1371////////////////////////////////////////////////////////////////////////////////
1372/// Determine which part (if any) of given integral can be performed analytically.
1373/// If any analytical integration is possible, return integration scenario code.
1374///
1375/// RooProdPdf implements two strategies in implementing analytical integrals
1376///
1377/// First, PDF components whose entire set of dependents are requested to be integrated
1378/// can be dropped from the product, as they will integrate out to 1 by construction
1379///
1380/// Second, RooProdPdf queries each remaining component PDF for its analytical integration
1381/// capability of the requested set ('allVars'). It finds the largest common set of variables
1382/// that can be integrated by all remaining components. If such a set exists, it reconfirms that
1383/// each component is capable of analytically integrating the common set, and combines the components
1384/// individual integration codes into a single integration code valid for RooProdPdf.
1385
1387 const RooArgSet* normSet, const char* rangeName) const
1388{
1389 if (_forceNumInt) return 0 ;
1390
1391 // Declare that we can analytically integrate all requested observables
1392 analVars.add(allVars) ;
1393
1394 // Retrieve (or create) the required partial integral list
1395 Int_t code = getPartIntList(normSet,&allVars,rangeName);
1396
1397 return code+1 ;
1398}
1399
1400
1401
1402
1403////////////////////////////////////////////////////////////////////////////////
1404/// Return analytical integral defined by given scenario code
1405
1407{
1408 // No integration scenario
1409 if (code==0) {
1410 return getVal(normSet) ;
1411 }
1412
1413
1414 // WVE needs adaptation for rangename feature
1415
1416 // Partial integration scenarios
1417 CacheElem* cache = static_cast<CacheElem*>(_cacheMgr.getObjByIndex(code-1)) ;
1418
1419 // If cache has been sterilized, revive this slot
1420 if (cache==nullptr) {
1421 std::unique_ptr<RooArgSet> vars{getParameters(RooArgSet())} ;
1422 RooArgSet nset = _cacheMgr.selectFromSet1(*vars, code-1) ;
1423 RooArgSet iset = _cacheMgr.selectFromSet2(*vars, code-1) ;
1424
1426
1427 // preceding call to getPartIntList guarantees non-null return
1428 // coverity[NULL_RETURNS]
1429 cache = static_cast<CacheElem*>(_cacheMgr.getObj(&nset,&iset,&code2,rangeName)) ;
1430 }
1431
1432 double val = calculate(*cache,true) ;
1433
1434 return val ;
1435}
1436
1437
1438
1439////////////////////////////////////////////////////////////////////////////////
1440/// If this product contains exactly one extendable p.d.f return the extension abilities of
1441/// that p.d.f, otherwise return CanNotBeExtended
1442
1444{
1445 return (_extendedIndex>=0) ? (static_cast<RooAbsPdf*>(_pdfList.at(_extendedIndex)))->extendMode() : CanNotBeExtended ;
1446}
1447
1448
1449
1450////////////////////////////////////////////////////////////////////////////////
1451/// Return the expected number of events associated with the extendable input PDF
1452/// in the product. If there is no extendable term, abort.
1453
1454double RooProdPdf::expectedEvents(const RooArgSet* nset) const
1455{
1456 if (_extendedIndex<0) {
1457 coutF(Generation) << "Requesting expected number of events from a RooProdPdf that does not contain an extended p.d.f" << std::endl ;
1458 throw std::logic_error(std::string("RooProdPdf ") + GetName() + " could not be extended.");
1459 }
1460
1461 return static_cast<RooAbsPdf*>(_pdfList.at(_extendedIndex))->expectedEvents(nset) ;
1462}
1463
1464std::unique_ptr<RooAbsReal> RooProdPdf::createExpectedEventsFunc(const RooArgSet* nset) const
1465{
1466 if (_extendedIndex<0) {
1467 coutF(Generation) << "Requesting expected number of events from a RooProdPdf that does not contain an extended p.d.f" << std::endl ;
1468 throw std::logic_error(std::string("RooProdPdf ") + GetName() + " could not be extended.");
1469 }
1470
1471 return static_cast<RooAbsPdf*>(_pdfList.at(_extendedIndex))->createExpectedEventsFunc(nset);
1472}
1473
1474
1475////////////////////////////////////////////////////////////////////////////////
1476/// Return generator context optimized for generating events from product p.d.f.s
1477
1479 const RooArgSet* auxProto, bool verbose) const
1480{
1481 if (_useDefaultGen) return RooAbsPdf::genContext(vars,prototype,auxProto,verbose) ;
1482 return new RooProdGenContext(*this,vars,prototype,auxProto,verbose) ;
1483}
1484
1485
1486
1487////////////////////////////////////////////////////////////////////////////////
1488/// Query internal generation capabilities of component p.d.f.s and aggregate capabilities
1489/// into master configuration passed to the generator context
1490
1492{
1493 if (!_useDefaultGen) return 0 ;
1494
1495 // Find the subset directVars that only depend on a single PDF in the product
1497 for (auto const* arg : directVars) {
1498 if (isDirectGenSafe(*arg)) directSafe.add(*arg) ;
1499 }
1500
1501
1502 // Now find direct integrator for relevant components ;
1503 std::vector<Int_t> code;
1504 code.reserve(64);
1505 for (auto const* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1507 Int_t pdfCode = pdf->getGenerator(directSafe,pdfDirect,staticInitOK);
1508 code.push_back(pdfCode);
1509 if (pdfCode != 0) {
1510 generateVars.add(pdfDirect) ;
1511 }
1512 }
1513
1514
1515 if (!generateVars.empty()) {
1516 Int_t masterCode = _genCode.store(code) ;
1517 return masterCode+1 ;
1518 } else {
1519 return 0 ;
1520 }
1521}
1522
1523
1524
1525////////////////////////////////////////////////////////////////////////////////
1526/// Forward one-time initialization call to component generation initialization
1527/// methods.
1528
1530{
1531 if (!_useDefaultGen) return ;
1532
1533 const std::vector<Int_t>& codeList = _genCode.retrieve(code-1) ;
1534 Int_t i(0) ;
1535 for (auto* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1536 if (codeList[i]!=0) {
1537 pdf->initGenerator(codeList[i]) ;
1538 }
1539 i++ ;
1540 }
1541}
1542
1543
1544
1545////////////////////////////////////////////////////////////////////////////////
1546/// Generate a single event with configuration specified by 'code'
1547/// Defer internal generation to components as encoded in the _genCode
1548/// registry for given generator code.
1549
1551{
1552 if (!_useDefaultGen) return ;
1553
1554 const std::vector<Int_t>& codeList = _genCode.retrieve(code-1) ;
1555 Int_t i(0) ;
1556 for (auto* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1557 if (codeList[i]!=0) {
1558 pdf->generateEvent(codeList[i]) ;
1559 }
1560 i++ ;
1561 }
1562}
1563
1564
1565
1566////////////////////////////////////////////////////////////////////////////////
1567/// Return RooAbsArg components contained in the cache
1568
1570{
1571 RooArgList ret ;
1572 ret.add(_partList) ;
1573 ret.add(_numList) ;
1574 ret.add(_denList) ;
1575 if (_rearrangedNum) ret.add(*_rearrangedNum) ;
1576 if (_rearrangedDen) ret.add(*_rearrangedDen) ;
1577 return ret ;
1578
1579}
1580
1581
1582
1583////////////////////////////////////////////////////////////////////////////////
1584/// Hook function to print cache contents in tree printing of RooProdPdf
1585
1587{
1588 if (curElem==0) {
1589 os << indent << "RooProdPdf begin partial integral cache" << std::endl ;
1590 }
1591
1592 auto indent2 = std::string(indent) + "[" + std::to_string(curElem) + "]";
1593 for(auto const& arg : _partList) {
1594 arg->printCompactTree(os,indent2.c_str()) ;
1595 }
1596
1597 if (curElem==maxElem) {
1598 os << indent << "RooProdPdf end partial integral cache" << std::endl ;
1599 }
1600}
1601
1602
1603
1604////////////////////////////////////////////////////////////////////////////////
1605/// Forward determination of safety of internal generator code to
1606/// component p.d.f that would generate the given observable
1607
1609{
1610 // Only override base class behaviour if default generator method is enabled
1611 if (!_useDefaultGen) return RooAbsPdf::isDirectGenSafe(arg) ;
1612
1613 // Argument may appear in only one PDF component
1614 RooAbsPdf* thePdf(nullptr) ;
1615 for (auto* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1616
1617 if (pdf->dependsOn(arg)) {
1618 // Found PDF depending on arg
1619
1620 // If multiple PDFs depend on arg directGen is not safe
1621 if (thePdf) return false ;
1622
1623 thePdf = pdf ;
1624 }
1625 }
1626 // Forward call to relevant component PDF
1627 return thePdf?(thePdf->isDirectGenSafe(arg)):false ;
1628}
1629
1630
1631
1632////////////////////////////////////////////////////////////////////////////////
1633/// Look up user specified normalization set for given input PDF component
1634
1636{
1637 Int_t idx = _pdfList.index(&pdf);
1638 return idx < 0 ? nullptr : _pdfNSetList[idx].get();
1639}
1640
1641
1642
1643/// Add some full PDFs to the factors of this RooProdPdf.
1645{
1646 size_t numExtended = (_extendedIndex==-1) ? 0 : 1;
1647
1648 for(auto arg : pdfs) {
1649 RooAbsPdf* pdf = dynamic_cast<RooAbsPdf*>(arg);
1650 if (!pdf) {
1651 coutW(InputArguments) << "RooProdPdf::addPdfs(" << GetName() << ") list arg "
1652 << arg->GetName() << " is not a PDF, ignored" << std::endl ;
1653 continue;
1654 }
1655 if(pdf->canBeExtended()) {
1656 if (_extendedIndex == -1) {
1658 } else {
1659 numExtended++;
1660 }
1661 }
1662 _pdfList.add(*pdf);
1663 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>("nset"));
1664 }
1665
1666 // Protect against multiple extended terms
1667 if (numExtended>1) {
1668 coutW(InputArguments) << "RooProdPdf::addPdfs(" << GetName()
1669 << ") WARNING: multiple components with extended terms detected,"
1670 << " product will not be extendable." << std::endl ;
1671 _extendedIndex = -1 ;
1672 }
1673
1674 // Reset cache
1675 _cacheMgr.reset() ;
1676
1677}
1678
1679/// Remove some PDFs from the factors of this RooProdPdf.
1681{
1682 // Remember what the extended PDF is
1683 RooAbsArg const* extPdf = _extendedIndex >= 0 ? &_pdfList[_extendedIndex] : nullptr;
1684
1685 // Actually remove the PDFs and associated nsets
1686 for(size_t i=0;i < _pdfList.size(); i++) {
1687 if(pdfs.contains(_pdfList[i])) {
1689 _pdfNSetList.erase(_pdfNSetList.begin()+i);
1690 i--;
1691 }
1692 }
1693
1694 // Since we may have removed PDFs from the list, the index of the extended
1695 // PDF in the list needs to be updated. The new index might also be -1 if the
1696 // extended PDF got removed.
1697 if(extPdf) {
1699 }
1700
1701 // Reset cache
1702 _cacheMgr.reset() ;
1703}
1704
1705
1706namespace {
1707
1708std::vector<TNamed const*> sortedNamePtrs(RooAbsCollection const& col)
1709{
1710 std::vector<TNamed const*> ptrs;
1711 ptrs.reserve(col.size());
1712 for(RooAbsArg* arg : col) {
1713 ptrs.push_back(arg->namePtr());
1714 }
1715 std::sort(ptrs.begin(), ptrs.end());
1716 return ptrs;
1717}
1718
1719bool sortedNamePtrsOverlap(std::vector<TNamed const*> const& ptrsA, std::vector<TNamed const*> const& ptrsB)
1720{
1721 auto pA = ptrsA.begin();
1722 auto pB = ptrsB.begin();
1723 while (pA != ptrsA.end() && pB != ptrsB.end()) {
1724 if (*pA < *pB) {
1725 ++pA;
1726 } else if (*pB < *pA) {
1727 ++pB;
1728 } else {
1729 return true;
1730 }
1731 }
1732 return false;
1733}
1734
1735} // namespace
1736
1737
1738////////////////////////////////////////////////////////////////////////////////
1739/// Return all parameter constraint p.d.f.s on parameters listed in constrainedParams.
1740/// The observables set is required to distinguish unambiguously p.d.f in terms
1741/// of observables and parameters, which are not constraints, and p.d.fs in terms
1742/// of parameters only, which can serve as constraints p.d.f.s
1743/// The pdfParams output parameter communicates to the caller which parameter
1744/// are used in the pdfs that are not constraints.
1745
1746std::unique_ptr<RooArgSet>
1748{
1749 auto constraints = std::make_unique<RooArgSet>("constraints");
1750
1751 // For the optimized implementation of checking if two collections overlap by name.
1752 auto observablesNamePtrs = sortedNamePtrs(observables);
1754
1755 // Loop over PDF components
1756 for (std::size_t iPdf = 0; iPdf < _pdfList.size(); ++iPdf) {
1757 auto * pdf = static_cast<RooAbsPdf*>(&_pdfList[iPdf]);
1758
1759 RooArgSet tmp;
1760 pdf->getParameters(nullptr, tmp);
1761
1762 // A constraint term is a p.d.f that doesn't contribute to the
1763 // expectedEvents() and does not depend on any of the listed observables
1764 // but does depends on any of the parameters that should be constrained
1765 bool isConstraint = false;
1766
1767 if(static_cast<int>(iPdf) != _extendedIndex) {
1769 // Before, there were calls to `pdf->dependsOn()` here, but they were very
1770 // expensive for large computation graphs! Given that we have to traverse
1771 // the computation graph with a call to `pdf->getParameters()` anyway, we
1772 // can just check if the set of all variables operlaps with the observables
1773 // or constraind parameters.
1774 //
1775 // We are using an optimized implementation of overlap checking. Because
1776 // the overlap is checked by name, we can check overlap of the
1777 // corresponding name pointers. The optimization can't be in
1778 // RooAbsCollection itself, because it is crucial that the memory for the
1779 // non-tmp name pointers is not reallocated for each pdf.
1782 }
1783 if (isConstraint) {
1784 constraints->add(*pdf) ;
1785 } else {
1786 // We only want to add parameter, not observables. Since a call like
1787 // `pdf->getParameters(&observables)` would be expensive, we take the set
1788 // of all variables and remove the ovservables, which is much cheaper. In
1789 // a call to `pdf->getParameters(&observables)`, the observables are
1790 // matched by name, so we have to pass the `matchByNameOnly` here.
1791 tmp.remove(observables, /*silent=*/false, /*matchByNameOnly=*/true);
1792 pdfParams.add(tmp,true) ;
1793 }
1794 }
1795
1796 return constraints;
1797}
1798
1799
1800
1801
1802////////////////////////////////////////////////////////////////////////////////
1803/// Return all parameter constraint p.d.f.s on parameters listed in constrainedParams.
1804/// The observables set is required to distinguish unambiguously p.d.f in terms
1805/// of observables and parameters, which are not constraints, and p.d.fs in terms
1806/// of parameters only, which can serve as constraints p.d.f.s
1807
1809{
1810 RooArgSet* connectedPars = new RooArgSet("connectedPars") ;
1811 for (std::size_t iPdf = 0; iPdf < _pdfList.size(); ++iPdf) {
1812 auto * pdf = static_cast<RooAbsPdf*>(&_pdfList[iPdf]);
1813 // Check if term is relevant, either because it provides a propablity
1814 // density in the observables or because it is used for the expected
1815 // events.
1816 if (static_cast<int>(iPdf) == _extendedIndex || pdf->dependsOn(observables)) {
1817 RooArgSet tmp;
1818 pdf->getParameters(&observables, tmp);
1819 connectedPars->add(tmp) ;
1820 }
1821 }
1822 return connectedPars ;
1823}
1824
1825////////////////////////////////////////////////////////////////////////////////
1826/// Interface function used by test statistics to freeze choice of range
1827/// for interpretation of conditional product terms
1828
1830{
1831 if (!force && _refRangeName) {
1832 return ;
1833 }
1834
1836}
1837
1838
1839
1840
1841////////////////////////////////////////////////////////////////////////////////
1842
1844{
1846}
1847
1848
1849
1850////////////////////////////////////////////////////////////////////////////////
1851/// Forward the plot sampling hint from the p.d.f. that defines the observable obs
1852
1853std::list<double>* RooProdPdf::plotSamplingHint(RooAbsRealLValue& obs, double xlo, double xhi) const
1854{
1855 for (auto const* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1856 if (std::list<double>* hint = pdf->plotSamplingHint(obs,xlo,xhi)) {
1857 return hint ;
1858 }
1859 }
1860
1861 return nullptr;
1862}
1863
1864
1865
1866////////////////////////////////////////////////////////////////////////////////
1867/// If all components that depend on obs are binned that so is the product
1868
1870{
1871 for (auto const* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1872 if (pdf->dependsOn(obs) && !pdf->isBinnedDistribution(obs)) {
1873 return false ;
1874 }
1875 }
1876
1877 return true ;
1878}
1879
1880
1881
1882
1883
1884
1885////////////////////////////////////////////////////////////////////////////////
1886/// Forward the plot sampling hint from the p.d.f. that defines the observable obs
1887
1888std::list<double>* RooProdPdf::binBoundaries(RooAbsRealLValue& obs, double xlo, double xhi) const
1889{
1890 for (auto const* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1891 if (std::list<double>* hint = pdf->binBoundaries(obs,xlo,xhi)) {
1892 return hint ;
1893 }
1894 }
1895
1896 return nullptr;
1897}
1898
1899
1900////////////////////////////////////////////////////////////////////////////////
1901/// Label OK'ed components of a RooProdPdf with cache-and-track, _and_ label all RooProdPdf
1902/// descendants with extra information about (conditional) normalization, needed to be able
1903/// to Cache-And-Track them outside the RooProdPdf context.
1904
1906{
1907 for (const auto parg : _pdfList) {
1908
1909 if (parg->canNodeBeCached()==Always) {
1910 trackNodes.add(*parg) ;
1911
1912 // Additional processing to fix normalization sets in case product defines conditional observables
1913 if (RooArgSet* pdf_nset = findPdfNSet(static_cast<RooAbsPdf&>(*parg))) {
1914 // Check if conditional normalization is specified
1916 if (string("nset")==pdf_nset->GetName() && !pdf_nset->empty()) {
1917 parg->setStringAttribute("CATNormSet",getColonSeparatedNameString(*pdf_nset).c_str()) ;
1918 }
1919 if (string("cset")==pdf_nset->GetName()) {
1920 parg->setStringAttribute("CATCondSet",getColonSeparatedNameString(*pdf_nset).c_str()) ;
1921 }
1922 } else {
1923 coutW(Optimization) << "RooProdPdf::setCacheAndTrackHints(" << GetName() << ") WARNING product pdf does not specify a normalization set for component " << parg->GetName() << std::endl ;
1924 }
1925 }
1926 }
1927}
1928
1929
1930
1931////////////////////////////////////////////////////////////////////////////////
1932/// Customized printing of arguments of a RooProdPdf to more intuitively reflect the contents of the
1933/// product operator construction
1934
1935void RooProdPdf::printMetaArgs(ostream& os) const
1936{
1937 for (std::size_t i=0 ; i<_pdfList.size() ; i++) {
1938 if (i>0) os << " * " ;
1939 RooArgSet* ncset = _pdfNSetList[i].get() ;
1940 os << _pdfList.at(i)->GetName() ;
1941 if (!ncset->empty()) {
1942 if (string("nset")==ncset->GetName()) {
1943 os << *ncset ;
1944 } else {
1945 os << "|" ;
1946 bool first(true) ;
1947 for (auto const* arg : *ncset) {
1948 if (!first) {
1949 os << "," ;
1950 } else {
1951 first = false ;
1952 }
1953 os << arg->GetName() ;
1954 }
1955 }
1956 }
1957 }
1958 os << " " ;
1959}
1960
1961
1962
1963////////////////////////////////////////////////////////////////////////////////
1964/// Implement support for node removal
1965
1967{
1968 if (nameChange && _pdfList.find("REMOVAL_DUMMY")) {
1969
1970 cxcoutD(LinkStateMgmt) << "RooProdPdf::redirectServersHook(" << GetName() << "): removing REMOVAL_DUMMY" << std::endl ;
1971
1972 // Remove node from _pdfList proxy and remove corresponding entry from normset list
1973 RooAbsArg* pdfDel = _pdfList.find("REMOVAL_DUMMY") ;
1974
1975 _pdfNSetList.erase(_pdfNSetList.begin() + _pdfList.index("REMOVAL_DUMMY")) ;
1977
1978 // Clear caches
1979 _cacheMgr.reset() ;
1980 }
1981
1982 // If the replaced server is an observable that is used in any of the
1983 // normalization sets for conditional fits, replace the element in the
1984 // normalization set too.
1985 for(std::unique_ptr<RooArgSet> const& normSet : _pdfNSetList) {
1986 for(RooAbsArg * arg : *normSet) {
1987 if(RooAbsArg * newArg = arg->findNewServer(newServerList, nameChange)) {
1988 // Since normSet is owning, the original arg is now deleted.
1989 normSet->replace(arg, std::unique_ptr<RooAbsArg>{newArg->cloneTree()});
1990 }
1991 }
1992 }
1993
1995}
1996
1997void RooProdPdf::CacheElem::writeToStream(std::ostream& os) const {
1998 using namespace RooHelpers;
1999 os << "_partList\n";
2000 os << getColonSeparatedNameString(_partList) << "\n";
2001 os << "_numList\n";
2002 os << getColonSeparatedNameString(_numList) << "\n";
2003 os << "_denList\n";
2004 os << getColonSeparatedNameString(_denList) << "\n";
2005 os << "_ownedList\n";
2006 os << getColonSeparatedNameString(_ownedList) << "\n";
2007 os << "_normList\n";
2008 for(auto const& set : _normList) {
2009 os << getColonSeparatedNameString(*set) << "\n";
2010 }
2011 os << "_isRearranged" << "\n";
2012 os << _isRearranged << "\n";
2013 os << "_rearrangedNum" << "\n";
2014 if(_rearrangedNum) {
2015 os << getColonSeparatedNameString(*_rearrangedNum) << "\n";
2016 } else {
2017 os << "nullptr" << "\n";
2018 }
2019 os << "_rearrangedDen" << "\n";
2020 if(_rearrangedDen) {
2021 os << getColonSeparatedNameString(*_rearrangedDen) << "\n";
2022 } else {
2023 os << "nullptr" << "\n";
2024 }
2025}
2026
2027std::unique_ptr<RooArgSet> RooProdPdf::fillNormSetForServer(RooArgSet const &normSet, RooAbsArg const &server) const
2028{
2029 if (normSet.empty())
2030 return nullptr;
2031 auto *pdfNset = findPdfNSet(static_cast<RooAbsPdf const &>(server));
2032 if (pdfNset && !pdfNset->empty()) {
2033 std::unique_ptr<RooArgSet> out;
2034 if (0 == strcmp("cset", pdfNset->GetName())) {
2035 // If the name of the normalization set is "cset", it doesn't contain the
2036 // normalization set but the conditional observables that should *not* be
2037 // normalized over.
2038 out = std::make_unique<RooArgSet>(normSet);
2040 out->selectCommon(*pdfNset, common);
2041 out->remove(common);
2042 } else {
2043 out = std::make_unique<RooArgSet>(*pdfNset);
2044 }
2045 // prefix also the arguments in the normSets if they have not already been
2046 if (auto prefix = getStringAttribute("__prefix__")) {
2047 for (RooAbsArg *arg : *out) {
2048 if (!arg->getStringAttribute("__prefix__")) {
2049 arg->SetName((std::string(prefix) + arg->GetName()).c_str());
2050 arg->setStringAttribute("__prefix__", prefix);
2051 }
2052 }
2053 }
2054 return out;
2055 } else {
2056 return nullptr;
2057 }
2058}
2059
2060std::unique_ptr<RooAbsArg>
2062{
2063 if (ctx.likelihoodMode()) {
2064 auto binnedInfo = RooHelpers::getBinnedL(*this);
2065 if (binnedInfo.binnedPdf && binnedInfo.binnedPdf != this) {
2066 return binnedInfo.binnedPdf->compileForNormSet(normSet, ctx);
2067 }
2068 }
2069
2070 std::unique_ptr<RooProdPdf> prodPdfClone{static_cast<RooProdPdf *>(this->Clone())};
2072
2073 for (const auto server : prodPdfClone->servers()) {
2075 RooArgSet const &nset = nsetForServer ? *nsetForServer : normSet;
2076
2078 server->getObservables(&nset, depList);
2079
2081 }
2082
2083 auto fixedProdPdf = std::make_unique<RooFit::Detail::RooFixedProdPdf>(std::move(prodPdfClone), normSet);
2085
2086 return fixedProdPdf;
2087}
2088
2089namespace RooFit::Detail {
2090
2091RooFixedProdPdf::RooFixedProdPdf(std::unique_ptr<RooProdPdf> &&prodPdf, RooArgSet const &normSet)
2092 : RooAbsPdf(prodPdf->GetName(), prodPdf->GetTitle()),
2093 _normSet{normSet},
2094 _servers("!servers", "List of servers", this),
2095 _prodPdf{std::move(prodPdf)}
2096{
2097 auto cache = _prodPdf->createCacheElem(&_normSet, nullptr);
2098 _isRearranged = cache->_isRearranged;
2099
2100 // We don't want to carry the full cache object around, so we let it go out
2101 // of scope and transfer the ownership of the args that we actually need.
2102 cache->_ownedList.releaseOwnership();
2103 cache->_numList.releaseOwnership();
2104 cache->_denList.releaseOwnership();
2105 addOwnedComponents(cache->_ownedList);
2106 addOwnedComponents(cache->_numList);
2107 addOwnedComponents(cache->_denList);
2108
2109 // The actual servers for a given normalization set depend on whether the
2110 // cache is rearranged or not. See RooProdPdf::calculate to see
2111 // which args in the cache are used directly.
2112 if (_isRearranged) {
2113 _servers.add(*cache->_rearrangedNum);
2114 _servers.add(*cache->_rearrangedDen);
2115 addOwnedComponents(std::move(cache->_rearrangedNum));
2116 addOwnedComponents(std::move(cache->_rearrangedDen));
2117 return;
2118 }
2119 for (RooAbsArg *arg : cache->_partList) {
2120 _servers.add(*arg);
2121 }
2122}
2123
2125 : RooAbsPdf(other, name),
2126 _normSet{other._normSet},
2127 _servers("!servers", this, other._servers),
2128 _prodPdf{static_cast<RooProdPdf *>(other._prodPdf->Clone())},
2129 _isRearranged{other._isRearranged}
2130{
2131}
2132
2133////////////////////////////////////////////////////////////////////////////////
2134/// Evaluate product of PDFs in batch mode.
2135
2137{
2138 if (_isRearranged) {
2139 auto numerator = ctx.at(rearrangedNum());
2140 auto denominator = ctx.at(rearrangedDen());
2141 RooBatchCompute::compute(ctx.config(this), RooBatchCompute::Ratio, ctx.output(), {numerator, denominator});
2142 return;
2143 }
2144 std::vector<std::span<const double>> factors;
2145 factors.reserve(partList()->size());
2146 for (const RooAbsArg *arg : *partList()) {
2147 auto span = ctx.at(arg);
2148 factors.push_back(span);
2149 }
2150 std::array<double, 1> special{static_cast<double>(factors.size())};
2152}
2153
2155{
2156 if (_isRearranged) {
2157 return rearrangedNum()->getVal() / rearrangedDen()->getVal();
2158 }
2159 double value = 1.0;
2160
2161 for (auto *arg : static_range_cast<RooAbsReal *>(*partList())) {
2162 value *= arg->getVal();
2163 }
2164 return value;
2165}
2166
2167} // namespace RooFit::Detail
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
#define cxcoutD(a)
#define coutW(a)
#define dologD(a)
#define coutF(a)
#define coutE(a)
#define TRACE_DESTROY
Definition RooTrace.h:24
#define TRACE_CREATE
Definition RooTrace.h:23
static void indent(ostringstream &buf, int indent_level)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
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
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2496
const_iterator begin() const
const_iterator end() const
const std::vector< Int_t > & retrieve(Int_t masterCode) const
Retrieve the array of integer codes associated with the given master code.
Int_t store(const std::vector< Int_t > &codeList, RooArgSet *set1=nullptr, RooArgSet *set2=nullptr, RooArgSet *set3=nullptr, RooArgSet *set4=nullptr)
Store given arrays of integer codes, and up to four RooArgSets in the registry (each setX pointer may...
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
RooExpensiveObjectCache & expensiveObjectCache() const
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...
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
const Text_t * getStringAttribute(const Text_t *key) const
Get string attribute mapped under key 'key'.
friend class RooRealIntegral
Definition RooAbsArg.h:564
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:88
void treeNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=nullptr, bool doBranch=true, bool doLeaf=true, bool valueOnly=false, bool recurseNonDerived=false) const
Fill supplied list with nodes of the arg tree, following all server links, starting with ourself as t...
OperMode operMode() const
Query the operation mode of this node.
Definition RooAbsArg.h:419
Abstract container object that can hold multiple RooAbsArg objects.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Int_t index(const RooAbsArg *arg) const
Returns index of given arg, or -1 if arg is not in the collection.
bool overlaps(Iterator_t otherCollBegin, Iterator_t otherCollEnd) const
Storage_t::size_type size() const
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for generator contexts of RooAbsPdf objects.
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
TString _normRange
Normalization range.
Definition RooAbsPdf.h:336
virtual bool isDirectGenSafe(const RooAbsArg &arg) const
Check if given observable can be safely generated using the pdfs internal generator mechanism (if tha...
RooArgSet const * _normSet
! Normalization set with for above integral
Definition RooAbsPdf.h:314
bool canBeExtended() const
If true, PDF can provide extended likelihood term.
Definition RooAbsPdf.h:214
@ CanNotBeExtended
Definition RooAbsPdf.h:208
const char * normRange() const
Definition RooAbsPdf.h:246
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursiveStep) override
Hook function intercepting redirectServer calls.
virtual RooAbsGenContext * genContext(const RooArgSet &vars, const RooDataSet *prototype=nullptr, const RooArgSet *auxProto=nullptr, bool verbose=false) const
Interface function to create a generator context from a p.d.f.
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
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
bool _forceNumInt
Force numerical integration if flag set.
Definition RooAbsReal.h:572
TString integralNameSuffix(const RooArgSet &iset, const RooArgSet *nset=nullptr, const char *rangeName=nullptr, bool omitEmpty=false) const
Construct string with unique suffix name to give to integral object that encodes integrated observabl...
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 ...
Calculates the sum of a set of RooAbsReal terms, or when constructed with two sets,...
Definition RooAddition.h:27
static TClass * Class()
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: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...
void reset()
Clear the cache.
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.
Named container for two doubles, two integers two object points and three string pointers that can be...
Definition RooCmdArg.h:26
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...
bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false) override
Remove object 'var' from set and deregister 'var' as server to owner.
TObject * clone(const char *newname=nullptr) const override
Definition RooConstVar.h:29
RooCustomizer is a factory class to produce clones of a prototype composite PDF object with the same ...
Container class to hold unbinned data.
Definition RooDataSet.h:32
void markAsCompiled(RooAbsArg &arg) const
void compileServer(RooAbsArg &server, RooAbsArg &arg, RooArgSet const &normSet)
A RooProdPdf with a fixed normalization set can be replaced by this class.
Definition RooProdPdf.h:212
RooFixedProdPdf(std::unique_ptr< RooProdPdf > &&prodPdf, RooArgSet const &normSet)
RooArgSet const * partList() const
Definition RooProdPdf.h:267
double evaluate() const override
Evaluate this PDF / function / constant. Needs to be overridden by all derived classes.
void doEval(RooFit::EvalContext &ctx) const override
Evaluate product of PDFs in batch mode.
std::unique_ptr< RooProdPdf > _prodPdf
Definition RooProdPdf.h:274
RooAbsReal const * rearrangedDen() const
Definition RooProdPdf.h:262
RooAbsReal const * rearrangedNum() const
Definition RooProdPdf.h:258
std::span< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
std::span< double > output()
RooBatchCompute::Config config(RooAbsArg const *arg) const
A RooFormulaVar is a generic implementation of a real-valued object, which takes a RooArgList of serv...
Collection class for internal use, storing a collection of RooAbsArg pointers in a doubly linked list...
void Delete(Option_t *o=nullptr) override
Remove all elements in collection and delete all elements NB: Collection does not own elements,...
static const char * str(const TNamed *ptr)
Return C++ string corresponding to given TNamed pointer.
Definition RooNameReg.h:39
static const TNamed * ptr(const char *stringPtr)
Return a unique TNamed pointer for given C++ string.
RooArgList containedArgs(Action) override
Return RooAbsArg components contained in the cache.
std::unique_ptr< RooAbsReal > _rearrangedNum
Definition RooProdPdf.h:116
void printCompactTreeHook(std::ostream &, const char *, Int_t, Int_t) override
Hook function to print cache contents in tree printing of RooProdPdf.
std::vector< std::unique_ptr< RooArgSet > > _normList
Definition RooProdPdf.h:114
std::unique_ptr< RooAbsReal > _rearrangedDen
Definition RooProdPdf.h:117
void writeToStream(std::ostream &os) const
Efficient implementation of a product of PDFs of the form.
Definition RooProdPdf.h:36
std::unique_ptr< RooArgSet > getConstraints(const RooArgSet &observables, RooArgSet const &constrainedParams, RooArgSet &pdfParams) const override
Return all parameter constraint p.d.f.s on parameters listed in constrainedParams.
void setCacheAndTrackHints(RooArgSet &) override
Label OK'ed components of a RooProdPdf with cache-and-track, and label all RooProdPdf descendants wit...
Int_t getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool staticInitOK=true) const override
Query internal generation capabilities of component p.d.f.s and aggregate capabilities into master co...
void rearrangeProduct(CacheElem &) const
double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Return analytical integral defined by given scenario code.
~RooProdPdf() override
Destructor.
Int_t _extendedIndex
Index of extended PDF (if any)
Definition RooProdPdf.h:193
std::unique_ptr< RooAbsReal > specializeRatio(RooFormulaVar &input, const char *targetRangeName) const
RooProdPdf()
Default constructor.
void removePdfs(RooAbsCollection const &pdfs)
Remove some PDFs from the factors of this RooProdPdf.
bool _useDefaultGen
Use default or distributed event generator.
Definition RooProdPdf.h:196
std::vector< std::unique_ptr< RooArgSet > > _pdfNSetList
List of PDF component normalization sets.
Definition RooProdPdf.h:192
std::unique_ptr< RooArgSet > fillNormSetForServer(RooArgSet const &normSet, RooAbsArg const &server) const
std::unique_ptr< RooAbsReal > specializeIntegral(RooAbsReal &orig, const char *targetRangeName) const
void factorizeProduct(const RooArgSet &normSet, const RooArgSet &intSet, Factorized &factorized) const
Factorize product in irreducible terms for given choice of integration/normalization.
bool forceAnalyticalInt(const RooAbsArg &dep) const override
Force RooRealIntegral to offer all observables for internal integration.
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
RooAbsGenContext * genContext(const RooArgSet &vars, const RooDataSet *prototype=nullptr, const RooArgSet *auxProto=nullptr, bool verbose=false) const override
Return generator context optimized for generating events from product p.d.f.s.
TNamed * _refRangeName
Reference range name for interpretation of conditional products.
Definition RooProdPdf.h:198
RooAICRegistry _genCode
! Registry of composite direct generator codes
Definition RooProdPdf.h:188
void addPdfs(RooAbsCollection const &pdfs)
Add some full PDFs to the factors of this RooProdPdf.
RooListProxy _pdfList
List of PDF components.
Definition RooProdPdf.h:191
Int_t getPartIntList(const RooArgSet *nset, const RooArgSet *iset, const char *isetRangeName=nullptr) const
Return list of (partial) integrals of product terms for integration of p.d.f over observables iset wh...
void printMetaArgs(std::ostream &os) const override
Customized printing of arguments of a RooProdPdf to more intuitively reflect the contents of the prod...
std::list< double > * binBoundaries(RooAbsRealLValue &, double, double) const override
Forward the plot sampling hint from the p.d.f. that defines the observable obs.
RooObjCacheManager _cacheMgr
! The cache manager
Definition RooProdPdf.h:174
std::string makeRGPPName(const char *pfx, const RooArgSet &term, const RooArgSet &iset, const RooArgSet &nset, const char *isetRangeName) const
Make an appropriate automatic name for a RooGenProdProj object in getPartIntList()
bool isDirectGenSafe(const RooAbsArg &arg) const override
Forward determination of safety of internal generator code to component p.d.f that would generate the...
ProcessProductTermOutput processProductTerm(const RooArgSet *nset, const RooArgSet *iset, const char *isetRangeName, const RooArgSet *term, const RooArgSet &termNSet, const RooArgSet &termISet, bool forceWrap=false) const
Calculate integrals of factorized product terms over observables iset while normalized to observables...
std::unique_ptr< RooAbsReal > makeCondPdfRatioCorr(RooAbsReal &term, const RooArgSet &termNset, const RooArgSet &termImpSet, const char *normRange, const char *refRange) const
For single normalization ranges.
RooArgSet * findPdfNSet(RooAbsPdf const &pdf) const
Look up user specified normalization set for given input PDF component.
ExtendMode extendMode() const override
If this product contains exactly one extendable p.d.f return the extension abilities of that p....
std::list< double > * plotSamplingHint(RooAbsRealLValue &obs, double xlo, double xhi) const override
Forward the plot sampling hint from the p.d.f. that defines the observable obs.
double expectedEvents(const RooArgSet *nset) const override
Return the expected number of events associated with the extendable input PDF in the product.
Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &numVars, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Determine which part (if any) of given integral can be performed analytically.
bool isBinnedDistribution(const RooArgSet &obs) const override
If all components that depend on obs are binned that so is the product.
friend class RooProdGenContext
Definition RooProdPdf.h:182
RooArgSet * getConnectedParameters(const RooArgSet &observables) const
Return all parameter constraint p.d.f.s on parameters listed in constrainedParams.
double calculate(const RooProdPdf::CacheElem &cache, bool verbose=false) const
Calculate running product of pdfs terms, using the supplied normalization set in 'normSetList' for ea...
RooArgSet _defNormSet
Default normalization set.
Definition RooProdPdf.h:201
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,...
CacheElem * getCacheElem(RooArgSet const *nset) const
bool redirectServersHook(const RooAbsCollection &, bool, bool, bool) override
Implement support for node removal.
void groupProductTerms(std::list< std::vector< RooArgSet * > > &groupedTerms, RooArgSet &outerIntDeps, Factorized const &factorized) const
Group product into terms that can be calculated independently.
void initGenerator(Int_t code) override
Forward one-time initialization call to component generation initialization methods.
void generateEvent(Int_t code) override
Generate a single event with configuration specified by 'code' Defer internal generation to component...
void fixRefRange(const char *rangeName)
std::unique_ptr< CacheElem > createCacheElem(const RooArgSet *nset, const RooArgSet *iset, const char *isetRangeName=nullptr) const
double evaluate() const override
Calculate current value of object.
void initializeFromCmdArgList(const RooArgSet &fullPdfSet, const RooLinkedList &l)
Initialize RooProdPdf configuration from given list of RooCmdArg configuration arguments and set of '...
void selectNormalizationRange(const char *rangeName=nullptr, bool force=false) override
Interface function used by test statistics to freeze choice of range for interpretation of conditiona...
double _cutOff
Cutoff parameter for running product.
Definition RooProdPdf.h:190
Represents the product of a given set of RooAbsReal objects.
Definition RooProduct.h:29
static TClass * Class()
Performs hybrid numerical/analytical integrals of RooAbsReal objects.
static TClass * Class()
Variable that can be changed from the outside.
Definition RooRealVar.h:37
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Mother of all ROOT objects.
Definition TObject.h:42
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:546
Basic string class.
Definition TString.h:138
Ssiz_t Length() const
Definition TString.h:425
const char * Data() const
Definition TString.h:384
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:641
RooConstVar & RooConst(double val)
Double_t x[n]
Definition legend1.C:17
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
void compute(Config cfg, Computer comp, std::span< double > output, VarSpan vars, ArgSpan extraArgs={})
BinnedLOutput getBinnedL(RooAbsPdf const &pdf)
std::string getColonSeparatedNameString(RooArgSet const &argSet, char delim=':')
RooLinkedList cross
Definition RooProdPdf.h:146
RooLinkedList norms
Definition RooProdPdf.h:143
RooLinkedList terms
Definition RooProdPdf.h:142
TLine l
Definition textangle.C:4