RooAcceptReject.cxx

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Project: RooFit                                                           *
00003  * Package: RooFitCore                                                       *
00004  * @(#)root/roofitcore:$Id: RooAcceptReject.cxx 34064 2010-06-22 15:05:19Z 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 // Class RooAcceptReject is a generic toy monte carlo generator implement
00021 // the accept/reject sampling technique on any positively valued function.
00022 // The RooAcceptReject generator is used by the various generator context
00023 // classes to take care of generation of observables for which p.d.fs
00024 // do not define internal methods
00025 // END_HTML
00026 //
00027 
00028 
00029 #include "RooFit.h"
00030 #include "Riostream.h"
00031 
00032 #include "RooAcceptReject.h"
00033 #include "RooAcceptReject.h"
00034 #include "RooAbsReal.h"
00035 #include "RooCategory.h"
00036 #include "RooRealVar.h"
00037 #include "RooDataSet.h"
00038 #include "RooRandom.h"
00039 #include "RooErrorHandler.h"
00040 
00041 #include "TString.h"
00042 #include "TIterator.h"
00043 #include "RooMsgService.h"
00044 #include "TClass.h"
00045 #include "TFoam.h"
00046 #include "RooRealBinding.h"
00047 #include "RooNumGenFactory.h"
00048 #include "RooNumGenConfig.h"
00049 
00050 #include <assert.h>
00051 
00052 ClassImp(RooAcceptReject)
00053   ;
00054 
00055 
00056 //_____________________________________________________________________________
00057 void RooAcceptReject::registerSampler(RooNumGenFactory& fact)
00058 {
00059   // Register RooIntegrator1D, is parameters and capabilities with RooNumIntFactory 
00060   RooRealVar nTrial0D("nTrial0D","Number of trial samples for cat-only generation",100,0,1e9) ;
00061   RooRealVar nTrial1D("nTrial1D","Number of trial samples for 1-dim generation",1000,0,1e9) ;
00062   RooRealVar nTrial2D("nTrial2D","Number of trial samples for 2-dim generation",100000,0,1e9) ;
00063   RooRealVar nTrial3D("nTrial3D","Number of trial samples for N-dim generation",10000000,0,1e9) ;
00064 
00065   RooAcceptReject* proto = new RooAcceptReject ;
00066   fact.storeProtoSampler(proto,RooArgSet(nTrial0D,nTrial1D,nTrial2D,nTrial3D)) ;
00067 }
00068 
00069 
00070 
00071 //_____________________________________________________________________________
00072 RooAcceptReject::RooAcceptReject(const RooAbsReal &func, const RooArgSet &genVars, const RooNumGenConfig& config, Bool_t verbose, const RooAbsReal* maxFuncVal) :
00073   RooAbsNumGenerator(func,genVars,verbose,maxFuncVal), _nextCatVar(0), _nextRealVar(0)
00074 {
00075   // Initialize an accept-reject generator for the specified distribution function,
00076   // which must be non-negative but does not need to be normalized over the
00077   // variables to be generated, genVars. The function and its dependents are
00078   // cloned and so will not be disturbed during the generation process.
00079 
00080   _minTrialsArray[0] = static_cast<Int_t>(config.getConfigSection("RooAcceptReject").getRealValue("nTrial0D")) ;
00081   _minTrialsArray[1] = static_cast<Int_t>(config.getConfigSection("RooAcceptReject").getRealValue("nTrial1D")) ;
00082   _minTrialsArray[2] = static_cast<Int_t>(config.getConfigSection("RooAcceptReject").getRealValue("nTrial2D")) ;
00083   _minTrialsArray[3] = static_cast<Int_t>(config.getConfigSection("RooAcceptReject").getRealValue("nTrial3D")) ;
00084 
00085   _realSampleDim = _realVars.getSize() ;
00086   TIterator* iter = _catVars.createIterator() ;
00087   RooAbsCategory* cat ;
00088   _catSampleMult = 1 ;
00089   while((cat=(RooAbsCategory*)iter->Next())) {
00090     _catSampleMult *=  cat->numTypes() ;
00091   }
00092   delete iter ;
00093 
00094 
00095   // calculate the minimum number of trials needed to estimate our integral and max value
00096   if (!_funcMaxVal) {
00097 
00098     if(_realSampleDim > 3) {
00099       _minTrials= _minTrialsArray[3]*_catSampleMult;
00100       coutW(Generation) << fName << "::" << ClassName() << ": WARNING: generating " << _realSampleDim
00101                         << " variables with accept-reject may not be accurate" << endl;
00102     }
00103     else {
00104       _minTrials= _minTrialsArray[_realSampleDim]*_catSampleMult;
00105     }
00106   } else {
00107     // No trials needed if we know the maximum a priori
00108     _minTrials=0 ;
00109   }
00110 
00111   // Need to fix some things here
00112   if (_realSampleDim > 1) {
00113     coutW(Generation) << "RooAcceptReject::ctor(" << fName 
00114                       << ") WARNING: performing accept/reject sampling on a p.d.f in " << _realSampleDim << " dimensions "
00115                       << "without prior knowledge on maximum value of p.d.f. Determining maximum value by taking " << _minTrials 
00116                       << " trial samples. If p.d.f contains sharp peaks smaller than average distance between trial sampling points"
00117                       << " these may be missed and p.d.f. may be sampled incorrectly." << endl ;
00118   }
00119   if (_minTrials>10000) {
00120     coutW(Generation) << "RooAcceptReject::ctor(" << fName << "): WARNING: " << _minTrials << " trial samples requested by p.d.f for " 
00121                       << _realSampleDim << "-dimensional accept/reject sampling, this may take some time" << endl ;
00122   }
00123 
00124   // print a verbose summary of our configuration, if requested
00125   if(_verbose) {
00126     coutI(Generation) << fName << "::" << ClassName() << ":" << endl
00127                       << "  Initializing accept-reject generator for" << endl << "    ";
00128     _funcClone->printStream(ccoutI(Generation),kName,kSingleLine);
00129     if (_funcMaxVal) {
00130       ccoutI(Generation) << "  Function maximum provided, no trial sampling performed" << endl ;
00131     } else {
00132       ccoutI(Generation) << "  Real sampling dimension is " << _realSampleDim << endl;
00133       ccoutI(Generation) << "  Category sampling multiplier is " << _catSampleMult << endl ;
00134       ccoutI(Generation) << "  Min sampling trials is " << _minTrials << endl;
00135     }
00136     if (_catVars.getSize()>0) {
00137       ccoutI(Generation) << "  Will generate category vars "<< _catVars << endl ;
00138     }
00139     if (_realVars.getSize()>0) {
00140       ccoutI(Generation) << "  Will generate real vars " << _realVars << endl ;
00141     }
00142   }
00143   // create iterators for the new sets
00144   _nextCatVar= _catVars.createIterator();
00145   _nextRealVar= _realVars.createIterator();
00146   assert(0 != _nextCatVar && 0 != _nextRealVar);
00147 
00148   // initialize our statistics
00149   _maxFuncVal= 0;
00150   _funcSum= 0;
00151   _totalEvents= 0;
00152   _eventsUsed= 0;
00153 }
00154 
00155 
00156 
00157 //_____________________________________________________________________________
00158 RooAcceptReject::~RooAcceptReject() 
00159 {
00160   // Destructor
00161   delete _nextCatVar;
00162   delete _nextRealVar;
00163 }
00164 
00165 
00166 
00167 //_____________________________________________________________________________
00168 const RooArgSet *RooAcceptReject::generateEvent(UInt_t remaining, Double_t& resampleRatio) 
00169 {
00170   // Return a pointer to a generated event. The caller does not own the event and it
00171   // will be overwritten by a subsequent call. The input parameter 'remaining' should
00172   // contain your best guess at the total number of subsequent events you will request.
00173 
00174   // are we actually generating anything? (the cache always contains at least our function value)
00175   const RooArgSet *event= _cache->get();
00176   if(event->getSize() == 1) return event;
00177 
00178   if (!_funcMaxVal) {
00179     // Generation with empirical maximum determination
00180 
00181     // first generate enough events to get reasonable estimates for the integral and
00182     // maximum function value
00183 
00184     while(_totalEvents < _minTrials) {
00185       addEventToCache();
00186 
00187       // Limit cache size to 1M events
00188       if (_cache->numEntries()>1000000) {
00189         coutI(Generation) << "RooAcceptReject::generateEvent: resetting event cache" << endl ;
00190         _cache->reset() ;
00191         _eventsUsed = 0 ;
00192       }
00193     }
00194     
00195     event= 0;
00196     Double_t oldMax2(_maxFuncVal);
00197     while(0 == event) {
00198       // Use any cached events first
00199       if (_maxFuncVal>oldMax2) {
00200         cxcoutD(Generation) << "RooAcceptReject::generateEvent maxFuncVal has changed, need to resample already accepted events by factor" 
00201                             << oldMax2 << "/" << _maxFuncVal << "=" << oldMax2/_maxFuncVal << endl ;    
00202         resampleRatio=oldMax2/_maxFuncVal ;
00203       }
00204       event= nextAcceptedEvent();
00205       if(event) break;
00206       // When we have used up the cache, start a new cache and add
00207       // some more events to it.      
00208       _cache->reset();
00209       _eventsUsed= 0;
00210       // Calculate how many more events to generate using our best estimate of our efficiency.
00211       // Always generate at least one more event so we don't get stuck.
00212       if(_totalEvents*_maxFuncVal <= 0) {
00213         coutE(Generation) << "RooAcceptReject::generateEvent: cannot estimate efficiency...giving up" << endl;
00214         return 0;
00215       }
00216 
00217       Double_t eff= _funcSum/(_totalEvents*_maxFuncVal);
00218       Long64_t extra= 1 + (Long64_t)(1.05*remaining/eff);
00219       cxcoutD(Generation) << "RooAcceptReject::generateEvent: adding " << extra << " events to the cache, eff = " << eff << endl;
00220       Double_t oldMax(_maxFuncVal);
00221       while(extra--) {
00222         addEventToCache();
00223         if((_maxFuncVal > oldMax)) {
00224           cxcoutD(Generation) << "RooAcceptReject::generateEvent: estimated function maximum increased from "
00225                               << oldMax << " to " << _maxFuncVal << endl;
00226           oldMax = _maxFuncVal ;
00227           // Trim cache here
00228         }
00229       }
00230     }
00231 
00232     // Limit cache size to 1M events
00233     if (_eventsUsed>1000000) {
00234       _cache->reset() ;
00235       _eventsUsed = 0 ;
00236     }
00237 
00238   } else {
00239     // Generation with a priori maximum knowledge
00240     _maxFuncVal = _funcMaxVal->getVal() ;
00241     
00242     // Generate enough trials to produce a single accepted event
00243     event = 0 ;
00244     while(0==event) {
00245       addEventToCache() ;
00246       event = nextAcceptedEvent() ;
00247     }
00248 
00249   }
00250   return event;
00251 }
00252 
00253 
00254 
00255 //_____________________________________________________________________________
00256 const RooArgSet *RooAcceptReject::nextAcceptedEvent() 
00257 {
00258   // Scan through events in the cache which have not been used yet,
00259   // looking for the first accepted one which is added to the specified
00260   // container. Return a pointer to the accepted event, or else zero
00261   // if we use up the cache before we accept an event. The caller does
00262   // not own the event and it will be overwritten by a subsequent call.
00263 
00264   const RooArgSet *event = 0;
00265   while((event= _cache->get(_eventsUsed))) {    
00266     _eventsUsed++ ;
00267     // accept this cached event?
00268     Double_t r= RooRandom::uniform();
00269     if(r*_maxFuncVal > _funcValPtr->getVal()) {
00270       //cout << " event number " << _eventsUsed << " has been rejected" << endl ;
00271       continue;
00272     }
00273     //cout << " event number " << _eventsUsed << " has been accepted" << endl ;
00274     // copy this event into the output container
00275     if(_verbose && (_eventsUsed%1000==0)) {
00276       cerr << "RooAcceptReject: accepted event (used " << _eventsUsed << " of "
00277            << _cache->numEntries() << " so far)" << endl;
00278     }
00279     break;
00280   }  
00281   //cout << "accepted event " << _eventsUsed << " of " << _cache->numEntries() << endl ;
00282   return event;
00283 }
00284 
00285 
00286 
00287 //_____________________________________________________________________________
00288 void RooAcceptReject::addEventToCache() 
00289 {
00290   // Add a trial event to our cache and update our estimates
00291   // of the function maximum value and integral.
00292 
00293   // randomize each discrete argument
00294   _nextCatVar->Reset();
00295   RooCategory *cat = 0;
00296   while((cat= (RooCategory*)_nextCatVar->Next())) cat->randomize();
00297 
00298   // randomize each real argument
00299   _nextRealVar->Reset();
00300   RooRealVar *real = 0;
00301   while((real= (RooRealVar*)_nextRealVar->Next())) real->randomize();
00302 
00303   // calculate and store our function value at this new point
00304   Double_t val= _funcClone->getVal();
00305   _funcValPtr->setVal(val);
00306 
00307   // Update the estimated integral and maximum value. Increase our
00308   // maximum estimate slightly to give a safety margin with a
00309   // corresponding loss of efficiency.
00310   if(val > _maxFuncVal) _maxFuncVal= 1.05*val;
00311   _funcSum+= val;
00312 
00313   // fill a new entry in our cache dataset for this point
00314   _cache->fill();
00315   _totalEvents++;
00316 
00317   if (_verbose &&_totalEvents%10000==0) {
00318     cerr << "RooAcceptReject: generated " << _totalEvents << " events so far." << endl ;
00319   }
00320 
00321 }
00322 
00323 Double_t RooAcceptReject::getFuncMax() 
00324 {
00325   // Empirically determine maximum value of function by taking a large number
00326   // of samples. The actual number depends on the number of dimensions in which
00327   // the sampling occurs
00328 
00329   // Generate the minimum required number of samples for a reliable maximum estimate
00330   while(_totalEvents < _minTrials) {
00331     addEventToCache();
00332 
00333     // Limit cache size to 1M events
00334     if (_cache->numEntries()>1000000) {
00335       coutI(Generation) << "RooAcceptReject::getFuncMax: resetting event cache" << endl ;
00336       _cache->reset() ;
00337       _eventsUsed = 0 ;
00338     }
00339   }  
00340 
00341   return _maxFuncVal ;
00342 }
00343 

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