RooMCIntegrator.cxx

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Project: RooFit                                                           *
00003  * Package: RooFitCore                                                       *
00004  * @(#)root/roofitcore:$Id: RooMCIntegrator.cxx 36209 2010-10-08 21:37:36Z 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 // RooMCIntegrator implements an adaptive multi-dimensional Monte Carlo
00021 // numerical integration, following the VEGAS algorithm originally described
00022 // in G. P. Lepage, J. Comp. Phys. 27, 192(1978). This implementation is
00023 // based on a C version from the 0.9 beta release of the GNU scientific library.
00024 // END_HTML
00025 //
00026 
00027 #include "RooFit.h"
00028 #include "Riostream.h"
00029 
00030 #include "TMath.h"
00031 #include "TClass.h"
00032 #include "RooMCIntegrator.h"
00033 #include "RooArgSet.h"
00034 #include "RooNumber.h"
00035 #include "RooAbsArg.h"
00036 #include "RooNumIntFactory.h"
00037 #include "RooRealVar.h"
00038 #include "RooCategory.h"
00039 #include "RooMsgService.h"
00040 
00041 #include <math.h>
00042 #include <assert.h>
00043 
00044 
00045 
00046 ClassImp(RooMCIntegrator)
00047 ;
00048 
00049 // Register this class with RooNumIntFactory
00050 
00051 
00052 //_____________________________________________________________________________
00053 void RooMCIntegrator::registerIntegrator(RooNumIntFactory& fact)
00054 {
00055   // This function registers class RooMCIntegrator, its configuration options
00056   // and its capabilities with RooNumIntFactory
00057   
00058   RooCategory samplingMode("samplingMode","Sampling Mode") ;
00059   samplingMode.defineType("Importance",RooMCIntegrator::Importance) ;
00060   samplingMode.defineType("ImportanceOnly",RooMCIntegrator::ImportanceOnly) ;
00061   samplingMode.defineType("Stratified",RooMCIntegrator::Stratified) ;
00062   samplingMode.setIndex(RooMCIntegrator::Importance) ;
00063 
00064   RooCategory genType("genType","Generator Type") ;
00065   genType.defineType("QuasiRandom",RooMCIntegrator::QuasiRandom) ;
00066   genType.defineType("PseudoRandom",RooMCIntegrator::PseudoRandom) ;
00067   genType.setIndex(RooMCIntegrator::QuasiRandom) ;
00068 
00069   RooCategory verbose("verbose","Verbose flag") ;
00070   verbose.defineType("true",1) ;
00071   verbose.defineType("false",0) ;
00072   verbose.setIndex(0) ;
00073 
00074   RooRealVar alpha("alpha","Grid structure constant",1.5) ;
00075   RooRealVar nRefineIter("nRefineIter","Number of refining iterations",5) ;
00076   RooRealVar nRefinePerDim("nRefinePerDim","Number of refining samples (per dimension)",1000) ;
00077   RooRealVar nIntPerDim("nIntPerDim","Number of integration samples (per dimension)",5000) ;
00078   
00079   // Create prototype integrator
00080   RooMCIntegrator* proto = new RooMCIntegrator() ;
00081 
00082   // Register prototype and default config with factory
00083   fact.storeProtoIntegrator(proto,RooArgSet(samplingMode,genType,verbose,alpha,nRefineIter,nRefinePerDim,nIntPerDim)) ;
00084 
00085   // Make this method the default for all N>2-dim integrals
00086   RooNumIntConfig::defaultConfig().methodND().setLabel(proto->IsA()->GetName()) ;
00087 }
00088 
00089 
00090 
00091 //_____________________________________________________________________________
00092  RooMCIntegrator::RooMCIntegrator()
00093 {
00094   // Default constructor 
00095   // 
00096   // coverity[UNINIT_CTOR] 
00097 }
00098 
00099 
00100 
00101 //_____________________________________________________________________________
00102 RooMCIntegrator::RooMCIntegrator(const RooAbsFunc& function, SamplingMode mode,
00103                                  GeneratorType genType, Bool_t verbose) :
00104   RooAbsIntegrator(function), _grid(function), _verbose(verbose),
00105   _alpha(1.5),  _mode(mode), _genType(genType),
00106   _nRefineIter(5),_nRefinePerDim(1000),_nIntegratePerDim(5000)
00107 {
00108   // Construct an integrator over 'function' with given sampling mode
00109   // and generator type.  The sampling mode can be 'Importance'
00110   // (default), 'ImportanceOnly' and 'Stratified'. The generator type
00111   // can be 'QuasiRandom' (default) and 'PseudoRandom'. Consult the original
00112   // VEGAS documentation on details of the mode and type parameters.
00113 
00114   // coverity[UNINIT_CTOR]
00115   if(!(_valid= _grid.isValid())) return;
00116   if(_verbose) _grid.Print();
00117 } 
00118 
00119 
00120 
00121 //_____________________________________________________________________________
00122 RooMCIntegrator::RooMCIntegrator(const RooAbsFunc& function, const RooNumIntConfig& config) :
00123   RooAbsIntegrator(function), _grid(function)
00124 { 
00125   // Construct an integrator over 'function' where the configuration details
00126   // are taken from 'config'
00127 
00128   const RooArgSet& configSet = config.getConfigSection(IsA()->GetName()) ;
00129   _verbose = (Bool_t) configSet.getCatIndex("verbose",0) ;
00130   _alpha = configSet.getRealValue("alpha",1.5) ;
00131   _mode = (SamplingMode) configSet.getCatIndex("samplingMode",Importance) ;
00132   _genType = (GeneratorType) configSet.getCatIndex("genType",QuasiRandom) ;
00133   _nRefineIter = (Int_t) configSet.getRealValue("nRefineIter",5) ;
00134   _nRefinePerDim = (Int_t) configSet.getRealValue("nRefinePerDim",1000) ;
00135   _nIntegratePerDim = (Int_t) configSet.getRealValue("nIntPerDim",5000) ;
00136 
00137   // check that our grid initialized without errors
00138   if(!(_valid= _grid.isValid())) return;
00139   if(_verbose) _grid.Print();
00140 } 
00141 
00142 
00143 
00144 //_____________________________________________________________________________
00145 RooAbsIntegrator* RooMCIntegrator::clone(const RooAbsFunc& function, const RooNumIntConfig& config) const
00146 {
00147   // Return clone of this generator operating on given function with given configuration
00148   // Needed to support RooNumIntFactory
00149 
00150   return new RooMCIntegrator(function,config) ;
00151 }
00152 
00153 
00154 
00155 //_____________________________________________________________________________
00156 RooMCIntegrator::~RooMCIntegrator() 
00157 {
00158   // Destructor
00159 }
00160 
00161 
00162 
00163 //_____________________________________________________________________________
00164 Bool_t RooMCIntegrator::checkLimits() const 
00165 {
00166   // Check if we can integrate over the current domain. If return value
00167   // is kTRUE we cannot handle the current limits (e.g. where the domain
00168   // of one or more observables is open ended.
00169   
00170   return _grid.initialize(*integrand());
00171 }
00172 
00173 
00174 
00175 //_____________________________________________________________________________
00176 Double_t RooMCIntegrator::integral(const Double_t* /*yvec*/) 
00177 {
00178   // Evaluate the integral using a fixed number of calls to evaluate the integrand
00179   // equal to about 10k per dimension. Use the first 5k calls to refine the grid
00180   // over 5 iterations of 1k calls each, and the remaining 5k calls for a single
00181   // high statistics integration.
00182 
00183   _timer.Start(kTRUE);
00184   vegas(AllStages,_nRefinePerDim*_grid.getDimension(),_nRefineIter);
00185   Double_t ret = vegas(ReuseGrid,_nIntegratePerDim*_grid.getDimension(),1);
00186   return ret ;
00187 }
00188 
00189 
00190 
00191 //_____________________________________________________________________________
00192 Double_t RooMCIntegrator::vegas(Stage stage, UInt_t calls, UInt_t iterations, Double_t *absError) 
00193 {
00194   // Perform one step of Monte Carlo integration using the specified number of iterations
00195   // with (approximately) the specified number of integrand evaluation calls per iteration.
00196   // Use the VEGAS algorithm, starting from the specified stage. Returns the best estimate
00197   // of the integral. Also sets *absError to the estimated absolute error of the integral
00198   // estimate if absError is non-zero.
00199 
00200   //cout << "VEGAS stage = " << stage << " calls = " << calls << " iterations = " << iterations << endl ;
00201 
00202   // reset the grid to its initial state if we are starting from scratch
00203   if(stage == AllStages) _grid.initialize(*_function);
00204 
00205   // reset the results of previous calculations on this grid, but reuse the grid itself.
00206   if(stage <= ReuseGrid) {
00207     _wtd_int_sum = 0;
00208     _sum_wgts = 0;
00209     _chi_sum = 0;
00210     _it_num = 1;
00211     _samples = 0;
00212   }
00213 
00214   // refine the results of previous calculations on the current grid.
00215   if(stage <= RefineGrid) {
00216     UInt_t bins = RooGrid::maxBins;
00217     UInt_t boxes = 1;
00218     UInt_t dim(_grid.getDimension());
00219 
00220     // select the sampling mode for the next step
00221     if(_mode != ImportanceOnly) {
00222       // calculate the largest number of equal subdivisions ("boxes") along each
00223       // axis that results in an average of no more than 2 integrand calls per cell
00224       boxes = (UInt_t)floor(TMath::Power(calls/2.0,1.0/dim));
00225       // use stratified sampling if we are allowed enough calls (or equivalently,
00226       // if the dimension is low enough)
00227       _mode = Importance;
00228       if (2*boxes >= RooGrid::maxBins) {
00229         _mode = Stratified;
00230         // adjust the number of bins and boxes to give an integral number >= 1 of boxes per bin
00231         Int_t box_per_bin= (boxes > RooGrid::maxBins) ? boxes/RooGrid::maxBins : 1;
00232         bins= boxes/box_per_bin;
00233         if(bins > RooGrid::maxBins) bins= RooGrid::maxBins;
00234         boxes = box_per_bin * bins;     
00235         oocxcoutD((TObject*)0,Integration) << "RooMCIntegrator: using stratified sampling with " << bins << " bins and "
00236                                          << box_per_bin << " boxes/bin" << endl;
00237       }
00238       else {
00239         oocxcoutD((TObject*)0,Integration) << "RooMCIntegrator: using importance sampling with " << bins << " bins and "
00240                                          << boxes << " boxes" << endl;
00241       }
00242     }
00243 
00244     // calculate the total number of n-dim boxes for this step
00245     Double_t tot_boxes = TMath::Power((Double_t)boxes,(Double_t)dim);
00246 
00247     // increase the total number of calls to get at least 2 calls per box, if necessary
00248     _calls_per_box = (UInt_t)(calls/tot_boxes);
00249     if(_calls_per_box < 2) _calls_per_box= 2;
00250     calls= (UInt_t)(_calls_per_box*tot_boxes);
00251 
00252     // calculate the Jacobean factor: volume/(avg # of calls/bin)
00253     _jac = _grid.getVolume()*TMath::Power((Double_t)bins,(Double_t)dim)/calls;
00254 
00255     // setup our grid to use the calculated number of boxes and bins
00256     _grid.setNBoxes(boxes);
00257     if(bins != _grid.getNBins()) _grid.resize(bins);
00258   }
00259 
00260   // allocate memory for some book-keeping arrays
00261   UInt_t *box= _grid.createIndexVector();
00262   UInt_t *bin= _grid.createIndexVector();
00263   Double_t *x= _grid.createPoint();
00264 
00265   // loop over iterations for this step
00266   Double_t cum_int(0),cum_sig(0);
00267   _it_start = _it_num;
00268   _chisq = 0.0;
00269   for (UInt_t it = 0; it < iterations; it++) {
00270     Double_t intgrl(0),intgrl_sq(0),sig(0),jacbin(_jac);
00271     
00272     _it_num = _it_start + it;
00273     
00274     // reset the values associated with each grid cell
00275     _grid.resetValues();
00276 
00277     // loop over grid boxes
00278     _grid.firstBox(box);
00279     do {
00280       Double_t m(0),q(0);
00281       // loop over integrand evaluations within this grid box
00282       for(UInt_t k = 0; k < _calls_per_box; k++) {
00283         // generate a random point in this box
00284         Double_t bin_vol(0);
00285         _grid.generatePoint(box, x, bin, bin_vol, _genType == QuasiRandom ? kTRUE : kFALSE);
00286         // evaluate the integrand at the generated point
00287         Double_t fval= jacbin*bin_vol*integrand(x);     
00288         // update mean and variance calculations
00289         Double_t d = fval - m;
00290         m+= d / (k + 1.0);
00291         q+= d * d * (k / (k + 1.0));
00292         // accumulate the results of this evaluation (importance sampling only)
00293         if (_mode != Stratified) _grid.accumulate(bin, fval*fval);
00294       }
00295       intgrl += m * _calls_per_box;
00296       Double_t f_sq_sum = q * _calls_per_box ;
00297       sig += f_sq_sum ;
00298 
00299       // accumulate the results for this grid box (stratified sampling only)      
00300       if (_mode == Stratified) _grid.accumulate(bin, f_sq_sum);
00301 
00302       // print occasional progress messages
00303       if(_timer.RealTime() > 1) { // wait at least 1 sec since the last message
00304         oocoutW((TObject*)0,Integration) << "RooMCIntegrator: still working..." << endl;
00305         _timer.Start(kTRUE);
00306       }
00307       else {
00308         _timer.Start(kFALSE);
00309       }
00310 
00311     } while(_grid.nextBox(box));
00312 
00313     // compute final results for this iteration
00314     Double_t wgt;
00315     sig = sig / (_calls_per_box - 1.0)  ;    
00316     if (sig > 0) {
00317       wgt = 1.0 / sig;
00318     }
00319     else if (_sum_wgts > 0) {
00320       wgt = _sum_wgts / _samples;
00321     }
00322     else {
00323       wgt = 0.0;
00324     }
00325     intgrl_sq = intgrl * intgrl;
00326     _result = intgrl;
00327     _sigma  = sqrt(sig);
00328     
00329     if (wgt > 0.0) {
00330       _samples++ ;
00331       _sum_wgts += wgt;
00332       _wtd_int_sum += intgrl * wgt;
00333       _chi_sum += intgrl_sq * wgt;
00334       
00335       cum_int = _wtd_int_sum / _sum_wgts;
00336       cum_sig = sqrt (1 / _sum_wgts);
00337       
00338       if (_samples > 1) {
00339         _chisq = (_chi_sum - _wtd_int_sum * cum_int)/(_samples - 1.0);
00340       }
00341     }
00342     else {
00343       cum_int += (intgrl - cum_int) / (it + 1.0);
00344       cum_sig = 0.0;
00345     }         
00346     oocxcoutD((TObject*)0,Integration) << "=== Iteration " << _it_num << " : I = " << intgrl << " +/- " << sqrt(sig) << endl
00347                                      << "    Cumulative : I = " << cum_int << " +/- " << cum_sig << "( chi2 = " << _chisq
00348                                      << ")" << endl;
00349     // print the grid after the final iteration
00350     if (oodologD((TObject*)0,Integration)) {
00351       if(it + 1 == iterations) _grid.Print("V");
00352     }
00353     _grid.refine(_alpha);
00354   }
00355 
00356   // cleanup
00357   delete[] bin;
00358   delete[] box;
00359   delete[] x;
00360 
00361   if(absError) *absError = cum_sig;
00362   return cum_int;
00363 }

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