Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooAbsCategory.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 RooAbsCategory.cxx
19 \class RooAbsCategory
20 \ingroup Roofitcore
21 
22 RooAbsCategory is the common abstract base class for objects that
23 represent a discrete value with a finite number of states. Each
24 state consist of a label/index pair, which is stored in a
25 RooCatType object.
26 
27 Implementation of RooAbsCategory may be derived, there no interface
28 is provided to modify the contents, nor a public interface to define states.
29 **/
30 
31 #include "RooFit.h"
32 
33 #include "Compression.h"
34 #include "Riostream.h"
35 #include "Riostream.h"
36 #include <stdlib.h>
37 #include "TString.h"
38 #include "TH1.h"
39 #include "TTree.h"
40 #include "TLeaf.h"
41 #include "RooAbsCategory.h"
42 #include "RooArgSet.h"
43 #include "Roo1DTable.h"
44 #include "RooCategory.h"
45 #include "RooMsgService.h"
46 #include "RooVectorDataStore.h"
47 #include "RooLinkedListIter.h"
48 
49 using namespace std;
50 
51 ClassImp(RooAbsCategory);
52 ;
53 
54 
55 ////////////////////////////////////////////////////////////////////////////////
56 /// Constructor
57 
58 RooAbsCategory::RooAbsCategory(const char *name, const char *title) :
59  RooAbsArg(name,title), _byteValue(0), _value("NULL",0), _treeVar(kFALSE)
60 {
61  setValueDirty() ;
62  setShapeDirty() ;
63 }
64 
65 
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 /// Copy constructor, copies the registered category states from the original.
69 
70 RooAbsCategory::RooAbsCategory(const RooAbsCategory& other,const char* name) :
71  RooAbsArg(other,name), _byteValue(0), _value(other._value), _treeVar(other._treeVar)
72 {
73  for (const auto cat : other._types) {
74  _types.push_back(new RooCatType(*cat));
75  }
76 
77  setValueDirty() ;
78  setShapeDirty() ;
79 }
80 
81 
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 /// Destructor
85 
86 RooAbsCategory::~RooAbsCategory()
87 {
88 
89 }
90 
91 
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 /// Return index number of current state
95 
96 Int_t RooAbsCategory::getIndex() const
97 {
98  if (isValueDirty() || isShapeDirty()) {
99  _value = traceEval() ;
100 
101  clearValueDirty() ;
102  clearShapeDirty() ;
103  }
104 
105  return _value.getVal() ;
106 }
107 
108 
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 /// Return label string of current state
112 
113 const char* RooAbsCategory::getLabel() const
114 {
115  if (isValueDirty() || isShapeDirty()) {
116  _value = traceEval() ;
117 
118  clearValueDirty() ;
119  clearShapeDirty() ;
120  }
121 
122  const char* ret = _value.GetName() ;
123  // If label is not set, do it now on the fly
124  if (ret==0) {
125  _value.SetName(lookupType(_value.getVal())->GetName()) ;
126  }
127  return _value.GetName() ;
128 }
129 
130 
131 
132 ////////////////////////////////////////////////////////////////////////////////
133 /// Recalculate current value and check validity of new result.
134 
135 RooCatType RooAbsCategory::traceEval() const
136 {
137  RooCatType value = evaluate() ;
138 
139  // Standard tracing code goes here
140  if (!isValid(value)) {
141  }
142 
143  // Call optional subclass tracing code
144  traceEvalHook(value) ;
145 
146  return value ;
147 }
148 
149 
150 ////////////////////////////////////////////////////////////////////////////////
151 /// Equality operator with a integer (compares with state index number)
152 
153 Bool_t RooAbsCategory::operator==(Int_t index) const
154 {
155  return (index==getIndex()) ;
156 }
157 
158 
159 
160 ////////////////////////////////////////////////////////////////////////////////
161 /// Equality operator with a string (compares with state label string)
162 
163 Bool_t RooAbsCategory::operator==(const char* label) const
164 {
165  return strcmp(label, getLabel()) == 0;
166 }
167 
168 
169 
170 ////////////////////////////////////////////////////////////////////////////////
171 /// Equality operator with another RooAbsArg. Only functional
172 /// is also a RooAbsCategory, will return true if index is the same
173 
174 Bool_t RooAbsCategory::operator==(const RooAbsArg& other)
175 {
176  const RooAbsCategory* otherCat = dynamic_cast<const RooAbsCategory*>(&other) ;
177  return otherCat ? operator==(otherCat->getIndex()) : kFALSE ;
178 }
179 
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 
183 Bool_t RooAbsCategory::isIdentical(const RooAbsArg& other, Bool_t assumeSameType)
184 {
185  if (!assumeSameType) {
186  const RooAbsCategory* otherCat = dynamic_cast<const RooAbsCategory*>(&other) ;
187  return otherCat ? operator==(otherCat->getIndex()) : kFALSE ;
188  } else {
189  return getIndex()==((RooAbsCategory&)other).getIndex() ;
190  }
191 }
192 
193 
194 
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 /// Check if state with given index is defined
198 
199 Bool_t RooAbsCategory::isValidIndex(Int_t index) const
200 {
201  return lookupType(index,kFALSE)?kTRUE:kFALSE ;
202 }
203 
204 
205 
206 ////////////////////////////////////////////////////////////////////////////////
207 /// Check if state with given name is defined
208 
209 Bool_t RooAbsCategory::isValidLabel(const char* label) const
210 {
211  return lookupType(label)?kTRUE:kFALSE ;
212 }
213 
214 
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 /// Define a new state with given name. The lowest available
218 /// integer number is assigned as index value
219 
220 const RooCatType* RooAbsCategory::defineType(const char* label)
221 {
222  // Find lowest unused index
223  Int_t index(-1) ;
224  while(lookupType(++index,kFALSE)) ;
225 
226  // Assign this index to given label
227  return defineType(label,index) ;
228 }
229 
230 
231 ////////////////////////////////////////////////////////////////////////////////
232 /// Internal version of defineType that does not check if type
233 /// already exists
234 
235 const RooCatType* RooAbsCategory::defineTypeUnchecked(const char* label, Int_t index)
236 {
237  _types.push_back(new RooCatType(label, index));
238 
239  if (_types.size() == 1) _value = *_types.back();
240  setShapeDirty();
241 
242  return _types.back();
243 }
244 
245 
246 
247 ////////////////////////////////////////////////////////////////////////////////
248 /// Define new state with given name and index number.
249 
250 const RooCatType* RooAbsCategory::defineType(const char* label, Int_t index)
251 {
252  if (isValidIndex(index)) {
253  coutE(InputArguments) << "RooAbsCategory::defineType(" << GetName() << "): index "
254  << index << " already assigned" << endl ;
255  return 0 ;
256  }
257 
258  if (isValidLabel(label)) {
259  coutE(InputArguments) << "RooAbsCategory::defineType(" << GetName() << "): label "
260  << label << " already assigned or not allowed" << endl ;
261  return 0 ;
262  }
263 
264  return defineTypeUnchecked(label,index) ;
265 }
266 
267 
268 
269 ////////////////////////////////////////////////////////////////////////////////
270 /// Delete all currently defined states
271 
272 void RooAbsCategory::clearTypes()
273 {
274  for (auto cat : _types)
275  delete cat;
276  _types.clear();
277  _value = RooCatType("",0) ;
278  setShapeDirty() ;
279 }
280 
281 
282 
283 ////////////////////////////////////////////////////////////////////////////////
284 /// Find our type that matches the specified type, or return 0 for no match.
285 
286 const RooCatType* RooAbsCategory::lookupType(const RooCatType &other, Bool_t printError) const
287 {
288  for (const auto type : _types) {
289  if (*type == other) return type; // delegate comparison to RooCatType
290  }
291 
292  if (printError) {
293  coutE(InputArguments) << ClassName() << "::" << GetName() << ":lookupType: no match for ";
294  if (dologE(InputArguments)) {
295  other.printStream(ccoutE(InputArguments),kName|kValue,kSingleLine);
296  }
297  }
298  return 0 ;
299 }
300 
301 
302 
303 ////////////////////////////////////////////////////////////////////////////////
304 /// Find our type corresponding to the specified index, or return 0 for no match.
305 
306 const RooCatType* RooAbsCategory::lookupType(Int_t index, Bool_t printError) const
307 {
308  for (const auto type : _types) {
309  if(*type == index) return type; // delegate comparison to RooCatType
310  }
311  if (printError) {
312  coutE(InputArguments) << ClassName() << "::" << GetName() << ":lookupType: no match for index "
313  << index << endl;
314  }
315  return 0 ;
316 }
317 
318 
319 
320 ////////////////////////////////////////////////////////////////////////////////
321 /// Find our type corresponding to the specified label, or return 0 for no match.
322 
323 const RooCatType* RooAbsCategory::lookupType(const char* label, Bool_t printError) const
324 {
325  for (const auto type : _types) {
326  if(*type == label) return type; // delegate comparison to RooCatType
327  }
328 
329  // Try if label represents integer number
330  char* endptr ;
331  Int_t idx=strtol(label,&endptr,10) ;
332  if (endptr==label+strlen(label)) {
333  for (const auto type : _types) {
334  if(*type == idx) return type; // delegate comparison to RooCatType
335  }
336  }
337 
338  if (printError) {
339  coutE(InputArguments) << ClassName() << "::" << GetName() << ":lookupType: no match for label "
340  << label << endl;
341  }
342  return 0 ;
343 }
344 
345 
346 
347 ////////////////////////////////////////////////////////////////////////////////
348 /// Check if current value is a valid state
349 
350 Bool_t RooAbsCategory::isValid() const
351 {
352  return isValid(_value) ;
353 }
354 
355 
356 
357 ////////////////////////////////////////////////////////////////////////////////
358 /// Check if given state is defined for this object
359 
360 Bool_t RooAbsCategory::isValid(const RooCatType& value) const
361 {
362  return isValidIndex(value.getVal()) ;
363 }
364 
365 
366 
367 ////////////////////////////////////////////////////////////////////////////////
368 /// Create a table matching the shape of this category
369 
370 Roo1DTable* RooAbsCategory::createTable(const char *label) const
371 {
372  return new Roo1DTable(GetName(),label,*this) ;
373 }
374 
375 
376 
377 ////////////////////////////////////////////////////////////////////////////////
378 /// Read object contents from stream (dummy for now)
379 
380 Bool_t RooAbsCategory::readFromStream(istream&, Bool_t, Bool_t)
381 {
382  return kFALSE ;
383 }
384 
385 
386 
387 ////////////////////////////////////////////////////////////////////////////////
388 /// Write object contents to ostream
389 
390 void RooAbsCategory::writeToStream(ostream& os, Bool_t /* compact */) const
391 {
392  os << getLabel() ;
393 }
394 
395 
396 
397 ////////////////////////////////////////////////////////////////////////////////
398 /// Print value (label name)
399 
400 void RooAbsCategory::printValue(ostream& os) const
401 {
402  os << getLabel() << "(idx = " << getIndex() << ")" << endl ;
403 }
404 
405 
406 
407 ////////////////////////////////////////////////////////////////////////////////
408 /// Print info about this object to the specified stream. In addition to the info
409 /// from RooAbsArg::printStream() we add:
410 ///
411 /// Shape : label, index, defined types
412 
413 void RooAbsCategory::printMultiline(ostream& os, Int_t contents, Bool_t verbose, TString indent) const
414 {
415  RooAbsArg::printMultiline(os,contents,verbose,indent);
416 
417  os << indent << "--- RooAbsCategory ---" << endl;
418  if (_types.empty()) {
419  os << indent << " ** No values defined **" << endl;
420  return;
421  }
422  os << indent << " Value is \"" << getLabel() << "\" (" << getIndex() << ")" << endl;
423  os << indent << " Has the following possible values:" << endl;
424  indent.Append(" ");
425  for (const auto type : _types) {
426  os << indent;
427  type->printStream(os,kName|kValue,kSingleLine,indent);
428  }
429 }
430 
431 
432 
433 ////////////////////////////////////////////////////////////////////////////////
434 /// Attach the category index and label to as branches to the given vector store
435 
436 void RooAbsCategory::attachToVStore(RooVectorDataStore& vstore)
437 {
438  RooVectorDataStore::CatVector* cv = vstore.addCategory(this) ;
439  cv->setBuffer(&_value) ;
440 }
441 
442 
443 
444 
445 ////////////////////////////////////////////////////////////////////////////////
446 /// Attach the category index and label to as branches to the given
447 /// TTree. The index field will be attached as integer with name
448 /// <name>_idx, the label field will be attached as char[] with label
449 /// <name>_lbl.
450 
451 void RooAbsCategory::attachToTree(TTree& t, Int_t bufSize)
452 {
453  // First check if there is an integer branch matching the category name
454  TString cleanName(cleanBranchName()) ;
455  TBranch* branch = t.GetBranch(cleanName) ;
456  if (branch) {
457 
458  TString typeName(((TLeaf*)branch->GetListOfLeaves()->At(0))->GetTypeName()) ;
459  if (!typeName.CompareTo("Int_t")) {
460  // Imported TTree: attach only index field as branch
461 
462  coutI(DataHandling) << "RooAbsCategory::attachToTree(" << GetName() << ") TTree branch " << GetName()
463  << " will be interpreted as category index" << endl ;
464 
465  t.SetBranchAddress(cleanName,&((Int_t&)_value._value)) ;
466  setAttribute("INTIDXONLY_TREE_BRANCH",kTRUE) ;
467  _treeVar = kTRUE ;
468  return ;
469  } else if (!typeName.CompareTo("UChar_t")) {
470  coutI(DataHandling) << "RooAbsReal::attachToTree(" << GetName() << ") TTree UChar_t branch " << GetName()
471  << " will be interpreted as category index" << endl ;
472  t.SetBranchAddress(cleanName,&_byteValue) ;
473  setAttribute("UCHARIDXONLY_TREE_BRANCH",kTRUE) ;
474  _treeVar = kTRUE ;
475  return ;
476  }
477 
478  if (branch->GetCompressionLevel()<0) {
479  cxcoutD(DataHandling) << "RooAbsCategory::attachToTree(" << GetName() << ") Fixing compression level of branch " << GetName() << endl ;
480  branch->SetCompressionLevel(ROOT::RCompressionSetting::EDefaults::kUseGlobal % 100) ;
481  }
482  }
483 
484  // Native TTree: attach both index and label of category as branches
485  TString idxName(cleanName) ;
486  TString lblName(cleanName) ;
487  idxName.Append("_idx") ;
488  lblName.Append("_lbl") ;
489 
490  // First determine if branch is taken
491  if ((branch = t.GetBranch(idxName))) {
492 
493  t.SetBranchAddress(idxName,&((Int_t&)_value._value)) ;
494  if (branch->GetCompressionLevel()<0) {
495  cxcoutD(Contents) << "RooAbsCategory::attachToTree(" << GetName() << ") Fixing compression level of branch " << idxName << endl ;
496  branch->SetCompressionLevel(ROOT::RCompressionSetting::EDefaults::kUseGlobal % 100) ;
497  }
498 
499  } else {
500  TString format(idxName);
501  format.Append("/I");
502  void* ptr = &(_value._value) ;
503  branch = t.Branch(idxName, ptr, (const Text_t*)format, bufSize);
504  branch->SetCompressionLevel(ROOT::RCompressionSetting::EDefaults::kUseGlobal % 100) ;
505  }
506 
507  // First determine if branch is taken
508  if ((branch = t.GetBranch(lblName))) {
509 
510  t.SetBranchAddress(lblName,_value._label) ;
511  if (branch->GetCompressionLevel()<0) {
512  cxcoutD(DataHandling) << "RooAbsCategory::attachToTree(" << GetName() << ") Fixing compression level of branch " << lblName << endl ;
513  branch->SetCompressionLevel(ROOT::RCompressionSetting::EDefaults::kUseGlobal % 100) ;
514  }
515 
516  } else {
517  TString format(lblName);
518  format.Append("/C");
519  void* ptr = _value._label ;
520  branch = t.Branch(lblName, ptr, (const Text_t*)format, bufSize);
521  branch->SetCompressionLevel(ROOT::RCompressionSetting::EDefaults::kUseGlobal % 100) ;
522  }
523 
524 }
525 
526 
527 
528 ////////////////////////////////////////////////////////////////////////////////
529 /// Fill tree branches associated with current object with current value
530 
531 void RooAbsCategory::fillTreeBranch(TTree& t)
532 {
533  TString idxName(GetName()) ;
534  TString lblName(GetName()) ;
535  idxName.Append("_idx") ;
536  lblName.Append("_lbl") ;
537 
538  // First determine if branch is taken
539  TBranch* idxBranch = t.GetBranch(idxName) ;
540  TBranch* lblBranch = t.GetBranch(lblName) ;
541  if (!idxBranch||!lblBranch) {
542  coutF(DataHandling) << "RooAbsCategory::fillTreeBranch(" << GetName() << ") ERROR: not attached to tree" << endl ;
543  assert(0) ;
544  }
545 
546  idxBranch->Fill() ;
547  lblBranch->Fill() ;
548 }
549 
550 
551 
552 ////////////////////////////////////////////////////////////////////////////////
553 /// (De)activate associate tree branch
554 
555 void RooAbsCategory::setTreeBranchStatus(TTree& t, Bool_t active)
556 {
557  TBranch* branch = t.GetBranch(Form("%s_idx",GetName())) ;
558  if (branch) {
559  t.SetBranchStatus(Form("%s_idx",GetName()),active?1:0) ;
560  t.SetBranchStatus(Form("%s_lbl",GetName()),active?1:0) ;
561  }
562 }
563 
564 
565 
566 ////////////////////////////////////////////////////////////////////////////////
567 /// Explicitly synchronize RooAbsCategory internal cache
568 
569 void RooAbsCategory::syncCache(const RooArgSet*)
570 {
571  getIndex() ;
572 }
573 
574 
575 
576 ////////////////////////////////////////////////////////////////////////////////
577 /// Copy the cached value from given source and raise dirty flag.
578 /// It is the callers responsability to ensure that the sources
579 /// cache is clean(valid) before this function is called, e.g. by
580 /// calling syncCache() on the source.
581 
582 void RooAbsCategory::copyCache(const RooAbsArg *source, Bool_t /*valueOnly*/, Bool_t setValDirty)
583 {
584  RooAbsCategory *other = static_cast<RooAbsCategory *>(const_cast<RooAbsArg *>(source));
585 
586  if (!_treeVar) {
587  _value = other->_value;
588  } else {
589  if (source->getAttribute("INTIDXONLY_TREE_BRANCH")) {
590  // Lookup cat state from other-index because label is missing
591  const RooCatType *type = lookupType(other->_value._value);
592  if (type) {
593  _value = *type;
594  } else {
595  coutE(DataHandling) << "RooAbsCategory::copyCache(" << GetName() << ") ERROR: index of source arg "
596  << source->GetName() << " is invalid (" << other->_value._value
597  << "), value not updated" << endl;
598  }
599  } else if (source->getAttribute("UCHARIDXONLY_TREE_BRANCH")) {
600  // Lookup cat state from other-index because label is missing
601  Int_t tmp = other->_byteValue;
602  const RooCatType *type = lookupType(tmp);
603  if (type) {
604  _value = *type;
605  } else {
606  coutE(DataHandling) << "RooAbsCategory::copyCache(" << GetName() << ") ERROR: index of source arg "
607  << source->GetName() << " is invalid (" << tmp << "), value not updated" << endl;
608  }
609  }
610  }
611 
612  if (setValDirty) {
613  setValueDirty();
614  }
615 }
616 
617 ////////////////////////////////////////////////////////////////////////////////
618 /// Return state definition of ordinal nth defined state,
619 /// needed by the generator mechanism.
620 
621 const RooCatType* RooAbsCategory::getOrdinal(UInt_t n, const char* /*rangeName*/) const
622 {
623  return _types.size() > n ? _types[n] : nullptr;
624 }
625 
626 
627 
628 ////////////////////////////////////////////////////////////////////////////////
629 /// Create a RooCategory fundamental object with our properties.
630 
631 RooAbsArg *RooAbsCategory::createFundamental(const char* newname) const
632 {
633  // Add and precalculate new category column
634  RooCategory *fund= new RooCategory(newname?newname:GetName(),GetTitle()) ;
635 
636  // Copy states
637  for (const auto type : _types) {
638  ((RooAbsCategory*)fund)->defineType(type->GetName(), type->getVal());
639  }
640 
641  return fund;
642 }
643 
644 
645 
646 ////////////////////////////////////////////////////////////////////////////////
647 /// Determine if category has 2 or 3 states with index values -1,0,1
648 
649 Bool_t RooAbsCategory::isSignType(Bool_t mustHaveZero) const
650 {
651  if (numTypes()>3||numTypes()<2) return kFALSE ;
652  if (mustHaveZero&&numTypes()!=3) return kFALSE ;
653 
654  Bool_t ret(kTRUE) ;
655  for (const auto type : _types) {
656  if (abs(type->getVal())>1) ret=kFALSE ;
657  }
658 
659  return ret ;
660 }