Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooTreeDataStore.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 RooTreeDataStore.cxx
19 \class RooTreeDataStore
20 \ingroup Roofitcore
21 
22 RooTreeDataStore is a TTree-backed data storage. When a file is opened before
23 creating the data storage, the storage will be file-backed. This reduces memory
24 pressure because it allows storing the data in the file and reading it on demand.
25 For a completely memory-backed storage, which is faster than the file-backed storage,
26 RooVectorDataStore can be used.
27 
28 With tree-backed storage, the tree can be found in the file with the name
29 `RooTreeDataStore_name_title` for a dataset created as
30 `RooDataSet("name", "title", ...)`.
31 
32 \note A file needs to be opened **before** creating the data storage to enable file-backed
33 storage.
34 ```
35 TFile outputFile("filename.root", "RECREATE");
36 RooAbsData::setDefaultStorageType(RooAbsData::Tree);
37 RooDataSet mydata(...);
38 ```
39 
40 One can also change between TTree- and std::vector-backed storage using
41 RooAbsData::convertToTreeStore() and
42 RooAbsData::convertToVectorStore().
43 **/
44 
45 #include "RooTreeDataStore.h"
46 
47 #include "RooFit.h"
48 #include "RooMsgService.h"
49 
50 #include "Riostream.h"
51 #include "TTree.h"
52 #include "TFile.h"
53 #include "TChain.h"
54 #include "TDirectory.h"
55 #include "TROOT.h"
56 #include "RooFormulaVar.h"
57 #include "RooRealVar.h"
58 #include "RooHistError.h"
59 #include "RooHelpers.h"
60 
61 #include <iomanip>
62 using namespace std ;
63 
64 ClassImp(RooTreeDataStore);
65 
66 
67 Int_t RooTreeDataStore::_defTreeBufSize = 10*1024*1024;
68 
69 
70 
71 ////////////////////////////////////////////////////////////////////////////////
72 
73 RooTreeDataStore::RooTreeDataStore() :
74  _tree(0),
75  _cacheTree(0),
76  _cacheOwner(0),
77  _defCtor(kTRUE),
78  _wgtVar(0),
79  _curWgt(1),
80  _curWgtErrLo(0),
81  _curWgtErrHi(0),
82  _curWgtErr(0)
83 {
84 }
85 
86 
87 
88 ////////////////////////////////////////////////////////////////////////////////
89 /// Constructor to facilitate reading of legacy RooDataSets
90 
91 RooTreeDataStore::RooTreeDataStore(TTree* t, const RooArgSet& vars, const char* wgtVarName) :
92  RooAbsDataStore("blah","blah",varsNoWeight(vars,wgtVarName)),
93  _tree(t),
94  _cacheTree(0),
95  _cacheOwner(0),
96  _defCtor(kTRUE),
97  _varsww(vars),
98  _wgtVar(weightVar(vars,wgtVarName)),
99  _curWgt(1)
100 {
101 }
102 
103 
104 
105 
106 ////////////////////////////////////////////////////////////////////////////////
107 
108 RooTreeDataStore::RooTreeDataStore(const char* name, const char* title, const RooArgSet& vars, const char* wgtVarName) :
109  RooAbsDataStore(name,title,varsNoWeight(vars,wgtVarName)),
110  _tree(0),
111  _cacheTree(0),
112  _cacheOwner(0),
113  _defCtor(kFALSE),
114  _varsww(vars),
115  _wgtVar(weightVar(vars,wgtVarName)),
116  _curWgt(1),
117  _curWgtErrLo(0),
118  _curWgtErrHi(0),
119  _curWgtErr(0)
120 {
121  initialize() ;
122 }
123 
124 
125 
126 
127 ////////////////////////////////////////////////////////////////////////////////
128 
129 RooTreeDataStore::RooTreeDataStore(const char* name, const char* title, const RooArgSet& vars, TTree& t, const RooFormulaVar& select, const char* wgtVarName) :
130  RooAbsDataStore(name,title,varsNoWeight(vars,wgtVarName)),
131  _tree(0),
132  _cacheTree(0),
133  _cacheOwner(0),
134  _defCtor(kFALSE),
135  _varsww(vars),
136  _wgtVar(weightVar(vars,wgtVarName)),
137  _curWgt(1),
138  _curWgtErrLo(0),
139  _curWgtErrHi(0),
140  _curWgtErr(0)
141 {
142  initialize() ;
143  loadValues(&t,&select) ;
144 }
145 
146 
147 
148 ////////////////////////////////////////////////////////////////////////////////
149 
150 RooTreeDataStore::RooTreeDataStore(const char* name, const char* title, const RooArgSet& vars, TTree& t, const char* selExpr, const char* wgtVarName) :
151  RooAbsDataStore(name,title,varsNoWeight(vars,wgtVarName)),
152  _tree(0),
153  _cacheTree(0),
154  _cacheOwner(0),
155  _defCtor(kFALSE),
156  _varsww(vars),
157  _wgtVar(weightVar(vars,wgtVarName)),
158  _curWgt(1),
159  _curWgtErrLo(0),
160  _curWgtErrHi(0),
161  _curWgtErr(0)
162 {
163  initialize() ;
164 
165  if (selExpr && *selExpr) {
166  // Create a RooFormulaVar cut from given cut expression
167  RooFormulaVar select(selExpr,selExpr,_vars) ;
168  loadValues(&t,&select);
169  } else {
170  loadValues(&t);
171  }
172 }
173 
174 
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 
178 RooTreeDataStore::RooTreeDataStore(const char* name, const char* title, const RooArgSet& vars, const RooAbsDataStore& tds, const RooFormulaVar& select, const char* wgtVarName) :
179  RooAbsDataStore(name,title,varsNoWeight(vars,wgtVarName)),
180  _tree(0),
181  _cacheTree(0),
182  _cacheOwner(0),
183  _defCtor(kFALSE),
184  _varsww(vars),
185  _wgtVar(weightVar(vars,wgtVarName)),
186  _curWgt(1),
187  _curWgtErrLo(0),
188  _curWgtErrHi(0),
189  _curWgtErr(0)
190 {
191  initialize() ;
192  loadValues(&tds,&select) ;
193 }
194 
195 
196 
197 ////////////////////////////////////////////////////////////////////////////////
198 
199 RooTreeDataStore::RooTreeDataStore(const char* name, const char* title, const RooArgSet& vars, const RooAbsDataStore& ads, const char* selExpr, const char* wgtVarName) :
200  RooAbsDataStore(name,title,varsNoWeight(vars,wgtVarName)),
201  _tree(0),
202  _cacheTree(0),
203  _cacheOwner(0),
204  _defCtor(kFALSE),
205  _varsww(vars),
206  _wgtVar(weightVar(vars,wgtVarName)),
207  _curWgt(1),
208  _curWgtErrLo(0),
209  _curWgtErrHi(0),
210  _curWgtErr(0)
211 {
212  initialize() ;
213 
214  if (selExpr && *selExpr) {
215  // Create a RooFormulaVar cut from given cut expression
216  RooFormulaVar select(selExpr,selExpr,_vars) ;
217  loadValues(&ads,&select);
218  } else {
219  loadValues(&ads);
220  }
221 }
222 
223 
224 
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 
228 RooTreeDataStore::RooTreeDataStore(const char *name, const char *title, RooAbsDataStore& tds,
229  const RooArgSet& vars, const RooFormulaVar* cutVar, const char* cutRange,
230  Int_t nStart, Int_t nStop, Bool_t /*copyCache*/, const char* wgtVarName) :
231  RooAbsDataStore(name,title,varsNoWeight(vars,wgtVarName)), _defCtor(kFALSE),
232  _varsww(vars),
233  _wgtVar(weightVar(vars,wgtVarName)),
234  _curWgt(1),
235  _curWgtErrLo(0),
236  _curWgtErrHi(0),
237  _curWgtErr(0)
238 {
239  // WVE NEED TO ADJUST THIS FOR WEIGHTS
240 
241  // Protected constructor for internal use only
242  _tree = 0 ;
243  _cacheTree = 0 ;
244  createTree(makeTreeName().c_str(), title);
245 
246  // Deep clone cutVar and attach clone to this dataset
247  RooFormulaVar* cloneVar = 0;
248  if (cutVar) {
249  cloneVar = (RooFormulaVar*) cutVar->cloneTree() ;
250  cloneVar->attachDataStore(tds) ;
251  }
252 
253  // Constructor from existing data set with list of variables that preserves the cache
254  initialize();
255 
256  attachCache(0,((RooTreeDataStore&)tds)._cachedVars) ;
257 
258  // WVE copy values of cached variables here!!!
259  _cacheTree->CopyEntries(((RooTreeDataStore&)tds)._cacheTree) ;
260  _cacheOwner = 0 ;
261 
262  loadValues(&tds,cloneVar,cutRange,nStart,nStop);
263 
264  if (cloneVar) delete cloneVar ;
265 }
266 
267 
268 
269 ////////////////////////////////////////////////////////////////////////////////
270 /// Utility function for constructors
271 /// Return RooArgSet that is copy of allVars minus variable matching wgtName if specified
272 
273 RooArgSet RooTreeDataStore::varsNoWeight(const RooArgSet& allVars, const char* wgtName)
274 {
275  RooArgSet ret(allVars) ;
276  if(wgtName) {
277  RooAbsArg* wgt = allVars.find(wgtName) ;
278  if (wgt) {
279  ret.remove(*wgt,kTRUE,kTRUE) ;
280  }
281  }
282  return ret ;
283 }
284 
285 
286 
287 ////////////////////////////////////////////////////////////////////////////////
288 /// Utility function for constructors
289 /// Return pointer to weight variable if it is defined
290 
291 RooRealVar* RooTreeDataStore::weightVar(const RooArgSet& allVars, const char* wgtName)
292 {
293  if(wgtName) {
294  RooRealVar* wgt = dynamic_cast<RooRealVar*>(allVars.find(wgtName)) ;
295  return wgt ;
296  }
297  return 0 ;
298 }
299 
300 
301 
302 
303 ////////////////////////////////////////////////////////////////////////////////
304 /// Initialize cache of dataset: attach variables of cache ArgSet
305 /// to the corresponding TTree branches
306 
307 void RooTreeDataStore::attachCache(const RooAbsArg* newOwner, const RooArgSet& cachedVarsIn)
308 {
309  // iterate over the cache variables for this dataset
310  _cachedVars.removeAll() ;
311  TIterator* iter = cachedVarsIn.createIterator() ;
312  RooAbsArg *var;
313  while((0 != (var= (RooAbsArg*)iter->Next()))) {
314  var->attachToTree(*_cacheTree,_defTreeBufSize) ;
315  _cachedVars.add(*var) ;
316  }
317  delete iter ;
318  _cacheOwner = newOwner ;
319 
320 }
321 
322 
323 
324 
325 
326 
327 ////////////////////////////////////////////////////////////////////////////////
328 
329 RooTreeDataStore::RooTreeDataStore(const RooTreeDataStore& other, const char* newname) :
330  RooAbsDataStore(other,newname),
331  _tree(0),
332  _cacheTree(0),
333  _defCtor(kFALSE),
334  _varsww(other._varsww),
335  _wgtVar(other._wgtVar),
336  _extWgtArray(other._extWgtArray),
337  _extWgtErrLoArray(other._extWgtErrLoArray),
338  _extWgtErrHiArray(other._extWgtErrHiArray),
339  _extSumW2Array(other._extSumW2Array),
340  _curWgt(other._curWgt),
341  _curWgtErrLo(other._curWgtErrLo),
342  _curWgtErrHi(other._curWgtErrHi),
343  _curWgtErr(other._curWgtErr)
344 {
345  initialize() ;
346  loadValues(&other) ;
347 }
348 
349 
350 ////////////////////////////////////////////////////////////////////////////////
351 
352 RooTreeDataStore::RooTreeDataStore(const RooTreeDataStore& other, const RooArgSet& vars, const char* newname) :
353  RooAbsDataStore(other,varsNoWeight(vars,other._wgtVar?other._wgtVar->GetName():0),newname),
354  _tree(0),
355  _cacheTree(0),
356  _defCtor(kFALSE),
357  _varsww(vars),
358  _wgtVar(other._wgtVar?weightVar(vars,other._wgtVar->GetName()):0),
359  _extWgtArray(other._extWgtArray),
360  _extWgtErrLoArray(other._extWgtErrLoArray),
361  _extWgtErrHiArray(other._extWgtErrHiArray),
362  _extSumW2Array(other._extSumW2Array),
363  _curWgt(other._curWgt),
364  _curWgtErrLo(other._curWgtErrLo),
365  _curWgtErrHi(other._curWgtErrHi),
366  _curWgtErr(other._curWgtErr)
367 {
368  initialize() ;
369  loadValues(&other) ;
370 }
371 
372 
373 
374 
375 ////////////////////////////////////////////////////////////////////////////////
376 /// Destructor
377 
378 RooTreeDataStore::~RooTreeDataStore()
379 {
380  if (_tree) {
381  delete _tree ;
382  }
383  if (_cacheTree) {
384  delete _cacheTree ;
385  }
386 }
387 
388 
389 
390 ////////////////////////////////////////////////////////////////////////////////
391 /// One-time initialization common to all constructor forms. Attach
392 /// variables of internal ArgSet to the corresponding TTree branches
393 
394 void RooTreeDataStore::initialize()
395 {
396  // Recreate (empty) cache tree
397  createTree(makeTreeName().c_str(), GetTitle());
398 
399  // Attach each variable to the dataset
400  for (auto var : _varsww) {
401  var->attachToTree(*_tree,_defTreeBufSize) ;
402  }
403 }
404 
405 
406 
407 
408 
409 ////////////////////////////////////////////////////////////////////////////////
410 /// Create TTree object that lives in memory, independent of current
411 /// location of gDirectory
412 
413 void RooTreeDataStore::createTree(const char* name, const char* title)
414 {
415  if (!_tree) {
416  _tree = new TTree(name,title);
417  _tree->ResetBit(kCanDelete);
418  _tree->ResetBit(kMustCleanup);
419  _tree->SetDirectory(nullptr);
420  }
421 
422  TString pwd(gDirectory->GetPath()) ;
423  TString memDir(gROOT->GetName()) ;
424  memDir.Append(":/") ;
425  Bool_t notInMemNow= (pwd!=memDir) ;
426 
427  // cout << "RooTreeData::createTree pwd=" << pwd << " memDir=" << memDir << " notInMemNow = " << (notInMemNow?"T":"F") << endl ;
428 
429  if (notInMemNow) {
430  gDirectory->cd(memDir) ;
431  }
432 
433  if (!_cacheTree) {
434  _cacheTree = new TTree((std::string(name) + "_cacheTree").c_str(), title);
435  _cacheTree->SetDirectory(0) ;
436  gDirectory->RecursiveRemove(_cacheTree) ;
437  }
438 
439  if (notInMemNow) {
440  gDirectory->cd(pwd) ;
441  }
442 
443 }
444 
445 
446 
447 
448 ////////////////////////////////////////////////////////////////////////////////
449 /// Load values from tree 't' into this data collection, optionally
450 /// selecting events using 'select' RooFormulaVar.
451 ///
452 /// The source tree 't' is first clone as not disturb its branch
453 /// structure when retrieving information from it.
454 
455 void RooTreeDataStore::loadValues(const TTree *t, const RooFormulaVar* select, const char* /*rangeName*/, Int_t /*nStart*/, Int_t /*nStop*/)
456 {
457  // Clone source tree
458  // WVE Clone() crashes on trees, CloneTree() crashes on tchains :-(
459 
460  // Change directory to memory dir before cloning tree to avoid ROOT errors
461  TString pwd(gDirectory->GetPath()) ;
462  TString memDir(gROOT->GetName()) ;
463  memDir.Append(":/") ;
464  Bool_t notInMemNow= (pwd!=memDir) ;
465 
466  if (notInMemNow) {
467  gDirectory->cd(memDir) ;
468  }
469 
470  TTree* tClone ;
471  if (dynamic_cast<const TChain*>(t)) {
472  tClone = (TTree*) t->Clone() ;
473  } else {
474  tClone = ((TTree*)t)->CloneTree() ;
475  }
476 
477  // Change directory back to original directory
478  tClone->SetDirectory(0) ;
479 
480  if (notInMemNow) {
481  gDirectory->cd(pwd) ;
482  }
483 
484  // Clone list of variables
485  RooArgSet *sourceArgSet = (RooArgSet*) _varsww.snapshot(kFALSE) ;
486 
487  // Check that we have the branches:
488  for (const auto var : *sourceArgSet) {
489  if (!tClone->GetBranch(var->GetName())) {
490  coutE(InputArguments) << "Didn't find a branch in Tree '" << tClone->GetName()
491  << "' to read variable '" << var->GetName() << "' from."
492  << "\n\tNote: Name the RooFit variable the same as the branch." << std::endl;
493  }
494  }
495 
496  // Attach args in cloned list to cloned source tree
497  for (const auto sourceArg : *sourceArgSet) {
498  sourceArg->attachToTree(*tClone,_defTreeBufSize) ;
499  }
500 
501  // Redirect formula servers to sourceArgSet
502  RooFormulaVar* selectClone(0) ;
503  if (select) {
504  selectClone = (RooFormulaVar*) select->cloneTree() ;
505  selectClone->recursiveRedirectServers(*sourceArgSet) ;
506  selectClone->setOperMode(RooAbsArg::ADirty,kTRUE) ;
507  }
508 
509  // Loop over events in source tree
510  Int_t numInvalid(0) ;
511  Int_t nevent= (Int_t)tClone->GetEntries();
512  for(Int_t i=0; i < nevent; ++i) {
513  Int_t entryNumber=tClone->GetEntryNumber(i);
514  if (entryNumber<0) break;
515  tClone->GetEntry(entryNumber,1);
516 
517  // Copy from source to destination
518  Bool_t allOK(kTRUE) ;
519  for (unsigned int j=0; j < sourceArgSet->size(); ++j) {
520  auto destArg = _varsww[j];
521  const auto sourceArg = (*sourceArgSet)[j];
522 
523  destArg->copyCache(sourceArg) ;
524  sourceArg->copyCache(destArg) ;
525  if (!destArg->isValid()) {
526  numInvalid++ ;
527  allOK=kFALSE ;
528  break ;
529  }
530  }
531 
532  // Does this event pass the cuts?
533  if (!allOK || (selectClone && selectClone->getVal()==0)) {
534  continue ;
535  }
536 
537  fill() ;
538  }
539 
540  if (numInvalid>0) {
541  coutI(Eval) << "RooTreeDataStore::loadValues(" << GetName() << ") Ignored " << numInvalid << " out of range events" << endl ;
542  }
543 
544  SetTitle(t->GetTitle());
545 
546  delete sourceArgSet ;
547  delete selectClone ;
548  delete tClone ;
549 }
550 
551 
552 
553 
554 
555 
556 ////////////////////////////////////////////////////////////////////////////////
557 /// Load values from dataset 't' into this data collection, optionally
558 /// selecting events using 'select' RooFormulaVar
559 ///
560 
561 void RooTreeDataStore::loadValues(const RooAbsDataStore *ads, const RooFormulaVar* select,
562  const char* rangeName, Int_t nStart, Int_t nStop)
563 {
564  // Redirect formula servers to source data row
565  RooFormulaVar* selectClone(0) ;
566  if (select) {
567  selectClone = (RooFormulaVar*) select->cloneTree() ;
568  selectClone->recursiveRedirectServers(*ads->get()) ;
569  selectClone->setOperMode(RooAbsArg::ADirty,kTRUE) ;
570  }
571 
572  // Force RDS internal initialization
573  ads->get(0) ;
574 
575  // Loop over events in source tree
576  Int_t nevent = nStop < ads->numEntries() ? nStop : ads->numEntries() ;
577 
578  Bool_t isTDS = dynamic_cast<const RooTreeDataStore*>(ads) ;
579  if (isTDS) {
580  ((RooTreeDataStore*)(ads))->resetBuffers() ;
581  }
582 
583  std::vector<std::string> ranges;
584  if (rangeName) {
585  ranges = RooHelpers::tokenise(rangeName, ",");
586  }
587 
588  for(Int_t i=nStart; i < nevent ; ++i) {
589  ads->get(i) ;
590 
591  // Does this event pass the cuts?
592  if (selectClone && selectClone->getVal()==0) {
593  continue ;
594  }
595 
596 
597  if (isTDS) {
598  _varsww.assignValueOnly(((RooTreeDataStore*)ads)->_varsww) ;
599  } else {
600  _varsww.assignValueOnly(*ads->get()) ;
601  }
602 
603  // Check that all copied values are valid
604  bool allValid = true;
605  for (const auto arg : _varsww) {
606  allValid = arg->isValid() && (ranges.empty() || std::any_of(ranges.begin(), ranges.end(),
607  [arg](const std::string& range){return arg->inRange(range.c_str());}) );
608  if (!allValid)
609  break ;
610  }
611  //cout << "RooTreeData::loadValues(" << GetName() << ") allValid = " << (allValid?"T":"F") << endl ;
612  if (!allValid) {
613  continue ;
614  }
615 
616  _cachedVars = ((RooTreeDataStore*)ads)->_cachedVars ;
617  fill() ;
618  }
619 
620  if (isTDS) {
621  ((RooTreeDataStore*)(ads))->restoreAlternateBuffers() ;
622  }
623 
624  delete selectClone ;
625  SetTitle(ads->GetTitle());
626 }
627 
628 
629 
630 ////////////////////////////////////////////////////////////////////////////////
631 /// Return true if currently loaded coordinate is considered valid within
632 /// the current range definitions of all observables
633 
634 Bool_t RooTreeDataStore::valid() const
635 {
636  return kTRUE ;
637 }
638 
639 
640 
641 
642 ////////////////////////////////////////////////////////////////////////////////
643 /// Interface function to TTree::Fill
644 
645 Int_t RooTreeDataStore::fill()
646 {
647  return _tree->Fill() ;
648 }
649 
650 
651 
652 ////////////////////////////////////////////////////////////////////////////////
653 /// Load the n-th data point (n='index') in memory
654 /// and return a pointer to the internal RooArgSet
655 /// holding its coordinates.
656 
657 const RooArgSet* RooTreeDataStore::get(Int_t index) const
658 {
659  checkInit() ;
660 
661  Int_t ret = ((RooTreeDataStore*)this)->GetEntry(index, 1) ;
662 
663  if(!ret) return 0;
664 
665  if (_doDirtyProp) {
666  // Raise all dirty flags
667  for (auto var : _vars) {
668  var->setValueDirty(); // This triggers recalculation of all clients
669  }
670 
671  for (auto var : _cachedVars) {
672  var->setValueDirty(); // This triggers recalculation of all clients, but doesn't recalculate self
673  var->clearValueDirty();
674  }
675  }
676 
677  // Update current weight cache
678  if (_extWgtArray) {
679 
680  // If external array is specified use that
681  _curWgt = _extWgtArray[index] ;
682  _curWgtErrLo = _extWgtErrLoArray[index] ;
683  _curWgtErrHi = _extWgtErrHiArray[index] ;
684  _curWgtErr = sqrt(_extSumW2Array[index]) ;
685 
686  } else if (_wgtVar) {
687 
688  // Otherwise look for weight variable
689  _curWgt = _wgtVar->getVal() ;
690  _curWgtErrLo = _wgtVar->getAsymErrorLo() ;
691  _curWgtErrHi = _wgtVar->getAsymErrorHi() ;
692  _curWgtErr = _wgtVar->hasAsymError() ? ((_wgtVar->getAsymErrorHi() - _wgtVar->getAsymErrorLo())/2) : _wgtVar->getError() ;
693 
694  } else {
695 
696  // Otherwise return 1
697  _curWgt=1.0 ;
698  _curWgtErrLo = 0 ;
699  _curWgtErrHi = 0 ;
700  _curWgtErr = 0 ;
701 
702  }
703 
704  return &_vars;
705 }
706 
707 
708 
709 ////////////////////////////////////////////////////////////////////////////////
710 /// Return the weight of the n-th data point (n='index') in memory
711 
712 Double_t RooTreeDataStore::weight(Int_t index) const
713 {
714  get(index) ;
715  return weight() ;
716 }
717 
718 
719 
720 ////////////////////////////////////////////////////////////////////////////////
721 /// Return the weight of the n-th data point (n='index') in memory
722 
723 Double_t RooTreeDataStore::weight() const
724 {
725  return _curWgt ;
726 }
727 
728 
729 ////////////////////////////////////////////////////////////////////////////////
730 
731 Double_t RooTreeDataStore::weightError(RooAbsData::ErrorType etype) const
732 {
733  if (_extWgtArray) {
734 
735  // We have a weight array, use that info
736 
737  // Return symmetric error on current bin calculated either from Poisson statistics or from SumOfWeights
738  Double_t lo,hi ;
739  weightError(lo,hi,etype) ;
740  return (lo+hi)/2 ;
741 
742  } else if (_wgtVar) {
743 
744  // We have a a weight variable, use that info
745  if (_wgtVar->hasAsymError()) {
746  return ( _wgtVar->getAsymErrorHi() - _wgtVar->getAsymErrorLo() ) / 2 ;
747  } else {
748  return _wgtVar->getError() ;
749  }
750 
751  } else {
752 
753  // We have no weights
754  return 0 ;
755 
756  }
757 }
758 
759 
760 
761 ////////////////////////////////////////////////////////////////////////////////
762 
763 void RooTreeDataStore::weightError(Double_t& lo, Double_t& hi, RooAbsData::ErrorType etype) const
764 {
765  if (_extWgtArray) {
766 
767  // We have a weight array, use that info
768  switch (etype) {
769 
770  case RooAbsData::Auto:
771  throw string(Form("RooDataHist::weightError(%s) error type Auto not allowed here",GetName())) ;
772  break ;
773 
774  case RooAbsData::Expected:
775  throw string(Form("RooDataHist::weightError(%s) error type Expected not allowed here",GetName())) ;
776  break ;
777 
778  case RooAbsData::Poisson:
779  // Weight may be preset or precalculated
780  if (_curWgtErrLo>=0) {
781  lo = _curWgtErrLo ;
782  hi = _curWgtErrHi ;
783  return ;
784  }
785 
786  // Otherwise Calculate poisson errors
787  Double_t ym,yp ;
788  RooHistError::instance().getPoissonInterval(Int_t(weight()+0.5),ym,yp,1) ;
789  lo = weight()-ym ;
790  hi = yp-weight() ;
791  return ;
792 
793  case RooAbsData::SumW2:
794  lo = _curWgtErr ;
795  hi = _curWgtErr ;
796  return ;
797 
798  case RooAbsData::None:
799  lo = 0 ;
800  hi = 0 ;
801  return ;
802  }
803 
804  } else if (_wgtVar) {
805 
806  // We have a a weight variable, use that info
807  if (_wgtVar->hasAsymError()) {
808  hi = _wgtVar->getAsymErrorHi() ;
809  lo = _wgtVar->getAsymErrorLo() ;
810  } else {
811  hi = _wgtVar->getError() ;
812  lo = _wgtVar->getError() ;
813  }
814 
815  } else {
816 
817  // We are unweighted
818  lo=0 ;
819  hi=0 ;
820 
821  }
822 }
823 
824 
825 ////////////////////////////////////////////////////////////////////////////////
826 /// Change name of internal observable named 'from' into 'to'
827 
828 Bool_t RooTreeDataStore::changeObservableName(const char* from, const char* to)
829 {
830  // Find observable to be changed
831  RooAbsArg* var = _vars.find(from) ;
832 
833  // Check that we found it
834  if (!var) {
835  coutE(InputArguments) << "RooTreeDataStore::changeObservableName(" << GetName() << " no observable " << from << " in this dataset" << endl ;
836  return kTRUE ;
837  }
838 
839  // Process name change
840  TString oldBranchName = var->cleanBranchName() ;
841  var->SetName(to) ;
842 
843  // Change the branch name as well
844  if (_tree->GetBranch(oldBranchName.Data())) {
845 
846  // Simple case varName = branchName
847  _tree->GetBranch(oldBranchName.Data())->SetName(var->cleanBranchName().Data()) ;
848 
849  // Process any error branch if existing
850  if (_tree->GetBranch(Form("%s_err",oldBranchName.Data()))) {
851  _tree->GetBranch(Form("%s_err",oldBranchName.Data()))->SetName(Form("%s_err",var->cleanBranchName().Data())) ;
852  }
853  if (_tree->GetBranch(Form("%s_aerr_lo",oldBranchName.Data()))) {
854  _tree->GetBranch(Form("%s_aerr_lo",oldBranchName.Data()))->SetName(Form("%s_aerr_lo",var->cleanBranchName().Data())) ;
855  }
856  if (_tree->GetBranch(Form("%s_aerr_hi",oldBranchName.Data()))) {
857  _tree->GetBranch(Form("%s_aerr_hi",oldBranchName.Data()))->SetName(Form("%s_aerr_hi",var->cleanBranchName().Data())) ;
858  }
859 
860  } else {
861 
862  // Native category case branchNames = varName_idx and varName_lbl
863  if (_tree->GetBranch(Form("%s_idx",oldBranchName.Data()))) {
864  _tree->GetBranch(Form("%s_idx",oldBranchName.Data()))->SetName(Form("%s_idx",var->cleanBranchName().Data())) ;
865  }
866  if (_tree->GetBranch(Form("%s_lbl",oldBranchName.Data()))) {
867  _tree->GetBranch(Form("%s_lbl",oldBranchName.Data()))->SetName(Form("%s_lb",var->cleanBranchName().Data())) ;
868  }
869 
870  }
871 
872  return kFALSE ;
873 }
874 
875 
876 
877 ////////////////////////////////////////////////////////////////////////////////
878 /// Add a new column to the data set which holds the pre-calculated values
879 /// of 'newVar'. This operation is only meaningful if 'newVar' is a derived
880 /// value.
881 ///
882 /// The return value points to the added element holding 'newVar's value
883 /// in the data collection. The element is always the corresponding fundamental
884 /// type of 'newVar' (e.g. a RooRealVar if 'newVar' is a RooFormulaVar)
885 ///
886 /// Note: This function is explicitly NOT intended as a speed optimization
887 /// opportunity for the user. Components of complex PDFs that can be
888 /// precalculated with the dataset are automatically identified as such
889 /// and will be precalculated when fitting to a dataset
890 ///
891 /// By forcibly precalculating functions with non-trivial Jacobians,
892 /// or functions of multiple variables occurring in the data set,
893 /// using addColumn(), you may alter the outcome of the fit.
894 ///
895 /// Only in cases where such a modification of fit behaviour is intentional,
896 /// this function should be used.
897 
898 RooAbsArg* RooTreeDataStore::addColumn(RooAbsArg& newVar, Bool_t adjustRange)
899 {
900  checkInit() ;
901 
902  // Create a fundamental object of the right type to hold newVar values
903  RooAbsArg* valHolder= newVar.createFundamental();
904  // Sanity check that the holder really is fundamental
905  if(!valHolder->isFundamental()) {
906  coutE(InputArguments) << GetName() << "::addColumn: holder argument is not fundamental: \""
907  << valHolder->GetName() << "\"" << endl;
908  return 0;
909  }
910 
911  // WVE need to reset TTRee buffers to original datamembers here
912  resetBuffers() ;
913 
914  // Clone variable and attach to cloned tree
915  RooAbsArg* newVarClone = newVar.cloneTree() ;
916  newVarClone->recursiveRedirectServers(_vars,kFALSE) ;
917 
918  // Attach value place holder to this tree
919  ((RooAbsArg*)valHolder)->attachToTree(*_tree,_defTreeBufSize) ;
920  _vars.add(*valHolder) ;
921  _varsww.add(*valHolder) ;
922 
923 
924  // Fill values of of placeholder
925  for (int i=0 ; i<GetEntries() ; i++) {
926  get(i) ;
927 
928  newVarClone->syncCache(&_vars) ;
929  valHolder->copyCache(newVarClone) ;
930  valHolder->fillTreeBranch(*_tree) ;
931  }
932 
933  // WVE need to restore TTRee buffers to previous values here
934  restoreAlternateBuffers() ;
935 
936  if (adjustRange) {
937 // // Set range of valHolder to (just) bracket all values stored in the dataset
938 // Double_t vlo,vhi ;
939 // RooRealVar* rrvVal = dynamic_cast<RooRealVar*>(valHolder) ;
940 // if (rrvVal) {
941 // getRange(*rrvVal,vlo,vhi,0.05) ;
942 // rrvVal->setRange(vlo,vhi) ;
943 // }
944  }
945 
946 
947 
948  delete newVarClone ;
949  return valHolder ;
950 }
951 
952 
953 
954 ////////////////////////////////////////////////////////////////////////////////
955 /// Utility function to add multiple columns in one call
956 /// See addColumn() for details
957 
958 RooArgSet* RooTreeDataStore::addColumns(const RooArgList& varList)
959 {
960  TIterator* vIter = varList.createIterator() ;
961  RooAbsArg* var ;
962 
963  checkInit() ;
964 
965  TList cloneSetList ;
966  RooArgSet cloneSet ;
967  RooArgSet* holderSet = new RooArgSet ;
968 
969  // WVE need to reset TTRee buffers to original datamembers here
970  resetBuffers() ;
971 
972 
973  while((var=(RooAbsArg*)vIter->Next())) {
974  // Create a fundamental object of the right type to hold newVar values
975  RooAbsArg* valHolder= var->createFundamental();
976  holderSet->add(*valHolder) ;
977 
978  // Sanity check that the holder really is fundamental
979  if(!valHolder->isFundamental()) {
980  coutE(InputArguments) << GetName() << "::addColumn: holder argument is not fundamental: \""
981  << valHolder->GetName() << "\"" << endl;
982  return 0;
983  }
984 
985  // Clone variable and attach to cloned tree
986  RooArgSet* newVarCloneList = (RooArgSet*) RooArgSet(*var).snapshot() ;
987  if (!newVarCloneList) {
988  coutE(InputArguments) << "RooTreeDataStore::RooTreeData(" << GetName()
989  << ") Couldn't deep-clone variable " << var->GetName() << ", abort." << endl ;
990  return 0 ;
991  }
992  RooAbsArg* newVarClone = newVarCloneList->find(var->GetName()) ;
993  newVarClone->recursiveRedirectServers(_vars,kFALSE) ;
994  newVarClone->recursiveRedirectServers(*holderSet,kFALSE) ;
995 
996  cloneSetList.Add(newVarCloneList) ;
997  cloneSet.add(*newVarClone) ;
998 
999  // Attach value place holder to this tree
1000  ((RooAbsArg*)valHolder)->attachToTree(*_tree,_defTreeBufSize) ;
1001  _vars.addOwned(*valHolder) ;
1002  }
1003  delete vIter ;
1004 
1005 
1006  TIterator* cIter = cloneSet.createIterator() ;
1007  TIterator* hIter = holderSet->createIterator() ;
1008  RooAbsArg *cloneArg, *holder ;
1009  // Fill values of of placeholder
1010  for (int i=0 ; i<GetEntries() ; i++) {
1011  get(i) ;
1012 
1013  cIter->Reset() ;
1014  hIter->Reset() ;
1015  while((cloneArg=(RooAbsArg*)cIter->Next())) {
1016  holder = (RooAbsArg*)hIter->Next() ;
1017 
1018  cloneArg->syncCache(&_vars) ;
1019  holder->copyCache(cloneArg) ;
1020  holder->fillTreeBranch(*_tree) ;
1021  }
1022  }
1023 
1024  // WVE need to restore TTRee buffers to previous values here
1025  restoreAlternateBuffers() ;
1026 
1027  delete cIter ;
1028  delete hIter ;
1029 
1030  cloneSetList.Delete() ;
1031  return holderSet ;
1032 }
1033 
1034 
1035 
1036 
1037 ////////////////////////////////////////////////////////////////////////////////
1038 /// Merge columns of supplied data set(s) with this data set. All
1039 /// data sets must have equal number of entries. In case of
1040 /// duplicate columns the column of the last dataset in the list
1041 /// prevails
1042 
1043 RooAbsDataStore* RooTreeDataStore::merge(const RooArgSet& allVars, list<RooAbsDataStore*> dstoreList)
1044 {
1045  RooTreeDataStore* mergedStore = new RooTreeDataStore("merged","merged",allVars) ;
1046 
1047  Int_t nevt = dstoreList.front()->numEntries() ;
1048  for (int i=0 ; i<nevt ; i++) {
1049 
1050  // Cope data from self
1051  mergedStore->_vars = *get(i) ;
1052 
1053  // Copy variables from merge sets
1054  for (list<RooAbsDataStore*>::iterator iter = dstoreList.begin() ; iter!=dstoreList.end() ; ++iter) {
1055  const RooArgSet* partSet = (*iter)->get(i) ;
1056  mergedStore->_vars = *partSet ;
1057  }
1058 
1059  mergedStore->fill() ;
1060  }
1061  return mergedStore ;
1062 }
1063 
1064 
1065 
1066 
1067 
1068 ////////////////////////////////////////////////////////////////////////////////
1069 
1070 void RooTreeDataStore::append(RooAbsDataStore& other)
1071 {
1072  Int_t nevt = other.numEntries() ;
1073  for (int i=0 ; i<nevt ; i++) {
1074  _vars = *other.get(i) ;
1075  if (_wgtVar) {
1076  _wgtVar->setVal(other.weight()) ;
1077  }
1078 
1079  fill() ;
1080  }
1081 }
1082 
1083 
1084 ////////////////////////////////////////////////////////////////////////////////
1085 
1086 Double_t RooTreeDataStore::sumEntries() const
1087 {
1088  if (_wgtVar) {
1089 
1090  Double_t sum(0), carry(0);
1091  Int_t nevt = numEntries() ;
1092  for (int i=0 ; i<nevt ; i++) {
1093  get(i) ;
1094  // Kahan's algorithm for summing to avoid loss of precision
1095  Double_t y = _wgtVar->getVal() - carry;
1096  Double_t t = sum + y;
1097  carry = (t - sum) - y;
1098  sum = t;
1099  }
1100  return sum ;
1101 
1102  } else if (_extWgtArray) {
1103 
1104  Double_t sum(0) , carry(0);
1105  Int_t nevt = numEntries() ;
1106  for (int i=0 ; i<nevt ; i++) {
1107  // Kahan's algorithm for summing to avoid loss of precision
1108  Double_t y = _extWgtArray[i] - carry;
1109  Double_t t = sum + y;
1110  carry = (t - sum) - y;
1111  sum = t;
1112  }
1113  return sum ;
1114 
1115  } else {
1116 
1117  return numEntries() ;
1118 
1119  }
1120 }
1121 
1122 
1123 
1124 
1125 ////////////////////////////////////////////////////////////////////////////////
1126 
1127 Int_t RooTreeDataStore::numEntries() const
1128 {
1129  return _tree->GetEntries() ;
1130 }
1131 
1132 
1133 
1134 ////////////////////////////////////////////////////////////////////////////////
1135 
1136 void RooTreeDataStore::reset()
1137 {
1138  Reset() ;
1139 }
1140 
1141 
1142 
1143 ////////////////////////////////////////////////////////////////////////////////
1144 /// Cache given RooAbsArgs with this tree: The tree is
1145 /// given direct write access of the args internal cache
1146 /// the args values is pre-calculated for all data points
1147 /// in this data collection. Upon a get() call, the
1148 /// internal cache of 'newVar' will be loaded with the
1149 /// precalculated value and it's dirty flag will be cleared.
1150 
1151 void RooTreeDataStore::cacheArgs(const RooAbsArg* owner, RooArgSet& newVarSet, const RooArgSet* nset, Bool_t /*skipZeroWeights*/)
1152 {
1153  checkInit() ;
1154 
1155  _cacheOwner = owner ;
1156 
1157  RooArgSet* constExprVarSet = (RooArgSet*) newVarSet.selectByAttrib("ConstantExpression",kTRUE) ;
1158  TIterator *iter = constExprVarSet->createIterator() ;
1159  RooAbsArg *arg ;
1160 
1161  Bool_t doTreeFill = (_cachedVars.getSize()==0) ;
1162 
1163  while ((arg=(RooAbsArg*)iter->Next())) {
1164  // Attach original newVar to this tree
1165  arg->attachToTree(*_cacheTree,_defTreeBufSize) ;
1166  //arg->recursiveRedirectServers(_vars) ;
1167  _cachedVars.add(*arg) ;
1168  }
1169 
1170  // WVE need to reset TTRee buffers to original datamembers here
1171  //resetBuffers() ;
1172 
1173  // Refill regular and cached variables of current tree from clone
1174  for (int i=0 ; i<GetEntries() ; i++) {
1175  get(i) ;
1176 
1177  // Evaluate the cached variables and store the results
1178  iter->Reset() ;
1179  while ((arg=(RooAbsArg*)iter->Next())) {
1180  arg->setValueDirty() ;
1181  arg->syncCache(nset) ;
1182  if (!doTreeFill) {
1183  arg->fillTreeBranch(*_cacheTree) ;
1184  }
1185  }
1186 
1187  if (doTreeFill) {
1188  _cacheTree->Fill() ;
1189  }
1190  }
1191 
1192  // WVE need to restore TTRee buffers to previous values here
1193  //restoreAlternateBuffers() ;
1194 
1195  delete iter ;
1196  delete constExprVarSet ;
1197 }
1198 
1199 
1200 
1201 
1202 ////////////////////////////////////////////////////////////////////////////////
1203 /// Activate or deactivate the branch status of the TTree branch associated
1204 /// with the given set of dataset observables
1205 
1206 void RooTreeDataStore::setArgStatus(const RooArgSet& set, Bool_t active)
1207 {
1208  TIterator* iter = set.createIterator() ;
1209  RooAbsArg* arg ;
1210  while ((arg=(RooAbsArg*)iter->Next())) {
1211  RooAbsArg* depArg = _vars.find(arg->GetName()) ;
1212  if (!depArg) {
1213  coutE(InputArguments) << "RooTreeDataStore::setArgStatus(" << GetName()
1214  << ") dataset doesn't contain variable " << arg->GetName() << endl ;
1215  continue ;
1216  }
1217  depArg->setTreeBranchStatus(*_tree,active) ;
1218  }
1219  delete iter ;
1220 }
1221 
1222 
1223 
1224 ////////////////////////////////////////////////////////////////////////////////
1225 /// Remove tree with values of cached observables
1226 /// and clear list of cached observables
1227 
1228 void RooTreeDataStore::resetCache()
1229 {
1230  // Empty list of cached functions
1231  _cachedVars.removeAll() ;
1232 
1233  // Delete & recreate cache tree
1234  delete _cacheTree ;
1235  _cacheTree = 0 ;
1236  createTree(makeTreeName().c_str(), GetTitle());
1237 
1238  return ;
1239 }
1240 
1241 
1242 
1243 
1244 ////////////////////////////////////////////////////////////////////////////////
1245 
1246 void RooTreeDataStore::attachBuffers(const RooArgSet& extObs)
1247 {
1248  _attachedBuffers.removeAll() ;
1249  for (const auto arg : _varsww) {
1250  RooAbsArg* extArg = extObs.find(arg->GetName()) ;
1251  if (extArg) {
1252  if (arg->getAttribute("StoreError")) {
1253  extArg->setAttribute("StoreError") ;
1254  }
1255  if (arg->getAttribute("StoreAsymError")) {
1256  extArg->setAttribute("StoreAsymError") ;
1257  }
1258  extArg->attachToTree(*_tree) ;
1259  _attachedBuffers.add(*extArg) ;
1260  }
1261  }
1262 }
1263 
1264 
1265 
1266 ////////////////////////////////////////////////////////////////////////////////
1267 
1268 void RooTreeDataStore::resetBuffers()
1269 {
1270  RooFIter iter = _varsww.fwdIterator() ;
1271  RooAbsArg* arg ;
1272  while((arg=iter.next())) {
1273  arg->attachToTree(*_tree) ;
1274  }
1275 }
1276 
1277 
1278 
1279 ////////////////////////////////////////////////////////////////////////////////
1280 
1281 void RooTreeDataStore::restoreAlternateBuffers()
1282 {
1283  RooFIter iter = _attachedBuffers.fwdIterator() ;
1284  RooAbsArg* arg ;
1285  while((arg=iter.next())) {
1286  arg->attachToTree(*_tree) ;
1287  }
1288 }
1289 
1290 
1291 
1292 ////////////////////////////////////////////////////////////////////////////////
1293 
1294 void RooTreeDataStore::checkInit() const
1295 {
1296  if (_defCtor) {
1297  const_cast<RooTreeDataStore*>(this)->initialize() ;
1298  _defCtor = kFALSE ;
1299  }
1300 }
1301 
1302 
1303 
1304 
1305 
1306 ////////////////////////////////////////////////////////////////////////////////
1307 /// Interface function to TTree::GetEntries
1308 
1309 Stat_t RooTreeDataStore::GetEntries() const
1310 {
1311  return _tree->GetEntries() ;
1312 }
1313 
1314 
1315 ////////////////////////////////////////////////////////////////////////////////
1316 /// Interface function to TTree::Reset
1317 
1318 void RooTreeDataStore::Reset(Option_t* option)
1319 {
1320  _tree->Reset(option) ;
1321 }
1322 
1323 
1324 ////////////////////////////////////////////////////////////////////////////////
1325 /// Interface function to TTree::Fill
1326 
1327 Int_t RooTreeDataStore::Fill()
1328 {
1329  return _tree->Fill() ;
1330 }
1331 
1332 
1333 ////////////////////////////////////////////////////////////////////////////////
1334 /// Interface function to TTree::GetEntry
1335 
1336 Int_t RooTreeDataStore::GetEntry(Int_t entry, Int_t getall)
1337 {
1338  Int_t ret1 = _tree->GetEntry(entry,getall) ;
1339  if (!ret1) return 0 ;
1340  _cacheTree->GetEntry(entry,getall) ;
1341  return ret1 ;
1342 }
1343 
1344 
1345 ////////////////////////////////////////////////////////////////////////////////
1346 
1347 void RooTreeDataStore::Draw(Option_t* option)
1348 {
1349  _tree->Draw(option) ;
1350 }
1351 
1352 ////////////////////////////////////////////////////////////////////////////////
1353 /// Stream an object of class RooTreeDataStore.
1354 
1355 void RooTreeDataStore::Streamer(TBuffer &R__b)
1356 {
1357  if (R__b.IsReading()) {
1358  UInt_t R__s, R__c;
1359  const Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
1360 
1361  R__b.ReadClassBuffer(RooTreeDataStore::Class(), this, R__v, R__s, R__c);
1362 
1363  if (!_tree) {
1364  // If the tree has not been deserialised automatically, it is time to load
1365  // it now.
1366  TFile* parent = dynamic_cast<TFile*>(R__b.GetParent());
1367  assert(parent);
1368  parent->GetObject(makeTreeName().c_str(), _tree);
1369  }
1370 
1371  initialize();
1372 
1373  } else {
1374 
1375  TTree* tmpTree = _tree;
1376  if (_tree) {
1377  // Large trees cannot be written because of the 1Gb I/O limitation.
1378  // Here, we take the tree away from our instance, write it, and continue
1379  // to write the rest of the class normally
1380  auto tmpDir = _tree->GetDirectory();
1381  TFile* parent = dynamic_cast<TFile*>(R__b.GetParent());
1382  assert(parent);
1383 
1384  _tree->SetDirectory(parent);
1385  _tree->FlushBaskets(false);
1386  parent->WriteObject(_tree, makeTreeName().c_str());
1387  _tree->SetDirectory(tmpDir);
1388  _tree = nullptr;
1389  }
1390 
1391  R__b.WriteClassBuffer(RooTreeDataStore::Class(), this);
1392 
1393  _tree = tmpTree;
1394  }
1395 }
1396 
1397 ////////////////////////////////////////////////////////////////////////////////
1398 /// Generate a name for the storage tree from the name and title of this instance.
1399 std::string RooTreeDataStore::makeTreeName() const {
1400  std::string title = GetTitle();
1401  std::replace(title.begin(), title.end(), ' ', '_');
1402  std::replace(title.begin(), title.end(), '-', '_');
1403  return std::string("RooTreeDataStore_") + GetName() + "_" + title;
1404 }
1405