Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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
22TTree-backed data storage. When a file is opened before
23creating the data storage, the storage will be file-backed. This reduces memory
24pressure because it allows storing the data in the file and reading it on demand.
25For a completely memory-backed storage, which is faster than the file-backed storage,
26RooVectorDataStore can be used.
27
28With 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
33storage.
34```
35TFile outputFile("filename.root", "RECREATE");
36RooAbsData::setDefaultStorageType(RooAbsData::Tree);
37RooDataSet mydata(...);
38```
39
40One can also change between TTree- and std::vector-backed storage using
41RooAbsData::convertToTreeStore() and
42RooAbsData::convertToVectorStore().
43**/
44
45#include "RooTreeDataStore.h"
46
47#include "RooMsgService.h"
48#include "RooFormulaVar.h"
49#include "RooRealVar.h"
50#include "RooHistError.h"
51
52#include "ROOT/StringUtils.hxx"
53
54#include "TTree.h"
55#include "TFile.h"
56#include "TChain.h"
57#include "TDirectory.h"
58#include "TBuffer.h"
59#include "TBranch.h"
60#include "TROOT.h"
61
62#include <iomanip>
63using std::endl, std::list, std::string;
64
66
67
69
70
71
72////////////////////////////////////////////////////////////////////////////////
73
75
76
77
78////////////////////////////////////////////////////////////////////////////////
79/// Constructor to facilitate reading of legacy RooDataSets
80
81RooTreeDataStore::RooTreeDataStore(TTree* t, const RooArgSet& vars, const char* wgtVarName) :
82 RooAbsDataStore("blah","blah",varsNoWeight(vars,wgtVarName)),
83 _tree(t),
85 _varsww(vars),
86 _wgtVar(weightVar(vars,wgtVarName))
87{
88}
89
90
91
92
93////////////////////////////////////////////////////////////////////////////////
94
95RooTreeDataStore::RooTreeDataStore(RooStringView name, RooStringView title, const RooArgSet& vars, const char* wgtVarName) :
96 RooAbsDataStore(name,title,varsNoWeight(vars,wgtVarName)),
97 _varsww(vars),
98 _wgtVar(weightVar(vars,wgtVarName))
99{
100 initialize() ;
101}
102
103
104////////////////////////////////////////////////////////////////////////////////
105
106RooTreeDataStore::RooTreeDataStore(RooStringView name, RooStringView title, const RooArgSet& vars, TTree& t, const char* selExpr, const char* wgtVarName) :
107 RooAbsDataStore(name,title,varsNoWeight(vars,wgtVarName)),
108 _varsww(vars),
109 _wgtVar(weightVar(vars,wgtVarName))
110{
111 initialize() ;
112
113 if (selExpr && *selExpr) {
114 // Create a RooFormulaVar cut from given cut expression
115 RooFormulaVar select(selExpr, selExpr, _vars, /*checkVariables=*/false);
116 loadValues(&t,&select);
117 } else {
118 loadValues(&t);
119 }
120}
121
122
123////////////////////////////////////////////////////////////////////////////////
124
125RooTreeDataStore::RooTreeDataStore(RooStringView name, RooStringView title, const RooArgSet& vars, const RooAbsDataStore& ads, const char* selExpr, const char* wgtVarName) :
126 RooAbsDataStore(name,title,varsNoWeight(vars,wgtVarName)),
127 _varsww(vars),
128 _wgtVar(weightVar(vars,wgtVarName))
129{
130 initialize() ;
131
132 if (selExpr && *selExpr) {
133 // Create a RooFormulaVar cut from given cut expression
134 RooFormulaVar select(selExpr, selExpr, _vars, /*checkVariables=*/false);
135 loadValues(&ads,&select);
136 } else {
137 loadValues(&ads);
138 }
139}
140
141
142
143
144////////////////////////////////////////////////////////////////////////////////
145
147 const RooFormulaVar *cutVar, const char *cutRange, Int_t nStart, Int_t nStop,
148 const char *wgtVarName)
149 : RooAbsDataStore(name, title, varsNoWeight(vars, wgtVarName)),
150 _varsww(vars),
151 _wgtVar(weightVar(vars, wgtVarName))
152{
153 // WVE NEED TO ADJUST THIS FOR WEIGHTS
154
155 // Protected constructor for internal use only
156
157 createTree(makeTreeName(), title);
158
159 // Deep clone cutVar and attach clone to this dataset
160 std::unique_ptr<RooFormulaVar> cloneVar;
161 if (cutVar) {
162 cloneVar.reset(static_cast<RooFormulaVar*>(cutVar->cloneTree()));
163 cloneVar->attachDataStore(tds) ;
164 }
165
166 // Constructor from existing data set with list of variables that preserves the cache
167 initialize();
168
169 attachCache(nullptr,(static_cast<RooTreeDataStore&>(tds))._cachedVars) ;
170
171 // WVE copy values of cached variables here!!!
172 _cacheTree->CopyEntries((static_cast<RooTreeDataStore&>(tds))._cacheTree) ;
173 _cacheOwner = nullptr ;
174
175 loadValues(&tds,cloneVar.get(),cutRange,nStart,nStop);
176}
177
178
179std::unique_ptr<RooAbsDataStore> RooTreeDataStore::reduce(RooStringView name, RooStringView title,
180 const RooArgSet& vars, const RooFormulaVar* cutVar, const char* cutRange,
181 std::size_t nStart, std::size_t nStop) {
182 RooArgSet tmp(vars) ;
183 if(_wgtVar && !tmp.contains(*_wgtVar)) {
184 tmp.add(*_wgtVar) ;
185 }
186 const char* wgtVarName = _wgtVar ? _wgtVar->GetName() : nullptr;
187 return std::make_unique<RooTreeDataStore>(name, title, *this, tmp, cutVar, cutRange, nStart, nStop, wgtVarName);
188}
189
190
191////////////////////////////////////////////////////////////////////////////////
192/// Utility function for constructors
193/// Return RooArgSet that is copy of allVars minus variable matching wgtName if specified
194
195RooArgSet RooTreeDataStore::varsNoWeight(const RooArgSet& allVars, const char* wgtName)
196{
197 RooArgSet ret(allVars) ;
198 if(wgtName) {
199 RooAbsArg* wgt = allVars.find(wgtName) ;
200 if (wgt) {
201 ret.remove(*wgt,true,true) ;
202 }
203 }
204 return ret ;
205}
206
207
208
209////////////////////////////////////////////////////////////////////////////////
210/// Utility function for constructors
211/// Return pointer to weight variable if it is defined
212
213RooRealVar* RooTreeDataStore::weightVar(const RooArgSet& allVars, const char* wgtName)
214{
215 if(wgtName) {
216 RooRealVar* wgt = dynamic_cast<RooRealVar*>(allVars.find(wgtName)) ;
217 return wgt ;
218 }
219 return nullptr ;
220}
221
222
223
224
225////////////////////////////////////////////////////////////////////////////////
226/// Initialize cache of dataset: attach variables of cache ArgSet
227/// to the corresponding TTree branches
228
229void RooTreeDataStore::attachCache(const RooAbsArg* newOwner, const RooArgSet& cachedVarsIn)
230{
231 // iterate over the cache variables for this dataset
232 _cachedVars.removeAll() ;
233 for (RooAbsArg * var : cachedVarsIn) {
234 var->attachToTree(*_cacheTree,_defTreeBufSize) ;
235 _cachedVars.add(*var) ;
236 }
237 _cacheOwner = newOwner ;
238
239}
240
241
242
243
244
245
246////////////////////////////////////////////////////////////////////////////////
247
248RooTreeDataStore::RooTreeDataStore(const RooTreeDataStore& other, const char* newname) :
249 RooAbsDataStore(other,newname),
250 _varsww(other._varsww),
251 _wgtVar(other._wgtVar),
256 _curWgt(other._curWgt),
260{
261 initialize() ;
262 loadValues(&other) ;
263}
264
265
266////////////////////////////////////////////////////////////////////////////////
267
268RooTreeDataStore::RooTreeDataStore(const RooTreeDataStore& other, const RooArgSet& vars, const char* newname) :
269 RooAbsDataStore(other,varsNoWeight(vars,other._wgtVar?other._wgtVar->GetName():nullptr),newname),
270 _varsww(vars),
271 _wgtVar(other._wgtVar?weightVar(vars,other._wgtVar->GetName()):nullptr),
276 _curWgt(other._curWgt),
280{
281 initialize() ;
282 loadValues(&other) ;
283}
284
285
286
287
288////////////////////////////////////////////////////////////////////////////////
289/// Destructor
290
292{
293 if (_tree) {
294 delete _tree ;
295 }
296 if (_cacheTree) {
297 delete _cacheTree ;
298 }
299}
300
301
302
303////////////////////////////////////////////////////////////////////////////////
304/// One-time initialization common to all constructor forms. Attach
305/// variables of internal ArgSet to the corresponding TTree branches
306
308{
309 // Recreate (empty) cache tree
311
312 // Attach each variable to the dataset
313 for (auto var : _varsww) {
314 var->attachToTree(*_tree,_defTreeBufSize) ;
315 }
316}
317
318
319
320
321
322////////////////////////////////////////////////////////////////////////////////
323/// Create TTree object that lives in memory, independent of current
324/// location of gDirectory
325
327{
328 if (!_tree) {
329 _tree = new TTree(name.c_str(),title.c_str());
330 _tree->ResetBit(kCanDelete);
331 _tree->ResetBit(kMustCleanup);
332 _tree->SetDirectory(nullptr);
333 }
334
335 TString pwd(gDirectory->GetPath()) ;
336 TString memDir(gROOT->GetName()) ;
337 memDir.Append(":/") ;
338 bool notInMemNow= (pwd!=memDir) ;
339
340 // cout << "RooTreeData::createTree pwd=" << pwd << " memDir=" << memDir << " notInMemNow = " << (notInMemNow?"T":"F") << endl ;
341
342 if (notInMemNow) {
343 gDirectory->cd(memDir) ;
344 }
345
346 if (!_cacheTree) {
347 _cacheTree = new TTree(TString{name.c_str()} + "_cacheTree", TString{title.c_str()});
348 _cacheTree->SetDirectory(nullptr) ;
349 gDirectory->RecursiveRemove(_cacheTree) ;
350 }
351
352 if (notInMemNow) {
353 gDirectory->cd(pwd) ;
354 }
355
356}
357
358
359
360
361////////////////////////////////////////////////////////////////////////////////
362/// Load values from tree 't' into this data collection, optionally
363/// selecting events using the RooFormulaVar 'select'.
364///
365/// The source tree 't' is cloned to not disturb its branch
366/// structure when retrieving information from it.
367void RooTreeDataStore::loadValues(const TTree *t, const RooFormulaVar* select, const char* /*rangeName*/, Int_t /*nStart*/, Int_t /*nStop*/)
368{
369 // Make our local copy of the tree, so we can safely loop through it.
370 // We need a custom deleter, because if we don't deregister the Tree from the directory
371 // of the original, it tears it down at destruction time!
372 auto deleter = [](TTree* tree){tree->SetDirectory(nullptr); delete tree;};
373 std::unique_ptr<TTree, decltype(deleter)> tClone(static_cast<TTree*>(t->Clone()), deleter);
374 tClone->SetDirectory(t->GetDirectory());
375
376 // Clone list of variables
377 RooArgSet sourceArgSet;
378 _varsww.snapshot(sourceArgSet, false);
379
380 // Check that we have the branches:
381 bool missingBranches = false;
382 for (const auto var : sourceArgSet) {
383 if (!tClone->GetBranch(var->GetName())) {
384 missingBranches = true;
385 coutE(InputArguments) << "Didn't find a branch in Tree '" << tClone->GetName() << "' to read variable '"
386 << var->GetName() << "' from."
387 << "\n\tNote: Name the RooFit variable the same as the branch." << std::endl;
388 }
389 }
390 if (missingBranches) {
391 coutE(InputArguments) << "Cannot import data from TTree '" << tClone->GetName()
392 << "' because some branches are missing !" << std::endl;
393 return;
394 }
395
396 // Attach args in cloned list to cloned source tree
397 for (const auto sourceArg : sourceArgSet) {
398 sourceArg->attachToTree(*tClone,_defTreeBufSize) ;
399 }
400
401 // Redirect formula servers to sourceArgSet
402 std::unique_ptr<RooFormulaVar> selectClone;
403 if (select) {
404 selectClone.reset( static_cast<RooFormulaVar*>(select->cloneTree()) );
405 selectClone->recursiveRedirectServers(sourceArgSet) ;
406 selectClone->setOperMode(RooAbsArg::ADirty,true) ;
407 }
408
409 // Loop over events in source tree
410 Int_t numInvalid(0) ;
411 const Long64_t nevent = tClone->GetEntries();
412 for(Long64_t i=0; i < nevent; ++i) {
413 const auto entryNumber = tClone->GetEntryNumber(i);
414 if (entryNumber<0) break;
415 tClone->GetEntry(entryNumber,1);
416
417 // Copy from source to destination
418 bool allOK(true) ;
419 for (unsigned int j=0; j < sourceArgSet.size(); ++j) {
420 auto destArg = _varsww[j];
421 const auto sourceArg = sourceArgSet[j];
422
423 destArg->copyCache(sourceArg) ;
424 sourceArg->copyCache(destArg) ;
425 if (!destArg->isValid()) {
426 numInvalid++ ;
427 allOK=false ;
428 if (numInvalid < 5) {
429 auto& log = coutI(DataHandling);
430 log << "RooTreeDataStore::loadValues(" << GetName() << ") Skipping event #" << i << " because " << destArg->GetName()
431 << " cannot accommodate the value ";
432 if(sourceArg->isCategory()) {
433 log << static_cast<RooAbsCategory*>(sourceArg)->getCurrentIndex();
434 } else {
435 log << static_cast<RooAbsReal*>(sourceArg)->getVal();
436 }
437 log << std::endl;
438 } else if (numInvalid == 5) {
439 coutI(DataHandling) << "RooTreeDataStore::loadValues(" << GetName() << ") Skipping ..." << std::endl;
440 }
441 break ;
442 }
443 }
444
445 // Does this event pass the cuts?
446 if (!allOK || (selectClone && selectClone->getVal()==0)) {
447 continue ;
448 }
449
450 fill() ;
451 }
452
453 if (numInvalid>0) {
454 coutW(DataHandling) << "RooTreeDataStore::loadValues(" << GetName() << ") Ignored " << numInvalid << " out-of-range events" << endl ;
455 }
456
457 SetTitle(t->GetTitle());
458}
459
460
461
462
463
464
465////////////////////////////////////////////////////////////////////////////////
466/// Load values from dataset 't' into this data collection, optionally
467/// selecting events using 'select' RooFormulaVar
468///
469
471 const char* rangeName, std::size_t nStart, std::size_t nStop)
472{
473 // Redirect formula servers to source data row
474 std::unique_ptr<RooFormulaVar> selectClone;
475 if (select) {
476 selectClone.reset( static_cast<RooFormulaVar*>(select->cloneTree()) );
477 selectClone->recursiveRedirectServers(*ads->get()) ;
478 selectClone->setOperMode(RooAbsArg::ADirty,true) ;
479 }
480
481 // Force RDS internal initialization
482 ads->get(0) ;
483
484 // Loop over events in source tree
485 const auto numEntr = static_cast<std::size_t>(ads->numEntries());
486 std::size_t nevent = nStop < numEntr ? nStop : numEntr;
487
488 auto TDS = dynamic_cast<const RooTreeDataStore*>(ads) ;
489 if (TDS) {
490 const_cast<RooTreeDataStore*>(TDS)->resetBuffers();
491 }
492
493 std::vector<std::string> ranges;
494 if (rangeName) {
495 ranges = ROOT::Split(rangeName, ",");
496 }
497
498 for (auto i=nStart; i < nevent ; ++i) {
499 ads->get(i) ;
500
501 // Does this event pass the cuts?
502 if (selectClone && selectClone->getVal()==0) {
503 continue ;
504 }
505
506
507 if (TDS) {
508 _varsww.assignValueOnly(TDS->_varsww) ;
509 } else {
510 _varsww.assignValueOnly(*ads->get()) ;
511 }
512
513 // Check that all copied values are valid
514 bool allValid = true;
515 for (const auto arg : _varsww) {
516 allValid = arg->isValid() && (ranges.empty() || std::any_of(ranges.begin(), ranges.end(),
517 [arg](const std::string& range){return arg->inRange(range.c_str());}) );
518 if (!allValid)
519 break ;
520 }
521
522 if (!allValid) {
523 continue ;
524 }
525
526 _cachedVars.assign(static_cast<RooTreeDataStore const*>(ads)->_cachedVars) ;
527 fill() ;
528 }
529
530 if (TDS) {
531 const_cast<RooTreeDataStore*>(TDS)->restoreAlternateBuffers();
532 }
533
534 SetTitle(ads->GetTitle());
535}
536
537
538////////////////////////////////////////////////////////////////////////////////
539/// Interface function to TTree::Fill
540
542{
543 return _tree->Fill() ;
544}
545
546
547
548////////////////////////////////////////////////////////////////////////////////
549/// Load the n-th data point (n='index') in memory
550/// and return a pointer to the internal RooArgSet
551/// holding its coordinates.
552
554{
555 checkInit() ;
556
557 Int_t ret = const_cast<RooTreeDataStore*>(this)->GetEntry(index, 1);
558
559 if(!ret) return nullptr;
560
561 if (_doDirtyProp) {
562 // Raise all dirty flags
563 for (auto var : _vars) {
564 var->setValueDirty(); // This triggers recalculation of all clients
565 }
566
567 for (auto var : _cachedVars) {
568 var->setValueDirty(); // This triggers recalculation of all clients, but doesn't recalculate self
569 var->clearValueDirty();
570 }
571 }
572
573 // Update current weight cache
574 if (_extWgtArray) {
575
576 // If external array is specified use that
581
582 } else if (_wgtVar) {
583
584 // Otherwise look for weight variable
585 _curWgt = _wgtVar->getVal() ;
586 _curWgtErrLo = _wgtVar->getAsymErrorLo() ;
587 _curWgtErrHi = _wgtVar->getAsymErrorHi() ;
588 _curWgtErr = _wgtVar->hasAsymError() ? ((_wgtVar->getAsymErrorHi() - _wgtVar->getAsymErrorLo())/2) : _wgtVar->getError() ;
589
590 } else {
591
592 // Otherwise return 1
593 _curWgt=1.0 ;
594 _curWgtErrLo = 0 ;
595 _curWgtErrHi = 0 ;
596 _curWgtErr = 0 ;
597
598 }
599
600 return &_vars;
601}
602
603
604////////////////////////////////////////////////////////////////////////////////
605/// Return the weight of the n-th data point (n='index') in memory
606
608{
609 return _curWgt ;
610}
611
612
613////////////////////////////////////////////////////////////////////////////////
614
616{
617 if (_extWgtArray) {
618
619 // We have a weight array, use that info
620
621 // Return symmetric error on current bin calculated either from Poisson statistics or from SumOfWeights
622 double lo = 0;
623 double hi = 0;
624 weightError(lo,hi,etype) ;
625 return (lo+hi)/2 ;
626
627 } else if (_wgtVar) {
628
629 // We have a weight variable, use that info
630 if (_wgtVar->hasAsymError()) {
631 return ( _wgtVar->getAsymErrorHi() - _wgtVar->getAsymErrorLo() ) / 2 ;
632 } else {
633 return _wgtVar->getError() ;
634 }
635
636 } else {
637
638 // We have no weights
639 return 0 ;
640
641 }
642}
643
644
645
646////////////////////////////////////////////////////////////////////////////////
647
648void RooTreeDataStore::weightError(double& lo, double& hi, RooAbsData::ErrorType etype) const
649{
650 if (_extWgtArray) {
651
652 // We have a weight array, use that info
653 switch (etype) {
654
655 case RooAbsData::Auto:
656 throw string(Form("RooDataHist::weightError(%s) error type Auto not allowed here",GetName())) ;
657 break ;
658
660 throw string(Form("RooDataHist::weightError(%s) error type Expected not allowed here",GetName())) ;
661 break ;
662
664 // Weight may be preset or precalculated
665 if (_curWgtErrLo>=0) {
666 lo = _curWgtErrLo ;
667 hi = _curWgtErrHi ;
668 return ;
669 }
670
671 // Otherwise Calculate poisson errors
672 double ym;
673 double yp;
675 lo = weight()-ym ;
676 hi = yp-weight() ;
677 return ;
678
680 lo = _curWgtErr ;
681 hi = _curWgtErr ;
682 return ;
683
684 case RooAbsData::None:
685 lo = 0 ;
686 hi = 0 ;
687 return ;
688 }
689
690 } else if (_wgtVar) {
691
692 // We have a weight variable, use that info
693 if (_wgtVar->hasAsymError()) {
694 hi = _wgtVar->getAsymErrorHi() ;
695 lo = _wgtVar->getAsymErrorLo() ;
696 } else {
697 hi = _wgtVar->getError() ;
698 lo = _wgtVar->getError() ;
699 }
700
701 } else {
702
703 // We are unweighted
704 lo=0 ;
705 hi=0 ;
706
707 }
708}
709
710
711////////////////////////////////////////////////////////////////////////////////
712/// Change name of internal observable named 'from' into 'to'
713
714bool RooTreeDataStore::changeObservableName(const char* from, const char* to)
715{
716 // Find observable to be changed
717 RooAbsArg* var = _vars.find(from) ;
718
719 // Check that we found it
720 if (!var) {
721 coutE(InputArguments) << "RooTreeDataStore::changeObservableName(" << GetName() << " no observable " << from << " in this dataset" << endl ;
722 return true ;
723 }
724
725 // Process name change
726 TString oldBranchName = var->cleanBranchName() ;
727 var->SetName(to) ;
728
729 // Change the branch name as well
730 if (_tree->GetBranch(oldBranchName.Data())) {
731
732 // Simple case varName = branchName
733 _tree->GetBranch(oldBranchName.Data())->SetName(var->cleanBranchName().Data()) ;
734
735 // Process any error branch if existing
736 if (_tree->GetBranch(Form("%s_err",oldBranchName.Data()))) {
737 _tree->GetBranch(Form("%s_err",oldBranchName.Data()))->SetName(Form("%s_err",var->cleanBranchName().Data())) ;
738 }
739 if (_tree->GetBranch(Form("%s_aerr_lo",oldBranchName.Data()))) {
740 _tree->GetBranch(Form("%s_aerr_lo",oldBranchName.Data()))->SetName(Form("%s_aerr_lo",var->cleanBranchName().Data())) ;
741 }
742 if (_tree->GetBranch(Form("%s_aerr_hi",oldBranchName.Data()))) {
743 _tree->GetBranch(Form("%s_aerr_hi",oldBranchName.Data()))->SetName(Form("%s_aerr_hi",var->cleanBranchName().Data())) ;
744 }
745
746 } else {
747
748 // Native category case branchNames = varName_idx and varName_lbl
749 if (_tree->GetBranch(Form("%s_idx",oldBranchName.Data()))) {
750 _tree->GetBranch(Form("%s_idx",oldBranchName.Data()))->SetName(Form("%s_idx",var->cleanBranchName().Data())) ;
751 }
752 if (_tree->GetBranch(Form("%s_lbl",oldBranchName.Data()))) {
753 _tree->GetBranch(Form("%s_lbl",oldBranchName.Data()))->SetName(Form("%s_lb",var->cleanBranchName().Data())) ;
754 }
755
756 }
757
758 return false ;
759}
760
761
762
763////////////////////////////////////////////////////////////////////////////////
764/// Add a new column to the data set which holds the pre-calculated values
765/// of 'newVar'. This operation is only meaningful if 'newVar' is a derived
766/// value.
767///
768/// The return value points to the added element holding 'newVar's value
769/// in the data collection. The element is always the corresponding fundamental
770/// type of 'newVar' (e.g. a RooRealVar if 'newVar' is a RooFormulaVar)
771///
772/// Note: This function is explicitly NOT intended as a speed optimization
773/// opportunity for the user. Components of complex PDFs that can be
774/// precalculated with the dataset are automatically identified as such
775/// and will be precalculated when fitting to a dataset
776///
777/// By forcibly precalculating functions with non-trivial Jacobians,
778/// or functions of multiple variables occurring in the data set,
779/// using addColumn(), you may alter the outcome of the fit.
780///
781/// Only in cases where such a modification of fit behaviour is intentional,
782/// this function should be used.
783
785{
786 checkInit() ;
787
788 // Create a fundamental object of the right type to hold newVar values
789 auto valHolder = std::unique_ptr<RooAbsArg>{newVar.createFundamental()}.release();
790 // Sanity check that the holder really is fundamental
791 if(!valHolder->isFundamental()) {
792 coutE(InputArguments) << GetName() << "::addColumn: holder argument is not fundamental: \""
793 << valHolder->GetName() << "\"" << endl;
794 return nullptr;
795 }
796
797 // WVE need to reset TTRee buffers to original datamembers here
798 resetBuffers() ;
799
800 // Clone variable and attach to cloned tree
801 RooAbsArg* newVarClone = newVar.cloneTree() ;
802 newVarClone->recursiveRedirectServers(_vars,false) ;
803
804 // Attach value place holder to this tree
805 ((RooAbsArg*)valHolder)->attachToTree(*_tree,_defTreeBufSize) ;
806 _vars.add(*valHolder) ;
807 _varsww.add(*valHolder) ;
808
809
810 // Fill values of placeholder
811 for (int i=0 ; i<GetEntries() ; i++) {
812 get(i) ;
813
814 newVarClone->syncCache(&_vars) ;
815 valHolder->copyCache(newVarClone) ;
816 valHolder->fillTreeBranch(*_tree) ;
817 }
818
819 // WVE need to restore TTRee buffers to previous values here
821
822 if (adjustRange) {
823// // Set range of valHolder to (just) bracket all values stored in the dataset
824// double vlo,vhi ;
825// RooRealVar* rrvVal = dynamic_cast<RooRealVar*>(valHolder) ;
826// if (rrvVal) {
827// getRange(*rrvVal,vlo,vhi,0.05) ;
828// rrvVal->setRange(vlo,vhi) ;
829// }
830 }
831
832
833
834 delete newVarClone ;
835 return valHolder ;
836}
837
838
839////////////////////////////////////////////////////////////////////////////////
840/// Merge columns of supplied data set(s) with this data set. All
841/// data sets must have equal number of entries. In case of
842/// duplicate columns the column of the last dataset in the list
843/// prevails
844
845RooAbsDataStore* RooTreeDataStore::merge(const RooArgSet& allVars, list<RooAbsDataStore*> dstoreList)
846{
847 RooTreeDataStore* mergedStore = new RooTreeDataStore("merged","merged",allVars) ;
848
849 Int_t nevt = dstoreList.front()->numEntries() ;
850 for (int i=0 ; i<nevt ; i++) {
851
852 // Cope data from self
853 mergedStore->_vars.assign(*get(i)) ;
854
855 // Copy variables from merge sets
856 for (list<RooAbsDataStore*>::iterator iter = dstoreList.begin() ; iter!=dstoreList.end() ; ++iter) {
857 const RooArgSet* partSet = (*iter)->get(i) ;
858 mergedStore->_vars.assign(*partSet) ;
859 }
860
861 mergedStore->fill() ;
862 }
863 return mergedStore ;
864}
865
866
867
868
869
870////////////////////////////////////////////////////////////////////////////////
871
873{
874 Int_t nevt = other.numEntries() ;
875 for (int i=0 ; i<nevt ; i++) {
876 _vars.assign(*other.get(i)) ;
877 if (_wgtVar) {
878 _wgtVar->setVal(other.weight()) ;
879 }
880
881 fill() ;
882 }
883}
884
885
886////////////////////////////////////////////////////////////////////////////////
887
889{
890 if (_wgtVar) {
891
892 double sum(0);
893 double carry(0);
894 Int_t nevt = numEntries() ;
895 for (int i=0 ; i<nevt ; i++) {
896 get(i) ;
897 // Kahan's algorithm for summing to avoid loss of precision
898 double y = _wgtVar->getVal() - carry;
899 double t = sum + y;
900 carry = (t - sum) - y;
901 sum = t;
902 }
903 return sum ;
904
905 } else if (_extWgtArray) {
906
907 double sum(0);
908 double carry(0);
909 Int_t nevt = numEntries() ;
910 for (int i=0 ; i<nevt ; i++) {
911 // Kahan's algorithm for summing to avoid loss of precision
912 double y = _extWgtArray[i] - carry;
913 double t = sum + y;
914 carry = (t - sum) - y;
915 sum = t;
916 }
917 return sum ;
918
919 } else {
920
921 return numEntries() ;
922
923 }
924}
925
926
927
928
929////////////////////////////////////////////////////////////////////////////////
930
932{
933 return _tree->GetEntries() ;
934}
935
936
937
938////////////////////////////////////////////////////////////////////////////////
939
941{
942 Reset() ;
943}
944
945
946
947////////////////////////////////////////////////////////////////////////////////
948/// Cache given RooAbsArgs with this tree: The tree is
949/// given direct write access of the args internal cache
950/// the args values is pre-calculated for all data points
951/// in this data collection. Upon a get() call, the
952/// internal cache of 'newVar' will be loaded with the
953/// precalculated value and it's dirty flag will be cleared.
954
955void RooTreeDataStore::cacheArgs(const RooAbsArg* owner, RooArgSet& newVarSet, const RooArgSet* nset, bool /*skipZeroWeights*/)
956{
957 checkInit() ;
958
959 _cacheOwner = owner ;
960
961 std::unique_ptr<RooArgSet> constExprVarSet{static_cast<RooArgSet*>(newVarSet.selectByAttrib("ConstantExpression",true))};
962
963 bool doTreeFill = (_cachedVars.empty()) ;
964
965 for (RooAbsArg * arg : *constExprVarSet) {
966 // Attach original newVar to this tree
967 arg->attachToTree(*_cacheTree,_defTreeBufSize) ;
968 //arg->recursiveRedirectServers(_vars) ;
969 _cachedVars.add(*arg) ;
970 }
971
972 // WVE need to reset TTRee buffers to original datamembers here
973 //resetBuffers() ;
974
975 // Refill regular and cached variables of current tree from clone
976 for (int i=0 ; i<GetEntries() ; i++) {
977 get(i) ;
978
979 // Evaluate the cached variables and store the results
980 for (RooAbsArg * arg : *constExprVarSet) {
981 arg->setValueDirty() ;
982 arg->syncCache(nset) ;
983 if (!doTreeFill) {
984 arg->fillTreeBranch(*_cacheTree) ;
985 }
986 }
987
988 if (doTreeFill) {
989 _cacheTree->Fill() ;
990 }
991 }
992
993 // WVE need to restore TTRee buffers to previous values here
994 //restoreAlternateBuffers() ;
995}
996
997
998
999
1000////////////////////////////////////////////////////////////////////////////////
1001/// Activate or deactivate the branch status of the TTree branch associated
1002/// with the given set of dataset observables
1003
1005{
1006 for (RooAbsArg * arg : set) {
1007 RooAbsArg* depArg = _vars.find(arg->GetName()) ;
1008 if (!depArg) {
1009 coutE(InputArguments) << "RooTreeDataStore::setArgStatus(" << GetName()
1010 << ") dataset doesn't contain variable " << arg->GetName() << endl ;
1011 continue ;
1012 }
1013 depArg->setTreeBranchStatus(*_tree,active) ;
1014 }
1015}
1016
1017
1018
1019////////////////////////////////////////////////////////////////////////////////
1020/// Remove tree with values of cached observables
1021/// and clear list of cached observables
1022
1024{
1025 // Empty list of cached functions
1026 _cachedVars.removeAll() ;
1027
1028 // Delete & recreate cache tree
1029 delete _cacheTree ;
1030 _cacheTree = nullptr ;
1031 createTree(makeTreeName().c_str(), GetTitle());
1032
1033 return ;
1034}
1035
1036
1037
1038
1039////////////////////////////////////////////////////////////////////////////////
1040
1042{
1043 _attachedBuffers.removeAll() ;
1044 for (const auto arg : _varsww) {
1045 RooAbsArg* extArg = extObs.find(arg->GetName()) ;
1046 if (extArg) {
1047 if (arg->getAttribute("StoreError")) {
1048 extArg->setAttribute("StoreError") ;
1049 }
1050 if (arg->getAttribute("StoreAsymError")) {
1051 extArg->setAttribute("StoreAsymError") ;
1052 }
1053 extArg->attachToTree(*_tree) ;
1054 _attachedBuffers.add(*extArg) ;
1055 }
1056 }
1057}
1058
1059
1060
1061////////////////////////////////////////////////////////////////////////////////
1062
1064{
1065 for(RooAbsArg * arg : _varsww) {
1066 arg->attachToTree(*_tree) ;
1067 }
1068}
1069
1070
1071
1072////////////////////////////////////////////////////////////////////////////////
1073
1075{
1076 for(RooAbsArg * arg : _attachedBuffers) {
1077 arg->attachToTree(*_tree) ;
1078 }
1079}
1080
1081
1082
1083////////////////////////////////////////////////////////////////////////////////
1084
1086{
1087 if (_defCtor) {
1088 const_cast<RooTreeDataStore*>(this)->initialize() ;
1089 _defCtor = false ;
1090 }
1091}
1092
1093
1094
1095
1096
1097////////////////////////////////////////////////////////////////////////////////
1098/// Interface function to TTree::GetEntries
1099
1101{
1102 return _tree->GetEntries() ;
1103}
1104
1105
1106////////////////////////////////////////////////////////////////////////////////
1107/// Interface function to TTree::Reset
1108
1110{
1111 _tree->Reset(option) ;
1112}
1113
1114
1115////////////////////////////////////////////////////////////////////////////////
1116/// Interface function to TTree::Fill
1117
1119{
1120 return _tree->Fill() ;
1121}
1122
1123
1124////////////////////////////////////////////////////////////////////////////////
1125/// Interface function to TTree::GetEntry
1126
1128{
1129 Int_t ret1 = _tree->GetEntry(entry,getall) ;
1130 if (!ret1) return 0 ;
1131 _cacheTree->GetEntry(entry,getall) ;
1132 return ret1 ;
1133}
1134
1135
1136////////////////////////////////////////////////////////////////////////////////
1137
1139{
1140 _tree->Draw(option) ;
1141}
1142
1143////////////////////////////////////////////////////////////////////////////////
1144/// Stream an object of class RooTreeDataStore.
1145
1147{
1148 if (R__b.IsReading()) {
1149 UInt_t R__s;
1150 UInt_t R__c;
1151 const Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
1152
1153 R__b.ReadClassBuffer(RooTreeDataStore::Class(), this, R__v, R__s, R__c);
1154
1155 if (!_tree) {
1156 // If the tree has not been deserialised automatically, it is time to load
1157 // it now.
1158 TFile* parent = dynamic_cast<TFile*>(R__b.GetParent());
1159 assert(parent);
1160 parent->GetObject(makeTreeName().c_str(), _tree);
1161 }
1162
1163 initialize();
1164
1165 } else {
1166
1167 TTree* tmpTree = _tree;
1168 auto parent = dynamic_cast<TDirectory*>(R__b.GetParent());
1169 if (_tree && parent) {
1170 // Large trees cannot be written because of the 1Gb I/O limitation.
1171 // Here, we take the tree away from our instance, write it, and continue
1172 // to write the rest of the class normally
1173 auto tmpDir = _tree->GetDirectory();
1174
1175 _tree->SetDirectory(parent);
1176 _tree->FlushBaskets(false);
1177 parent->WriteObject(_tree, makeTreeName().c_str());
1178 _tree->SetDirectory(tmpDir);
1179 _tree = nullptr;
1180 }
1181
1183
1184 _tree = tmpTree;
1185 }
1186}
1187
1188////////////////////////////////////////////////////////////////////////////////
1189/// Generate a name for the storage tree from the name and title of this instance.
1191 std::string title = GetTitle();
1192 std::replace(title.begin(), title.end(), ' ', '_');
1193 std::replace(title.begin(), title.end(), '-', '_');
1194 return std::string("RooTreeDataStore_") + GetName() + "_" + title;
1195}
1196
1197
1198////////////////////////////////////////////////////////////////////////////////
1199/// Get the weights of the events in the range [first, first+len).
1200/// This implementation will fill a vector with every event retrieved one by one
1201/// (even if the weight is constant). Then, it returns a span.
1202std::span<const double> RooTreeDataStore::getWeightBatch(std::size_t first, std::size_t len) const {
1203
1204 if (_extWgtArray) {
1205 return {_extWgtArray + first, len};
1206 }
1207
1208 if (!_weightBuffer) {
1209 _weightBuffer = std::make_unique<std::vector<double>>();
1210 _weightBuffer->reserve(len);
1211
1212 for (std::size_t i = 0; i < GetEntries(); ++i) {
1213 _weightBuffer->push_back(weight(i));
1214 }
1215 }
1216
1217 return {_weightBuffer->data() + first, len};
1218}
true
Register systematic variations for multiple existing columns using auto-generated tags.
#define coutI(a)
#define coutW(a)
#define coutE(a)
int Int_t
Definition RtypesCore.h:45
short Version_t
Definition RtypesCore.h:65
unsigned int UInt_t
Definition RtypesCore.h:46
double Stat_t
Definition RtypesCore.h:86
long long Long64_t
Definition RtypesCore.h:80
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:377
return
Invalidate stored TCling state for declarations included in transaction ‘T’.
Definition TCling.cxx:6896
#define gDirectory
Definition TDirectory.h:384
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
char name[80]
Definition TGX11.cxx:110
Int_t i
#define hi
#define gROOT
Definition TROOT.h:414
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2489
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
bool recursiveRedirectServers(const RooAbsCollection &newServerList, bool mustReplaceAll=false, bool nameChange=false, bool recurseInNewSet=true)
Recursively replace all servers with the new servers in newSet.
virtual void syncCache(const RooArgSet *nset=nullptr)=0
void SetName(const char *name) override
Set the name of the TNamed.
virtual RooFit::OwningPtr< RooAbsArg > createFundamental(const char *newname=nullptr) const =0
Create a fundamental-type object that stores our type of value.
virtual void attachToTree(TTree &t, Int_t bufSize=32000)=0
Overloadable function for derived classes to implement attachment as branch to a TTree.
virtual void setTreeBranchStatus(TTree &t, bool active)=0
virtual RooAbsArg * cloneTree(const char *newname=nullptr) const
Clone tree expression of objects.
TString cleanBranchName() const
Construct a mangled name from the actual name that is free of any math symbols that might be interpre...
void setAttribute(const Text_t *name, bool value=true)
Set (default) or clear a named boolean attribute of this object.
RooAbsCollection * selectByAttrib(const char *name, bool value) const
Create a subset of the current collection, consisting only of those elements with the specified attri...
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
Storage_t const & get() const
Const access to the underlying stl container.
void assign(const RooAbsCollection &other) const
Sets the value, cache and constant attribute of any argument in our set that also appears in the othe...
Storage_t::size_type size() const
RooAbsArg * find(const char *name) const
Find object with given name in list.
virtual const RooArgSet * get(Int_t index) const =0
bool _doDirtyProp
Switch do (de)activate dirty state propagation when loading a data point.
virtual double weight() const =0
virtual Int_t numEntries() const =0
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
A RooFormulaVar is a generic implementation of a real-valued object, which takes a RooArgList of serv...
static const RooHistError & instance()
Return a reference to a singleton object that is created the first time this method is called.
bool getPoissonInterval(Int_t n, double &mu1, double &mu2, double nSigma=1) const
Return a confidence interval for the expected number of events given n observed (unweighted) events.
Variable that can be changed from the outside.
Definition RooRealVar.h:37
The RooStringView is a wrapper around a C-style string that can also be constructed from a std::strin...
const char * c_str() const
TTree-backed data storage.
void initialize()
One-time initialization common to all constructor forms.
double _curWgtErr
Weight of current event.
double weightError(RooAbsData::ErrorType etype=RooAbsData::Poisson) const override
void resetBuffers() override
double _curWgt
Buffer for weights in case a batch of values is requested.
void Draw(Option_t *option="") override
Default Draw method for all objects.
void attachCache(const RooAbsArg *newOwner, const RooArgSet &cachedVars) override
Initialize cache of dataset: attach variables of cache ArgSet to the corresponding TTree branches.
double _curWgtErrHi
Weight of current event.
static TClass * Class()
Int_t numEntries() const override
std::string makeTreeName() const
Generate a name for the storage tree from the name and title of this instance.
RooArgSet varsNoWeight(const RooArgSet &allVars, const char *wgtName=nullptr)
Utility function for constructors Return RooArgSet that is copy of allVars minus variable matching wg...
~RooTreeDataStore() override
Destructor.
void createTree(RooStringView name, RooStringView title)
Create TTree object that lives in memory, independent of current location of gDirectory.
const double * _extWgtErrHiArray
! External weight array - high error
Stat_t GetEntries() const
Interface function to TTree::GetEntries.
void attachBuffers(const RooArgSet &extObs) override
Int_t GetEntry(Int_t entry=0, Int_t getall=0)
Interface function to TTree::GetEntry.
void reset() override
RooAbsDataStore * merge(const RooArgSet &allvars, std::list< RooAbsDataStore * > dstoreList) override
Merge columns of supplied data set(s) with this data set.
static Int_t _defTreeBufSize
RooArgSet _attachedBuffers
! Currently attached buffers (if different from _varsww)
Int_t fill() override
Interface function to TTree::Fill.
double sumEntries() const override
std::unique_ptr< RooAbsDataStore > reduce(RooStringView name, RooStringView title, const RooArgSet &vars, const RooFormulaVar *cutVar, const char *cutRange, std::size_t nStart, std::size_t nStop) override
bool _defCtor
Object owning cache contents.
RooAbsArg * addColumn(RooAbsArg &var, bool adjustRange=true) override
Add a new column to the data set which holds the pre-calculated values of 'newVar'.
double weight() const override
Return the weight of the n-th data point (n='index') in memory.
void Reset(Option_t *option=nullptr)
Interface function to TTree::Reset.
void loadValues(const TTree *t, const RooFormulaVar *select=nullptr, const char *rangeName=nullptr, Int_t nStart=0, Int_t nStop=2000000000)
Load values from tree 't' into this data collection, optionally selecting events using the RooFormula...
void append(RooAbsDataStore &other) override
std::span< const double > getWeightBatch(std::size_t first, std::size_t len) const override
Get the weights of the events in the range [first, first+len).
const double * _extWgtErrLoArray
! External weight array - low error
void checkInit() const override
std::unique_ptr< std::vector< double > > _weightBuffer
Int_t Fill()
Interface function to TTree::Fill.
const double * _extSumW2Array
! External sum of weights array
void Streamer(TBuffer &) override
Stream an object of class RooTreeDataStore.
RooRealVar * weightVar(const RooArgSet &allVars, const char *wgtName=nullptr)
Utility function for constructors Return pointer to weight variable if it is defined.
const double * _extWgtArray
! External weight array
double _curWgtErrLo
Weight of current event.
bool changeObservableName(const char *from, const char *to) override
Change name of internal observable named 'from' into 'to'.
void resetCache() override
Remove tree with values of cached observables and clear list of cached observables.
void setArgStatus(const RooArgSet &set, bool active) override
Activate or deactivate the branch status of the TTree branch associated with the given set of dataset...
void cacheArgs(const RooAbsArg *owner, RooArgSet &varSet, const RooArgSet *nset=nullptr, bool skipZeroWeights=false) override
Cache given RooAbsArgs with this tree: The tree is given direct write access of the args internal cac...
virtual const RooArgSet * get() const
const RooAbsArg * _cacheOwner
TTree holding the cached function values.
RooArgSet _varsww
Was object constructed with default ctor?
Buffer base class used for serializing objects.
Definition TBuffer.h:43
virtual Version_t ReadVersion(UInt_t *start=nullptr, UInt_t *bcnt=nullptr, const TClass *cl=nullptr)=0
TObject * GetParent() const
Return pointer to parent of this buffer.
Definition TBuffer.cxx:262
virtual Int_t ReadClassBuffer(const TClass *cl, void *pointer, const TClass *onfile_class=nullptr)=0
Bool_t IsReading() const
Definition TBuffer.h:86
virtual Int_t WriteClassBuffer(const TClass *cl, void *pointer)=0
Describe directory structure in memory.
Definition TDirectory.h:45
void GetObject(const char *namecycle, T *&ptr)
Get an object with proper type checking.
Definition TDirectory.h:212
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:53
TObject * Clone(const char *newname="") const override
Make a clone of an object using the Streamer facility.
Definition TNamed.cxx:74
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:164
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:62
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition TObject.h:64
Basic string class.
Definition TString.h:139
const char * Data() const
Definition TString.h:376
TString & Append(const char *cs)
Definition TString.h:572
A TTree represents a columnar dataset.
Definition TTree.h:79
TDirectory * GetDirectory() const
Definition TTree.h:465
virtual void SetDirectory(TDirectory *dir)
Change the tree's directory.
Definition TTree.cxx:8956
STL class.
Double_t y[n]
Definition legend1.C:17
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2345