Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooNDKeysPdf.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitModels *
4 * File: $Id: RooNDKeysPdf.cxx 31258 2009-11-17 22:41:06Z wouter $
5 * Authors: *
6 * Max Baak, CERN, mbaak@cern.ch *
7 * *
8 * Redistribution and use in source and binary forms, *
9 * with or without modification, are permitted according to the terms *
10 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
11 *****************************************************************************/
12
13/** \class RooNDKeysPdf
14 \ingroup Roofit
15
16Generic N-dimensional implementation of a kernel estimation p.d.f. This p.d.f. models the distribution
17of an arbitrary input dataset as a superposition of Gaussian kernels, one for each data point,
18each contributing 1/N to the total integral of the p.d.f.
19If the 'adaptive mode' is enabled, the width of the Gaussian is adaptively calculated from the
20local density of events, i.e. narrow for regions with high event density to preserve details and
21wide for regions with log event density to promote smoothness. The details of the general algorithm
22are described in the following paper:
23Cranmer KS, Kernel Estimation in High-Energy Physics.
24 Computer Physics Communications 136:198-207,2001 - e-Print Archive: hep ex/0011057
25For multi-dimensional datasets, the kernels are modeled by multidimensional Gaussians. The kernels are
26constructed such that they reflect the correlation coefficients between the observables
27in the input dataset.
28**/
29
30#include <iostream>
31#include <algorithm>
32#include <string>
33
34#include "TMath.h"
35#include "TMatrixDSymEigen.h"
36#include "RooNDKeysPdf.h"
37#include "RooRealVar.h"
38#include "RooRandom.h"
39#include "RooHist.h"
40#include "RooMsgService.h"
41#include "RooChangeTracker.h"
42
43#include "TError.h"
44
45using std::cout, std::endl, std::string, std::vector, std::pair, std::map;
46
48
49////////////////////////////////////////////////////////////////////////////////
50/// Construct N-dimensional kernel estimation p.d.f. in observables 'varList'
51/// from dataset 'data'. Options can be
52///
53/// - 'a' = Use adaptive kernels (width varies with local event density)
54/// - 'm' = Mirror data points over observable boundaries. Improves modeling
55/// behavior at edges for distributions that are not close to zero
56/// at edge
57/// - 'd' = Debug flag
58/// - 'v' = Verbose flag
59///
60/// The parameter rho (default = 1) provides an overall scale factor that can
61/// be applied to the bandwidth calculated for each kernel. The nSigma parameter
62/// determines the size of the box that is used to search for contributing kernels
63/// around a given point in observable space. The nSigma parameters is used
64/// in case of non-adaptive bandwidths and for the 1st non-adaptive pass for
65/// the calculation of adaptive keys p.d.f.s.
66///
67/// The optional weight arguments allows to specify an observable or function
68/// expression in observables that specifies the weight of each event.
69
70RooNDKeysPdf::RooNDKeysPdf(const char *name, const char *title, const RooArgList &varList, const RooDataSet &data,
71 TString options, double rho, double nSigma, bool rotate, bool sortInput)
72 : RooAbsPdf(name, title), _varList("varList", "List of variables", this),
73 _rhoList("rhoList", "List of rho parameters", this), _options(options), _widthFactor(rho),
74 _nSigma(nSigma), _rotate(rotate), _sortInput(sortInput), _nAdpt(1)
75{
77
78 createPdf(true, data);
79}
80
81////////////////////////////////////////////////////////////////////////////////
82/// Constructor
83
84RooNDKeysPdf::RooNDKeysPdf(const char *name, const char *title, const RooArgList &varList, const TH1 &hist,
85 TString options, double rho, double nSigma, bool rotate, bool sortInput)
86 : RooAbsPdf(name, title), _varList("varList", "List of variables", this),
87 _rhoList("rhoList", "List of rho parameters", this),
88 _options(options), _widthFactor(rho), _nSigma(nSigma), _rotate(rotate),
89 _sortInput(sortInput), _nAdpt(1)
90{
92
93 createPdf(true, *std::unique_ptr<RooDataSet>{createDatasetFromHist(varList, hist)});
94}
95
96////////////////////////////////////////////////////////////////////////////////
97/// Constructor
98
99RooNDKeysPdf::RooNDKeysPdf(const char *name, const char *title, const RooArgList &varList, const RooDataSet &data,
100 const TVectorD &rho, TString options, double nSigma, bool rotate, bool sortInput)
101 : RooAbsPdf(name, title), _varList("varList", "List of variables", this),
102 _rhoList("rhoList", "List of rho parameters", this), _options(options), _widthFactor(-1.0),
103 _nSigma(nSigma), _rotate(rotate), _sortInput(sortInput), _nAdpt(1)
104{
105 _varList.addTyped<RooAbsReal>(varList);
106
107 // copy rho widths
108 if(int( _varList.size()) != rho.GetNrows() ) {
109 coutE(InputArguments)
110 << "ERROR: RooNDKeysPdf::RooNDKeysPdf() : The vector-size of rho is different from that of varList."
111 << "Unable to create the PDF." << endl;
112 R__ASSERT(int(_varList.size()) == rho.GetNrows());
113 }
114
115 // negative width factor will serve as a switch in initialize()
116 // negative value means that a vector has been provided as input,
117 // and that _rho has already been set ...
118 _rho.resize( rho.GetNrows() );
119 for (Int_t j = 0; j < rho.GetNrows(); j++) {
120 _rho[j] = rho[j]; /*cout<<"RooNDKeysPdf ctor, _rho["<<j<<"]="<<_rho[j]<<endl;*/
121 }
122
123 createPdf(true, data); // calls initialize ...
124}
125
126////////////////////////////////////////////////////////////////////////////////
127/// Backward compatibility constructor for (1-dim) RooKeysPdf. If you are a new user,
128/// please use the first constructor form.
129
130RooNDKeysPdf::RooNDKeysPdf(const char *name, const char *title, const RooArgList &varList, const RooDataSet &data,
131 const RooArgList &rhoList, TString options, double nSigma, bool rotate, bool sortInput)
132 : RooAbsPdf(name, title), _varList("varList", "List of variables", this),
133 _rhoList("rhoList", "List of rho parameters", this), _options(options), _widthFactor(-1.0),
134 _nSigma(nSigma), _rotate(rotate), _sortInput(sortInput), _nAdpt(1)
135{
136 _varList.addTyped<RooAbsReal>(varList);
137
138 _rho.resize(rhoList.size(), 1.0);
139
140 for (unsigned int i=0; i < rhoList.size(); ++i) {
141 const auto rho = rhoList.at(i);
142 if (!dynamic_cast<const RooAbsReal *>(rho)) {
143 coutE(InputArguments) << "RooNDKeysPdf::ctor(" << GetName() << ") ERROR: parameter " << rho->GetName()
144 << " is not of type RooRealVar" << endl;
145 assert(0);
146 }
147 _rhoList.add(*rho);
148 _rho[i] = (dynamic_cast<RooAbsReal *>(rho))->getVal();
149 }
150
151 // copy rho widths
152 if ((_varList.size() != _rhoList.size())) {
153 coutE(InputArguments) << "ERROR: RooNDKeysPdf::RooNDKeysPdf() : The size of rhoList is different from varList."
154 << "Unable to create the PDF." << endl;
155 assert(_varList.size() == _rhoList.size());
156 }
157
158 // keep track of changes in rho parameters
159 _tracker = new RooChangeTracker("tracker", "track rho parameters", _rhoList, true); // check for value updates
160 (void)_tracker->hasChanged(true); // first evaluation always true for new parameters (?)
161
162 createPdf(true, data);
163}
164
165////////////////////////////////////////////////////////////////////////////////
166/// Constructor
167
168RooNDKeysPdf::RooNDKeysPdf(const char *name, const char *title, const RooArgList &varList, const TH1 &hist,
169 const RooArgList &rhoList, TString options, double nSigma, bool rotate, bool sortInput)
170 : RooAbsPdf(name, title), _varList("varList", "List of variables", this),
171 _rhoList("rhoList", "List of rho parameters", this),
172 _options(options), _widthFactor(-1), _nSigma(nSigma), _rotate(rotate), _sortInput(sortInput),
173 _nAdpt(1)
174{
175 _varList.addTyped<RooAbsReal>(varList);
176
177 // copy rho widths
178 _rho.resize(rhoList.size(), 1.0);
179
180 for (unsigned int i=0; i < rhoList.size(); ++i) {
181 const auto rho = rhoList.at(i);
182 if (!dynamic_cast<RooAbsReal *>(rho)) {
183 coutE(InputArguments) << "RooNDKeysPdf::ctor(" << GetName() << ") ERROR: parameter " << rho->GetName()
184 << " is not of type RooRealVar" << endl;
185 assert(0);
186 }
187 _rhoList.add(*rho);
188 _rho[i] = (dynamic_cast<RooAbsReal *>(rho))->getVal();
189 }
190
191 if ((_varList.size() != _rhoList.size())) {
192 coutE(InputArguments) << "ERROR: RooNDKeysPdf::RooNDKeysPdf() : The size of rhoList is different from varList."
193 << "Unable to create the PDF." << endl;
194 assert(_varList.size() == _rhoList.size());
195 }
196
197 // keep track of changes in rho parameters
198 _tracker = new RooChangeTracker("tracker", "track rho parameters", _rhoList, true); // check for value updates
199 (void)_tracker->hasChanged(true); // first evaluation always true for new parameters (?)
200
201 createPdf(true, *std::unique_ptr<RooDataSet>{createDatasetFromHist(varList, hist)});
202}
203
204////////////////////////////////////////////////////////////////////////////////
205/// Constructor
206
207RooNDKeysPdf::RooNDKeysPdf(const char *name, const char *title, RooAbsReal &x, const RooDataSet &data, Mirror mirror,
208 double rho, double nSigma, bool rotate, bool sortInput)
209 : RooAbsPdf(name, title), _varList("varList", "List of variables", this),
210 _rhoList("rhoList", "List of rho parameters", this), _options("a"), _widthFactor(rho),
211 _nSigma(nSigma), _rotate(rotate), _sortInput(sortInput), _nAdpt(1)
212{
213 _varList.add(x);
214
215 if (mirror != NoMirror) {
216 if (mirror != MirrorBoth) {
217 coutW(InputArguments) << "RooNDKeysPdf::RooNDKeysPdf() : Warning : asymmetric mirror(s) no longer supported."
218 << endl;
219 }
220 _options = "m";
221 }
222
223 createPdf(true, data);
224}
225
226////////////////////////////////////////////////////////////////////////////////
227/// Backward compatibility constructor for Roo2DKeysPdf. If you are a new user,
228/// please use the first constructor form.
229
230RooNDKeysPdf::RooNDKeysPdf(const char *name, const char *title, RooAbsReal &x, RooAbsReal &y, const RooDataSet &data,
231 TString options, double rho, double nSigma, bool rotate, bool sortInput)
232 : RooAbsPdf(name, title), _varList("varList", "List of variables", this),
233 _rhoList("rhoList", "List of rho parameters", this), _options(options), _widthFactor(rho),
234 _nSigma(nSigma), _rotate(rotate), _sortInput(sortInput), _nAdpt(1)
235{
237
238 createPdf(true, data);
239}
240
241////////////////////////////////////////////////////////////////////////////////
242/// Constructor
243
245 : RooAbsPdf(other, name),
246 _varList("varList", this, other._varList),
247 _rhoList("rhoList", this, other._rhoList),
248 _options(other._options),
249 _widthFactor(other._widthFactor),
250 _nSigma(other._nSigma),
251 _fixedShape(other._fixedShape),
252 _mirror(other._mirror),
253 _debug(other._debug),
254 _verbose(other._verbose),
255 _nDim(other._nDim),
256 _nEvents(other._nEvents),
257 _nEventsM(other._nEventsM),
258 _nEventsW(other._nEventsW),
259 _d(other._d),
260 _n(other._n),
261 _dataPts(other._dataPts),
262 _dataPtsR(other._dataPtsR),
263 _weights0(other._weights0),
264 _weights1(other._weights1),
265 _weights(_options.Contains("a") ? &_weights1 : &_weights0),
266 _sortTVIdcs(other._sortTVIdcs),
267 _rho(other._rho),
268 _x(other._x),
269 _x0(other._x0),
270 _x1(other._x1),
271 _x2(other._x2),
272 _mean(other._mean),
273 _sigma(other._sigma),
274 _xDatLo(other._xDatLo),
275 _xDatHi(other._xDatHi),
276 _xDatLo3s(other._xDatLo3s),
277 _xDatHi3s(other._xDatHi3s),
278 _netFluxZ(other._netFluxZ),
279 _nEventsBW(other._nEventsBW),
280 _nEventsBMSW(other._nEventsBMSW),
281 _xVarLo(other._xVarLo),
282 _xVarHi(other._xVarHi),
283 _xVarLoM3s(other._xVarLoM3s),
284 _xVarLoP3s(other._xVarLoP3s),
285 _xVarHiM3s(other._xVarHiM3s),
286 _xVarHiP3s(other._xVarHiP3s),
287 _bpsIdcs(other._bpsIdcs),
288 _ibNoSort(other._ibNoSort),
289 _sIdcs(other._sIdcs),
290 _bIdcs(other._bIdcs),
291 _bmsIdcs(other._bmsIdcs),
292 _rangeBoxInfo(other._rangeBoxInfo),
293 _fullBoxInfo(other._fullBoxInfo),
294 _idx(other._idx),
295 _minWeight(other._minWeight),
296 _maxWeight(other._maxWeight),
297 _wMap(other._wMap),
298 _covMat(new TMatrixDSym(*other._covMat)),
299 _corrMat(new TMatrixDSym(*other._corrMat)),
300 _rotMat(new TMatrixD(*other._rotMat)),
301 _sigmaR(new TVectorD(*other._sigmaR)),
302 _dx(new TVectorD(*other._dx)),
303 _sigmaAvgR(other._sigmaAvgR),
304 _rotate(other._rotate),
305 _sortInput(other._sortInput),
306 _nAdpt(other._nAdpt),
307 _tracker(other._tracker != nullptr ? new RooChangeTracker(*other._tracker) : nullptr)
308{
309}
310
311////////////////////////////////////////////////////////////////////////////////
312
314{
315 if (_covMat) delete _covMat;
316 if (_corrMat) delete _corrMat;
317 if (_rotMat) delete _rotMat;
318 if (_sigmaR) delete _sigmaR;
319 if (_dx) delete _dx;
320 if (_tracker)
321 delete _tracker;
322
323 // delete all the boxinfos map
324 while ( !_rangeBoxInfo.empty() ) {
325 map<pair<string,int>,BoxInfo*>::iterator iter = _rangeBoxInfo.begin();
326 BoxInfo* box= (*iter).second;
327 _rangeBoxInfo.erase(iter);
328 delete box;
329 }
330}
331
332////////////////////////////////////////////////////////////////////////////////
333/// evaluation order of constructor.
334
335void RooNDKeysPdf::createPdf(bool firstCall, RooDataSet const& data)
336{
337 if (firstCall) {
338 // set options
339 setOptions();
340 // initialization
342 }
343
344
345 // copy dataset, calculate sigma_i's, determine min and max event weight
346 loadDataSet(firstCall, data);
347
348 // mirror dataset around dataset boundaries -- does not depend on event weights
349 if (_mirror) mirrorDataSet();
350
351 // store indices and weights of events with high enough weights
353
354 // store indices of events in variable boundaries and box shell.
355//calculateShell(&_fullBoxInfo);
356 // calculate normalization needed in analyticalIntegral()
357//calculatePreNorm(&_fullBoxInfo);
358
359 // lookup table for determining which events contribute to a certain coordinate
360 const_cast<RooNDKeysPdf*>(this)->sortDataIndices();
361
362 // determine static and/or adaptive bandwidth
364}
365
366////////////////////////////////////////////////////////////////////////////////
367/// set the configuration
368
370{
372
373 if( _options.Contains("a") ) { _weights = &_weights1; }
374 else { _weights = &_weights0; }
375 if( _options.Contains("m") ) _mirror = true;
376 else _mirror = false;
377 if( _options.Contains("d") ) _debug = true;
378 else _debug = false;
379 if( _options.Contains("v") ) { _debug = true; _verbose = true; }
380 else { _debug = false; _verbose = false; }
381
382 cxcoutD(InputArguments) << "RooNDKeysPdf::setOptions() options = " << _options
383 << "\n\tbandWidthType = " << _options.Contains("a")
384 << "\n\tmirror = " << _mirror
385 << "\n\tdebug = " << _debug
386 << "\n\tverbose = " << _verbose
387 << endl;
388
389 if (_nSigma<2.0) {
390 coutW(InputArguments) << "RooNDKeysPdf::setOptions() : Warning : nSigma = " << _nSigma << " < 2.0. "
391 << "Calculated normalization could be too large."
392 << endl;
393 }
394
395 // number of adaptive width iterations. Default is 1.
396 if (_options.Contains("a")) {
397 if (!sscanf(_options.Data(), "%d%*s", &_nAdpt)) {
398 _nAdpt = 1;
399 }
400 }
401}
402
403////////////////////////////////////////////////////////////////////////////////
404/// initialization
405
407{
408 _nDim = _varList.size();
409 _nEvents = (Int_t)data.numEntries();
411 _fixedShape= false;
412
413 _netFluxZ = false;
414 _nEventsBW = 0;
415 _nEventsBMSW = 0;
416
417 if(_nDim==0) {
418 coutE(InputArguments) << "ERROR: RooNDKeysPdf::initialize() : The observable list is empty. "
419 << "Unable to begin generating the PDF." << endl;
420 R__ASSERT (_nDim!=0);
421 }
422
423 if(_nEvents==0) {
424 coutE(InputArguments) << "ERROR: RooNDKeysPdf::initialize() : The input data set is empty. "
425 << "Unable to begin generating the PDF." << endl;
426 R__ASSERT (_nEvents!=0);
427 }
428
429 _d = static_cast<double>(_nDim);
430
431 std::vector<double> dummy(_nDim,0.);
432 _dataPts.resize(_nEvents,dummy);
433 _weights0.resize(_nEvents,dummy);
434
435 //rdh _rho.resize(_nDim,_widthFactor);
436
437 if (_widthFactor>0) { _rho.resize(_nDim,_widthFactor); }
438 // else: _rho has been provided as external input
439
440 _x.resize(_nDim,0.);
441 _x0.resize(_nDim,0.);
442 _x1.resize(_nDim,0.);
443 _x2.resize(_nDim,0.);
444
445 _mean.resize(_nDim,0.);
446 _sigma.resize(_nDim,0.);
447
448 _xDatLo.resize(_nDim,0.);
449 _xDatHi.resize(_nDim,0.);
450 _xDatLo3s.resize(_nDim,0.);
451 _xDatHi3s.resize(_nDim,0.);
452
453 boxInfoInit(&_fullBoxInfo,nullptr,0xFFFF);
454
455 _minWeight=0;
456 _maxWeight=0;
457 _wMap.clear();
458
459 _covMat = nullptr;
460 _corrMat= nullptr;
461 _rotMat = nullptr;
462 _sigmaR = nullptr;
463 _dx = new TVectorD(_nDim); _dx->Zero();
464 _dataPtsR.resize(_nEvents,*_dx);
465
466 for(unsigned int j=0; j < _varList.size(); ++j) {
467 auto& var = static_cast<const RooRealVar&>(_varList[j]);
468 _xDatLo[j] = var.getMin();
469 _xDatHi[j] = var.getMax();
470 }
471}
472
473////////////////////////////////////////////////////////////////////////////////
474/// copy the dataset and calculate some useful variables
475
476void RooNDKeysPdf::loadDataSet(bool firstCall, RooDataSet const& data)
477{
478 // first some initialization
479 _nEventsW=0.;
480
481 TMatrixD mat(_nDim,_nDim);
482 if (!_covMat) _covMat = new TMatrixDSym(_nDim);
484 if (!_rotMat) _rotMat = new TMatrixD(_nDim,_nDim);
485 if (!_sigmaR) _sigmaR = new TVectorD(_nDim);
486
487 mat.Zero();
488 _covMat->Zero();
489 _corrMat->Zero();
490 _rotMat->Zero();
491 _sigmaR->Zero();
492
493 const RooArgSet* values= data.get();
494 vector<RooRealVar*> dVars(_nDim);
495 for (Int_t j=0; j<_nDim; j++) {
496 dVars[j] = static_cast<RooRealVar*>(values->find(_varList[j].GetName()));
497 _x0[j]=_x1[j]=_x2[j]=0.;
498 }
499
500 _idx.clear();
501 for (Int_t i=0; i<_nEvents; i++) {
502
503 data.get(i); // fills dVars
504 _idx.push_back(i);
505 std::vector<double>& point = _dataPts[i];
506 TVectorD& pointV = _dataPtsR[i];
507
508 double myweight = data.weight(); // default is one?
509 if ( TMath::Abs(myweight)>_maxWeight ) { _maxWeight = TMath::Abs(myweight); }
510 _nEventsW += myweight;
511
512 for (Int_t j=0; j<_nDim; j++) {
513 for (Int_t k=0; k<_nDim; k++) {
514 mat(j,k) += dVars[j]->getVal() * dVars[k]->getVal() * myweight;
515 }
516 // only need to do once
517 if (firstCall)
518 point[j] = pointV[j] = dVars[j]->getVal();
519
520 _x0[j] += 1. * myweight;
521 _x1[j] += point[j] * myweight ;
522 _x2[j] += point[j] * point[j] * myweight ;
523 if (_x2[j]!=_x2[j]) exit(3);
524
525 // only need to do once
526 if (firstCall) {
527 if (point[j]<_xDatLo[j]) { _xDatLo[j]=point[j]; }
528 if (point[j]>_xDatHi[j]) { _xDatHi[j]=point[j]; }
529 }
530 }
531 }
532
533 _n = TMath::Power(4./(_nEventsW*(_d+2.)), 1./(_d+4.)) ;
534 // = (4/[n(dim(R) + 2)])^1/(dim(R)+4); dim(R) = 2
535 _minWeight = (0.5 - TMath::Erf(_nSigma/sqrt(2.))/2.) * _maxWeight;
536
537 for (Int_t j=0; j<_nDim; j++) {
538 _mean[j] = _x1[j]/_x0[j];
539 _sigma[j] = sqrt(_x2[j]/_x0[j]-_mean[j]*_mean[j]);
540 }
541
542 for (Int_t j=0; j<_nDim; j++) {
543 for (Int_t k=0; k<_nDim; k++) {
544 (*_covMat)(j,k) = mat(j,k)/_x0[j] - _mean[j]*_mean[k];
545 }
546 }
547
548 for (Int_t j=0; j<_nDim; j++) {
549 for (Int_t k=0; k<_nDim; k++)
550 (*_corrMat)(j,k) = (*_covMat)(j,k)/(_sigma[j]*_sigma[k]) ;
551 }
552
553 // use raw sigmas (without rho) for sigmaAvgR
554 TMatrixDSymEigen evCalculator(*_covMat);
555 TVectorD sigmaRraw = evCalculator.GetEigenValues();
556 for (Int_t j=0; j<_nDim; j++) { sigmaRraw[j] = sqrt(sigmaRraw[j]); }
557
558 _sigmaAvgR=1.;
559 for (Int_t j=0; j<_nDim; j++) { _sigmaAvgR *= sigmaRraw[j]; }
561
562 // find decorrelation matrix and eigenvalues (R)
563 if (_nDim > 1 && _rotate) {
564 // new: rotation matrix now independent of rho evaluation
565 *_rotMat = evCalculator.GetEigenVectors();
566 *_rotMat = _rotMat->T(); // transpose
567 } else {
568 TMatrixD haar(_nDim, _nDim);
569 TMatrixD unit(TMatrixD::kUnit, haar);
570 *_rotMat = unit;
571 }
572
573 // update sigmas (rho dependent)
574 updateRho();
575
576 //// rho no longer used after this.
577 //// Now set rho = 1 because sigmaR now contains rho
578 // for (Int_t j=0; j<_nDim; j++) { _rho[j] = 1.; } // reset: important!
579
580 if (_verbose) {
581 //_covMat->Print();
582 _rotMat->Print();
583 _corrMat->Print();
584 _sigmaR->Print();
585 }
586
587 if (_nDim > 1 && _rotate) {
588 // apply rotation
589 for (Int_t i = 0; i < _nEvents; i++) {
590 TVectorD &pointR = _dataPtsR[i];
591 pointR *= *_rotMat;
592 }
593 }
594
595 coutI(Contents) << "RooNDKeysPdf::loadDataSet(" << this << ")"
596 << "\n Number of events in dataset: " << _nEvents
597 << "\n Weighted number of events in dataset: " << _nEventsW << endl;
598}
599
600////////////////////////////////////////////////////////////////////////////////
601/// determine mirror dataset.
602/// mirror points are added around the physical boundaries of the dataset
603/// Two steps:
604/// 1. For each entry, determine if it should be mirrored (the mirror configuration).
605/// 2. For each mirror configuration, make the mirror points.
606
608{
609 for (Int_t j=0; j<_nDim; j++) {
610 _xDatLo3s[j] = _xDatLo[j] + _nSigma * (_n * _sigma[j]);
611 _xDatHi3s[j] = _xDatHi[j] - _nSigma * (_n * _sigma[j]);
612
613 // cout<<"xDatLo3s["<<j<<"]="<<_xDatLo3s[j]<<endl;
614 // cout<<"xDatHi3s["<<j<<"]="<<_xDatHi3s[j]<<endl;
615 }
616
617 vector<double> dummy(_nDim,0.);
618
619 // 1.
620 for (Int_t i=0; i<_nEvents; i++) {
621 vector<double>& x = _dataPts[i];
622
623 Int_t size = 1;
624 vector<vector<double> > mpoints(size,dummy);
625 vector<vector<Int_t> > mjdcs(size);
626
627 // create all mirror configurations for event i
628 for (Int_t j=0; j<_nDim; j++) {
629
630 vector<Int_t>& mjdxK = mjdcs[0];
631 vector<double>& mpointK = mpoints[0];
632
633 // single mirror *at physical boundaries*
634 if ((x[j]>_xDatLo[j] && x[j]<_xDatLo3s[j]) && x[j]<(_xDatLo[j]+_xDatHi[j])/2.) {
635 mpointK[j] = 2.*_xDatLo[j]-x[j];
636 mjdxK.push_back(j);
637 } else if ((x[j]<_xDatHi[j] && x[j]>_xDatHi3s[j]) && x[j]>(_xDatLo[j]+_xDatHi[j])/2.) {
638 mpointK[j] = 2.*_xDatHi[j]-x[j];
639 mjdxK.push_back(j);
640 }
641 }
642
643 vector<Int_t>& mjdx0 = mjdcs[0];
644 // no mirror point(s) for this event
645 if (size==1 && mjdx0.empty()) continue;
646
647 // 2.
648 // generate all mirror points for event i
649 vector<Int_t>& mjdx = mjdcs[0];
650 vector<double>& mpoint = mpoints[0];
651
652 // number of mirror points for this mirror configuration
653 Int_t eMir = 1 << mjdx.size();
654 vector<vector<double> > epoints(eMir,x);
655
656 for (Int_t m=0; m<Int_t(mjdx.size()); m++) {
657 Int_t size1 = 1 << m;
658 Int_t size2 = 1 << (m+1);
659 // copy all previous mirror points
660 for (Int_t l=size1; l<size2; ++l) {
661 epoints[l] = epoints[l-size1];
662 // fill high mirror points
663 vector<double>& epoint = epoints[l];
664 epoint[mjdx[Int_t(mjdx.size()-1)-m]] = mpoint[mjdx[Int_t(mjdx.size()-1)-m]];
665 }
666 }
667
668 // remove duplicate mirror points
669 // note that: first epoint == x
670 epoints.erase(epoints.begin());
671
672 // add mirror points of event i to total dataset
673 TVectorD pointR(_nDim);
674
675 for (Int_t m=0; m<Int_t(epoints.size()); m++) {
676 _idx.push_back(i);
677 _dataPts.push_back(epoints[m]);
678 //_weights0.push_back(_weights0[i]);
679 for (Int_t j=0; j<_nDim; j++) { pointR[j] = (epoints[m])[j]; }
680 if (_nDim > 1 && _rotate) {
681 pointR *= *_rotMat;
682 }
683 _dataPtsR.push_back(pointR);
684 }
685
686 epoints.clear();
687 mpoints.clear();
688 mjdcs.clear();
689 } // end of event loop
690
691 _nEventsM = Int_t(_dataPts.size());
692}
693
694////////////////////////////////////////////////////////////////////////////////
695
697{
698 _wMap.clear();
699
700 for (Int_t i=0; i<_nEventsM; i++) {
701 data.get(_idx[i]);
702 double myweight = data.weight();
703 //if ( TMath::Abs(myweight)>_minWeight ) {
704 _wMap[i] = myweight;
705 //}
706 }
707
708 coutI(Contents) << "RooNDKeysPdf::loadWeightSet(" << this << ") : Number of weighted events : " << _wMap.size() << endl;
709}
710
711////////////////////////////////////////////////////////////////////////////////
712/// determine points in +/- nSigma shell around the box determined by the variable
713/// ranges. These points are needed in the normalization, to determine probability
714/// leakage in and out of the box.
715
717{
718 for (Int_t j=0; j<_nDim; j++) {
719 if (bi->xVarLo[j]==_xDatLo[j] && bi->xVarHi[j]==_xDatHi[j]) {
720 bi->netFluxZ = bi->netFluxZ && true;
721 } else { bi->netFluxZ = false; }
722
723 bi->xVarLoM3s[j] = bi->xVarLo[j] - _nSigma * (_n * _sigma[j]);
724 bi->xVarLoP3s[j] = bi->xVarLo[j] + _nSigma * (_n * _sigma[j]);
725 bi->xVarHiM3s[j] = bi->xVarHi[j] - _nSigma * (_n * _sigma[j]);
726 bi->xVarHiP3s[j] = bi->xVarHi[j] + _nSigma * (_n * _sigma[j]);
727
728 //cout<<"bi->xVarLoM3s["<<j<<"]="<<bi->xVarLoM3s[j]<<endl;
729 //cout<<"bi->xVarLoP3s["<<j<<"]="<<bi->xVarLoP3s[j]<<endl;
730 //cout<<"bi->xVarHiM3s["<<j<<"]="<<bi->xVarHiM3s[j]<<endl;
731 //cout<<"bi->xVarHiM3s["<<j<<"]="<<bi->xVarHiM3s[j]<<endl;
732 }
733
734 //for (Int_t i=0; i<_nEventsM; i++) {
735 for (const auto& wMapItr : _wMap) {
736 Int_t i = wMapItr.first;
737
738 const vector<double>& x = _dataPts[i];
739 bool inVarRange(true);
740 bool inVarRangePlusShell(true);
741
742 for (Int_t j=0; j<_nDim; j++) {
743
744 if (x[j]>bi->xVarLo[j] && x[j]<bi->xVarHi[j]) {
745 inVarRange = inVarRange && true;
746 } else { inVarRange = inVarRange && false; }
747
748 if (x[j]>bi->xVarLoM3s[j] && x[j]<bi->xVarHiP3s[j]) {
749 inVarRangePlusShell = inVarRangePlusShell && true;
750 } else { inVarRangePlusShell = inVarRangePlusShell && false; }
751 }
752
753 // event in range?
754 if (inVarRange) {
755 bi->bIdcs.push_back(i);
756 }
757
758 // event in shell?
759 if (inVarRangePlusShell) {
760 bi->bpsIdcs[i] = true;
761 bool inShell(false);
762 for (Int_t j=0; j<_nDim; j++) {
763 if ((x[j]>bi->xVarLoM3s[j] && x[j]<bi->xVarLoP3s[j]) && x[j]<(bi->xVarLo[j]+bi->xVarHi[j])/2.) {
764 inShell = true;
765 } else if ((x[j]>bi->xVarHiM3s[j] && x[j]<bi->xVarHiP3s[j]) && x[j]>(bi->xVarLo[j]+bi->xVarHi[j])/2.) {
766 inShell = true;
767 }
768 }
769 if (inShell) bi->sIdcs.push_back(i); // needed for normalization
770 else {
771 bi->bmsIdcs.push_back(i); // idem
772 }
773 }
774 }
775
776 coutI(Contents) << "RooNDKeysPdf::calculateShell() : "
777 << "\n Events in shell " << bi->sIdcs.size()
778 << "\n Events in box " << bi->bIdcs.size()
779 << "\n Events in box and shell " << bi->bpsIdcs.size()
780 << endl;
781}
782
783////////////////////////////////////////////////////////////////////////////////
784///bi->nEventsBMSW=0.;
785///bi->nEventsBW=0.;
786
788{
789 // box minus shell
790 for (Int_t i=0; i<Int_t(bi->bmsIdcs.size()); i++)
791 bi->nEventsBMSW += _wMap.at(bi->bmsIdcs[i]);
792
793 // box
794 for (Int_t i=0; i<Int_t(bi->bIdcs.size()); i++)
795 bi->nEventsBW += _wMap.at(bi->bIdcs[i]);
796
797 cxcoutD(Eval) << "RooNDKeysPdf::calculatePreNorm() : "
798 << "\n nEventsBMSW " << bi->nEventsBMSW
799 << "\n nEventsBW " << bi->nEventsBW
800 << endl;
801}
802
803////////////////////////////////////////////////////////////////////////////////
804/// sort entries, as needed for loopRange()
805
807{
808 // will loop over all events by default
809 if (!_sortInput) {
810 _ibNoSort.clear();
811 for (unsigned int i = 0; i < _dataPtsR.size(); ++i) {
812 _ibNoSort[i] = true;
813 }
814 return;
815 }
816
817 itVec itrVecR;
818 vector<TVectorD>::iterator dpRItr = _dataPtsR.begin();
819 for (Int_t i = 0; dpRItr != _dataPtsR.end(); ++dpRItr, ++i) {
820 if (bi) {
821 if (bi->bpsIdcs.find(i) != bi->bpsIdcs.end()) {
822 // if (_wMap.find(i)!=_wMap.end())
823 itrVecR.push_back(itPair(i, dpRItr));
824 }
825 } else
826 itrVecR.push_back(itPair(i, dpRItr));
827 }
828
829 _sortTVIdcs.resize(_nDim);
830 for (Int_t j=0; j<_nDim; j++) {
831 _sortTVIdcs[j].clear();
832 sort(itrVecR.begin(), itrVecR.end(), [=](const itPair& a, const itPair& b) {
833 return (*a.second)[j] < (*b.second)[j];
834 });
835 _sortTVIdcs[j] = itrVecR;
836 }
837
838 for (Int_t j=0; j<_nDim; j++) {
839 cxcoutD(Eval) << "RooNDKeysPdf::sortDataIndices() : Number of sorted events : " << _sortTVIdcs[j].size() << endl;
840 }
841}
842
843////////////////////////////////////////////////////////////////////////////////
844
846{
847 cxcoutD(Eval) << "RooNDKeysPdf::calculateBandWidth()" << endl;
848
849 const bool adaptive = _options.Contains("a");
850 if (_weights != &_weights1 || _weights != &_weights0) {
851 _weights = adaptive ? &_weights1 : &_weights0;
852 }
853
854 // non-adaptive bandwidth
855 // (default, and needed to calculate adaptive bandwidth)
856
857 if(!adaptive) {
858 cxcoutD(Eval) << "RooNDKeysPdf::calculateBandWidth() Using static bandwidth." << endl;
859 }
860
861 // fixed width approximation
862 for (Int_t i=0; i<_nEvents; i++) {
863 vector<double>& weight = _weights0[i];
864 for (Int_t j = 0; j < _nDim; j++) {
865 weight[j] = _n * (*_sigmaR)[j];
866 // cout<<"j: "<<j<<", _n: "<<_n<<", sigmaR="<<(*_sigmaR)[j]<<", weight="<<weight[j]<<endl;
867 }
868 }
869
870 // adaptive width
871 if (adaptive) {
872 cxcoutD(Eval) << "RooNDKeysPdf::calculateBandWidth() Using adaptive bandwidth." << endl;
873
874 double sqrt12 = sqrt(12.);
875 double sqrtSigmaAvgR = sqrt(_sigmaAvgR);
876
877 vector<double> dummy(_nDim, 0.);
878 _weights1.resize(_nEvents, dummy);
879
880 std::vector<std::vector<double>> *weights_prev(nullptr);
881 std::vector<std::vector<double>> *weights_new(nullptr);
882
883 // cout << "Number of adaptive iterations: " << _nAdpt << endl;
884
885 for (Int_t k = 1; k <= _nAdpt; ++k) {
886
887 // cout << " Cycle: " << k << endl;
888
889 // if multiple adaptive iterations, need to swap weight sets
890 if (k % 2) {
891 weights_prev = &_weights0;
892 weights_new = &_weights1;
893 } else {
894 weights_prev = &_weights1;
895 weights_new = &_weights0;
896 }
897
898 for (Int_t i = 0; i < _nEvents; ++i) {
899 vector<double> &x = _dataPts[i];
900 double f = TMath::Power(gauss(x, *weights_prev) / _nEventsW, -1. / (2. * _d));
901
902 vector<double> &weight = (*weights_new)[i];
903 for (Int_t j = 0; j < _nDim; j++) {
904 double norm = (_n * (*_sigmaR)[j]) / sqrtSigmaAvgR;
905 weight[j] = norm * f / sqrt12; // note additional factor of sqrt(12) compared with HEP-EX/0011057
906 }
907 }
908 }
909 // this is the latest updated weights set
910 _weights = weights_new;
911 }
912}
913
914////////////////////////////////////////////////////////////////////////////////
915/// loop over all closest point to x, as determined by loopRange()
916
917double RooNDKeysPdf::gauss(vector<double>& x, vector<vector<double> >& weights) const
918{
919 if(_nEvents==0) return 0.;
920
921 const double sqrt2pi = std::sqrt(TMath::TwoPi());
922
923 double z=0.;
924 std::vector<int> indices;
925
926 // determine input loop range for event x
927 if (_sortInput) {
928 if (_sortTVIdcs.empty())
929 const_cast<RooNDKeysPdf*>(this)->sortDataIndices();
930
931 loopRange(x, indices);
932 } else {
933 indices.reserve(_ibNoSort.size());
934 for (const auto& ibMapItr : _ibNoSort) {
935 indices.push_back(ibMapItr.first);
936 }
937 }
938
939 for (const auto& i : indices) {
940 double g(1.);
941
942 if (i >= (Int_t)_idx.size()) {
943 continue;
944 } //---> 1.myline
945
946 const vector<double> &point = _dataPts[i];
947 const vector<double> &weight = weights[_idx[i]];
948
949 for (Int_t j = 0; j < _nDim; j++) {
950 (*_dx)[j] = x[j] - point[j];
951 }
952
953 if (_nDim > 1 && _rotate) {
954 *_dx *= *_rotMat; // rotate to decorrelated frame!
955 }
956
957 for (Int_t j = 0; j < _nDim; j++) {
958 double r = (*_dx)[j]; // x[j] - point[j];
959 double c = 1. / (2. * weight[j] * weight[j]);
960
961 // cout << "j = " << j << " x[j] = " << point[j] << " w = " << weight[j] << endl;
962
963 g *= exp(-c * r * r);
964 g *= 1. / (sqrt2pi * weight[j]);
965 }
966 z += (g * _wMap.at(_idx[i]));
967 }
968 return z;
969}
970
971////////////////////////////////////////////////////////////////////////////////
972/// determine closest points to x, to loop over in evaluate()
973
974void RooNDKeysPdf::loopRange(vector<double>& x, std::vector<Int_t>& ibMap) const
975{
976 ibMap.clear();
977 TVectorD xRm(_nDim);
978 TVectorD xRp(_nDim);
979
980 for (Int_t j = 0; j < _nDim; j++) {
981 xRm[j] = xRp[j] = x[j];
982 }
983
984 if (_nDim > 1 && _rotate) {
985 xRm *= *_rotMat;
986 xRp *= *_rotMat;
987 }
988 for (Int_t j = 0; j < _nDim; j++) {
989 xRm[j] -= _nSigma * (_n * (*_sigmaR)[j]);
990 xRp[j] += _nSigma * (_n * (*_sigmaR)[j]);
991 }
992
993 std::vector<TVectorD> xvecRm(1,xRm);
994 std::vector<TVectorD> xvecRp(1,xRp);
995
996 // To remember the indices that were selected in the previous dimensions
997 std::vector<Int_t> ibMapRT;
998
999 for (Int_t j=0; j<_nDim; j++) {
1000 ibMap.clear();
1001 auto comp = [=](const itPair& a, const itPair& b) {
1002 return (*a.second)[j] < (*b.second)[j];
1003 };
1004
1005 // Figure out which elements are to be selected in the current dimension
1006 auto lo = std::lower_bound(_sortTVIdcs[j].begin(), _sortTVIdcs[j].end(), itPair(0, xvecRm.begin()), comp);
1007 auto hi = std::upper_bound(_sortTVIdcs[j].begin(), _sortTVIdcs[j].end(), itPair(0, xvecRp.begin()), comp);
1008 auto it = lo;
1009
1010 if (j==0) {
1011 // In the first dimension, we can skip straight to filling the remembered
1012 // indices for the previous dimension, or in the 1-d case, just fill the
1013 // output map.
1014 auto& m = _nDim==1 ? ibMap : ibMapRT;
1015 m.reserve(std::distance(lo, hi));
1016 for (it=lo; it!=hi; ++it) {
1017 m.push_back(it->first);
1018 }
1019 // Sort by indices so we can use binary search
1020 std::sort(m.begin(), m.end());
1021 continue;
1022 }
1023
1024 // Iterate over elements in current dimension and add them to the list if
1025 // they were also selected in the previous dimension.
1026 for (it=lo; it!=hi; ++it) {
1027 // Look up in ibMapRT with binary search
1028 auto found = std::lower_bound(ibMapRT.begin(), ibMapRT.end(), it->first);
1029 if (found != ibMapRT.end() && !(it->first < *found)) {
1030 ibMap.push_back(it->first);
1031 }
1032 }
1033 // Sort by indices so we can use binary search
1034 std::sort(ibMap.begin(), ibMap.end());
1035
1036 ibMapRT.clear();
1037 if (j!=_nDim-1) { ibMapRT = std::move(ibMap); }
1038 }
1039}
1040
1041////////////////////////////////////////////////////////////////////////////////
1042
1043void RooNDKeysPdf::boxInfoInit(BoxInfo* bi, const char* rangeName, Int_t /*code*/) const
1044{
1045 vector<bool> doInt(_nDim,true);
1046
1047 bi->filled = false;
1048
1049 bi->xVarLo.resize(_nDim,0.);
1050 bi->xVarHi.resize(_nDim,0.);
1051 bi->xVarLoM3s.resize(_nDim,0.);
1052 bi->xVarLoP3s.resize(_nDim,0.);
1053 bi->xVarHiM3s.resize(_nDim,0.);
1054 bi->xVarHiP3s.resize(_nDim,0.);
1055
1056 bi->netFluxZ = true;
1057 bi->bpsIdcs.clear();
1058 bi->bIdcs.clear();
1059 bi->sIdcs.clear();
1060 bi->bmsIdcs.clear();
1061
1062 bi->nEventsBMSW=0.;
1063 bi->nEventsBW=0.;
1064
1065 for (unsigned int j=0; j < _varList.size(); ++j) {
1066 auto var = static_cast<const RooAbsRealLValue*>(_varList.at(j));
1067 if (doInt[j]) {
1068 bi->xVarLo[j] = var->getMin(rangeName);
1069 bi->xVarHi[j] = var->getMax(rangeName);
1070 } else {
1071 bi->xVarLo[j] = var->getVal() ;
1072 bi->xVarHi[j] = var->getVal() ;
1073 }
1074 }
1075}
1076
1077////////////////////////////////////////////////////////////////////////////////
1078
1080{
1081 if ( (_tracker && _tracker->hasChanged(true)) || (_weights != &_weights0 && _weights != &_weights1) ) {
1082 updateRho(); // update internal rho parameters
1083 // redetermine static and/or adaptive bandwidth
1084 const_cast<RooNDKeysPdf*>(this)->calculateBandWidth();
1085 }
1086
1087 const RooArgSet *nset = _varList.nset();
1088 for (unsigned int j=0; j < _varList.size(); ++j) {
1089 auto var = static_cast<const RooAbsReal*>(_varList.at(j));
1090 _x[j] = var->getVal(nset);
1091 }
1092
1093 double val = gauss(_x,*_weights);
1094 //cout<<"returning "<<val<<endl;
1095
1096 if (val >= 1E-20) {
1097 return val;
1098 } else {
1099 return (1E-20);
1100 }
1101}
1102
1103////////////////////////////////////////////////////////////////////////////////
1104
1105Int_t RooNDKeysPdf::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* rangeName) const
1106{
1107 if (rangeName) return 0 ;
1108
1109 Int_t code=0;
1110 if (matchArgs(allVars,analVars,RooArgSet(_varList))) { code=1; }
1111
1112 return code;
1113
1114}
1115
1116////////////////////////////////////////////////////////////////////////////////
1117
1118double RooNDKeysPdf::analyticalIntegral(Int_t code, const char* rangeName) const
1119{
1121
1122 cxcoutD(Eval) << "Calling RooNDKeysPdf::analyticalIntegral(" << GetName() << ") with code " << code
1123 << " and rangeName " << (rangeName?rangeName:"<none>") << endl;
1124
1125 // determine which observables need to be integrated over ...
1126 Int_t nComb = 1 << (_nDim);
1127 R__ASSERT(code>=1 && code<nComb) ;
1128
1129 vector<bool> doInt(_nDim,true);
1130
1131 // get BoxInfo
1132 BoxInfo* bi(nullptr);
1133
1134 if (rangeName) {
1135 string rangeNameStr(rangeName) ;
1136 bi = _rangeBoxInfo[make_pair(rangeNameStr,code)] ;
1137 if (!bi) {
1138 bi = new BoxInfo ;
1139 _rangeBoxInfo[make_pair(rangeNameStr,code)] = bi ;
1140 boxInfoInit(bi,rangeName,code);
1141 }
1142 } else bi= &_fullBoxInfo ;
1143
1144 // have boundaries changed?
1145 bool newBounds(false);
1146 for (unsigned int j=0; j < _varList.size(); ++j) {
1147 auto var = static_cast<const RooAbsRealLValue*>(_varList.at(j));
1148 if ((var->getMin(rangeName)-bi->xVarLo[j]!=0) ||
1149 (var->getMax(rangeName)-bi->xVarHi[j]!=0)) {
1150 newBounds = true;
1151 }
1152 }
1153
1154 // reset
1155 if (newBounds) {
1156 cxcoutD(Eval) << "RooNDKeysPdf::analyticalIntegral() : Found new boundaries ... " << (rangeName?rangeName:"<none>") << endl;
1157 boxInfoInit(bi,rangeName,code);
1158 }
1159
1160 // recalculates netFluxZero and nEventsIR
1161 if (!bi->filled || newBounds) {
1162 // Fill box info with contents
1163 calculateShell(bi);
1164 calculatePreNorm(bi);
1165 bi->filled = true;
1166 const_cast<RooNDKeysPdf*>(this)->sortDataIndices(bi);
1167 }
1168
1169 // first guess
1170 double norm=bi->nEventsBW;
1171
1172 if (_mirror && bi->netFluxZ) {
1173 // KEYS expression is self-normalized
1174 cxcoutD(Eval) << "RooNDKeysPdf::analyticalIntegral() : Using mirrored normalization : " << bi->nEventsBW << endl;
1175 return bi->nEventsBW;
1176 }
1177 // calculate leakage in and out of variable range box
1178 else
1179 {
1180 norm = bi->nEventsBMSW;
1181 if (norm<0.) norm=0.;
1182
1183 for (Int_t i=0; i<Int_t(bi->sIdcs.size()); ++i) {
1184 double prob=1.;
1185 const vector<double>& x = _dataPts[bi->sIdcs[i]];
1186 const vector<double>& weight = (*_weights)[_idx[bi->sIdcs[i]]];
1187
1188 vector<double> chi(_nDim,100.);
1189
1190 for (Int_t j=0; j<_nDim; j++) {
1191 if(!doInt[j]) continue;
1192
1193 if ((x[j] > bi->xVarLoM3s[j] && x[j] < bi->xVarLoP3s[j]) && x[j] < (bi->xVarLo[j] + bi->xVarHi[j]) / 2.) {
1194 chi[j] = (x[j] - bi->xVarLo[j]) / weight[j];
1195 } else if ((x[j] > bi->xVarHiM3s[j] && x[j] < bi->xVarHiP3s[j]) && x[j] > (bi->xVarLo[j] + bi->xVarHi[j]) / 2.) {
1196 chi[j] = (bi->xVarHi[j] - x[j]) / weight[j];
1197 }
1198
1199 if (chi[j] > 0) { // inVarRange
1200 prob *= (0.5 + TMath::Erf(std::abs(chi[j]) / sqrt(2.)) / 2.);
1201 } else { // outside Var range
1202 prob *= (0.5 - TMath::Erf(std::abs(chi[j]) / sqrt(2.)) / 2.);
1203 }
1204 }
1205
1206 norm += prob * _wMap.at(_idx[bi->sIdcs[i]]);
1207 }
1208
1209 cxcoutD(Eval) << "RooNDKeysPdf::analyticalIntegral() : Final normalization : " << norm << " " << bi->nEventsBW << endl;
1210 return norm;
1211 }
1212}
1213
1214
1215////////////////////////////////////////////////////////////////////////////////
1216
1218{
1219 RooArgSet varSet{varList};
1220 std::vector<RooRealVar *> varVec;
1221
1222 for (const auto var : varList) {
1223 if (!dynamic_cast<RooRealVar *>(var)) {
1224 coutE(InputArguments) << "RooNDKeysPdf::createDatasetFromHist(" << GetName() << ") WARNING: variable "
1225 << var->GetName() << " is not of type RooRealVar. Skip." << endl;
1226 continue;
1227 }
1228 varVec.push_back(static_cast<RooRealVar *>(var)); // used for setting the variables.
1229 }
1230
1231 /// determine histogram dimensionality
1232 unsigned int histndim(0);
1233 std::string classname = hist.ClassName();
1234 if (classname.find("TH1") == 0) {
1235 histndim = 1;
1236 } else if (classname.find("TH2") == 0) {
1237 histndim = 2;
1238 } else if (classname.find("TH3") == 0) {
1239 histndim = 3;
1240 }
1241 assert(histndim == varVec.size());
1242
1243 if (histndim > 3 || histndim <= 0) {
1244 coutE(InputArguments) << "RooNDKeysPdf::createDatasetFromHist(" << GetName()
1245 << ") ERROR: input histogram dimension not between [1-3]: " << histndim << endl;
1246 assert(0);
1247 }
1248
1249 /// dataset creation
1250 RooDataSet *dataFromHist = new RooDataSet("datasetFromHist", "datasetFromHist", varSet, RooFit::WeightVar());
1251
1252 /// dataset filling
1253 for (int i = 1; i <= hist.GetXaxis()->GetNbins(); ++i) {
1254 // 1 or more dimension
1255
1256 double xval = hist.GetXaxis()->GetBinCenter(i);
1257 varVec[0]->setVal(xval);
1258
1259 if (varVec.size() == 1) {
1260 double fval = hist.GetBinContent(i);
1261 dataFromHist->add(varSet, fval);
1262 } else { // 2 or more dimensions
1263
1264 for (int j = 1; j <= hist.GetYaxis()->GetNbins(); ++j) {
1265 double yval = hist.GetYaxis()->GetBinCenter(j);
1266 varVec[1]->setVal(yval);
1267
1268 if (varVec.size() == 2) {
1269 double fval = hist.GetBinContent(i, j);
1270 dataFromHist->add(varSet, fval);
1271 } else { // 3 dimensions
1272
1273 for (int k = 1; k <= hist.GetZaxis()->GetNbins(); ++k) {
1274 double zval = hist.GetZaxis()->GetBinCenter(k);
1275 varVec[2]->setVal(zval);
1276
1277 double fval = hist.GetBinContent(i, j, k);
1278 dataFromHist->add(varSet, fval);
1279 }
1280 }
1281 }
1282 }
1283 }
1284
1285 return dataFromHist;
1286}
1287
1288
1289////////////////////////////////////////////////////////////////////////////////
1290/// Return evaluated weights
1292{
1294
1295 TMatrixD mref(_nEvents, _nDim + 1);
1296
1297 cxcoutD(Eval) << "RooNDKeysPdf::getWeights() Return evaluated weights." << endl;
1298
1299 for (Int_t i = 0; i < _nEvents; ++i) {
1300 const vector<double>& x = _dataPts[i];
1301 for (Int_t j = 0; j < _nDim; j++) {
1302 mref(i, j) = x[j];
1303 }
1304
1305 const vector<double>& weight = (*_weights)[i];
1306 mref(i, _nDim) = weight[k];
1307 }
1308
1309 return mref;
1310}
1311
1312 ////////////////////////////////////////////////////////////////////////////////
1314{
1315 for (unsigned int j = 0; j < _rhoList.size(); ++j) {
1316 auto rho = static_cast<const RooAbsReal*>(_rhoList.at(j));
1317 _rho[j] = rho->getVal();
1318 }
1319
1320 if (_nDim > 1 && _rotate) {
1321 TMatrixDSym covMatRho(_nDim); // covariance matrix times rho parameters
1322 for (Int_t j = 0; j < _nDim; j++) {
1323 for (Int_t k = 0; k < _nDim; k++) {
1324 covMatRho(j, k) = (*_covMat)(j, k) * _rho[j] * _rho[k];
1325 }
1326 }
1327 // find decorrelation matrix and eigenvalues (R)
1328 TMatrixDSymEigen evCalculatorRho(covMatRho);
1329 *_sigmaR = evCalculatorRho.GetEigenValues();
1330 for (Int_t j = 0; j < _nDim; j++) {
1331 (*_sigmaR)[j] = sqrt((*_sigmaR)[j]);
1332 }
1333 } else {
1334 for (Int_t j = 0; j < _nDim; j++) {
1335 (*_sigmaR)[j] = (_sigma[j] * _rho[j]);
1336 } // * rho
1337 }
1338}
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define g(i)
Definition RSha256.hxx:105
#define a(i)
Definition RSha256.hxx:99
bool _verbose
Verbose messaging if true.
bool initialize()
Int_t _nEvents
Total number of events in test statistic calculation.
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define coutI(a)
#define cxcoutD(a)
#define coutW(a)
#define coutE(a)
std::vector< itPair > itVec
std::pair< Int_t, VecTVecDouble::iterator > itPair
int Int_t
Definition RtypesCore.h:45
#define ClassImp(name)
Definition Rtypes.h:377
#define R__ASSERT(e)
Definition TError.h:118
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
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
#define hi
TMatrixTSym< Double_t > TMatrixDSym
TMatrixT< Double_t > TMatrixD
Definition TMatrixDfwd.h:23
TVectorT< Double_t > TVectorD
Definition TVectorDfwd.h:23
friend class RooDataSet
Definition RooAbsArg.h:667
TIterator Use end() or range-based loops.")
Definition RooAbsArg.h:136
const char * GetName() const override
Returns name of object.
Storage_t::size_type size() const
bool addTyped(const RooAbsCollection &list, bool silent=false)
Adds elements of a given RooAbsCollection to the container if they match the specified type.
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
const RooArgSet * nset() const
Definition RooAbsProxy.h:52
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
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
bool matchArgs(const RooArgSet &allDeps, RooArgSet &numDeps, const RooArgProxy &a) const
Utility function for use in getAnalyticalIntegral().
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition RooArgList.h:110
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
Meta object that tracks value changes in a given set of RooAbsArgs by registering itself as value cli...
bool hasChanged(bool clearState)
Returns true if state has changed since last call with clearState=true.
bool add(const RooAbsArg &var, bool valueServer, bool shapeServer, bool silent)
Overloaded RooCollection_t::add() method insert object into set and registers object as server to own...
Container class to hold unbinned data.
Definition RooDataSet.h:57
void add(const RooArgSet &row, double weight, double weightError)
Add one ore more rows of data.
Generic N-dimensional implementation of a kernel estimation p.d.f.
BoxInfo _fullBoxInfo
RooListProxy _rhoList
TVectorD * _dx
std::map< Int_t, bool > _ibNoSort
std::vector< std::vector< double > > _weights0
double analyticalIntegral(Int_t code, const char *rangeName=nullptr) const override
Implements the actual analytical integral(s) advertised by getAnalyticalIntegral.
~RooNDKeysPdf() override
void calculatePreNorm(BoxInfo *bi) const
bi->nEventsBMSW=0.; bi->nEventsBW=0.;
std::vector< double > _xDatHi
std::vector< std::vector< double > > * _weights
TVectorD * _sigmaR
void createPdf(bool firstCall, RooDataSet const &data)
evaluation order of constructor.
double evaluate() const override
Evaluate this PDF / function / constant. Needs to be overridden by all derived classes.
void loopRange(std::vector< double > &x, std::vector< Int_t > &indices) const
determine closest points to x, to loop over in evaluate()
std::vector< double > _xDatLo
std::vector< double > _x
void initialize(RooDataSet const &data)
initialization
std::map< Int_t, double > _wMap
double _maxWeight
void sortDataIndices(BoxInfo *bi=nullptr)
sort entries, as needed for loopRange()
double _nEventsBMSW
void loadDataSet(bool firstCall, RooDataSet const &data)
copy the dataset and calculate some useful variables
std::vector< TVectorD > _dataPtsR
void updateRho() const
std::vector< double > _mean
void calculateShell(BoxInfo *bi) const
determine points in +/- nSigma shell around the box determined by the variable ranges.
void calculateBandWidth()
std::vector< double > _xDatLo3s
std::vector< double > _x1
double _widthFactor
std::vector< std::vector< double > > _dataPts
double _sigmaAvgR
std::vector< double > _x0
std::vector< double > _x2
double gauss(std::vector< double > &x, std::vector< std::vector< double > > &weights) const
loop over all closest point to x, as determined by loopRange()
std::vector< double > _rho
RooListProxy _varList
TMatrixDSym * _corrMat
void loadWeightSet(RooDataSet const &data)
std::vector< itVec > _sortTVIdcs
Weights to be used. Points either to _weights0 or _weights1.
void boxInfoInit(BoxInfo *bi, const char *rangeName, Int_t code) const
std::map< std::pair< std::string, int >, BoxInfo * > _rangeBoxInfo
std::vector< Int_t > _idx
Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName=nullptr) const override
Interface function getAnalyticalIntergral advertises the analytical integrals that are supported.
std::vector< std::vector< double > > _weights1
std::vector< double > _xDatHi3s
TString _options
TMatrixD getWeights(const int &k) const
Return evaluated weights.
std::vector< double > _sigma
void mirrorDataSet()
determine mirror dataset.
void setOptions()
set the configuration
RooDataSet * createDatasetFromHist(const RooArgList &varList, const TH1 &hist) const
RooNDKeysPdf()=default
void checkInitWeights() const
double _nEventsBW
TMatrixD * _rotMat
TMatrixDSym * _covMat
double _minWeight
RooChangeTracker * _tracker
Variable that can be changed from the outside.
Definition RooRealVar.h:37
virtual Double_t GetBinCenter(Int_t bin) const
Return center of bin.
Definition TAxis.cxx:478
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:59
TAxis * GetZaxis()
Definition TH1.h:326
TAxis * GetXaxis()
Definition TH1.h:324
TAxis * GetYaxis()
Definition TH1.h:325
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition TH1.cxx:5029
TMatrixDSymEigen.
const TVectorD & GetEigenValues() const
const TMatrixD & GetEigenVectors() const
virtual TMatrixTBase< Element > & Zero()
Set matrix elements to zero.
void Print(Option_t *name="") const override
Print the matrix as a table of elements.
TMatrixT< Element > & T()
Definition TMatrixT.h:155
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:207
Basic string class.
Definition TString.h:139
void ToLower()
Change string to lower-case.
Definition TString.cxx:1182
const char * Data() const
Definition TString.h:376
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:632
TVectorT< Element > & Zero()
Set vector elements to zero.
Definition TVectorT.cxx:453
Int_t GetNrows() const
Definition TVectorT.h:73
void Print(Option_t *option="") const override
Print the vector as a list of elements.
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition fillpatterns.C:1
RooCmdArg WeightVar(const char *name="weight", bool reinterpretAsWeight=false)
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
Double_t Erf(Double_t x)
Computation of the error function erf(x).
Definition TMath.cxx:190
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Returns x raised to the power y.
Definition TMath.h:721
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:123
constexpr Double_t TwoPi()
Definition TMath.h:44
std::vector< double > xVarHiM3s
std::vector< Int_t > bIdcs
std::vector< double > xVarHiP3s
std::vector< double > xVarLo
std::vector< double > xVarHi
std::map< Int_t, bool > bpsIdcs
std::vector< Int_t > sIdcs
std::vector< double > xVarLoM3s
std::vector< double > xVarLoP3s
std::vector< Int_t > bmsIdcs
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4