RooNumConvolution.cxx

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Project: RooFit                                                           *
00003  * Package: RooFitCore                                                       *
00004  * @(#)root/roofitcore:$Id: RooNumConvolution.cxx 28259 2009-04-16 16:21:16Z wouter $
00005  * Authors:                                                                  *
00006  *   WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu       *
00007  *   DK, David Kirkby,    UC Irvine,         dkirkby@uci.edu                 *
00008  *                                                                           *
00009  * Copyright (c) 2000-2005, Regents of the University of California          *
00010  *                          and Stanford University. All rights reserved.    *
00011  *                                                                           *
00012  * Redistribution and use in source and binary forms,                        *
00013  * with or without modification, are permitted according to the terms        *
00014  * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
00015  *****************************************************************************/
00016 
00017 //////////////////////////////////////////////////////////////////////////////
00018 //
00019 // BEGIN_HTML
00020 // Numeric 1-dimensional convolution operator PDF. This class can convolve any PDF
00021 // with any other PDF
00022 // <p>
00023 // This class should not be used blindly as numeric convolution is computing
00024 // intensive and prone to stability fitting problems. If an analytic convolution
00025 // can be calculated, you should use that or implement it if not available.
00026 // RooNumConvolution implements reasonable defaults that should convolve most
00027 // functions reasonably well, but results strongly depend on the shape of your
00028 // input PDFS so always check your result.
00029 //
00030 // The default integration engine for the numeric convolution is the
00031 // adaptive Gauss-Kronrod method, which empirically seems the most robust
00032 // for this task. You can override the convolution integration settings via
00033 // the RooNumIntConfig object reference returned by the convIntConfig() member
00034 // function
00035 // <p>
00036 // By default the numeric convolution is integrated from -infinity to
00037 // +infinity through a <pre>x -> 1/x</pre> coordinate transformation of the
00038 // tails. For convolution with a very small bandwidth it may be
00039 // advantageous (for both CPU consumption and stability) if the
00040 // integration domain is limited to a finite range. The function
00041 // setConvolutionWindow(mean,width,scale) allows to set a sliding
00042 // window around the x value to be calculated taking a RooAbsReal
00043 // expression for an offset and a width to be taken around the x
00044 // value. These input expression can be RooFormulaVars or other
00045 // function objects although the 3d 'scale' argument 'scale'
00046 // multiplies the width RooAbsReal expression given in the 2nd
00047 // argument, allowing for an appropriate window definition for most
00048 // cases without need for a RooFormulaVar object: e.g. a Gaussian
00049 // resolution PDF do setConvolutionWindow(gaussMean,gaussSigma,5)
00050 // Note that for a 'wide' Gaussian the -inf to +inf integration
00051 // may converge more quickly than that over a finite range!
00052 // <p>
00053 // The default numeric precision is 1e-7, i.e. the global default for
00054 // numeric integration but you should experiment with this value to
00055 // see if it is sufficient for example by studying the number of function
00056 // calls that MINUIT needs to fit your function as function of the
00057 // convolution precision. 
00058 // END_HTML
00059 //
00060 
00061 #include "RooFit.h"
00062 
00063 #include "Riostream.h"
00064 #include "Riostream.h"
00065 #include "TH2F.h"
00066 #include "RooNumConvolution.h"
00067 #include "RooArgList.h"
00068 #include "RooRealVar.h"
00069 #include "RooFormulaVar.h"
00070 #include "RooCustomizer.h"
00071 #include "RooConvIntegrandBinding.h"
00072 #include "RooNumIntFactory.h"
00073 #include "RooGenContext.h"
00074 #include "RooConvGenContext.h"
00075 #include "RooMsgService.h"
00076 
00077 
00078 ClassImp(RooNumConvolution)
00079 ;
00080 
00081 
00082 //_____________________________________________________________________________
00083 RooNumConvolution::RooNumConvolution() :
00084   _init(kFALSE),
00085   _integrand(0),
00086   _integrator(0),
00087   _callHist(0)
00088 {
00089 }
00090 
00091 
00092 
00093 //_____________________________________________________________________________
00094 RooNumConvolution::RooNumConvolution(const char *name, const char *title, RooRealVar& convVar, RooAbsReal& inPdf, RooAbsReal& resmodel, const RooNumConvolution* proto) : 
00095   RooAbsReal(name,title), 
00096   _init(kFALSE),
00097   _convIntConfig(RooNumIntConfig::defaultConfig()),
00098   _integrand(0),
00099   _integrator(0),
00100   _origVar("origVar","Original Convolution variable",this,convVar),
00101   _origPdf("origPdf","Original Input PDF",this,inPdf),
00102   _origModel("origModel","Original Resolution model",this,resmodel),
00103   _ownedClonedPdfSet("ownedClonePdfSet"),
00104   _ownedClonedModelSet("ownedCloneModelSet"),
00105   _cloneVar(0),
00106   _clonePdf(0),
00107   _cloneModel(0),
00108   _useWindow(kFALSE),
00109   _windowScale(1),
00110   _windowParam("windowParam","Convolution window parameter",this,kFALSE),
00111   _verboseThresh(2000),
00112   _doProf(kFALSE),
00113   _callHist(0)
00114 {
00115   // Constructor of convolution operator PDF
00116   // 
00117   // convVar  :  convolution variable (on which both pdf and resmodel should depend)
00118   // pdf      :  input 'physics' pdf
00119   // resmodel :  input 'resultion' pdf
00120   //
00121   // output is pdf(x) (X) resmodel(x) = Int [ pdf(x') resmodel (x-x') ] dx'
00122   //
00123 
00124   // Use Adaptive Gauss-Kronrod integration by default for the convolution integral
00125   _convIntConfig.method1D().setLabel("RooAdaptiveGaussKronrodIntegrator1D") ;
00126   _convIntConfig.method1DOpen().setLabel("RooAdaptiveGaussKronrodIntegrator1D") ;
00127 
00128   if (proto) {
00129     convIntConfig() = proto->convIntConfig() ;
00130     if (proto->_useWindow) {
00131       setConvolutionWindow((RooAbsReal&)*proto->_windowParam.at(0),(RooAbsReal&)*proto->_windowParam.at(1),proto->_windowScale) ;
00132     }
00133   }
00134 }
00135 
00136 
00137 
00138 //_____________________________________________________________________________
00139 RooNumConvolution::RooNumConvolution(const RooNumConvolution& other, const char* name) :
00140   RooAbsReal(other,name),
00141   _init(kFALSE),
00142   _convIntConfig(other._convIntConfig),
00143   _integrand(0),
00144   _integrator(0),
00145   _origVar("origVar",this,other._origVar),
00146   _origPdf("origPdf",this,other._origPdf),
00147   _origModel("origModel",this,other._origModel),
00148   _ownedClonedPdfSet("ownedClonePdfSet"),
00149   _ownedClonedModelSet("ownedCloneModelSet"),
00150   _cloneVar(0),
00151   _clonePdf(0),
00152   _cloneModel(0),
00153   _useWindow(other._useWindow),
00154   _windowScale(other._windowScale),
00155   _windowParam("windowParam",this,other._windowParam),
00156   _verboseThresh(other._verboseThresh),
00157   _doProf(other._doProf),
00158   _callHist(other._callHist)
00159 {
00160   // Copy constructor
00161 }
00162 
00163 
00164 
00165 //_____________________________________________________________________________
00166 void RooNumConvolution::initialize() const
00167 {
00168   // One-time initialization of object
00169 
00170   // Initialization function -- create clone of convVar (x') and deep-copy clones of pdf and
00171   // model that are connected to x' rather than x (convVar)
00172 
00173   // Start out clean 
00174   _ownedClonedPdfSet.removeAll() ;
00175   _ownedClonedModelSet.removeAll() ;
00176 
00177   if (_cloneVar) delete _cloneVar ;
00178 
00179   // Customize a copy of origPdf that is connected to x' rather than x
00180   // store all cloned components in _clonePdfSet as well as x' itself
00181   _cloneVar = new RooRealVar(Form("%s_prime",_origVar.arg().GetName()),"Convolution Variable",0) ;
00182 
00183   RooCustomizer mgr1(pdf(),"NumConv_PdfClone") ;
00184   mgr1.setCloneBranchSet(_ownedClonedPdfSet) ;
00185   mgr1.replaceArg(var(),*_cloneVar) ;
00186   _clonePdf = (RooAbsReal*) mgr1.build() ;
00187 
00188   RooCustomizer mgr2(model(),"NumConv_ModelClone") ;
00189   mgr2.setCloneBranchSet(_ownedClonedModelSet) ;
00190   mgr2.replaceArg(var(),*_cloneVar) ;
00191   _cloneModel = (RooAbsReal*) mgr2.build() ;
00192 
00193   // Change name back to original name
00194   _cloneVar->SetName(var().GetName()) ;
00195   
00196   // Create Convolution integrand
00197   _integrand = new RooConvIntegrandBinding(*_clonePdf,*_cloneModel,*_cloneVar,var(),0) ;
00198  
00199   // Instantiate integrator for convolution integrand
00200   _integrator = RooNumIntFactory::instance().createIntegrator(*_integrand,_convIntConfig,1) ;
00201   _integrator->setUseIntegrandLimits(kFALSE) ;
00202 
00203   _init = kTRUE ;
00204 }
00205  
00206 
00207 
00208 
00209 //_____________________________________________________________________________
00210 RooNumConvolution::~RooNumConvolution() 
00211 {
00212   // Destructor
00213 }
00214 
00215 
00216 
00217 //_____________________________________________________________________________
00218 Double_t RooNumConvolution::evaluate() const 
00219 {
00220   // Calculate convolution integral
00221 
00222   // Check if deferred initialization has occurred
00223   if (!_init) initialize() ;
00224 
00225   // Retrieve current value of convolution variable
00226   Double_t x = _origVar ;
00227 
00228   // Propagate current normalization set to integrand
00229   _integrand->setNormalizationSet(_origVar.nset()) ;
00230 
00231   // Adjust convolution integration window
00232   if (_useWindow) {
00233     Double_t center = ((RooAbsReal*)_windowParam.at(0))->getVal() ;
00234     Double_t width = _windowScale * ((RooAbsReal*)_windowParam.at(1))->getVal() ;
00235     _integrator->setLimits(x-center-width,x-center+width) ;
00236   } else {
00237     _integrator->setLimits(-RooNumber::infinity(),RooNumber::infinity()) ;
00238   }
00239   
00240   // Calculate convolution for present x
00241   if (_doProf) _integrand->resetNumCall() ;
00242   Double_t ret = _integrator->integral(&x) ;
00243   if (_doProf) {
00244     _callHist->Fill(x,_integrand->numCall()) ;
00245     if (_integrand->numCall()>_verboseThresh) {
00246       coutW(Integration) << "RooNumConvolution::eveluate(" << GetName() << ") WARNING convolution integral at x=" << x 
00247                          << " required " << _integrand->numCall() << " function evaluations" << endl ;
00248     }
00249   }
00250 
00251   return ret ;
00252 }
00253 
00254 
00255 
00256 //_____________________________________________________________________________
00257 Bool_t RooNumConvolution::redirectServersHook(const RooAbsCollection& /*newServerList*/, Bool_t /*mustReplaceAll*/, 
00258                                               Bool_t /*nameChange*/, Bool_t /*isRecursive*/) 
00259 {
00260   // Intercept server redirects. Throw away cache, as figuring out redirections on the cache is an unsolvable problem.   
00261   
00262   _init = kFALSE ;
00263   return kFALSE ;
00264 }
00265 
00266 
00267 
00268 //_____________________________________________________________________________
00269 void RooNumConvolution::clearConvolutionWindow() 
00270 {
00271   // Removes previously defined convolution window, reverting to convolution from -inf to +inf
00272 
00273   _useWindow = kFALSE ;
00274   _windowParam.removeAll() ;
00275 }
00276 
00277 
00278 
00279 //_____________________________________________________________________________
00280 void RooNumConvolution::setConvolutionWindow(RooAbsReal& centerParam, RooAbsReal& widthParam, Double_t widthScaleFactor) 
00281 {
00282   // Restrict convolution integral to finite range [ x - C - S*W, x - C + S*W ] 
00283   // where x is current value of convolution variablem, C = centerParam, W=widthParam and S = widthScaleFactor
00284   // Inputs centerParam and withParam can be function expressions (RooAbsReal, RooFormulaVar) etc.
00285 
00286   _useWindow = kTRUE ;
00287   _windowParam.removeAll() ;
00288   _windowParam.add(centerParam) ;
00289   _windowParam.add(widthParam) ;
00290   _windowScale = widthScaleFactor ;
00291 }
00292 
00293 
00294 
00295 //_____________________________________________________________________________
00296 void RooNumConvolution::setCallWarning(Int_t threshold) 
00297 {
00298   // Activate warning messages if number of function calls needed for evaluation of convolution integral 
00299   // exceeds given threshold
00300 
00301   if (threshold<0) {
00302     coutE(InputArguments) << "RooNumConvolution::setCallWarning(" << GetName() << ") ERROR: threshold must be positive, value unchanged" << endl ;
00303     return ;
00304   }
00305   _verboseThresh = threshold ;
00306 }
00307 
00308 
00309 //_____________________________________________________________________________
00310 void RooNumConvolution::setCallProfiling(Bool_t flag, Int_t nbinX, Int_t nbinCall, Int_t nCallHigh) 
00311 {
00312   // Activate call profile if flag is set to true. A 2-D histogram is kept that stores the required number
00313   // of function calls versus the value of x, the convolution variable
00314   //
00315   // All clones of RooNumConvolution objects will keep logging to the histogram of the original class
00316   // so that performance of temporary object clones, such as used in e.g. fitting, plotting and generating
00317   // are all logged in a single place.
00318   // 
00319   // Function caller should take ownership of profiling histogram as it is not deleted at the RooNumConvolution dtor
00320   //
00321   // Calling this function with flag set to false will deactivate call profiling and delete the profiling histogram
00322 
00323   if (flag) {
00324     if (_doProf) {
00325       delete _callHist ;
00326     }
00327     _callHist = new TH2F(Form("callHist_%s",GetName()),Form("Call Profiling of RooNumConvolution %s",GetTitle()),
00328                          nbinX,_origVar.min(),_origVar.max(),
00329                          nbinCall,0,nCallHigh) ;
00330     _doProf=kTRUE ;
00331 
00332   } else if (_doProf) {
00333 
00334     delete _callHist ;
00335     _callHist = 0 ;
00336     _doProf = kFALSE ;
00337   }
00338 
00339 }
00340 
00341 
00342 
00343 //_____________________________________________________________________________
00344 void RooNumConvolution::printCompactTreeHook(ostream& os, const char* indent) 
00345 {
00346   // Hook function to intercept printCompactTree() calls so that it can print out
00347   // the content of its private cache in the print sequence
00348 
00349   os << indent << "RooNumConvolution begin cache" << endl ;
00350 
00351   if (_init) {
00352     _cloneVar->printCompactTree(os,Form("%s[Var]",indent)) ;
00353     _clonePdf->printCompactTree(os,Form("%s[Pdf]",indent)) ;
00354     _cloneModel->printCompactTree(os,Form("%s[Mod]",indent)) ;
00355   }
00356 
00357   os << indent << "RooNumConvolution end cache" << endl ;
00358 }
00359 
00360 

Generated on Tue Jul 5 15:06:53 2011 for ROOT_528-00b_version by  doxygen 1.5.1