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
36#include "Riostream.h"
37#include <cmath>
38
39#include "RooGenProdProj.h"
40#include "RooAbsReal.h"
41#include "RooAbsPdf.h"
42#include "RooErrorHandler.h"
43#include "RooProduct.h"
44
45
46////////////////////////////////////////////////////////////////////////////////
47/// Constructor for a normalization projection of the product of p.d.f.s _prodSet
48/// integrated over _intSet in range isetRangeName while normalized over _normSet
49
50RooGenProdProj::RooGenProdProj(const char *name, const char *title, const RooArgSet& _prodSet, const RooArgSet& _intSet,
51 const RooArgSet& _normSet, const char* isetRangeName, const char* normRangeName, bool doFactorize) :
52 RooAbsReal(name, title),
53 _compSetN("compSetN","Set of integral components owned by numerator",this,false),
54 _compSetD("compSetD","Set of integral components owned by denominator",this,false),
55 _intList("intList","List of integrals",this,true)
56{
57 // Set expensive object cache to that of first item in prodSet
58 setExpensiveObjectCache(_prodSet.first()->expensiveObjectCache()) ;
59
60 // Create owners of components created in constructor
61 _compSetOwnedN = std::make_unique<RooArgSet>();
62 _compSetOwnedD = std::make_unique<RooArgSet>();
63
65 RooAbsReal* denominator = makeIntegral("denominator",_prodSet,_normSet,*_compSetOwnedD,normRangeName,doFactorize) ;
66
67// std::cout << "RooGenProdPdf::ctor(" << GetName() << ") numerator = " << numerator->GetName() << std::endl ;
68// numerator->printComponentTree() ;
69// std::cout << "RooGenProdPdf::ctor(" << GetName() << ") denominator = " << denominator->GetName() << std::endl ;
70// denominator->printComponentTree() ;
71
72 // Copy all components in (non-owning) set proxy
75
76 _intList.add(*numerator) ;
77 if (denominator) {
78 _intList.add(*denominator) ;
79 _haveD = true ;
80 }
81}
82
83
84
85////////////////////////////////////////////////////////////////////////////////
86/// Copy constructor
87
88RooGenProdProj::RooGenProdProj(const RooGenProdProj &other, const char *name)
90 _compSetN("compSetN", "Set of integral components owned by numerator", this),
91 _compSetD("compSetD", "Set of integral components owned by denominator", this),
92 _intList("intList", "List of integrals", this),
94{
95 // Copy constructor
96 _compSetOwnedN = std::make_unique<RooArgSet>();
97 other._compSetN.snapshot(*_compSetOwnedN);
99
100 _compSetOwnedD = std::make_unique<RooArgSet>();
101 other._compSetD.snapshot(*_compSetOwnedD);
103
104 for (RooAbsArg * arg : *_compSetOwnedN) {
105 arg->setOperMode(_operMode) ;
106 }
107 for (RooAbsArg * arg : *_compSetOwnedD) {
108 arg->setOperMode(_operMode) ;
109 }
110
111 // Fill _intList
112
113 _intList.add(*_compSetN.find(other._intList.at(0)->GetName())) ;
114 if (other._haveD) {
115 _intList.add(*_compSetD.find(other._intList.at(1)->GetName())) ;
116 }
117}
118
119
120////////////////////////////////////////////////////////////////////////////////
121/// Utility function to create integral for product over certain observables.
122/// \param[in] name Name of integral to be created.
123/// \param[in] compSet All components of the product.
124/// \param[in] intSet Observables to be integrated.
125/// \param[out] saveSet All component objects needed to represent the product integral are added as owned members to saveSet.
126/// \note The set owns new components that are created for the integral.
127/// \param[in] isetRangeName Integral range.
128/// \param[in] doFactorize
129///
130/// \return A RooAbsReal object representing the requested integral. The object is owned by `saveSet`.
131///
132/// The integration is factorized into components as much as possible and done analytically as far as possible.
133RooAbsReal* RooGenProdProj::makeIntegral(const char* name, const RooArgSet& compSet, const RooArgSet& intSet,
134 RooArgSet& saveSet, const char* isetRangeName, bool doFactorize)
135{
138
139 // First determine subset of observables in intSet that are factorizable
140 for (const auto arg : intSet) {
141 auto count = std::count_if(compSet.begin(), compSet.end(), [arg](const RooAbsArg* pdfAsArg){
142 auto pdf = static_cast<const RooAbsPdf*>(pdfAsArg);
143 return (pdf->dependsOn(*arg));
144 });
145
146 if (count==1) {
147 anaIntSet.add(*arg) ;
148 }
149 }
150
151 // Determine which of the factorizable integrals can be done analytically
153 numIntSet.add(intSet) ;
154
155 // The idea of the RooGenProdProj is that we divide two integral objects each
156 // created with this makeIntegral() function to get the normalized integral of
157 // a product. Therefore, we don't need to normalize the numerater and
158 // denominator integrals themselves. Doing the normalization would be
159 // expensive and it would cancel out anyway. However, if we don't specify an
160 // explicit normalization integral in createIntegral(), the last-used
161 // normalization set might be used to normalize the pdf, resulting in
162 // redundant computations.
163 //
164 // For this reason, the normalization set of the integrated pdfs is fixed to
165 // an empty set in this case. Note that in RooFit, a nullptr normalization
166 // set and an empty normalization set is not equivalent. The former implies
167 // taking the last-used normalization set, and the latter means explicitly no
168 // normalization.
170
172
173 for (const auto pdfAsArg : compSet) {
174 auto pdf = static_cast<const RooAbsPdf*>(pdfAsArg);
175
176 if (doFactorize && pdf->dependsOn(anaIntSet)) {
178 Int_t code = pdf->getAnalyticalIntegralWN(anaIntSet,anaSet,nullptr,isetRangeName) ;
179 if (code!=0) {
180 // Analytical integral, create integral object
181 std::unique_ptr<RooAbsReal> pai{pdf->createIntegral(anaSet,emptyNormSet,isetRangeName)};
182 pai->setOperMode(_operMode) ;
183
184 // Add to integral to product
185 prodSet.add(*pai) ;
186
187 // Remove analytically integratable observables from numeric integration list
188 numIntSet.remove(anaSet) ;
189
190 // Keep integral alive until the prodSet is cloned later
191 keepAlive.addOwned(std::move(pai));
192 } else {
193 // Analytic integration of factorizable observable not possible, add straight pdf to product
194 prodSet.add(*pdf) ;
195 }
196 } else {
197 // Non-factorizable observables, add straight pdf to product
198 prodSet.add(*pdf) ;
199 }
200 }
201
202 // Create product of (partial) analytical integrals
204 if (isetRangeName) {
205 prodName = Form("%s_%s_Range[%s]",GetName(),name,isetRangeName) ;
206 } else {
207 prodName = Form("%s_%s",GetName(),name) ;
208 }
209
210 // Create clones of the elements in prodSet. These need to be cloned
211 // because when caching optimisation lvl 2 is activated, pre-computed
212 // values are side-loaded into the elements.
213 // Those pre-cached values already contain normalisation constants, so
214 // the integral comes out wrongly. Therefore, we create here nodes that
215 // don't participate in any caching, which are used to compute integrals.
217 prodSet.snapshot(prodSetClone, false);
218
219 auto prod = std::make_unique<RooProduct>(prodName, "product", prodSetClone);
220 prod->setExpensiveObjectCache(expensiveObjectCache()) ;
221 prod->setOperMode(_operMode) ;
222
223 // Create integral performing remaining numeric integration over (partial) analytic product
224 std::unique_ptr<RooAbsReal> integral{prod->createIntegral(numIntSet,emptyNormSet,isetRangeName)};
225 integral->setOperMode(_operMode) ;
226 auto ret = integral.get();
227
228 // Declare ownership of prodSet, product, and integral
229 saveSet.addOwned(std::move(prodSetClone));
230 saveSet.addOwned(std::move(prod));
231 saveSet.addOwned(std::move(integral)) ;
232
233
234 // Caller owners returned master integral object
235 return ret ;
236}
237
238
239
240////////////////////////////////////////////////////////////////////////////////
241/// Calculate and return value of normalization projection
242
243double RooGenProdProj::evaluate() const
244{
245 RooArgSet const* nset = _intList.nset();
246
247 double nom = static_cast<RooAbsReal*>(_intList.at(0))->getVal(nset);
248
249 if (!_haveD) return nom ;
250
251 double den = static_cast<RooAbsReal*>(_intList.at(1))->getVal(nset);
252
253 //cout << "RooGenProdProj::eval(" << GetName() << ") nom = " << nom << " den = " << den << std::endl ;
254
255 return nom / den ;
256}
257
258
259
260////////////////////////////////////////////////////////////////////////////////
261/// Intercept cache mode operation changes and propagate them to the components
262
263void RooGenProdProj::operModeHook()
264{
265 // WVE use cache manager here!
266
267 for(RooAbsArg * arg : *_compSetOwnedN) {
268 arg->setOperMode(_operMode) ;
269 }
270
271 for(RooAbsArg * arg : *_compSetOwnedD) {
272 arg->setOperMode(_operMode) ;
273 }
274
275 _intList.at(0)->setOperMode(_operMode) ;
276 if (_haveD) _intList.at(1)->setOperMode(Auto) ; // Denominator always stays in Auto mode (normalization integral)
277}
278
279/// \endcond
int Int_t
Definition RtypesCore.h:45
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:110
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2489
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:77
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:59
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Basic string class.
Definition TString.h:139