Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooAcceptReject.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8 * *
9 * Copyright (c) 2000-2005, Regents of the University of California *
10 * and Stanford University. All rights reserved. *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17/**
18\file RooAcceptReject.cxx
19\class RooAcceptReject
20\ingroup Roofitcore
21
22Class RooAcceptReject is a generic toy monte carlo generator implement
23the accept/reject sampling technique on any positively valued function.
24The RooAcceptReject generator is used by the various generator context
25classes to take care of generation of observables for which p.d.fs
26do not define internal methods
27**/
28
29#include "Riostream.h"
30
31#include "RooAcceptReject.h"
32#include "RooAbsReal.h"
33#include "RooCategory.h"
34#include "RooRealVar.h"
35#include "RooDataSet.h"
36#include "RooRandom.h"
37#include "RooErrorHandler.h"
38#include "RooPrintable.h"
39#include "RooMsgService.h"
40#include "RooRealBinding.h"
41#include "RooNumGenFactory.h"
42#include "RooNumGenConfig.h"
43
44#include "TFoam.h"
45#include "TNamed.h"
46
47#include <cassert>
48
49using namespace std;
50
51
52////////////////////////////////////////////////////////////////////////////////
53/// Register RooIntegrator1D, is parameters and capabilities with RooNumIntFactory
54
56{
57 RooRealVar nTrial0D("nTrial0D","Number of trial samples for cat-only generation",100,0,1e9) ;
58 RooRealVar nTrial1D("nTrial1D","Number of trial samples for 1-dim generation",1000,0,1e9) ;
59 RooRealVar nTrial2D("nTrial2D","Number of trial samples for 2-dim generation",100000,0,1e9) ;
60 RooRealVar nTrial3D("nTrial3D","Number of trial samples for N-dim generation",10000000,0,1e9) ;
61
63 fact.storeProtoSampler(proto,RooArgSet(nTrial0D,nTrial1D,nTrial2D,nTrial3D)) ;
64}
65
66
67
68////////////////////////////////////////////////////////////////////////////////
69/// Initialize an accept-reject generator for the specified distribution function,
70/// which must be non-negative but does not need to be normalized over the
71/// variables to be generated, genVars. The function and its dependents are
72/// cloned and so will not be disturbed during the generation process.
73
74RooAcceptReject::RooAcceptReject(const RooAbsReal &func, const RooArgSet &genVars, const RooNumGenConfig& config, bool verbose, const RooAbsReal* maxFuncVal) :
75 RooAbsNumGenerator(func,genVars,verbose,maxFuncVal)
76{
77 _minTrialsArray[0] = static_cast<Int_t>(config.getConfigSection("RooAcceptReject").getRealValue("nTrial0D")) ;
78 _minTrialsArray[1] = static_cast<Int_t>(config.getConfigSection("RooAcceptReject").getRealValue("nTrial1D")) ;
79 _minTrialsArray[2] = static_cast<Int_t>(config.getConfigSection("RooAcceptReject").getRealValue("nTrial2D")) ;
80 _minTrialsArray[3] = static_cast<Int_t>(config.getConfigSection("RooAcceptReject").getRealValue("nTrial3D")) ;
81
83 _catSampleMult = 1 ;
84 for (auto * cat : static_range_cast<RooAbsCategory*>(_catVars)) {
85 _catSampleMult *= cat->numTypes() ;
86 }
87
88
89 // calculate the minimum number of trials needed to estimate our integral and max value
90 if (!_funcMaxVal) {
91
92 if(_realSampleDim > 3) {
94 oocoutW(nullptr, Generation) << _funcClone->GetName() << "::RooAcceptReject" << ": WARNING: generating " << _realSampleDim
95 << " variables with accept-reject may not be accurate" << endl;
96 }
97 else {
99 }
100 if (_realSampleDim > 1) {
101 oocoutW(nullptr, Generation) << "RooAcceptReject::ctor(" << _funcClone->GetName()
102 << ") WARNING: performing accept/reject sampling on a p.d.f in "
103 << _realSampleDim << " dimensions without prior knowledge on maximum value "
104 << "of p.d.f. Determining maximum value by taking " << _minTrials
105 << " trial samples. If p.d.f contains sharp peaks smaller than average "
106 << "distance between trial sampling points these may be missed and p.d.f. "
107 << "may be sampled incorrectly." << endl ;
108 }
109 } else {
110 // No trials needed if we know the maximum a priori
111 _minTrials=0 ;
112 }
113
114 // Need to fix some things here
115 if (_minTrials>10000) {
116 oocoutW(nullptr, Generation) << "RooAcceptReject::ctor(" << func.GetName() << "): WARNING: " << _minTrials << " trial samples requested by p.d.f for "
117 << _realSampleDim << "-dimensional accept/reject sampling, this may take some time" << endl ;
118 }
119
120 // print a verbose summary of our configuration, if requested
121 if(_verbose) {
122 oocoutI(nullptr, Generation) << func.GetName() << "::RooAcceptReject" << ":" << endl
123 << " Initializing accept-reject generator for" << endl << " ";
125 if (_funcMaxVal) {
126 ooccoutI(nullptr, Generation) << " Function maximum provided, no trial sampling performed" << endl ;
127 } else {
128 ooccoutI(nullptr, Generation) << " Real sampling dimension is " << _realSampleDim << endl;
129 ooccoutI(nullptr, Generation) << " Category sampling multiplier is " << _catSampleMult << endl ;
130 ooccoutI(nullptr, Generation) << " Min sampling trials is " << _minTrials << endl;
131 }
132 if (_catVars.getSize()>0) {
133 ooccoutI(nullptr, Generation) << " Will generate category vars "<< _catVars << endl ;
134 }
135 if (_realVars.getSize()>0) {
136 ooccoutI(nullptr, Generation) << " Will generate real vars " << _realVars << endl ;
137 }
138 }
139
140 // initialize our statistics
141 _maxFuncVal= 0;
142 _funcSum= 0;
143 _totalEvents= 0;
144 _eventsUsed= 0;
145}
146
147
148////////////////////////////////////////////////////////////////////////////////
149/// Return a pointer to a generated event. The caller does not own the event and it
150/// will be overwritten by a subsequent call. The input parameter 'remaining' should
151/// contain your best guess at the total number of subsequent events you will request.
152
153const RooArgSet *RooAcceptReject::generateEvent(UInt_t remaining, double& resampleRatio)
154{
155 // are we actually generating anything? (the cache always contains at least our function value)
156 const RooArgSet *event= _cache->get();
157 if(event->getSize() == 1) return event;
158
159 if (!_funcMaxVal) {
160 // Generation with empirical maximum determination
161
162 // first generate enough events to get reasonable estimates for the integral and
163 // maximum function value
164
165 while(_totalEvents < _minTrials) {
167
168 // Limit cache size to 1M events
169 if (_cache->numEntries()>1000000) {
170 oocoutI(nullptr, Generation) << "RooAcceptReject::generateEvent: resetting event cache" << std::endl;
171 _cache->reset() ;
172 _eventsUsed = 0 ;
173 }
174 }
175
176 event= nullptr;
177 double oldMax2(_maxFuncVal);
178 while(nullptr == event) {
179 // Use any cached events first
180 if (_maxFuncVal>oldMax2) {
181 oocxcoutD(nullptr, Generation) << "RooAcceptReject::generateEvent maxFuncVal has changed, need to resample already accepted events by factor"
182 << oldMax2 << "/" << _maxFuncVal << "=" << oldMax2/_maxFuncVal << endl ;
183 resampleRatio=oldMax2/_maxFuncVal ;
184 }
185 event= nextAcceptedEvent();
186 if(event) break;
187 // When we have used up the cache, start a new cache and add
188 // some more events to it.
189 _cache->reset();
190 _eventsUsed= 0;
191 // Calculate how many more events to generate using our best estimate of our efficiency.
192 // Always generate at least one more event so we don't get stuck.
193 if(_totalEvents*_maxFuncVal <= 0) {
194 oocoutE(nullptr, Generation) << "RooAcceptReject::generateEvent: cannot estimate efficiency...giving up" << endl;
195 return nullptr;
196 }
197
198 double eff= _funcSum/(_totalEvents*_maxFuncVal);
199 Long64_t extra= 1 + (Long64_t)(1.05*remaining/eff);
200 oocxcoutD(nullptr, Generation) << "RooAcceptReject::generateEvent: adding " << extra << " events to the cache, eff = " << eff << endl;
201 double oldMax(_maxFuncVal);
202 while(extra--) {
204 if((_maxFuncVal > oldMax)) {
205 oocxcoutD(nullptr, Generation) << "RooAcceptReject::generateEvent: estimated function maximum increased from "
206 << oldMax << " to " << _maxFuncVal << endl;
207 oldMax = _maxFuncVal ;
208 // Trim cache here
209 }
210 }
211 }
212
213 // Limit cache size to 1M events
214 if (_eventsUsed>1000000) {
215 _cache->reset() ;
216 _eventsUsed = 0 ;
217 }
218
219 } else {
220 // Generation with a priori maximum knowledge
222
223 // Generate enough trials to produce a single accepted event
224 event = nullptr ;
225 while(nullptr==event) {
227 event = nextAcceptedEvent() ;
228 }
229
230 }
231 return event;
232}
233
234
235
236////////////////////////////////////////////////////////////////////////////////
237/// Scan through events in the cache which have not been used yet,
238/// looking for the first accepted one which is added to the specified
239/// container. Return a pointer to the accepted event, or else zero
240/// if we use up the cache before we accept an event. The caller does
241/// not own the event and it will be overwritten by a subsequent call.
242
244{
245 const RooArgSet *event = nullptr;
246 while((event= _cache->get(_eventsUsed))) {
247 _eventsUsed++ ;
248 // accept this cached event?
249 double r= RooRandom::uniform();
251 //cout << " event number " << _eventsUsed << " has been rejected" << endl ;
252 continue;
253 }
254 //cout << " event number " << _eventsUsed << " has been accepted" << endl ;
255 // copy this event into the output container
256 if(_verbose && (_eventsUsed%1000==0)) {
257 cerr << "RooAcceptReject: accepted event (used " << _eventsUsed << " of "
258 << _cache->numEntries() << " so far)" << endl;
259 }
260 break;
261 }
262 //cout << "accepted event " << _eventsUsed << " of " << _cache->numEntries() << endl ;
263 return event;
264}
265
266
267
268////////////////////////////////////////////////////////////////////////////////
269/// Add a trial event to our cache and update our estimates
270/// of the function maximum value and integral.
271
273{
274 // randomize each discrete argument
275 for(auto * cat : static_range_cast<RooCategory*>(_catVars)) cat->randomize();
276
277 // randomize each real argument
278 for(auto * real : static_range_cast<RooRealVar*>(_realVars)) real->randomize();
279
280 // calculate and store our function value at this new point
281 double val= _funcClone->getVal();
282 _funcValPtr->setVal(val);
283
284 // Update the estimated integral and maximum value. Increase our
285 // maximum estimate slightly to give a safety margin with a
286 // corresponding loss of efficiency.
287 if(val > _maxFuncVal) _maxFuncVal= 1.05*val;
288 _funcSum+= val;
289
290 // fill a new entry in our cache dataset for this point
291 _cache->fill();
292 _totalEvents++;
293
294 if (_verbose &&_totalEvents%10000==0) {
295 cerr << "RooAcceptReject: generated " << _totalEvents << " events so far." << endl ;
296 }
297
298}
299
301{
302 // Empirically determine maximum value of function by taking a large number
303 // of samples. The actual number depends on the number of dimensions in which
304 // the sampling occurs
305
306 // Generate the minimum required number of samples for a reliable maximum estimate
307 while(_totalEvents < _minTrials) {
309
310 // Limit cache size to 1M events
311 if (_cache->numEntries()>1000000) {
312 oocoutI(nullptr, Generation) << "RooAcceptReject::getFuncMax: resetting event cache" << endl ;
313 _cache->reset() ;
314 _eventsUsed = 0 ;
315 }
316 }
317
318 return _maxFuncVal ;
319}
320
321std::string const& RooAcceptReject::generatorName() const {
322 static const std::string name = "RooAcceptReject";
323 return name;
324}
#define oocoutW(o, a)
#define oocxcoutD(o, a)
#define oocoutE(o, a)
#define oocoutI(o, a)
#define ooccoutI(o, a)
long long Long64_t
Definition RtypesCore.h:80
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
char name[80]
Definition TGX11.cxx:110
const char * proto
Definition civetweb.c:17536
double getRealValue(const char *name, double defVal=0.0, bool verbose=false) const
Get value of a RooAbsReal stored in set with given name.
Storage_t const & get() const
Const access to the underlying stl container.
Int_t getSize() const
Return the number of elements in the collection.
Class RooAbsNumGenerator is the abstract base class for MC event generator implementations like RooAc...
RooArgSet _catVars
Set of discrete observabeles.
RooArgSet _realVars
Set of real valued observabeles.
const RooAbsReal * _funcMaxVal
Container for maximum function value.
RooAbsReal * _funcClone
Pointer to top level node of cloned function.
bool _verbose
Verbose flag.
RooRealVar * _funcValPtr
RRV storing function value in output dataset.
std::unique_ptr< RooDataSet > _cache
Dataset holding generared values of observables.
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:59
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:103
Class RooAcceptReject is a generic toy monte carlo generator implement the accept/reject sampling tec...
UInt_t _minTrialsArray[4]
Minimum number of trials samples for 1,2,3 dimensional problems.
UInt_t _minTrials
Minimum number of max.finding trials, total number of samples.
static void registerSampler(RooNumGenFactory &fact)
Register RooIntegrator1D, is parameters and capabilities with RooNumIntFactory.
double getFuncMax() override
const RooArgSet * nextAcceptedEvent()
Scan through events in the cache which have not been used yet, looking for the first accepted one whi...
void addEventToCache()
Add a trial event to our cache and update our estimates of the function maximum value and integral.
double _funcSum
Maximum function value found, and sum of all samples made.
std::string const & generatorName() const override
Return unique name of generator implementation.
UInt_t _totalEvents
Total number of function samples.
UInt_t _catSampleMult
Number of real and discrete dimensions to be sampled.
const RooArgSet * generateEvent(UInt_t remaining, double &resampleRatio) override
Return a pointer to a generated event.
UInt_t _eventsUsed
Accepted number of function samples.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
RooNumGenConfig holds the configuration parameters of the various numeric integrators used by RooReal...
const RooArgSet & getConfigSection(const char *name) const
Retrieve configuration information specific to integrator with given name.
RooNumGenFactory is a factory to instantiate numeric integrators from a given function binding and a ...
bool storeProtoSampler(RooAbsNumGenerator *proto, const RooArgSet &defConfig)
Method accepting registration of a prototype numeric integrator along with a RooArgSet of its default...
virtual void printStream(std::ostream &os, Int_t contents, StyleOption style, TString indent="") const
Print description of object on ostream, printing contents set by contents integer,...
static double uniform(TRandom *generator=randomGenerator())
Return a number uniformly distributed from (0,1)
Definition RooRandom.cxx:81
RooRealVar represents a variable that can be changed from the outside.
Definition RooRealVar.h:37
void setVal(double value) override
Set value of variable to 'value'.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47