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
22RooProdPdf is an efficient 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 "RooHelpers.h"
63#include "RooBatchCompute.h"
64#include "strtok.h"
65
66#include <cstring>
67#include <sstream>
68#include <algorithm>
69
70#ifndef _WIN32
71#include <strings.h>
72#endif
73
74using namespace std;
75
77
78
79////////////////////////////////////////////////////////////////////////////////
80/// Default constructor
81
83 _cacheMgr(this,10)
84{
85 // Default constructor
87}
88
89
90////////////////////////////////////////////////////////////////////////////////
91/// Constructor with 2 PDFs (most frequent use case).
92///
93/// The optional cutOff parameter can be used as a speed optimization if
94/// one or more of the PDF have sizable regions with very small values,
95/// which would pull the entire product of PDFs to zero in those regions.
96///
97/// After each PDF multiplication, the running product is compared with
98/// the cutOff parameter. If the running product is smaller than the
99/// cutOff value, the product series is terminated and remaining PDFs
100/// are not evaluated.
101///
102/// There is no magic value of the cutOff, the user should experiment
103/// to find the appropriate balance between speed and precision.
104/// If a cutoff is specified, the PDFs most likely to be small should
105/// be put first in the product. The default cutOff value is zero.
106///
107
108RooProdPdf::RooProdPdf(const char *name, const char *title,
109 RooAbsPdf& pdf1, RooAbsPdf& pdf2, double cutOff) :
110 RooAbsPdf(name,title),
111 _cacheMgr(this,10),
112 _cutOff(cutOff),
113 _pdfList("!pdfs","List of PDFs",this)
114{
115 _pdfList.add(pdf1) ;
116 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>("nset")) ;
117 if (pdf1.canBeExtended()) {
118 _extendedIndex = _pdfList.index(&pdf1) ;
119 }
120
121 _pdfList.add(pdf2) ;
122 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>("nset")) ;
123
124 if (pdf2.canBeExtended()) {
125 if (_extendedIndex>=0) {
126 // Protect against multiple extended terms
127 coutW(InputArguments) << "RooProdPdf::RooProdPdf(" << GetName()
128 << ") multiple components with extended terms detected,"
129 << " product will not be extendible." << endl ;
130 _extendedIndex=-1 ;
131 } else {
133 }
134 }
136}
137
138
139
140////////////////////////////////////////////////////////////////////////////////
141/// Constructor from a list of PDFs.
142///
143/// The optional cutOff parameter can be used as a speed optimization if
144/// one or more of the PDF have sizable regions with very small values,
145/// which would pull the entire product of PDFs to zero in those regions.
146///
147/// After each PDF multiplication, the running product is compared with
148/// the cutOff parameter. If the running product is smaller than the
149/// cutOff value, the product series is terminated and remaining PDFs
150/// are not evaluated.
151///
152/// There is no magic value of the cutOff, the user should experiment
153/// to find the appropriate balance between speed and precision.
154/// If a cutoff is specified, the PDFs most likely to be small should
155/// be put first in the product. The default cutOff value is zero.
156
157RooProdPdf::RooProdPdf(const char* name, const char* title, const RooArgList& inPdfList, double cutOff) :
158 RooAbsPdf(name,title),
159 _cacheMgr(this,10),
160 _cutOff(cutOff),
161 _pdfList("!pdfs","List of PDFs",this)
162{
163 addPdfs(inPdfList);
165}
166
167
168
169////////////////////////////////////////////////////////////////////////////////
170/// Constructor from named argument list.
171/// \param[in] name Name used by RooFit
172/// \param[in] title Title used for plotting
173/// \param[in] fullPdfSet Set of "regular" PDFs that are normalised over all their observables
174/// \param[in] arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 Optional arguments according to table below.
175///
176/// <table>
177/// <tr><th> Argument <th> Description
178/// <tr><td> `Conditional(pdfSet,depSet,depsAreCond=false)` <td> Add PDF to product with condition that it
179/// only be normalized over specified observables. Any remaining observables will be conditional observables.
180/// (Setting `depsAreCond` to true inverts this, so the observables in depSet will be the conditional observables.)
181/// </table>
182///
183/// For example, given a PDF \f$ F(x,y) \f$ and \f$ G(y) \f$,
184///
185/// `RooProdPdf("P", "P", G, Conditional(F,x))` will construct a 2-dimensional PDF as follows:
186/// \f[
187/// P(x,y) = \frac{G(y)}{\int_y G(y)} \cdot \frac{F(x,y)}{\int_x F(x,y)},
188/// \f]
189///
190/// which is a well normalised and properly defined PDF, but different from
191/// \f[
192/// P'(x,y) = \frac{F(x,y) \cdot G(y)}{\int_x\int_y F(x,y) \cdot G(y)}.
193/// \f]
194///
195/// In the former case, the \f$ y \f$ distribution of \f$ P \f$ is identical to that of \f$ G \f$, while
196/// \f$ F \f$ only is used to determine the correlation between \f$ X \f$ and \f$ Y \f$. In the latter
197/// case, the \f$ Y \f$ distribution is defined by the product of \f$ F \f$ and \f$ G \f$.
198///
199/// This \f$ P(x,y) \f$ construction is analoguous to generating events from \f$ F(x,y) \f$ with
200/// a prototype dataset sampled from \f$ G(y) \f$.
201
202RooProdPdf::RooProdPdf(const char* name, const char* title, const RooArgSet& fullPdfSet,
203 const RooCmdArg& arg1, const RooCmdArg& arg2,
204 const RooCmdArg& arg3, const RooCmdArg& arg4,
205 const RooCmdArg& arg5, const RooCmdArg& arg6,
206 const RooCmdArg& arg7, const RooCmdArg& arg8) :
207 RooAbsPdf(name,title),
208 _cacheMgr(this,10),
209 _pdfList("!pdfs","List of PDFs",this)
210{
212 l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
213 l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
214 l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
215 l.Add((TObject*)&arg7) ; l.Add((TObject*)&arg8) ;
216
217 initializeFromCmdArgList(fullPdfSet,l) ;
219}
220
221
222
223////////////////////////////////////////////////////////////////////////////////
224/// Constructor from named argument list
225
226RooProdPdf::RooProdPdf(const char* name, const char* title,
227 const RooCmdArg& arg1, const RooCmdArg& arg2,
228 const RooCmdArg& arg3, const RooCmdArg& arg4,
229 const RooCmdArg& arg5, const RooCmdArg& arg6,
230 const RooCmdArg& arg7, const RooCmdArg& arg8) :
231 RooAbsPdf(name,title),
232 _cacheMgr(this,10),
233 _pdfList("!pdfList","List of PDFs",this)
234{
236 l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
237 l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
238 l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
239 l.Add((TObject*)&arg7) ; l.Add((TObject*)&arg8) ;
240
243}
244
245
246
247////////////////////////////////////////////////////////////////////////////////
248/// Internal constructor from list of named arguments
249
250RooProdPdf::RooProdPdf(const char* name, const char* title, const RooArgSet& fullPdfSet, const RooLinkedList& cmdArgList) :
251 RooAbsPdf(name,title),
252 _cacheMgr(this,10),
253 _pdfList("!pdfs","List of PDFs",this)
254{
255 initializeFromCmdArgList(fullPdfSet, cmdArgList) ;
257}
258
259
260
261////////////////////////////////////////////////////////////////////////////////
262/// Copy constructor
263
264RooProdPdf::RooProdPdf(const RooProdPdf& other, const char* name) :
265 RooAbsPdf(other,name),
266 _cacheMgr(other._cacheMgr,this),
267 _genCode(other._genCode),
268 _cutOff(other._cutOff),
269 _pdfList("!pdfs",this,other._pdfList),
270 _extendedIndex(other._extendedIndex),
271 _useDefaultGen(other._useDefaultGen),
272 _refRangeName(other._refRangeName),
273 _selfNorm(other._selfNorm),
274 _defNormSet(other._defNormSet)
275{
276 // Clone contents of normalizarion set list
277 for(auto const& nset : other._pdfNSetList) {
278 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>(nset->GetName()));
279 nset->snapshot(*_pdfNSetList.back());
280 }
282}
283
284
285
286////////////////////////////////////////////////////////////////////////////////
287/// Initialize RooProdPdf configuration from given list of RooCmdArg configuration arguments
288/// and set of 'regular' p.d.f.s in product
289
291{
292 Int_t numExtended(0) ;
293
294 // Process set of full PDFS
295 for(auto const* pdf : static_range_cast<RooAbsPdf*>(fullPdfSet)) {
296 _pdfList.add(*pdf) ;
297 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>("nset")) ;
298
299 if (pdf->canBeExtended()) {
301 numExtended++ ;
302 }
303
304 }
305
306 // Process list of conditional PDFs
307 for(auto * carg : static_range_cast<RooCmdArg*>(l)) {
308
309 if (0 == strcmp(carg->GetName(), "Conditional")) {
310
311 Int_t argType = carg->getInt(0) ;
312 auto pdfSet = static_cast<RooArgSet const*>(carg->getSet(0));
313 auto normSet = static_cast<RooArgSet const*>(carg->getSet(1));
314
315 for(auto * thePdf : static_range_cast<RooAbsPdf*>(*pdfSet)) {
316 _pdfList.add(*thePdf) ;
317
318 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>(0 == argType ? "nset" : "cset"));
319 normSet->snapshot(*_pdfNSetList.back());
320
321 if (thePdf->canBeExtended()) {
322 _extendedIndex = _pdfList.index(thePdf) ;
323 numExtended++ ;
324 }
325
326 }
327
328 } else if (0 != strlen(carg->GetName())) {
329 coutW(InputArguments) << "Unknown arg: " << carg->GetName() << endl ;
330 }
331 }
332
333 // Protect against multiple extended terms
334 if (numExtended>1) {
335 coutW(InputArguments) << "RooProdPdf::RooProdPdf(" << GetName()
336 << ") WARNING: multiple components with extended terms detected,"
337 << " product will not be extendible." << endl ;
338 _extendedIndex = -1 ;
339 }
340
341
342}
343
344
345
346////////////////////////////////////////////////////////////////////////////////
347/// Destructor
348
350{
352}
353
354
356 int code ;
357 auto cache = static_cast<CacheElem*>(_cacheMgr.getObj(nset, 0, &code)) ;
358
359 // If cache doesn't have our configuration, recalculate here
360 if (!cache) {
361 code = getPartIntList(nset, nullptr) ;
362 cache = static_cast<CacheElem*>(_cacheMgr.getObj(nset, 0, &code)) ;
363 }
364 return cache;
365}
366
367
368////////////////////////////////////////////////////////////////////////////////
369/// Calculate current value of object
370
372{
374}
375
376
377
378////////////////////////////////////////////////////////////////////////////////
379/// Calculate running product of pdfs terms, using the supplied
380/// normalization set in 'normSetList' for each component
381
382double RooProdPdf::calculate(const RooProdPdf::CacheElem& cache, bool /*verbose*/) const
383{
384 if (cache._isRearranged) {
385 if (dologD(Eval)) {
386 cxcoutD(Eval) << "RooProdPdf::calculate(" << GetName() << ") rearranged product calculation"
387 << " calculate: num = " << cache._rearrangedNum->GetName() << " = " << cache._rearrangedNum->getVal() << endl ;
388// cache._rearrangedNum->printComponentTree("",0,5) ;
389 cxcoutD(Eval) << "calculate: den = " << cache._rearrangedDen->GetName() << " = " << cache._rearrangedDen->getVal() << endl ;
390// cache._rearrangedDen->printComponentTree("",0,5) ;
391 }
392
393 return cache._rearrangedNum->getVal() / cache._rearrangedDen->getVal();
394 } else {
395
396 double value = 1.0;
397 assert(cache._normList.size() == cache._partList.size());
398 for (std::size_t i = 0; i < cache._partList.size(); ++i) {
399 const auto& partInt = static_cast<const RooAbsReal&>(cache._partList[i]);
400 const auto normSet = cache._normList[i].get();
401
402 const double piVal = partInt.getVal(normSet->getSize() > 0 ? normSet : nullptr);
403 value *= piVal ;
404 if (value <= _cutOff) break;
405 }
406
407 return value ;
408 }
409}
410
411////////////////////////////////////////////////////////////////////////////////
412/// Evaluate product of PDFs in batch mode.
413void RooProdPdf::calculateBatch(const RooProdPdf::CacheElem& cache, cudaStream_t* stream, double* output, size_t nEvents, RooFit::Detail::DataMap const& dataMap) const
414{
416
417 if (cache._isRearranged) {
418 auto numerator = dataMap.at(cache._rearrangedNum.get());
419 auto denominator = dataMap.at(cache._rearrangedDen.get());
420 dispatch->compute(stream, RooBatchCompute::Ratio, output, nEvents, {numerator, denominator});
421 } else {
423 factors.reserve(cache._partList.size());
424 for (const RooAbsArg *i : cache._partList) {
425 auto span = dataMap.at(i);
426 factors.push_back(span);
427 }
428 RooBatchCompute::ArgVector special{static_cast<double>(factors.size())};
429 dispatch->compute(stream, RooBatchCompute::ProdPdf, output, nEvents, factors, special);
430 }
431}
432
433namespace {
434
435template<class T>
436void eraseNullptrs(std::vector<T*>& v) {
437 v.erase(std::remove_if(v.begin(), v.end(), [](T* x){ return x == nullptr; } ), v.end());
438}
439
440void removeCommon(std::vector<RooAbsArg*> &v, std::span<RooAbsArg * const> other) {
441
442 for (auto const& arg : other) {
443 auto namePtrMatch = [&arg](const RooAbsArg* elm) {
444 return elm != nullptr && elm->namePtr() == arg->namePtr();
445 };
446
447 auto found = std::find_if(v.begin(), v.end(), namePtrMatch);
448 if(found != v.end()) {
449 *found = nullptr;
450 }
451 }
452 eraseNullptrs(v);
453}
454
455void addCommon(std::vector<RooAbsArg*> &v, std::vector<RooAbsArg*> const& o1, std::vector<RooAbsArg*> const& o2) {
456
457 for (auto const& arg : o1) {
458 auto namePtrMatch = [&arg](const RooAbsArg* elm) {
459 return elm->namePtr() == arg->namePtr();
460 };
461
462 if(std::find_if(o2.begin(), o2.end(), namePtrMatch) != o2.end()) {
463 v.push_back(arg);
464 }
465 }
466}
467
468}
469
470
471////////////////////////////////////////////////////////////////////////////////
472/// Factorize product in irreducible terms for given choice of integration/normalization
473
474void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& intSet,
475 RooLinkedList& termList, RooLinkedList& normList,
476 RooLinkedList& impDepList, RooLinkedList& crossDepList,
477 RooLinkedList& intList) const
478{
479 // List of all term dependents: normalization and imported
480 std::vector<RooArgSet> depAllList;
481 std::vector<RooArgSet> depIntNoNormList;
482
483 // Setup lists for factorization terms and their dependents
484 RooArgSet* term(0);
485 RooArgSet* termNormDeps(0);
486 RooArgSet* termIntDeps(0);
487 RooArgSet* termIntNoNormDeps(0);
488
489 std::vector<RooAbsArg*> pdfIntNoNormDeps;
490 std::vector<RooAbsArg*> pdfIntSet;
491 std::vector<RooAbsArg*> pdfNSet;
492 std::vector<RooAbsArg*> pdfCSet;
493 std::vector<RooAbsArg*> pdfNormDeps; // Dependents to be normalized for the PDF
494 std::vector<RooAbsArg*> pdfAllDeps; // All dependents of this PDF
495
496 // Loop over the PDFs
497 for(std::size_t iPdf = 0; iPdf < _pdfList.size(); ++iPdf) {
498 RooAbsPdf& pdf = static_cast<RooAbsPdf&>(_pdfList[iPdf]);
499 RooArgSet& pdfNSetOrig = *_pdfNSetList[iPdf];
500
501 pdfNSet.clear();
502 pdfCSet.clear();
503
504 // Make iterator over tree leaf node list to get the observables.
505 // This code is borrowed from RooAgsPdf::getObservables.
506 // RooAbsArg::treeNodeServer list is relatively expensive, so we only do it
507 // once and use it in a lambda function.
508 RooArgSet pdfLeafList("leafNodeServerList") ;
509 pdf.treeNodeServerList(&pdfLeafList,0,false,true,true) ;
510 auto getObservablesOfCurrentPdf = [&pdfLeafList](
511 std::vector<RooAbsArg*> & out,
512 const RooArgSet& dataList) {
513 for (const auto arg : pdfLeafList) {
514 if (arg->dependsOnValue(dataList) && arg->isLValue()) {
515 out.push_back(arg) ;
516 }
517 }
518 };
519
520 // Reduce pdfNSet to actual dependents
521 if (0 == strcmp("cset", pdfNSetOrig.GetName())) {
522 getObservablesOfCurrentPdf(pdfNSet, normSet);
523 removeCommon(pdfNSet, pdfNSetOrig.get());
524 pdfCSet = pdfNSetOrig.get();
525 } else {
526 // Interpret at NSet
527 getObservablesOfCurrentPdf(pdfNSet, pdfNSetOrig);
528 }
529
530
531 pdfNormDeps.clear();
532 pdfAllDeps.clear();
533
534 // Make list of all dependents of this PDF
535 getObservablesOfCurrentPdf(pdfAllDeps, normSet);
536
537
538// cout << GetName() << ": pdf = " << pdf->GetName() << " pdfAllDeps = " << pdfAllDeps << " pdfNSet = " << *pdfNSet << " pdfCSet = " << *pdfCSet << endl;
539
540 // Make list of normalization dependents for this PDF;
541 if (!pdfNSet.empty()) {
542 // PDF is conditional
543 addCommon(pdfNormDeps, pdfAllDeps, pdfNSet);
544 } else {
545 // PDF is regular
546 pdfNormDeps = pdfAllDeps;
547 }
548
549// cout << GetName() << ": pdfNormDeps for " << pdf->GetName() << " = " << pdfNormDeps << endl;
550
551 pdfIntSet.clear();
552 getObservablesOfCurrentPdf(pdfIntSet, intSet) ;
553
554 // WVE if we have no norm deps, conditional observables should be taken out of pdfIntSet
555 if (pdfNormDeps.empty() && !pdfCSet.empty()) {
556 removeCommon(pdfIntSet, pdfCSet);
557// cout << GetName() << ": have no norm deps, removing conditional observables from intset" << endl;
558 }
559
560 pdfIntNoNormDeps.clear();
561 pdfIntNoNormDeps = pdfIntSet;
562 removeCommon(pdfIntNoNormDeps, pdfNormDeps);
563
564// cout << GetName() << ": pdf = " << pdf->GetName() << " intset = " << *pdfIntSet << " pdfIntNoNormDeps = " << pdfIntNoNormDeps << endl;
565
566 // Check if this PDF has dependents overlapping with one of the existing terms
567 bool done = false;
568 int j = 0;
569 auto lIter = termList.begin();
570 auto ldIter = normList.begin();
571 for(;lIter != termList.end(); (++lIter, ++ldIter, ++j)) {
572 termNormDeps = static_cast<RooArgSet*>(*ldIter);
573 term = static_cast<RooArgSet*>(*lIter);
574 // PDF should be added to existing term if
575 // 1) It has overlapping normalization dependents with any other PDF in existing term
576 // 2) It has overlapping dependents of any class for which integration is requested
577 // 3) If normalization happens over multiple ranges, and those ranges are both defined
578 // in either observable
579
580 bool normOverlap = termNormDeps->overlaps(pdfNormDeps.begin(), pdfNormDeps.end());
581 //bool intOverlap = pdfIntSet->overlaps(*termAllDeps);
582
583 if (normOverlap) {
584// cout << GetName() << ": this term overlaps with term " << (*term) << " in normalization observables" << endl;
585
586 term->add(pdf);
587 termNormDeps->add(pdfNormDeps.begin(), pdfNormDeps.end(), false);
588 depAllList[j].add(pdfAllDeps.begin(), pdfAllDeps.end(), false);
589 if (termIntDeps) {
590 termIntDeps->add(pdfIntSet.begin(), pdfIntSet.end(), false);
591 }
592 if (termIntNoNormDeps) {
593 termIntNoNormDeps->add(pdfIntNoNormDeps.begin(), pdfIntNoNormDeps.end(), false);
594 }
595 termIntNoNormDeps->add(pdfIntNoNormDeps.begin(), pdfIntNoNormDeps.end(), false);
596 done = true;
597 }
598 }
599
600 // If not, create a new term
601 if (!done) {
602 if (!(pdfNormDeps.empty() && pdfAllDeps.empty() &&
603 pdfIntSet.empty()) || normSet.empty()) {
604 term = new RooArgSet("term");
605 termNormDeps = new RooArgSet("termNormDeps");
606 depAllList.emplace_back(pdfAllDeps.begin(), pdfAllDeps.end(), "termAllDeps");
607 termIntDeps = new RooArgSet(pdfIntSet.begin(), pdfIntSet.end(), "termIntDeps");
608 depIntNoNormList.emplace_back(pdfIntNoNormDeps.begin(), pdfIntNoNormDeps.end(), "termIntNoNormDeps");
609 termIntNoNormDeps = &depIntNoNormList.back();
610
611 term->add(pdf);
612 termNormDeps->add(pdfNormDeps.begin(), pdfNormDeps.end(), false);
613
614 termList.Add(term);
615 normList.Add(termNormDeps);
616 intList.Add(termIntDeps);
617 }
618 }
619
620 }
621
622 // Loop over list of terms again to determine 'imported' observables
623 int i = 0;
624 RooArgSet *normDeps;
625 auto lIter = termList.begin();
626 auto ldIter = normList.begin();
627 for(;lIter != termList.end(); (++lIter, ++ldIter, ++i)) {
628 normDeps = static_cast<RooArgSet*>(*ldIter);
629 term = static_cast<RooArgSet*>(*lIter);
630 // Make list of wholly imported dependents
631 RooArgSet impDeps(depAllList[i]);
632 impDeps.remove(*normDeps, true, true);
633 impDepList.Add(impDeps.snapshot());
634// cout << GetName() << ": list of imported dependents for term " << (*term) << " set to " << impDeps << endl ;
635
636 // Make list of cross dependents (term is self contained for these dependents,
637 // but components import dependents from other components)
638 auto crossDeps = std::unique_ptr<RooAbsCollection>{depIntNoNormList[i].selectCommon(*normDeps)};
639 crossDepList.Add(crossDeps->snapshot());
640// cout << GetName() << ": list of cross dependents for term " << (*term) << " set to " << *crossDeps << endl ;
641 }
642
643 return;
644}
645
646
647
648
649////////////////////////////////////////////////////////////////////////////////
650/// Return list of (partial) integrals of product terms for integration
651/// of p.d.f over observables iset while normalization over observables nset.
652/// Also return list of normalization sets to be used to evaluate
653/// each component in the list correctly.
654
655Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, const char* isetRangeName) const
656{
657 // Check if this configuration was created before
658 Int_t sterileIdx(-1);
659
660 if (static_cast<CacheElem*>(_cacheMgr.getObj(nset,iset,&sterileIdx,isetRangeName))) {
661 return _cacheMgr.lastIndex();
662 }
663
664 std::unique_ptr<CacheElem> cache = createCacheElem(nset, iset, isetRangeName);
665
666 // Store the partial integral list and return the assigned code
667 return _cacheMgr.setObj(nset, iset, cache.release(), RooNameReg::ptr(isetRangeName));
668}
669
670
671
672std::unique_ptr<RooProdPdf::CacheElem> RooProdPdf::createCacheElem(const RooArgSet* nset,
673 const RooArgSet* iset,
674 const char* isetRangeName) const
675{
676// cout << " FOLKERT::RooProdPdf::getPartIntList(" << GetName() <<") nset = " << (nset?*nset:RooArgSet()) << endl
677// << " _normRange = " << _normRange << endl
678// << " iset = " << (iset?*iset:RooArgSet()) << endl
679// << " isetRangeName = " << (isetRangeName?isetRangeName:"<null>") << endl ;
680
681 // Create containers for partial integral components to be generated
682 auto cache = std::make_unique<CacheElem>();
683
684 // Factorize the product in irreducible terms for this nset
685 RooLinkedList terms, norms, imp, ints, cross;
686// cout << "RooProdPdf::getPIL -- now calling factorizeProduct()" << endl ;
687
688
689 // Normalization set used for factorization
690 RooArgSet factNset(nset ? (*nset) : _defNormSet);
691// cout << GetName() << "factNset = " << factNset << endl ;
692
693 factorizeProduct(factNset, iset ? (*iset) : RooArgSet(), terms, norms, imp, cross, ints);
694
695 RooArgSet *norm, *integ, *xdeps, *imps;
696
697 // Group irriducible terms that need to be (partially) integrated together
698 std::list<std::vector<RooArgSet*>> groupedList;
699 RooArgSet outerIntDeps;
700// cout << "RooProdPdf::getPIL -- now calling groupProductTerms()" << endl;
701 groupProductTerms(groupedList, outerIntDeps, terms, norms, imp, ints, cross);
702
703 // Loop over groups
704// cout<<"FK: pdf("<<GetName()<<") Starting selecting F(x|y)!"<<endl;
705 // Find groups of type F(x|y), i.e. termImpSet!=0, construct ratio object
706 std::map<std::string, RooArgSet> ratioTerms;
707 for (auto const& group : groupedList) {
708 if (1 == group.size()) {
709// cout<<"FK: Starting Single Term"<<endl;
710
711 RooArgSet* term = group[0];
712
713 Int_t termIdx = terms.IndexOf(term);
714 norm=(RooArgSet*) norms.At(termIdx);
715 imps=(RooArgSet*)imp.At(termIdx);
716 RooArgSet termNSet(*norm), termImpSet(*imps);
717
718// cout<<"FK: termImpSet.getSize() = "<<termImpSet.getSize()<< " " << termImpSet << endl;
719// cout<<"FK: _refRangeName = "<<_refRangeName<<endl;
720
721 if (!termImpSet.empty() && 0 != _refRangeName) {
722
723// cout << "WVE now here" << endl;
724
725 // WVE we can skip this if the ref range is equal to the normalization range
726 bool rangeIdentical(true);
727// cout << "_normRange = " << _normRange << " _refRangeName = " << RooNameReg::str(_refRangeName) << endl ;
728 for (auto const* normObs : static_range_cast<RooRealVar*>(termNSet)) {
729 //FK: Here the refRange should be compared to _normRange, if it's set, and to the normObs range if it's not set
730 if (_normRange.Length() > 0) {
731 if (normObs->getMin(_normRange.Data()) != normObs->getMin(RooNameReg::str(_refRangeName))) rangeIdentical = false;
732 if (normObs->getMax(_normRange.Data()) != normObs->getMax(RooNameReg::str(_refRangeName))) rangeIdentical = false;
733 }
734 else{
735 if (normObs->getMin() != normObs->getMin(RooNameReg::str(_refRangeName))) rangeIdentical = false;
736 if (normObs->getMax() != normObs->getMax(RooNameReg::str(_refRangeName))) rangeIdentical = false;
737 }
738 }
739// cout<<"FK: rangeIdentical Single = "<<(rangeIdentical ? 'T':'F')<<endl;
740 // coverity[CONSTANT_EXPRESSION_RESULT]
741 // LM : avoid making integral ratio if range is the same. Why was not included ??? (same at line 857)
742 if (!rangeIdentical ) {
743// cout << "PREPARING RATIO HERE (SINGLE TERM)" << endl ;
744 auto ratio = makeCondPdfRatioCorr(*(RooAbsReal*)term->first(), termNSet, termImpSet, normRange(), RooNameReg::str(_refRangeName));
745 std::ostringstream str; termImpSet.printValue(str);
746// cout << GetName() << "inserting ratio term" << endl;
747 ratioTerms[str.str()].addOwned(std::move(ratio));
748 }
749 }
750
751 } else {
752// cout<<"FK: Starting Composite Term"<<endl;
753
754 for (auto const& term : group) {
755
756 Int_t termIdx = terms.IndexOf(term);
757 norm=(RooArgSet*) norms.At(termIdx);
758 imps=(RooArgSet*)imp.At(termIdx);
759 RooArgSet termNSet(*norm), termImpSet(*imps);
760
761 if (!termImpSet.empty() && 0 != _refRangeName) {
762
763 // WVE we can skip this if the ref range is equal to the normalization range
764 bool rangeIdentical(true);
765 //FK: Here the refRange should be compared to _normRange, if it's set, and to the normObs range if it's not set
766 if(_normRange.Length() > 0) {
767 for (auto const* normObs : static_range_cast<RooRealVar*>(termNSet)) {
768 if (normObs->getMin(_normRange.Data()) != normObs->getMin(RooNameReg::str(_refRangeName))) rangeIdentical = false;
769 if (normObs->getMax(_normRange.Data()) != normObs->getMax(RooNameReg::str(_refRangeName))) rangeIdentical = false;
770 }
771 } else {
772 for (auto const* normObs : static_range_cast<RooRealVar*>(termNSet)) {
773 if (normObs->getMin() != normObs->getMin(RooNameReg::str(_refRangeName))) rangeIdentical = false;
774 if (normObs->getMax() != normObs->getMax(RooNameReg::str(_refRangeName))) rangeIdentical = false;
775 }
776 }
777// cout<<"FK: rangeIdentical Composite = "<<(rangeIdentical ? 'T':'F') <<endl;
778 if (!rangeIdentical ) {
779// cout << "PREPARING RATIO HERE (COMPOSITE TERM)" << endl ;
780 auto ratio = makeCondPdfRatioCorr(*(RooAbsReal*)term->first(), termNSet, termImpSet, normRange(), RooNameReg::str(_refRangeName));
781 std::ostringstream str; termImpSet.printValue(str);
782 ratioTerms[str.str()].addOwned(std::move(ratio));
783 }
784 }
785 }
786 }
787
788 }
789
790 // Find groups with y as termNSet
791 // Replace G(y) with (G(y),ratio)
792 for (auto const& group : groupedList) {
793 for (auto const& term : group) {
794 Int_t termIdx = terms.IndexOf(term);
795 norm = (RooArgSet*) norms.At(termIdx);
796 imps = (RooArgSet*) imp.At(termIdx);
797 RooArgSet termNSet(*norm), termImpSet(*imps);
798
799 // If termNset matches index of ratioTerms, insert ratio here
800 ostringstream str; termNSet.printValue(str);
801 if (!ratioTerms[str.str()].empty()) {
802// cout << "MUST INSERT RATIO OBJECT IN TERM (COMPOSITE)" << *term << endl;
803 term->add(ratioTerms[str.str()]);
804 cache->_ownedList.addOwned(std::move(ratioTerms[str.str()]));
805 }
806 }
807 }
808
809 for (auto const& group : groupedList) {
810// cout << GetName() << ":now processing group" << endl;
811// group->Print("1");
812
813 if (1 == group.size()) {
814// cout << "processing atomic item" << endl;
815 RooArgSet* term = group[0];
816
817 Int_t termIdx = terms.IndexOf(term);
818 norm = (RooArgSet*) norms.At(termIdx);
819 integ = (RooArgSet*) ints.At(termIdx);
820 xdeps = (RooArgSet*) cross.At(termIdx);
821 imps = (RooArgSet*) imp.At(termIdx);
822
823 RooArgSet termNSet, termISet, termXSet, termImpSet;
824
825 // Take list of normalization, integrated dependents from factorization algorithm
826 termISet.add(*integ);
827 termNSet.add(*norm);
828
829 // Cross-imported integrated dependents
830 termXSet.add(*xdeps);
831 termImpSet.add(*imps);
832
833 // Add prefab term to partIntList.
834 bool isOwned(false);
835 vector<RooAbsReal*> func = processProductTerm(nset, iset, isetRangeName, term, termNSet, termISet, isOwned);
836 if (func[0]) {
837 cache->_partList.add(*func[0]);
838 if (isOwned) cache->_ownedList.addOwned(std::unique_ptr<RooAbsArg>{func[0]});
839
840 cache->_normList.emplace_back(norm->snapshot(false));
841
842 cache->_numList.addOwned(std::unique_ptr<RooAbsArg>{func[1]});
843 cache->_denList.addOwned(std::unique_ptr<RooAbsArg>{func[2]});
844 }
845 } else {
846// cout << "processing composite item" << endl;
847 RooArgSet compTermSet, compTermNorm, compTermNum, compTermDen;
848 for (auto const& term : group) {
849// cout << GetName() << ": processing term " << (*term) << " of composite item" << endl ;
850 Int_t termIdx = terms.IndexOf(term);
851 norm = (RooArgSet*) norms.At(termIdx);
852 integ = (RooArgSet*) ints.At(termIdx);
853 xdeps = (RooArgSet*) cross.At(termIdx);
854 imps = (RooArgSet*) imp.At(termIdx);
855
856 RooArgSet termNSet, termISet, termXSet, termImpSet;
857 termISet.add(*integ);
858 termNSet.add(*norm);
859 termXSet.add(*xdeps);
860 termImpSet.add(*imps);
861
862 // Remove outer integration dependents from termISet
863 termISet.remove(outerIntDeps, true, true);
864
865 bool isOwned = false;
866 vector<RooAbsReal*> func = processProductTerm(nset, iset, isetRangeName, term, termNSet, termISet, isOwned, true);
867// cout << GetName() << ": created composite term component " << func[0]->GetName() << endl;
868 if (func[0]) {
869 compTermSet.add(*func[0]);
870 if (isOwned) cache->_ownedList.addOwned(std::unique_ptr<RooAbsArg>{func[0]});
871 compTermNorm.add(*norm, false);
872
873 compTermNum.add(*func[1]);
874 compTermDen.add(*func[2]);
875 //cache->_numList.add(*func[1]);
876 //cache->_denList.add(*func[2]);
877
878 }
879 }
880
881// cout << GetName() << ": constructing special composite product" << endl;
882// cout << GetName() << ": compTermSet = " ; compTermSet.Print("1");
883
884 // WVE THIS NEEDS TO BE REARRANGED
885
886 // compTermset is set van partial integrals to be multiplied
887 // prodtmp = product (compTermSet)
888 // inttmp = int ( prodtmp ) d (outerIntDeps) _range_isetRangeName
889
890 const std::string prodname = makeRGPPName("SPECPROD", compTermSet, outerIntDeps, RooArgSet(), isetRangeName);
891 auto prodtmp = std::make_unique<RooProduct>(prodname.c_str(), prodname.c_str(), compTermSet);
892
893 const std::string intname = makeRGPPName("SPECINT", compTermSet, outerIntDeps, RooArgSet(), isetRangeName);
894 auto inttmp = std::make_unique<RooRealIntegral>(intname.c_str(), intname.c_str(), *prodtmp, outerIntDeps, nullptr, nullptr, isetRangeName);
895 inttmp->setStringAttribute("PROD_TERM_TYPE", "SPECINT");
896
897 cache->_partList.add(*inttmp);
898
899 // Product of numerator terms
900 const string prodname_num = makeRGPPName("SPECPROD_NUM", compTermNum, RooArgSet(), RooArgSet(), 0);
901 auto prodtmp_num = std::make_unique<RooProduct>(prodname_num.c_str(), prodname_num.c_str(), compTermNum);
902 prodtmp_num->addOwnedComponents(compTermNum);
903
904 // Product of denominator terms
905 const string prodname_den = makeRGPPName("SPECPROD_DEN", compTermDen, RooArgSet(), RooArgSet(), 0);
906 auto prodtmp_den = std::make_unique<RooProduct>(prodname_den.c_str(), prodname_den.c_str(), compTermDen);
907 prodtmp_den->addOwnedComponents(compTermDen);
908
909 // Ratio
910 std::string name = Form("SPEC_RATIO(%s,%s)", prodname_num.c_str(), prodname_den.c_str());
911 auto ndr = std::make_unique<RooFormulaVar>(name.c_str(), "@0/@1", RooArgList(*prodtmp_num, *prodtmp_den));
912
913 // Integral of ratio
914 std::unique_ptr<RooAbsReal> numtmp{ndr->createIntegral(outerIntDeps,isetRangeName)};
915 numtmp->addOwnedComponents(std::move(ndr));
916
917 cache->_ownedList.addOwned(std::move(prodtmp));
918 cache->_ownedList.addOwned(std::move(inttmp));
919 cache->_ownedList.addOwned(std::move(prodtmp_num));
920 cache->_ownedList.addOwned(std::move(prodtmp_den));
921 cache->_numList.addOwned(std::move(numtmp));
922 cache->_denList.addOwned(std::unique_ptr<RooAbsArg>{static_cast<RooAbsArg*>(RooFit::RooConst(1).clone("1"))});
923 cache->_normList.emplace_back(std::make_unique<RooArgSet>());
924 compTermNorm.snapshot(*cache->_normList.back(), false);
925 }
926 }
927
928 // Need to rearrange product in case of multiple ranges
929 if (_normRange.Contains(",")) {
930 rearrangeProduct(*cache);
931 }
932
933 // We own contents of all lists filled by factorizeProduct()
934 terms.Delete();
935 ints.Delete();
936 imp.Delete();
937 norms.Delete();
938 cross.Delete();
939
940 return cache;
941}
942
943
944
945////////////////////////////////////////////////////////////////////////////////
946/// For single normalization ranges
947
948std::unique_ptr<RooAbsReal> RooProdPdf::makeCondPdfRatioCorr(RooAbsReal& pdf, const RooArgSet& termNset, const RooArgSet& /*termImpSet*/, const char* normRangeTmp, const char* refRange) const
949{
950 std::unique_ptr<RooAbsReal> ratio_num{pdf.createIntegral(termNset,normRangeTmp)};
951 std::unique_ptr<RooAbsReal> ratio_den{pdf.createIntegral(termNset,refRange)};
952 auto ratio = std::make_unique<RooFormulaVar>(Form("ratio(%s,%s)",ratio_num->GetName(),ratio_den->GetName()),"@0/@1",
953 RooArgList(*ratio_num,*ratio_den)) ;
954
955 ratio->addOwnedComponents(std::move(ratio_num));
956 ratio->addOwnedComponents(std::move(ratio_den));
957 ratio->setAttribute("RATIO_TERM") ;
958 return ratio ;
959}
960
961
962
963
964////////////////////////////////////////////////////////////////////////////////
965
967{
968 RooAbsReal *part, *num, *den ;
969 RooArgSet nomList ;
970
971 list<string> rangeComps ;
972 {
973 std::vector<char> buf(strlen(_normRange.Data()) + 1);
974 strcpy(buf.data(),_normRange.Data()) ;
975 char* save(0) ;
976 char* token = R__STRTOK_R(buf.data(),",",&save) ;
977 while(token) {
978 rangeComps.push_back(token) ;
979 token = R__STRTOK_R(0,",",&save) ;
980 }
981 }
982
983
984 std::map<std::string,RooArgSet> denListList ;
985 RooArgSet specIntDeps ;
986 string specIntRange ;
987
988// cout << "THIS IS REARRANGEPRODUCT" << endl ;
989
990 for (std::size_t i = 0; i < cache._partList.size(); i++) {
991
992 part = static_cast<RooAbsReal*>(cache._partList.at(i));
993 num = static_cast<RooAbsReal*>(cache._numList.at(i));
994 den = static_cast<RooAbsReal*>(cache._denList.at(i));
995 i++;
996
997// cout << "now processing part " << part->GetName() << " of type " << part->getStringAttribute("PROD_TERM_TYPE") << endl ;
998// cout << "corresponding numerator = " << num->GetName() << endl ;
999// cout << "corresponding denominator = " << den->GetName() << endl ;
1000
1001
1002 RooFormulaVar* ratio(0) ;
1003 RooArgSet origNumTerm ;
1004
1005 if (string("SPECINT")==part->getStringAttribute("PROD_TERM_TYPE")) {
1006
1007 RooRealIntegral* orig = (RooRealIntegral*) num;
1008 RooFormulaVar* specratio = (RooFormulaVar*) &orig->integrand() ;
1009 RooProduct* func = (RooProduct*) specratio->getParameter(0) ;
1010
1011 std::unique_ptr<RooArgSet> components{orig->getComponents()};
1012 for(RooAbsArg * carg : *components) {
1013 if (carg->getAttribute("RATIO_TERM")) {
1014 ratio = (RooFormulaVar*)carg ;
1015 break ;
1016 }
1017 }
1018
1019 if (ratio) {
1020 RooCustomizer cust(*func,"blah") ;
1021 cust.replaceArg(*ratio,RooFit::RooConst(1)) ;
1022 RooAbsArg* funcCust = cust.build() ;
1023// cout << "customized function = " << endl ;
1024// funcCust->printComponentTree() ;
1025 nomList.add(*funcCust) ;
1026 } else {
1027 nomList.add(*func) ;
1028 }
1029
1030
1031 } else {
1032
1033 // Find the ratio term
1034 RooAbsReal* func = num;
1035 // If top level object is integral, navigate to integrand
1036 if (func->InheritsFrom(RooRealIntegral::Class())) {
1037 func = (RooAbsReal*) &((RooRealIntegral*)(func))->integrand();
1038 }
1039 if (func->InheritsFrom(RooProduct::Class())) {
1040// cout << "product term found: " ; func->Print() ;
1041 for(RooAbsArg * arg : static_cast<RooProduct*>(func)->components()) {
1042 if (arg->getAttribute("RATIO_TERM")) {
1043 ratio = (RooFormulaVar*)(arg) ;
1044 } else {
1045 origNumTerm.add(*arg) ;
1046 }
1047 }
1048 }
1049
1050 if (ratio) {
1051// cout << "Found ratio term in numerator: " << ratio->GetName() << endl ;
1052// cout << "Adding only original term to numerator: " << origNumTerm << endl ;
1053 nomList.add(origNumTerm) ;
1054 } else {
1055 nomList.add(*num) ;
1056 }
1057
1058 }
1059
1060 for (list<string>::iterator iter = rangeComps.begin() ; iter != rangeComps.end() ; ++iter) {
1061 // If denominator is an integral, make a clone with the integration range adjusted to
1062 // the selected component of the normalization integral
1063// cout << "NOW PROCESSING DENOMINATOR " << den->ClassName() << "::" << den->GetName() << endl ;
1064
1065 if (string("SPECINT")==part->getStringAttribute("PROD_TERM_TYPE")) {
1066
1067// cout << "create integral: SPECINT case" << endl ;
1068 RooRealIntegral* orig = (RooRealIntegral*) num;
1069 RooFormulaVar* specRatio = (RooFormulaVar*) &orig->integrand() ;
1070 specIntDeps.add(orig->intVars()) ;
1071 if (orig->intRange()) {
1072 specIntRange = orig->intRange() ;
1073 }
1074 //RooProduct* numtmp = (RooProduct*) specRatio->getParameter(0) ;
1075 RooProduct* dentmp = (RooProduct*) specRatio->getParameter(1) ;
1076
1077// cout << "numtmp = " << numtmp->ClassName() << "::" << numtmp->GetName() << endl ;
1078// cout << "dentmp = " << dentmp->ClassName() << "::" << dentmp->GetName() << endl ;
1079
1080// cout << "denominator components are " << dentmp->components() << endl ;
1081 for (auto* parg : static_range_cast<RooAbsReal*>(dentmp->components())) {
1082// cout << "now processing denominator component " << parg->ClassName() << "::" << parg->GetName() << endl ;
1083
1084 if (ratio && parg->dependsOn(*ratio)) {
1085// cout << "depends in value of ratio" << endl ;
1086
1087 // Make specialize ratio instance
1088 std::unique_ptr<RooAbsReal> specializedRatio{specializeRatio(*(RooFormulaVar*)ratio,iter->c_str())};
1089
1090// cout << "specRatio = " << endl ;
1091// specializedRatio->printComponentTree() ;
1092
1093 // Replace generic ratio with specialized ratio
1094 RooAbsArg *partCust(0) ;
1095 if (parg->InheritsFrom(RooAddition::Class())) {
1096
1097
1098
1099 RooAddition* tmpadd = (RooAddition*)(parg) ;
1100
1101 RooCustomizer cust(*tmpadd->list1().first(),Form("blah_%s",iter->c_str())) ;
1102 cust.replaceArg(*ratio,*specializedRatio) ;
1103 partCust = cust.build() ;
1104
1105 } else {
1106 RooCustomizer cust(*parg,Form("blah_%s",iter->c_str())) ;
1107 cust.replaceArg(*ratio,*specializedRatio) ;
1108 partCust = cust.build() ;
1109 }
1110
1111 // Print customized denominator
1112// cout << "customized function = " << endl ;
1113// partCust->printComponentTree() ;
1114
1115 std::unique_ptr<RooAbsReal> specializedPartCust{specializeIntegral(*(RooAbsReal*)partCust,iter->c_str())};
1116
1117 // Finally divide again by ratio
1118 string name = Form("%s_divided_by_ratio",specializedPartCust->GetName()) ;
1119 auto specIntFinal = std::make_unique<RooFormulaVar>(name.c_str(),"@0/@1",RooArgList(*specializedPartCust,*specializedRatio)) ;
1120 specIntFinal->addOwnedComponents(std::move(specializedPartCust));
1121 specIntFinal->addOwnedComponents(std::move(specializedRatio));
1122
1123 denListList[*iter].addOwned(std::move(specIntFinal));
1124 } else {
1125
1126// cout << "does NOT depend on value of ratio" << endl ;
1127// parg->Print("t") ;
1128
1129 denListList[*iter].addOwned(specializeIntegral(*parg,iter->c_str()));
1130
1131 }
1132 }
1133// cout << "end iteration over denominator components" << endl ;
1134 } else {
1135
1136 if (ratio) {
1137
1138 std::unique_ptr<RooAbsReal> specRatio{specializeRatio(*(RooFormulaVar*)ratio,iter->c_str())};
1139
1140 // If integral is 'Int r(y)*g(y) dy ' then divide a posteriori by r(y)
1141// cout << "have ratio, orig den = " << den->GetName() << endl ;
1142
1143 RooArgSet tmp(origNumTerm) ;
1144 tmp.add(*specRatio) ;
1145 const string pname = makeRGPPName("PROD",tmp,RooArgSet(),RooArgSet(),0) ;
1146 auto specDenProd = std::make_unique<RooProduct>(pname.c_str(),pname.c_str(),tmp) ;
1147 std::unique_ptr<RooAbsReal> specInt;
1148
1150 specInt = std::unique_ptr<RooAbsReal>{specDenProd->createIntegral(((RooRealIntegral*)den)->intVars(),iter->c_str())};
1151 specInt->addOwnedComponents(std::move(specDenProd));
1152 } else if (den->InheritsFrom(RooAddition::Class())) {
1153 RooAddition* orig = (RooAddition*)den ;
1154 RooRealIntegral* origInt = (RooRealIntegral*) orig->list1().first() ;
1155 specInt = std::unique_ptr<RooAbsReal>{specDenProd->createIntegral(origInt->intVars(),iter->c_str())};
1156 specInt->addOwnedComponents(std::move(specDenProd));
1157 } else {
1158 throw string("this should not happen") ;
1159 }
1160
1161 //RooAbsReal* specInt = specializeIntegral(*den,iter->c_str()) ;
1162 string name = Form("%s_divided_by_ratio",specInt->GetName()) ;
1163 auto specIntFinal = std::make_unique<RooFormulaVar>(name.c_str(),"@0/@1",RooArgList(*specInt,*specRatio)) ;
1164 specIntFinal->addOwnedComponents(std::move(specInt));
1165 specIntFinal->addOwnedComponents(std::move(specRatio));
1166 denListList[*iter].addOwned(std::move(specIntFinal));
1167 } else {
1168 denListList[*iter].addOwned(specializeIntegral(*den,iter->c_str()));
1169 }
1170
1171 }
1172 }
1173
1174 }
1175
1176 // Do not rearrage terms if numerator and denominator are effectively empty
1177 if (nomList.empty()) {
1178 return ;
1179 }
1180
1181 string name = Form("%s_numerator",GetName()) ;
1182 // WVE FIX THIS (2)
1183
1184 std::unique_ptr<RooAbsReal> numerator = std::make_unique<RooProduct>(name.c_str(),name.c_str(),nomList) ;
1185
1186 RooArgSet products ;
1187// cout << "nomList = " << nomList << endl ;
1188 for (map<string,RooArgSet>::iterator iter = denListList.begin() ; iter != denListList.end() ; ++iter) {
1189// cout << "denList[" << iter->first << "] = " << iter->second << endl ;
1190 name = Form("%s_denominator_comp_%s",GetName(),iter->first.c_str()) ;
1191 // WVE FIX THIS (2)
1192 RooProduct* prod_comp = new RooProduct(name.c_str(),name.c_str(),iter->second) ;
1193 prod_comp->addOwnedComponents(std::move(iter->second));
1194 products.add(*prod_comp) ;
1195 }
1196 name = Form("%s_denominator_sum",GetName()) ;
1197 RooAbsReal* norm = new RooAddition(name.c_str(),name.c_str(),products) ;
1198 norm->addOwnedComponents(products) ;
1199
1200 if (!specIntDeps.empty()) {
1201 // Apply posterior integration required for SPECINT case
1202
1203 string namesr = Form("SPEC_RATIO(%s,%s)",numerator->GetName(),norm->GetName()) ;
1204 RooFormulaVar* ndr = new RooFormulaVar(namesr.c_str(),"@0/@1",RooArgList(*numerator,*norm)) ;
1205 ndr->addOwnedComponents(std::move(numerator));
1206
1207 // Integral of ratio
1208 numerator = std::unique_ptr<RooAbsReal>{ndr->createIntegral(specIntDeps,specIntRange.c_str())};
1209
1210 norm = (RooAbsReal*) RooFit::RooConst(1).Clone() ;
1211 }
1212
1213
1214// cout << "numerator" << endl ;
1215// numerator->printComponentTree("",0,5) ;
1216// cout << "denominator" << endl ;
1217// norm->printComponentTree("",0,5) ;
1218
1219
1220 // WVE DEBUG
1221 //RooMsgService::instance().debugWorkspace()->import(RooArgSet(*numerator,*norm)) ;
1222
1223 cache._rearrangedNum = std::move(numerator);
1224 cache._rearrangedDen.reset(norm);
1225 cache._isRearranged = true ;
1226
1227}
1228
1229
1230////////////////////////////////////////////////////////////////////////////////
1231
1232std::unique_ptr<RooAbsReal> RooProdPdf::specializeRatio(RooFormulaVar& input, const char* targetRangeName) const
1233{
1234 RooRealIntegral* numint = (RooRealIntegral*) input.getParameter(0) ;
1235 RooRealIntegral* denint = (RooRealIntegral*) input.getParameter(1) ;
1236
1237 std::unique_ptr<RooAbsReal> numint_spec{specializeIntegral(*numint,targetRangeName)};
1238
1239 std::unique_ptr<RooAbsReal> ret = std::make_unique<RooFormulaVar>(Form("ratio(%s,%s)",numint_spec->GetName(),denint->GetName()),"@0/@1",RooArgList(*numint_spec,*denint)) ;
1240 ret->addOwnedComponents(std::move(numint_spec));
1241
1242 return ret;
1243}
1244
1245
1246
1247////////////////////////////////////////////////////////////////////////////////
1248
1249std::unique_ptr<RooAbsReal> RooProdPdf::specializeIntegral(RooAbsReal& input, const char* targetRangeName) const
1250{
1251 if (input.InheritsFrom(RooRealIntegral::Class())) {
1252
1253 // If input is integral, recreate integral but override integration range to be targetRangeName
1255// cout << "creating integral: integrand = " << orig->integrand().GetName() << " vars = " << orig->intVars() << " range = " << targetRangeName << endl ;
1256 return std::unique_ptr<RooAbsReal>{orig->integrand().createIntegral(orig->intVars(),targetRangeName)};
1257
1258 } else if (input.InheritsFrom(RooAddition::Class())) {
1259
1260 // If input is sum of integrals, recreate integral from first component of set, but override integration range to be targetRangeName
1261 RooAddition* orig = (RooAddition*)&input ;
1262 RooRealIntegral* origInt = (RooRealIntegral*) orig->list1().first() ;
1263// cout << "creating integral from addition: integrand = " << origInt->integrand().GetName() << " vars = " << origInt->intVars() << " range = " << targetRangeName << endl ;
1264 return std::unique_ptr<RooAbsReal>{origInt->integrand().createIntegral(origInt->intVars(),targetRangeName)};
1265 }
1266
1267 std::stringstream errMsg;
1268 errMsg << "specializeIntegral: unknown input type " << input.ClassName() << "::" << input.GetName();
1269 throw std::runtime_error(errMsg.str());
1270}
1271
1272
1273////////////////////////////////////////////////////////////////////////////////
1274/// Group product into terms that can be calculated independently
1275
1276void RooProdPdf::groupProductTerms(std::list<std::vector<RooArgSet*>>& groupedTerms, RooArgSet& outerIntDeps,
1277 const RooLinkedList& terms, const RooLinkedList& norms,
1278 const RooLinkedList& imps, const RooLinkedList& ints, const RooLinkedList& /*cross*/) const
1279{
1280 // Start out with each term in its own group
1281 for(auto * term : static_range_cast<RooArgSet*>(terms)) {
1282 groupedTerms.emplace_back();
1283 groupedTerms.back().emplace_back(term) ;
1284 }
1285
1286 // Make list of imported dependents that occur in any term
1287 RooArgSet allImpDeps ;
1288 for(auto * impDeps : static_range_cast<RooArgSet*>(imps)) {
1289 allImpDeps.add(*impDeps,false) ;
1290 }
1291
1292 // Make list of integrated dependents that occur in any term
1293 RooArgSet allIntDeps ;
1294 for(auto * intDeps : static_range_cast<RooArgSet*>(ints)) {
1295 allIntDeps.add(*intDeps,false) ;
1296 }
1297
1298 outerIntDeps.removeAll() ;
1299 outerIntDeps.add(*std::unique_ptr<RooArgSet>{static_cast<RooArgSet*>(allIntDeps.selectCommon(allImpDeps))});
1300
1301 // Now iteratively merge groups that should be (partially) integrated together
1302 for(RooAbsArg * outerIntDep : outerIntDeps) {
1303
1304 // Collect groups that feature this dependent
1305 std::vector<RooArgSet*>* newGroup = nullptr ;
1306
1307 // Loop over groups
1308 bool needMerge = false ;
1309 auto group = groupedTerms.begin();
1310 auto nGroups = groupedTerms.size();
1311 for (size_t iGroup = 0; iGroup < nGroups; ++iGroup) {
1312
1313 // See if any term in this group depends in any ay on outerDepInt
1314 for (auto const& term2 : *group) {
1315
1316 Int_t termIdx = terms.IndexOf(term2) ;
1317 RooArgSet* termNormDeps = (RooArgSet*) norms.At(termIdx) ;
1318 RooArgSet* termIntDeps = (RooArgSet*) ints.At(termIdx) ;
1319 RooArgSet* termImpDeps = (RooArgSet*) imps.At(termIdx) ;
1320
1321 if (termNormDeps->contains(*outerIntDep) ||
1322 termIntDeps->contains(*outerIntDep) ||
1323 termImpDeps->contains(*outerIntDep)) {
1324 needMerge = true ;
1325 }
1326
1327 }
1328
1329 if (needMerge) {
1330 // Create composite group if not yet existing
1331 if (newGroup==nullptr) {
1332 groupedTerms.emplace_back() ;
1333 newGroup = &groupedTerms.back() ;
1334 }
1335
1336 // Add terms of this group to new term
1337 for (auto& term2 : *group) {
1338 newGroup->emplace_back(term2) ;
1339 }
1340
1341 // Remove this non-owning group from list
1342 group = groupedTerms.erase(group);
1343 } else {
1344 ++group;
1345 }
1346 }
1347
1348 }
1349}
1350
1351
1352
1353////////////////////////////////////////////////////////////////////////////////
1354/// Calculate integrals of factorized product terms over observables iset while normalized
1355/// to observables in nset.
1356
1357std::vector<RooAbsReal*> RooProdPdf::processProductTerm(const RooArgSet* nset, const RooArgSet* iset, const char* isetRangeName,
1358 const RooArgSet* term,const RooArgSet& termNSet, const RooArgSet& termISet,
1359 bool& isOwned, bool forceWrap) const
1360{
1361 vector<RooAbsReal*> ret(3) ; ret[0] = 0 ; ret[1] = 0 ; ret[2] = 0 ;
1362
1363 // CASE I: factorizing term: term is integrated over all normalizing observables
1364 // -----------------------------------------------------------------------------
1365 // Check if all observbales of this term are integrated. If so the term cancels
1366 if (termNSet.getSize()>0 && termNSet.getSize()==termISet.getSize() && isetRangeName==0) {
1367
1368
1369 //cout << "processProductTerm(" << GetName() << ") case I " << endl ;
1370
1371 // Term factorizes
1372 return ret ;
1373 }
1374
1375 // CASE II: Dropped terms: if term is entirely unnormalized, it should be dropped
1376 // ------------------------------------------------------------------------------
1377 if (nset && termNSet.empty()) {
1378
1379 //cout << "processProductTerm(" << GetName() << ") case II " << endl ;
1380
1381 // Drop terms that are not asked to be normalized
1382 return ret ;
1383 }
1384
1385 if (iset && termISet.getSize()>0) {
1386 if (term->getSize()==1) {
1387
1388 // CASE IIIa: Normalized and partially integrated single PDF term
1389 //---------------------------------------------------------------
1390
1391 RooAbsPdf* pdf = (RooAbsPdf*) term->first() ;
1392
1393 RooAbsReal* partInt = std::unique_ptr<RooAbsReal>{pdf->createIntegral(termISet,termNSet,isetRangeName)}.release();
1394 partInt->setOperMode(operMode()) ;
1395 partInt->setStringAttribute("PROD_TERM_TYPE","IIIa") ;
1396
1397 isOwned=true ;
1398
1399 //cout << "processProductTerm(" << GetName() << ") case IIIa func = " << partInt->GetName() << endl ;
1400
1401 ret[0] = partInt ;
1402
1403 // Split mode results
1404 ret[1] = std::unique_ptr<RooAbsReal>{pdf->createIntegral(termISet,isetRangeName)}.release();
1405 ret[2] = std::unique_ptr<RooAbsReal>{pdf->createIntegral(termNSet,normRange())}.release();
1406
1407 return ret ;
1408
1409
1410 } else {
1411
1412 // CASE IIIb: Normalized and partially integrated composite PDF term
1413 //---------------------------------------------------------------
1414
1415 // Use auxiliary class RooGenProdProj to calculate this term
1416 const std::string name = makeRGPPName("GENPROJ_",*term,termISet,termNSet,isetRangeName) ;
1417 RooAbsReal* partInt = new RooGenProdProj(name.c_str(),name.c_str(),*term,termISet,termNSet,isetRangeName) ;
1418 partInt->setStringAttribute("PROD_TERM_TYPE","IIIb") ;
1419 partInt->setOperMode(operMode()) ;
1420
1421 //cout << "processProductTerm(" << GetName() << ") case IIIb func = " << partInt->GetName() << endl ;
1422
1423 isOwned=true ;
1424 ret[0] = partInt ;
1425
1426 const std::string name1 = makeRGPPName("PROD",*term,RooArgSet(),RooArgSet(),0) ;
1427
1428 // WVE FIX THIS
1429 RooProduct* tmp_prod = new RooProduct(name1.c_str(),name1.c_str(),*term) ;
1430
1431 ret[1] = std::unique_ptr<RooAbsReal>{tmp_prod->createIntegral(termISet,isetRangeName)}.release();
1432 ret[2] = std::unique_ptr<RooAbsReal>{tmp_prod->createIntegral(termNSet,normRange())}.release();
1433
1434 return ret ;
1435 }
1436 }
1437
1438 // CASE IVa: Normalized non-integrated composite PDF term
1439 // -------------------------------------------------------
1440 if (nset && nset->getSize()>0 && term->getSize()>1) {
1441 // Composite term needs normalized integration
1442
1443 const std::string name = makeRGPPName("GENPROJ_",*term,termISet,termNSet,isetRangeName) ;
1444 RooAbsReal* partInt = new RooGenProdProj(name.c_str(),name.c_str(),*term,termISet,termNSet,isetRangeName,normRange()) ;
1446
1447 partInt->setStringAttribute("PROD_TERM_TYPE","IVa") ;
1448 partInt->setOperMode(operMode()) ;
1449
1450 //cout << "processProductTerm(" << GetName() << ") case IVa func = " << partInt->GetName() << endl ;
1451
1452 isOwned=true ;
1453 ret[0] = partInt ;
1454
1455 const std::string name1 = makeRGPPName("PROD",*term,RooArgSet(),RooArgSet(),0) ;
1456
1457 // WVE FIX THIS
1458 RooProduct* tmp_prod = new RooProduct(name1.c_str(),name1.c_str(),*term) ;
1459
1460 ret[1] = std::unique_ptr<RooAbsReal>{tmp_prod->createIntegral(termISet,isetRangeName)}.release();
1461 ret[2] = std::unique_ptr<RooAbsReal>{tmp_prod->createIntegral(termNSet,normRange())}.release();
1462
1463 return ret ;
1464 }
1465
1466 // CASE IVb: Normalized, non-integrated single PDF term
1467 // -----------------------------------------------------
1468 for (auto* pdf : static_range_cast<RooAbsPdf*>(*term)) {
1469
1470 if (forceWrap) {
1471
1472 // Construct representative name of normalization wrapper
1473 TString name(pdf->GetName()) ;
1474 name.Append("_NORM[") ;
1475 bool first(true) ;
1476 for (auto const* arg : termNSet) {
1477 if (!first) {
1478 name.Append(",") ;
1479 } else {
1480 first=false ;
1481 }
1482 name.Append(arg->GetName()) ;
1483 }
1484 if (normRange()) {
1485 name.Append("|") ;
1486 name.Append(normRange()) ;
1487 }
1488 name.Append("]") ;
1489
1490 RooAbsReal* partInt = new RooRealIntegral(name.Data(),name.Data(),*pdf,RooArgSet(),&termNSet) ;
1491 partInt->setStringAttribute("PROD_TERM_TYPE","IVb") ;
1492 isOwned=true ;
1493
1494 //cout << "processProductTerm(" << GetName() << ") case IVb func = " << partInt->GetName() << endl ;
1495
1496 ret[0] = partInt ;
1497
1498 ret[1] = std::unique_ptr<RooAbsReal>{pdf->createIntegral(RooArgSet())}.release();
1499 ret[2] = std::unique_ptr<RooAbsReal>{pdf->createIntegral(termNSet,normRange())}.release();
1500
1501 return ret ;
1502
1503
1504 } else {
1505 isOwned=false ;
1506
1507 //cout << "processProductTerm(" << GetName() << ") case IVb func = " << pdf->GetName() << endl ;
1508
1509
1510 pdf->setStringAttribute("PROD_TERM_TYPE","IVb") ;
1511 ret[0] = pdf ;
1512
1513 ret[1] = std::unique_ptr<RooAbsReal>{pdf->createIntegral(RooArgSet())}.release();
1514 ret[2] = !termNSet.empty() ? std::unique_ptr<RooAbsReal>{pdf->createIntegral(termNSet,normRange())}.release()
1515 : ((RooAbsReal*)RooFit::RooConst(1).clone("1"));
1516 return ret ;
1517 }
1518 }
1519
1520 coutE(Eval) << "RooProdPdf::processProductTerm(" << GetName() << ") unidentified term!!!" << endl ;
1521 return ret ;
1522}
1523
1524
1525
1526
1527////////////////////////////////////////////////////////////////////////////////
1528/// Make an appropriate automatic name for a RooGenProdProj object in getPartIntList()
1529
1530std::string RooProdPdf::makeRGPPName(const char* pfx, const RooArgSet& term, const RooArgSet& iset,
1531 const RooArgSet& nset, const char* isetRangeName) const
1532{
1533 // Make an appropriate automatic name for a RooGenProdProj object in getPartIntList()
1534
1535 std::ostringstream os(pfx);
1536 os << "[";
1537
1538 // Encode component names
1539 bool first(true) ;
1540 for (auto const* pdf : static_range_cast<RooAbsPdf*>(term)) {
1541 if (!first) os << "_X_";
1542 first = false;
1543 os << pdf->GetName();
1544 }
1545 os << "]" << integralNameSuffix(iset,&nset,isetRangeName,true);
1546
1547 return os.str();
1548}
1549
1550
1551
1552////////////////////////////////////////////////////////////////////////////////
1553/// Force RooRealIntegral to offer all observables for internal integration
1554
1556{
1557 return true ;
1558}
1559
1560
1561
1562////////////////////////////////////////////////////////////////////////////////
1563/// Determine which part (if any) of given integral can be performed analytically.
1564/// If any analytical integration is possible, return integration scenario code.
1565///
1566/// RooProdPdf implements two strategies in implementing analytical integrals
1567///
1568/// First, PDF components whose entire set of dependents are requested to be integrated
1569/// can be dropped from the product, as they will integrate out to 1 by construction
1570///
1571/// Second, RooProdPdf queries each remaining component PDF for its analytical integration
1572/// capability of the requested set ('allVars'). It finds the largest common set of variables
1573/// that can be integrated by all remaining components. If such a set exists, it reconfirms that
1574/// each component is capable of analytically integrating the common set, and combines the components
1575/// individual integration codes into a single integration code valid for RooProdPdf.
1576
1578 const RooArgSet* normSet, const char* rangeName) const
1579{
1580 if (_forceNumInt) return 0 ;
1581
1582 // Declare that we can analytically integrate all requested observables
1583 analVars.add(allVars) ;
1584
1585 // Retrieve (or create) the required partial integral list
1586 Int_t code = getPartIntList(normSet,&allVars,rangeName);
1587
1588 return code+1 ;
1589}
1590
1591
1592
1593
1594////////////////////////////////////////////////////////////////////////////////
1595/// Return analytical integral defined by given scenario code
1596
1597double RooProdPdf::analyticalIntegralWN(Int_t code, const RooArgSet* normSet, const char* rangeName) const
1598{
1599 // No integration scenario
1600 if (code==0) {
1601 return getVal(normSet) ;
1602 }
1603
1604
1605 // WVE needs adaptation for rangename feature
1606
1607 // Partial integration scenarios
1608 CacheElem* cache = (CacheElem*) _cacheMgr.getObjByIndex(code-1) ;
1609
1610 // If cache has been sterilized, revive this slot
1611 if (cache==0) {
1612 std::unique_ptr<RooArgSet> vars{getParameters(RooArgSet())} ;
1613 RooArgSet nset = _cacheMgr.selectFromSet1(*vars, code-1) ;
1614 RooArgSet iset = _cacheMgr.selectFromSet2(*vars, code-1) ;
1615
1616 Int_t code2 = getPartIntList(&nset, &iset, rangeName) ;
1617
1618 // preceding call to getPartIntList guarantees non-null return
1619 // coverity[NULL_RETURNS]
1620 cache = (CacheElem*) _cacheMgr.getObj(&nset,&iset,&code2,rangeName) ;
1621 }
1622
1623 double val = calculate(*cache,true) ;
1624// cout << "RPP::aIWN(" << GetName() << ") ,code = " << code << ", value = " << val << endl ;
1625
1626 return val ;
1627}
1628
1629
1630
1631////////////////////////////////////////////////////////////////////////////////
1632/// If this product contains exactly one extendable p.d.f return the extension abilities of
1633/// that p.d.f, otherwise return CanNotBeExtended
1634
1636{
1638}
1639
1640
1641
1642////////////////////////////////////////////////////////////////////////////////
1643/// Return the expected number of events associated with the extendable input PDF
1644/// in the product. If there is no extendable term, abort.
1645
1646double RooProdPdf::expectedEvents(const RooArgSet* nset) const
1647{
1648 if (_extendedIndex<0) {
1649 coutF(Generation) << "Requesting expected number of events from a RooProdPdf that does not contain an extended p.d.f" << endl ;
1650 throw std::logic_error(std::string("RooProdPdf ") + GetName() + " could not be extended.");
1651 }
1652
1653 return static_cast<RooAbsPdf*>(_pdfList.at(_extendedIndex))->expectedEvents(nset) ;
1654}
1655
1656std::unique_ptr<RooAbsReal> RooProdPdf::createExpectedEventsFunc(const RooArgSet* nset) const
1657{
1658 if (_extendedIndex<0) {
1659 coutF(Generation) << "Requesting expected number of events from a RooProdPdf that does not contain an extended p.d.f" << endl ;
1660 throw std::logic_error(std::string("RooProdPdf ") + GetName() + " could not be extended.");
1661 }
1662
1663 return static_cast<RooAbsPdf*>(_pdfList.at(_extendedIndex))->createExpectedEventsFunc(nset);
1664}
1665
1666
1667////////////////////////////////////////////////////////////////////////////////
1668/// Return generator context optimized for generating events from product p.d.f.s
1669
1671 const RooArgSet* auxProto, bool verbose) const
1672{
1673 if (_useDefaultGen) return RooAbsPdf::genContext(vars,prototype,auxProto,verbose) ;
1674 return new RooProdGenContext(*this,vars,prototype,auxProto,verbose) ;
1675}
1676
1677
1678
1679////////////////////////////////////////////////////////////////////////////////
1680/// Query internal generation capabilities of component p.d.f.s and aggregate capabilities
1681/// into master configuration passed to the generator context
1682
1683Int_t RooProdPdf::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, bool staticInitOK) const
1684{
1685 if (!_useDefaultGen) return 0 ;
1686
1687 // Find the subset directVars that only depend on a single PDF in the product
1688 RooArgSet directSafe ;
1689 for (auto const* arg : directVars) {
1690 if (isDirectGenSafe(*arg)) directSafe.add(*arg) ;
1691 }
1692
1693
1694 // Now find direct integrator for relevant components ;
1695 std::vector<Int_t> code;
1696 code.reserve(64);
1697 for (auto const* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1698 RooArgSet pdfDirect ;
1699 Int_t pdfCode = pdf->getGenerator(directSafe,pdfDirect,staticInitOK);
1700 code.push_back(pdfCode);
1701 if (pdfCode != 0) {
1702 generateVars.add(pdfDirect) ;
1703 }
1704 }
1705
1706
1707 if (generateVars.getSize()>0) {
1708 Int_t masterCode = _genCode.store(code) ;
1709 return masterCode+1 ;
1710 } else {
1711 return 0 ;
1712 }
1713}
1714
1715
1716
1717////////////////////////////////////////////////////////////////////////////////
1718/// Forward one-time initialization call to component generation initialization
1719/// methods.
1720
1722{
1723 if (!_useDefaultGen) return ;
1724
1725 const std::vector<Int_t>& codeList = _genCode.retrieve(code-1) ;
1726 Int_t i(0) ;
1727 for (auto* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1728 if (codeList[i]!=0) {
1729 pdf->initGenerator(codeList[i]) ;
1730 }
1731 i++ ;
1732 }
1733}
1734
1735
1736
1737////////////////////////////////////////////////////////////////////////////////
1738/// Generate a single event with configuration specified by 'code'
1739/// Defer internal generation to components as encoded in the _genCode
1740/// registry for given generator code.
1741
1743{
1744 if (!_useDefaultGen) return ;
1745
1746 const std::vector<Int_t>& codeList = _genCode.retrieve(code-1) ;
1747 Int_t i(0) ;
1748 for (auto* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1749 if (codeList[i]!=0) {
1750 pdf->generateEvent(codeList[i]) ;
1751 }
1752 i++ ;
1753 }
1754}
1755
1756
1757
1758////////////////////////////////////////////////////////////////////////////////
1759/// Return RooAbsArg components contained in the cache
1760
1762{
1763 RooArgList ret ;
1764 ret.add(_partList) ;
1765 ret.add(_numList) ;
1766 ret.add(_denList) ;
1767 if (_rearrangedNum) ret.add(*_rearrangedNum) ;
1768 if (_rearrangedDen) ret.add(*_rearrangedDen) ;
1769 return ret ;
1770
1771}
1772
1773
1774
1775////////////////////////////////////////////////////////////////////////////////
1776/// Hook function to print cache contents in tree printing of RooProdPdf
1777
1778void RooProdPdf::CacheElem::printCompactTreeHook(ostream& os, const char* indent, Int_t curElem, Int_t maxElem)
1779{
1780 if (curElem==0) {
1781 os << indent << "RooProdPdf begin partial integral cache" << endl ;
1782 }
1783
1784 auto indent2 = std::string(indent) + "[" + std::to_string(curElem) + "]";
1785 for(auto const& arg : _partList) {
1786 arg->printCompactTree(os,indent2.c_str()) ;
1787 }
1788
1789 if (curElem==maxElem) {
1790 os << indent << "RooProdPdf end partial integral cache" << endl ;
1791 }
1792}
1793
1794
1795
1796////////////////////////////////////////////////////////////////////////////////
1797/// Forward determination of safety of internal generator code to
1798/// component p.d.f that would generate the given observable
1799
1801{
1802 // Only override base class behaviour if default generator method is enabled
1803 if (!_useDefaultGen) return RooAbsPdf::isDirectGenSafe(arg) ;
1804
1805 // Argument may appear in only one PDF component
1806 RooAbsPdf* thePdf(0) ;
1807 for (auto* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
1808
1809 if (pdf->dependsOn(arg)) {
1810 // Found PDF depending on arg
1811
1812 // If multiple PDFs depend on arg directGen is not safe
1813 if (thePdf) return false ;
1814
1815 thePdf = pdf ;
1816 }
1817 }
1818 // Forward call to relevant component PDF
1819 return thePdf?(thePdf->isDirectGenSafe(arg)):false ;
1820}
1821
1822
1823
1824////////////////////////////////////////////////////////////////////////////////
1825/// Look up user specified normalization set for given input PDF component
1826
1828{
1829 Int_t idx = _pdfList.index(&pdf) ;
1830 if (idx<0) return nullptr;
1831 return _pdfNSetList[idx].get() ;
1832}
1833
1834
1835
1836/// Add some full PDFs to the factors of this RooProdPdf.
1838{
1839 size_t numExtended = (_extendedIndex==-1) ? 0 : 1;
1840
1841 for(auto arg : pdfs) {
1842 RooAbsPdf* pdf = dynamic_cast<RooAbsPdf*>(arg);
1843 if (!pdf) {
1844 coutW(InputArguments) << "RooProdPdf::addPdfs(" << GetName() << ") list arg "
1845 << arg->GetName() << " is not a PDF, ignored" << endl ;
1846 continue;
1847 }
1848 if(pdf->canBeExtended()) {
1849 if (_extendedIndex == -1) {
1851 } else {
1852 numExtended++;
1853 }
1854 }
1855 _pdfList.add(*pdf);
1856 _pdfNSetList.emplace_back(std::make_unique<RooArgSet>("nset"));
1857 }
1858
1859 // Protect against multiple extended terms
1860 if (numExtended>1) {
1861 coutW(InputArguments) << "RooProdPdf::addPdfs(" << GetName()
1862 << ") WARNING: multiple components with extended terms detected,"
1863 << " product will not be extendible." << endl ;
1864 _extendedIndex = -1 ;
1865 }
1866
1867 // Reset cache
1868 _cacheMgr.reset() ;
1869
1870}
1871
1872/// Remove some PDFs from the factors of this RooProdPdf.
1874{
1875 // Remember what the extended PDF is
1876 RooAbsArg const* extPdf = _extendedIndex >= 0 ? &_pdfList[_extendedIndex] : nullptr;
1877
1878 // Actually remove the PDFs and associated nsets
1879 for(size_t i=0;i < _pdfList.size(); i++) {
1880 if(pdfs.contains(_pdfList[i])) {
1882 _pdfNSetList.erase(_pdfNSetList.begin()+i);
1883 i--;
1884 }
1885 }
1886
1887 // Since we may have removed PDFs from the list, the index of the extended
1888 // PDF in the list needs to be updated. The new index might also be -1 if the
1889 // extended PDF got removed.
1890 if(extPdf) {
1891 _extendedIndex = _pdfList.index(*extPdf);
1892 }
1893
1894 // Reset cache
1895 _cacheMgr.reset() ;
1896}
1897
1898
1899namespace {
1900
1901std::vector<TNamed const*> sortedNamePtrs(RooAbsCollection const& col)
1902{
1903 std::vector<TNamed const*> ptrs;
1904 ptrs.reserve(col.size());
1905 for(RooAbsArg* arg : col) {
1906 ptrs.push_back(arg->namePtr());
1907 }
1908 std::sort(ptrs.begin(), ptrs.end());
1909 return ptrs;
1910}
1911
1912bool sortedNamePtrsOverlap(std::vector<TNamed const*> const& ptrsA, std::vector<TNamed const*> const& ptrsB)
1913{
1914 auto pA = ptrsA.begin();
1915 auto pB = ptrsB.begin();
1916 while (pA != ptrsA.end() && pB != ptrsB.end()) {
1917 if (*pA < *pB) {
1918 ++pA;
1919 } else if (*pB < *pA) {
1920 ++pB;
1921 } else {
1922 return true;
1923 }
1924 }
1925 return false;
1926}
1927
1928} // namespace
1929
1930
1931////////////////////////////////////////////////////////////////////////////////
1932/// Return all parameter constraint p.d.f.s on parameters listed in constrainedParams.
1933/// The observables set is required to distinguish unambiguously p.d.f in terms
1934/// of observables and parameters, which are not constraints, and p.d.fs in terms
1935/// of parameters only, which can serve as constraints p.d.f.s
1936
1937RooArgSet* RooProdPdf::getConstraints(const RooArgSet& observables, RooArgSet& constrainedParams,
1938 bool stripDisconnected, bool removeConstraintsFromPdf) const
1939{
1940 RooArgSet constraints ;
1941 RooArgSet pdfParams, conParams ;
1942
1943 // For the optimized implementation of checking if two collections overlap by name.
1944 auto observablesNamePtrs = sortedNamePtrs(observables);
1945 auto constrainedParamsNamePtrs = sortedNamePtrs(constrainedParams);
1946
1947 // Loop over PDF components
1948 for (std::size_t iPdf = 0; iPdf < _pdfList.size(); ++iPdf) {
1949 auto * pdf = static_cast<RooAbsPdf*>(&_pdfList[iPdf]);
1950
1951 RooArgSet tmp;
1952 pdf->getParameters(nullptr, tmp);
1953
1954 // A constraint term is a p.d.f that doesn't contribute to the
1955 // expectedEvents() and does not depend on any of the listed observables
1956 // but does depends on any of the parameters that should be constrained
1957 bool isConstraint = false;
1958
1959 if(static_cast<int>(iPdf) != _extendedIndex) {
1960 auto tmpNamePtrs = sortedNamePtrs(tmp);
1961 // Before, there were calls to `pdf->dependsOn()` here, but they were very
1962 // expensive for large computation graphs! Given that we have to traverse
1963 // the computation graph with a call to `pdf->getParameters()` anyway, we
1964 // can just check if the set of all variables operlaps with the observables
1965 // or constraind parameters.
1966 //
1967 // We are using an optimized implementation of overlap checking. Because
1968 // the overlap is checked by name, we can check overlap of the
1969 // corresponding name pointers. The optimization can't be in
1970 // RooAbsCollection itself, because it is crucial that the memory for the
1971 // non-tmp name pointers is not reallocated for each pdf.
1972 isConstraint = !sortedNamePtrsOverlap(tmpNamePtrs, observablesNamePtrs) &&
1973 sortedNamePtrsOverlap(tmpNamePtrs, constrainedParamsNamePtrs);
1974 }
1975 if (isConstraint) {
1976 constraints.add(*pdf) ;
1977 conParams.add(tmp,true) ;
1978 } else {
1979 // We only want to add parameter, not observables. Since a call like
1980 // `pdf->getParameters(&observables)` would be expensive, we take the set
1981 // of all variables and remove the ovservables, which is much cheaper. In
1982 // a call to `pdf->getParameters(&observables)`, the observables are
1983 // matched by name, so we have to pass the `matchByNameOnly` here.
1984 tmp.remove(observables, /*silent=*/false, /*matchByNameOnly=*/true);
1985 pdfParams.add(tmp,true) ;
1986 }
1987 }
1988
1989 // Remove the constraints now from the PDF if the caller requested it
1990 if(removeConstraintsFromPdf) {
1991 const_cast<RooProdPdf*>(this)->removePdfs(constraints);
1992 }
1993
1994 // Strip any constraints that are completely decoupled from the other product terms
1995 RooArgSet* finalConstraints = new RooArgSet("constraints") ;
1996 for(auto * pdf : static_range_cast<RooAbsPdf*>(constraints)) {
1997 if (pdf->dependsOnValue(pdfParams) || !stripDisconnected) {
1998 finalConstraints->add(*pdf) ;
1999 } else {
2000 coutI(Minimization) << "RooProdPdf::getConstraints(" << GetName() << ") omitting term " << pdf->GetName()
2001 << " as constraint term as it does not share any parameters with the other pdfs in product. "
2002 << "To force inclusion in likelihood, add an explicit Constrain() argument for the target parameter" << endl ;
2003 }
2004 }
2005
2006 // Now remove from constrainedParams all parameters that occur exclusively in constraint term and not in regular pdf term
2007
2008 RooArgSet cexl;
2009 conParams.selectCommon(constrainedParams, cexl);
2010 cexl.remove(pdfParams,true,true) ;
2011 constrainedParams.remove(cexl,true,true) ;
2012
2013 return finalConstraints ;
2014}
2015
2016
2017
2018
2019////////////////////////////////////////////////////////////////////////////////
2020/// Return all parameter constraint p.d.f.s on parameters listed in constrainedParams.
2021/// The observables set is required to distinguish unambiguously p.d.f in terms
2022/// of observables and parameters, which are not constraints, and p.d.fs in terms
2023/// of parameters only, which can serve as constraints p.d.f.s
2024
2026{
2027 RooArgSet* connectedPars = new RooArgSet("connectedPars") ;
2028 for (std::size_t iPdf = 0; iPdf < _pdfList.size(); ++iPdf) {
2029 auto * pdf = static_cast<RooAbsPdf*>(&_pdfList[iPdf]);
2030 // Check if term is relevant, either because it provides a probablity
2031 // density in the observables or because it is used for the expected
2032 // events.
2033 if (static_cast<int>(iPdf) == _extendedIndex || pdf->dependsOn(observables)) {
2034 RooArgSet tmp;
2035 pdf->getParameters(&observables, tmp);
2036 connectedPars->add(tmp) ;
2037 }
2038 }
2039 return connectedPars ;
2040}
2041
2042
2043
2044
2045////////////////////////////////////////////////////////////////////////////////
2046
2047void RooProdPdf::getParametersHook(const RooArgSet* nset, RooArgSet* params, bool stripDisconnected) const
2048{
2049 if (!stripDisconnected) return ;
2050 if (!nset || nset->empty()) return ;
2051
2052 // Get/create appropriate term list for this normalization set
2053 Int_t code = getPartIntList(nset, nullptr);
2054 RooArgList & plist = static_cast<CacheElem*>(_cacheMgr.getObj(nset, &code))->_partList;
2055
2056 // Strip any terms from params that do not depend on any term
2057 RooArgSet tostrip ;
2058 for (auto param : *params) {
2059 bool anyDep(false) ;
2060 for (auto term : plist) {
2061 if (term->dependsOnValue(*param)) {
2062 anyDep=true ;
2063 }
2064 }
2065 if (!anyDep) {
2066 tostrip.add(*param) ;
2067 }
2068 }
2069
2070 if (!tostrip.empty()) {
2071 params->remove(tostrip,true,true);
2072 }
2073
2074}
2075
2076
2077
2078////////////////////////////////////////////////////////////////////////////////
2079/// Interface function used by test statistics to freeze choice of range
2080/// for interpretation of conditional product terms
2081
2082void RooProdPdf::selectNormalizationRange(const char* rangeName, bool force)
2083{
2084 if (!force && _refRangeName) {
2085 return ;
2086 }
2087
2088 fixRefRange(rangeName) ;
2089}
2090
2091
2092
2093
2094////////////////////////////////////////////////////////////////////////////////
2095
2096void RooProdPdf::fixRefRange(const char* rangeName)
2097{
2098 _refRangeName = (TNamed*)RooNameReg::ptr(rangeName) ;
2099}
2100
2101
2102
2103////////////////////////////////////////////////////////////////////////////////
2104/// Forward the plot sampling hint from the p.d.f. that defines the observable obs
2105
2106std::list<double>* RooProdPdf::plotSamplingHint(RooAbsRealLValue& obs, double xlo, double xhi) const
2107{
2108 for (auto const* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
2109 if (std::list<double>* hint = pdf->plotSamplingHint(obs,xlo,xhi)) {
2110 return hint ;
2111 }
2112 }
2113
2114 return nullptr;
2115}
2116
2117
2118
2119////////////////////////////////////////////////////////////////////////////////
2120/// If all components that depend on obs are binned that so is the product
2121
2123{
2124 for (auto const* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
2125 if (pdf->dependsOn(obs) && !pdf->isBinnedDistribution(obs)) {
2126 return false ;
2127 }
2128 }
2129
2130 return true ;
2131}
2132
2133
2134
2135
2136
2137
2138////////////////////////////////////////////////////////////////////////////////
2139/// Forward the plot sampling hint from the p.d.f. that defines the observable obs
2140
2141std::list<double>* RooProdPdf::binBoundaries(RooAbsRealLValue& obs, double xlo, double xhi) const
2142{
2143 for (auto const* pdf : static_range_cast<RooAbsPdf*>(_pdfList)) {
2144 if (std::list<double>* hint = pdf->binBoundaries(obs,xlo,xhi)) {
2145 return hint ;
2146 }
2147 }
2148
2149 return nullptr;
2150}
2151
2152
2153////////////////////////////////////////////////////////////////////////////////
2154/// Label OK'ed components of a RooProdPdf with cache-and-track, _and_ label all RooProdPdf
2155/// descendants with extra information about (conditional) normalization, needed to be able
2156/// to Cache-And-Track them outside the RooProdPdf context.
2157
2159{
2160 for (const auto parg : _pdfList) {
2161
2162 if (parg->canNodeBeCached()==Always) {
2163 trackNodes.add(*parg) ;
2164// cout << "tracking node RooProdPdf component " << parg << " " << parg->ClassName() << "::" << parg->GetName() << endl ;
2165
2166 // Additional processing to fix normalization sets in case product defines conditional observables
2167 if (RooArgSet* pdf_nset = findPdfNSet(static_cast<RooAbsPdf&>(*parg))) {
2168 // Check if conditional normalization is specified
2170 if (string("nset")==pdf_nset->GetName() && !pdf_nset->empty()) {
2171 parg->setStringAttribute("CATNormSet",getColonSeparatedNameString(*pdf_nset).c_str()) ;
2172 }
2173 if (string("cset")==pdf_nset->GetName()) {
2174 parg->setStringAttribute("CATCondSet",getColonSeparatedNameString(*pdf_nset).c_str()) ;
2175 }
2176 } else {
2177 coutW(Optimization) << "RooProdPdf::setCacheAndTrackHints(" << GetName() << ") WARNING product pdf does not specify a normalization set for component " << parg->GetName() << endl ;
2178 }
2179 }
2180 }
2181}
2182
2183
2184
2185////////////////////////////////////////////////////////////////////////////////
2186/// Customized printing of arguments of a RooProdPdf to more intuitively reflect the contents of the
2187/// product operator construction
2188
2189void RooProdPdf::printMetaArgs(ostream& os) const
2190{
2191 for (int i=0 ; i<_pdfList.getSize() ; i++) {
2192 if (i>0) os << " * " ;
2193 RooArgSet* ncset = _pdfNSetList[i].get() ;
2194 os << _pdfList.at(i)->GetName() ;
2195 if (ncset->getSize()>0) {
2196 if (string("nset")==ncset->GetName()) {
2197 os << *ncset ;
2198 } else {
2199 os << "|" ;
2200 bool first(true) ;
2201 for (auto const* arg : *ncset) {
2202 if (!first) {
2203 os << "," ;
2204 } else {
2205 first = false ;
2206 }
2207 os << arg->GetName() ;
2208 }
2209 }
2210 }
2211 }
2212 os << " " ;
2213}
2214
2215
2216
2217////////////////////////////////////////////////////////////////////////////////
2218/// Implement support for node removal
2219
2220bool RooProdPdf::redirectServersHook(const RooAbsCollection& newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive)
2221{
2222 if (nameChange && _pdfList.find("REMOVAL_DUMMY")) {
2223
2224 cxcoutD(LinkStateMgmt) << "RooProdPdf::redirectServersHook(" << GetName() << "): removing REMOVAL_DUMMY" << endl ;
2225
2226 // Remove node from _pdfList proxy and remove corresponding entry from normset list
2227 RooAbsArg* pdfDel = _pdfList.find("REMOVAL_DUMMY") ;
2228
2229 _pdfNSetList.erase(_pdfNSetList.begin() + _pdfList.index("REMOVAL_DUMMY")) ;
2230 _pdfList.remove(*pdfDel) ;
2231
2232 // Clear caches
2233 _cacheMgr.reset() ;
2234 }
2235
2236 // If the replaced server is an observable that is used in any of the
2237 // normalization sets for conditional fits, replace the element in the
2238 // normalization set too.
2239 for(std::unique_ptr<RooArgSet> const& normSet : _pdfNSetList) {
2240 for(RooAbsArg * arg : *normSet) {
2241 if(RooAbsArg * newArg = arg->findNewServer(newServerList, nameChange)) {
2242 // Need to do some tricks here because it's not possible to replace in
2243 // an owning RooAbsCollection.
2244 normSet->releaseOwnership();
2245 normSet->replace(*std::unique_ptr<RooAbsArg>{arg}, *newArg->cloneTree());
2246 normSet->takeOwnership();
2247 }
2248 }
2249 }
2250
2251 return RooAbsPdf::redirectServersHook(newServerList, mustReplaceAll, nameChange, isRecursive);
2252}
2253
2254void RooProdPdf::CacheElem::writeToStream(std::ostream& os) const {
2255 using namespace RooHelpers;
2256 os << "_partList\n";
2257 os << getColonSeparatedNameString(_partList) << "\n";
2258 os << "_numList\n";
2259 os << getColonSeparatedNameString(_numList) << "\n";
2260 os << "_denList\n";
2261 os << getColonSeparatedNameString(_denList) << "\n";
2262 os << "_ownedList\n";
2263 os << getColonSeparatedNameString(_ownedList) << "\n";
2264 os << "_normList\n";
2265 for(auto const& set : _normList) {
2266 os << getColonSeparatedNameString(*set) << "\n";
2267 }
2268 os << "_isRearranged" << "\n";
2269 os << _isRearranged << "\n";
2270 os << "_rearrangedNum" << "\n";
2271 if(_rearrangedNum) {
2272 os << getColonSeparatedNameString(*_rearrangedNum) << "\n";
2273 } else {
2274 os << "nullptr" << "\n";
2275 }
2276 os << "_rearrangedDen" << "\n";
2277 if(_rearrangedDen) {
2278 os << getColonSeparatedNameString(*_rearrangedDen) << "\n";
2279 } else {
2280 os << "nullptr" << "\n";
2281 }
2282}
2283
2284std::unique_ptr<RooArgSet> RooProdPdf::fillNormSetForServer(RooArgSet const &normSet, RooAbsArg const &server) const
2285{
2286 if (normSet.empty())
2287 return nullptr;
2288 auto *pdfNset = findPdfNSet(static_cast<RooAbsPdf const &>(server));
2289 if (pdfNset && !pdfNset->empty()) {
2290 std::unique_ptr<RooArgSet> out;
2291 if (0 == strcmp("cset", pdfNset->GetName())) {
2292 // If the name of the normalization set is "cset", it doesn't contain the
2293 // normalization set but the conditional observables that should *not* be
2294 // normalized over.
2295 out = std::make_unique<RooArgSet>(normSet);
2296 RooArgSet common;
2297 out->selectCommon(*pdfNset, common);
2298 out->remove(common);
2299 } else {
2300 out = std::make_unique<RooArgSet>(*pdfNset);
2301 }
2302 // prefix also the arguments in the normSets if they have not already been
2303 if (auto prefix = getStringAttribute("__prefix__")) {
2304 for (RooAbsArg *arg : *out) {
2305 if (!arg->getStringAttribute("__prefix__")) {
2306 arg->SetName((std::string(prefix) + arg->GetName()).c_str());
2307 arg->setStringAttribute("__prefix__", prefix);
2308 }
2309 }
2310 }
2311 return out;
2312 } else {
2313 return nullptr;
2314 }
2315}
2316
2317/// A RooProdPdf with a fixed normalization set can be replaced by this class.
2318/// Its purpose is to provide the right client-server interface for the
2319/// evaluation of RooProdPdf cache elements that were created for a given
2320/// normalization set.
2322public:
2323 RooFixedProdPdf(std::unique_ptr<RooProdPdf> &&prodPdf, RooArgSet const &normSet)
2324 : RooAbsPdf(prodPdf->GetName(), prodPdf->GetTitle()), _normSet{normSet},
2325 _servers("!servers", "List of servers", this), _prodPdf{std::move(prodPdf)}
2326 {
2327 initialize();
2328 }
2329 RooFixedProdPdf(const RooFixedProdPdf &other, const char *name = nullptr)
2330 : RooAbsPdf(other, name), _normSet{other._normSet},
2331 _servers("!servers", "List of servers", this), _prodPdf{static_cast<RooProdPdf *>(other._prodPdf->Clone())}
2332 {
2333 initialize();
2334 }
2335 TObject *clone(const char *newname) const override { return new RooFixedProdPdf(*this, newname); }
2336
2337 bool selfNormalized() const override { return true; }
2338
2339 inline bool canComputeBatchWithCuda() const override { return true; }
2340
2341 void computeBatch(cudaStream_t *stream, double *output, size_t nEvents,
2342 RooFit::Detail::DataMap const &dataMap) const override
2343 {
2344 _prodPdf->calculateBatch(*_cache, stream, output, nEvents, dataMap);
2345 }
2346
2347 ExtendMode extendMode() const override { return _prodPdf->extendMode(); }
2348 double expectedEvents(const RooArgSet * /*nset*/) const override { return _prodPdf->expectedEvents(&_normSet); }
2349 std::unique_ptr<RooAbsReal> createExpectedEventsFunc(const RooArgSet * /*nset*/) const override
2350 {
2351 return _prodPdf->createExpectedEventsFunc(&_normSet);
2352 }
2353
2354 // Analytical Integration handling
2355 bool forceAnalyticalInt(const RooAbsArg &dep) const override { return _prodPdf->forceAnalyticalInt(dep); }
2356 Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &analVars, const RooArgSet *normSet,
2357 const char *rangeName = nullptr) const override
2358 {
2359 return _prodPdf->getAnalyticalIntegralWN(allVars, analVars, normSet, rangeName);
2360 }
2361 Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &numVars, const char *rangeName = nullptr) const override
2362 {
2363 return _prodPdf->getAnalyticalIntegral(allVars, numVars, rangeName);
2364 }
2365 double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName) const override
2366 {
2367 return _prodPdf->analyticalIntegralWN(code, normSet, rangeName);
2368 }
2369 double analyticalIntegral(Int_t code, const char *rangeName = nullptr) const override
2370 {
2371 return _prodPdf->analyticalIntegral(code, rangeName);
2372 }
2373
2374private:
2376 {
2377 _cache = _prodPdf->createCacheElem(&_normSet, nullptr);
2378 auto &cache = *_cache;
2379
2380 // The actual servers for a given normalization set depend on whether the
2381 // cache is rearranged or not. See RooProdPdf::calculateBatch to see
2382 // which args in the cache are used directly.
2383 if (cache._isRearranged) {
2384 _servers.add(*cache._rearrangedNum);
2385 _servers.add(*cache._rearrangedDen);
2386 } else {
2387 for (std::size_t i = 0; i < cache._partList.size(); ++i) {
2388 _servers.add(cache._partList[i]);
2389 }
2390 }
2391 }
2392
2393 double evaluate() const override { return _prodPdf->calculate(*_cache); }
2394
2396 std::unique_ptr<RooProdPdf::CacheElem> _cache;
2398 std::unique_ptr<RooProdPdf> _prodPdf;
2399};
2400
2401std::unique_ptr<RooAbsArg>
2403{
2404 if (ctx.likelihoodMode()) {
2405 auto binnedInfo = RooHelpers::getBinnedL(*this);
2406 if (binnedInfo.binnedPdf && binnedInfo.binnedPdf != this) {
2407 return binnedInfo.binnedPdf->compileForNormSet(normSet, ctx);
2408 }
2409 }
2410
2411 std::unique_ptr<RooProdPdf> prodPdfClone{static_cast<RooProdPdf *>(this->Clone())};
2412 ctx.markAsCompiled(*prodPdfClone);
2413
2414 for (const auto server : prodPdfClone->servers()) {
2415 auto nsetForServer = fillNormSetForServer(normSet, *server);
2416 RooArgSet const &nset = nsetForServer ? *nsetForServer : normSet;
2417
2418 RooArgSet depList;
2419 server->getObservables(&nset, depList);
2420
2421 ctx.compileServer(*server, *prodPdfClone, depList);
2422 }
2423
2424 auto fixedProdPdf = std::make_unique<RooFixedProdPdf>(std::move(prodPdfClone), normSet);
2425 ctx.markAsCompiled(*fixedProdPdf);
2426
2427 return fixedProdPdf;
2428}
RooFitResult * save(const char *name=nullptr, const char *title=nullptr)
#define coutI(a)
#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
#define ClassImp(name)
Definition Rtypes.h:377
static void indent(ostringstream &buf, int indent_level)
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:110
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2467
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...
RooAbsArg is the common abstract base class for objects that represent a value and a "shape" in RooFi...
Definition RooAbsArg.h:74
RooExpensiveObjectCache & expensiveObjectCache() const
bool dependsOn(const RooAbsCollection &serverList, const RooAbsArg *ignoreArg=nullptr, bool valueOnly=false) const
Test whether we depend on (ie, are served by) any object in the specified collection.
void setOperMode(OperMode mode, bool recurseADirty=true)
Set the operation mode of this node.
void setStringAttribute(const Text_t *key, const Text_t *value)
Associate string 'value' to this object under key 'key'.
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...
virtual void setExpensiveObjectCache(RooExpensiveObjectCache &cache)
Definition RooAbsArg.h:500
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:628
RooFit::OwningPtr< RooArgSet > getComponents() const
Create a RooArgSet with all components (branch nodes) of the expression tree headed by this object.
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:86
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...
RooAbsArg * findNewServer(const RooAbsCollection &newSet, bool nameChange) const
Find the new server in the specified set that matches the old server.
OperMode operMode() const
Query the operation mode of this node.
Definition RooAbsArg.h:481
RooAbsCollection is an abstract container object that can hold multiple RooAbsArg objects.
virtual void removeAll()
Remove all arguments from our set, deleting them if we own them.
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
Storage_t const & get() const
Const access to the underlying stl container.
bool contains(const RooAbsArg &var) const
Check if collection contains an argument with the same name as var.
void printValue(std::ostream &os) const override
Print value of collection, i.e.
Int_t getSize() const
Return the number of elements in the collection.
const char * GetName() const override
Returns name of object.
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 * first() const
void clear()
Clear contents. If the collection is owning, it will also delete the contents.
bool selectCommon(const RooAbsCollection &refColl, RooAbsCollection &outColl) const
Create a subset of the current collection, consisting only of those elements that are contained as we...
RooAbsArg * find(const char *name) const
Find object with given name in list.
RooAbsGenContext is the abstract base class for generator contexts of RooAbsPdf objects.
TString _normRange
Normalization range.
Definition RooAbsPdf.h:400
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 integral (owned by _normMgr)
Definition RooAbsPdf.h:377
bool canBeExtended() const
If true, PDF can provide extended likelihood term.
Definition RooAbsPdf.h:278
@ CanNotBeExtended
Definition RooAbsPdf.h:272
const char * normRange() const
Definition RooAbsPdf.h:310
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursiveStep) override
The cache manager.
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.
RooAbsRealLValue is the common abstract base class for objects that represent a real value that may a...
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition RooAbsReal.h:62
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:91
RooFit::OwningPtr< RooAbsReal > createIntegral(const RooArgSet &iset, const RooCmdArg &arg1, const RooCmdArg &arg2=RooCmdArg::none(), const RooCmdArg &arg3=RooCmdArg::none(), const RooCmdArg &arg4=RooCmdArg::none(), const RooCmdArg &arg5=RooCmdArg::none(), const RooCmdArg &arg6=RooCmdArg::none(), const RooCmdArg &arg7=RooCmdArg::none(), const RooCmdArg &arg8=RooCmdArg::none()) const
Create an object that represents the integral of the function over one or more observables std::liste...
bool _forceNumInt
Force numerical integration if flag set.
Definition RooAbsReal.h:512
TString integralNameSuffix(const RooArgSet &iset, const RooArgSet *nset=nullptr, const char *rangeName=nullptr, bool omitEmpty=false) const
Construct std::string with unique suffix name to give to integral object that encodes integrated obse...
RooAddition calculates the sum of a set of RooAbsReal terms, or when constructed with two sets,...
Definition RooAddition.h:27
const RooArgList & list1() const
Definition RooAddition.h:49
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:55
RooArgSet * snapshot(bool deepCopy=true) const
Use RooAbsCollection::snapshot(), but return as RooArgSet.
Definition RooArgSet.h:178
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 contatining the objects that are both in the cached set 1.
T * getObjByIndex(Int_t index) const
Retrieve payload object by slot index.
RooArgSet selectFromSet2(RooArgSet const &argSet, int index) const
Create RooArgSet contatining the objects that are both in the cached set 2.
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.
RooCmdArg is a named container for two doubles, two integers two object points and three string point...
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) const override
Definition RooConstVar.h:32
RooCustomizer is a factory class to produce clones of a prototype composite PDF object with the same ...
void replaceArg(const RooAbsArg &orig, const RooAbsArg &subst)
Replace any occurence of arg 'orig' with arg 'subst'.
RooAbsArg * build(const char *masterCatState, bool verbose=false)
Build a clone of the prototype executing all registered 'replace' rules and 'split' rules for the mas...
RooDataSet is a container class to hold unbinned data.
Definition RooDataSet.h:57
void markAsCompiled(RooAbsArg &arg) const
void compileServer(RooAbsArg &server, RooAbsArg &arg, RooArgSet const &normSet)
RooSpan< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
Definition DataMap.cxx:21
A RooProdPdf with a fixed normalization set can be replaced by this class.
std::unique_ptr< RooProdPdf::CacheElem > _cache
void computeBatch(cudaStream_t *stream, double *output, size_t nEvents, RooFit::Detail::DataMap const &dataMap) const override
Base function for computing multiple values of a RooAbsReal.
RooSetProxy _servers
RooFixedProdPdf(const RooFixedProdPdf &other, const char *name=nullptr)
RooFixedProdPdf(std::unique_ptr< RooProdPdf > &&prodPdf, RooArgSet const &normSet)
double analyticalIntegral(Int_t code, const char *rangeName=nullptr) const override
Implements the actual analytical integral(s) advertised by getAnalyticalIntegral.
bool selfNormalized() const override
Shows if a PDF is self-normalized, which means that no attempt is made to add a normalization term.
Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &numVars, const char *rangeName=nullptr) const override
Interface function getAnalyticalIntergral advertises the analytical integrals that are supported.
Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &analVars, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Variant of getAnalyticalIntegral that is also passed the normalization set that should be applied to ...
std::unique_ptr< RooAbsReal > createExpectedEventsFunc(const RooArgSet *) const override
Returns an object that represents the expected number of events for a given normalization set,...
TObject * clone(const char *newname) const override
double evaluate() const override
Evaluate this PDF / function / constant. Needs to be overridden by all derived classes.
std::unique_ptr< RooProdPdf > _prodPdf
double expectedEvents(const RooArgSet *) const override
Return expected number of events to be used in calculation of extended likelihood.
bool canComputeBatchWithCuda() const override
bool forceAnalyticalInt(const RooAbsArg &dep) const override
double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName) const override
Analytical integral with normalization (see RooAbsReal::analyticalIntegralWN() for further informatio...
ExtendMode extendMode() const override
Returns ability of PDF to provide extended likelihood terms.
A RooFormulaVar is a generic implementation of a real-valued object, which takes a RooArgList of serv...
RooAbsArg * getParameter(const char *name) const
Return pointer to parameter with given name.
RooGenProdProj is an auxiliary class for RooProdPdf that calculates a general normalised projection o...
RooLinkedList is an collection class for internal use, storing a collection of RooAbsArg pointers in ...
TObject * At(int index) const
Return object stored in sequential position given by index.
RooLinkedListIterImpl end() const
void Delete(Option_t *o=nullptr) override
Remove all elements in collection and delete all elements NB: Collection does not own elements,...
virtual void Add(TObject *arg)
RooLinkedListIterImpl begin() const
Int_t IndexOf(const char *name) const
Return position of given object in list.
static const char * str(const TNamed *ptr)
Return C++ string corresponding to given TNamed pointer.
Definition RooNameReg.h:37
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:147
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:145
std::unique_ptr< RooAbsReal > _rearrangedDen
Definition RooProdPdf.h:148
void writeToStream(std::ostream &os) const
RooProdPdf is an efficient implementation of a product of PDFs of the form.
Definition RooProdPdf.h:33
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
void factorizeProduct(const RooArgSet &normSet, const RooArgSet &intSet, RooLinkedList &termList, RooLinkedList &normList, RooLinkedList &impDepList, RooLinkedList &crossDepList, RooLinkedList &intList) const
Factorize product in irreducible terms for given choice of integration/normalization.
double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Return analytical integral defined by given scenario code.
RooArgSet * getConstraints(const RooArgSet &observables, RooArgSet &constrainedParams, bool stripDisconnected, bool removeConstraintsFromPdf=false) const override
Return all parameter constraint p.d.f.s on parameters listed in constrainedParams.
~RooProdPdf() override
Destructor.
Int_t _extendedIndex
Index of extended PDF (if any)
Definition RooProdPdf.h:178
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:181
std::vector< std::unique_ptr< RooArgSet > > _pdfNSetList
List of PDF component normalization sets.
Definition RooProdPdf.h:177
std::unique_ptr< RooArgSet > fillNormSetForServer(RooArgSet const &normSet, RooAbsArg const &server) const
std::unique_ptr< RooAbsReal > specializeIntegral(RooAbsReal &orig, const char *targetRangeName) const
bool forceAnalyticalInt(const RooAbsArg &dep) const override
Force RooRealIntegral to offer all observables for internal integration.
void calculateBatch(const RooProdPdf::CacheElem &cache, cudaStream_t *, double *output, size_t nEvents, RooFit::Detail::DataMap const &) const
Evaluate product of PDFs in batch mode.
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
void getParametersHook(const RooArgSet *, RooArgSet *, bool stripDisconnected) 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:183
RooAICRegistry _genCode
! Registry of composite direct generator codes
Definition RooProdPdf.h:173
void addPdfs(RooAbsCollection const &pdfs)
Add some full PDFs to the factors of this RooProdPdf.
RooListProxy _pdfList
List of PDF components.
Definition RooProdPdf.h:176
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
Definition RooProdPdf.h:157
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...
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.
std::vector< RooAbsReal * > processProductTerm(const RooArgSet *nset, const RooArgSet *iset, const char *isetRangeName, const RooArgSet *term, const RooArgSet &termNSet, const RooArgSet &termISet, bool &isOwned, bool forceWrap=false) const
Calculate integrals of factorized product terms over observables iset while normalized to observables...
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.
friend class RooFixedProdPdf
Definition RooProdPdf.h:168
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:167
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:186
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
The cache manager.
bool redirectServersHook(const RooAbsCollection &, bool, bool, bool) override
Implement support for node removal.
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 groupProductTerms(std::list< std::vector< RooArgSet * > > &groupedTerms, RooArgSet &outerIntDeps, const RooLinkedList &terms, const RooLinkedList &norms, const RooLinkedList &imps, const RooLinkedList &ints, const RooLinkedList &cross) const
Group product into terms that can be calculated independently.
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:175
A RooProduct represents the product of a given set of RooAbsReal objects.
Definition RooProduct.h:29
static TClass * Class()
RooArgList components()
Definition RooProduct.h:48
RooRealIntegral performs hybrid numerical/analytical integrals of RooAbsReal objects.
RooArgSet intVars() const
const RooAbsReal & integrand() const
static TClass * Class()
const char * intRange() const
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:47
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
Mother of all ROOT objects.
Definition TObject.h:41
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:525
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:421
const char * Data() const
Definition TString.h:380
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:636
RooConstVar & RooConst(double val)
Double_t x[n]
Definition legend1.C:17
std::vector< RooSpan< const double > > VarVector
R__EXTERN RooBatchComputeInterface * dispatchCUDA
R__EXTERN RooBatchComputeInterface * dispatchCPU
This dispatch pointer points to an implementation of the compute library, provided one has been loade...
std::vector< double > ArgVector
BinnedLOutput getBinnedL(RooAbsPdf const &pdf)
std::string getColonSeparatedNameString(RooArgSet const &argSet)
Create a string with all sorted names of RooArgSet elements separated by colons.
Definition first.py:1
TLine l
Definition textangle.C:4
static void output()