#include "RooFit.h"
#include "TClass.h"
#include "TStopwatch.h"
#include "RooAbsCategoryLValue.h"
#include "RooAbsCategory.h"
#include "RooAbsArg.h"
#include "RooAbsPdf.h"
#include "RooArgSet.h"
#include "RooArgList.h"
#include "RooMsgService.h"
#include "RooCustomizer.h"
#include "Riostream.h"
#include "RooWorkspace.h"
#include "RooGlobalFunc.h"
ClassImp(RooCustomizer)
;
static Int_t init()
{
RooFactoryWSTool::IFace* iface = new RooCustomizer::CustIFace ;
RooFactoryWSTool::registerSpecial("EDIT",iface) ;
return 0 ;
}
static Int_t dummy = init() ;
RooCustomizer::RooCustomizer(const RooAbsArg& pdf, const RooAbsCategoryLValue& masterCat, RooArgSet& splitLeafs, RooArgSet* splitLeafsAll) :
TNamed(pdf.GetName(),pdf.GetTitle()),
_sterile(kFALSE),
_owning(kTRUE),
_masterPdf((RooAbsArg*)&pdf),
_masterCat((RooAbsCategoryLValue*)&masterCat),
_masterBranchList("masterBranchList"),
_masterLeafList("masterLeafList"),
_internalCloneBranchList("cloneBranchList"),
_cloneNodeListAll(splitLeafsAll),
_cloneNodeListOwned(&splitLeafs)
{
_masterBranchList.setHashTableSize(1000) ;
_masterLeafList.setHashTableSize(1000) ;
_cloneBranchList = &_internalCloneBranchList ;
_cloneBranchList->setHashTableSize(1000) ;
initialize() ;
}
RooCustomizer::RooCustomizer(const RooAbsArg& pdf, const char* name) :
TNamed(pdf.GetName(),pdf.GetTitle()),
_sterile(kTRUE),
_owning(kFALSE),
_name(name),
_masterPdf((RooAbsArg*)&pdf),
_masterCat(0),
_masterBranchList("masterBranchList"),
_masterLeafList("masterLeafList"),
_internalCloneBranchList("cloneBranchList"),
_cloneNodeListAll(0),
_cloneNodeListOwned(0)
{
_masterBranchList.setHashTableSize(1000) ;
_masterLeafList.setHashTableSize(1000) ;
_cloneBranchList = &_internalCloneBranchList ;
_cloneBranchList->setHashTableSize(1000) ;
initialize() ;
}
void RooCustomizer::initialize()
{
_masterPdf->leafNodeServerList(&_masterLeafList) ;
_masterPdf->branchNodeServerList(&_masterBranchList) ;
_masterLeafListIter = _masterLeafList.createIterator() ;
_masterBranchListIter = _masterBranchList.createIterator() ;
}
RooCustomizer::~RooCustomizer()
{
delete _masterLeafListIter ;
delete _masterBranchListIter ;
}
void RooCustomizer::splitArgs(const RooArgSet& set, const RooAbsCategory& splitCat)
{
if (_sterile) {
coutE(InputArguments) << "RooCustomizer::splitArgs(" << _name
<< ") ERROR cannot set spitting rules on this sterile customizer" << endl ;
return ;
}
TIterator* iter = set.createIterator() ;
RooAbsArg* arg ;
while((arg=(RooAbsArg*)iter->Next())){
splitArg(*arg,splitCat) ;
}
delete iter ;
}
void RooCustomizer::splitArg(const RooAbsArg& arg, const RooAbsCategory& splitCat)
{
if (_splitArgList.FindObject(arg.GetName())) {
coutE(InputArguments) << "RooCustomizer(" << GetName() << ") ERROR: multiple splitting rules defined for "
<< arg.GetName() << " only using first rule" << endl ;
return ;
}
if (_sterile) {
coutE(InputArguments) << "RooCustomizer::splitArg(" << _name
<< ") ERROR cannot set spitting rules on this sterile customizer" << endl ;
return ;
}
_splitArgList.Add((RooAbsArg*)&arg) ;
_splitCatList.Add((RooAbsCategory*)&splitCat) ;
}
void RooCustomizer::replaceArg(const RooAbsArg& orig, const RooAbsArg& subst)
{
if (_replaceArgList.FindObject(orig.GetName())) {
coutE(InputArguments) << "RooCustomizer(" << GetName() << ") ERROR: multiple replacement rules defined for "
<< orig.GetName() << " only using first rule" << endl ;
return ;
}
_replaceArgList.Add((RooAbsArg*)&orig) ;
_replaceSubList.Add((RooAbsArg*)&subst) ;
}
RooAbsArg* RooCustomizer::build(Bool_t verbose)
{
RooAbsArg* ret = doBuild(_name,verbose) ;
RooArgSet allOwned ;
if (_cloneNodeListOwned) {
allOwned.add(*_cloneNodeListOwned) ;
}
allOwned.add(*_cloneBranchList) ;
allOwned.remove(*ret) ;
if (allOwned.getSize()>0) {
ret->addOwnedComponents(allOwned) ;
}
return ret ;
}
RooAbsArg* RooCustomizer::build(const char* masterCatState, Bool_t verbose)
{
if (_sterile) {
coutE(InputArguments) << "RooCustomizer::build(" << _name
<< ") ERROR cannot use leaf spitting build() on this sterile customizer" << endl ;
return 0 ;
}
if (_masterCat->setLabel(masterCatState)) {
coutE(InputArguments) << "RooCustomizer::build(" << _masterPdf->GetName() << "): ERROR label '" << masterCatState
<< "' not defined for master splitting category " << _masterCat->GetName() << endl ;
return 0 ;
}
return doBuild(masterCatState,verbose) ;
}
RooAbsArg* RooCustomizer::doBuild(const char* masterCatState, Bool_t verbose)
{
RooArgSet masterNodesToBeSplit("masterNodesToBeSplit") ;
RooArgSet masterNodesToBeReplaced("masterNodesToBeReplaced") ;
RooArgSet masterReplacementNodes("masterReplacementNodes") ;
RooArgSet clonedMasterNodes("clonedMasterNodes") ;
masterNodesToBeSplit.setHashTableSize(1000) ;
masterNodesToBeReplaced.setHashTableSize(1000) ;
masterReplacementNodes.setHashTableSize(1000) ;
clonedMasterNodes.setHashTableSize(1000) ;
_masterLeafListIter->Reset() ;
RooAbsArg* node ;
RooArgSet nodeList(_masterLeafList) ;
nodeList.setHashTableSize(1000) ;
nodeList.add(_masterBranchList) ;
TIterator* nIter = nodeList.createIterator() ;
while((node=(RooAbsArg*)nIter->Next())) {
RooAbsArg* theSplitArg = !_sterile?(RooAbsArg*) _splitArgList.FindObject(node->GetName()):0 ;
if (theSplitArg) {
RooAbsCategory* splitCat = (RooAbsCategory*) _splitCatList.At(_splitArgList.IndexOf(theSplitArg)) ;
if (verbose) {
coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
<< "): tree node " << node->GetName() << " is split by category " << splitCat->GetName() << endl ;
}
TString newName(node->GetName()) ;
newName.Append("_") ;
newName.Append(splitCat->getLabel()) ;
RooAbsArg* specNode = _cloneNodeListAll ? _cloneNodeListAll->find(newName) : _cloneNodeListOwned->find(newName) ;
if (specNode) {
clonedMasterNodes.add(*specNode) ;
if (verbose) {
coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
<< ") Adding existing node specialization " << newName << " to clonedMasterNodes" << endl ;
}
TString nameAttrib("ORIGNAME:") ;
nameAttrib.Append(node->GetName()) ;
specNode->setAttribute(nameAttrib) ;
} else {
if (node->isDerived()) {
coutW(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
<< "): WARNING: branch node " << node->GetName() << " is split but has no pre-defined specializations" << endl ;
}
TString newTitle(node->GetTitle()) ;
newTitle.Append(" (") ;
newTitle.Append(splitCat->getLabel()) ;
newTitle.Append(")") ;
RooAbsArg* clone = (RooAbsArg*) node->Clone(newName.Data()) ;
clone->SetTitle(newTitle) ;
TString nameAttrib("ORIGNAME:") ;
nameAttrib.Append(node->GetName()) ;
clone->setAttribute(nameAttrib) ;
clonedMasterNodes.add(*clone) ;
if (_owning) {
_cloneNodeListOwned->addOwned(*clone) ;
} else {
_cloneNodeListOwned->add(*clone) ;
}
if (_cloneNodeListAll) {
_cloneNodeListAll->add(*clone) ;
}
}
masterNodesToBeSplit.add(*node) ;
}
RooAbsArg* ReplaceArg = (RooAbsArg*) _replaceArgList.FindObject(node->GetName()) ;
if (ReplaceArg) {
RooAbsArg* substArg = (RooAbsArg*) _replaceSubList.At(_replaceArgList.IndexOf(ReplaceArg)) ;
if (verbose) {
coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
<< "): tree node " << node->GetName() << " will be replaced by " << substArg->GetName() << endl ;
}
TString nameAttrib("ORIGNAME:") ;
nameAttrib.Append(node->GetName()) ;
substArg->setAttribute(nameAttrib) ;
masterNodesToBeReplaced.add(*node) ;
masterReplacementNodes.add(*substArg) ;
}
}
delete nIter ;
RooArgSet masterBranchesToBeCloned("masterBranchesToBeCloned") ;
masterBranchesToBeCloned.setHashTableSize(1000) ;
_masterBranchListIter->Reset() ;
RooAbsArg* branch ;
while((branch=(RooAbsArg*)_masterBranchListIter->Next())) {
if (masterNodesToBeSplit.find(branch->GetName())) {
if (verbose) {
coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node " << branch->GetName() << " is already split" << endl ;
}
continue ;
}
if (masterNodesToBeReplaced.find(branch->GetName())) {
if (verbose) {
coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node " << branch->GetName() << " is already replaced" << endl ;
}
continue ;
}
if (branch->dependsOn(masterNodesToBeSplit)) {
if (verbose) {
coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node "
<< branch->IsA()->GetName() << "::" << branch->GetName() << " cloned: depends on a split parameter" << endl ;
}
masterBranchesToBeCloned.add(*branch) ;
} else if (branch->dependsOn(masterNodesToBeReplaced)) {
if (verbose) {
coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node "
<< branch->IsA()->GetName() << "::" << branch->GetName() << " cloned: depends on a replaced parameter" << endl ;
}
masterBranchesToBeCloned.add(*branch) ;
}
}
RooAbsArg* cloneTopPdf = 0;
RooArgSet clonedMasterBranches("clonedMasterBranches") ;
clonedMasterBranches.setHashTableSize(1000) ;
TIterator* iter = masterBranchesToBeCloned.createIterator() ;
while((branch=(RooAbsArg*)iter->Next())) {
TString newName(branch->GetName()) ;
newName.Append("_") ;
newName.Append(masterCatState) ;
RooAbsArg* clone = (RooAbsArg*) branch->Clone(newName.Data()) ;
TString nameAttrib("ORIGNAME:") ;
nameAttrib.Append(branch->GetName()) ;
clone->setAttribute(nameAttrib) ;
clonedMasterBranches.add(*clone) ;
if (branch==_masterPdf) cloneTopPdf=(RooAbsArg*)clone ;
}
delete iter ;
if (_owning) {
_cloneBranchList->addOwned(clonedMasterBranches) ;
} else {
_cloneBranchList->add(clonedMasterBranches) ;
}
iter = clonedMasterBranches.createIterator() ;
while((branch=(RooAbsArg*)iter->Next())) {
branch->redirectServers(clonedMasterBranches,kFALSE,kTRUE) ;
branch->redirectServers(clonedMasterNodes,kFALSE,kTRUE) ;
branch->redirectServers(masterReplacementNodes,kFALSE,kTRUE) ;
}
delete iter ;
return cloneTopPdf?cloneTopPdf:_masterPdf ;
}
void RooCustomizer::printName(ostream& os) const
{
os << GetName() ;
}
void RooCustomizer::printTitle(ostream& os) const
{
os << GetTitle() ;
}
void RooCustomizer::printClassName(ostream& os) const
{
os << IsA()->GetName() ;
}
void RooCustomizer::printArgs(ostream& os) const
{
os << "[ masterPdf=" << _masterPdf->GetName() ;
if (_masterCat) {
os << " masterCat=" << _masterCat->GetName() ;
}
os << " ]" ;
}
void RooCustomizer::printMultiline(ostream& os, Int_t , Bool_t , TString indent) const
{
os << indent << "RooCustomizer for " << _masterPdf->GetName() << (_sterile?" (sterile)":"") << endl ;
Int_t i, nsplit = _splitArgList.GetSize() ;
if (nsplit>0) {
os << indent << " Splitting rules:" << endl ;
for (i=0 ; i<nsplit ; i++) {
os << indent << " " << _splitArgList.At(i)->GetName() << " is split by " << _splitCatList.At(i)->GetName() << endl ;
}
}
Int_t nrepl = _replaceArgList.GetSize() ;
if (nrepl>0) {
os << indent << " Replacement rules:" << endl ;
for (i=0 ; i<nrepl ; i++) {
os << indent << " " << _replaceSubList.At(i)->GetName() << " replaces " << _replaceArgList.At(i)->GetName() << endl ;
}
}
return ;
}
void RooCustomizer::setCloneBranchSet(RooArgSet& cloneBranchSet)
{
_cloneBranchList = &cloneBranchSet ;
_cloneBranchList->setHashTableSize(1000) ;
}
std::string RooCustomizer::CustIFace::create(RooFactoryWSTool& ft, const char* typeName, const char* instanceName, std::vector<std::string> args)
{
if (args.size()<2) {
throw string(Form("RooCustomizer::CustIFace::create() ERROR: expect at least 2 arguments for EDIT: the input object and at least one $Replace() rule")) ;
}
if (string(typeName)!="EDIT") {
throw string(Form("RooCustomizer::CustIFace::create() ERROR: unknown type requested: %s",typeName)) ;
}
RooAbsArg* arg = ft.ws().arg(args[0].c_str()) ;
if (!arg) {
throw string(Form("RooCustomizer::CustIFace::create() ERROR: input RooAbsArg %s does not exist",args[0].c_str())) ;
}
RooCustomizer cust(*arg,instanceName) ;
for (unsigned int i=1 ; i<args.size() ; i++) {
char buf[1024] ;
strlcpy(buf,args[i].c_str(),1024) ;
char* sep = strchr(buf,'=') ;
if (!sep) {
throw string(Form("RooCustomizer::CustIFace::create() ERROR: unknown argument: %s, expect form orig=subst",args[i].c_str())) ;
}
*sep = 0 ;
RooAbsArg* orig = ft.ws().arg(buf) ;
RooAbsArg* subst = ft.ws().arg(sep+1) ;
if (!orig) {
throw string(Form("RooCustomizer::CustIFace::create() ERROR: $Replace() input RooAbsArg %s does not exist",buf)) ;
}
if (!subst) {
throw string(Form("RooCustomizer::CustIFace::create() ERROR: $Replace() input RooAbsArg %s does not exist",sep+1)) ;
}
cust.replaceArg(*orig,*subst) ;
}
RooAbsArg* targ = cust.build(kFALSE) ;
if (!targ) {
throw string(Form("RooCustomizer::CustIFace::create() ERROR in customizer build, object %snot created",instanceName)) ;
}
targ->SetName(instanceName) ;
ft.ws().import(*targ,RooFit::Silence()) ;
return string(instanceName) ;
}