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