Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooDataSet.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 RooDataSet.cxx
19 \class RooDataSet
20 \ingroup Roofitcore
21 
22 RooDataSet is a container class to hold unbinned data. Each data point
23 in N-dimensional space is represented by a RooArgSet of RooRealVar, RooCategory
24 or RooStringVar objects.
25 
26 There are two storage backends:
27 - RooVectorDataStore (default): std::vectors in memory. They are fast, but they
28 cannot be serialised if the dataset exceeds a size of 1 Gb
29 - RooTreeDataStore: Uses a TTree, which can be file backed if a file is opened
30 before creating the dataset. This significantly reduces the memory pressure, as the
31 baskets of the tree can be written to a file, and only the basket that's currently
32 being read stays in RAM.
33  - Enable tree-backed storage similar to this:
34  ```
35  TFile outputFile("filename.root", "RECREATE");
36  RooAbsData::setDefaultStorageType(RooAbsData::Tree);
37  RooDataSet mydata(...);
38  ```
39  - Or convert an existing memory-backed data storage:
40  ```
41  RooDataSet mydata(...);
42 
43  TFile outputFile("filename.root", "RECREATE");
44  mydata.convertToTreeStore();
45  ```
46 
47 For the inverse conversion, see `RooAbsData::convertToVectorStore()`.
48 
49 **/
50 
51 #include "RooFit.h"
52 
53 #include "Riostream.h"
54 #include "Riostream.h"
55 #include <fstream>
56 #include "TTree.h"
57 #include "TH2.h"
58 #include "TDirectory.h"
59 #include "RooDataSet.h"
60 #include "RooPlot.h"
61 #include "RooAbsReal.h"
62 #include "Roo1DTable.h"
63 #include "RooCategory.h"
64 #include "RooFormulaVar.h"
65 #include "RooArgList.h"
66 #include "RooAbsRealLValue.h"
67 #include "RooRealVar.h"
68 #include "RooDataHist.h"
69 #include "RooMsgService.h"
70 #include "RooCmdConfig.h"
71 #include "RooHist.h"
72 #include "TROOT.h"
73 #include "TFile.h"
74 #include "RooTreeDataStore.h"
75 #include "RooVectorDataStore.h"
76 #include "RooCompositeDataStore.h"
77 #include "RooTreeData.h"
78 #include "RooSentinel.h"
79 #include "RooTrace.h"
80 
81 #if (__GNUC__==3&&__GNUC_MINOR__==2&&__GNUC_PATCHLEVEL__==3)
82 char* operator+( streampos&, char* );
83 #endif
84 
85 using namespace std;
86 
87 ClassImp(RooDataSet);
88 
89 #ifndef USEMEMPOOLFORDATASET
90 void RooDataSet::cleanup() {}
91 #else
92 
93 #include "MemPoolForRooSets.h"
94 
95 RooDataSet::MemPool* RooDataSet::memPool() {
96  RooSentinel::activate();
97  static auto * memPool = new RooDataSet::MemPool();
98  return memPool;
99 }
100 
101 void RooDataSet::cleanup() {
102  auto pool = memPool();
103  pool->teardown();
104 
105  //The pool will have to leak if it's not empty at this point.
106  if (pool->empty())
107  delete pool;
108 }
109 
110 
111 ////////////////////////////////////////////////////////////////////////////////
112 /// Overloaded new operator guarantees that all RooDataSets allocated with new
113 /// have a unique address, a property that is exploited in several places
114 /// in roofit to quickly index contents on normalization set pointers.
115 /// The memory pool only allocates space for the class itself. The elements
116 /// stored in the set are stored outside the pool.
117 
118 void* RooDataSet::operator new (size_t bytes)
119 {
120  //This will fail if a derived class uses this operator
121  assert(sizeof(RooDataSet) == bytes);
122 
123  return memPool()->allocate(bytes);
124 }
125 
126 
127 
128 ////////////////////////////////////////////////////////////////////////////////
129 /// Memory is owned by pool, we need to do nothing to release it
130 
131 void RooDataSet::operator delete (void* ptr)
132 {
133  // Decrease use count in pool that ptr is on
134  if (memPool()->deallocate(ptr))
135  return;
136 
137  std::cerr << __func__ << " " << ptr << " is not in any of the pools." << std::endl;
138 
139  // Not part of any pool; use global op delete:
140  ::operator delete(ptr);
141 }
142 
143 #endif
144 
145 
146 ////////////////////////////////////////////////////////////////////////////////
147 /// Default constructor for persistence
148 
149 RooDataSet::RooDataSet() : _wgtVar(0)
150 {
151  TRACE_CREATE
152 }
153 
154 
155 
156 
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 /// Construct an unbinned dataset from a RooArgSet defining the dimensions of the data space. Optionally, data
160 /// can be imported at the time of construction.
161 ///
162 /// <table>
163 /// <tr><th> %RooCmdArg <th> Effect
164 /// <tr><td> Import(TTree*) <td> Import contents of given TTree. Only braches of the TTree that have names
165 /// corresponding to those of the RooAbsArgs that define the RooDataSet are
166 /// imported.
167 /// <tr><td> ImportFromFile(const char* fileName, const char* treeName) <td> Import tree with given name from file with given name.
168 /// <tr><td> Import(RooDataSet&)
169 /// <td> Import contents of given RooDataSet. Only observables that are common with the definition of this dataset will be imported
170 /// <tr><td> Index(RooCategory&) <td> Prepare import of datasets into a N+1 dimensional RooDataSet
171 /// where the extra discrete dimension labels the source of the imported histogram.
172 /// <tr><td> Import(const char*, RooDataSet&)
173 /// <td> Import a dataset to be associated with the given state name of the index category
174 /// specified in Index(). If the given state name is not yet defined in the index
175 /// category it will be added on the fly. The import command can be specified multiple times.
176 /// <tr><td> Link(const char*, RooDataSet&) <td> Link contents of supplied RooDataSet to this dataset for given index category state name.
177 /// In this mode, no data is copied and the linked dataset must be remain live for the duration
178 /// of this dataset. Note that link is active for both reading and writing, so modifications
179 /// to the aggregate dataset will also modify its components. Link() and Import() are mutually exclusive.
180 /// <tr><td> OwnLinked() <td> Take ownership of all linked datasets
181 /// <tr><td> Import(map<string,RooDataSet*>&) <td> As above, but allows specification of many imports in a single operation
182 /// <tr><td> Link(map<string,RooDataSet*>&) <td> As above, but allows specification of many links in a single operation
183 /// <tr><td> Cut(const char*) <br>
184 /// Cut(RooFormulaVar&)
185 /// <td> Apply the given cut specification when importing data
186 /// <tr><td> CutRange(const char*) <td> Only accept events in the observable range with the given name
187 /// <tr><td> WeightVar(const char*) <br>
188 /// WeightVar(const RooAbsArg&)
189 /// <td> Interpret the given variable as event weight rather than as observable
190 /// <tr><td> StoreError(const RooArgSet&) <td> Store symmetric error along with value for given subset of observables
191 /// <tr><td> StoreAsymError(const RooArgSet&) <td> Store asymmetric error along with value for given subset of observables
192 /// </table>
193 ///
194 
195 RooDataSet::RooDataSet(const char* name, const char* title, const RooArgSet& vars, const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3,
196  const RooCmdArg& arg4,const RooCmdArg& arg5,const RooCmdArg& arg6,const RooCmdArg& arg7,const RooCmdArg& arg8) :
197  RooAbsData(name,title,RooArgSet(vars,(RooAbsArg*)RooCmdConfig::decodeObjOnTheFly("RooDataSet::RooDataSet", "IndexCat",0,0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)))
198 {
199  // Define configuration for this method
200  RooCmdConfig pc(Form("RooDataSet::ctor(%s)",GetName())) ;
201  pc.defineInt("ownLinked","OwnLinked",0) ;
202  pc.defineObject("impTree","ImportTree",0) ;
203  pc.defineObject("impData","ImportData",0) ;
204  pc.defineObject("indexCat","IndexCat",0) ;
205  pc.defineObject("impSliceData","ImportDataSlice",0,0,kTRUE) ; // array
206  pc.defineString("impSliceState","ImportDataSlice",0,"",kTRUE) ; // array
207  pc.defineObject("lnkSliceData","LinkDataSlice",0,0,kTRUE) ; // array
208  pc.defineString("lnkSliceState","LinkDataSlice",0,"",kTRUE) ; // array
209  pc.defineString("cutSpec","CutSpec",0,"") ;
210  pc.defineObject("cutVar","CutVar",0) ;
211  pc.defineString("cutRange","CutRange",0,"") ;
212  pc.defineString("wgtVarName","WeightVarName",0,"") ;
213  pc.defineInt("newWeight1","WeightVarName",0,0) ;
214  pc.defineString("fname","ImportFromFile",0,"") ;
215  pc.defineString("tname","ImportFromFile",1,"") ;
216  pc.defineObject("wgtVar","WeightVar",0) ;
217  pc.defineInt("newWeight2","WeightVar",0,0) ;
218  pc.defineObject("dummy1","ImportDataSliceMany",0) ;
219  pc.defineObject("dummy2","LinkDataSliceMany",0) ;
220  pc.defineSet("errorSet","StoreError",0) ;
221  pc.defineSet("asymErrSet","StoreAsymError",0) ;
222  pc.defineMutex("ImportTree","ImportData","ImportDataSlice","LinkDataSlice","ImportFromFile") ;
223  pc.defineMutex("CutSpec","CutVar") ;
224  pc.defineMutex("WeightVarName","WeightVar") ;
225  pc.defineDependency("ImportDataSlice","IndexCat") ;
226  pc.defineDependency("LinkDataSlice","IndexCat") ;
227  pc.defineDependency("OwnLinked","LinkDataSlice") ;
228 
229 
230  RooLinkedList l ;
231  l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
232  l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
233  l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
234  l.Add((TObject*)&arg7) ; l.Add((TObject*)&arg8) ;
235 
236  // Process & check varargs
237  pc.process(l) ;
238  if (!pc.ok(kTRUE)) {
239  assert(0) ;
240  return ;
241  }
242 
243  // Extract relevant objects
244  TTree* impTree = static_cast<TTree*>(pc.getObject("impTree")) ;
245  RooDataSet* impData = static_cast<RooDataSet*>(pc.getObject("impData")) ;
246  RooFormulaVar* cutVar = static_cast<RooFormulaVar*>(pc.getObject("cutVar")) ;
247  const char* cutSpec = pc.getString("cutSpec","",kTRUE) ;
248  const char* cutRange = pc.getString("cutRange","",kTRUE) ;
249  const char* wgtVarName = pc.getString("wgtVarName","",kTRUE) ;
250  RooRealVar* wgtVar = static_cast<RooRealVar*>(pc.getObject("wgtVar")) ;
251  const char* impSliceNames = pc.getString("impSliceState","",kTRUE) ;
252  const RooLinkedList& impSliceData = pc.getObjectList("impSliceData") ;
253  const char* lnkSliceNames = pc.getString("lnkSliceState","",kTRUE) ;
254  const RooLinkedList& lnkSliceData = pc.getObjectList("lnkSliceData") ;
255  RooCategory* indexCat = static_cast<RooCategory*>(pc.getObject("indexCat")) ;
256  RooArgSet* errorSet = pc.getSet("errorSet") ;
257  RooArgSet* asymErrorSet = pc.getSet("asymErrSet") ;
258  const char* fname = pc.getString("fname") ;
259  const char* tname = pc.getString("tname") ;
260  Int_t ownLinked = pc.getInt("ownLinked") ;
261  Int_t newWeight = pc.getInt("newWeight1") + pc.getInt("newWeight2") ;
262 
263  // Case 1 --- Link multiple dataset as slices
264  if (lnkSliceNames) {
265 
266  // Make import mapping if index category is specified
267  map<string,RooAbsData*> hmap ;
268  if (indexCat) {
269  char tmp[64000];
270  strlcpy(tmp, lnkSliceNames, 64000);
271  char *token = strtok(tmp, ",");
272  TIterator *hiter = lnkSliceData.MakeIterator();
273  while (token) {
274  hmap[token] = (RooAbsData *)hiter->Next();
275  token = strtok(0, ",");
276  }
277  delete hiter ;
278  }
279 
280  // Lookup name of weight variable if it was specified by object reference
281  if (wgtVar) {
282  // coverity[UNUSED_VALUE]
283  wgtVarName = wgtVar->GetName() ;
284  }
285 
286  appendToDir(this,kTRUE) ;
287 
288  // Initialize RooDataSet with optional weight variable
289  initialize(0) ;
290 
291  map<string,RooAbsDataStore*> storeMap ;
292  RooCategory* icat = (RooCategory*) (indexCat ? _vars.find(indexCat->GetName()) : 0 ) ;
293  if (!icat) {
294  throw std::string("RooDataSet::RooDataSet() ERROR in constructor, cannot find index category") ;
295  }
296  for (map<string,RooAbsData*>::iterator hiter = hmap.begin() ; hiter!=hmap.end() ; ++hiter) {
297  // Define state labels in index category (both in provided indexCat and in internal copy in dataset)
298  if (indexCat && !indexCat->lookupType(hiter->first.c_str())) {
299  indexCat->defineType(hiter->first.c_str()) ;
300  coutI(InputArguments) << "RooDataSet::ctor(" << GetName() << ") defining state \"" << hiter->first << "\" in index category " << indexCat->GetName() << endl ;
301  }
302  if (icat && !icat->lookupType(hiter->first.c_str())) {
303  icat->defineType(hiter->first.c_str()) ;
304  }
305  icat->setLabel(hiter->first.c_str()) ;
306  storeMap[icat->getLabel()]=hiter->second->store() ;
307 
308  // Take ownership of slice if requested
309  if (ownLinked) {
310  addOwnedComponent(hiter->first.c_str(),*hiter->second) ;
311  }
312  }
313 
314  // Create composite datastore
315  _dstore = new RooCompositeDataStore(name,title,_vars,*icat,storeMap) ;
316 
317  } else {
318 
319  if (wgtVar) {
320  wgtVarName = wgtVar->GetName() ;
321  }
322 
323  // Clone weight variable of imported dataset if we are not weighted
324  if (!wgtVar && !wgtVarName && impData && impData->_wgtVar) {
325  _wgtVar = (RooRealVar*) impData->_wgtVar->createFundamental() ;
326  _vars.addOwned(*_wgtVar) ;
327  wgtVarName = _wgtVar->GetName() ;
328  }
329 
330  // Create empty datastore
331  RooTreeDataStore* tstore(0) ;
332  RooVectorDataStore* vstore(0) ;
333 
334  if (defaultStorageType==Tree) {
335  tstore = new RooTreeDataStore(name,title,_vars,wgtVarName) ;
336  _dstore = tstore ;
337  } else if (defaultStorageType==Vector) {
338  if (wgtVarName && newWeight) {
339  RooAbsArg* wgttmp = _vars.find(wgtVarName) ;
340  if (wgttmp) {
341  wgttmp->setAttribute("NewWeight") ;
342  }
343  }
344  vstore = new RooVectorDataStore(name,title,_vars,wgtVarName) ;
345  _dstore = vstore ;
346  } else {
347  _dstore = 0 ;
348  }
349 
350 
351  // Make import mapping if index category is specified
352  map<string,RooDataSet*> hmap ;
353  if (indexCat) {
354  char tmp[100000] ;
355  strlcpy(tmp,impSliceNames,100000) ;
356  char* token = strtok(tmp,",") ;
357  TIterator* hiter = impSliceData.MakeIterator() ;
358  while(token) {
359  hmap[token] = (RooDataSet*) hiter->Next() ;
360  token = strtok(0,",") ;
361  }
362  delete hiter ;
363  }
364 
365  // process StoreError requests
366  if (errorSet) {
367  RooArgSet* intErrorSet = (RooArgSet*) _vars.selectCommon(*errorSet) ;
368  intErrorSet->setAttribAll("StoreError") ;
369  TIterator* iter = intErrorSet->createIterator() ;
370  RooAbsArg* arg ;
371  while((arg=(RooAbsArg*)iter->Next())) {
372  arg->attachToStore(*_dstore) ;
373  }
374  delete iter ;
375  delete intErrorSet ;
376  }
377  if (asymErrorSet) {
378  RooArgSet* intAsymErrorSet = (RooArgSet*) _vars.selectCommon(*asymErrorSet) ;
379  intAsymErrorSet->setAttribAll("StoreAsymError") ;
380  TIterator* iter = intAsymErrorSet->createIterator() ;
381  RooAbsArg* arg ;
382  while((arg=(RooAbsArg*)iter->Next())) {
383  arg->attachToStore(*_dstore) ;
384  }
385  delete iter ;
386  delete intAsymErrorSet ;
387  }
388 
389  // Lookup name of weight variable if it was specified by object reference
390  if (wgtVar) {
391  wgtVarName = wgtVar->GetName() ;
392  }
393 
394 
395  appendToDir(this,kTRUE) ;
396 
397  // Initialize RooDataSet with optional weight variable
398  if (wgtVarName && *wgtVarName) {
399  // Use the supplied weight column
400  initialize(wgtVarName) ;
401 
402  } else {
403  if (impData && impData->_wgtVar && vars.find(impData->_wgtVar->GetName())) {
404 
405  // Use the weight column of the source data set
406  initialize(impData->_wgtVar->GetName()) ;
407 
408  } else if (indexCat) {
409 
410  RooDataSet* firstDS = hmap.begin()->second ;
411  if (firstDS->_wgtVar && vars.find(firstDS->_wgtVar->GetName())) {
412  initialize(firstDS->_wgtVar->GetName()) ;
413  } else {
414  initialize(0) ;
415  }
416  } else {
417  initialize(0) ;
418  }
419  }
420 
421  // Import one or more datasets with a cut specification
422  if (cutSpec && *cutSpec) {
423 
424  // Create a RooFormulaVar cut from given cut expression
425  if (indexCat) {
426 
427  // Case 2a --- Import multiple RooDataSets as slices with cutspec
428  RooCategory* icat = (RooCategory*) _vars.find(indexCat->GetName()) ;
429  for (map<string,RooDataSet*>::iterator hiter = hmap.begin() ; hiter!=hmap.end() ; ++hiter) {
430  // Define state labels in index category (both in provided indexCat and in internal copy in dataset)
431  if (!indexCat->lookupType(hiter->first.c_str())) {
432  indexCat->defineType(hiter->first.c_str()) ;
433  coutI(InputArguments) << "RooDataSet::ctor(" << GetName() << ") defining state \"" << hiter->first << "\" in index category " << indexCat->GetName() << endl ;
434  }
435  if (!icat->lookupType(hiter->first.c_str())) {
436  icat->defineType(hiter->first.c_str()) ;
437  }
438  icat->setLabel(hiter->first.c_str()) ;
439 
440  RooFormulaVar cutVarTmp(cutSpec,cutSpec,hiter->second->_vars) ;
441  _dstore->loadValues(hiter->second->store(),&cutVarTmp,cutRange) ;
442  }
443 
444  } else if (impData) {
445 
446  // Case 3a --- Import RooDataSet with cutspec
447  RooFormulaVar cutVarTmp(cutSpec,cutSpec,impData->_vars) ;
448  _dstore->loadValues(impData->store(),&cutVarTmp,cutRange);
449  } else if (impTree) {
450 
451  // Case 4a --- Import TTree from memory with cutspec
452  RooFormulaVar cutVarTmp(cutSpec,cutSpec,_vars) ;
453  if (tstore) {
454  tstore->loadValues(impTree,&cutVarTmp,cutRange);
455  } else {
456  RooTreeDataStore tmpstore(name,title,_vars,wgtVarName) ;
457  tmpstore.loadValues(impTree,&cutVarTmp,cutRange) ;
458  _dstore->append(tmpstore) ;
459  }
460  } else if (fname && strlen(fname)) {
461 
462  // Case 5a --- Import TTree from file with cutspec
463  TFile *f = TFile::Open(fname) ;
464  if (!f) {
465  coutE(InputArguments) << "RooDataSet::ctor(" << GetName() << ") ERROR file '" << fname << "' cannot be opened or does not exist" << endl ;
466  throw string(Form("RooDataSet::ctor(%s) ERROR file %s cannot be opened or does not exist",GetName(),fname)) ;
467  }
468  TTree* t = dynamic_cast<TTree*>(f->Get(tname)) ;
469  if (!t) {
470  coutE(InputArguments) << "RooDataSet::ctor(" << GetName() << ") ERROR file '" << fname << "' does not contain a TTree named '" << tname << "'" << endl ;
471  throw string(Form("RooDataSet::ctor(%s) ERROR file %s does not contain a TTree named %s",GetName(),fname,tname)) ;
472  }
473  RooFormulaVar cutVarTmp(cutSpec,cutSpec,_vars) ;
474  if (tstore) {
475  tstore->loadValues(t,&cutVarTmp,cutRange);
476  } else {
477  RooTreeDataStore tmpstore(name,title,_vars,wgtVarName) ;
478  tmpstore.loadValues(t,&cutVarTmp,cutRange) ;
479  _dstore->append(tmpstore) ;
480  }
481  f->Close() ;
482 
483  }
484 
485  // Import one or more datasets with a cut formula
486  } else if (cutVar) {
487 
488  if (indexCat) {
489 
490  // Case 2b --- Import multiple RooDataSets as slices with cutvar
491 
492  RooCategory* icat = (RooCategory*) _vars.find(indexCat->GetName()) ;
493  for (map<string,RooDataSet*>::iterator hiter = hmap.begin() ; hiter!=hmap.end() ; ++hiter) {
494  // Define state labels in index category (both in provided indexCat and in internal copy in dataset)
495  if (!indexCat->lookupType(hiter->first.c_str())) {
496  indexCat->defineType(hiter->first.c_str()) ;
497  coutI(InputArguments) << "RooDataSet::ctor(" << GetName() << ") defining state \"" << hiter->first << "\" in index category " << indexCat->GetName() << endl ;
498  }
499  if (!icat->lookupType(hiter->first.c_str())) {
500  icat->defineType(hiter->first.c_str()) ;
501  }
502  icat->setLabel(hiter->first.c_str()) ;
503  _dstore->loadValues(hiter->second->store(),cutVar,cutRange) ;
504  }
505 
506 
507  } else if (impData) {
508  // Case 3b --- Import RooDataSet with cutvar
509  _dstore->loadValues(impData->store(),cutVar,cutRange);
510  } else if (impTree) {
511  // Case 4b --- Import TTree from memory with cutvar
512  if (tstore) {
513  tstore->loadValues(impTree,cutVar,cutRange);
514  } else {
515  RooTreeDataStore tmpstore(name,title,_vars,wgtVarName) ;
516  tmpstore.loadValues(impTree,cutVar,cutRange) ;
517  _dstore->append(tmpstore) ;
518  }
519  } else if (fname && strlen(fname)) {
520  // Case 5b --- Import TTree from file with cutvar
521  TFile *f = TFile::Open(fname) ;
522  if (!f) {
523  coutE(InputArguments) << "RooDataSet::ctor(" << GetName() << ") ERROR file '" << fname << "' cannot be opened or does not exist" << endl ;
524  throw string(Form("RooDataSet::ctor(%s) ERROR file %s cannot be opened or does not exist",GetName(),fname)) ;
525  }
526  TTree* t = dynamic_cast<TTree*>(f->Get(tname)) ;
527  if (!t) {
528  coutE(InputArguments) << "RooDataSet::ctor(" << GetName() << ") ERROR file '" << fname << "' does not contain a TTree named '" << tname << "'" << endl ;
529  throw string(Form("RooDataSet::ctor(%s) ERROR file %s does not contain a TTree named %s",GetName(),fname,tname)) ;
530  }
531  if (tstore) {
532  tstore->loadValues(t,cutVar,cutRange);
533  } else {
534  RooTreeDataStore tmpstore(name,title,_vars,wgtVarName) ;
535  tmpstore.loadValues(t,cutVar,cutRange) ;
536  _dstore->append(tmpstore) ;
537  }
538 
539  f->Close() ;
540  }
541 
542  // Import one or more datasets without cuts
543  } else {
544 
545  if (indexCat) {
546 
547  RooCategory* icat = (RooCategory*) _vars.find(indexCat->GetName()) ;
548  for (map<string,RooDataSet*>::iterator hiter = hmap.begin() ; hiter!=hmap.end() ; ++hiter) {
549  // Define state labels in index category (both in provided indexCat and in internal copy in dataset)
550  if (!indexCat->lookupType(hiter->first.c_str())) {
551  indexCat->defineType(hiter->first.c_str()) ;
552  coutI(InputArguments) << "RooDataSet::ctor(" << GetName() << ") defining state \"" << hiter->first << "\" in index category " << indexCat->GetName() << endl ;
553  }
554  if (!icat->lookupType(hiter->first.c_str())) {
555  icat->defineType(hiter->first.c_str()) ;
556  }
557  icat->setLabel(hiter->first.c_str()) ;
558  // Case 2c --- Import multiple RooDataSets as slices
559  _dstore->loadValues(hiter->second->store(),0,cutRange) ;
560  }
561 
562 
563  } else if (impData) {
564  // Case 3c --- Import RooDataSet
565  _dstore->loadValues(impData->store(),0,cutRange);
566 
567  } else if (impTree || (fname && strlen(fname))) {
568  // Case 4c --- Import TTree from memory / file
569  std::unique_ptr<TFile> file;
570 
571  if (impTree == nullptr) {
572  file.reset(TFile::Open(fname));
573  if (!file) {
574  coutE(InputArguments) << "RooDataSet::ctor(" << GetName() << ") ERROR file '" << fname << "' cannot be opened or does not exist" << endl ;
575  throw std::invalid_argument(Form("RooDataSet::ctor(%s) ERROR file %s cannot be opened or does not exist",GetName(),fname)) ;
576  }
577 
578  file->GetObject(tname, impTree);
579  if (!impTree) {
580  coutE(InputArguments) << "RooDataSet::ctor(" << GetName() << ") ERROR file '" << fname << "' does not contain a TTree named '" << tname << "'" << endl ;
581  throw std::invalid_argument(Form("RooDataSet::ctor(%s) ERROR file %s does not contain a TTree named %s",GetName(),fname,tname)) ;
582  }
583  }
584 
585  if (tstore) {
586  tstore->loadValues(impTree,0,cutRange);
587  } else {
588  RooTreeDataStore tmpstore(name,title,_vars,wgtVarName) ;
589  tmpstore.loadValues(impTree,0,cutRange) ;
590  _dstore->append(tmpstore) ;
591  }
592  }
593  }
594 
595  }
596  TRACE_CREATE
597 }
598 
599 
600 
601 ////////////////////////////////////////////////////////////////////////////////
602 /// Constructor of an empty data set from a RooArgSet defining the dimensions
603 /// of the data space.
604 
605 RooDataSet::RooDataSet(const char *name, const char *title, const RooArgSet& vars, const char* wgtVarName) :
606  RooAbsData(name,title,vars)
607 {
608 // cout << "RooDataSet::ctor(" << this << ") storageType = " << ((defaultStorageType==Tree)?"Tree":"Vector") << endl ;
609  _dstore = (defaultStorageType==Tree) ? ((RooAbsDataStore*) new RooTreeDataStore(name,title,_vars,wgtVarName)) :
610  ((RooAbsDataStore*) new RooVectorDataStore(name,title,_vars,wgtVarName)) ;
611 
612  appendToDir(this,kTRUE) ;
613  initialize(wgtVarName) ;
614  TRACE_CREATE
615 }
616 
617 
618 ////////////////////////////////////////////////////////////////////////////////
619 /// Constructor of a data set from (part of) an existing data
620 /// set. The dimensions of the data set are defined by the 'vars'
621 /// RooArgSet, which can be identical to 'dset' dimensions, or a
622 /// subset thereof. The 'cuts' string is an optional RooFormula
623 /// expression and can be used to select the subset of the data
624 /// points in 'dset' to be copied. The cut expression can refer to
625 /// any variable in the source dataset. For cuts involving variables
626 /// other than those contained in the source data set, such as
627 /// intermediate formula objects, use the equivalent constructor
628 /// accepting RooFormulaVar reference as cut specification.
629 ///
630 /// This constructor will internally store the data in a TTree.
631 ///
632 /// For most uses the RooAbsData::reduce() wrapper function, which
633 /// uses this constructor, is the most convenient way to create a
634 /// subset of an existing data
635 ///
636 
637 RooDataSet::RooDataSet(const char *name, const char *title, RooDataSet *dset,
638  const RooArgSet& vars, const char *cuts, const char* wgtVarName) :
639  RooAbsData(name,title,vars)
640 {
641  // Initialize datastore
642  _dstore = new RooTreeDataStore(name,title,_vars,*dset->_dstore,cuts,wgtVarName) ;
643 
644  appendToDir(this,kTRUE) ;
645 
646  if (wgtVarName) {
647  // Use the supplied weight column
648  initialize(wgtVarName) ;
649  } else {
650  if (dset->_wgtVar && vars.find(dset->_wgtVar->GetName())) {
651  // Use the weight column of the source data set
652  initialize(dset->_wgtVar->GetName()) ;
653  } else {
654  initialize(0) ;
655  }
656  }
657  TRACE_CREATE
658 }
659 
660 
661 ////////////////////////////////////////////////////////////////////////////////
662 /// Constructor of a data set from (part of) an existing data
663 /// set. The dimensions of the data set are defined by the 'vars'
664 /// RooArgSet, which can be identical to 'dset' dimensions, or a
665 /// subset thereof. The 'cutVar' formula variable is used to select
666 /// the subset of data points to be copied. For subsets without
667 /// selection on the data points, or involving cuts operating
668 /// exclusively and directly on the data set dimensions, the
669 /// equivalent constructor with a string based cut expression is
670 /// recommended.
671 ///
672 /// This constructor will internally store the data in a TTree.
673 ///
674 /// For most uses the RooAbsData::reduce() wrapper function, which
675 /// uses this constructor, is the most convenient way to create a
676 /// subset of an existing data
677 
678 RooDataSet::RooDataSet(const char *name, const char *title, RooDataSet *dset,
679  const RooArgSet& vars, const RooFormulaVar& cutVar, const char* wgtVarName) :
680  RooAbsData(name,title,vars)
681 {
682  // Initialize datastore
683  _dstore = new RooTreeDataStore(name,title,_vars,*dset->_dstore,cutVar,wgtVarName) ;
684 
685  appendToDir(this,kTRUE) ;
686 
687  if (wgtVarName) {
688  // Use the supplied weight column
689  initialize(wgtVarName) ;
690  } else {
691  if (dset->_wgtVar && vars.find(dset->_wgtVar->GetName())) {
692  // Use the weight column of the source data set
693  initialize(dset->_wgtVar->GetName()) ;
694  } else {
695  initialize(0) ;
696  }
697  }
698  TRACE_CREATE
699 }
700 
701 
702 
703 
704 ////////////////////////////////////////////////////////////////////////////////
705 /// Constructor of a data set from (part of) an ROOT TTRee. The dimensions
706 /// of the data set are defined by the 'vars' RooArgSet. For each dimension
707 /// specified, the TTree must have a branch with the same name. For category
708 /// branches, this branch should contain the numeric index value. Real dimensions
709 /// can be constructed from either 'Double_t' or 'Float_t' tree branches. In the
710 /// latter case, an automatic conversion is applied.
711 ///
712 /// The 'cutVar' formula variable
713 /// is used to select the subset of data points to be copied.
714 /// For subsets without selection on the data points, or involving cuts
715 /// operating exclusively and directly on the data set dimensions, the equivalent
716 /// constructor with a string based cut expression is recommended.
717 
718 RooDataSet::RooDataSet(const char *name, const char *title, TTree *intree,
719  const RooArgSet& vars, const RooFormulaVar& cutVar, const char* wgtVarName) :
720  RooAbsData(name,title,vars)
721 {
722  // Create tree version of datastore
723  RooTreeDataStore* tstore = new RooTreeDataStore(name,title,_vars,*intree,cutVar,wgtVarName) ;
724 
725  // Convert to vector datastore if needed
726  if (defaultStorageType==Tree) {
727  _dstore = tstore ;
728  } else if (defaultStorageType==Vector) {
729  RooVectorDataStore* vstore = new RooVectorDataStore(name,title,_vars,wgtVarName) ;
730  _dstore = vstore ;
731  _dstore->append(*tstore) ;
732  delete tstore ;
733  } else {
734  _dstore = 0 ;
735  }
736 
737  appendToDir(this,kTRUE) ;
738  initialize(wgtVarName) ;
739  TRACE_CREATE
740 }
741 
742 
743 
744 ////////////////////////////////////////////////////////////////////////////////
745 /// Constructor of a data set from (part of) an ROOT TTRee. The dimensions
746 /// of the data set are defined by the 'vars' RooArgSet. For each dimension
747 /// specified, the TTree must have a branch with the same name. For category
748 /// branches, this branch should contain the numeric index value. Real dimensions
749 /// can be constructed from either 'Double_t' or 'Float_t' tree branches. In the
750 /// latter case, an automatic conversion is applied.
751 ///
752 /// The 'cuts' string is an optional
753 /// RooFormula expression and can be used to select the subset of the data points
754 /// in 'dset' to be copied. The cut expression can refer to any variable in the
755 /// vars argset. For cuts involving variables other than those contained in
756 /// the vars argset, such as intermediate formula objects, use the
757 /// equivalent constructor accepting RooFormulaVar reference as cut specification
758 ///
759 
760 RooDataSet::RooDataSet(const char *name, const char *title, TTree *intree,
761  const RooArgSet& vars, const char *selExpr, const char* wgtVarName) :
762  RooAbsData(name,title,vars)
763 {
764  // Create tree version of datastore
765  RooTreeDataStore* tstore = new RooTreeDataStore(name,title,_vars,*intree,selExpr,wgtVarName) ;
766 
767  // Convert to vector datastore if needed
768  if (defaultStorageType==Tree) {
769  _dstore = tstore ;
770  } else if (defaultStorageType==Vector) {
771  RooVectorDataStore* vstore = new RooVectorDataStore(name,title,_vars,wgtVarName) ;
772  _dstore = vstore ;
773  _dstore->append(*tstore) ;
774  delete tstore ;
775  } else {
776  _dstore = 0 ;
777  }
778 
779  appendToDir(this,kTRUE) ;
780 
781  initialize(wgtVarName) ;
782  TRACE_CREATE
783 }
784 
785 
786 
787 ////////////////////////////////////////////////////////////////////////////////
788 /// Copy constructor
789 
790 RooDataSet::RooDataSet(RooDataSet const & other, const char* newname) :
791  RooAbsData(other,newname), RooDirItem()
792 {
793  appendToDir(this,kTRUE) ;
794  initialize(other._wgtVar?other._wgtVar->GetName():0) ;
795  TRACE_CREATE
796 }
797 
798 ////////////////////////////////////////////////////////////////////////////////
799 /// Protected constructor for internal use only
800 
801 RooDataSet::RooDataSet(const char *name, const char *title, RooDataSet *dset,
802  const RooArgSet& vars, const RooFormulaVar* cutVar, const char* cutRange,
803  Int_t nStart, Int_t nStop, Bool_t copyCache, const char* wgtVarName) :
804  RooAbsData(name,title,vars)
805 {
806  _dstore =
807  (defaultStorageType == Tree)
808  ? ((RooAbsDataStore *)new RooTreeDataStore(name, title, *dset->_dstore, _vars, cutVar, cutRange, nStart, nStop,
809  copyCache, wgtVarName))
810  : (
811  // ( dset->_dstore->IsA()==RooCompositeDataStore::Class() )?
812  // ((RooAbsDataStore*) new
813  // RooCompositeDataStore(name,title,(RooCompositeDataStore&)(*dset->_dstore),_vars,cutVar,cutRange,nStart,nStop,copyCache,wgtVarName))
814  // :
815  ((RooAbsDataStore *)new RooVectorDataStore(name, title, *dset->_dstore, _vars, cutVar, cutRange, nStart,
816  nStop, copyCache, wgtVarName)));
817 
818  _cachedVars.add(_dstore->cachedVars());
819 
820  appendToDir(this, kTRUE);
821  initialize(dset->_wgtVar ? dset->_wgtVar->GetName() : 0);
822  TRACE_CREATE
823 }
824 
825 
826 ////////////////////////////////////////////////////////////////////////////////
827 /// Helper function for constructor that adds optional weight variable to construct
828 /// total set of observables
829 
830 RooArgSet RooDataSet::addWgtVar(const RooArgSet& origVars, const RooAbsArg* wgtVar)
831 {
832  RooArgSet tmp(origVars) ;
833  if (wgtVar) tmp.add(*wgtVar) ;
834  return tmp ;
835 }
836 
837 
838 
839 ////////////////////////////////////////////////////////////////////////////////
840 /// Return a clone of this dataset containing only the cached variables
841 
842 RooAbsData* RooDataSet::cacheClone(const RooAbsArg* newCacheOwner, const RooArgSet* newCacheVars, const char* newName)
843 {
844  RooDataSet* dset = new RooDataSet(newName?newName:GetName(),GetTitle(),this,_vars,(RooFormulaVar*)0,0,0,2000000000,kTRUE,_wgtVar?_wgtVar->GetName():0) ;
845  //if (_wgtVar) dset->setWeightVar(_wgtVar->GetName()) ;
846 
847  RooArgSet* selCacheVars = (RooArgSet*) newCacheVars->selectCommon(dset->_cachedVars) ;
848  dset->attachCache(newCacheOwner, *selCacheVars) ;
849  delete selCacheVars ;
850 
851  return dset ;
852 }
853 
854 
855 
856 ////////////////////////////////////////////////////////////////////////////////
857 /// Return an empty clone of this dataset. If vars is not null, only the variables in vars
858 /// are added to the definition of the empty clone
859 
860 RooAbsData* RooDataSet::emptyClone(const char* newName, const char* newTitle, const RooArgSet* vars, const char* wgtVarName) const
861 {
862  // If variables are given, be sure to include weight variable if it exists and is not included
863  RooArgSet vars2 ;
864  RooRealVar* tmpWgtVar = _wgtVar ;
865  if (wgtVarName && vars && !_wgtVar) {
866  tmpWgtVar = (RooRealVar*) vars->find(wgtVarName) ;
867  }
868 
869  if (vars) {
870  vars2.add(*vars) ;
871  if (_wgtVar && !vars2.find(_wgtVar->GetName())) {
872  vars2.add(*_wgtVar) ;
873  }
874  } else {
875  vars2.add(_vars) ;
876  }
877 
878  RooDataSet* dset = new RooDataSet(newName?newName:GetName(),newTitle?newTitle:GetTitle(),vars2,tmpWgtVar?tmpWgtVar->GetName():0) ;
879  //if (_wgtVar) dset->setWeightVar(_wgtVar->GetName()) ;
880  return dset ;
881 }
882 
883 
884 
885 ////////////////////////////////////////////////////////////////////////////////
886 /// Initialize the dataset. If wgtVarName is not null, interpret the observable
887 /// with that name as event weight
888 
889 void RooDataSet::initialize(const char* wgtVarName)
890 {
891  _varsNoWgt.removeAll() ;
892  _varsNoWgt.add(_vars) ;
893  _wgtVar = 0 ;
894  if (wgtVarName) {
895  RooAbsArg* wgt = _varsNoWgt.find(wgtVarName) ;
896  if (!wgt) {
897  coutW(DataHandling) << "RooDataSet::RooDataSet(" << GetName() << ") WARNING: designated weight variable "
898  << wgtVarName << " not found in set of variables, no weighting will be assigned" << endl ;
899  } else if (!dynamic_cast<RooRealVar*>(wgt)) {
900  coutW(DataHandling) << "RooDataSet::RooDataSet(" << GetName() << ") WARNING: designated weight variable "
901  << wgtVarName << " is not of type RooRealVar, no weighting will be assigned" << endl ;
902  } else {
903  _varsNoWgt.remove(*wgt) ;
904  _wgtVar = (RooRealVar*) wgt ;
905  }
906  }
907 }
908 
909 
910 
911 ////////////////////////////////////////////////////////////////////////////////
912 /// Implementation of RooAbsData virtual method that drives the RooAbsData::reduce() methods
913 
914 RooAbsData* RooDataSet::reduceEng(const RooArgSet& varSubset, const RooFormulaVar* cutVar, const char* cutRange,
915  Int_t nStart, Int_t nStop, Bool_t copyCache)
916 {
917  checkInit() ;
918 
919  //cout << "reduceEng varSubset = " << varSubset << " _wgtVar = " << (_wgtVar ? _wgtVar->GetName() : "") << endl;
920 
921  RooArgSet tmp(varSubset) ;
922  if (_wgtVar) {
923  tmp.add(*_wgtVar) ;
924  }
925  RooDataSet* ret = new RooDataSet(GetName(), GetTitle(), this, tmp, cutVar, cutRange, nStart, nStop, copyCache,_wgtVar?_wgtVar->GetName():0) ;
926 
927  // WVE - propagate optional weight variable
928  // check behaviour in plotting.
929  // if (_wgtVar) {
930  // ret->setWeightVar(_wgtVar->GetName()) ;
931  // }
932  return ret ;
933 }
934 
935 
936 
937 ////////////////////////////////////////////////////////////////////////////////
938 /// Destructor
939 
940 RooDataSet::~RooDataSet()
941 {
942  removeFromDir(this) ;
943  TRACE_DESTROY
944 }
945 
946 
947 
948 ////////////////////////////////////////////////////////////////////////////////
949 /// Return binned clone of this dataset
950 
951 RooDataHist* RooDataSet::binnedClone(const char* newName, const char* newTitle) const
952 {
953  TString title, name ;
954  if (newName) {
955  name = newName ;
956  } else {
957  name = Form("%s_binned",GetName()) ;
958  }
959  if (newTitle) {
960  title = newTitle ;
961  } else {
962  title = Form("%s_binned",GetTitle()) ;
963  }
964 
965  return new RooDataHist(name,title,*get(),*this) ;
966 }
967 
968 
969 
970 ////////////////////////////////////////////////////////////////////////////////
971 /// Return event weight of current event
972 
973 Double_t RooDataSet::weight() const
974 {
975  return store()->weight() ;
976 }
977 
978 
979 
980 ////////////////////////////////////////////////////////////////////////////////
981 /// Return squared event weight of current event
982 
983 Double_t RooDataSet::weightSquared() const
984 {
985  return store()->weight()*store()->weight() ;
986 }
987 
988 
989 
990 ////////////////////////////////////////////////////////////////////////////////
991 /// Return event weights of all events in range
992 
993 RooSpan<const double> RooDataSet::getWeightBatch(std::size_t first, std::size_t last) const {
994  return _dstore->getWeightBatch(first, last);
995 }
996 
997 
998 ////////////////////////////////////////////////////////////////////////////////
999 
1000 void RooDataSet::weightError(Double_t& lo, Double_t& hi, ErrorType etype) const
1001 {
1002  store()->weightError(lo,hi,etype) ;
1003 }
1004 
1005 
1006 
1007 ////////////////////////////////////////////////////////////////////////////////
1008 
1009 Double_t RooDataSet::weightError(ErrorType etype) const
1010 {
1011  return store()->weightError(etype) ;
1012 }
1013 
1014 
1015 
1016 ////////////////////////////////////////////////////////////////////////////////
1017 /// Return RooArgSet with coordinates of event 'index'
1018 
1019 const RooArgSet* RooDataSet::get(Int_t index) const
1020 {
1021  const RooArgSet* ret = RooAbsData::get(index) ;
1022  return ret ? &_varsNoWgt : 0 ;
1023 }
1024 
1025 
1026 ////////////////////////////////////////////////////////////////////////////////
1027 
1028 Double_t RooDataSet::sumEntries() const
1029 {
1030  return store()->sumEntries() ;
1031 
1032  //---------
1033 
1034  // Shortcut for unweighted unselected datasets
1035  if (!isWeighted()) {
1036  return numEntries() ;
1037  }
1038 
1039  // Otherwise sum the weights in the event
1040  Double_t sumw(0), carry(0);
1041  Int_t i ;
1042  for (i=0 ; i<numEntries() ; i++) {
1043  get(i) ;
1044  Double_t y = weight() - carry;
1045  Double_t t = sumw + y;
1046  carry = (t - sumw) - y;
1047  sumw = t;
1048  }
1049 
1050  return sumw ;
1051 }
1052 
1053 
1054 ////////////////////////////////////////////////////////////////////////////////
1055 /// Return the sum of weights in all entries matching cutSpec (if specified)
1056 /// and in named range cutRange (if specified)
1057 
1058 Double_t RooDataSet::sumEntries(const char* cutSpec, const char* cutRange) const
1059 {
1060  // Setup RooFormulaVar for cutSpec if it is present
1061  RooFormula* select = 0 ;
1062  if (cutSpec && strlen(cutSpec) > 0) {
1063  select = new RooFormula("select",cutSpec,*get()) ;
1064  }
1065 
1066  // Shortcut for unweighted unselected datasets
1067  if (!select && !cutRange && !isWeighted()) {
1068  return numEntries() ;
1069  }
1070 
1071  // Otherwise sum the weights in the event
1072  Double_t sumw(0), carry(0);
1073  Int_t i ;
1074  for (i=0 ; i<numEntries() ; i++) {
1075  get(i) ;
1076  if (select && select->eval()==0.) continue ;
1077  if (cutRange && !_vars.allInRange(cutRange)) continue ;
1078  Double_t y = weight() - carry;
1079  Double_t t = sumw + y;
1080  carry = (t - sumw) - y;
1081  sumw = t;
1082  }
1083 
1084  if (select) delete select ;
1085 
1086  return sumw ;
1087 }
1088 
1089 
1090 
1091 
1092 ////////////////////////////////////////////////////////////////////////////////
1093 /// Return true if dataset contains weighted events
1094 
1095 Bool_t RooDataSet::isWeighted() const
1096 {
1097  return store()->isWeighted() ;
1098 }
1099 
1100 
1101 
1102 ////////////////////////////////////////////////////////////////////////////////
1103 /// Returns true if histogram contains bins with entries with a non-integer weight
1104 
1105 Bool_t RooDataSet::isNonPoissonWeighted() const
1106 {
1107  // Return false if we have no weights
1108  if (!_wgtVar) return kFALSE ;
1109 
1110  // Now examine individual weights
1111  for (int i=0 ; i<numEntries() ; i++) {
1112  get(i) ;
1113  if (fabs(weight()-Int_t(weight()))>1e-10) return kTRUE ;
1114  }
1115  // If sum of weights is less than number of events there are negative (integer) weights
1116  if (sumEntries()<numEntries()) return kTRUE ;
1117 
1118  return kFALSE ;
1119 }
1120 
1121 
1122 
1123 
1124 ////////////////////////////////////////////////////////////////////////////////
1125 /// Return a RooArgSet with the coordinates of the current event
1126 
1127 const RooArgSet* RooDataSet::get() const
1128 {
1129  return &_varsNoWgt ;
1130 }
1131 
1132 
1133 
1134 ////////////////////////////////////////////////////////////////////////////////
1135 /// Add a data point, with its coordinates specified in the 'data' argset, to the data set.
1136 /// Any variables present in 'data' but not in the dataset will be silently ignored.
1137 /// \param[in] data Data point.
1138 /// \param[in] wgt Event weight. Defaults to 1. The current value of the weight variable is
1139 /// ignored.
1140 /// \note To obtain weighted events, a variable must be designated `WeightVar` in the constructor.
1141 /// \param[in] wgtError Optional weight error.
1142 /// \note This requires including the weight variable in the set of `StoreError` variables when constructing
1143 /// the dataset.
1144 
1145 void RooDataSet::add(const RooArgSet& data, Double_t wgt, Double_t wgtError)
1146 {
1147  checkInit() ;
1148 
1149  const double oldW = _wgtVar ? _wgtVar->getVal() : 0.;
1150 
1151  _varsNoWgt = data;
1152 
1153  if (_wgtVar) {
1154  _wgtVar->setVal(wgt) ;
1155  if (wgtError!=0.) {
1156  _wgtVar->setError(wgtError) ;
1157  }
1158  } else if ((wgt != 1. || wgtError != 0.) && _errorMsgCount < 5) {
1159  ccoutE(DataHandling) << "An event weight/error was passed but no weight variable was defined"
1160  << " in the dataset '" << GetName() << "'. The weight will be ignored." << std::endl;
1161  ++_errorMsgCount;
1162  }
1163 
1164  if (_wgtVar && _doWeightErrorCheck
1165  && wgtError != 0.
1166  && fabs(wgt*wgt - wgtError)/wgtError > 1.E-15 //Exception for standard wgt^2 errors, which need not be stored.
1167  && _errorMsgCount < 5 && !_wgtVar->getAttribute("StoreError")) {
1168  coutE(DataHandling) << "An event weight error was passed to the RooDataSet '" << GetName()
1169  << "', but the weight variable '" << _wgtVar->GetName()
1170  << "' does not store errors. Check `StoreError` in the RooDataSet constructor." << std::endl;
1171  ++_errorMsgCount;
1172  }
1173 
1174  fill();
1175 
1176  // Restore weight state
1177  if (_wgtVar) {
1178  _wgtVar->setVal(oldW);
1179  _wgtVar->removeError();
1180  }
1181 }
1182 
1183 
1184 
1185 
1186 ////////////////////////////////////////////////////////////////////////////////
1187 /// Add a data point, with its coordinates specified in the 'data' argset, to the data set.
1188 /// Any variables present in 'data' but not in the dataset will be silently ignored.
1189 /// \param[in] data Data point.
1190 /// \param[in] wgt Event weight. The current value of the weight variable is ignored.
1191 /// \note To obtain weighted events, a variable must be designated `WeightVar` in the constructor.
1192 /// \param[in] wgtErrorLo Asymmetric weight error.
1193 /// \param[in] wgtErrorHi Asymmetric weight error.
1194 /// \note This requires including the weight variable in the set of `StoreAsymError` variables when constructing
1195 /// the dataset.
1196 
1197 void RooDataSet::add(const RooArgSet& indata, Double_t inweight, Double_t weightErrorLo, Double_t weightErrorHi)
1198 {
1199  checkInit() ;
1200 
1201  const double oldW = _wgtVar ? _wgtVar->getVal() : 0.;
1202 
1203  _varsNoWgt = indata;
1204  if (_wgtVar) {
1205  _wgtVar->setVal(inweight) ;
1206  _wgtVar->setAsymError(weightErrorLo,weightErrorHi) ;
1207  } else if (inweight != 1. && _errorMsgCount < 5) {
1208  ccoutE(DataHandling) << "An event weight was given but no weight variable was defined"
1209  << " in the dataset '" << GetName() << "'. The weight will be ignored." << std::endl;
1210  ++_errorMsgCount;
1211  }
1212 
1213  if (_wgtVar && _doWeightErrorCheck
1214  && _errorMsgCount < 5 && !_wgtVar->getAttribute("StoreAsymError")) {
1215  coutE(DataHandling) << "An event weight error was passed to the RooDataSet '" << GetName()
1216  << "', but the weight variable '" << _wgtVar->GetName()
1217  << "' does not store errors. Check `StoreAsymError` in the RooDataSet constructor." << std::endl;
1218  ++_errorMsgCount;
1219  }
1220 
1221  fill();
1222 
1223  // Restore weight state
1224  if (_wgtVar) {
1225  _wgtVar->setVal(oldW);
1226  _wgtVar->removeAsymError();
1227  }
1228 }
1229 
1230 
1231 
1232 
1233 
1234 ////////////////////////////////////////////////////////////////////////////////
1235 /// Add a data point, with its coordinates specified in the 'data' argset, to the data set.
1236 /// \attention The order and type of the input variables are **assumed** to be the same as
1237 /// for the RooArgSet returned by RooDataSet::get(). Input values will just be written
1238 /// into the internal data columns by ordinal position.
1239 /// \param[in] data Data point.
1240 /// \param[in] wgt Event weight. Defaults to 1. The current value of the weight variable is
1241 /// ignored.
1242 /// \note To obtain weighted events, a variable must be designated `WeightVar` in the constructor.
1243 /// \param[in] wgtError Optional weight error.
1244 /// \note This requires including the weight variable in the set of `StoreError` variables when constructing
1245 /// the dataset.
1246 
1247 void RooDataSet::addFast(const RooArgSet& data, Double_t wgt, Double_t wgtError)
1248 {
1249  checkInit() ;
1250 
1251  const double oldW = _wgtVar ? _wgtVar->getVal() : 0.;
1252 
1253  _varsNoWgt.assignFast(data,_dstore->dirtyProp());
1254  if (_wgtVar) {
1255  _wgtVar->setVal(wgt) ;
1256  if (wgtError!=0.) {
1257  _wgtVar->setError(wgtError) ;
1258  }
1259  } else if (wgt != 1. && _errorMsgCount < 5) {
1260  ccoutE(DataHandling) << "An event weight was given but no weight variable was defined"
1261  << " in the dataset '" << GetName() << "'. The weight will be ignored." << std::endl;
1262  ++_errorMsgCount;
1263  }
1264 
1265  fill();
1266 
1267  if (_wgtVar && _doWeightErrorCheck
1268  && wgtError != 0. && wgtError != wgt*wgt //Exception for standard weight error, which need not be stored
1269  && _errorMsgCount < 5 && !_wgtVar->getAttribute("StoreError")) {
1270  coutE(DataHandling) << "An event weight error was passed to the RooDataSet '" << GetName()
1271  << "', but the weight variable '" << _wgtVar->GetName()
1272  << "' does not store errors. Check `StoreError` in the RooDataSet constructor." << std::endl;
1273  ++_errorMsgCount;
1274  }
1275  if (_wgtVar && _doWeightErrorCheck) {
1276  _doWeightErrorCheck = false;
1277  }
1278 
1279  if (_wgtVar) {
1280  _wgtVar->setVal(oldW);
1281  _wgtVar->removeError();
1282  }
1283 }
1284 
1285 
1286 
1287 ////////////////////////////////////////////////////////////////////////////////
1288 
1289 Bool_t RooDataSet::merge(RooDataSet* data1, RooDataSet* data2, RooDataSet* data3,
1290  RooDataSet* data4, RooDataSet* data5, RooDataSet* data6)
1291 {
1292  checkInit() ;
1293  list<RooDataSet*> dsetList ;
1294  if (data1) dsetList.push_back(data1) ;
1295  if (data2) dsetList.push_back(data2) ;
1296  if (data3) dsetList.push_back(data3) ;
1297  if (data4) dsetList.push_back(data4) ;
1298  if (data5) dsetList.push_back(data5) ;
1299  if (data6) dsetList.push_back(data6) ;
1300  return merge(dsetList) ;
1301 }
1302 
1303 
1304 
1305 ////////////////////////////////////////////////////////////////////////////////
1306 /// Merge columns of supplied data set(s) with this data set. All
1307 /// data sets must have equal number of entries. In case of
1308 /// duplicate columns the column of the last dataset in the list
1309 /// prevails
1310 
1311 Bool_t RooDataSet::merge(list<RooDataSet*>dsetList)
1312 {
1313 
1314  checkInit() ;
1315  // Sanity checks: data sets must have the same size
1316  for (list<RooDataSet*>::iterator iter = dsetList.begin() ; iter != dsetList.end() ; ++iter) {
1317  if (numEntries()!=(*iter)->numEntries()) {
1318  coutE(InputArguments) << "RooDataSet::merge(" << GetName() << ") ERROR: datasets have different size" << endl ;
1319  return kTRUE ;
1320  }
1321  }
1322 
1323  // Extend vars with elements of other dataset
1324  list<RooAbsDataStore*> dstoreList ;
1325  for (list<RooDataSet*>::iterator iter = dsetList.begin() ; iter != dsetList.end() ; ++iter) {
1326  _vars.addClone((*iter)->_vars,kTRUE) ;
1327  dstoreList.push_back((*iter)->store()) ;
1328  }
1329 
1330  // Merge data stores
1331  RooAbsDataStore* mergedStore = _dstore->merge(_vars,dstoreList) ;
1332  mergedStore->SetName(_dstore->GetName()) ;
1333  mergedStore->SetTitle(_dstore->GetTitle()) ;
1334 
1335  // Replace current data store with merged store
1336  delete _dstore ;
1337  _dstore = mergedStore ;
1338 
1339  initialize(_wgtVar?_wgtVar->GetName():0) ;
1340  return kFALSE ;
1341 }
1342 
1343 
1344 ////////////////////////////////////////////////////////////////////////////////
1345 /// Add all data points of given data set to this data set.
1346 /// Observable in 'data' that are not in this dataset
1347 /// with not be transferred
1348 
1349 void RooDataSet::append(RooDataSet& data)
1350 {
1351  checkInit() ;
1352  _dstore->append(*data._dstore) ;
1353 }
1354 
1355 
1356 
1357 ////////////////////////////////////////////////////////////////////////////////
1358 /// Add a column with the values of the given (function) argument
1359 /// to this dataset. The function value is calculated for each
1360 /// event using the observable values of each event in case the
1361 /// function depends on variables with names that are identical
1362 /// to the observable names in the dataset
1363 
1364 RooAbsArg* RooDataSet::addColumn(RooAbsArg& var, Bool_t adjustRange)
1365 {
1366  checkInit() ;
1367  RooAbsArg* ret = _dstore->addColumn(var,adjustRange) ;
1368  _vars.addOwned(*ret) ;
1369  initialize(_wgtVar?_wgtVar->GetName():0) ;
1370  return ret ;
1371 }
1372 
1373 
1374 ////////////////////////////////////////////////////////////////////////////////
1375 /// Add a column with the values of the given list of (function)
1376 /// argument to this dataset. Each function value is calculated for
1377 /// each event using the observable values of the event in case the
1378 /// function depends on variables with names that are identical to
1379 /// the observable names in the dataset
1380 
1381 RooArgSet* RooDataSet::addColumns(const RooArgList& varList)
1382 {
1383  checkInit() ;
1384  RooArgSet* ret = _dstore->addColumns(varList) ;
1385  _vars.addOwned(*ret) ;
1386  initialize(_wgtVar?_wgtVar->GetName():0) ;
1387  return ret ;
1388 }
1389 
1390 
1391 
1392 ////////////////////////////////////////////////////////////////////////////////
1393 /// Create a TH2F histogram of the distribution of the specified variable
1394 /// using this dataset. Apply any cuts to select which events are used.
1395 /// The variable being plotted can either be contained directly in this
1396 /// dataset, or else be a function of the variables in this dataset.
1397 /// The histogram will be created using RooAbsReal::createHistogram() with
1398 /// the name provided (with our dataset name prepended).
1399 
1400 TH2F* RooDataSet::createHistogram(const RooAbsRealLValue& var1, const RooAbsRealLValue& var2, const char* cuts, const char *name) const
1401 {
1402  checkInit() ;
1403  return createHistogram(var1, var2, var1.getBins(), var2.getBins(), cuts, name);
1404 }
1405 
1406 
1407 
1408 ////////////////////////////////////////////////////////////////////////////////
1409 /// Create a TH2F histogram of the distribution of the specified variable
1410 /// using this dataset. Apply any cuts to select which events are used.
1411 /// The variable being plotted can either be contained directly in this
1412 /// dataset, or else be a function of the variables in this dataset.
1413 /// The histogram will be created using RooAbsReal::createHistogram() with
1414 /// the name provided (with our dataset name prepended).
1415 
1416 TH2F* RooDataSet::createHistogram(const RooAbsRealLValue& var1, const RooAbsRealLValue& var2,
1417  Int_t nx, Int_t ny, const char* cuts, const char *name) const
1418 {
1419  checkInit() ;
1420  static Int_t counter(0) ;
1421 
1422  Bool_t ownPlotVarX(kFALSE) ;
1423  // Is this variable in our dataset?
1424  RooAbsReal* plotVarX= (RooAbsReal*)_vars.find(var1.GetName());
1425  if(0 == plotVarX) {
1426  // Is this variable a client of our dataset?
1427  if (!var1.dependsOn(_vars)) {
1428  coutE(InputArguments) << GetName() << "::createHistogram: Argument " << var1.GetName()
1429  << " is not in dataset and is also not dependent on data set" << endl ;
1430  return 0 ;
1431  }
1432 
1433  // Clone derived variable
1434  plotVarX = (RooAbsReal*) var1.Clone() ;
1435  ownPlotVarX = kTRUE ;
1436 
1437  //Redirect servers of derived clone to internal ArgSet representing the data in this set
1438  plotVarX->redirectServers(const_cast<RooArgSet&>(_vars)) ;
1439  }
1440 
1441  Bool_t ownPlotVarY(kFALSE) ;
1442  // Is this variable in our dataset?
1443  RooAbsReal* plotVarY= (RooAbsReal*)_vars.find(var2.GetName());
1444  if(0 == plotVarY) {
1445  // Is this variable a client of our dataset?
1446  if (!var2.dependsOn(_vars)) {
1447  coutE(InputArguments) << GetName() << "::createHistogram: Argument " << var2.GetName()
1448  << " is not in dataset and is also not dependent on data set" << endl ;
1449  return 0 ;
1450  }
1451 
1452  // Clone derived variable
1453  plotVarY = (RooAbsReal*) var2.Clone() ;
1454  ownPlotVarY = kTRUE ;
1455 
1456  //Redirect servers of derived clone to internal ArgSet representing the data in this set
1457  plotVarY->redirectServers(const_cast<RooArgSet&>(_vars)) ;
1458  }
1459 
1460  // Create selection formula if selection cuts are specified
1461  RooFormula* select = 0;
1462  if(0 != cuts && strlen(cuts)) {
1463  select=new RooFormula(cuts,cuts,_vars);
1464  if (!select || !select->ok()) {
1465  delete select;
1466  return 0 ;
1467  }
1468  }
1469 
1470  TString histName(name);
1471  histName.Prepend("_");
1472  histName.Prepend(fName);
1473  histName.Append("_") ;
1474  histName.Append(Form("%08x",counter++)) ;
1475 
1476  // create the histogram
1477  TH2F* histogram=new TH2F(histName.Data(), "Events", nx, var1.getMin(), var1.getMax(),
1478  ny, var2.getMin(), var2.getMax());
1479  if(!histogram) {
1480  coutE(DataHandling) << fName << "::createHistogram: unable to create a new histogram" << endl;
1481  return 0;
1482  }
1483 
1484  // Dump contents
1485  Int_t nevent= numEntries() ;
1486  for(Int_t i=0; i < nevent; ++i)
1487  {
1488  get(i);
1489 
1490  if (select && select->eval()==0) continue ;
1491  histogram->Fill(plotVarX->getVal(), plotVarY->getVal(),weight()) ;
1492  }
1493 
1494  if (ownPlotVarX) delete plotVarX ;
1495  if (ownPlotVarY) delete plotVarY ;
1496  if (select) delete select ;
1497 
1498  return histogram ;
1499 }
1500 
1501 
1502 
1503 
1504 
1505 ////////////////////////////////////////////////////////////////////////////////
1506 /// Special plot method for 'X-Y' datasets used in \f$ \chi^2 \f$ fitting. These datasets
1507 /// have one observable (X) and have weights (Y) and associated errors.
1508 /// <table>
1509 /// <tr><th> Contents options <th> Effect
1510 /// <tr><td> YVar(RooRealVar& var) <td> Designate specified observable as 'y' variable
1511 /// If not specified, the event weight will be the y variable
1512 /// <tr><th> Histogram drawing options <th> Effect
1513 /// <tr><td> DrawOption(const char* opt) <td> Select ROOT draw option for resulting TGraph object
1514 /// <tr><td> LineStyle(Int_t style) <td> Select line style by ROOT line style code, default is solid
1515 /// <tr><td> LineColor(Int_t color) <td> Select line color by ROOT color code, default is black
1516 /// <tr><td> LineWidth(Int_t width) <td> Select line with in pixels, default is 3
1517 /// <tr><td> MarkerStyle(Int_t style) <td> Select the ROOT marker style, default is 21
1518 /// <tr><td> MarkerColor(Int_t color) <td> Select the ROOT marker color, default is black
1519 /// <tr><td> MarkerSize(Double_t size) <td> Select the ROOT marker size
1520 /// <tr><td> Rescale(Double_t factor) <td> Apply global rescaling factor to histogram
1521 /// <tr><th> Misc. other options <th> Effect
1522 /// <tr><td> Name(const chat* name) <td> Give curve specified name in frame. Useful if curve is to be referenced later
1523 /// <tr><td> Invisible(Bool_t flag) <td> Add curve to frame, but do not display. Useful in combination AddTo()
1524 /// </table>
1525 
1526 RooPlot* RooDataSet::plotOnXY(RooPlot* frame, const RooCmdArg& arg1, const RooCmdArg& arg2,
1527  const RooCmdArg& arg3, const RooCmdArg& arg4,
1528  const RooCmdArg& arg5, const RooCmdArg& arg6,
1529  const RooCmdArg& arg7, const RooCmdArg& arg8) const
1530 {
1531  checkInit() ;
1532 
1533  RooLinkedList argList ;
1534  argList.Add((TObject*)&arg1) ; argList.Add((TObject*)&arg2) ;
1535  argList.Add((TObject*)&arg3) ; argList.Add((TObject*)&arg4) ;
1536  argList.Add((TObject*)&arg5) ; argList.Add((TObject*)&arg6) ;
1537  argList.Add((TObject*)&arg7) ; argList.Add((TObject*)&arg8) ;
1538 
1539  // Process named arguments
1540  RooCmdConfig pc(Form("RooDataSet::plotOnXY(%s)",GetName())) ;
1541  pc.defineString("drawOption","DrawOption",0,"P") ;
1542  pc.defineString("histName","Name",0,"") ;
1543  pc.defineInt("lineColor","LineColor",0,-999) ;
1544  pc.defineInt("lineStyle","LineStyle",0,-999) ;
1545  pc.defineInt("lineWidth","LineWidth",0,-999) ;
1546  pc.defineInt("markerColor","MarkerColor",0,-999) ;
1547  pc.defineInt("markerStyle","MarkerStyle",0,8) ;
1548  pc.defineDouble("markerSize","MarkerSize",0,-999) ;
1549  pc.defineInt("fillColor","FillColor",0,-999) ;
1550  pc.defineInt("fillStyle","FillStyle",0,-999) ;
1551  pc.defineInt("histInvisible","Invisible",0,0) ;
1552  pc.defineDouble("scaleFactor","Rescale",0,1.) ;
1553  pc.defineObject("xvar","XVar",0,0) ;
1554  pc.defineObject("yvar","YVar",0,0) ;
1555 
1556 
1557  // Process & check varargs
1558  pc.process(argList) ;
1559  if (!pc.ok(kTRUE)) {
1560  return frame ;
1561  }
1562 
1563  // Extract values from named arguments
1564  const char* drawOptions = pc.getString("drawOption") ;
1565  Int_t histInvisible = pc.getInt("histInvisible") ;
1566  const char* histName = pc.getString("histName",0,kTRUE) ;
1567  Double_t scaleFactor = pc.getDouble("scaleFactor") ;
1568 
1569  RooRealVar* xvar = (RooRealVar*) _vars.find(frame->getPlotVar()->GetName()) ;
1570 
1571  // Determine Y variable (default is weight, if present)
1572  RooRealVar* yvar = (RooRealVar*)(pc.getObject("yvar")) ;
1573 
1574  // Sanity check. XY plotting only applies to weighted datasets if no YVar is specified
1575  if (!_wgtVar && !yvar) {
1576  coutE(InputArguments) << "RooDataSet::plotOnXY(" << GetName() << ") ERROR: no YVar() argument specified and dataset is not weighted" << endl ;
1577  return 0 ;
1578  }
1579 
1580  RooRealVar* dataY = yvar ? (RooRealVar*) _vars.find(yvar->GetName()) : 0 ;
1581  if (yvar && !dataY) {
1582  coutE(InputArguments) << "RooDataSet::plotOnXY(" << GetName() << ") ERROR on YVar() argument, dataset does not contain a variable named " << yvar->GetName() << endl ;
1583  return 0 ;
1584  }
1585 
1586 
1587  // Make RooHist representing XY contents of data
1588  RooHist* graph = new RooHist ;
1589  if (histName) {
1590  graph->SetName(histName) ;
1591  } else {
1592  graph->SetName(Form("hxy_%s",GetName())) ;
1593  }
1594 
1595  for (int i=0 ; i<numEntries() ; i++) {
1596  get(i) ;
1597  Double_t x = xvar->getVal() ;
1598  Double_t exlo = xvar->getErrorLo() ;
1599  Double_t exhi = xvar->getErrorHi() ;
1600  Double_t y,eylo,eyhi ;
1601  if (!dataY) {
1602  y = weight() ;
1603  weightError(eylo,eyhi) ;
1604  } else {
1605  y = dataY->getVal() ;
1606  eylo = dataY->getErrorLo() ;
1607  eyhi = dataY->getErrorHi() ;
1608  }
1609  graph->addBinWithXYError(x,y,-1*exlo,exhi,-1*eylo,eyhi,scaleFactor) ;
1610  }
1611 
1612  // Adjust style options according to named arguments
1613  Int_t lineColor = pc.getInt("lineColor") ;
1614  Int_t lineStyle = pc.getInt("lineStyle") ;
1615  Int_t lineWidth = pc.getInt("lineWidth") ;
1616  Int_t markerColor = pc.getInt("markerColor") ;
1617  Int_t markerStyle = pc.getInt("markerStyle") ;
1618  Size_t markerSize = pc.getDouble("markerSize") ;
1619  Int_t fillColor = pc.getInt("fillColor") ;
1620  Int_t fillStyle = pc.getInt("fillStyle") ;
1621 
1622  if (lineColor!=-999) graph->SetLineColor(lineColor) ;
1623  if (lineStyle!=-999) graph->SetLineStyle(lineStyle) ;
1624  if (lineWidth!=-999) graph->SetLineWidth(lineWidth) ;
1625  if (markerColor!=-999) graph->SetMarkerColor(markerColor) ;
1626  if (markerStyle!=-999) graph->SetMarkerStyle(markerStyle) ;
1627  if (markerSize!=-999) graph->SetMarkerSize(markerSize) ;
1628  if (fillColor!=-999) graph->SetFillColor(fillColor) ;
1629  if (fillStyle!=-999) graph->SetFillStyle(fillStyle) ;
1630 
1631  // Add graph to frame
1632  frame->addPlotable(graph,drawOptions,histInvisible) ;
1633 
1634  return frame ;
1635 }
1636 
1637 
1638 
1639 
1640 ////////////////////////////////////////////////////////////////////////////////
1641 /// Read given list of ascii files, and construct a data set, using the given
1642 /// ArgList as structure definition.
1643 /// \param fileList Multiple file names, comma separated. Each
1644 /// file is optionally prefixed with 'commonPath' if such a path is
1645 /// provided
1646 ///
1647 /// \param varList Specify the dimensions of the dataset to be built.
1648 /// This list describes the order in which these dimensions appear in the
1649 /// ascii files to be read.
1650 /// Each line in the ascii file should contain N white-space separated
1651 /// tokens, with N the number of args in `varList`. Any text beyond
1652 /// N tokens will be ignored with a warning message.
1653 /// (NB: This is the default output of RooArgList::writeToStream())
1654 ///
1655 /// \param verbOpt `Q` be quiet, `D` debug mode (verbose)
1656 ///
1657 /// \param commonPath All filenames in `fileList` will be prefixed with this optional path.
1658 ///
1659 /// \param indexCatName Interpret the data as belonging to category `indexCatName`.
1660 /// When multiple files are read, a RooCategory arg in `varList` can
1661 /// optionally be designated to hold information about the source file
1662 /// of each data point. This feature is enabled by giving the name
1663 /// of the (already existing) category variable in `indexCatName`.
1664 ///
1665 /// \attention If the value of any of the variables on a given line exceeds the
1666 /// fit range associated with that dimension, the entire line will be
1667 /// ignored. A warning message is printed in each case, unless the
1668 /// `Q` verbose option is given. The number of events read and skipped
1669 /// is always summarized at the end.
1670 ///
1671 /// If no further information is given a label name 'fileNNN' will
1672 /// be assigned to each event, where NNN is the sequential number of
1673 /// the source file in `fileList`.
1674 ///
1675 /// Alternatively, it is possible to override the default label names
1676 /// of the index category by specifying them in the fileList string:
1677 /// When instead of `file1.txt,file2.txt` the string
1678 /// `file1.txt:FOO,file2.txt:BAR` is specified, a state named "FOO"
1679 /// is assigned to the index category for each event originating from
1680 /// file1.txt. The labels FOO,BAR may be predefined in the index
1681 /// category via defineType(), but don't have to be.
1682 ///
1683 /// Finally, one can also assign the same label to multiple files,
1684 /// either by specifying `file1.txt:FOO,file2,txt:FOO,file3.txt:BAR`
1685 /// or `file1.txt,file2.txt:FOO,file3.txt:BAR`.
1686 ///
1687 
1688 RooDataSet *RooDataSet::read(const char *fileList, const RooArgList &varList,
1689  const char *verbOpt, const char* commonPath,
1690  const char* indexCatName) {
1691  // Make working copy of variables list
1692  RooArgList variables(varList) ;
1693 
1694  // Append blinding state category to variable list if not already there
1695  Bool_t ownIsBlind(kTRUE) ;
1696  RooAbsArg* blindState = variables.find("blindState") ;
1697  if (!blindState) {
1698  blindState = new RooCategory("blindState","Blinding State") ;
1699  variables.add(*blindState) ;
1700  } else {
1701  ownIsBlind = kFALSE ;
1702  if (blindState->IsA()!=RooCategory::Class()) {
1703  oocoutE((TObject*)0,DataHandling) << "RooDataSet::read: ERROR: variable list already contains"
1704  << "a non-RooCategory blindState member" << endl ;
1705  return 0 ;
1706  }
1707  oocoutW((TObject*)0,DataHandling) << "RooDataSet::read: WARNING: recycling existing "
1708  << "blindState category in variable list" << endl ;
1709  }
1710  RooCategory* blindCat = (RooCategory*) blindState ;
1711 
1712  // Configure blinding state category
1713  blindCat->setAttribute("Dynamic") ;
1714  blindCat->defineType("Normal",0) ;
1715  blindCat->defineType("Blind",1) ;
1716 
1717  // parse the option string
1718  TString opts= verbOpt;
1719  opts.ToLower();
1720  Bool_t verbose= !opts.Contains("q");
1721  Bool_t debug= opts.Contains("d");
1722 
1723  RooDataSet *data= new RooDataSet("dataset", fileList, variables);
1724  if (ownIsBlind) { variables.remove(*blindState) ; delete blindState ; }
1725  if(!data) {
1726  oocoutE((TObject*)0,DataHandling) << "RooDataSet::read: unable to create a new dataset"
1727  << endl;
1728  return 0;
1729  }
1730 
1731  // Redirect blindCat to point to the copy stored in the data set
1732  blindCat = (RooCategory*) data->_vars.find("blindState") ;
1733 
1734  // Find index category, if requested
1735  RooCategory *indexCat = 0;
1736  //RooCategory *indexCatOrig = 0;
1737  if (indexCatName) {
1738  RooAbsArg* tmp = 0;
1739  tmp = data->_vars.find(indexCatName) ;
1740  if (!tmp) {
1741  oocoutE((TObject*)0,DataHandling) << "RooDataSet::read: no index category named "
1742  << indexCatName << " in supplied variable list" << endl ;
1743  return 0 ;
1744  }
1745  if (tmp->IsA()!=RooCategory::Class()) {
1746  oocoutE((TObject*)0,DataHandling) << "RooDataSet::read: variable " << indexCatName
1747  << " is not a RooCategory" << endl ;
1748  return 0 ;
1749  }
1750  indexCat = (RooCategory*)tmp ;
1751 
1752  // Prevent RooArgSet from attempting to read in indexCat
1753  indexCat->setAttribute("Dynamic") ;
1754  }
1755 
1756 
1757  Int_t outOfRange(0) ;
1758 
1759  // Make local copy of file list for tokenizing
1760  char fileList2[64000];
1761  strlcpy(fileList2, fileList, 64000);
1762 
1763  // Loop over all names in comma separated list
1764  char *filename = strtok(fileList2,", ") ;
1765  Int_t fileSeqNum(0) ;
1766  while (filename) {
1767  // Determine index category number, if this option is active
1768  if (indexCat) {
1769 
1770  // Find and detach optional file category name
1771  char *catname = strchr(filename,':') ;
1772 
1773  if (catname) {
1774  // Use user category name if provided
1775  *catname=0 ;
1776  catname++ ;
1777 
1778  const RooCatType* type = indexCat->lookupType(catname,kFALSE) ;
1779  if (type) {
1780  // Use existing category index
1781  indexCat->setIndex(type->getVal()) ;
1782  } else {
1783  // Register cat name
1784  indexCat->defineType(catname,fileSeqNum) ;
1785  indexCat->setIndex(fileSeqNum) ;
1786  }
1787  } else {
1788  // Assign autogenerated name
1789  char newLabel[128] ;
1790  snprintf(newLabel,128,"file%03d",fileSeqNum) ;
1791  if (indexCat->defineType(newLabel,fileSeqNum)) {
1792  oocoutE((TObject*)0,DataHandling) << "RooDataSet::read: Error, cannot register automatic type name " << newLabel
1793  << " in index category " << indexCat->GetName() << endl ;
1794  return 0 ;
1795  }
1796  // Assign new category number
1797  indexCat->setIndex(fileSeqNum) ;
1798  }
1799  }
1800 
1801  oocoutI((TObject*)0,DataHandling) << "RooDataSet::read: reading file " << filename << endl ;
1802 
1803  // Prefix common path
1804  TString fullName(commonPath) ;
1805  fullName.Append(filename) ;
1806  ifstream file(fullName) ;
1807 
1808  if(!file.good()) {
1809  oocoutW((TObject*)0,DataHandling) << "RooDataSet::read: unable to open '"
1810  << filename << "', skipping" << endl;
1811  }
1812 
1813 // Double_t value;
1814  Int_t line(0) ;
1815  Bool_t haveBlindString(false) ;
1816 
1817  while(file.good() && !file.eof()) {
1818  line++;
1819  if(debug) oocxcoutD((TObject*)0,DataHandling) << "reading line " << line << endl;
1820 
1821  // process comment lines
1822  if (file.peek() == '#')
1823  {
1824  if(debug) oocxcoutD((TObject*)0,DataHandling) << "skipping comment on line " << line << endl;
1825  }
1826  else {
1827 
1828  // Skip empty lines
1829  // if(file.peek() == '\n') { file.get(); }
1830 
1831  // Read single line
1832  Bool_t readError = variables.readFromStream(file,kTRUE,verbose) ;
1833  data->_vars = variables ;
1834 // Bool_t readError = data->_vars.readFromStream(file,kTRUE,verbose) ;
1835 
1836  // Stop at end of file or on read error
1837  if(file.eof()) break ;
1838  if(!file.good()) {
1839  oocoutE((TObject*)0,DataHandling) << "RooDataSet::read(static): read error at line " << line << endl ;
1840  break;
1841  }
1842 
1843  if (readError) {
1844  outOfRange++ ;
1845  continue ;
1846  }
1847  blindCat->setIndex(haveBlindString) ;
1848  data->fill(); // store this event
1849  }
1850  }
1851 
1852  file.close();
1853 
1854  // get next file name
1855  filename = strtok(0," ,") ;
1856  fileSeqNum++ ;
1857  }
1858 
1859  if (indexCat) {
1860  // Copy dynamically defined types from new data set to indexCat in original list
1861  RooCategory* origIndexCat = (RooCategory*) variables.find(indexCatName) ;
1862  for (const auto type : *indexCat) {
1863  origIndexCat->defineType(type->GetName(), type->getVal());
1864  }
1865  }
1866  oocoutI((TObject*)0,DataHandling) << "RooDataSet::read: read " << data->numEntries()
1867  << " events (ignored " << outOfRange << " out of range events)" << endl;
1868  return data;
1869 }
1870 
1871 
1872 
1873 
1874 ////////////////////////////////////////////////////////////////////////////////
1875 /// Write the contents of this dataset to an ASCII file with the specified name.
1876 /// Each event will be written as a single line containing the written values
1877 /// of each observable in the order they were declared in the dataset and
1878 /// separated by whitespaces
1879 
1880 Bool_t RooDataSet::write(const char* filename) const
1881 {
1882  // Open file for writing
1883  ofstream ofs(filename) ;
1884  if (ofs.fail()) {
1885  coutE(DataHandling) << "RooDataSet::write(" << GetName() << ") cannot create file " << filename << endl ;
1886  return kTRUE ;
1887  }
1888 
1889  // Write all lines as arglist in compact mode
1890  coutI(DataHandling) << "RooDataSet::write(" << GetName() << ") writing ASCII file " << filename << endl ;
1891  return write(ofs);
1892 }
1893 
1894 ////////////////////////////////////////////////////////////////////////////////
1895 /// Write the contents of this dataset to the stream.
1896 /// Each event will be written as a single line containing the written values
1897 /// of each observable in the order they were declared in the dataset and
1898 /// separated by whitespaces
1899 
1900 Bool_t RooDataSet::write(ostream & ofs) const {
1901  checkInit();
1902 
1903  for (Int_t i=0; i<numEntries(); ++i) {
1904  get(i)->writeToStream(ofs,kTRUE);
1905  }
1906 
1907  if (ofs.fail()) {
1908  coutW(DataHandling) << "RooDataSet::write(" << GetName() << "): WARNING error(s) have occured in writing" << endl ;
1909  }
1910 
1911  return ofs.fail() ;
1912 }
1913 
1914 
1915 ////////////////////////////////////////////////////////////////////////////////
1916 /// Print info about this dataset to the specified output stream.
1917 ///
1918 /// Standard: number of entries
1919 /// Shape: list of variables we define & were generated with
1920 
1921 void RooDataSet::printMultiline(ostream& os, Int_t contents, Bool_t verbose, TString indent) const
1922 {
1923  checkInit() ;
1924  RooAbsData::printMultiline(os,contents,verbose,indent) ;
1925  if (_wgtVar) {
1926  os << indent << " Dataset variable \"" << _wgtVar->GetName() << "\" is interpreted as the event weight" << endl ;
1927  }
1928 }
1929 
1930 
1931 ////////////////////////////////////////////////////////////////////////////////
1932 /// Print value of the dataset, i.e. the sum of weights contained in the dataset
1933 
1934 void RooDataSet::printValue(ostream& os) const
1935 {
1936  os << numEntries() << " entries" ;
1937  if (isWeighted()) {
1938  os << " (" << sumEntries() << " weighted)" ;
1939  }
1940 }
1941 
1942 
1943 
1944 ////////////////////////////////////////////////////////////////////////////////
1945 /// Print argument of dataset, i.e. the observable names
1946 
1947 void RooDataSet::printArgs(ostream& os) const
1948 {
1949  os << "[" ;
1950  TIterator* iter = _varsNoWgt.createIterator() ;
1951  RooAbsArg* arg ;
1952  Bool_t first(kTRUE) ;
1953  while((arg=(RooAbsArg*)iter->Next())) {
1954  if (first) {
1955  first=kFALSE ;
1956  } else {
1957  os << "," ;
1958  }
1959  os << arg->GetName() ;
1960  }
1961  if (_wgtVar) {
1962  os << ",weight:" << _wgtVar->GetName() ;
1963  }
1964  os << "]" ;
1965  delete iter ;
1966 }
1967 
1968 
1969 
1970 ////////////////////////////////////////////////////////////////////////////////
1971 /// Change the name of this dataset into the given name
1972 
1973 void RooDataSet::SetName(const char *name)
1974 {
1975  if (_dir) _dir->GetList()->Remove(this);
1976  TNamed::SetName(name) ;
1977  if (_dir) _dir->GetList()->Add(this);
1978 }
1979 
1980 
1981 ////////////////////////////////////////////////////////////////////////////////
1982 /// Change the title of this dataset into the given name
1983 
1984 void RooDataSet::SetNameTitle(const char *name, const char* title)
1985 {
1986  if (_dir) _dir->GetList()->Remove(this);
1987  TNamed::SetNameTitle(name,title) ;
1988  if (_dir) _dir->GetList()->Add(this);
1989 }
1990 
1991 
1992 ////////////////////////////////////////////////////////////////////////////////
1993 /// Stream an object of class RooDataSet.
1994 
1995 void RooDataSet::Streamer(TBuffer &R__b)
1996 {
1997  if (R__b.IsReading()) {
1998 
1999  UInt_t R__s, R__c;
2000  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
2001 
2002  if (R__v>1) {
2003 
2004  // Use new-style streaming for version >1
2005  R__b.ReadClassBuffer(RooDataSet::Class(),this,R__v,R__s,R__c);
2006 
2007  } else {
2008 
2009  // Legacy dataset conversion happens here. Legacy RooDataSet inherits from RooTreeData
2010  // which in turn inherits from RooAbsData. Manually stream RooTreeData contents on
2011  // file here and convert it into a RooTreeDataStore which is installed in the
2012  // new-style RooAbsData base class
2013 
2014  // --- This is the contents of the streamer code of RooTreeData version 1 ---
2015  UInt_t R__s1, R__c1;
2016  Version_t R__v1 = R__b.ReadVersion(&R__s1, &R__c1); if (R__v1) { }
2017 
2018  RooAbsData::Streamer(R__b);
2019  TTree* X_tree(0) ; R__b >> X_tree;
2020  RooArgSet X_truth ; X_truth.Streamer(R__b);
2021  TString X_blindString ; X_blindString.Streamer(R__b);
2022  R__b.CheckByteCount(R__s1, R__c1, RooTreeData::Class());
2023  // --- End of RooTreeData-v1 streamer
2024 
2025  // Construct RooTreeDataStore from X_tree and complete initialization of new-style RooAbsData
2026  _dstore = new RooTreeDataStore(X_tree,_vars) ;
2027  _dstore->SetName(GetName()) ;
2028  _dstore->SetTitle(GetTitle()) ;
2029  _dstore->checkInit() ;
2030 
2031  // This is the contents of the streamer code of RooDataSet version 1
2032  RooDirItem::Streamer(R__b);
2033  _varsNoWgt.Streamer(R__b);
2034  R__b >> _wgtVar;
2035  R__b.CheckByteCount(R__s, R__c, RooDataSet::IsA());
2036 
2037 
2038  }
2039  } else {
2040  R__b.WriteClassBuffer(RooDataSet::Class(),this);
2041  }
2042 }
2043 
2044 
2045 
2046 ////////////////////////////////////////////////////////////////////////////////
2047 /// Convert vector-based storage to tree-based storage. This implementation overrides the base class
2048 /// implementation because the latter doesn't transfer weights.
2049 void RooDataSet::convertToTreeStore()
2050 {
2051  if (storageType != RooAbsData::Tree) {
2052  RooTreeDataStore *newStore = new RooTreeDataStore(GetName(), GetTitle(), _vars, *_dstore, nullptr, _wgtVar ? _wgtVar->GetName() : nullptr);
2053  delete _dstore;
2054  _dstore = newStore;
2055  storageType = RooAbsData::Tree;
2056  }
2057 }
2058