Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooAbsData.cxx
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitCore *
4  * @(#)root/roofitcore:$Id$
5  * Authors: *
6  * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7  * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8  * *
9  * Copyright (c) 2000-2005, Regents of the University of California *
10  * and Stanford University. All rights reserved. *
11  * *
12  * Redistribution and use in source and binary forms, *
13  * with or without modification, are permitted according to the terms *
14  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15  *****************************************************************************/
16 
17 /**
18 \file RooAbsData.cxx
19 \class RooAbsData
20 \ingroup Roofitcore
21 
22 RooAbsData is the common abstract base class for binned and unbinned
23 datasets. The abstract interface defines plotting and tabulating entry
24 points for its contents and provides an iterator over its elements
25 (bins for binned data sets, data points for unbinned datasets).
26 **/
27 
28 #include "RooAbsData.h"
29 
30 #include "RooFit.h"
31 #include "Riostream.h"
32 
33 #include "TBuffer.h"
34 #include "TClass.h"
35 #include "TMath.h"
36 #include "TTree.h"
37 
38 #include "RooAbsData.h"
39 #include "RooFormulaVar.h"
40 #include "RooCmdConfig.h"
41 #include "RooAbsRealLValue.h"
42 #include "RooMsgService.h"
43 #include "RooMultiCategory.h"
44 #include "Roo1DTable.h"
45 #include "RooAbsDataStore.h"
46 #include "RooVectorDataStore.h"
47 #include "RooTreeDataStore.h"
48 #include "RooDataHist.h"
49 #include "RooCompositeDataStore.h"
50 #include "RooCategory.h"
51 #include "RooTrace.h"
52 
53 #include "RooRealVar.h"
54 #include "RooGlobalFunc.h"
55 #include "RooPlot.h"
56 #include "RooCurve.h"
57 #include "RooHist.h"
58 
59 #include "TMatrixDSym.h"
60 #include "TPaveText.h"
61 #include "TH1.h"
62 #include "TH2.h"
63 #include "TH3.h"
64 
65 
66 using namespace std;
67 
68 ClassImp(RooAbsData);
69 ;
70 
71 static std::map<RooAbsData*,int> _dcc ;
72 
73 RooAbsData::StorageType RooAbsData::defaultStorageType=RooAbsData::Vector ;
74 
75 ////////////////////////////////////////////////////////////////////////////////
76 
77 void RooAbsData::setDefaultStorageType(RooAbsData::StorageType s)
78 {
79  if (RooAbsData::Composite == s) {
80  cout << "Composite storage is not a valid *default* storage type." << endl;
81  } else {
82  defaultStorageType = s;
83  }
84 }
85 
86 ////////////////////////////////////////////////////////////////////////////////
87 
88 RooAbsData::StorageType RooAbsData::getDefaultStorageType( )
89 {
90  return defaultStorageType;
91 }
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 
95 void RooAbsData::claimVars(RooAbsData* data)
96 {
97  _dcc[data]++ ;
98  //cout << "RooAbsData(" << data << ") claim incremented to " << _dcc[data] << endl ;
99 }
100 
101 ////////////////////////////////////////////////////////////////////////////////
102 /// If return value is true variables can be deleted
103 
104 Bool_t RooAbsData::releaseVars(RooAbsData* data)
105 {
106  if (_dcc[data]>0) {
107  _dcc[data]-- ;
108  }
109 
110  //cout << "RooAbsData(" << data << ") claim decremented to " << _dcc[data] << endl ;
111  return (_dcc[data]==0) ;
112 }
113 
114 ////////////////////////////////////////////////////////////////////////////////
115 /// Default constructor
116 
117 RooAbsData::RooAbsData()
118 {
119  claimVars(this) ;
120  _dstore = 0 ;
121  storageType = defaultStorageType;
122 
123  RooTrace::create(this) ;
124 }
125 
126 ////////////////////////////////////////////////////////////////////////////////
127 /// Constructor from a set of variables. Only fundamental elements of vars
128 /// (RooRealVar,RooCategory etc) are stored as part of the dataset
129 
130 RooAbsData::RooAbsData(const char *name, const char *title, const RooArgSet& vars, RooAbsDataStore* dstore) :
131  TNamed(name,title), _vars("Dataset Variables"), _cachedVars("Cached Variables"), _dstore(dstore)
132 {
133  if (dynamic_cast<RooTreeDataStore *>(dstore)) {
134  storageType = RooAbsData::Tree;
135  } else if (dynamic_cast<RooVectorDataStore *>(dstore)) {
136  storageType = RooAbsData::Vector;
137  } else {
138  storageType = RooAbsData::Composite;
139  }
140  // cout << "created dataset " << this << endl ;
141  claimVars(this);
142 
143  // clone the fundamentals of the given data set into internal buffer
144  TIterator *iter = vars.createIterator();
145  RooAbsArg *var;
146  while ((0 != (var = (RooAbsArg *)iter->Next()))) {
147  if (!var->isFundamental()) {
148  coutE(InputArguments) << "RooAbsDataStore::initialize(" << GetName()
149  << "): Data set cannot contain non-fundamental types, ignoring " << var->GetName()
150  << endl;
151  } else {
152  _vars.addClone(*var);
153  }
154  }
155  delete iter;
156 
157  // reconnect any parameterized ranges to internal dataset observables
158  iter = _vars.createIterator();
159  while ((0 != (var = (RooAbsArg *)iter->Next()))) {
160  var->attachDataSet(*this);
161  }
162  delete iter;
163 
164  RooTrace::create(this);
165 }
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 /// Copy constructor
169 
170 RooAbsData::RooAbsData(const RooAbsData& other, const char* newname) :
171  TNamed(newname?newname:other.GetName(),other.GetTitle()),
172  RooPrintable(other), _vars(),
173  _cachedVars("Cached Variables")
174 {
175  //cout << "created dataset " << this << endl ;
176  claimVars(this) ;
177  _vars.addClone(other._vars) ;
178 
179  // reconnect any parameterized ranges to internal dataset observables
180  for (const auto var : _vars) {
181  var->attachDataSet(*this) ;
182  }
183 
184 
185  if (other._ownedComponents.size()>0) {
186 
187  // copy owned components here
188 
189  map<string,RooAbsDataStore*> smap ;
190  for (auto& itero : other._ownedComponents) {
191  RooAbsData* dclone = (RooAbsData*) itero.second->Clone();
192  _ownedComponents[itero.first] = dclone;
193  smap[itero.first] = dclone->store();
194  }
195 
196  RooCategory* idx = (RooCategory*) _vars.find(*((RooCompositeDataStore*)other.store())->index()) ;
197  _dstore = new RooCompositeDataStore(newname?newname:other.GetName(),other.GetTitle(),_vars,*idx,smap) ;
198  storageType = RooAbsData::Composite;
199 
200  } else {
201 
202  // Convert to vector store if default is vector
203  _dstore = other._dstore->clone(_vars,newname?newname:other.GetName()) ;
204  storageType = other.storageType;
205  }
206 
207  RooTrace::create(this) ;
208 }
209 
210 RooAbsData& RooAbsData::operator=(const RooAbsData& other) {
211  TNamed::operator=(other);
212  RooPrintable::operator=(other);
213 
214  claimVars(this);
215  _vars.Clear();
216  _vars.addClone(other._vars);
217 
218  // reconnect any parameterized ranges to internal dataset observables
219  for (const auto var : _vars) {
220  var->attachDataSet(*this) ;
221  }
222 
223 
224  if (other._ownedComponents.size()>0) {
225 
226  // copy owned components here
227 
228  map<string,RooAbsDataStore*> smap ;
229  for (auto& itero : other._ownedComponents) {
230  RooAbsData* dclone = (RooAbsData*) itero.second->Clone();
231  _ownedComponents[itero.first] = dclone;
232  smap[itero.first] = dclone->store();
233  }
234 
235  RooCategory* idx = (RooCategory*) _vars.find(*((RooCompositeDataStore*)other.store())->index()) ;
236  _dstore = new RooCompositeDataStore(GetName(), GetTitle(), _vars, *idx, smap);
237  storageType = RooAbsData::Composite;
238 
239  } else {
240 
241  // Convert to vector store if default is vector
242  _dstore = other._dstore->clone(_vars);
243  storageType = other.storageType;
244  }
245 
246  return *this;
247 }
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 /// Destructor
251 
252 RooAbsData::~RooAbsData()
253 {
254  if (releaseVars(this)) {
255  // will cause content to be deleted subsequently in dtor
256  } else {
257  _vars.releaseOwnership() ;
258  }
259 
260  // delete owned contents.
261  delete _dstore ;
262 
263  // Delete owned dataset components
264  for(map<std::string,RooAbsData*>::iterator iter = _ownedComponents.begin() ; iter!= _ownedComponents.end() ; ++iter) {
265  delete iter->second ;
266  }
267 
268  RooTrace::destroy(this) ;
269 }
270 
271 ////////////////////////////////////////////////////////////////////////////////
272 /// Convert tree-based storage to vector-based storage
273 
274 void RooAbsData::convertToVectorStore()
275 {
276  if (storageType == RooAbsData::Tree) {
277  RooVectorDataStore *newStore = new RooVectorDataStore(*(RooTreeDataStore *)_dstore, _vars, GetName());
278  delete _dstore;
279  _dstore = newStore;
280  storageType = RooAbsData::Vector;
281  }
282 }
283 
284 ////////////////////////////////////////////////////////////////////////////////
285 
286 Bool_t RooAbsData::changeObservableName(const char* from, const char* to)
287 {
288  Bool_t ret = _dstore->changeObservableName(from,to) ;
289 
290  RooAbsArg* tmp = _vars.find(from) ;
291  if (tmp) {
292  tmp->SetName(to) ;
293  }
294  return ret ;
295 }
296 
297 ////////////////////////////////////////////////////////////////////////////////
298 
299 void RooAbsData::fill()
300 {
301  _dstore->fill() ;
302 }
303 
304 ////////////////////////////////////////////////////////////////////////////////
305 
306 Int_t RooAbsData::numEntries() const
307 {
308  return nullptr != _dstore ? _dstore->numEntries() : 0;
309 }
310 
311 ////////////////////////////////////////////////////////////////////////////////
312 
313 void RooAbsData::reset()
314 {
315  _dstore->reset() ;
316 }
317 
318 ////////////////////////////////////////////////////////////////////////////////
319 
320 const RooArgSet* RooAbsData::get(Int_t index) const
321 {
322  checkInit() ;
323  return _dstore->get(index) ;
324 }
325 
326 ////////////////////////////////////////////////////////////////////////////////
327 /// Internal method -- Cache given set of functions with data
328 
329 void RooAbsData::cacheArgs(const RooAbsArg* cacheOwner, RooArgSet& varSet, const RooArgSet* nset, Bool_t skipZeroWeights)
330 {
331  _dstore->cacheArgs(cacheOwner,varSet,nset,skipZeroWeights) ;
332 }
333 
334 ////////////////////////////////////////////////////////////////////////////////
335 /// Internal method -- Remove cached function values
336 
337 void RooAbsData::resetCache()
338 {
339  _dstore->resetCache() ;
340  _cachedVars.removeAll() ;
341 }
342 
343 ////////////////////////////////////////////////////////////////////////////////
344 /// Internal method -- Attach dataset copied with cache contents to copied instances of functions
345 
346 void RooAbsData::attachCache(const RooAbsArg* newOwner, const RooArgSet& cachedVars)
347 {
348  _dstore->attachCache(newOwner, cachedVars) ;
349 }
350 
351 ////////////////////////////////////////////////////////////////////////////////
352 
353 void RooAbsData::setArgStatus(const RooArgSet& set, Bool_t active)
354 {
355  _dstore->setArgStatus(set,active) ;
356 }
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 /// Control propagation of dirty flags from observables in dataset
360 
361 void RooAbsData::setDirtyProp(Bool_t flag)
362 {
363  _dstore->setDirtyProp(flag) ;
364 }
365 
366 ////////////////////////////////////////////////////////////////////////////////
367 /// Create a reduced copy of this dataset. The caller takes ownership of the returned dataset
368 ///
369 /// The following optional named arguments are accepted
370 /// <table>
371 /// <tr><td> `SelectVars(const RooArgSet& vars)` <td> Only retain the listed observables in the output dataset
372 /// <tr><td> `Cut(const char* expression)` <td> Only retain event surviving the given cut expression
373 /// <tr><td> `Cut(const RooFormulaVar& expr)` <td> Only retain event surviving the given cut formula
374 /// <tr><td> `CutRange(const char* name)` <td> Only retain events inside range with given name. Multiple CutRange
375 /// arguments may be given to select multiple ranges
376 /// <tr><td> `EventRange(int lo, int hi)` <td> Only retain events with given sequential event numbers
377 /// <tr><td> `Name(const char* name)` <td> Give specified name to output dataset
378 /// <tr><td> `Title(const char* name)` <td> Give specified title to output dataset
379 /// </table>
380 
381 RooAbsData* RooAbsData::reduce(const RooCmdArg& arg1,const RooCmdArg& arg2,const RooCmdArg& arg3,const RooCmdArg& arg4,
382  const RooCmdArg& arg5,const RooCmdArg& arg6,const RooCmdArg& arg7,const RooCmdArg& arg8)
383 {
384  // Define configuration for this method
385  RooCmdConfig pc(Form("RooAbsData::reduce(%s)",GetName())) ;
386  pc.defineString("name","Name",0,"") ;
387  pc.defineString("title","Title",0,"") ;
388  pc.defineString("cutRange","CutRange",0,"") ;
389  pc.defineString("cutSpec","CutSpec",0,"") ;
390  pc.defineObject("cutVar","CutVar",0,0) ;
391  pc.defineInt("evtStart","EventRange",0,0) ;
392  pc.defineInt("evtStop","EventRange",1,2000000000) ;
393  pc.defineObject("varSel","SelectVars",0,0) ;
394  pc.defineMutex("CutVar","CutSpec") ;
395 
396  // Process & check varargs
397  pc.process(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ;
398  if (!pc.ok(kTRUE)) {
399  return 0 ;
400  }
401 
402  // Extract values from named arguments
403  const char* cutRange = pc.getString("cutRange",0,kTRUE) ;
404  const char* cutSpec = pc.getString("cutSpec",0,kTRUE) ;
405  RooFormulaVar* cutVar = static_cast<RooFormulaVar*>(pc.getObject("cutVar",0)) ;
406  Int_t nStart = pc.getInt("evtStart",0) ;
407  Int_t nStop = pc.getInt("evtStop",2000000000) ;
408  RooArgSet* varSet = static_cast<RooArgSet*>(pc.getObject("varSel")) ;
409  const char* name = pc.getString("name",0,kTRUE) ;
410  const char* title = pc.getString("title",0,kTRUE) ;
411 
412  // Make sure varSubset doesn't contain any variable not in this dataset
413  RooArgSet varSubset ;
414  if (varSet) {
415  varSubset.add(*varSet) ;
416  TIterator* iter = varSubset.createIterator() ;
417  RooAbsArg* arg ;
418  while((arg=(RooAbsArg*)iter->Next())) {
419  if (!_vars.find(arg->GetName())) {
420  coutW(InputArguments) << "RooAbsData::reduce(" << GetName() << ") WARNING: variable "
421  << arg->GetName() << " not in dataset, ignored" << endl ;
422  varSubset.remove(*arg) ;
423  }
424  }
425  delete iter ;
426  } else {
427  varSubset.add(*get()) ;
428  }
429 
430  RooAbsData* ret = 0 ;
431  if (cutSpec) {
432 
433  RooFormulaVar cutVarTmp(cutSpec,cutSpec,*get()) ;
434  ret = reduceEng(varSubset,&cutVarTmp,cutRange,nStart,nStop,kFALSE) ;
435 
436  } else if (cutVar) {
437 
438  ret = reduceEng(varSubset,cutVar,cutRange,nStart,nStop,kFALSE) ;
439 
440  } else {
441 
442  ret = reduceEng(varSubset,0,cutRange,nStart,nStop,kFALSE) ;
443 
444  }
445 
446  if (!ret) return 0 ;
447 
448  if (name) {
449  ret->SetName(name) ;
450  }
451  if (title) {
452  ret->SetTitle(title) ;
453  }
454 
455  return ret ;
456 }
457 
458 ////////////////////////////////////////////////////////////////////////////////
459 /// Create a subset of the data set by applying the given cut on the data points.
460 /// The cut expression can refer to any variable in the data set. For cuts involving
461 /// other variables, such as intermediate formula objects, use the equivalent
462 /// reduce method specifying the as a RooFormulVar reference.
463 
464 RooAbsData* RooAbsData::reduce(const char* cut)
465 {
466  RooFormulaVar cutVar(cut,cut,*get()) ;
467  return reduceEng(*get(),&cutVar,0,0,2000000000,kFALSE) ;
468 }
469 
470 ////////////////////////////////////////////////////////////////////////////////
471 /// Create a subset of the data set by applying the given cut on the data points.
472 /// The 'cutVar' formula variable is used to select the subset of data points to be
473 /// retained in the reduced data collection.
474 
475 RooAbsData* RooAbsData::reduce(const RooFormulaVar& cutVar)
476 {
477  return reduceEng(*get(),&cutVar,0,0,2000000000,kFALSE) ;
478 }
479 
480 ////////////////////////////////////////////////////////////////////////////////
481 /// Create a subset of the data set by applying the given cut on the data points
482 /// and reducing the dimensions to the specified set.
483 ///
484 /// The cut expression can refer to any variable in the data set. For cuts involving
485 /// other variables, such as intermediate formula objects, use the equivalent
486 /// reduce method specifying the as a RooFormulVar reference.
487 
488 RooAbsData* RooAbsData::reduce(const RooArgSet& varSubset, const char* cut)
489 {
490  // Make sure varSubset doesn't contain any variable not in this dataset
491  RooArgSet varSubset2(varSubset) ;
492  for (const auto arg : varSubset) {
493  if (!_vars.find(arg->GetName())) {
494  coutW(InputArguments) << "RooAbsData::reduce(" << GetName() << ") WARNING: variable "
495  << arg->GetName() << " not in dataset, ignored" << endl ;
496  varSubset2.remove(*arg) ;
497  }
498  }
499 
500  if (cut && strlen(cut)>0) {
501  RooFormulaVar cutVar(cut, cut, *get(), false);
502  return reduceEng(varSubset2,&cutVar,0,0,2000000000,kFALSE) ;
503  }
504  return reduceEng(varSubset2,0,0,0,2000000000,kFALSE) ;
505 }
506 
507 ////////////////////////////////////////////////////////////////////////////////
508 /// Create a subset of the data set by applying the given cut on the data points
509 /// and reducing the dimensions to the specified set.
510 ///
511 /// The 'cutVar' formula variable is used to select the subset of data points to be
512 /// retained in the reduced data collection.
513 
514 RooAbsData* RooAbsData::reduce(const RooArgSet& varSubset, const RooFormulaVar& cutVar)
515 {
516  // Make sure varSubset doesn't contain any variable not in this dataset
517  RooArgSet varSubset2(varSubset) ;
518  TIterator* iter = varSubset.createIterator() ;
519  RooAbsArg* arg ;
520  while((arg=(RooAbsArg*)iter->Next())) {
521  if (!_vars.find(arg->GetName())) {
522  coutW(InputArguments) << "RooAbsData::reduce(" << GetName() << ") WARNING: variable "
523  << arg->GetName() << " not in dataset, ignored" << endl ;
524  varSubset2.remove(*arg) ;
525  }
526  }
527  delete iter ;
528 
529  return reduceEng(varSubset2,&cutVar,0,0,2000000000,kFALSE) ;
530 }
531 
532 ////////////////////////////////////////////////////////////////////////////////
533 /// Return error on current weight (dummy implementation returning zero)
534 
535 Double_t RooAbsData::weightError(ErrorType) const
536 {
537  return 0 ;
538 }
539 
540 ////////////////////////////////////////////////////////////////////////////////
541 /// Return asymmetric error on weight. (Dummy implementation returning zero)
542 
543 void RooAbsData::weightError(Double_t& lo, Double_t& hi, ErrorType) const
544 {
545  lo=0 ; hi=0 ;
546 }
547 
548 
549 RooPlot* RooAbsData::plotOn(RooPlot* frame, const RooCmdArg& arg1, const RooCmdArg& arg2,
550  const RooCmdArg& arg3, const RooCmdArg& arg4, const RooCmdArg& arg5,
551  const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8) const
552 {
553  RooLinkedList l ;
554  l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
555  l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
556  l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
557  l.Add((TObject*)&arg7) ; l.Add((TObject*)&arg8) ;
558  return plotOn(frame,l) ;
559 }
560 
561 ////////////////////////////////////////////////////////////////////////////////
562 /// Create and fill a ROOT histogram TH1,TH2 or TH3 with the values of this dataset for the variables with given names
563 /// The range of each observable that is histogrammed is always automatically calculated from the distribution in
564 /// the dataset. The number of bins can be controlled using the [xyz]bins parameters. For a greater degree of control
565 /// use the createHistogram() method below with named arguments
566 ///
567 /// The caller takes ownership of the returned histogram
568 
569 TH1 *RooAbsData::createHistogram(const char* varNameList, Int_t xbins, Int_t ybins, Int_t zbins) const
570 {
571  // Parse list of variable names
572  char buf[1024] ;
573  strlcpy(buf,varNameList,1024) ;
574  char* varName = strtok(buf,",:") ;
575 
576  RooRealVar* xvar = (RooRealVar*) get()->find(varName) ;
577  if (!xvar) {
578  coutE(InputArguments) << "RooAbsData::createHistogram(" << GetName() << ") ERROR: dataset does not contain an observable named " << varName << endl ;
579  return 0 ;
580  }
581  varName = strtok(0,",") ;
582  RooRealVar* yvar = varName ? (RooRealVar*) get()->find(varName) : 0 ;
583  if (varName && !yvar) {
584  coutE(InputArguments) << "RooAbsData::createHistogram(" << GetName() << ") ERROR: dataset does not contain an observable named " << varName << endl ;
585  return 0 ;
586  }
587  varName = strtok(0,",") ;
588  RooRealVar* zvar = varName ? (RooRealVar*) get()->find(varName) : 0 ;
589  if (varName && !zvar) {
590  coutE(InputArguments) << "RooAbsData::createHistogram(" << GetName() << ") ERROR: dataset does not contain an observable named " << varName << endl ;
591  return 0 ;
592  }
593 
594  // Construct list of named arguments to pass to the implementation version of createHistogram()
595 
596  RooLinkedList argList ;
597  if (xbins<=0 || !xvar->hasMax() || !xvar->hasMin() ) {
598  argList.Add(RooFit::AutoBinning(xbins==0?xvar->numBins():abs(xbins)).Clone()) ;
599  } else {
600  argList.Add(RooFit::Binning(xbins).Clone()) ;
601  }
602 
603  if (yvar) {
604  if (ybins<=0 || !yvar->hasMax() || !yvar->hasMin() ) {
605  argList.Add(RooFit::YVar(*yvar,RooFit::AutoBinning(ybins==0?yvar->numBins():abs(ybins))).Clone()) ;
606  } else {
607  argList.Add(RooFit::YVar(*yvar,RooFit::Binning(ybins)).Clone()) ;
608  }
609  }
610 
611  if (zvar) {
612  if (zbins<=0 || !zvar->hasMax() || !zvar->hasMin() ) {
613  argList.Add(RooFit::ZVar(*zvar,RooFit::AutoBinning(zbins==0?zvar->numBins():abs(zbins))).Clone()) ;
614  } else {
615  argList.Add(RooFit::ZVar(*zvar,RooFit::Binning(zbins)).Clone()) ;
616  }
617  }
618 
619 
620 
621  // Call implementation function
622  TH1* result = createHistogram(GetName(),*xvar,argList) ;
623 
624  // Delete temporary list of RooCmdArgs
625  argList.Delete() ;
626 
627  return result ;
628 }
629 
630 
631 TH1 *RooAbsData::createHistogram(const char *name, const RooAbsRealLValue& xvar,
632  const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3, const RooCmdArg& arg4,
633  const RooCmdArg& arg5, const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8) const
634 {
635  RooLinkedList l ;
636  l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
637  l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
638  l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
639  l.Add((TObject*)&arg7) ; l.Add((TObject*)&arg8) ;
640 
641  return createHistogram(name,xvar,l) ;
642 }
643 
644 ////////////////////////////////////////////////////////////////////////////////
645 ///
646 /// This function accepts the following arguments
647 ///
648 /// \param[in] name Name of the ROOT histogram
649 /// \param[in] xvar Observable to be mapped on x axis of ROOT histogram
650 /// \return Histogram now owned by user.
651 ///
652 /// <table>
653 /// <tr><td> `AutoBinning(Int_t nbins, Double_y margin)` <td> Automatically calculate range with given added fractional margin, set binning to nbins
654 /// <tr><td> `AutoSymBinning(Int_t nbins, Double_y margin)` <td> Automatically calculate range with given added fractional margin,
655 /// with additional constraint that mean of data is in center of range, set binning to nbins
656 /// <tr><td> `Binning(const char* name)` <td> Apply binning with given name to x axis of histogram
657 /// <tr><td> `Binning(RooAbsBinning& binning)` <td> Apply specified binning to x axis of histogram
658 /// <tr><td> `Binning(int nbins, double lo, double hi)` <td> Apply specified binning to x axis of histogram
659 ///
660 /// <tr><td> `YVar(const RooAbsRealLValue& var,...)` <td> Observable to be mapped on y axis of ROOT histogram
661 /// <tr><td> `ZVar(const RooAbsRealLValue& var,...)` <td> Observable to be mapped on z axis of ROOT histogram
662 /// </table>
663 ///
664 /// The YVar() and ZVar() arguments can be supplied with optional Binning() Auto(Sym)Range() arguments to control the binning of the Y and Z axes, e.g.
665 /// ```
666 /// createHistogram("histo",x,Binning(-1,1,20), YVar(y,Binning(-1,1,30)), ZVar(z,Binning("zbinning")))
667 /// ```
668 ///
669 /// The caller takes ownership of the returned histogram
670 
671 TH1 *RooAbsData::createHistogram(const char *name, const RooAbsRealLValue& xvar, const RooLinkedList& argListIn) const
672 {
673  RooLinkedList argList(argListIn) ;
674 
675  // Define configuration for this method
676  RooCmdConfig pc(Form("RooAbsData::createHistogram(%s)",GetName())) ;
677  pc.defineString("cutRange","CutRange",0,"",kTRUE) ;
678  pc.defineString("cutString","CutSpec",0,"") ;
679  pc.defineObject("yvar","YVar",0,0) ;
680  pc.defineObject("zvar","ZVar",0,0) ;
681  pc.allowUndefined() ;
682 
683  // Process & check varargs
684  pc.process(argList) ;
685  if (!pc.ok(kTRUE)) {
686  return 0 ;
687  }
688 
689  const char* cutSpec = pc.getString("cutString",0,kTRUE) ;
690  const char* cutRange = pc.getString("cutRange",0,kTRUE) ;
691 
692  RooArgList vars(xvar) ;
693  RooAbsArg* yvar = static_cast<RooAbsArg*>(pc.getObject("yvar")) ;
694  if (yvar) {
695  vars.add(*yvar) ;
696  }
697  RooAbsArg* zvar = static_cast<RooAbsArg*>(pc.getObject("zvar")) ;
698  if (zvar) {
699  vars.add(*zvar) ;
700  }
701 
702  pc.stripCmdList(argList,"CutRange,CutSpec") ;
703 
704  // Swap Auto(Sym)RangeData with a Binning command
705  RooLinkedList ownedCmds ;
706  RooCmdArg* autoRD = (RooCmdArg*) argList.find("AutoRangeData") ;
707  if (autoRD) {
708  Double_t xmin,xmax ;
709  getRange((RooRealVar&)xvar,xmin,xmax,autoRD->getDouble(0),autoRD->getInt(0)) ;
710  RooCmdArg* bincmd = (RooCmdArg*) RooFit::Binning(autoRD->getInt(1),xmin,xmax).Clone() ;
711  ownedCmds.Add(bincmd) ;
712  argList.Replace(autoRD,bincmd) ;
713  }
714 
715  if (yvar) {
716  RooCmdArg* autoRDY = (RooCmdArg*) ((RooCmdArg*)argList.find("YVar"))->subArgs().find("AutoRangeData") ;
717  if (autoRDY) {
718  Double_t ymin,ymax ;
719  getRange((RooRealVar&)(*yvar),ymin,ymax,autoRDY->getDouble(0),autoRDY->getInt(0)) ;
720  RooCmdArg* bincmd = (RooCmdArg*) RooFit::Binning(autoRDY->getInt(1),ymin,ymax).Clone() ;
721  //ownedCmds.Add(bincmd) ;
722  ((RooCmdArg*)argList.find("YVar"))->subArgs().Replace(autoRDY,bincmd) ;
723  delete autoRDY ;
724  }
725  }
726 
727  if (zvar) {
728  RooCmdArg* autoRDZ = (RooCmdArg*) ((RooCmdArg*)argList.find("ZVar"))->subArgs().find("AutoRangeData") ;
729  if (autoRDZ) {
730  Double_t zmin,zmax ;
731  getRange((RooRealVar&)(*zvar),zmin,zmax,autoRDZ->getDouble(0),autoRDZ->getInt(0)) ;
732  RooCmdArg* bincmd = (RooCmdArg*) RooFit::Binning(autoRDZ->getInt(1),zmin,zmax).Clone() ;
733  //ownedCmds.Add(bincmd) ;
734  ((RooCmdArg*)argList.find("ZVar"))->subArgs().Replace(autoRDZ,bincmd) ;
735  delete autoRDZ ;
736  }
737  }
738 
739 
740  TH1* histo = xvar.createHistogram(name,argList) ;
741  fillHistogram(histo,vars,cutSpec,cutRange) ;
742 
743  ownedCmds.Delete() ;
744 
745  return histo ;
746 }
747 
748 ////////////////////////////////////////////////////////////////////////////////
749 /// Construct table for product of categories in catSet
750 
751 Roo1DTable* RooAbsData::table(const RooArgSet& catSet, const char* cuts, const char* opts) const
752 {
753  RooArgSet catSet2 ;
754 
755  string prodName("(") ;
756  TIterator* iter = catSet.createIterator() ;
757  RooAbsArg* arg ;
758  while((arg=(RooAbsArg*)iter->Next())) {
759  if (dynamic_cast<RooAbsCategory*>(arg)) {
760  RooAbsCategory* varsArg = dynamic_cast<RooAbsCategory*>(_vars.find(arg->GetName())) ;
761  if (varsArg != 0) catSet2.add(*varsArg) ;
762  else catSet2.add(*arg) ;
763  if (prodName.length()>1) {
764  prodName += " x " ;
765  }
766  prodName += arg->GetName() ;
767  } else {
768  coutW(InputArguments) << "RooAbsData::table(" << GetName() << ") non-RooAbsCategory input argument " << arg->GetName() << " ignored" << endl ;
769  }
770  }
771  prodName += ")" ;
772  delete iter ;
773 
774  RooMultiCategory tmp(prodName.c_str(),prodName.c_str(),catSet2) ;
775  return table(tmp,cuts,opts) ;
776 }
777 
778 ////////////////////////////////////////////////////////////////////////////////
779 /// Print name of dataset
780 
781 void RooAbsData::printName(ostream& os) const
782 {
783  os << GetName() ;
784 }
785 
786 ////////////////////////////////////////////////////////////////////////////////
787 /// Print title of dataset
788 
789 void RooAbsData::printTitle(ostream& os) const
790 {
791  os << GetTitle() ;
792 }
793 
794 ////////////////////////////////////////////////////////////////////////////////
795 /// Print class name of dataset
796 
797 void RooAbsData::printClassName(ostream& os) const
798 {
799  os << IsA()->GetName() ;
800 }
801 
802 ////////////////////////////////////////////////////////////////////////////////
803 
804 void RooAbsData::printMultiline(ostream& os, Int_t contents, Bool_t verbose, TString indent) const
805 {
806  _dstore->printMultiline(os,contents,verbose,indent) ;
807 }
808 
809 ////////////////////////////////////////////////////////////////////////////////
810 /// Define default print options, for a given print style
811 
812 Int_t RooAbsData::defaultPrintContents(Option_t* /*opt*/) const
813 {
814  return kName|kClassName|kArgs|kValue ;
815 }
816 
817 ////////////////////////////////////////////////////////////////////////////////
818 /// Calculate standardized moment.
819 ///
820 /// \param[in] var Variable to be used for calculating the moment.
821 /// \param[in] order Order of the moment.
822 /// \param[in] cutSpec If specified, the moment is calculated on the subset of the data which pass the C++ cut specification expression 'cutSpec'
823 /// \param[in] cutRange If specified, calculate inside the range named 'cutRange' (also applies cut spec)
824 /// \return \f$ \frac{\left< \left( X - \left< X \right> \right)^n \right>}{\sigma^n} \f$, where n = order.
825 
826 Double_t RooAbsData::standMoment(RooRealVar &var, Double_t order, const char* cutSpec, const char* cutRange) const
827 {
828  // Hardwire invariant answer for first and second moment
829  if (order==1) return 0 ;
830  if (order==2) return 1 ;
831 
832  return moment(var,order,cutSpec,cutRange) / TMath::Power(sigma(var,cutSpec,cutRange),order) ;
833 }
834 
835 ////////////////////////////////////////////////////////////////////////////////
836 /// Calculate moment of requested order.
837 ///
838 /// \param[in] var Variable to be used for calculating the moment.
839 /// \param[in] order Order of the moment.
840 /// \param[in] cutSpec If specified, the moment is calculated on the subset of the data which pass the C++ cut specification expression 'cutSpec'
841 /// \param[in] cutRange If specified, calculate inside the range named 'cutRange' (also applies cut spec)
842 /// \return \f$ \left< \left( X - \left< X \right> \right)^n \right> \f$ of order \f$n\f$.
843 ///
844 
845 Double_t RooAbsData::moment(RooRealVar &var, Double_t order, const char* cutSpec, const char* cutRange) const
846 {
847  Double_t offset = order>1 ? moment(var,1,cutSpec,cutRange) : 0 ;
848  return moment(var,order,offset,cutSpec,cutRange) ;
849 
850 }
851 
852 ////////////////////////////////////////////////////////////////////////////////
853 /// Return the 'order'-ed moment of observable 'var' in this dataset. If offset is non-zero it is subtracted
854 /// from the values of 'var' prior to the moment calculation. If cutSpec and/or cutRange are specified
855 /// the moment is calculated on the subset of the data which pass the C++ cut specification expression 'cutSpec'
856 /// and/or are inside the range named 'cutRange'
857 
858 Double_t RooAbsData::moment(RooRealVar &var, Double_t order, Double_t offset, const char* cutSpec, const char* cutRange) const
859 {
860  // Lookup variable in dataset
861  RooRealVar *varPtr= (RooRealVar*) _vars.find(var.GetName());
862  if(0 == varPtr) {
863  coutE(InputArguments) << "RooDataSet::moment(" << GetName() << ") ERROR: unknown variable: " << var.GetName() << endl ;
864  return 0;
865  }
866 
867  // Check if found variable is of type RooRealVar
868  if (!dynamic_cast<RooRealVar*>(varPtr)) {
869  coutE(InputArguments) << "RooDataSet::moment(" << GetName() << ") ERROR: variable " << var.GetName() << " is not of type RooRealVar" << endl ;
870  return 0;
871  }
872 
873  // Check if dataset is not empty
874  if(sumEntries(cutSpec, cutRange) == 0.) {
875  coutE(InputArguments) << "RooDataSet::moment(" << GetName() << ") WARNING: empty dataset" << endl ;
876  return 0;
877  }
878 
879  // Setup RooFormulaVar for cutSpec if it is present
880  std::unique_ptr<RooFormula> select;
881  if (cutSpec) {
882  select.reset(new RooFormula("select",cutSpec,*get()));
883  }
884 
885 
886  // Calculate requested moment
887  Double_t sum(0);
888  const RooArgSet* vars ;
889  for(Int_t index= 0; index < numEntries(); index++) {
890  vars = get(index) ;
891  if (select && select->eval()==0) continue ;
892  if (cutRange && vars->allInRange(cutRange)) continue ;
893 
894  sum+= weight() * TMath::Power(varPtr->getVal() - offset,order);
895  }
896  return sum/sumEntries(cutSpec, cutRange);
897 }
898 
899 ////////////////////////////////////////////////////////////////////////////////
900 /// Internal method to check if given RooRealVar maps to a RooRealVar in this dataset
901 
902 RooRealVar* RooAbsData::dataRealVar(const char* methodname, RooRealVar& extVar) const
903 {
904  // Lookup variable in dataset
905  RooRealVar *xdata = (RooRealVar*) _vars.find(extVar.GetName());
906  if(!xdata) {
907  coutE(InputArguments) << "RooDataSet::" << methodname << "(" << GetName() << ") ERROR: variable : " << extVar.GetName() << " is not in data" << endl ;
908  return 0;
909  }
910  // Check if found variable is of type RooRealVar
911  if (!dynamic_cast<RooRealVar*>(xdata)) {
912  coutE(InputArguments) << "RooDataSet::" << methodname << "(" << GetName() << ") ERROR: variable : " << extVar.GetName() << " is not of type RooRealVar in data" << endl ;
913  return 0;
914  }
915  return xdata;
916 }
917 
918 ////////////////////////////////////////////////////////////////////////////////
919 /// Internal method to calculate single correlation and covariance elements
920 
921 Double_t RooAbsData::corrcov(RooRealVar &x,RooRealVar &y, const char* cutSpec, const char* cutRange, Bool_t corr) const
922 {
923  // Lookup variable in dataset
924  RooRealVar *xdata = dataRealVar(corr?"correlation":"covariance",x) ;
925  RooRealVar *ydata = dataRealVar(corr?"correlation":"covariance",y) ;
926  if (!xdata||!ydata) return 0 ;
927 
928  // Check if dataset is not empty
929  if(sumEntries(cutSpec, cutRange) == 0.) {
930  coutW(InputArguments) << "RooDataSet::" << (corr?"correlation":"covariance") << "(" << GetName() << ") WARNING: empty dataset, returning zero" << endl ;
931  return 0;
932  }
933 
934  // Setup RooFormulaVar for cutSpec if it is present
935  RooFormula* select = cutSpec ? new RooFormula("select",cutSpec,*get()) : 0 ;
936 
937  // Calculate requested moment
938  Double_t xysum(0),xsum(0),ysum(0),x2sum(0),y2sum(0);
939  const RooArgSet* vars ;
940  for(Int_t index= 0; index < numEntries(); index++) {
941  vars = get(index) ;
942  if (select && select->eval()==0) continue ;
943  if (cutRange && vars->allInRange(cutRange)) continue ;
944 
945  xysum += weight()*xdata->getVal()*ydata->getVal() ;
946  xsum += weight()*xdata->getVal() ;
947  ysum += weight()*ydata->getVal() ;
948  if (corr) {
949  x2sum += weight()*xdata->getVal()*xdata->getVal() ;
950  y2sum += weight()*ydata->getVal()*ydata->getVal() ;
951  }
952  }
953 
954  // Normalize entries
955  xysum/=sumEntries(cutSpec, cutRange) ;
956  xsum/=sumEntries(cutSpec, cutRange) ;
957  ysum/=sumEntries(cutSpec, cutRange) ;
958  if (corr) {
959  x2sum/=sumEntries(cutSpec, cutRange) ;
960  y2sum/=sumEntries(cutSpec, cutRange) ;
961  }
962 
963  // Cleanup
964  if (select) delete select ;
965 
966  // Return covariance or correlation as requested
967  if (corr) {
968  return (xysum-xsum*ysum)/(sqrt(x2sum-(xsum*xsum))*sqrt(y2sum-(ysum*ysum))) ;
969  } else {
970  return (xysum-xsum*ysum);
971  }
972 }
973 
974 ////////////////////////////////////////////////////////////////////////////////
975 /// Return covariance matrix from data for given list of observables
976 
977 TMatrixDSym* RooAbsData::corrcovMatrix(const RooArgList& vars, const char* cutSpec, const char* cutRange, Bool_t corr) const
978 {
979  RooArgList varList ;
980  TIterator* iter = vars.createIterator() ;
981  RooRealVar* var ;
982  while((var=(RooRealVar*)iter->Next())) {
983  RooRealVar* datavar = dataRealVar("covarianceMatrix",*var) ;
984  if (!datavar) {
985  delete iter ;
986  return 0 ;
987  }
988  varList.add(*datavar) ;
989  }
990  delete iter ;
991 
992 
993  // Check if dataset is not empty
994  if(sumEntries(cutSpec, cutRange) == 0.) {
995  coutW(InputArguments) << "RooDataSet::covariance(" << GetName() << ") WARNING: empty dataset, returning zero" << endl ;
996  return 0;
997  }
998 
999  // Setup RooFormulaVar for cutSpec if it is present
1000  RooFormula* select = cutSpec ? new RooFormula("select",cutSpec,*get()) : 0 ;
1001 
1002  iter = varList.createIterator() ;
1003  TIterator* iter2 = varList.createIterator() ;
1004 
1005  TMatrixDSym xysum(varList.getSize()) ;
1006  vector<double> xsum(varList.getSize()) ;
1007  vector<double> x2sum(varList.getSize()) ;
1008 
1009  // Calculate <x_i> and <x_i y_j>
1010  for(Int_t index= 0; index < numEntries(); index++) {
1011  const RooArgSet* dvars = get(index) ;
1012  if (select && select->eval()==0) continue ;
1013  if (cutRange && dvars->allInRange(cutRange)) continue ;
1014 
1015  RooRealVar* varx, *vary ;
1016  iter->Reset() ;
1017  Int_t ix=0,iy=0 ;
1018  while((varx=(RooRealVar*)iter->Next())) {
1019  xsum[ix] += weight()*varx->getVal() ;
1020  if (corr) {
1021  x2sum[ix] += weight()*varx->getVal()*varx->getVal() ;
1022  }
1023 
1024  *iter2=*iter ; iy=ix ;
1025  vary=varx ;
1026  while(vary) {
1027  xysum(ix,iy) += weight()*varx->getVal()*vary->getVal() ;
1028  xysum(iy,ix) = xysum(ix,iy) ;
1029  iy++ ;
1030  vary=(RooRealVar*)iter2->Next() ;
1031  }
1032  ix++ ;
1033  }
1034 
1035  }
1036 
1037  // Normalize sums
1038  for (Int_t ix=0 ; ix<varList.getSize() ; ix++) {
1039  xsum[ix] /= sumEntries(cutSpec, cutRange) ;
1040  if (corr) {
1041  x2sum[ix] /= sumEntries(cutSpec, cutRange) ;
1042  }
1043  for (Int_t iy=0 ; iy<varList.getSize() ; iy++) {
1044  xysum(ix,iy) /= sumEntries(cutSpec, cutRange) ;
1045  }
1046  }
1047 
1048  // Calculate covariance matrix
1049  TMatrixDSym* C = new TMatrixDSym(varList.getSize()) ;
1050  for (Int_t ix=0 ; ix<varList.getSize() ; ix++) {
1051  for (Int_t iy=0 ; iy<varList.getSize() ; iy++) {
1052  (*C)(ix,iy) = xysum(ix,iy)-xsum[ix]*xsum[iy] ;
1053  if (corr) {
1054  (*C)(ix,iy) /= sqrt((x2sum[ix]-(xsum[ix]*xsum[ix]))*(x2sum[iy]-(xsum[iy]*xsum[iy]))) ;
1055  }
1056  }
1057  }
1058 
1059  if (select) delete select ;
1060  delete iter ;
1061  delete iter2 ;
1062 
1063  return C ;
1064 }
1065 
1066 ////////////////////////////////////////////////////////////////////////////////
1067 /// Create a RooRealVar containing the mean of observable 'var' in
1068 /// this dataset. If cutSpec and/or cutRange are specified the
1069 /// moment is calculated on the subset of the data which pass the C++
1070 /// cut specification expression 'cutSpec' and/or are inside the
1071 /// range named 'cutRange'
1072 
1073 RooRealVar* RooAbsData::meanVar(RooRealVar &var, const char* cutSpec, const char* cutRange) const
1074 {
1075  // Create a new variable with appropriate strings. The error is calculated as
1076  // RMS/Sqrt(N) which is generally valid.
1077 
1078  // Create holder variable for mean
1079  TString name(var.GetName()),title("Mean of ") ;
1080  name.Append("Mean");
1081  title.Append(var.GetTitle());
1082  RooRealVar *meanv= new RooRealVar(name,title,0) ;
1083  meanv->setConstant(kFALSE) ;
1084 
1085  // Adjust plot label
1086  TString label("<") ;
1087  label.Append(var.getPlotLabel());
1088  label.Append(">");
1089  meanv->setPlotLabel(label.Data());
1090 
1091  // fill in this variable's value and error
1092  Double_t meanVal=moment(var,1,0,cutSpec,cutRange) ;
1093  Double_t N(sumEntries(cutSpec,cutRange)) ;
1094 
1095  Double_t rmsVal= sqrt(moment(var,2,meanVal,cutSpec,cutRange)*N/(N-1));
1096  meanv->setVal(meanVal) ;
1097  meanv->setError(N > 0 ? rmsVal/sqrt(N) : 0);
1098 
1099  return meanv;
1100 }
1101 
1102 ////////////////////////////////////////////////////////////////////////////////
1103 /// Create a RooRealVar containing the RMS of observable 'var' in
1104 /// this dataset. If cutSpec and/or cutRange are specified the
1105 /// moment is calculated on the subset of the data which pass the C++
1106 /// cut specification expression 'cutSpec' and/or are inside the
1107 /// range named 'cutRange'
1108 
1109 RooRealVar* RooAbsData::rmsVar(RooRealVar &var, const char* cutSpec, const char* cutRange) const
1110 {
1111  // Create a new variable with appropriate strings. The error is calculated as
1112  // RMS/(2*Sqrt(N)) which is only valid if the variable has a Gaussian distribution.
1113 
1114  // Create RMS value holder
1115  TString name(var.GetName()),title("RMS of ") ;
1116  name.Append("RMS");
1117  title.Append(var.GetTitle());
1118  RooRealVar *rms= new RooRealVar(name,title,0) ;
1119  rms->setConstant(kFALSE) ;
1120 
1121  // Adjust plot label
1122  TString label(var.getPlotLabel());
1123  label.Append("_{RMS}");
1124  rms->setPlotLabel(label);
1125 
1126  // Fill in this variable's value and error
1127  Double_t meanVal(moment(var,1,0,cutSpec,cutRange)) ;
1128  Double_t N(sumEntries(cutSpec, cutRange));
1129  Double_t rmsVal= sqrt(moment(var,2,meanVal,cutSpec,cutRange)*N/(N-1));
1130  rms->setVal(rmsVal) ;
1131  rms->setError(rmsVal/sqrt(2*N));
1132 
1133  return rms;
1134 }
1135 
1136 ////////////////////////////////////////////////////////////////////////////////
1137 /// Add a box with statistics information to the specified frame. By default a box with the
1138 /// event count, mean and rms of the plotted variable is added.
1139 ///
1140 /// The following optional named arguments are accepted
1141 /// <table>
1142 /// <tr><td> `What(const char* whatstr)` <td> Controls what is printed: "N" = count, "M" is mean, "R" is RMS.
1143 /// <tr><td> `Format(const char* optStr)` <td> \deprecated Classing parameter formatting options, provided for backward compatibility
1144 ///
1145 /// <tr><td> `Format(const char* what,...)` <td> Parameter formatting options.
1146 /// <table>
1147 /// <tr><td> const char* what <td> Controls what is shown:
1148 /// - "N" adds name
1149 /// - "E" adds error
1150 /// - "A" shows asymmetric error
1151 /// - "U" shows unit
1152 /// - "H" hides the value
1153 /// <tr><td> `FixedPrecision(int n)` <td> Controls precision, set fixed number of digits
1154 /// <tr><td> `AutoPrecision(int n)` <td> Controls precision. Number of shown digits is calculated from error + n specified additional digits (1 is sensible default)
1155 /// <tr><td> `VerbatimName(Bool_t flag)` <td> Put variable name in a \\verb+ + clause.
1156 /// </table>
1157 /// <tr><td> `Label(const chat* label)` <td> Add header label to parameter box
1158 /// <tr><td> `Layout(Double_t xmin, Double_t xmax, Double_t ymax)` <td> Specify relative position of left,right side of box and top of box. Position of
1159 /// bottom of box is calculated automatically from number lines in box
1160 /// <tr><td> `Cut(const char* expression)` <td> Apply given cut expression to data when calculating statistics
1161 /// <tr><td> `CutRange(const char* rangeName)` <td> Only consider events within given range when calculating statistics. Multiple
1162 /// CutRange() argument may be specified to combine ranges.
1163 ///
1164 /// </table>
1165 
1166 RooPlot* RooAbsData::statOn(RooPlot* frame, const RooCmdArg& arg1, const RooCmdArg& arg2,
1167  const RooCmdArg& arg3, const RooCmdArg& arg4, const RooCmdArg& arg5,
1168  const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8)
1169 {
1170  // Stuff all arguments in a list
1171  RooLinkedList cmdList;
1172  cmdList.Add(const_cast<RooCmdArg*>(&arg1)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg2)) ;
1173  cmdList.Add(const_cast<RooCmdArg*>(&arg3)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg4)) ;
1174  cmdList.Add(const_cast<RooCmdArg*>(&arg5)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg6)) ;
1175  cmdList.Add(const_cast<RooCmdArg*>(&arg7)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg8)) ;
1176 
1177  // Select the pdf-specific commands
1178  RooCmdConfig pc(Form("RooTreeData::statOn(%s)",GetName())) ;
1179  pc.defineString("what","What",0,"MNR") ;
1180  pc.defineString("label","Label",0,"") ;
1181  pc.defineDouble("xmin","Layout",0,0.65) ;
1182  pc.defineDouble("xmax","Layout",1,0.99) ;
1183  pc.defineInt("ymaxi","Layout",0,Int_t(0.95*10000)) ;
1184  pc.defineString("formatStr","Format",0,"NELU") ;
1185  pc.defineInt("sigDigit","Format",0,2) ;
1186  pc.defineInt("dummy","FormatArgs",0,0) ;
1187  pc.defineString("cutRange","CutRange",0,"",kTRUE) ;
1188  pc.defineString("cutString","CutSpec",0,"") ;
1189  pc.defineMutex("Format","FormatArgs") ;
1190 
1191  // Process and check varargs
1192  pc.process(cmdList) ;
1193  if (!pc.ok(kTRUE)) {
1194  return frame ;
1195  }
1196 
1197  const char* label = pc.getString("label") ;
1198  Double_t xmin = pc.getDouble("xmin") ;
1199  Double_t xmax = pc.getDouble("xmax") ;
1200  Double_t ymax = pc.getInt("ymaxi") / 10000. ;
1201  const char* formatStr = pc.getString("formatStr") ;
1202  Int_t sigDigit = pc.getInt("sigDigit") ;
1203  const char* what = pc.getString("what") ;
1204 
1205  const char* cutSpec = pc.getString("cutString",0,kTRUE) ;
1206  const char* cutRange = pc.getString("cutRange",0,kTRUE) ;
1207 
1208  if (pc.hasProcessed("FormatArgs")) {
1209  RooCmdArg* formatCmd = static_cast<RooCmdArg*>(cmdList.FindObject("FormatArgs")) ;
1210  return statOn(frame,what,label,0,0,xmin,xmax,ymax,cutSpec,cutRange,formatCmd) ;
1211  } else {
1212  return statOn(frame,what,label,sigDigit,formatStr,xmin,xmax,ymax,cutSpec,cutRange) ;
1213  }
1214 }
1215 
1216 ////////////////////////////////////////////////////////////////////////////////
1217 /// Implementation back-end of statOn() method with named arguments
1218 
1219 RooPlot* RooAbsData::statOn(RooPlot* frame, const char* what, const char *label, Int_t sigDigits,
1220  Option_t *options, Double_t xmin, Double_t xmax, Double_t ymax,
1221  const char* cutSpec, const char* cutRange, const RooCmdArg* formatCmd)
1222 {
1223  Bool_t showLabel= (label != 0 && strlen(label) > 0);
1224 
1225  TString whatStr(what) ;
1226  whatStr.ToUpper() ;
1227  Bool_t showN = whatStr.Contains("N") ;
1228  Bool_t showR = whatStr.Contains("R") ;
1229  Bool_t showM = whatStr.Contains("M") ;
1230  Int_t nPar= 0;
1231  if (showN) nPar++ ;
1232  if (showR) nPar++ ;
1233  if (showM) nPar++ ;
1234 
1235  // calculate the box's size
1236  Double_t dy(0.06), ymin(ymax-nPar*dy);
1237  if(showLabel) ymin-= dy;
1238 
1239  // create the box and set its options
1240  TPaveText *box= new TPaveText(xmin,ymax,xmax,ymin,"BRNDC");
1241  if(!box) return 0;
1242  box->SetName(Form("%s_statBox",GetName())) ;
1243  box->SetFillColor(0);
1244  box->SetBorderSize(1);
1245  box->SetTextAlign(12);
1246  box->SetTextSize(0.04F);
1247  box->SetFillStyle(1001);
1248 
1249  // add formatted text for each statistic
1250  RooRealVar N("N","Number of Events",sumEntries(cutSpec,cutRange));
1251  N.setPlotLabel("Entries") ;
1252  RooRealVar *meanv= meanVar(*(RooRealVar*)frame->getPlotVar(),cutSpec,cutRange);
1253  meanv->setPlotLabel("Mean") ;
1254  RooRealVar *rms= rmsVar(*(RooRealVar*)frame->getPlotVar(),cutSpec,cutRange);
1255  rms->setPlotLabel("RMS") ;
1256  TString *rmsText, *meanText, *NText ;
1257  if (options) {
1258  rmsText= rms->format(sigDigits,options);
1259  meanText= meanv->format(sigDigits,options);
1260  NText= N.format(sigDigits,options);
1261  } else {
1262  rmsText= rms->format(*formatCmd);
1263  meanText= meanv->format(*formatCmd);
1264  NText= N.format(*formatCmd);
1265  }
1266  if (showR) box->AddText(rmsText->Data());
1267  if (showM) box->AddText(meanText->Data());
1268  if (showN) box->AddText(NText->Data());
1269 
1270  // cleanup heap memory
1271  delete NText;
1272  delete meanText;
1273  delete rmsText;
1274  delete meanv;
1275  delete rms;
1276 
1277  // add the optional label if specified
1278  if(showLabel) box->AddText(label);
1279 
1280  frame->addObject(box) ;
1281  return frame ;
1282 }
1283 
1284 ////////////////////////////////////////////////////////////////////////////////
1285 /// Loop over columns of our tree data and fill the input histogram. Returns a pointer to the
1286 /// input histogram, or zero in case of an error. The input histogram can be any TH1 subclass, and
1287 /// therefore of arbitrary dimension. Variables are matched with the (x,y,...) dimensions of the input
1288 /// histogram according to the order in which they appear in the input plotVars list.
1289 
1290 TH1 *RooAbsData::fillHistogram(TH1 *hist, const RooArgList &plotVars, const char *cuts, const char* cutRange) const
1291 {
1292  // Do we have a valid histogram to use?
1293  if(0 == hist) {
1294  coutE(InputArguments) << ClassName() << "::" << GetName() << ":fillHistogram: no valid histogram to fill" << endl;
1295  return 0;
1296  }
1297 
1298  // Check that the number of plotVars matches the input histogram's dimension
1299  Int_t hdim= hist->GetDimension();
1300  if(hdim != plotVars.getSize()) {
1301  coutE(InputArguments) << ClassName() << "::" << GetName() << ":fillHistogram: plotVars has the wrong dimension" << endl;
1302  return 0;
1303  }
1304 
1305  // Check that the plot variables are all actually RooAbsReal's and print a warning if we do not
1306  // explicitly depend on one of them. Clone any variables that we do not contain directly and
1307  // redirect them to use our event data.
1308  RooArgSet plotClones,localVars;
1309  for(Int_t index= 0; index < plotVars.getSize(); index++) {
1310  const RooAbsArg *var= plotVars.at(index);
1311  const RooAbsReal *realVar= dynamic_cast<const RooAbsReal*>(var);
1312  if(0 == realVar) {
1313  coutE(InputArguments) << ClassName() << "::" << GetName() << ":fillHistogram: cannot plot variable \"" << var->GetName()
1314  << "\" of type " << var->ClassName() << endl;
1315  return 0;
1316  }
1317  RooAbsArg *found= _vars.find(realVar->GetName());
1318  if(!found) {
1319  RooAbsArg *clone= plotClones.addClone(*realVar,kTRUE); // do not complain about duplicates
1320  assert(0 != clone);
1321  if(!clone->dependsOn(_vars)) {
1322  coutE(InputArguments) << ClassName() << "::" << GetName()
1323  << ":fillHistogram: Data does not contain the variable '" << realVar->GetName() << "'." << endl;
1324  return nullptr;
1325  }
1326  else {
1327  clone->recursiveRedirectServers(_vars);
1328  }
1329  localVars.add(*clone);
1330  }
1331  else {
1332  localVars.add(*found);
1333  }
1334  }
1335 
1336  // Create selection formula if selection cuts are specified
1337  std::unique_ptr<RooFormula> select;
1338  if (cuts != nullptr && strlen(cuts) > 0) {
1339  select.reset(new RooFormula(cuts, cuts, _vars, false));
1340  if (!select || !select->ok()) {
1341  coutE(InputArguments) << ClassName() << "::" << GetName() << ":fillHistogram: invalid cuts \"" << cuts << "\"" << endl;
1342  return 0 ;
1343  }
1344  }
1345 
1346  // Lookup each of the variables we are binning in our tree variables
1347  const RooAbsReal *xvar = 0;
1348  const RooAbsReal *yvar = 0;
1349  const RooAbsReal *zvar = 0;
1350  switch(hdim) {
1351  case 3:
1352  zvar= dynamic_cast<RooAbsReal*>(localVars.find(plotVars.at(2)->GetName()));
1353  assert(0 != zvar);
1354  // fall through to next case...
1355  case 2:
1356  yvar= dynamic_cast<RooAbsReal*>(localVars.find(plotVars.at(1)->GetName()));
1357  assert(0 != yvar);
1358  // fall through to next case...
1359  case 1:
1360  xvar= dynamic_cast<RooAbsReal*>(localVars.find(plotVars.at(0)->GetName()));
1361  assert(0 != xvar);
1362  break;
1363  default:
1364  coutE(InputArguments) << ClassName() << "::" << GetName() << ":fillHistogram: cannot fill histogram with "
1365  << hdim << " dimensions" << endl;
1366  break;
1367  }
1368 
1369  // Parse cutRange specification
1370  vector<string> cutVec ;
1371  if (cutRange && strlen(cutRange)>0) {
1372  if (strchr(cutRange,',')==0) {
1373  cutVec.push_back(cutRange) ;
1374  } else {
1375  const size_t bufSize = strlen(cutRange)+1;
1376  char* buf = new char[bufSize] ;
1377  strlcpy(buf,cutRange,bufSize) ;
1378  const char* oneRange = strtok(buf,",") ;
1379  while(oneRange) {
1380  cutVec.push_back(oneRange) ;
1381  oneRange = strtok(0,",") ;
1382  }
1383  delete[] buf ;
1384  }
1385  }
1386 
1387  // Loop over events and fill the histogram
1388  if (hist->GetSumw2()->fN==0) {
1389  hist->Sumw2() ;
1390  }
1391  Int_t nevent= numEntries() ; //(Int_t)_tree->GetEntries();
1392  for(Int_t i=0; i < nevent; ++i) {
1393 
1394  //Int_t entryNumber= _tree->GetEntryNumber(i);
1395  //if (entryNumber<0) break;
1396  get(i);
1397 
1398  // Apply expression based selection criteria
1399  if (select && select->eval()==0) {
1400  continue ;
1401  }
1402 
1403 
1404  // Apply range based selection criteria
1405  Bool_t selectByRange = kTRUE ;
1406  if (cutRange) {
1407  for (const auto arg : _vars) {
1408  Bool_t selectThisArg = kFALSE ;
1409  UInt_t icut ;
1410  for (icut=0 ; icut<cutVec.size() ; icut++) {
1411  if (arg->inRange(cutVec[icut].c_str())) {
1412  selectThisArg = kTRUE ;
1413  break ;
1414  }
1415  }
1416  if (!selectThisArg) {
1417  selectByRange = kFALSE ;
1418  break ;
1419  }
1420  }
1421  }
1422 
1423  if (!selectByRange) {
1424  // Go to next event in loop over events
1425  continue ;
1426  }
1427 
1428  Int_t bin(0);
1429  switch(hdim) {
1430  case 1:
1431  bin= hist->FindBin(xvar->getVal());
1432  hist->Fill(xvar->getVal(),weight()) ;
1433  break;
1434  case 2:
1435  bin= hist->FindBin(xvar->getVal(),yvar->getVal());
1436  static_cast<TH2*>(hist)->Fill(xvar->getVal(),yvar->getVal(),weight()) ;
1437  break;
1438  case 3:
1439  bin= hist->FindBin(xvar->getVal(),yvar->getVal(),zvar->getVal());
1440  static_cast<TH3*>(hist)->Fill(xvar->getVal(),yvar->getVal(),zvar->getVal(),weight()) ;
1441  break;
1442  default:
1443  assert(hdim < 3);
1444  break;
1445  }
1446 
1447 
1448  Double_t error2 = TMath::Power(hist->GetBinError(bin),2)-TMath::Power(weight(),2) ;
1449  Double_t we = weightError(RooAbsData::SumW2) ;
1450  if (we==0) we = weight() ;
1451  error2 += TMath::Power(we,2) ;
1452 
1453 
1454 // Double_t we = weightError(RooAbsData::SumW2) ;
1455 // Double_t error2(0) ;
1456 // if (we==0) {
1457 // we = weight() ; //sqrt(weight()) ;
1458 // error2 = TMath::Power(hist->GetBinError(bin),2)-TMath::Power(weight(),2) + TMath::Power(we,2) ;
1459 // } else {
1460 // error2 = TMath::Power(hist->GetBinError(bin),2)-TMath::Power(weight(),2) + TMath::Power(we,2) ;
1461 // }
1462  //hist->AddBinContent(bin,weight());
1463  hist->SetBinError(bin,sqrt(error2)) ;
1464 
1465  //cout << "RooTreeData::fillHistogram() bin = " << bin << " weight() = " << weight() << " we = " << we << endl ;
1466 
1467  }
1468 
1469  return hist;
1470 }
1471 
1472 ////////////////////////////////////////////////////////////////////////////////
1473 /// Split dataset into subsets based on states of given splitCat in this dataset.
1474 /// A TList of RooDataSets is returned in which each RooDataSet is named
1475 /// after the state name of splitCat of which it contains the dataset subset.
1476 /// The observables splitCat itself is no longer present in the sub datasets.
1477 /// If createEmptyDataSets is kFALSE (default) this method only creates datasets for states
1478 /// which have at least one entry The caller takes ownership of the returned list and its contents
1479 
1480 TList* RooAbsData::split(const RooAbsCategory& splitCat, Bool_t createEmptyDataSets) const
1481 {
1482  // Sanity check
1483  if (!splitCat.dependsOn(*get())) {
1484  coutE(InputArguments) << "RooTreeData::split(" << GetName() << ") ERROR category " << splitCat.GetName()
1485  << " doesn't depend on any variable in this dataset" << endl ;
1486  return 0 ;
1487  }
1488 
1489  // Clone splitting category and attach to self
1490  RooAbsCategory* cloneCat =0;
1491  RooArgSet* cloneSet = 0;
1492  if (splitCat.isDerived()) {
1493  cloneSet = (RooArgSet*) RooArgSet(splitCat).snapshot(kTRUE) ;
1494  if (!cloneSet) {
1495  coutE(InputArguments) << "RooTreeData::split(" << GetName() << ") Couldn't deep-clone splitting category, abort." << endl ;
1496  return 0 ;
1497  }
1498  cloneCat = (RooAbsCategory*) cloneSet->find(splitCat.GetName()) ;
1499  cloneCat->attachDataSet(*this) ;
1500  } else {
1501  cloneCat = dynamic_cast<RooAbsCategory*>(get()->find(splitCat.GetName())) ;
1502  if (!cloneCat) {
1503  coutE(InputArguments) << "RooTreeData::split(" << GetName() << ") ERROR category " << splitCat.GetName()
1504  << " is fundamental and does not appear in this dataset" << endl ;
1505  return 0 ;
1506  }
1507  }
1508 
1509  // Split a dataset in a series of subsets, each corresponding
1510  // to a state of splitCat
1511  TList* dsetList = new TList ;
1512 
1513  // Construct set of variables to be included in split sets = full set - split category
1514  RooArgSet subsetVars(*get()) ;
1515  if (splitCat.isDerived()) {
1516  RooArgSet* vars = splitCat.getVariables() ;
1517  subsetVars.remove(*vars,kTRUE,kTRUE) ;
1518  delete vars ;
1519  } else {
1520  subsetVars.remove(splitCat,kTRUE,kTRUE) ;
1521  }
1522 
1523  // Add weight variable explicitly if dataset has weights, but no top-level weight
1524  // variable exists (can happen with composite datastores)
1525  Bool_t addWV(kFALSE) ;
1526  RooRealVar newweight("weight","weight",-1e9,1e9) ;
1527  if (isWeighted() && !IsA()->InheritsFrom(RooDataHist::Class())) {
1528  subsetVars.add(newweight) ;
1529  addWV = kTRUE ;
1530  }
1531 
1532  // If createEmptyDataSets is true, prepopulate with empty sets corresponding to all states
1533  if (createEmptyDataSets) {
1534  TIterator* stateIter = cloneCat->typeIterator() ;
1535  RooCatType* state ;
1536  while ((state=(RooCatType*)stateIter->Next())) {
1537  RooAbsData* subset = emptyClone(state->GetName(),state->GetName(),&subsetVars,(addWV?"weight":0)) ;
1538  dsetList->Add((RooAbsArg*)subset) ;
1539  }
1540  delete stateIter ;
1541  }
1542 
1543 
1544  // Loop over dataset and copy event to matching subset
1545  const bool propWeightSquared = isWeighted();
1546  for (Int_t i = 0; i < numEntries(); ++i) {
1547  const RooArgSet* row = get(i);
1548  RooAbsData* subset = (RooAbsData*) dsetList->FindObject(cloneCat->getLabel());
1549  if (!subset) {
1550  subset = emptyClone(cloneCat->getLabel(),cloneCat->getLabel(),&subsetVars,(addWV?"weight":0));
1551  dsetList->Add((RooAbsArg*)subset);
1552  }
1553  if (!propWeightSquared) {
1554  subset->add(*row, weight());
1555  } else {
1556  subset->add(*row, weight(), weightSquared());
1557  }
1558  }
1559 
1560  delete cloneSet;
1561  return dsetList;
1562 }
1563 
1564 ////////////////////////////////////////////////////////////////////////////////
1565 /// Plot dataset on specified frame. By default an unbinned dataset will use the default binning of
1566 /// the target frame. A binned dataset will by default retain its intrinsic binning.
1567 ///
1568 /// The following optional named arguments can be used to modify the default behavior
1569 ///
1570 /// <table>
1571 /// <tr><th> <th> Data representation options
1572 /// <tr><td> `Asymmetry(const RooCategory& c)` <td> Show the asymmetry of the data in given two-state category [F(+)-F(-)] / [F(+)+F(-)].
1573 /// Category must have two states with indices -1 and +1 or three states with indices -1,0 and +1.
1574 /// <tr><td> `Efficiency(const RooCategory& c)` <td> Show the efficiency F(acc)/[F(acc)+F(rej)]. Category must have two states with indices 0 and 1
1575 /// <tr><td> `DataError(RooAbsData::EType)` <td> Select the type of error drawn:
1576 /// - `Auto(default)` results in Poisson for unweighted data and SumW2 for weighted data
1577 /// - `Poisson` draws asymmetric Poisson confidence intervals.
1578 /// - `SumW2` draws symmetric sum-of-weights error ( sum(w)^2/sum(w^2) )
1579 /// - `None` draws no error bars
1580 /// <tr><td> `Binning(int nbins, double xlo, double xhi)` <td> Use specified binning to draw dataset
1581 /// <tr><td> `Binning(const RooAbsBinning&)` <td> Use specified binning to draw dataset
1582 /// <tr><td> `Binning(const char* name)` <td> Use binning with specified name to draw dataset
1583 /// <tr><td> `RefreshNorm(Bool_t flag)` <td> Force refreshing for PDF normalization information in frame.
1584 /// If set, any subsequent PDF will normalize to this dataset, even if it is
1585 /// not the first one added to the frame. By default only the 1st dataset
1586 /// added to a frame will update the normalization information
1587 /// <tr><td> `Rescale(Double_t f)` <td> Rescale drawn histogram by given factor
1588 /// <tr><td> `CutRange(const char*)` <td> Apply cuts to dataset.
1589 /// \note This often requires passing the normalisation when plotting the PDF because RooFit does not save
1590 /// how many events were being plotted (it will only work for cutting slices out of uniformly distributed variables).
1591 /// ```
1592 /// data->plotOn(frame01, CutRange("SB1"));
1593 /// const double nData = data->sumEntries("", "SB1");
1594 /// // Make clear that the target normalisation is nData. The enumerator NumEvent
1595 /// // is needed to switch between relative and absolute scaling.
1596 /// model.plotOn(frame01, Normalization(nData, RooAbsReal::NumEvent),
1597 /// ProjectionRange("SB1"));
1598 /// ```
1599 ///
1600 /// <tr><th> <th> Histogram drawing options
1601 /// <tr><td> `DrawOption(const char* opt)` <td> Select ROOT draw option for resulting TGraph object
1602 /// <tr><td> `LineStyle(Int_t style)` <td> Select line style by ROOT line style code, default is solid
1603 /// <tr><td> `LineColor(Int_t color)` <td> Select line color by ROOT color code, default is black
1604 /// <tr><td> `LineWidth(Int_t width)` <td> Select line with in pixels, default is 3
1605 /// <tr><td> `MarkerStyle(Int_t style)` <td> Select the ROOT marker style, default is 21
1606 /// <tr><td> `MarkerColor(Int_t color)` <td> Select the ROOT marker color, default is black
1607 /// <tr><td> `MarkerSize(Double_t size)` <td> Select the ROOT marker size
1608 /// <tr><td> `FillStyle(Int_t style)` <td> Select fill style, default is filled.
1609 /// <tr><td> `FillColor(Int_t color)` <td> Select fill color by ROOT color code
1610 /// <tr><td> `XErrorSize(Double_t frac)` <td> Select size of X error bar as fraction of the bin width, default is 1
1611 ///
1612 ///
1613 /// <tr><th> <th> Misc. other options
1614 /// <tr><td> `Name(const chat* name)` <td> Give curve specified name in frame. Useful if curve is to be referenced later
1615 /// <tr><td> `Invisible()` <td> Add curve to frame, but do not display. Useful in combination AddTo()
1616 /// <tr><td> `AddTo(const char* name, double_t wgtSelf, double_t wgtOther)` <td> Add constructed histogram to already existing histogram with given name and relative weight factors
1617 /// </table>
1618 
1619 RooPlot* RooAbsData::plotOn(RooPlot* frame, const RooLinkedList& argList) const
1620 {
1621  // New experimental plotOn() with varargs...
1622 
1623  // Define configuration for this method
1624  RooCmdConfig pc(Form("RooTreeData::plotOn(%s)",GetName())) ;
1625  pc.defineString("drawOption","DrawOption",0,"P") ;
1626  pc.defineString("cutRange","CutRange",0,"",kTRUE) ;
1627  pc.defineString("cutString","CutSpec",0,"") ;
1628  pc.defineString("histName","Name",0,"") ;
1629  pc.defineObject("cutVar","CutVar",0) ;
1630  pc.defineObject("binning","Binning",0) ;
1631  pc.defineString("binningName","BinningName",0,"") ;
1632  pc.defineInt("nbins","BinningSpec",0,100) ;
1633  pc.defineDouble("xlo","BinningSpec",0,0) ;
1634  pc.defineDouble("xhi","BinningSpec",1,1) ;
1635  pc.defineObject("asymCat","Asymmetry",0) ;
1636  pc.defineObject("effCat","Efficiency",0) ;
1637  pc.defineInt("lineColor","LineColor",0,-999) ;
1638  pc.defineInt("lineStyle","LineStyle",0,-999) ;
1639  pc.defineInt("lineWidth","LineWidth",0,-999) ;
1640  pc.defineInt("markerColor","MarkerColor",0,-999) ;
1641  pc.defineInt("markerStyle","MarkerStyle",0,-999) ;
1642  pc.defineDouble("markerSize","MarkerSize",0,-999) ;
1643  pc.defineInt("fillColor","FillColor",0,-999) ;
1644  pc.defineInt("fillStyle","FillStyle",0,-999) ;
1645  pc.defineInt("errorType","DataError",0,(Int_t)RooAbsData::Auto) ;
1646  pc.defineInt("histInvisible","Invisible",0,0) ;
1647  pc.defineInt("refreshFrameNorm","RefreshNorm",0,1) ;
1648  pc.defineString("addToHistName","AddTo",0,"") ;
1649  pc.defineDouble("addToWgtSelf","AddTo",0,1.) ;
1650  pc.defineDouble("addToWgtOther","AddTo",1,1.) ;
1651  pc.defineDouble("xErrorSize","XErrorSize",0,1.) ;
1652  pc.defineDouble("scaleFactor","Rescale",0,1.) ;
1653  pc.defineMutex("DataError","Asymmetry","Efficiency") ;
1654  pc.defineMutex("Binning","BinningName","BinningSpec") ;
1655 
1656  // Process & check varargs
1657  pc.process(argList) ;
1658  if (!pc.ok(kTRUE)) {
1659  return frame ;
1660  }
1661 
1662  PlotOpt o ;
1663 
1664  // Extract values from named arguments
1665  o.drawOptions = pc.getString("drawOption") ;
1666  o.cuts = pc.getString("cutString") ;
1667  if (pc.hasProcessed("Binning")) {
1668  o.bins = (RooAbsBinning*) pc.getObject("binning") ;
1669  } else if (pc.hasProcessed("BinningName")) {
1670  o.bins = &frame->getPlotVar()->getBinning(pc.getString("binningName")) ;
1671  } else if (pc.hasProcessed("BinningSpec")) {
1672  Double_t xlo = pc.getDouble("xlo") ;
1673  Double_t xhi = pc.getDouble("xhi") ;
1674  o.bins = new RooUniformBinning((xlo==xhi)?frame->getPlotVar()->getMin():xlo,
1675  (xlo==xhi)?frame->getPlotVar()->getMax():xhi,pc.getInt("nbins")) ;
1676  }
1677  const RooAbsCategoryLValue* asymCat = (const RooAbsCategoryLValue*) pc.getObject("asymCat") ;
1678  const RooAbsCategoryLValue* effCat = (const RooAbsCategoryLValue*) pc.getObject("effCat") ;
1679  o.etype = (RooAbsData::ErrorType) pc.getInt("errorType") ;
1680  o.histInvisible = pc.getInt("histInvisible") ;
1681  o.xErrorSize = pc.getDouble("xErrorSize") ;
1682  o.cutRange = pc.getString("cutRange",0,kTRUE) ;
1683  o.histName = pc.getString("histName",0,kTRUE) ;
1684  o.addToHistName = pc.getString("addToHistName",0,kTRUE) ;
1685  o.addToWgtSelf = pc.getDouble("addToWgtSelf") ;
1686  o.addToWgtOther = pc.getDouble("addToWgtOther") ;
1687  o.refreshFrameNorm = pc.getInt("refreshFrameNorm") ;
1688  o.scaleFactor = pc.getDouble("scaleFactor") ;
1689 
1690  // Map auto error type to actual type
1691  if (o.etype == Auto) {
1692  o.etype = isNonPoissonWeighted() ? SumW2 : Poisson ;
1693  if (o.etype == SumW2) {
1694  coutI(InputArguments) << "RooAbsData::plotOn(" << GetName()
1695  << ") INFO: dataset has non-integer weights, auto-selecting SumW2 errors instead of Poisson errors" << endl ;
1696  }
1697  }
1698 
1699  if (o.addToHistName && !frame->findObject(o.addToHistName,RooHist::Class())) {
1700  coutE(InputArguments) << "RooAbsData::plotOn(" << GetName() << ") cannot find existing histogram " << o.addToHistName
1701  << " to add to in RooPlot" << endl ;
1702  return frame ;
1703  }
1704 
1705  RooPlot* ret ;
1706  if (!asymCat && !effCat) {
1707  ret = plotOn(frame,o) ;
1708  } else if (asymCat) {
1709  ret = plotAsymOn(frame,*asymCat,o) ;
1710  } else {
1711  ret = plotEffOn(frame,*effCat,o) ;
1712  }
1713 
1714  Int_t lineColor = pc.getInt("lineColor") ;
1715  Int_t lineStyle = pc.getInt("lineStyle") ;
1716  Int_t lineWidth = pc.getInt("lineWidth") ;
1717  Int_t markerColor = pc.getInt("markerColor") ;
1718  Int_t markerStyle = pc.getInt("markerStyle") ;
1719  Size_t markerSize = pc.getDouble("markerSize") ;
1720  Int_t fillColor = pc.getInt("fillColor") ;
1721  Int_t fillStyle = pc.getInt("fillStyle") ;
1722  if (lineColor!=-999) ret->getAttLine()->SetLineColor(lineColor) ;
1723  if (lineStyle!=-999) ret->getAttLine()->SetLineStyle(lineStyle) ;
1724  if (lineWidth!=-999) ret->getAttLine()->SetLineWidth(lineWidth) ;
1725  if (markerColor!=-999) ret->getAttMarker()->SetMarkerColor(markerColor) ;
1726  if (markerStyle!=-999) ret->getAttMarker()->SetMarkerStyle(markerStyle) ;
1727  if (markerSize!=-999) ret->getAttMarker()->SetMarkerSize(markerSize) ;
1728  if (fillColor!=-999) ret->getAttFill()->SetFillColor(fillColor) ;
1729  if (fillStyle!=-999) ret->getAttFill()->SetFillStyle(fillStyle) ;
1730 
1731  if (pc.hasProcessed("BinningSpec")) {
1732  delete o.bins ;
1733  }
1734 
1735  return ret ;
1736 }
1737 
1738 ////////////////////////////////////////////////////////////////////////////////
1739 /// Create and fill a histogram of the frame's variable and append it to the frame.
1740 /// The frame variable must be one of the data sets dimensions.
1741 ///
1742 /// The plot range and the number of plot bins is determined by the parameters
1743 /// of the plot variable of the frame (RooAbsReal::setPlotRange(), RooAbsReal::setPlotBins())
1744 ///
1745 /// The optional cut string expression can be used to select the events to be plotted.
1746 /// The cut specification may refer to any variable contained in the data set
1747 ///
1748 /// The drawOptions are passed to the TH1::Draw() method
1749 
1750 RooPlot *RooAbsData::plotOn(RooPlot *frame, PlotOpt o) const
1751 {
1752  if(0 == frame) {
1753  coutE(Plotting) << ClassName() << "::" << GetName() << ":plotOn: frame is null" << endl;
1754  return 0;
1755  }
1756  RooAbsRealLValue *var= (RooAbsRealLValue*) frame->getPlotVar();
1757  if(0 == var) {
1758  coutE(Plotting) << ClassName() << "::" << GetName()
1759  << ":plotOn: frame does not specify a plot variable" << endl;
1760  return 0;
1761  }
1762 
1763  // create and fill a temporary histogram of this variable
1764  TString histName(GetName());
1765  histName.Append("_plot");
1766  TH1F *hist ;
1767  if (o.bins) {
1768  hist= static_cast<TH1F*>(var->createHistogram(histName.Data(), RooFit::AxisLabel("Events"), RooFit::Binning(*o.bins))) ;
1769  } else {
1770  hist= var->createHistogram(histName.Data(), "Events",
1771  frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(), frame->GetNbinsX());
1772  }
1773 
1774  // Keep track of sum-of-weights error
1775  hist->Sumw2() ;
1776 
1777  if(0 == fillHistogram(hist,RooArgList(*var),o.cuts,o.cutRange)) {
1778  coutE(Plotting) << ClassName() << "::" << GetName()
1779  << ":plotOn: fillHistogram() failed" << endl;
1780  return 0;
1781  }
1782 
1783  // If frame has no predefined bin width (event density) it will be adjusted to
1784  // our histograms bin width so we should force that bin width here
1785  Double_t nomBinWidth ;
1786  if (frame->getFitRangeNEvt()==0 && o.bins) {
1787  nomBinWidth = o.bins->averageBinWidth() ;
1788  } else {
1789  nomBinWidth = o.bins ? frame->getFitRangeBinW() : 0 ;
1790  }
1791 
1792  // convert this histogram to a RooHist object on the heap
1793  RooHist *graph= new RooHist(*hist,nomBinWidth,1,o.etype,o.xErrorSize,o.correctForBinWidth,o.scaleFactor);
1794  if(0 == graph) {
1795  coutE(Plotting) << ClassName() << "::" << GetName()
1796  << ":plotOn: unable to create a RooHist object" << endl;
1797  delete hist;
1798  return 0;
1799  }
1800 
1801  // If the dataset variable has a wide range than the plot variable,
1802  // calculate the number of entries in the dataset in the plot variable fit range
1803  RooAbsRealLValue* dataVar = (RooAbsRealLValue*) _vars.find(var->GetName()) ;
1804  Double_t nEnt(sumEntries()) ;
1805  if (dataVar->getMin()<var->getMin() || dataVar->getMax()>var->getMax()) {
1806  RooAbsData* tmp = ((RooAbsData*)this)->reduce(*var) ;
1807  nEnt = tmp->sumEntries() ;
1808  delete tmp ;
1809  }
1810 
1811  // Store the number of entries before the cut, if any was made
1812  if ((o.cuts && strlen(o.cuts)) || o.cutRange) {
1813  coutI(Plotting) << "RooTreeData::plotOn: plotting " << hist->GetSum() << " events out of " << nEnt << " total events" << endl ;
1814  graph->setRawEntries(nEnt) ;
1815  }
1816 
1817  // Add self to other hist if requested
1818  if (o.addToHistName) {
1819  RooHist* otherGraph = static_cast<RooHist*>(frame->findObject(o.addToHistName,RooHist::Class())) ;
1820 
1821  if (!graph->hasIdenticalBinning(*otherGraph)) {
1822  coutE(Plotting) << "RooTreeData::plotOn: ERROR Histogram to be added to, '" << o.addToHistName << "',has different binning" << endl ;
1823  delete graph ;
1824  return frame ;
1825  }
1826 
1827  RooHist* sumGraph = new RooHist(*graph,*otherGraph,o.addToWgtSelf,o.addToWgtOther,o.etype) ;
1828  delete graph ;
1829  graph = sumGraph ;
1830  }
1831 
1832  // Rename graph if requested
1833  if (o.histName) {
1834  graph->SetName(o.histName) ;
1835  } else {
1836  TString hname(Form("h_%s",GetName())) ;
1837  if (o.cutRange && strlen(o.cutRange)>0) {
1838  hname.Append(Form("_CutRange[%s]",o.cutRange)) ;
1839  }
1840  if (o.cuts && strlen(o.cuts)>0) {
1841  hname.Append(Form("_Cut[%s]",o.cuts)) ;
1842  }
1843  graph->SetName(hname.Data()) ;
1844  }
1845 
1846  // initialize the frame's normalization setup, if necessary
1847  frame->updateNormVars(_vars);
1848 
1849 
1850  // add the RooHist to the specified plot
1851  frame->addPlotable(graph,o.drawOptions,o.histInvisible,o.refreshFrameNorm);
1852 
1853 
1854 
1855  // cleanup
1856  delete hist;
1857 
1858  return frame;
1859 }
1860 
1861 ////////////////////////////////////////////////////////////////////////////////
1862 /// Create and fill a histogram with the asymmetry N[+] - N[-] / ( N[+] + N[-] ),
1863 /// where N(+/-) is the number of data points with asymCat=+1 and asymCat=-1
1864 /// as function of the frames variable. The asymmetry category 'asymCat' must
1865 /// have exactly 2 (or 3) states defined with index values +1,-1 (and 0)
1866 ///
1867 /// The plot range and the number of plot bins is determined by the parameters
1868 /// of the plot variable of the frame (RooAbsReal::setPlotRange(), RooAbsReal::setPlotBins())
1869 ///
1870 /// The optional cut string expression can be used to select the events to be plotted.
1871 /// The cut specification may refer to any variable contained in the data set
1872 ///
1873 /// The drawOptions are passed to the TH1::Draw() method
1874 
1875 RooPlot* RooAbsData::plotAsymOn(RooPlot* frame, const RooAbsCategoryLValue& asymCat, PlotOpt o) const
1876 {
1877  if(0 == frame) {
1878  coutE(Plotting) << ClassName() << "::" << GetName() << ":plotAsymOn: frame is null" << endl;
1879  return 0;
1880  }
1881  RooAbsRealLValue *var= (RooAbsRealLValue*) frame->getPlotVar();
1882  if(0 == var) {
1883  coutE(Plotting) << ClassName() << "::" << GetName()
1884  << ":plotAsymOn: frame does not specify a plot variable" << endl;
1885  return 0;
1886  }
1887 
1888  // create and fill temporary histograms of this variable for each state
1889  TString hist1Name(GetName()),hist2Name(GetName());
1890  hist1Name.Append("_plot1");
1891  TH1F *hist1, *hist2 ;
1892  hist2Name.Append("_plot2");
1893 
1894  if (o.bins) {
1895  hist1= var->createHistogram(hist1Name.Data(), "Events", *o.bins) ;
1896  hist2= var->createHistogram(hist2Name.Data(), "Events", *o.bins) ;
1897  } else {
1898  hist1= var->createHistogram(hist1Name.Data(), "Events",
1899  frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(),
1900  frame->GetNbinsX());
1901  hist2= var->createHistogram(hist2Name.Data(), "Events",
1902  frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(),
1903  frame->GetNbinsX());
1904  }
1905 
1906  assert(0 != hist1 && 0 != hist2);
1907 
1908  TString cuts1,cuts2 ;
1909  if (o.cuts && strlen(o.cuts)) {
1910  cuts1 = Form("(%s)&&(%s>0)",o.cuts,asymCat.GetName());
1911  cuts2 = Form("(%s)&&(%s<0)",o.cuts,asymCat.GetName());
1912  } else {
1913  cuts1 = Form("(%s>0)",asymCat.GetName());
1914  cuts2 = Form("(%s<0)",asymCat.GetName());
1915  }
1916 
1917  if(0 == fillHistogram(hist1,RooArgList(*var),cuts1.Data(),o.cutRange) ||
1918  0 == fillHistogram(hist2,RooArgList(*var),cuts2.Data(),o.cutRange)) {
1919  coutE(Plotting) << ClassName() << "::" << GetName()
1920  << ":plotAsymOn: createHistogram() failed" << endl;
1921  return 0;
1922  }
1923 
1924  // convert this histogram to a RooHist object on the heap
1925  RooHist *graph= new RooHist(*hist1,*hist2,0,1,o.etype,o.xErrorSize,kFALSE,o.scaleFactor);
1926  graph->setYAxisLabel(Form("Asymmetry in %s",asymCat.GetName())) ;
1927 
1928  // initialize the frame's normalization setup, if necessary
1929  frame->updateNormVars(_vars);
1930 
1931  // Rename graph if requested
1932  if (o.histName) {
1933  graph->SetName(o.histName) ;
1934  } else {
1935  TString hname(Form("h_%s_Asym[%s]",GetName(),asymCat.GetName())) ;
1936  if (o.cutRange && strlen(o.cutRange)>0) {
1937  hname.Append(Form("_CutRange[%s]",o.cutRange)) ;
1938  }
1939  if (o.cuts && strlen(o.cuts)>0) {
1940  hname.Append(Form("_Cut[%s]",o.cuts)) ;
1941  }
1942  graph->SetName(hname.Data()) ;
1943  }
1944 
1945  // add the RooHist to the specified plot
1946  frame->addPlotable(graph,o.drawOptions,o.histInvisible,o.refreshFrameNorm);
1947 
1948  // cleanup
1949  delete hist1;
1950  delete hist2;
1951 
1952  return frame;
1953 }
1954 
1955 ////////////////////////////////////////////////////////////////////////////////
1956 /// Create and fill a histogram with the efficiency N[1] / ( N[1] + N[0] ),
1957 /// where N(1/0) is the number of data points with effCat=1 and effCat=0
1958 /// as function of the frames variable. The efficiency category 'effCat' must
1959 /// have exactly 2 +1 and 0.
1960 ///
1961 /// The plot range and the number of plot bins is determined by the parameters
1962 /// of the plot variable of the frame (RooAbsReal::setPlotRange(), RooAbsReal::setPlotBins())
1963 ///
1964 /// The optional cut string expression can be used to select the events to be plotted.
1965 /// The cut specification may refer to any variable contained in the data set
1966 ///
1967 /// The drawOptions are passed to the TH1::Draw() method
1968 
1969 RooPlot* RooAbsData::plotEffOn(RooPlot* frame, const RooAbsCategoryLValue& effCat, PlotOpt o) const
1970 {
1971  if(0 == frame) {
1972  coutE(Plotting) << ClassName() << "::" << GetName() << ":plotEffOn: frame is null" << endl;
1973  return 0;
1974  }
1975  RooAbsRealLValue *var= (RooAbsRealLValue*) frame->getPlotVar();
1976  if(0 == var) {
1977  coutE(Plotting) << ClassName() << "::" << GetName()
1978  << ":plotEffOn: frame does not specify a plot variable" << endl;
1979  return 0;
1980  }
1981 
1982  // create and fill temporary histograms of this variable for each state
1983  TString hist1Name(GetName()),hist2Name(GetName());
1984  hist1Name.Append("_plot1");
1985  TH1F *hist1, *hist2 ;
1986  hist2Name.Append("_plot2");
1987 
1988  if (o.bins) {
1989  hist1= var->createHistogram(hist1Name.Data(), "Events", *o.bins) ;
1990  hist2= var->createHistogram(hist2Name.Data(), "Events", *o.bins) ;
1991  } else {
1992  hist1= var->createHistogram(hist1Name.Data(), "Events",
1993  frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(),
1994  frame->GetNbinsX());
1995  hist2= var->createHistogram(hist2Name.Data(), "Events",
1996  frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(),
1997  frame->GetNbinsX());
1998  }
1999 
2000  assert(0 != hist1 && 0 != hist2);
2001 
2002  TString cuts1,cuts2 ;
2003  if (o.cuts && strlen(o.cuts)) {
2004  cuts1 = Form("(%s)&&(%s==1)",o.cuts,effCat.GetName());
2005  cuts2 = Form("(%s)&&(%s==0)",o.cuts,effCat.GetName());
2006  } else {
2007  cuts1 = Form("(%s==1)",effCat.GetName());
2008  cuts2 = Form("(%s==0)",effCat.GetName());
2009  }
2010 
2011  if(0 == fillHistogram(hist1,RooArgList(*var),cuts1.Data(),o.cutRange) ||
2012  0 == fillHistogram(hist2,RooArgList(*var),cuts2.Data(),o.cutRange)) {
2013  coutE(Plotting) << ClassName() << "::" << GetName()
2014  << ":plotEffOn: createHistogram() failed" << endl;
2015  return 0;
2016  }
2017 
2018  // convert this histogram to a RooHist object on the heap
2019  RooHist *graph= new RooHist(*hist1,*hist2,0,1,o.etype,o.xErrorSize,kTRUE);
2020  graph->setYAxisLabel(Form("Efficiency of %s=%s",effCat.GetName(),effCat.lookupType(1)->GetName())) ;
2021 
2022  // initialize the frame's normalization setup, if necessary
2023  frame->updateNormVars(_vars);
2024 
2025  // Rename graph if requested
2026  if (o.histName) {
2027  graph->SetName(o.histName) ;
2028  } else {
2029  TString hname(Form("h_%s_Eff[%s]",GetName(),effCat.GetName())) ;
2030  if (o.cutRange && strlen(o.cutRange)>0) {
2031  hname.Append(Form("_CutRange[%s]",o.cutRange)) ;
2032  }
2033  if (o.cuts && strlen(o.cuts)>0) {
2034  hname.Append(Form("_Cut[%s]",o.cuts)) ;
2035  }
2036  graph->SetName(hname.Data()) ;
2037  }
2038 
2039  // add the RooHist to the specified plot
2040  frame->addPlotable(graph,o.drawOptions,o.histInvisible,o.refreshFrameNorm);
2041 
2042  // cleanup
2043  delete hist1;
2044  delete hist2;
2045 
2046  return frame;
2047 }
2048 
2049 ////////////////////////////////////////////////////////////////////////////////
2050 /// Create and fill a 1-dimensional table for given category column
2051 /// This functions is the equivalent of plotOn() for category dimensions.
2052 ///
2053 /// The optional cut string expression can be used to select the events to be tabulated
2054 /// The cut specification may refer to any variable contained in the data set
2055 ///
2056 /// The option string is currently not used
2057 
2058 Roo1DTable* RooAbsData::table(const RooAbsCategory& cat, const char* cuts, const char* /*opts*/) const
2059 {
2060  // First see if var is in data set
2061  RooAbsCategory* tableVar = (RooAbsCategory*) _vars.find(cat.GetName()) ;
2062  RooArgSet *tableSet = 0;
2063  Bool_t ownPlotVar(kFALSE) ;
2064  if (!tableVar) {
2065  if (!cat.dependsOn(_vars)) {
2066  coutE(Plotting) << "RooTreeData::Table(" << GetName() << "): Argument " << cat.GetName()
2067  << " is not in dataset and is also not dependent on data set" << endl ;
2068  return 0 ;
2069  }
2070 
2071  // Clone derived variable
2072  tableSet = (RooArgSet*) RooArgSet(cat).snapshot(kTRUE) ;
2073  if (!tableSet) {
2074  coutE(Plotting) << "RooTreeData::table(" << GetName() << ") Couldn't deep-clone table category, abort." << endl ;
2075  return 0 ;
2076  }
2077  tableVar = (RooAbsCategory*) tableSet->find(cat.GetName()) ;
2078  ownPlotVar = kTRUE ;
2079 
2080  //Redirect servers of derived clone to internal ArgSet representing the data in this set
2081  tableVar->recursiveRedirectServers(_vars) ;
2082  }
2083 
2084  TString tableName(GetName()) ;
2085  if (cuts && strlen(cuts)) {
2086  tableName.Append("(") ;
2087  tableName.Append(cuts) ;
2088  tableName.Append(")") ;
2089  }
2090  Roo1DTable* table2 = tableVar->createTable(tableName) ;
2091 
2092  // Make cut selector if cut is specified
2093  RooFormulaVar* cutVar = 0;
2094  if (cuts && strlen(cuts)) {
2095  cutVar = new RooFormulaVar("cutVar",cuts,_vars) ;
2096  }
2097 
2098  // Dump contents
2099  Int_t nevent= numEntries() ;
2100  for(Int_t i=0; i < nevent; ++i) {
2101  get(i);
2102 
2103  if (cutVar && cutVar->getVal()==0) continue ;
2104 
2105  table2->fill(*tableVar,weight()) ;
2106  }
2107 
2108  if (ownPlotVar) delete tableSet ;
2109  if (cutVar) delete cutVar ;
2110 
2111  return table2 ;
2112 }
2113 
2114 ////////////////////////////////////////////////////////////////////////////////
2115 /// Fill Doubles 'lowest' and 'highest' with the lowest and highest value of
2116 /// observable 'var' in this dataset. If the return value is kTRUE and error
2117 /// occurred
2118 
2119 Bool_t RooAbsData::getRange(RooRealVar& var, Double_t& lowest, Double_t& highest, Double_t marginFrac, Bool_t symMode) const
2120 {
2121  // Lookup variable in dataset
2122  RooRealVar *varPtr= (RooRealVar*) _vars.find(var.GetName());
2123  if(0 == varPtr) {
2124  coutE(InputArguments) << "RooDataSet::getRange(" << GetName() << ") ERROR: unknown variable: " << var.GetName() << endl ;
2125  return kTRUE;
2126  }
2127 
2128  // Check if found variable is of type RooRealVar
2129  if (!dynamic_cast<RooRealVar*>(varPtr)) {
2130  coutE(InputArguments) << "RooDataSet::getRange(" << GetName() << ") ERROR: variable " << var.GetName() << " is not of type RooRealVar" << endl ;
2131  return kTRUE;
2132  }
2133 
2134  // Check if dataset is not empty
2135  if(sumEntries() == 0.) {
2136  coutE(InputArguments) << "RooDataSet::getRange(" << GetName() << ") WARNING: empty dataset" << endl ;
2137  return kTRUE;
2138  }
2139 
2140  // Look for highest and lowest value
2141  lowest = RooNumber::infinity() ;
2142  highest = -RooNumber::infinity() ;
2143  for (Int_t i=0 ; i<numEntries() ; i++) {
2144  get(i) ;
2145  if (varPtr->getVal()<lowest) {
2146  lowest = varPtr->getVal() ;
2147  }
2148  if (varPtr->getVal()>highest) {
2149  highest = varPtr->getVal() ;
2150  }
2151  }
2152 
2153  if (marginFrac>0) {
2154  if (symMode==kFALSE) {
2155 
2156  Double_t margin = marginFrac*(highest-lowest) ;
2157  lowest -= margin ;
2158  highest += margin ;
2159  if (lowest<var.getMin()) lowest = var.getMin() ;
2160  if (highest>var.getMax()) highest = var.getMax() ;
2161 
2162  } else {
2163 
2164  Double_t mom1 = moment(var,1) ;
2165  Double_t delta = ((highest-mom1)>(mom1-lowest)?(highest-mom1):(mom1-lowest))*(1+marginFrac) ;
2166  lowest = mom1-delta ;
2167  highest = mom1+delta ;
2168  if (lowest<var.getMin()) lowest = var.getMin() ;
2169  if (highest>var.getMax()) highest = var.getMax() ;
2170 
2171  }
2172  }
2173 
2174  return kFALSE ;
2175 }
2176 
2177 ////////////////////////////////////////////////////////////////////////////////
2178 /// Prepare dataset for use with cached constant terms listed in
2179 /// 'cacheList' of expression 'arg'. Deactivate tree branches
2180 /// for any dataset observable that is either not used at all,
2181 /// or is used exclusively by cached branch nodes.
2182 
2183 void RooAbsData::optimizeReadingWithCaching(RooAbsArg& arg, const RooArgSet& cacheList, const RooArgSet& keepObsList)
2184 {
2185  RooArgSet pruneSet ;
2186 
2187  // Add unused observables in this dataset to pruneSet
2188  pruneSet.add(*get()) ;
2189  RooArgSet* usedObs = arg.getObservables(*this) ;
2190  pruneSet.remove(*usedObs,kTRUE,kTRUE) ;
2191 
2192  // Add observables exclusively used to calculate cached observables to pruneSet
2193  TIterator* vIter = get()->createIterator() ;
2194  RooAbsArg *var ;
2195  while ((var=(RooAbsArg*) vIter->Next())) {
2196  if (allClientsCached(var,cacheList)) {
2197  pruneSet.add(*var) ;
2198  }
2199  }
2200  delete vIter ;
2201 
2202 
2203  if (pruneSet.getSize()!=0) {
2204 
2205  // Go over all used observables and check if any of them have parameterized
2206  // ranges in terms of pruned observables. If so, remove those observable
2207  // from the pruning list
2208  TIterator* uIter = usedObs->createIterator() ;
2209  RooAbsArg* obs ;
2210  while((obs=(RooAbsArg*)uIter->Next())) {
2211  RooRealVar* rrv = dynamic_cast<RooRealVar*>(obs) ;
2212  if (rrv && !rrv->getBinning().isShareable()) {
2213  RooArgSet depObs ;
2214  RooAbsReal* loFunc = rrv->getBinning().lowBoundFunc() ;
2215  RooAbsReal* hiFunc = rrv->getBinning().highBoundFunc() ;
2216  if (loFunc) {
2217  loFunc->leafNodeServerList(&depObs,0,kTRUE) ;
2218  }
2219  if (hiFunc) {
2220  hiFunc->leafNodeServerList(&depObs,0,kTRUE) ;
2221  }
2222  if (depObs.getSize()>0) {
2223  pruneSet.remove(depObs,kTRUE,kTRUE) ;
2224  }
2225  }
2226  }
2227  delete uIter ;
2228  }
2229 
2230 
2231  // Remove all observables in keep list from prune list
2232  pruneSet.remove(keepObsList,kTRUE,kTRUE) ;
2233 
2234  if (pruneSet.getSize()!=0) {
2235 
2236  // Deactivate tree branches here
2237  cxcoutI(Optimization) << "RooTreeData::optimizeReadingForTestStatistic(" << GetName() << "): Observables " << pruneSet
2238  << " in dataset are either not used at all, orserving exclusively p.d.f nodes that are now cached, disabling reading of these observables for TTree" << endl ;
2239  setArgStatus(pruneSet,kFALSE) ;
2240  }
2241 
2242  delete usedObs ;
2243 
2244 }
2245 
2246 ////////////////////////////////////////////////////////////////////////////////
2247 /// Utility function that determines if all clients of object 'var'
2248 /// appear in given list of cached nodes.
2249 
2250 Bool_t RooAbsData::allClientsCached(RooAbsArg* var, const RooArgSet& cacheList)
2251 {
2252  Bool_t ret(kTRUE), anyClient(kFALSE) ;
2253 
2254  for (const auto client : var->valueClients()) {
2255  anyClient = kTRUE ;
2256  if (!cacheList.find(client->GetName())) {
2257  // If client is not cached recurse
2258  ret &= allClientsCached(client,cacheList) ;
2259  }
2260  }
2261 
2262  return anyClient?ret:kFALSE ;
2263 }
2264 
2265 ////////////////////////////////////////////////////////////////////////////////
2266 
2267 void RooAbsData::attachBuffers(const RooArgSet& extObs)
2268 {
2269  _dstore->attachBuffers(extObs) ;
2270 }
2271 
2272 ////////////////////////////////////////////////////////////////////////////////
2273 
2274 void RooAbsData::resetBuffers()
2275 {
2276  _dstore->resetBuffers() ;
2277 }
2278 
2279 ////////////////////////////////////////////////////////////////////////////////
2280 
2281 Bool_t RooAbsData::canSplitFast() const
2282 {
2283  if (_ownedComponents.size()>0) {
2284  return kTRUE ;
2285  }
2286  return kFALSE ;
2287 }
2288 
2289 ////////////////////////////////////////////////////////////////////////////////
2290 
2291 RooAbsData* RooAbsData::getSimData(const char* name)
2292 {
2293  map<string,RooAbsData*>::iterator i = _ownedComponents.find(name) ;
2294  if (i==_ownedComponents.end()) return 0 ;
2295  return i->second ;
2296 }
2297 
2298 ////////////////////////////////////////////////////////////////////////////////
2299 
2300 void RooAbsData::addOwnedComponent(const char* idxlabel, RooAbsData& data)
2301 {
2302  _ownedComponents[idxlabel]= &data ;
2303 }
2304 
2305 ////////////////////////////////////////////////////////////////////////////////
2306 /// Stream an object of class RooAbsData.
2307 
2308 void RooAbsData::Streamer(TBuffer &R__b)
2309 {
2310  if (R__b.IsReading()) {
2311  R__b.ReadClassBuffer(RooAbsData::Class(),this);
2312 
2313  // Convert on the fly to vector storage if that the current working default
2314  if (defaultStorageType==RooAbsData::Vector) {
2315  convertToVectorStore() ;
2316  }
2317 
2318  } else {
2319  R__b.WriteClassBuffer(RooAbsData::Class(),this);
2320  }
2321 }
2322 
2323 ////////////////////////////////////////////////////////////////////////////////
2324 
2325 void RooAbsData::checkInit() const
2326 {
2327  _dstore->checkInit() ;
2328 }
2329 
2330 ////////////////////////////////////////////////////////////////////////////////
2331 /// Forward draw command to data store
2332 
2333 void RooAbsData::Draw(Option_t* option)
2334 {
2335  if (_dstore) _dstore->Draw(option) ;
2336 }
2337 
2338 ////////////////////////////////////////////////////////////////////////////////
2339 
2340 Bool_t RooAbsData::hasFilledCache() const
2341 {
2342  return _dstore->hasFilledCache() ;
2343 }
2344 
2345 ////////////////////////////////////////////////////////////////////////////////
2346 /// Return a pointer to the TTree which stores the data. Returns a nullpointer
2347 /// if vector-based storage is used. The RooAbsData remains owner of the tree.
2348 /// GetClonedTree() can be used to get a tree even if the internal storage does not use one.
2349 
2350 const TTree *RooAbsData::tree() const
2351 {
2352  if (storageType == RooAbsData::Tree) {
2353  return _dstore->tree();
2354  } else {
2355  coutW(InputArguments) << "RooAbsData::tree(" << GetName() << ") WARNING: is not of StorageType::Tree. "
2356  << "Use GetClonedTree() instead or convert to tree storage." << endl;
2357  return (TTree *)nullptr;
2358  }
2359 }
2360 
2361 ////////////////////////////////////////////////////////////////////////////////
2362 /// Return a clone of the TTree which stores the data or create such a tree
2363 /// if vector storage is used. The user is responsible for deleting the tree
2364 
2365 TTree *RooAbsData::GetClonedTree() const
2366 {
2367  if (storageType == RooAbsData::Tree) {
2368  auto tmp = const_cast<TTree *>(_dstore->tree());
2369  return tmp->CloneTree();
2370  } else {
2371  RooTreeDataStore buffer(GetName(), GetTitle(), *get(), *_dstore);
2372  return buffer.tree().CloneTree();
2373  }
2374 }
2375 
2376 ////////////////////////////////////////////////////////////////////////////////
2377 /// Convert vector-based storage to tree-based storage
2378 
2379 void RooAbsData::convertToTreeStore()
2380 {
2381  if (storageType != RooAbsData::Tree) {
2382  RooTreeDataStore *newStore = new RooTreeDataStore(GetName(), GetTitle(), _vars, *_dstore);
2383  delete _dstore;
2384  _dstore = newStore;
2385  storageType = RooAbsData::Tree;
2386  }
2387 }
2388 
2389 ////////////////////////////////////////////////////////////////////////////////
2390 /// If one of the TObject we have a referenced to is deleted, remove the
2391 /// reference.
2392 
2393 void RooAbsData::RecursiveRemove(TObject *obj)
2394 {
2395  for(auto &iter : _ownedComponents) {
2396  if (iter.second == obj) {
2397  iter.second = nullptr;
2398  }
2399  }
2400 }