Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooGenProdProj.cxx
Go to the documentation of this file.
1/// \cond ROOFIT_INTERNAL
2
3/*****************************************************************************
4 * Project: RooFit *
5 * Package: RooFitCore *
6 * @(#)root/roofitcore:$Id$
7 * Authors: *
8 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
9 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
10 * *
11 * Copyright (c) 2000-2005, Regents of the University of California *
12 * and Stanford University. All rights reserved. *
13 * *
14 * Redistribution and use in source and binary forms, *
15 * with or without modification, are permitted according to the terms *
16 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
17 *****************************************************************************/
18
19/**
20\file RooGenProdProj.cxx
21\class RooGenProdProj
22\ingroup Roofitcore
23
24
25RooGenProdProj is an auxiliary class for RooProdPdf that calculates
26a general normalised projection of a product of non-factorising PDFs, e.g.
27\f[
28 P_{x,xy} = \frac{\int ( P1 * P2 * \ldots) \mathrm{d}x}{\int ( P1 * P2 * \ldots ) \mathrm{d}x \mathrm{d}y}
29\f]
30
31Partial integrals, which factorise and can be calculated, are calculated
32analytically. Remaining non-factorising observables are integrated numerically.
33**/
34
35#include "RooGenProdProj.h"
36#include "RooAbsReal.h"
37#include "RooAbsPdf.h"
38#include "RooProduct.h"
39
40////////////////////////////////////////////////////////////////////////////////
41/// Constructor for a normalization projection of the product of p.d.f.s _prodSet
42/// integrated over _intSet in range isetRangeName while normalized over _normSet
43
44RooGenProdProj::RooGenProdProj(const char *name, const char *title, const RooArgSet& _prodSet, const RooArgSet& _intSet,
45 const RooArgSet& _normSet, const char* isetRangeName, const char* normRangeName, bool doFactorize) :
46 RooAbsReal(name, title),
47 _compSetN("compSetN","Set of integral components owned by numerator",this,false),
48 _compSetD("compSetD","Set of integral components owned by denominator",this,false),
49 _intList("intList","List of integrals",this,true)
50{
51 // Set expensive object cache to that of first item in prodSet
52 setExpensiveObjectCache(_prodSet.first()->expensiveObjectCache()) ;
53
54 // Create owners of components created in constructor
55 _compSetOwnedN = std::make_unique<RooArgSet>();
56 _compSetOwnedD = std::make_unique<RooArgSet>();
57
59 RooAbsReal* denominator = makeIntegral("denominator",_prodSet,_normSet,*_compSetOwnedD,normRangeName,doFactorize) ;
60
61// std::cout << "RooGenProdPdf::ctor(" << GetName() << ") numerator = " << numerator->GetName() << std::endl ;
62// numerator->printComponentTree() ;
63// std::cout << "RooGenProdPdf::ctor(" << GetName() << ") denominator = " << denominator->GetName() << std::endl ;
64// denominator->printComponentTree() ;
65
66 // Copy all components in (non-owning) set proxy
69
70 _intList.add(*numerator) ;
71 if (denominator) {
72 _intList.add(*denominator) ;
73 _haveD = true ;
74 }
75}
76
77
78
79////////////////////////////////////////////////////////////////////////////////
80/// Copy constructor
81
82RooGenProdProj::RooGenProdProj(const RooGenProdProj &other, const char *name)
84 _compSetN("compSetN", "Set of integral components owned by numerator", this),
85 _compSetD("compSetD", "Set of integral components owned by denominator", this),
86 _intList("intList", "List of integrals", this),
88{
89 // Copy constructor
90 _compSetOwnedN = std::make_unique<RooArgSet>();
91 other._compSetN.snapshot(*_compSetOwnedN);
93
94 _compSetOwnedD = std::make_unique<RooArgSet>();
95 other._compSetD.snapshot(*_compSetOwnedD);
97
98 for (RooAbsArg * arg : *_compSetOwnedN) {
99 arg->setOperMode(_operMode) ;
100 }
101 for (RooAbsArg * arg : *_compSetOwnedD) {
102 arg->setOperMode(_operMode) ;
103 }
104
105 // Fill _intList
106
107 _intList.add(*_compSetN.find(other._intList.at(0)->GetName())) ;
108 if (other._haveD) {
109 _intList.add(*_compSetD.find(other._intList.at(1)->GetName())) ;
110 }
111}
112
113
114////////////////////////////////////////////////////////////////////////////////
115/// Utility function to create integral for product over certain observables.
116/// \param[in] name Name of integral to be created.
117/// \param[in] compSet All components of the product.
118/// \param[in] intSet Observables to be integrated.
119/// \param[out] saveSet All component objects needed to represent the product integral are added as owned members to saveSet.
120/// \note The set owns new components that are created for the integral.
121/// \param[in] isetRangeName Integral range.
122/// \param[in] doFactorize
123///
124/// \return A RooAbsReal object representing the requested integral. The object is owned by `saveSet`.
125///
126/// The integration is factorized into components as much as possible and done analytically as far as possible.
127RooAbsReal* RooGenProdProj::makeIntegral(const char* name, const RooArgSet& compSet, const RooArgSet& intSet,
128 RooArgSet& saveSet, const char* isetRangeName, bool doFactorize)
129{
132
133 // First determine subset of observables in intSet that are factorizable
134 for (const auto arg : intSet) {
135 auto count = std::count_if(compSet.begin(), compSet.end(), [arg](const RooAbsArg* pdfAsArg){
136 auto pdf = static_cast<const RooAbsPdf*>(pdfAsArg);
137 return (pdf->dependsOn(*arg));
138 });
139
140 if (count==1) {
141 anaIntSet.add(*arg) ;
142 }
143 }
144
145 // Determine which of the factorizable integrals can be done analytically
147 numIntSet.add(intSet) ;
148
149 // The idea of the RooGenProdProj is that we divide two integral objects each
150 // created with this makeIntegral() function to get the normalized integral of
151 // a product. Therefore, we don't need to normalize the numerater and
152 // denominator integrals themselves. Doing the normalization would be
153 // expensive and it would cancel out anyway. However, if we don't specify an
154 // explicit normalization integral in createIntegral(), the last-used
155 // normalization set might be used to normalize the pdf, resulting in
156 // redundant computations.
157 //
158 // For this reason, the normalization set of the integrated pdfs is fixed to
159 // an empty set in this case. Note that in RooFit, a nullptr normalization
160 // set and an empty normalization set is not equivalent. The former implies
161 // taking the last-used normalization set, and the latter means explicitly no
162 // normalization.
164
166
167 for (const auto pdfAsArg : compSet) {
168 auto pdf = static_cast<const RooAbsPdf*>(pdfAsArg);
169
170 if (doFactorize && pdf->dependsOn(anaIntSet)) {
172 Int_t code = pdf->getAnalyticalIntegralWN(anaIntSet,anaSet,nullptr,isetRangeName) ;
173 if (code!=0) {
174 // Analytical integral, create integral object
175 std::unique_ptr<RooAbsReal> pai{pdf->createIntegral(anaSet,emptyNormSet,isetRangeName)};
176 pai->setOperMode(_operMode) ;
177
178 // Add to integral to product
179 prodSet.add(*pai) ;
180
181 // Remove analytically integratable observables from numeric integration list
182 numIntSet.remove(anaSet) ;
183
184 // Keep integral alive until the prodSet is cloned later
185 keepAlive.addOwned(std::move(pai));
186 } else {
187 // Analytic integration of factorizable observable not possible, add straight pdf to product
188 prodSet.add(*pdf) ;
189 }
190 } else {
191 // Non-factorizable observables, add straight pdf to product
192 prodSet.add(*pdf) ;
193 }
194 }
195
196 // Create product of (partial) analytical integrals
198 if (isetRangeName) {
199 prodName = Form("%s_%s_Range[%s]",GetName(),name,isetRangeName) ;
200 } else {
201 prodName = Form("%s_%s",GetName(),name) ;
202 }
203
204 // Create clones of the elements in prodSet. These need to be cloned
205 // because when caching optimisation lvl 2 is activated, pre-computed
206 // values are side-loaded into the elements.
207 // Those pre-cached values already contain normalisation constants, so
208 // the integral comes out wrongly. Therefore, we create here nodes that
209 // don't participate in any caching, which are used to compute integrals.
211 prodSet.snapshot(prodSetClone, false);
212
213 auto prod = std::make_unique<RooProduct>(prodName, "product", prodSetClone);
214 prod->setExpensiveObjectCache(expensiveObjectCache()) ;
215 prod->setOperMode(_operMode) ;
216
217 // Create integral performing remaining numeric integration over (partial) analytic product
218 std::unique_ptr<RooAbsReal> integral{prod->createIntegral(numIntSet,emptyNormSet,isetRangeName)};
219 integral->setOperMode(_operMode) ;
220 auto ret = integral.get();
221
222 // Declare ownership of prodSet, product, and integral
223 saveSet.addOwned(std::move(prodSetClone));
224 saveSet.addOwned(std::move(prod));
225 saveSet.addOwned(std::move(integral)) ;
226
227
228 // Caller owners returned master integral object
229 return ret ;
230}
231
232
233
234////////////////////////////////////////////////////////////////////////////////
235/// Calculate and return value of normalization projection
236
237double RooGenProdProj::evaluate() const
238{
239 RooArgSet const* nset = _intList.nset();
240
241 double nom = static_cast<RooAbsReal*>(_intList.at(0))->getVal(nset);
242
243 if (!_haveD) return nom ;
244
245 double den = static_cast<RooAbsReal*>(_intList.at(1))->getVal(nset);
246
247 //cout << "RooGenProdProj::eval(" << GetName() << ") nom = " << nom << " den = " << den << std::endl ;
248
249 return nom / den ;
250}
251
252
253
254////////////////////////////////////////////////////////////////////////////////
255/// Intercept cache mode operation changes and propagate them to the components
256
257void RooGenProdProj::operModeHook()
258{
259 // WVE use cache manager here!
260
261 for(RooAbsArg * arg : *_compSetOwnedN) {
262 arg->setOperMode(_operMode) ;
263 }
264
265 for(RooAbsArg * arg : *_compSetOwnedD) {
266 arg->setOperMode(_operMode) ;
267 }
268
269 _intList.at(0)->setOperMode(_operMode) ;
270 if (_haveD) _intList.at(1)->setOperMode(Auto) ; // Denominator always stays in Auto mode (normalization integral)
271}
272
273/// \endcond
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
char name[80]
Definition TGX11.cxx:142
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2571
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Basic string class.
Definition TString.h:137