// RooAbsCategory is the common abstract base class for objects that
// represent a discrete value with a finite number of states. Each
// state consist of a label/index pair, which is stored in a
// RooCatType object.
//
// Implementation of RooAbsCategory may be derived, there no interface
// is provided to modify the contents, nor a public interface to define states.
// END_HTML
#include "RooFit.h"
#include "Riostream.h"
#include "Riostream.h"
#include <stdlib.h>
#include "TString.h"
#include "TH1.h"
#include "TTree.h"
#include "TLeaf.h"
#include "RooAbsCategory.h"
#include "RooArgSet.h"
#include "Roo1DTable.h"
#include "RooCategory.h"
#include "RooMsgService.h"
#include "RooVectorDataStore.h"
ClassImp(RooAbsCategory)
;
RooAbsCategory::RooAbsCategory(const char *name, const char *title) :
RooAbsArg(name,title), _value("NULL",0), _treeVar(kFALSE)
{
_typeIter = _types.MakeIterator() ;
setValueDirty() ;
setShapeDirty() ;
}
RooAbsCategory::RooAbsCategory(const RooAbsCategory& other,const char* name) :
RooAbsArg(other,name), _value(other._value), _treeVar(other._treeVar)
{
_typeIter = _types.MakeIterator() ;
other._typeIter->Reset() ;
TObject* obj ;
while ((obj=other._typeIter->Next())) {
_types.Add(obj->Clone()) ;
}
setValueDirty() ;
setShapeDirty() ;
}
RooAbsCategory::~RooAbsCategory()
{
delete _typeIter ;
_types.Delete() ;
}
Int_t RooAbsCategory::getIndex() const
{
if (isValueDirty() || isShapeDirty()) {
_value = traceEval() ;
clearValueDirty() ;
clearShapeDirty() ;
}
return _value.getVal() ;
}
const char* RooAbsCategory::getLabel() const
{
if (isValueDirty() || isShapeDirty()) {
_value = traceEval() ;
clearValueDirty() ;
clearShapeDirty() ;
}
const char* ret = _value.GetName() ;
if (ret==0) {
_value.SetName(lookupType(_value.getVal())->GetName()) ;
}
return _value.GetName() ;
}
RooCatType RooAbsCategory::traceEval() const
{
RooCatType value = evaluate() ;
if (!isValid(value)) {
}
traceEvalHook(value) ;
return value ;
}
TIterator* RooAbsCategory::typeIterator() const
{
return _types.MakeIterator() ;
}
Bool_t RooAbsCategory::operator==(Int_t index) const
{
return (index==getIndex()) ;
}
Bool_t RooAbsCategory::operator==(const char* label) const
{
return !TString(label).CompareTo(getLabel()) ;
}
Bool_t RooAbsCategory::operator==(const RooAbsArg& other)
{
const RooAbsCategory* otherCat = dynamic_cast<const RooAbsCategory*>(&other) ;
return otherCat ? operator==(otherCat->getIndex()) : kFALSE ;
}
Bool_t RooAbsCategory::isValidIndex(Int_t index) const
{
return lookupType(index,kFALSE)?kTRUE:kFALSE ;
}
Bool_t RooAbsCategory::isValidLabel(const char* label) const
{
return lookupType(label)?kTRUE:kFALSE ;
}
const RooCatType* RooAbsCategory::defineType(const char* label)
{
Int_t index(-1) ;
while(lookupType(++index,kFALSE)) ;
return defineType(label,index) ;
}
const RooCatType* RooAbsCategory::defineTypeUnchecked(const char* label, Int_t index)
{
Bool_t first = _types.GetEntries()?kFALSE:kTRUE ;
RooCatType *newType = new RooCatType(label,index) ;
_types.Add(newType) ;
if (first) _value = RooCatType(label,index) ;
setShapeDirty() ;
return newType ;
}
const RooCatType* RooAbsCategory::defineType(const char* label, Int_t index)
{
if (isValidIndex(index)) {
coutE(InputArguments) << "RooAbsCategory::defineType(" << GetName() << "): index "
<< index << " already assigned" << endl ;
return 0 ;
}
if (isValidLabel(label)) {
coutE(InputArguments) << "RooAbsCategory::defineType(" << GetName() << "): label "
<< label << " already assigned or not allowed" << endl ;
return 0 ;
}
return defineTypeUnchecked(label,index) ;
}
void RooAbsCategory::clearTypes()
{
_types.Delete() ;
_value = RooCatType("",0) ;
setShapeDirty() ;
}
const RooCatType* RooAbsCategory::lookupType(const RooCatType &other, Bool_t printError) const
{
RooCatType* type ;
_typeIter->Reset() ;
while((type=(RooCatType*)_typeIter->Next())){
if((*type) == other) return type;
}
if (printError) {
coutE(InputArguments) << ClassName() << "::" << GetName() << ":lookupType: no match for ";
if (dologE(InputArguments)) {
other.printStream(ccoutE(InputArguments),kName|kValue,kSingleLine);
}
}
return 0 ;
}
const RooCatType* RooAbsCategory::lookupType(Int_t index, Bool_t printError) const
{
RooCatType* type ;
_typeIter->Reset() ;
while((type=(RooCatType*)_typeIter->Next())){
if((*type) == index) return type;
}
if (printError) {
coutE(InputArguments) << ClassName() << "::" << GetName() << ":lookupType: no match for index "
<< index << endl;
}
return 0 ;
}
const RooCatType* RooAbsCategory::lookupType(const char* label, Bool_t printError) const
{
RooCatType* type ;
_typeIter->Reset() ;
while((type=(RooCatType*)_typeIter->Next())){
if((*type) == label) return type;
}
char* endptr ;
Int_t idx=strtol(label,&endptr,10) ;
if (endptr==label+strlen(label)) {
_typeIter->Reset() ;
while((type=(RooCatType*)_typeIter->Next())){
if((*type) == idx) return type;
}
}
if (printError) {
coutE(InputArguments) << ClassName() << "::" << GetName() << ":lookupType: no match for label "
<< label << endl;
}
return 0 ;
}
Bool_t RooAbsCategory::isValid() const
{
return isValid(_value) ;
}
Bool_t RooAbsCategory::isValid(const RooCatType& value) const
{
return isValidIndex(value.getVal()) ;
}
Roo1DTable* RooAbsCategory::createTable(const char *label) const
{
return new Roo1DTable(GetName(),label,*this) ;
}
Bool_t RooAbsCategory::readFromStream(istream&, Bool_t, Bool_t)
{
return kFALSE ;
}
void RooAbsCategory::writeToStream(ostream& os, Bool_t compact) const
{
if (compact) {
os << getLabel() ;
} else {
os << getLabel() ;
}
}
void RooAbsCategory::printValue(ostream& os) const
{
os << getLabel() << "(idx = " << getIndex() << ")" << endl ;
}
void RooAbsCategory::printMultiline(ostream& os, Int_t contents, Bool_t verbose, TString indent) const
{
RooAbsArg::printMultiline(os,contents,verbose,indent);
os << indent << "--- RooAbsCategory ---" << endl;
if (_types.GetEntries()==0) {
os << indent << " ** No values defined **" << endl;
return;
}
os << indent << " Value is \"" << getLabel() << "\" (" << getIndex() << ")" << endl;
os << indent << " Has the following possible values:" << endl;
indent.Append(" ");
RooCatType *type;
_typeIter->Reset() ;
while((type=(RooCatType*)_typeIter->Next())) {
os << indent;
type->printStream(os,kName|kValue,kSingleLine,indent);
}
}
void RooAbsCategory::attachToVStore(RooVectorDataStore& vstore)
{
RooVectorDataStore::CatVector* cv = vstore.addCategory(this) ;
cv->setBuffer(&_value) ;
}
void RooAbsCategory::attachToTree(TTree& t, Int_t bufSize)
{
TString cleanName(cleanBranchName()) ;
TBranch* branch = t.GetBranch(cleanName) ;
if (branch) {
TString typeName(((TLeaf*)branch->GetListOfLeaves()->At(0))->GetTypeName()) ;
if (!typeName.CompareTo("Int_t")) {
coutI(DataHandling) << "RooAbsCategory::attachToTree(" << GetName() << ") TTree branch " << GetName()
<< " will be interpreted as category index" << endl ;
t.SetBranchAddress(cleanName,&((Int_t&)_value._value)) ;
setAttribute("INTIDXONLY_TREE_BRANCH",kTRUE) ;
_treeVar = kTRUE ;
return ;
} else if (!typeName.CompareTo("UChar_t")) {
coutI(DataHandling) << "RooAbsReal::attachToTree(" << GetName() << ") TTree UChar_t branch " << GetName()
<< " will be interpreted as category index" << endl ;
t.SetBranchAddress(cleanName,&_byteValue) ;
setAttribute("UCHARIDXONLY_TREE_BRANCH",kTRUE) ;
_treeVar = kTRUE ;
return ;
}
if (branch->GetCompressionLevel()<0) {
cxcoutD(DataHandling) << "RooAbsCategory::attachToTree(" << GetName() << ") Fixing compression level of branch " << GetName() << endl ;
branch->SetCompressionLevel(1) ;
}
}
TString idxName(cleanName) ;
TString lblName(cleanName) ;
idxName.Append("_idx") ;
lblName.Append("_lbl") ;
if ((branch = t.GetBranch(idxName))) {
t.SetBranchAddress(idxName,&((Int_t&)_value._value)) ;
if (branch->GetCompressionLevel()<0) {
cxcoutD(Contents) << "RooAbsCategory::attachToTree(" << GetName() << ") Fixing compression level of branch " << idxName << endl ;
branch->SetCompressionLevel(1) ;
}
} else {
TString format(idxName);
format.Append("/I");
void* ptr = &(_value._value) ;
branch = t.Branch(idxName, ptr, (const Text_t*)format, bufSize);
branch->SetCompressionLevel(1) ;
}
if ((branch = t.GetBranch(lblName))) {
t.SetBranchAddress(lblName,_value._label) ;
if (branch->GetCompressionLevel()<0) {
cxcoutD(DataHandling) << "RooAbsCategory::attachToTree(" << GetName() << ") Fixing compression level of branch " << lblName << endl ;
branch->SetCompressionLevel(1) ;
}
} else {
TString format(lblName);
format.Append("/C");
void* ptr = _value._label ;
branch = t.Branch(lblName, ptr, (const Text_t*)format, bufSize);
branch->SetCompressionLevel(1) ;
}
}
void RooAbsCategory::fillTreeBranch(TTree& t)
{
TString idxName(GetName()) ;
TString lblName(GetName()) ;
idxName.Append("_idx") ;
lblName.Append("_lbl") ;
TBranch* idxBranch = t.GetBranch(idxName) ;
TBranch* lblBranch = t.GetBranch(lblName) ;
if (!idxBranch||!lblBranch) {
coutF(DataHandling) << "RooAbsCategory::fillTreeBranch(" << GetName() << ") ERROR: not attached to tree" << endl ;
assert(0) ;
}
idxBranch->Fill() ;
lblBranch->Fill() ;
}
void RooAbsCategory::setTreeBranchStatus(TTree& t, Bool_t active)
{
TBranch* branch = t.GetBranch(Form("%s_idx",GetName())) ;
if (branch) {
t.SetBranchStatus(Form("%s_idx",GetName()),active?1:0) ;
t.SetBranchStatus(Form("%s_lbl",GetName()),active?1:0) ;
}
}
void RooAbsCategory::syncCache(const RooArgSet*)
{
getIndex() ;
}
void RooAbsCategory::copyCache(const RooAbsArg* source, Bool_t , Bool_t setValDirty)
{
RooAbsCategory* other = static_cast<RooAbsCategory*>(const_cast<RooAbsArg*>(source)) ;
if (!_treeVar) {
_value = other->_value ;
} else {
if (source->getAttribute("INTIDXONLY_TREE_BRANCH")) {
const RooCatType* type = lookupType(other->_value._value) ;
if (type) {
_value = *type ;
} else {
coutE(DataHandling) << "RooAbsCategory::copyCache(" << GetName()
<< ") ERROR: index of source arg " << source->GetName()
<< " is invalid (" << other->_value._value
<< "), value not updated" << endl ;
}
} if (source->getAttribute("UCHARIDXONLY_TREE_BRANCH")) {
Int_t tmp = other->_byteValue ;
const RooCatType* type = lookupType(tmp) ;
if (type) {
_value = *type ;
} else {
coutE(DataHandling) << "RooAbsCategory::copyCache(" << GetName()
<< ") ERROR: index of source arg " << source->GetName()
<< " is invalid (" << tmp
<< "), value not updated" << endl ;
}
}
}
if (setValDirty) {
setValueDirty() ;
}
}
const RooCatType* RooAbsCategory::getOrdinal(UInt_t n, const char* ) const
{
return (const RooCatType*)_types.At(n);
}
RooAbsArg *RooAbsCategory::createFundamental(const char* newname) const
{
RooCategory *fund= new RooCategory(newname?newname:GetName(),GetTitle()) ;
TIterator* tIter = typeIterator() ;
RooCatType* type ;
while ((type=(RooCatType*)tIter->Next())) {
((RooAbsCategory*)fund)->defineType(type->GetName(),type->getVal()) ;
}
delete tIter;
return fund;
}
Bool_t RooAbsCategory::isSignType(Bool_t mustHaveZero) const
{
if (numTypes()>3||numTypes()<2) return kFALSE ;
if (mustHaveZero&&numTypes()!=3) return kFALSE ;
Bool_t ret(kTRUE) ;
TIterator* tIter = typeIterator() ;
RooCatType* type ;
while((type=(RooCatType*)tIter->Next())) {
if (abs(type->getVal())>1) ret=kFALSE ;
}
delete tIter ;
return ret ;
}