RooGenContext.cxx

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Project: RooFit                                                           *
00003  * Package: RooFitCore                                                       *
00004  * @(#)root/roofitcore:$Id: RooGenContext.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 RooGenContext implement a universal generator context for all
00021 // RooAbsPdf classes that do not have or need a specialized generator
00022 // context. This generator context queries the input p.d.f which observables
00023 // it can generate internally and delegates generation of those observables
00024 // to the p.d.f if it deems that safe. The other observables are generated
00025 // use a RooAcceptReject sampling technique.
00026 // END_HTML
00027 //
00028 
00029 
00030 #include "RooFit.h"
00031 #include "RooMsgService.h"
00032 #include "Riostream.h"
00033 
00034 #include "RooGenContext.h"
00035 #include "RooGenContext.h"
00036 #include "RooAbsPdf.h"
00037 #include "RooDataSet.h"
00038 #include "RooRealIntegral.h"
00039 #include "RooAcceptReject.h"
00040 #include "RooRealVar.h"
00041 #include "RooDataHist.h"
00042 #include "RooErrorHandler.h"
00043 #include "RooNumGenConfig.h"
00044 #include "RooNumGenFactory.h"
00045 
00046 #include "TString.h"
00047 #include "TIterator.h"
00048 #include "TClass.h"
00049 
00050 
00051 
00052 ClassImp(RooGenContext)
00053   ;
00054 
00055 
00056 
00057 //_____________________________________________________________________________
00058 RooGenContext::RooGenContext(const RooAbsPdf &model, const RooArgSet &vars,
00059                              const RooDataSet *prototype, const RooArgSet* auxProto,
00060                              Bool_t verbose, const RooArgSet* forceDirect) :  
00061   RooAbsGenContext(model,vars,prototype,auxProto,verbose),
00062   _cloneSet(0), _pdfClone(0), _acceptRejectFunc(0), _generator(0),
00063   _maxVar(0), _uniIter(0), _updateFMaxPerEvent(0) 
00064 {
00065   // Initialize a new context for generating events with the specified
00066   // variables, using the specified PDF model. A prototype dataset (if provided)
00067   // is not cloned and still belongs to the caller. The contents and shape
00068   // of this dataset can be changed between calls to generate() as long as the
00069   // expected columns to be copied to the generated dataset are present.
00070   // Any argument supplied in the forceDirect RooArgSet are always offered
00071   // for internal generation to the p.d.f., even if this is deemed unsafe by
00072   // the logic of RooGenContext.
00073 
00074   cxcoutI(Generation) << "RooGenContext::ctor() setting up event generator context for p.d.f. " << model.GetName() 
00075                         << " for generation of observable(s) " << vars ;
00076   if (prototype) ccxcoutI(Generation) << " with prototype data for " << *prototype->get() ;
00077   if (auxProto && auxProto->getSize()>0)  ccxcoutI(Generation) << " with auxiliary prototypes " << *auxProto ;
00078   if (forceDirect && forceDirect->getSize()>0)  ccxcoutI(Generation) << " with internal generation forced for observables " << *forceDirect ;
00079   ccxcoutI(Generation) << endl ;
00080 
00081 
00082   // Clone the model and all nodes that it depends on so that this context
00083   // is independent of any existing objects.
00084   RooArgSet nodes(model,model.GetName());
00085   _cloneSet= (RooArgSet*) nodes.snapshot(kTRUE);
00086   if (!_cloneSet) {
00087     coutE(Generation) << "RooGenContext::RooGenContext(" << GetName() << ") Couldn't deep-clone PDF, abort," << endl ;
00088     RooErrorHandler::softAbort() ;
00089   }
00090 
00091   // Find the clone in the snapshot list
00092   _pdfClone = (RooAbsPdf*)_cloneSet->find(model.GetName());
00093 
00094   // Optionally fix RooAddPdf normalizations
00095   if (prototype&&_pdfClone->dependsOn(*prototype->get())) {
00096     RooArgSet fullNormSet(vars) ;
00097     fullNormSet.add(*prototype->get()) ;
00098     _pdfClone->fixAddCoefNormalization(fullNormSet) ;
00099   }
00100       
00101   // Analyze the list of variables to generate...
00102   _isValid= kTRUE;
00103   TIterator *iterator= vars.createIterator();
00104   TIterator *servers= _pdfClone->serverIterator();
00105   const RooAbsArg *tmp = 0;
00106   const RooAbsArg *arg = 0;
00107   while((_isValid && (tmp= (const RooAbsArg*)iterator->Next()))) {
00108     // is this argument derived?
00109     if(!tmp->isFundamental()) {
00110       coutE(Generation) << "RooGenContext::ctor(): cannot generate values for derived \""  << tmp->GetName() << "\"" << endl;
00111       _isValid= kFALSE;
00112       continue;
00113     }
00114     // lookup this argument in the cloned set of PDF dependents
00115     arg= (const RooAbsArg*)_cloneSet->find(tmp->GetName());
00116     if(0 == arg) {
00117       coutI(Generation) << "RooGenContext::ctor() WARNING model does not depend on \"" << tmp->GetName() 
00118                           << "\" which will have uniform distribution" << endl;
00119       _uniformVars.add(*tmp);
00120     }
00121     else {
00122 
00123       // does the model depend on this variable directly, ie, like "x" in
00124       // f(x) or f(x,g(x,y)) or even f(x,x) ?      
00125       const RooAbsArg *direct= arg ;
00126       if (forceDirect==0 || !forceDirect->find(direct->GetName())) {
00127         if (!_pdfClone->isDirectGenSafe(*arg)) {
00128           cxcoutD(Generation) << "RooGenContext::ctor() observable " << arg->GetName() << " has been determined to be unsafe for internal generation" << endl;
00129           direct=0 ;
00130         }
00131       }
00132       
00133       // does the model depend indirectly on this variable through an lvalue chain?     
00134       // otherwise, this variable will have to be generated with accept/reject
00135       if(direct) { 
00136         _directVars.add(*arg);
00137       } else {
00138         _otherVars.add(*arg);
00139       }
00140     }
00141   }
00142   delete servers;
00143   delete iterator;
00144   if(!isValid()) {
00145     coutE(Generation) << "RooGenContext::ctor() constructor failed with errors" << endl;
00146     return;
00147   }
00148 
00149   // At this point directVars are all variables that are safe to be generated directly
00150   //               otherVars are all variables that are _not_ safe to be generated directly
00151   if (_directVars.getSize()>0) {
00152     cxcoutD(Generation) << "RooGenContext::ctor() observables " << _directVars << " are safe for internal generator (if supported by p.d.f)" << endl ;
00153   }
00154   if (_otherVars.getSize()>0) {
00155     cxcoutD(Generation) << "RooGenContext::ctor() observables " << _otherVars << " are NOT safe for internal generator (if supported by p.d.f)" << endl ;
00156   }
00157 
00158   // If PDF depends on prototype data, direct generator cannot use static initialization
00159   // in initGenerator()
00160   Bool_t staticInitOK = !_pdfClone->dependsOn(_protoVars) ;
00161   if (!staticInitOK) {
00162     cxcoutD(Generation) << "RooGenContext::ctor() Model depends on supplied protodata observables, static initialization of internal generator will not be allowed" << endl ;
00163   }
00164   
00165   // Can the model generate any of the direct variables itself?
00166   RooArgSet generatedVars;
00167   if (_directVars.getSize()>0) {
00168     _code= _pdfClone->getGenerator(_directVars,generatedVars,staticInitOK);
00169     
00170     cxcoutD(Generation) << "RooGenContext::ctor() Model indicates that it can internally generate observables " 
00171                           << generatedVars << " with configuration identifier " << _code << endl ;
00172   } else {
00173     _code = 0 ;
00174   }
00175 
00176   // Move variables which cannot be generated into the list to be generated with accept/reject
00177   _directVars.remove(generatedVars);
00178   _otherVars.add(_directVars);
00179 
00180   // Update _directVars to only include variables that will actually be directly generated
00181   _directVars.removeAll();
00182   _directVars.add(generatedVars);
00183 
00184   cxcoutI(Generation) << "RooGenContext::ctor() Context will" ;
00185   if (_directVars.getSize()>0) ccxcoutI(Generation) << " let model internally generate observables " << _directVars ;
00186   if (_directVars.getSize()>0 && _otherVars.getSize()>0)  ccxcoutI(Generation) << " and" ;
00187   if (_otherVars.getSize()>0)  ccxcoutI(Generation) << " generate variables " << _otherVars << " with accept/reject sampling" ;
00188   if (_uniformVars.getSize()>0) ccxcoutI(Generation) << ", non-observable variables " << _uniformVars << " will be generated with flat distribution" ;
00189   ccxcoutI(Generation) << endl ;
00190 
00191   // initialize the accept-reject generator
00192   RooArgSet *depList= _pdfClone->getObservables(_theEvent);
00193   depList->remove(_otherVars);
00194 
00195   TString nname(_pdfClone->GetName()) ;
00196   nname.Append("_AccRej") ;
00197   TString ntitle(_pdfClone->GetTitle()) ;
00198   ntitle.Append(" (Accept/Reject)") ;
00199   
00200 
00201   RooArgSet* protoDeps = model.getObservables(_protoVars) ;
00202   
00203 
00204   if (_protoVars.getSize()==0) {
00205 
00206     // No prototype variables
00207     
00208     if(depList->getSize()==0) {
00209       // All variable are generated with accept-reject
00210       
00211       // Check if PDF supports maximum finding
00212       Int_t maxFindCode = _pdfClone->getMaxVal(_otherVars) ;
00213       if (maxFindCode != 0) {
00214         coutI(Generation) << "RooGenContext::ctor() no prototype data provided, all observables are generated with numerically and "
00215                               << "model supports analytical maximum findin:, can provide analytical pdf maximum to numeric generator" << endl ;
00216         Double_t maxVal = _pdfClone->maxVal(maxFindCode) / _pdfClone->getNorm(_theEvent) ;
00217         _maxVar = new RooRealVar("funcMax","function maximum",maxVal) ;
00218         cxcoutD(Generation) << "RooGenContext::ctor() maximum value returned by RooAbsPdf::maxVal() is " << maxVal << endl ;
00219       }
00220     }
00221 
00222     if (_otherVars.getSize()>0) {
00223       _pdfClone->getVal(&vars) ; // WVE debug
00224       _acceptRejectFunc= new RooRealIntegral(nname,ntitle,*_pdfClone,*depList,&vars);
00225       cxcoutI(Generation) << "RooGenContext::ctor() accept/reject sampling function is " << _acceptRejectFunc->GetName() << endl ;
00226     } else {
00227       _acceptRejectFunc = 0 ;
00228     }
00229 
00230   } else {
00231 
00232     // Generation _with_ prototype variable
00233     depList->remove(_protoVars,kTRUE,kTRUE) ;
00234     _acceptRejectFunc= (RooRealIntegral*) _pdfClone->createIntegral(*depList,vars) ;
00235     cxcoutI(Generation) << "RooGenContext::ctor() accept/reject sampling function is " << _acceptRejectFunc->GetName() << endl ;
00236     
00237     if (_directVars.getSize()==0)  {
00238       
00239       // Check if PDF supports maximum finding
00240       Int_t maxFindCode = _pdfClone->getMaxVal(_otherVars) ;
00241       if (maxFindCode != 0) {
00242         
00243         // Special case: PDF supports max-finding in otherVars, no need to scan other+proto space for maximum
00244         coutI(Generation) << "RooGenContext::ctor() prototype data provided, all observables are generated numerically and "
00245                             << "model supports analytical maximum finding: can provide analytical pdf maximum to numeric generator" << endl ;
00246         _maxVar = new RooRealVar("funcMax","function maximum",1) ;
00247         _updateFMaxPerEvent = maxFindCode ;
00248         cxcoutD(Generation) << "RooGenContext::ctor() maximum value must be reevaluated for each event with configuration code " << maxFindCode << endl ;
00249       }
00250     }
00251     
00252     if (!_maxVar) {
00253       
00254       // Regular case: First find maximum in other+proto space
00255       RooArgSet otherAndProto(_otherVars) ;
00256 
00257       otherAndProto.add(*protoDeps) ;
00258       
00259       if (_otherVars.getSize()>0) {      
00260 
00261         cxcoutD(Generation) << "RooGenContext::ctor() prototype data provided, observables are generated numericaly no " 
00262                               << "analytical estimate of maximum function value provided by model, must determine maximum value through initial sampling space "
00263                               << "of accept/reject observables plus prototype observables: " << otherAndProto << endl ;
00264 
00265         // Calculate maximum in other+proto space if there are any accept/reject generated observables
00266         RooAbsNumGenerator* maxFinder = RooNumGenFactory::instance().createSampler(*_acceptRejectFunc,otherAndProto,RooArgSet(_protoVars),
00267                                                                                    *model.getGeneratorConfig(),_verbose) ;
00268 //      RooAcceptReject maxFinder(*_acceptRejectFunc,otherAndProto,RooNumGenConfig::defaultConfig(),_verbose) ;
00269         Double_t max = maxFinder->getFuncMax() ;
00270         _maxVar = new RooRealVar("funcMax","function maximum",max) ;
00271 
00272         if (max==0) {     
00273           coutE(Generation) << "RooGenContext::ctor(" << model.GetName() 
00274                             << ") ERROR: generating conditional p.d.f. which requires prior knowledge of function maximum, " 
00275                             << "but chosen numeric generator (" << maxFinder->IsA()->GetName() << ") does not support maximum finding" << endl ;        
00276           delete maxFinder ;    
00277           throw string("RooGenContext::ctor()") ;         
00278         }       
00279         delete maxFinder ;      
00280 
00281         cxcoutD(Generation) << "RooGenContext::ctor() maximum function value found through initial sampling is " << max << endl ;
00282       }
00283     }
00284       
00285   }
00286 
00287   if (_acceptRejectFunc && _otherVars.getSize()>0) {
00288     _generator = RooNumGenFactory::instance().createSampler(*_acceptRejectFunc,_otherVars,RooArgSet(_protoVars),*model.getGeneratorConfig(),_verbose,_maxVar) ;    
00289     cxcoutD(Generation) << "RooGenContext::ctor() creating MC sampling generator " << _generator->IsA()->GetName() << "  from function for observables " << _otherVars << endl ;
00290     //_generator= new RooAcceptReject(*_acceptRejectFunc,_otherVars,RooNumGenConfig::defaultConfig(),_verbose,_maxVar);
00291   } else {
00292     _generator = 0 ;
00293   }
00294 
00295   delete protoDeps ;
00296   delete depList;
00297   _otherVars.add(_uniformVars);
00298 }
00299 
00300 
00301 //_____________________________________________________________________________
00302 RooGenContext::~RooGenContext() 
00303 {
00304   // Destructor.
00305 
00306   // Clean up the cloned objects used in this context.
00307   delete _cloneSet;
00308 
00309   // Clean up our accept/reject generator
00310   if (_generator) delete _generator;
00311   if (_acceptRejectFunc) delete _acceptRejectFunc;
00312   if (_maxVar) delete _maxVar ;
00313   if (_uniIter) delete _uniIter ;
00314 }
00315 
00316 
00317 
00318 //_____________________________________________________________________________
00319 void RooGenContext::attach(const RooArgSet& args) 
00320 {
00321   // Attach the cloned model to the event buffer we will be filling.
00322   
00323   _pdfClone->recursiveRedirectServers(args,kFALSE);
00324   if (_acceptRejectFunc) {
00325     _acceptRejectFunc->recursiveRedirectServers(args,kFALSE) ; // WVE DEBUG
00326   }
00327 
00328   // Attach the RooAcceptReject generator the event buffer
00329   if (_generator) {
00330     _generator->attachParameters(args) ;
00331   }
00332 
00333 }
00334 
00335 
00336 
00337 //_____________________________________________________________________________
00338 void RooGenContext::initGenerator(const RooArgSet &theEvent) 
00339 {
00340   // Perform one-time initialization of the generator context
00341   
00342   attach(theEvent) ;
00343 
00344   // Reset the cloned model's error counters.
00345   _pdfClone->resetErrorCounters();
00346 
00347   // Initialize the PDFs internal generator
00348   if (_directVars.getSize()>0) {
00349     cxcoutD(Generation) << "RooGenContext::initGenerator() initializing internal generator of model with code " << _code << endl ;
00350     _pdfClone->initGenerator(_code) ;
00351   }
00352 
00353   // Create iterator for uniform vars (if any)
00354   if (_uniformVars.getSize()>0) {
00355     _uniIter = _uniformVars.createIterator() ;
00356   }
00357 }
00358 
00359 
00360 //_____________________________________________________________________________
00361 void RooGenContext::generateEvent(RooArgSet &theEvent, Int_t remaining) 
00362 {
00363   // Generate one event. The 'remaining' integer is not used other than
00364   // for printing messages 
00365 
00366   if(_otherVars.getSize() > 0) {
00367     // call the accept-reject generator to generate its variables
00368 
00369     if (_updateFMaxPerEvent!=0) {
00370       Double_t max = _pdfClone->maxVal(_updateFMaxPerEvent)/_pdfClone->getNorm(_otherVars) ;
00371       cxcoutD(Generation) << "RooGenContext::initGenerator() reevaluation of maximum function value is required for each event, new value is  " << max << endl ;
00372       _maxVar->setVal(max) ;
00373     }
00374 
00375     if (_generator) {
00376       Double_t resampleRatio(1) ;
00377       const RooArgSet *subEvent= _generator->generateEvent(remaining,resampleRatio);
00378       if (resampleRatio<1) {
00379         coutI(Generation) << "RooGenContext::generateEvent INFO: accept/reject generator requests resampling of previously produced events by factor " 
00380                           << resampleRatio << " due to increased maximum weight" << endl ; 
00381         resampleData(resampleRatio) ;
00382       }
00383       if(0 == subEvent) {
00384         coutE(Generation) << "RooGenContext::generateEvent ERROR accept/reject generator failed" << endl ;
00385         return;
00386       }
00387       theEvent= *subEvent;
00388       
00389     }
00390   }
00391 
00392   // Use the model's optimized generator, if one is available.
00393   // The generator writes directly into our local 'event' since we attached it above.
00394   if(_directVars.getSize() > 0) {
00395     _pdfClone->generateEvent(_code);
00396   }
00397 
00398   // Generate uniform variables (non-dependents)  
00399   if (_uniIter) {
00400     _uniIter->Reset() ;
00401     RooAbsArg* uniVar ;
00402     while((uniVar=(RooAbsArg*)_uniIter->Next())) {
00403       RooAbsLValue* arglv = dynamic_cast<RooAbsLValue*>(uniVar) ;
00404       if (!arglv) {
00405         coutE(Generation) << "RooGenContext::generateEvent(" << GetName() << ") ERROR: uniform variable " << uniVar->GetName() << " is not an lvalue" << endl ;
00406         RooErrorHandler::softAbort() ;
00407       }
00408       arglv->randomize() ;
00409     }
00410     theEvent = _uniformVars ;
00411   }
00412 
00413 }
00414 
00415 
00416 //_____________________________________________________________________________
00417 void RooGenContext::printMultiline(ostream &os, Int_t content, Bool_t verbose, TString indent) const
00418 {
00419   // Printing interface
00420 
00421   RooAbsGenContext::printMultiline(os,content,verbose,indent);
00422   os << indent << " --- RooGenContext --- " << endl ;
00423   os << indent << "Using PDF ";
00424   _pdfClone->printStream(os,kName|kArgs|kClassName,kSingleLine,indent);
00425   
00426   if(verbose) {
00427     os << indent << "Use PDF generator for " << _directVars << endl ;
00428     os << indent << "Use MC sampling generator " << (_generator ? _generator->IsA()->GetName() : "<none>") << " for " << _otherVars << endl ;
00429     if (_protoVars.getSize()>0) {
00430       os << indent << "Prototype observables are " << _protoVars << endl ;
00431     }
00432   }
00433 }

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