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