Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooMCIntegrator.cxx
Go to the documentation of this file.
1/// \cond ROOFIT_INTERNAL
2
3/*****************************************************************************
4 * Project: RooFit *
5 * Package: RooFitCore *
6 * @(#)root/roofitcore:$Id$
7 * Authors: *
8 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
9 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
10 * *
11 * Copyright (c) 2000-2005, Regents of the University of California *
12 * and Stanford University. All rights reserved. *
13 * *
14 * Redistribution and use in source and binary forms, *
15 * with or without modification, are permitted according to the terms *
16 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
17 *****************************************************************************/
18
19/**
20\file RooMCIntegrator.cxx
21\class RooMCIntegrator
22\ingroup Roofitcore
23
24Implements an adaptive multi-dimensional Monte Carlo
25numerical integration, following the VEGAS algorithm originally described
26in G. P. Lepage, J. Comp. Phys. 27, 192(1978). This implementation is
27based on a C version from the 0.9 beta release of the GNU scientific library.
28**/
29
30#include "RooMCIntegrator.h"
31#include "RooArgSet.h"
32#include "RooNumIntFactory.h"
33#include "RooRealVar.h"
34#include "RooCategory.h"
35#include "RooMsgService.h"
36
37#include <cmath>
38#include <ostream>
39
40using std::endl;
41
42
43// Register this class with RooNumIntFactory
44
45
46////////////////////////////////////////////////////////////////////////////////
47/// This function registers class RooMCIntegrator, its configuration options
48/// and its capabilities with RooNumIntFactory
49
50void RooMCIntegrator::registerIntegrator(RooNumIntFactory& fact)
51{
52 RooCategory samplingMode("samplingMode","Sampling Mode") ;
53 samplingMode.defineType("Importance",RooMCIntegrator::Importance) ;
54 samplingMode.defineType("ImportanceOnly",RooMCIntegrator::ImportanceOnly) ;
55 samplingMode.defineType("Stratified",RooMCIntegrator::Stratified) ;
56 samplingMode.setIndex(RooMCIntegrator::Importance) ;
57
58 RooCategory genType("genType","Generator Type") ;
59 genType.defineType("QuasiRandom",RooMCIntegrator::QuasiRandom) ;
60 genType.defineType("PseudoRandom",RooMCIntegrator::PseudoRandom) ;
61 genType.setIndex(RooMCIntegrator::QuasiRandom) ;
62
63 RooCategory verbose("verbose","Verbose flag") ;
64 verbose.defineType("true",1) ;
65 verbose.defineType("false",0) ;
66 verbose.setIndex(0) ;
67
68 RooRealVar alpha("alpha","Grid structure constant",1.5) ;
69 RooRealVar nRefineIter("nRefineIter","Number of refining iterations",5) ;
70 RooRealVar nRefinePerDim("nRefinePerDim","Number of refining samples (per dimension)",1000) ;
71 RooRealVar nIntPerDim("nIntPerDim","Number of integration samples (per dimension)",5000) ;
72
73 // Create prototype integrator
74 auto creator = [](const RooAbsFunc& function, const RooNumIntConfig& config) {
75 return std::make_unique<RooMCIntegrator>(function,config);
76 };
77
78 // Register prototype and default config with factory
79 std::string name = "RooMCIntegrator";
81 /*canIntegrate1D=*/true,
82 /*canIntegrate2D=*/true,
83 /*canIntegrateND=*/true,
84 /*canIntegrateOpenEnded=*/false);
85
86 // Make this method the default for all N>2-dim integrals
87 RooNumIntConfig::defaultConfig().methodND().setLabel(name) ;
88}
89
90
91////////////////////////////////////////////////////////////////////////////////
92/// Construct an integrator over 'function' with given sampling mode
93/// and generator type. The sampling mode can be 'Importance'
94/// (default), 'ImportanceOnly' and 'Stratified'. The generator type
95/// can be 'QuasiRandom' (default) and 'PseudoRandom'. Consult the original
96/// VEGAS documentation on details of the mode and type parameters.
97
98RooMCIntegrator::RooMCIntegrator(const RooAbsFunc& function, SamplingMode mode,
99 GeneratorType genType, bool verbose) :
100 RooAbsIntegrator(function), _grid(function), _verbose(verbose),
101 _alpha(1.5), _mode(mode), _genType(genType),
103{
104 // coverity[UNINIT_CTOR]
105 if(!(_valid= _grid.isValid())) return;
106 if(_verbose) _grid.print(std::cout);
107}
108
109
110
111////////////////////////////////////////////////////////////////////////////////
112/// Construct an integrator over 'function' where the configuration details
113/// are taken from 'config'
114
115RooMCIntegrator::RooMCIntegrator(const RooAbsFunc& function, const RooNumIntConfig& config) :
116 RooAbsIntegrator(function), _grid(function)
117{
118 const RooArgSet& configSet = config.getConfigSection("RooMCIntegrator") ;
119 _verbose = (bool) configSet.getCatIndex("verbose",0) ;
120 _alpha = configSet.getRealValue("alpha",1.5) ;
121 _mode = (SamplingMode) configSet.getCatIndex("samplingMode",Importance) ;
122 _genType = (GeneratorType) configSet.getCatIndex("genType",QuasiRandom) ;
123 _nRefineIter = (Int_t) configSet.getRealValue("nRefineIter",5) ;
124 _nRefinePerDim = (Int_t) configSet.getRealValue("nRefinePerDim",1000) ;
125 _nIntegratePerDim = (Int_t) configSet.getRealValue("nIntPerDim",5000) ;
126
127 // check that our grid initialized without errors
128 if(!(_valid= _grid.isValid())) return;
129 if(_verbose) _grid.print(std::cout);
130}
131
132////////////////////////////////////////////////////////////////////////////////
133/// Check if we can integrate over the current domain. If return value
134/// is true we cannot handle the current limits (e.g. where the domain
135/// of one or more observables is open ended.
136
137bool RooMCIntegrator::checkLimits() const
138{
139 return _grid.initialize(*integrand());
140}
141
142
143
144////////////////////////////////////////////////////////////////////////////////
145/// Evaluate the integral using a fixed number of calls to evaluate the integrand
146/// equal to about 10k per dimension. Use the first 5k calls to refine the grid
147/// over 5 iterations of 1k calls each, and the remaining 5k calls for a single
148/// high statistics integration.
149
150double RooMCIntegrator::integral(const double* /*yvec*/)
151{
152 _timer.Start(true);
153 vegas(AllStages,_nRefinePerDim*_grid.getDimension(),_nRefineIter);
154 double ret = vegas(ReuseGrid,_nIntegratePerDim*_grid.getDimension(),1);
155 return ret ;
156}
157
158
159
160////////////////////////////////////////////////////////////////////////////////
161/// Perform one step of Monte Carlo integration using the specified number of iterations
162/// with (approximately) the specified number of integrand evaluation calls per iteration.
163/// Use the VEGAS algorithm, starting from the specified stage. Returns the best estimate
164/// of the integral. Also sets *absError to the estimated absolute error of the integral
165/// estimate if absError is non-zero.
166
167double RooMCIntegrator::vegas(Stage stage, UInt_t calls, UInt_t iterations, double *absError)
168{
169 //cout << "VEGAS stage = " << stage << " calls = " << calls << " iterations = " << iterations << std::endl ;
170
171 // reset the grid to its initial state if we are starting from scratch
172 if(stage == AllStages) _grid.initialize(*_function);
173
174 // reset the results of previous calculations on this grid, but reuse the grid itself.
175 if(stage <= ReuseGrid) {
176 _wtd_int_sum = 0;
177 _sum_wgts = 0;
178 _chi_sum = 0;
179 _it_num = 1;
180 _samples = 0;
181 }
182
183 // refine the results of previous calculations on the current grid.
184 if(stage <= RefineGrid) {
185 UInt_t bins = RooGrid::maxBins;
186 UInt_t boxes = 1;
187 UInt_t dim(_grid.getDimension());
188
189 // select the sampling mode for the next step
190 if(_mode != ImportanceOnly) {
191 // calculate the largest number of equal subdivisions ("boxes") along each
192 // axis that results in an average of no more than 2 integrand calls per cell
193 boxes = (UInt_t)floor(std::pow(calls/2.0,1.0/dim));
194 // use stratified sampling if we are allowed enough calls (or equivalently,
195 // if the dimension is low enough)
196 _mode = Importance;
197 if (2*boxes >= RooGrid::maxBins) {
198 _mode = Stratified;
199 // adjust the number of bins and boxes to give an integral number >= 1 of boxes per bin
200 Int_t box_per_bin= (boxes > RooGrid::maxBins) ? boxes/RooGrid::maxBins : 1;
201 bins= boxes/box_per_bin;
202 if(bins > RooGrid::maxBins) bins= RooGrid::maxBins;
203 boxes = box_per_bin * bins;
204 oocxcoutD((TObject*)nullptr,Integration) << "RooMCIntegrator: using stratified sampling with " << bins << " bins and "
205 << box_per_bin << " boxes/bin" << std::endl;
206 }
207 else {
208 oocxcoutD((TObject*)nullptr,Integration) << "RooMCIntegrator: using importance sampling with " << bins << " bins and "
209 << boxes << " boxes" << std::endl;
210 }
211 }
212
213 // calculate the total number of n-dim boxes for this step
214 double tot_boxes = std::pow((double)boxes,(double)dim);
215
216 // increase the total number of calls to get at least 2 calls per box, if necessary
220
221 // calculate the Jacobean factor: volume/(avg # of calls/bin)
222 _jac = _grid.getVolume()*std::pow((double)bins,(double)dim)/calls;
223
224 // setup our grid to use the calculated number of boxes and bins
225 _grid.setNBoxes(boxes);
226 if(bins != _grid.getNBins()) _grid.resize(bins);
227 }
228
229 // allocate memory for some book-keeping arrays
230 std::vector<UInt_t> box(_grid.getDimension());
231 std::vector<UInt_t> bin(_grid.getDimension());
232 std::vector<double> x(_grid.getDimension());
233
234
235 // loop over iterations for this step
236 double cum_int(0);
237 double cum_sig(0);
239 _chisq = 0.0;
240 for (UInt_t it = 0; it < iterations; it++) {
241 double intgrl(0);
242 double intgrl_sq(0);
243 double sig(0);
244 double jacbin(_jac);
245
246 _it_num = _it_start + it;
247
248 // reset the values associated with each grid cell
249 _grid.resetValues();
250
251 // loop over grid boxes
252 _grid.firstBox(box.data());
253 do {
254 double m(0);
255 double q(0);
256 // loop over integrand evaluations within this grid box
257 for(UInt_t k = 0; k < _calls_per_box; k++) {
258 // generate a random point in this box
259 double bin_vol(0);
260 _grid.generatePoint(box.data(), x.data(), bin.data(), bin_vol, _genType == QuasiRandom ? true : false);
261 // evaluate the integrand at the generated point
262 double fval= jacbin*bin_vol*integrand(x.data());
263 // update mean and variance calculations
264 double d = fval - m;
265 m+= d / (k + 1.0);
266 q+= d * d * (k / (k + 1.0));
267 // accumulate the results of this evaluation (importance sampling only)
268 if (_mode != Stratified) _grid.accumulate(bin.data(), fval*fval);
269 }
271 double f_sq_sum = q * _calls_per_box ;
272 sig += f_sq_sum ;
273
274 // accumulate the results for this grid box (stratified sampling only)
275 if (_mode == Stratified) _grid.accumulate(bin.data(), f_sq_sum);
276
277 // print occasional progress messages
278 if(_timer.RealTime() > 30) {
279 std::size_t index = 0;
280 std::size_t sizeOfDim = 1;
281
282 for (unsigned int i=0; i < _grid.getDimension(); ++i) {
283 index += box[i] * sizeOfDim;
284 sizeOfDim *= _grid.getNBoxes();
285 }
286 oocoutP(nullptr, Integration) << "RooMCIntegrator: still working ... iteration "
287 << it << '/' << iterations << " box " << index << "/"<< std::pow(_grid.getNBoxes(), _grid.getDimension()) << std::endl;
288 _timer.Start(true);
289 }
290 else {
291 _timer.Start(false);
292 }
293
294 } while(_grid.nextBox(box.data()));
295
296 // compute final results for this iteration
297 double wgt;
298 sig = sig / (_calls_per_box - 1.0) ;
299 if (sig > 0) {
300 wgt = 1.0 / sig;
301 }
302 else if (_sum_wgts > 0) {
304 }
305 else {
306 wgt = 0.0;
307 }
309 _result = intgrl;
310 _sigma = sqrt(sig);
311
312 if (wgt > 0.0) {
313 _samples++ ;
314 _sum_wgts += wgt;
317
319 cum_sig = sqrt (1 / _sum_wgts);
320
321 if (_samples > 1) {
323 }
324 }
325 else {
326 cum_int += (intgrl - cum_int) / (it + 1.0);
327 cum_sig = 0.0;
328 }
329 oocxcoutD((TObject*)nullptr,Integration) << "=== Iteration " << _it_num << " : I = " << intgrl << " +/- " << sqrt(sig) << std::endl
330 << " Cumulative : I = " << cum_int << " +/- " << cum_sig << "( chi2 = " << _chisq
331 << ")" << std::endl;
332 // print the grid after the final iteration
333 if (oodologD((TObject*)nullptr,Integration)) {
334 if(it + 1 == iterations) _grid.print(std::cout, true);
335 }
336 _grid.refine(_alpha);
337 }
338
340 return cum_int;
341}
342
343/// \endcond
#define d(i)
Definition RSha256.hxx:102
#define oocxcoutD(o, a)
#define oodologD(o, a)
#define oocoutP(o, a)
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:61
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char mode
char name[80]
Definition TGX11.cxx:142
float * q
Abstract interface for evaluating a real-valued function of one real variable and performing numerica...
Definition RooAbsFunc.h:27
Abstract interface for integrators of real-valued functions that implement the RooAbsFunc interface.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Object to represent discrete states.
Definition RooCategory.h:28
Holds the configuration parameters of the various numeric integrators used by RooRealIntegral.
const RooArgSet & getConfigSection(const char *name) const
Retrieve configuration information specific to integrator with given name.
static RooNumIntConfig & defaultConfig()
Return reference to instance of default numeric integrator configuration object.
Factory to instantiate numeric integrators from a given function binding and a given configuration.
Variable that can be changed from the outside.
Definition RooRealVar.h:37
Mother of all ROOT objects.
Definition TObject.h:42
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition fillpatterns.C:1
Double_t x[n]
Definition legend1.C:17
TMarker m
Definition textangle.C:8