Revision 716fb731a3c8c9b583235feddac21006994d9626 authored by Kyle Cranmer on 03 August 2011, 22:09:36 UTC, committed by Kyle Cranmer on 03 August 2011, 22:09:36 UTC
git-svn-id: http://root.cern.ch/svn/root/branches/v5-30-00-patches@40446 27541ba8-7e3a-0410-8455-c3a389f83636
1 parent 0db9ccb
RooWorkspace.cxx
/*****************************************************************************
* Project: RooFit *
* Package: RooFitCore *
* @(#)root/roofitcore:$Id$
* Authors: *
* WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
* *
* Copyright (c) 2000-2005, Regents of the University of California *
* and Stanford University. All rights reserved. *
* *
* Redistribution and use in source and binary forms, *
* with or without modification, are permitted according to the terms *
* listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
*****************************************************************************/
//////////////////////////////////////////////////////////////////////////////
//
// BEGIN_HTML
// The RooWorkspace is a persistable container for RooFit projects. A workspace
// can contain and own variables, p.d.f.s, functions and datasets. All objects
// that live in the workspace are owned by the workspace. The import() method
// enforces consistency of objects upon insertion into the workspace (e.g. no
// duplicate object with the same name are allowed) and makes sure all objects
// in the workspace are connected to each other. Easy accessor methods like
// pdf(), var() and data() allow to refer to the contents of the workspace by
// object name. The entire RooWorkspace can be saved into a ROOT TFile and organises
// the consistent streaming of its contents without duplication.
// <p>
// If a RooWorkspace contains custom classes, i.e. classes not in the
// ROOT distribution, portability of workspaces can be enhanced by
// storing the source code of those classes in the workspace as well.
// This process is also organized by the workspace through the
// importClassCode() method.
// END_HTML
//
#include "RooFit.h"
#include "RooWorkspace.h"
#include "RooAbsPdf.h"
#include "RooRealVar.h"
#include "RooCategory.h"
#include "RooAbsData.h"
#include "RooCmdConfig.h"
#include "RooMsgService.h"
#include "RooConstVar.h"
#include "RooResolutionModel.h"
#include "TInterpreter.h"
#include "TClassTable.h"
#include "TBaseClass.h"
#include "TSystem.h"
#include "TRegexp.h"
#include "RooFactoryWSTool.h"
#include "RooAbsStudy.h"
#include "RooTObjWrap.h"
#include "RooAbsOptTestStatistic.h"
#include "TROOT.h"
#include "TFile.h"
#include "TH1.h"
#include "Api.h"
#include <map>
#include <string>
#include <list>
#include <set>
using namespace std ;
#if ROOT_VERSION_CODE <= ROOT_VERSION(5,19,02)
#include "Api.h"
#endif
#include "TClass.h"
#include "Riostream.h"
#include <string.h>
#include <assert.h>
ClassImp(RooWorkspace)
;
//_____________________________________________________________________________
ClassImp(RooWorkspace::CodeRepo)
;
//_____________________________________________________________________________
ClassImp(RooWorkspace::WSDir)
;
list<string> RooWorkspace::_classDeclDirList ;
list<string> RooWorkspace::_classImplDirList ;
string RooWorkspace::_classFileExportDir = ".wscode.%s.%s" ;
Bool_t RooWorkspace::_autoClass = kFALSE ;
//_____________________________________________________________________________
void RooWorkspace::addClassDeclImportDir(const char* dir)
{
// Add 'dir' to search path for class declaration (header) files, when
// attempting to import class code with importClassClode()
_classDeclDirList.push_back(dir) ;
}
//_____________________________________________________________________________
void RooWorkspace::addClassImplImportDir(const char* dir)
{
// Add 'dir' to search path for class implementation (.cxx) files, when
// attempting to import class code with importClassClode()
_classImplDirList.push_back(dir) ;
}
//_____________________________________________________________________________
void RooWorkspace::setClassFileExportDir(const char* dir)
{
// Specify the name of the directory in which embedded source
// code is unpacked and compiled. The specified string may contain
// one '%s' token which will be substituted by the workspace name
if (dir) {
_classFileExportDir = dir ;
} else {
_classFileExportDir = ".wscode.%s.%s" ;
}
}
//_____________________________________________________________________________
void RooWorkspace::autoImportClassCode(Bool_t flag)
{
// If flag is true, source code of classes not the the ROOT distribution
// is automatically imported if on object of such a class is imported
// in the workspace
_autoClass = flag ;
}
//_____________________________________________________________________________
RooWorkspace::RooWorkspace() : _classes(this), _dir(0), _factory(0), _doExport(kFALSE), _openTrans(kFALSE)
{
// Default constructor
}
//_____________________________________________________________________________
RooWorkspace::RooWorkspace(const char* name, const char* title) :
TNamed(name,title?title:name), _classes(this), _dir(0), _factory(0), _doExport(kFALSE), _openTrans(kFALSE)
{
// Construct empty workspace with given name and title
}
RooWorkspace::RooWorkspace(const char* name, Bool_t doCINTExport) :
TNamed(name,name), _classes(this), _dir(0), _factory(0), _doExport(kFALSE), _openTrans(kFALSE)
{
// Construct empty workspace with given name and option to export reference to all workspace contents to a CINT namespace with the same name
if (doCINTExport) {
exportToCint(name) ;
}
}
//_____________________________________________________________________________
RooWorkspace::RooWorkspace(const RooWorkspace& other) :
TNamed(other), _uuid(other._uuid), _classes(this), _dir(0), _factory(0), _doExport(kFALSE), _openTrans(kFALSE)
{
// Workspace copy constructor
// Copy owned nodes
other._allOwnedNodes.snapshot(_allOwnedNodes,kTRUE) ;
// Copy datasets
TIterator* iter = other._dataList.MakeIterator() ;
TObject* data2 ;
while((data2=iter->Next())) {
_dataList.Add(data2->Clone()) ;
}
delete iter ;
// Copy snapshots
TIterator* iter2 = other._snapshots.MakeIterator() ;
RooArgSet* snap ;
while((snap=(RooArgSet*)iter2->Next())) {
RooArgSet* snapClone = (RooArgSet*) snap->snapshot() ;
snapClone->setName(snap->GetName()) ;
_snapshots.Add(snapClone) ;
}
delete iter2 ;
// Copy named sets
for (map<string,RooArgSet>::const_iterator iter3 = other._namedSets.begin() ; iter3 != other._namedSets.end() ; ++iter3) {
// Make RooArgSet with equivalent content of this workspace
RooArgSet* tmp = (RooArgSet*) _allOwnedNodes.selectCommon(iter3->second) ;
_namedSets[iter3->first].add(*tmp) ;
delete tmp ;
}
// Copy generic objects
TIterator* iter4 = other._genObjects.MakeIterator() ;
TObject* gobj ;
while((gobj=iter4->Next())) {
_genObjects.Add(gobj->Clone()) ;
}
delete iter4 ;
}
//_____________________________________________________________________________
RooWorkspace::~RooWorkspace()
{
// Workspace destructor
// Delete references to variables that were declared in CINT
if (_doExport) {
unExport() ;
}
// Delete contents
_dataList.Delete() ;
if (_dir) {
delete _dir ;
}
_snapshots.Delete() ;
// WVE named sets too?
_genObjects.Delete() ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::import(const char* fileSpec, const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3)
{
// Import a RooAbsArg or RooAbsData set from a workspace in a file. Filespec should be constructed as "filename:wspacename:objectname"
// The arguments will be passed on to the relevant RooAbsArg& or RooAbsData& import call
// Parse file/workspace/objectname specification
char buf[1024] ;
strlcpy(buf,fileSpec,1024) ;
char* filename = strtok(buf,":") ;
char* wsname = strtok(0,":") ;
char* objname = strtok(0,":") ;
// Check that parsing was successful
if (!filename||!wsname||!objname) {
coutE(InputArguments) << "RooWorkspace(" << GetName() << ") ERROR in file specification, expecting for 'filename:wsname:objname'" << endl ;
return kTRUE ;
}
// Check that file can be opened
TFile* f = TFile::Open(filename) ;
if (f==0) {
coutE(InputArguments) << "RooWorkspace(" << GetName() << ") ERROR opening file " << filename << endl ;
return 0 ;
}
// That that file contains workspace
RooWorkspace* w = dynamic_cast<RooWorkspace*>(f->Get(wsname)) ;
if (w==0) {
coutE(InputArguments) << "RooWorkspace(" << GetName() << ") ERROR: No object named " << wsname << " in file " << filename
<< " or object is not a RooWorkspace" << endl ;
return 0 ;
}
// Check that workspace contains object and forward to appropriate import method
RooAbsArg* warg = w->arg(objname) ;
if (warg) {
Bool_t ret = import(*warg,arg1,arg2,arg3) ;
delete f ;
return ret ;
}
RooAbsData* wdata = w->data(objname) ;
if (wdata) {
Bool_t ret = import(*wdata,arg1,arg2,arg3) ;
delete f ;
return ret ;
}
coutE(InputArguments) << "RooWorkspace(" << GetName() << ") ERROR: No RooAbsArg or RooAbsData object named " << objname
<< " in workspace " << wsname << " in file " << filename << endl ;
return kTRUE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::import(const RooArgSet& args, const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3)
{
// Import multiple RooAbsArg objects into workspace. For details on arguments see documentation
// of import() method for single RooAbsArg
TIterator* iter = args.createIterator() ;
RooAbsArg* oneArg ;
Bool_t ret(kFALSE) ;
while((oneArg=(RooAbsArg*)iter->Next())) {
ret |= import(*oneArg,arg1,arg2,arg3) ;
}
return ret ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::import(const RooAbsArg& inArg, const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3)
{
// Import a RooAbsArg object, e.g. function, p.d.f or variable into the workspace. This import function clones the input argument and will
// own the clone. If a composite object is offered for import, e.g. a p.d.f with parameters and observables, the
// complete tree of objects is imported. If any of the _variables_ of a composite object (parameters/observables) are already
// in the workspace the imported p.d.f. is connected to the already existing variables. If any of the _function_ objects (p.d.f, formulas)
// to be imported already exists in the workspace an error message is printed and the import of the entire tree of objects is cancelled.
// Several optional arguments can be provided to modify the import procedure.
//
// Accepted arguments
// -------------------------------
// RenameConflictNodes(const char* suffix) -- Add suffix to branch node name if name conflicts with existing node in workspace
// RenameAllNodes(const char* suffix) -- Add suffix to all branch node names including top level node
// RenameAllVariables(const char* suffix) -- Add suffix to all variables names
// RenameAllVariablesExcept(const char* suffix, const char* exceptionList) -- Add suffix to all variables names, except ones listed
// RenameVariable(const char* inputName, const char* outputName) -- Rename variable as specified upon import.
// RecycleConflictNodes() -- If any of the function objects to be imported already exist in the name space, connect the
// imported expression to the already existing nodes. WARNING: use with care! If function definitions
// do not match, this alters the definition of your function upon import
// Silence() -- Do not issue any info message
//
// The RenameConflictNodes, RenameNodes and RecycleConflictNodes arguments are mutually exclusive. The RenameVariable argument can be repeated
// as often as necessary to rename multiple variables. Alternatively, a single RenameVariable argument can be given with
// two comma separated lists.
RooLinkedList args ;
args.Add((TObject*)&arg1) ;
args.Add((TObject*)&arg2) ;
args.Add((TObject*)&arg3) ;
// Select the pdf-specific commands
RooCmdConfig pc(Form("RooWorkspace::import(%s)",GetName())) ;
pc.defineString("conflictSuffix","RenameConflictNodes",0) ;
pc.defineString("allSuffix","RenameAllNodes",0) ;
pc.defineString("allVarsSuffix","RenameAllVariables",0) ;
pc.defineString("allVarsExcept","RenameAllVariables",1) ;
pc.defineString("varChangeIn","RenameVar",0,"",kTRUE) ;
pc.defineString("varChangeOut","RenameVar",1,"",kTRUE) ;
pc.defineString("factoryTag","FactoryTag",0) ;
pc.defineInt("useExistingNodes","RecycleConflictNodes",0,0) ;
pc.defineInt("silence","Silence",0,0) ;
pc.defineMutex("RenameConflictNodes","RenameAllNodes") ;
pc.defineMutex("RenameConflictNodes","RecycleConflictNodes") ;
pc.defineMutex("RenameAllNodes","RecycleConflictNodes") ;
pc.defineMutex("RenameVariable","RenameAllVariables") ;
// Process and check varargs
pc.process(args) ;
if (!pc.ok(kTRUE)) {
return kTRUE ;
}
// Decode renaming logic into suffix string and boolean for conflictOnly mode
const char* suffixC = pc.getString("conflictSuffix") ;
const char* suffixA = pc.getString("allSuffix") ;
const char* suffixV = pc.getString("allVarsSuffix") ;
const char* exceptVars = pc.getString("allVarsExcept") ;
const char* varChangeIn = pc.getString("varChangeIn") ;
const char* varChangeOut = pc.getString("varChangeOut") ;
Int_t useExistingNodes = pc.getInt("useExistingNodes") ;
Int_t silence = pc.getInt("silence") ;
// Turn zero length strings into null pointers
if (suffixC && strlen(suffixC)==0) suffixC = 0 ;
if (suffixA && strlen(suffixA)==0) suffixA = 0 ;
Bool_t conflictOnly = suffixA ? kFALSE : kTRUE ;
const char* suffix = suffixA ? suffixA : suffixC ;
// Process any change in variable names
map<string,string> varMap ;
if (strlen(varChangeIn)>0) {
// Parse comma separated lists into map<string,string>
char tmp[1024] ;
strlcpy(tmp,varChangeIn,1024) ;
list<string> tmpIn,tmpOut ;
char* ptr = strtok(tmp,",") ;
while (ptr) {
tmpIn.push_back(ptr) ;
ptr = strtok(0,",") ;
}
strlcpy(tmp,varChangeOut,1024) ;
ptr = strtok(tmp,",") ;
while (ptr) {
tmpOut.push_back(ptr) ;
ptr = strtok(0,",") ;
}
list<string>::iterator iin = tmpIn.begin() ;
list<string>::iterator iout = tmpOut.begin() ;
for (;iin!=tmpIn.end() ; ++iin,++iout) {
varMap[*iin]=*iout ;
}
}
// Process RenameAllVariables argument if specified
// First convert exception list if provided
std::set<string> exceptVarNames ;
char tmp[1024] ;
if (exceptVars && strlen(exceptVars)) {
strlcpy(tmp,exceptVars,1024) ;
char* ptr = strtok(tmp,",") ;
while(ptr) {
exceptVarNames.insert(ptr) ;
ptr = strtok(0,",") ;
}
}
if (suffixV != 0 && strlen(suffixV)>0) {
RooArgSet* vars = inArg.getVariables() ;
TIterator* iter = vars->createIterator() ;
RooAbsArg* v ;
while((v=(RooAbsArg*)iter->Next())) {
if (exceptVarNames.find(v->GetName())==exceptVarNames.end()) {
varMap[v->GetName()] = Form("%s_%s",v->GetName(),suffixV) ;
}
}
delete iter ;
delete vars ;
}
// Scan for overlaps with current contents
RooAbsArg* wsarg = _allOwnedNodes.find(inArg.GetName()) ;
// Check for factory specification match
const char* tagIn = inArg.getStringAttribute("factory_tag") ;
const char* tagWs = wsarg ? wsarg->getStringAttribute("factory_tag") : 0 ;
Bool_t factoryMatch = (tagIn && tagWs && !strcmp(tagIn,tagWs)) ;
if (factoryMatch) {
((RooAbsArg&)inArg).setAttribute("RooWorkspace::Recycle") ;
}
if (!suffix && wsarg && !useExistingNodes && !(inArg.isFundamental() && varMap[inArg.GetName()]!="")) {
if (!factoryMatch) {
if (wsarg!=&inArg) {
coutE(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") ERROR importing object named " << inArg.GetName()
<< ": another instance with same name already in the workspace and no conflict resolution protocol specified" << endl ;
return kTRUE ;
} else {
if (!silence) {
coutI(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") Object " << inArg.GetName() << " is already in workspace!" << endl ;
}
return kTRUE ;
}
} else {
coutI(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") Recycling existing object " << inArg.GetName() << " created with identical factory specification" << endl ;
}
}
// Make list of conflicting nodes
RooArgSet conflictNodes ;
RooArgSet branchSet ;
inArg.branchNodeServerList(&branchSet) ;
TIterator* iter = branchSet.createIterator() ;
RooAbsArg* branch ;
while ((branch=(RooAbsArg*)iter->Next())) {
RooAbsArg* wsbranch = _allOwnedNodes.find(branch->GetName()) ;
if (wsbranch && wsbranch!=branch && !branch->getAttribute("RooWorkspace::Recycle") && !useExistingNodes) {
conflictNodes.add(*branch) ;
}
}
delete iter ;
// Terminate here if there are conflicts and no resolution protocol
if (conflictNodes.getSize()>0 && !suffix && !useExistingNodes) {
coutE(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") ERROR object named " << inArg.GetName() << ": component(s) "
<< conflictNodes << " already in the workspace and no conflict resolution protocol specified" << endl ;
return kTRUE ;
}
// Now create a working copy of the incoming object tree
RooArgSet* cloneSet = (RooArgSet*) RooArgSet(inArg).snapshot(kTRUE) ;
RooAbsArg* cloneTop = cloneSet->find(inArg.GetName()) ;
// Mark all nodes for renaming if we are not in conflictOnly mode
if (!conflictOnly) {
conflictNodes.removeAll() ;
conflictNodes.add(branchSet) ;
}
// Mark nodes that are to be renamed with special attribute
TIterator* citer = conflictNodes.createIterator() ;
string topName2 = cloneTop->GetName() ;
RooAbsArg* cnode ;
while ((cnode=(RooAbsArg*)citer->Next())) {
RooAbsArg* cnode2 = cloneSet->find(cnode->GetName()) ;
string origName = cnode2->GetName() ;
cnode2->SetName(Form("%s_%s",cnode2->GetName(),suffix)) ;
cnode2->SetTitle(Form("%s (%s)",cnode2->GetTitle(),suffix)) ;
string tag = Form("ORIGNAME:%s",origName.c_str()) ;
cnode2->setAttribute(tag.c_str()) ;
// Save name of new top level node for later use
if (cnode2==cloneTop) {
topName2 = cnode2->GetName() ;
}
if (!silence) {
coutI(ObjectHandling) << "RooWorkspace::import(" << GetName()
<< ") Resolving name conflict in workspace by changing name of imported node "
<< origName << " to " << cnode2->GetName() << endl ;
}
}
delete citer ;
// Process any change in variable names
if (strlen(varChangeIn)>0 || (suffixV && strlen(suffixV)>0)) {
// Process all changes in variable names
TIterator* cliter = cloneSet->createIterator() ;
while ((cnode=(RooAbsArg*)cliter->Next())) {
if (varMap.find(cnode->GetName())!=varMap.end()) {
string origName = cnode->GetName() ;
cnode->SetName(varMap[cnode->GetName()].c_str()) ;
string tag = Form("ORIGNAME:%s",origName.c_str()) ;
cnode->setAttribute(tag.c_str()) ;
if (!silence) {
coutI(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") Changing name of variable "
<< origName << " to " << cnode->GetName() << " on request" << endl ;
}
if (cnode==cloneTop) {
topName2 = cnode->GetName() ;
}
}
}
delete cliter ;
}
// Now clone again with renaming effective
RooArgSet* cloneSet2 = (RooArgSet*) RooArgSet(*cloneTop).snapshot(kTRUE) ;
RooAbsArg* cloneTop2 = cloneSet2->find(topName2.c_str()) ;
// Make final check list of conflicting nodes
RooArgSet conflictNodes2 ;
RooArgSet branchSet2 ;
inArg.branchNodeServerList(&branchSet) ;
TIterator* iter2 = branchSet2.createIterator() ;
RooAbsArg* branch2 ;
while ((branch2=(RooAbsArg*)iter2->Next())) {
if (_allOwnedNodes.find(branch2->GetName())) {
conflictNodes2.add(*branch2) ;
}
}
delete iter2 ;
// Terminate here if there are conflicts and no resolution protocol
if (conflictNodes2.getSize()) {
coutE(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") ERROR object named " << inArg.GetName() << ": component(s) "
<< conflictNodes2 << " cause naming conflict after conflict resolution protocol was executed" << endl ;
return kTRUE ;
}
// Print a message for each imported node
iter = cloneSet2->createIterator() ;
// Perform any auxiliary imports at this point
RooAbsArg* node ;
while((node=(RooAbsArg*)iter->Next())) {
if (node->importWorkspaceHook(*this)) {
coutE(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") ERROR object named " << node->GetName()
<< " has an error in importing in one or more of its auxiliary objects, aborting" << endl ;
return kTRUE ;
}
}
iter->Reset() ;
RooArgSet recycledNodes ;
RooArgSet nodesToBeDeleted ;
while((node=(RooAbsArg*)iter->Next())) {
if (_autoClass) {
if (!_classes.autoImportClass(node->IsA())) {
coutW(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") WARNING: problems import class code of object "
<< node->IsA()->GetName() << "::" << node->GetName() << ", reading of workspace will require external definition of class" << endl ;
}
}
// Point expensiveObjectCache to copy in this workspace
RooExpensiveObjectCache& oldCache = node->expensiveObjectCache() ;
node->setExpensiveObjectCache(_eocache) ;
_eocache.importCacheObjects(oldCache,node->GetName(),kTRUE) ;
// Check if node is already in workspace (can only happen for variables or identical instances, unless RecycleConflictNodes is specified)
RooAbsArg* wsnode = _allOwnedNodes.find(node->GetName()) ;
if (wsnode) {
// Do not import node, add not to list of nodes that require reconnection
if (!silence && useExistingNodes) {
coutI(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") using existing copy of " << node->IsA()->GetName()
<< "::" << node->GetName() << " for import of " << cloneTop2->IsA()->GetName() << "::"
<< cloneTop2->GetName() << endl ;
}
recycledNodes.add(*_allOwnedNodes.find(node->GetName())) ;
// Delete clone of incoming node
nodesToBeDeleted.addOwned(*node) ;
} else {
// Import node
if (!silence) {
coutI(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") importing " << node->IsA()->GetName() << "::"
<< node->GetName() << endl ;
}
_allOwnedNodes.addOwned(*node) ;
if (_openTrans) {
_sandboxNodes.add(*node) ;
} else {
if (_dir && node->IsA() != RooConstVar::Class()) {
_dir->InternalAppend(node) ;
}
if (_doExport && node->IsA() != RooConstVar::Class()) {
exportObj(node) ;
}
}
}
}
// Release working copy
delete cloneSet ;
// Reconnect any nodes that need to be
if (recycledNodes.getSize()>0) {
iter->Reset() ;
while((node=(RooAbsArg*)iter->Next())) {
node->redirectServers(recycledNodes) ;
}
}
delete iter ;
cloneSet2->releaseOwnership() ;
delete cloneSet2 ;
return kFALSE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::import(RooAbsData& inData, const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3)
{
// Import a dataset (RooDataSet or RooDataHist) into the work space. The workspace will contain a copy of the data
// The dataset and its variables can be renamed upon insertion with the options below
//
// Accepted arguments
// -------------------------------
// Rename(const char* suffix) -- Rename dataset upon insertion
// RenameVariable(const char* inputName, const char* outputName) -- Change names of observables in dataset upon insertion
coutI(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") importing dataset " << inData.GetName() << endl ;
RooLinkedList args ;
args.Add((TObject*)&arg1) ;
args.Add((TObject*)&arg2) ;
args.Add((TObject*)&arg3) ;
// Select the pdf-specific commands
RooCmdConfig pc(Form("RooWorkspace::import(%s)",GetName())) ;
pc.defineString("dsetName","Rename",0,"") ;
pc.defineString("varChangeIn","RenameVar",0,"",kTRUE) ;
pc.defineString("varChangeOut","RenameVar",1,"",kTRUE) ;
// Process and check varargs
pc.process(args) ;
if (!pc.ok(kTRUE)) {
return kTRUE ;
}
// Decode renaming logic into suffix string and boolean for conflictOnly mode
const char* dsetName = pc.getString("dsetName") ;
const char* varChangeIn = pc.getString("varChangeIn") ;
const char* varChangeOut = pc.getString("varChangeOut") ;
// Transform emtpy string into null pointer
if (dsetName && strlen(dsetName)==0) {
dsetName=0 ;
}
// Check that no dataset with target name already exists
if (dsetName && _dataList.FindObject(dsetName)) {
coutE(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") ERROR dataset with name " << dsetName << " already exists in workspace, import aborted" << endl ;
return kTRUE ;
}
if (!dsetName && _dataList.FindObject(inData.GetName())) {
coutE(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") ERROR dataset with name " << inData.GetName() << " already exists in workspace, import aborted" << endl ;
return kTRUE ;
}
// Rename dataset if required
RooAbsData* clone ;
if (dsetName) {
coutI(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") changing name of dataset from " << inData.GetName() << " to " << dsetName << endl ;
clone = (RooAbsData*) inData.Clone(dsetName) ;
} else {
clone = (RooAbsData*) inData.Clone(inData.GetName()) ;
}
// Process any change in variable names
if (strlen(varChangeIn)>0) {
// Parse comma separated lists of variable name changes
char tmp[1024] ;
strlcpy(tmp,varChangeIn,1024) ;
list<string> tmpIn,tmpOut ;
char* ptr = strtok(tmp,",") ;
while (ptr) {
tmpIn.push_back(ptr) ;
ptr = strtok(0,",") ;
}
strlcpy(tmp,varChangeOut,1024) ;
ptr = strtok(tmp,",") ;
while (ptr) {
tmpOut.push_back(ptr) ;
ptr = strtok(0,",") ;
}
list<string>::iterator iin = tmpIn.begin() ;
list<string>::iterator iout = tmpOut.begin() ;
for (; iin!=tmpIn.end() ; ++iin,++iout) {
coutI(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") changing name of dataset observable " << *iin << " to " << *iout << endl ;
clone->changeObservableName(iin->c_str(),iout->c_str()) ;
}
}
// Now import the dataset observables
TIterator* iter = clone->get()->createIterator() ;
RooAbsArg* carg ;
while((carg=(RooAbsArg*)iter->Next())) {
if (!arg(carg->GetName())) {
import(*carg) ;
}
}
delete iter ;
_dataList.Add(clone) ;
if (_dir) {
_dir->InternalAppend(clone) ;
}
if (_doExport) {
exportObj(clone) ;
}
return kFALSE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::defineSet(const char* name, const RooArgSet& aset, Bool_t importMissing)
{
// Define a named RooArgSet with given constituents. If importMissing is true, any constituents
// of aset that are not in the workspace will be imported, otherwise an error is returned
// for missing components
// Check if set was previously defined, if so print warning
map<string,RooArgSet>::iterator i = _namedSets.find(name) ;
if (i!=_namedSets.end()) {
coutW(InputArguments) << "RooWorkspace::defineSet(" << GetName() << ") WARNING redefining previously defined named set " << name << endl ;
}
RooArgSet wsargs ;
// Check all constituents of provided set
TIterator* iter = aset.createIterator() ;
RooAbsArg* sarg ;
while((sarg=(RooAbsArg*)iter->Next())) {
// If missing, either import or report error
if (!arg(sarg->GetName())) {
if (importMissing) {
import(*sarg) ;
} else {
coutE(InputArguments) << "RooWorkspace::defineSet(" << GetName() << ") ERROR set constituent " << sarg->GetName()
<< " is not in workspace and importMissing option is disabled" << endl ;
return kTRUE ;
}
}
wsargs.add(*arg(sarg->GetName())) ;
}
delete iter ;
// Install named set
_namedSets[name].removeAll() ;
_namedSets[name].add(wsargs) ;
return kFALSE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::defineSet(const char* name, const char* contentList)
{
// Define a named set in the work space through a comma separated list of
// names of objects already in the workspace
// Check if set was previously defined, if so print warning
map<string,RooArgSet>::iterator i = _namedSets.find(name) ;
if (i!=_namedSets.end()) {
coutW(InputArguments) << "RooWorkspace::defineSet(" << GetName() << ") WARNING redefining previously defined named set " << name << endl ;
}
RooArgSet wsargs ;
// Check all constituents of provided set
char buf[1024] ;
strlcpy(buf,contentList,1024) ;
char* token = strtok(buf,",") ;
while(token) {
// If missing, either import or report error
if (!arg(token)) {
coutE(InputArguments) << "RooWorkspace::defineSet(" << GetName() << ") ERROR proposed set constituent " << token
<< " is not in workspace" << endl ;
return kTRUE ;
}
wsargs.add(*arg(token)) ;
token = strtok(0,",") ;
}
// Install named set
_namedSets[name].removeAll() ;
_namedSets[name].add(wsargs) ;
return kFALSE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::extendSet(const char* name, const char* newContents)
{
// Define a named set in the work space through a comma separated list of
// names of objects already in the workspace
RooArgSet wsargs ;
// Check all constituents of provided set
char buf[1024] ;
strlcpy(buf,newContents,1024) ;
char* token = strtok(buf,",") ;
while(token) {
// If missing, either import or report error
if (!arg(token)) {
coutE(InputArguments) << "RooWorkspace::defineSet(" << GetName() << ") ERROR proposed set constituent " << token
<< " is not in workspace" << endl ;
return kTRUE ;
}
wsargs.add(*arg(token)) ;
token = strtok(0,",") ;
}
// Extend named set
_namedSets[name].add(wsargs,kTRUE) ;
return kFALSE ;
}
//_____________________________________________________________________________
const RooArgSet* RooWorkspace::set(const char* name)
{
// Return pointer to previously defined named set with given nmame
// If no such set is found a null pointer is returned
map<string,RooArgSet>::iterator i = _namedSets.find(name) ;
return (i!=_namedSets.end()) ? &(i->second) : 0 ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::renameSet(const char* name, const char* newName)
{
// Rename set to a new name
// First check if set exists
if (!set(name)) {
coutE(InputArguments) << "RooWorkspace::renameSet(" << GetName() << ") ERROR a set with name " << name
<< " does not exist" << endl ;
return kTRUE ;
}
// Check if no set exists with new name
if (set(newName)) {
coutE(InputArguments) << "RooWorkspace::renameSet(" << GetName() << ") ERROR a set with name " << newName
<< " already exists" << endl ;
return kTRUE ;
}
// Copy entry under 'name' to 'newName'
_namedSets[newName].add(_namedSets[name]) ;
// Remove entry under old name
_namedSets.erase(name) ;
return kFALSE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::removeSet(const char* name)
{
// Remove a named set from the workspace
// First check if set exists
if (!set(name)) {
coutE(InputArguments) << "RooWorkspace::removeSet(" << GetName() << ") ERROR a set with name " << name
<< " does not exist" << endl ;
return kTRUE ;
}
// Remove set with given name
_namedSets.erase(name) ;
return kFALSE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::startTransaction()
{
// Open an import transaction operations. Returns kTRUE if successful, kFALSE
// if there is already an ongoing transaction
// Check that there was no ongoing transaction
if (_openTrans) {
return kFALSE ;
}
// Open transaction
_openTrans = kTRUE ;
return kTRUE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::cancelTransaction()
{
// Cancel an ongoing import transaction. All objects imported since startTransaction()
// will be removed and the transaction will be terminated. Return kTRUE if cancel operation
// succeeds, return kFALSE if there was no open transaction
// Check that there is an ongoing transaction
if (!_openTrans) {
return kFALSE ;
}
// Delete all objects in the sandbox
TIterator* iter = _sandboxNodes.createIterator() ;
RooAbsArg* tmpArg ;
while((tmpArg=(RooAbsArg*)iter->Next())) {
_allOwnedNodes.remove(*tmpArg) ;
}
delete iter ;
_sandboxNodes.removeAll() ;
// Mark transaction as finished
_openTrans = kFALSE ;
return kTRUE ;
}
Bool_t RooWorkspace::commitTransaction()
{
// Commit an ongoing import transaction. Returns kTRUE if commit succeeded,
// return kFALSE if there was no ongoing transaction
// Check that there is an ongoing transaction
if (!_openTrans) {
return kFALSE ;
}
// Publish sandbox nodes in directory and/or CINT if requested
TIterator* iter = _sandboxNodes.createIterator() ;
RooAbsArg* sarg ;
while((sarg=(RooAbsArg*)iter->Next())) {
if (_dir && sarg->IsA() != RooConstVar::Class()) {
_dir->InternalAppend(sarg) ;
}
if (_doExport && sarg->IsA() != RooConstVar::Class()) {
exportObj(sarg) ;
}
}
delete iter ;
// Remove all commited objects from the sandbox
_sandboxNodes.removeAll() ;
// Mark transaction as finished
_openTrans = kFALSE ;
return kTRUE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::importClassCode(TClass* theClass, Bool_t doReplace)
{
return _classes.autoImportClass(theClass,doReplace) ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::importClassCode(const char* pat, Bool_t doReplace)
{
// Inport code of all classes in the workspace that have a class name
// that matches pattern 'pat' and which are not found to be part of
// the standard ROOT distribution. If doReplace is true any existing
// class code saved in the workspace is replaced
Bool_t ret(kTRUE) ;
TRegexp re(pat,kTRUE) ;
TIterator* iter = componentIterator() ;
RooAbsArg* carg ;
while((carg=(RooAbsArg*)iter->Next())) {
TString className = carg->IsA()->GetName() ;
if (className.Index(re)>=0 && !_classes.autoImportClass(carg->IsA(),doReplace)) {
coutW(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") WARNING: problems import class code of object "
<< carg->IsA()->GetName() << "::" << carg->GetName() << ", reading of workspace will require external definition of class" << endl ;
ret = kFALSE ;
}
}
delete iter ;
return ret ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::saveSnapshot(const char* name, const char* paramNames)
{
// Save snapshot of values and attributes (including "Constant") of parameters 'params'
// If importValues is FALSE, the present values from the object in the workspace are
// saved. If importValues is TRUE, the values of the objects passed in the 'params'
// argument are saved
return saveSnapshot(name,argSet(paramNames),kFALSE) ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::saveSnapshot(const char* name, const RooArgSet& params, Bool_t importValues)
{
// Save snapshot of values and attributes (including "Constant") of parameters 'params'
// If importValues is FALSE, the present values from the object in the workspace are
// saved. If importValues is TRUE, the values of the objects passed in the 'params'
// argument are saved
RooArgSet* actualParams = (RooArgSet*) _allOwnedNodes.selectCommon(params) ;
RooArgSet* snapshot = (RooArgSet*) actualParams->snapshot() ;
delete actualParams ;
snapshot->setName(name) ;
if (importValues) {
*snapshot = params ;
}
RooArgSet* oldSnap = (RooArgSet*) _snapshots.FindObject(name) ;
if (oldSnap) {
coutI(ObjectHandling) << "RooWorkspace::saveSnaphot(" << GetName() << ") replacing previous snapshot with name " << name << endl ;
_snapshots.Remove(oldSnap) ;
delete oldSnap ;
}
_snapshots.Add(snapshot) ;
return kTRUE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::loadSnapshot(const char* name)
{
// Load the values and attributes of the parameters in the snapshot saved with
// the given name
RooArgSet* snap = (RooArgSet*) _snapshots.find(name) ;
if (!snap) {
coutE(ObjectHandling) << "RooWorkspace::loadSnapshot(" << GetName() << ") no snapshot with name " << name << " is available" << endl ;
return kFALSE ;
}
RooArgSet* actualParams = (RooArgSet*) _allOwnedNodes.selectCommon(*snap) ;
*actualParams = *snap ;
delete actualParams ;
return kTRUE ;
}
// //_____________________________________________________________________________
// RooAbsPdf* RooWorkspace::joinPdf(const char* jointPdfName, const char* indexName, const char* inputMapping)
// {
// // Join given list of p.d.f.s into a simultaneous p.d.f with given name. If the named index category
// // does not exist, it is created.
// //
// // Example : joinPdf("simPdf","expIndex","A=pdfA,B=pdfB") ;
// //
// // will return a RooSimultaneous named 'simPdf' with index category 'expIndex' with
// // state names A and B. Pdf 'pdfA' will be associated with state A and pdf 'pdfB'
// // will be associated with state B
// //
// return 0 ;
// }
// //_____________________________________________________________________________
// RooAbsData* RooWorkspace::joinData(const char* jointDataName, const char* indexName, const char* inputMapping)
// {
// // Join given list of dataset into a joint dataset for use with a simultaneous pdf
// // (as e.g. created by joingPdf"
// //
// // Example : joinData("simData","expIndex","A=dataA,B=dataB") ;
// //
// // will return a RooDataSet named 'simData' that consist of the entries of both
// // dataA and dataB. An extra category column 'expIndex' is added that labels
// // each entry with state 'A' and 'B' to indicate the originating dataset
// return 0 ;
// }
//_____________________________________________________________________________
RooAbsPdf* RooWorkspace::pdf(const char* name) const
{
// Retrieve p.d.f (RooAbsPdf) with given name. A null pointer is returned if not found
return dynamic_cast<RooAbsPdf*>(_allOwnedNodes.find(name)) ;
}
//_____________________________________________________________________________
RooAbsReal* RooWorkspace::function(const char* name) const
{
// Retrieve function (RooAbsReal) with given name. Note that all RooAbsPdfs are also RooAbsReals. A null pointer is returned if not found.
return dynamic_cast<RooAbsReal*>(_allOwnedNodes.find(name)) ;
}
//_____________________________________________________________________________
RooRealVar* RooWorkspace::var(const char* name) const
{
// Retrieve real-valued variable (RooRealVar) with given name. A null pointer is returned if not found
return dynamic_cast<RooRealVar*>(_allOwnedNodes.find(name)) ;
}
//_____________________________________________________________________________
RooCategory* RooWorkspace::cat(const char* name) const
{
// Retrieve discrete variable (RooCategory) with given name. A null pointer is returned if not found
return dynamic_cast<RooCategory*>(_allOwnedNodes.find(name)) ;
}
//_____________________________________________________________________________
RooAbsCategory* RooWorkspace::catfunc(const char* name) const
{
// Retrieve discrete function (RooAbsCategory) with given name. A null pointer is returned if not found
return dynamic_cast<RooAbsCategory*>(_allOwnedNodes.find(name)) ;
}
//_____________________________________________________________________________
RooAbsArg* RooWorkspace::arg(const char* name) const
{
// Return RooAbsArg with given name. A null pointer is returned if none is found.
return _allOwnedNodes.find(name) ;
}
//_____________________________________________________________________________
RooArgSet RooWorkspace::argSet(const char* nameList) const
{
// Return set of RooAbsArgs matching to given list of names
RooArgSet ret ;
char tmp[1024] ;
strlcpy(tmp,nameList,1024) ;
char* token = strtok(tmp,",") ;
while(token) {
RooAbsArg* oneArg = arg(token) ;
if (oneArg) {
ret.add(*oneArg) ;
} else {
coutE(InputArguments) << " RooWorkspace::argSet(" << GetName() << ") no RooAbsArg named " << token << " in workspace" << endl ;
}
token = strtok(0,",") ;
}
return ret ;
}
//_____________________________________________________________________________
RooAbsArg* RooWorkspace::fundArg(const char* name) const
{
// Return fundamental (i.e. non-derived) RooAbsArg with given name. Fundamental types
// are e.g. RooRealVar, RooCategory. A null pointer is returned if none is found.
RooAbsArg* tmp = arg(name) ;
if (!tmp) {
return 0 ;
}
return tmp->isFundamental() ? tmp : 0 ;
}
//_____________________________________________________________________________
RooAbsData* RooWorkspace::data(const char* name) const
{
// Retrieve dataset (binned or unbinned) with given name. A null pointer is returned if not found
return (RooAbsData*)_dataList.FindObject(name) ;
}
//_____________________________________________________________________________
RooArgSet RooWorkspace::allVars() const
{
// Return set with all variable objects
RooArgSet ret ;
// Split list of components in pdfs, functions and variables
TIterator* iter = _allOwnedNodes.createIterator() ;
RooAbsArg* parg ;
while((parg=(RooAbsArg*)iter->Next())) {
if (parg->IsA()->InheritsFrom(RooRealVar::Class())) {
ret.add(*parg) ;
}
}
delete iter ;
return ret ;
}
//_____________________________________________________________________________
RooArgSet RooWorkspace::allCats() const
{
// Return set with all category objects
RooArgSet ret ;
// Split list of components in pdfs, functions and variables
TIterator* iter = _allOwnedNodes.createIterator() ;
RooAbsArg* parg ;
while((parg=(RooAbsArg*)iter->Next())) {
if (parg->IsA()->InheritsFrom(RooCategory::Class())) {
ret.add(*parg) ;
}
}
delete iter ;
return ret ;
}
//_____________________________________________________________________________
RooArgSet RooWorkspace::allFunctions() const
{
// Return set with all function objects
RooArgSet ret ;
// Split list of components in pdfs, functions and variables
TIterator* iter = _allOwnedNodes.createIterator() ;
RooAbsArg* parg ;
while((parg=(RooAbsArg*)iter->Next())) {
if (parg->IsA()->InheritsFrom(RooAbsReal::Class()) &&
!parg->IsA()->InheritsFrom(RooAbsPdf::Class()) &&
!parg->IsA()->InheritsFrom(RooConstVar::Class()) &&
!parg->IsA()->InheritsFrom(RooRealVar::Class())) {
ret.add(*parg) ;
}
}
return ret ;
}
//_____________________________________________________________________________
RooArgSet RooWorkspace::allCatFunctions() const
{
// Return set with all category function objects
RooArgSet ret ;
// Split list of components in pdfs, functions and variables
TIterator* iter = _allOwnedNodes.createIterator() ;
RooAbsArg* parg ;
while((parg=(RooAbsArg*)iter->Next())) {
if (parg->IsA()->InheritsFrom(RooAbsCategory::Class()) &&
!parg->IsA()->InheritsFrom(RooCategory::Class())) {
ret.add(*parg) ;
}
}
return ret ;
}
//_____________________________________________________________________________
RooArgSet RooWorkspace::allResolutionModels() const
{
// Return set with all resolution model objects
RooArgSet ret ;
// Split list of components in pdfs, functions and variables
TIterator* iter = _allOwnedNodes.createIterator() ;
RooAbsArg* parg ;
while((parg=(RooAbsArg*)iter->Next())) {
if (parg->IsA()->InheritsFrom(RooResolutionModel::Class())) {
if (!((RooResolutionModel*)parg)->isConvolved()) {
ret.add(*parg) ;
}
}
}
return ret ;
}
//_____________________________________________________________________________
RooArgSet RooWorkspace::allPdfs() const
{
// Return set with all probability density function objects
RooArgSet ret ;
// Split list of components in pdfs, functions and variables
TIterator* iter = _allOwnedNodes.createIterator() ;
RooAbsArg* parg ;
while((parg=(RooAbsArg*)iter->Next())) {
if (parg->IsA()->InheritsFrom(RooAbsPdf::Class()) &&
!parg->IsA()->InheritsFrom(RooResolutionModel::Class())) {
ret.add(*parg) ;
}
}
return ret ;
}
//_____________________________________________________________________________
list<RooAbsData*> RooWorkspace::allData() const
{
// Return list of all dataset in the workspace
list<RooAbsData*> ret ;
TIterator* iter = _dataList.MakeIterator() ;
RooAbsData* dat ;
while((dat=(RooAbsData*)iter->Next())) {
ret.push_back(dat) ;
}
delete iter ;
return ret ;
}
//_____________________________________________________________________________
list<TObject*> RooWorkspace::allGenericObjects() const
{
// Return list of all generic objects in the workspace
list<TObject*> ret ;
TIterator* iter = _genObjects.MakeIterator() ;
TObject* gobj ;
while((gobj=(RooAbsData*)iter->Next())) {
// If found object is wrapper, return payload
if (gobj->IsA()==RooTObjWrap::Class()) {
ret.push_back(((RooTObjWrap*)gobj)->obj()) ;
} else {
ret.push_back(gobj) ;
}
}
delete iter ;
return ret ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::CodeRepo::autoImportClass(TClass* tc, Bool_t doReplace)
{
// Import code of class 'tc' into the repository. If code is already in repository it is only imported
// again if doReplace is false. The names and location of the source files is determined from the information
// in TClass. If no location is found in the TClass information, the files are searched in the workspace
// search path, defined by addClassDeclImportDir() and addClassImplImportDir() for declaration and implementation
// files respectively. If files cannot be found, abort with error status, otherwise update the internal
// class-to-file map and import the contents of the files, if they are not imported yet.
oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo(" << _wspace->GetName() << ") request to import code of class " << tc->GetName() << endl ;
// *** PHASE 1 *** Check if file needs to be imported, or is in ROOT distribution, and check if it can be persisted
// Check if we already have the class (i.e. it is in the classToFile map)
if (!doReplace && _c2fmap.find(tc->GetName())!=_c2fmap.end()) {
oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo(" << _wspace->GetName() << ") code of class " << tc->GetName() << " already imported, skipping" << endl ;
return kTRUE ;
}
// Check if class is listed in a ROOTMAP file - if so we can skip it because it is in the root distribtion
const char* mapEntry = gInterpreter->GetClassSharedLibs(tc->GetName()) ;
if (mapEntry && strlen(mapEntry)>0) {
oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo(" << _wspace->GetName() << ") code of class " << tc->GetName() << " is in ROOT distribution, skipping " << endl ;
return kTRUE ;
}
// Retrieve file names through ROOT TClass interface
string implfile = tc->GetImplFileName() ;
string declfile = tc->GetDeclFileName() ;
// Check that file names are not empty
if (implfile.empty() || declfile.empty()) {
oocoutE(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo(" << _wspace->GetName() << ") ERROR: cannot retrieve code file names for class "
<< tc->GetName() << " through ROOT TClass interface, unable to import code" << endl ;
return kFALSE ;
}
// Check if header filename is found in ROOT distribution, if so, do not import class
TString rootsys = gSystem->Getenv("ROOTSYS") ;
if (TString(implfile.c_str()).Index(rootsys)>=0) {
oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo(" << _wspace->GetName() << ") code of class " << tc->GetName() << " is in ROOT distribution, skipping " << endl ;
return kTRUE ;
}
const char* implpath=0 ;
// Require that class meets technical criteria to be persistable (i.e it has a default ctor)
// (We also need a default ctor of abstract classes, but cannot check that through is interface
// as TClass::HasDefaultCtor only returns true for callable default ctors)
#if ROOT_VERSION_CODE <= ROOT_VERSION(5,19,02)
if (!(tc->GetClassInfo()->Property()&G__BIT_ISABSTRACT) && !tc->HasDefaultConstructor()) {
#else
if (!(gCint->ClassInfo_Property(tc->GetClassInfo())&G__BIT_ISABSTRACT) && !tc->HasDefaultConstructor()) {
#endif
oocoutW(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName() << ") WARNING cannot import class "
<< tc->GetName() << " : it cannot be persisted because it doesn't have a default constructor. Please fix " << endl ;
return kFALSE ;
}
// *** PHASE 2 *** Check if declaration and implementation files can be located
char* declpath = 0 ;
// Check if header file can be found in specified location
// If not, scan through list of 'class declaration' paths in RooWorkspace
if (gSystem->AccessPathName(declfile.c_str())) {
// Check list of additional declaration paths
list<string>::iterator diter = RooWorkspace::_classDeclDirList.begin() ;
while(diter!= RooWorkspace::_classDeclDirList.end()) {
declpath = gSystem->ConcatFileName(diter->c_str(),declfile.c_str()) ;
if (!gSystem->AccessPathName(declpath)) {
// found declaration file
break ;
}
// cleanup and continue ;
delete[] declpath ;
declpath=0 ;
++diter ;
}
// Header file cannot be found anywhere, warn user and abort operation
if (!declpath) {
oocoutW(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName() << ") WARNING Cannot access code of class "
<< tc->GetName() << " because header file " << declfile << " is not found in current directory nor in $ROOTSYS" ;
if (_classDeclDirList.size()>0) {
ooccoutW(_wspace,ObjectHandling) << ", nor in the search path " ;
diter = RooWorkspace::_classDeclDirList.begin() ;
while(diter!= RooWorkspace::_classDeclDirList.end()) {
if (diter!=RooWorkspace::_classDeclDirList.begin()) {
ooccoutW(_wspace,ObjectHandling) << "," ;
}
ooccoutW(_wspace,ObjectHandling) << diter->c_str() ;
++diter ;
}
}
ooccoutW(_wspace,ObjectHandling) << ". To fix this problem add the required directory to the search "
<< "path using RooWorkspace::addClassDeclDir(const char* dir)" << endl ;
return kFALSE ;
}
}
// Check if implementation file can be found in specified location
// If not, scan through list of 'class implementation' paths in RooWorkspace
if (gSystem->AccessPathName(implfile.c_str())) {
// Check list of additional declaration paths
list<string>::iterator iiter = RooWorkspace::_classImplDirList.begin() ;
while(iiter!= RooWorkspace::_classImplDirList.end()) {
implpath = gSystem->ConcatFileName(iiter->c_str(),implfile.c_str()) ;
if (!gSystem->AccessPathName(implpath)) {
// found implementation file
break ;
}
// cleanup and continue ;
delete[] implpath ;
implpath=0 ;
++iiter ;
}
// Implementation file cannot be found anywhere, warn user and abort operation
if (!implpath) {
oocoutW(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName() << ") WARNING Cannot access code of class "
<< tc->GetName() << " because implementation file " << implfile << " is not found in current directory nor in $ROOTSYS" ;
if (_classDeclDirList.size()>0) {
ooccoutW(_wspace,ObjectHandling) << ", nor in the search path " ;
iiter = RooWorkspace::_classImplDirList.begin() ;
while(iiter!= RooWorkspace::_classImplDirList.end()) {
if (iiter!=RooWorkspace::_classImplDirList.begin()) {
ooccoutW(_wspace,ObjectHandling) << "," ;
}
ooccoutW(_wspace,ObjectHandling) << iiter->c_str() ;
++iiter ;
}
}
ooccoutW(_wspace,ObjectHandling) << ". To fix this problem add the required directory to the search "
<< "path using RooWorkspace::addClassImplDir(const char* dir)" << endl ;
return kFALSE ;
}
}
char buf[1024] ;
// *** Phase 3 *** Prepare to import code from files into STL string buffer
//
// Code storage is organized in two linked maps
//
// _fmap contains stl strings with code, indexed on declaration file name
//
// _c2fmap contains list of declaration file names and list of base classes
// and is indexed on class name
//
// Phase 3 is skipped if fmap already contains an entry with given filebasename
string declfilename = declpath?gSystem->BaseName(declpath):gSystem->BaseName(declfile.c_str()) ;
// Split in base and extension
int dotpos2 = strrchr(declfilename.c_str(),'.') - declfilename.c_str() ;
string declfilebase = declfilename.substr(0,dotpos2) ;
string declfileext = declfilename.substr(dotpos2+1) ;
// If file has not beed stored yet, enter stl strings with implementation and declaration in file map
if (_fmap.find(declfilebase) == _fmap.end()) {
// Open declaration file
fstream fdecl(declpath?declpath:declfile.c_str()) ;
// Abort import if declaration file cannot be opened
if (!fdecl) {
oocoutE(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
<< ") ERROR opening declaration file " << declfile << endl ;
return kFALSE ;
}
oocoutI(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
<< ") importing code of class " << tc->GetName()
<< " from " << (implpath?implpath:implfile.c_str())
<< " and " << (declpath?declpath:declfile.c_str()) << endl ;
// Read entire file into an stl string
string decl ;
while(fdecl.getline(buf,1023)) {
decl += buf ;
decl += '\n' ;
}
// Open implementation file
fstream fimpl(implpath?implpath:implfile.c_str()) ;
// Abort import if implementation file cannot be opened
if (!fimpl) {
oocoutE(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
<< ") ERROR opening implementation file " << implfile << endl ;
return kFALSE ;
}
// Import entire implentation file into stl string
string impl ;
while(fimpl.getline(buf,1023)) {
// Process #include statements here
// Look for include state of self
Bool_t foundSelfInclude=kFALSE ;
// Look for include of declaration file corresponding to this implementation file
if (strstr(buf,"#include")) {
// Process #include statements here
char tmp[1024] ;
strlcpy(tmp,buf,1024) ;
strtok(tmp," <\"") ;
char* incfile = strtok(0," <\"") ;
if (strstr(incfile,declfilename.c_str())) {
foundSelfInclude=kTRUE ;
}
}
// Explicitly rewrite include of own declaration file to string
// any directory prefixes, copy all other lines verbatim in stl string
if (foundSelfInclude) {
// If include of self is found, substitute original include
// which may have directory structure with a plain include
impl += Form("#include \"%s.%s\"\n",declfilebase.c_str(),declfileext.c_str()) ;
} else {
impl += buf ;
impl += '\n' ;
}
}
// Create entry in file map
_fmap[declfilebase]._hfile = decl ;
_fmap[declfilebase]._cxxfile = impl ;
_fmap[declfilebase]._hext = declfileext ;
} else {
// Inform that existing file entry is being recycled because it already contained class code
oocoutI(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
<< ") code of class " << tc->GetName()
<< " was already imported from " << (implpath?implpath:implfile.c_str())
<< " and " << (declpath?declpath:declfile.c_str()) << endl ;
}
// *** PHASE 4 *** Import stl strings with code into workspace
//
// If multiple classes are declared in a single code unit, there will be
// multiple _c2fmap entries all pointing to the same _fmap entry.
// Make list of all immediate base classes of this class
TString baseNameList ;
TList* bl = tc->GetListOfBases() ;
TIterator* iter = bl->MakeIterator() ;
TBaseClass* base ;
list<TClass*> bases ;
while((base=(TBaseClass*)iter->Next())) {
if (baseNameList.Length()>0) {
baseNameList += "," ;
}
baseNameList += base->GetClassPointer()->GetName() ;
bases.push_back(base->GetClassPointer()) ;
}
// Map class name to above _fmap entries, along with list of base classes
// in _c2fmap
_c2fmap[tc->GetName()]._baseName = baseNameList ;
_c2fmap[tc->GetName()]._fileBase = declfilebase ;
// Recursive store all base classes.
list<TClass*>::iterator biter = bases.begin() ;
while(biter!=bases.end()) {
autoImportClass(*biter,doReplace) ;
++biter ;
}
// Cleanup
if (implpath) {
delete[] implpath ;
}
if (declpath) {
delete[] declpath ;
}
return kTRUE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::makeDir()
{
// Create transient TDirectory representation of this workspace. This directory
// will appear as a subdirectory of the directory that contains the workspace
// and will have the name of the workspace suffixed with "Dir". The TDirectory
// interface is read-only. Any attempt to insert objects into the workspace
// directory representation will result in an error message. Note that some
// ROOT object like TH1 automatically insert themselves into the current directory
// when constructed. This will give error messages when done in a workspace
// directory.
if (_dir) return kTRUE ;
TString title= Form("TDirectory representation of RooWorkspace %s",GetName()) ;
_dir = new WSDir(GetName(),title.Data(),this) ;
TIterator* iter = componentIterator() ;
RooAbsArg* darg ;
while((darg=(RooAbsArg*)iter->Next())) {
if (darg->IsA() != RooConstVar::Class()) {
_dir->InternalAppend(darg) ;
}
}
return kTRUE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::import(TObject& object, Bool_t replaceExisting)
{
// Import a clone of a generic TObject into workspace generic object container. Imported
// object can be retrieved by name through the obj() method. The object is cloned upon
// importation and the input argument does not need to live beyond the import call
//
// Returns kTRUE if an error has occurred.
// First check if object with given name already exists
TObject* oldObj = _genObjects.FindObject(object.GetName()) ;
if (oldObj && !replaceExisting) {
coutE(InputArguments) << "RooWorkspace::import(" << GetName() << ") generic object with name "
<< object.GetName() << " is already in workspace and replaceExisting flag is set to false" << endl ;
return kTRUE ;
}
TH1::AddDirectory(kFALSE) ;
if (oldObj) {
_genObjects.Replace(oldObj,object.Clone()) ;
delete oldObj ;
} else {
_genObjects.Add(object.Clone()) ;
}
TH1::AddDirectory(kTRUE) ;
return kFALSE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::import(TObject& object, const char* aliasName, Bool_t replaceExisting)
{
// Import a clone of a generic TObject into workspace generic object container.
// The imported object will be stored under the given alias name rather than its
// own name. Imported object can be retrieved its alias name through the obj() method.
// The object is cloned upon importation and the input argument does not need to live beyond the import call
// This method is mostly useful for importing objects that do not have a settable name such as TMatrix
//
// Returns kTRUE if an error has occurred.
// First check if object with given name already exists
TObject* oldObj = _genObjects.FindObject(object.GetName()) ;
if (oldObj && !replaceExisting) {
coutE(InputArguments) << "RooWorkspace::import(" << GetName() << ") generic object with name "
<< object.GetName() << " is already in workspace and replaceExisting flag is set to false" << endl ;
return kTRUE ;
}
TH1::AddDirectory(kFALSE) ;
RooTObjWrap* wrapper = new RooTObjWrap(object.Clone()) ;
TH1::AddDirectory(kTRUE) ;
wrapper->setOwning(kTRUE) ;
wrapper->SetName(aliasName) ;
wrapper->SetTitle(aliasName) ;
if (oldObj) {
_genObjects.Replace(oldObj,wrapper) ;
delete oldObj ;
} else {
_genObjects.Add(wrapper) ;
}
return kFALSE ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::addStudy(RooAbsStudy& study)
{
// Insert RooStudyManager module
RooAbsStudy* clone = (RooAbsStudy*) study.Clone() ;
_studyMods.Add(clone) ;
return kFALSE ;
}
//_____________________________________________________________________________
void RooWorkspace::clearStudies()
{
// Remove all RooStudyManager modules
_studyMods.Delete() ;
}
//_____________________________________________________________________________
TObject* RooWorkspace::obj(const char* name) const
{
// Return any type of object (RooAbsArg, RooAbsData or generic object) with given name)
// Try RooAbsArg first
TObject* ret = arg(name) ;
if (ret) return ret ;
// Then try RooAbsData
ret = data(name) ;
if (ret) return ret ;
// Finally try generic object store
return genobj(name) ;
}
//_____________________________________________________________________________
TObject* RooWorkspace::genobj(const char* name) const
{
// Return generic object with given name
// Find object by name
TObject* gobj = _genObjects.FindObject(name) ;
// Exit here if not found
if (!gobj) return 0 ;
// If found object is wrapper, return payload
if (gobj->IsA()==RooTObjWrap::Class()) return ((RooTObjWrap*)gobj)->obj() ;
return gobj ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::cd(const char* path)
{
makeDir() ;
return _dir->cd(path) ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::writeToFile(const char* fileName, Bool_t recreate)
{
// Save this current workspace into given file
TFile f(fileName,recreate?"RECREATE":"UPDATE") ;
Write() ;
return kFALSE ;
}
//_____________________________________________________________________________
RooFactoryWSTool& RooWorkspace::factory()
{
// Return instance to factory tool
if (_factory) {
return *_factory ;
}
cxcoutD(ObjectHandling) << "INFO: Creating RooFactoryWSTool associated with this workspace" << endl ;
_factory = new RooFactoryWSTool(*this) ;
return *_factory ;
}
//_____________________________________________________________________________
RooAbsArg* RooWorkspace::factory(const char* expr)
{
// Short-hand function for factory()->process(expr) ;
return factory().process(expr) ;
}
//_____________________________________________________________________________
void RooWorkspace::Print(Option_t* opts) const
{
// Print contents of the workspace
Bool_t treeMode(kFALSE) ;
if (TString(opts).Contains("t")) {
treeMode=kTRUE ;
}
cout << endl << "RooWorkspace(" << GetName() << ") " << GetTitle() << " contents" << endl << endl ;
RooAbsArg* parg ;
RooArgSet pdfSet ;
RooArgSet funcSet ;
RooArgSet varSet ;
RooArgSet catfuncSet ;
RooArgSet convResoSet ;
RooArgSet resoSet ;
// Split list of components in pdfs, functions and variables
TIterator* iter = _allOwnedNodes.createIterator() ;
while((parg=(RooAbsArg*)iter->Next())) {
//---------------
if (treeMode) {
// In tree mode, only add nodes with no clients to the print lists
if (parg->IsA()->InheritsFrom(RooAbsPdf::Class())) {
if (!parg->hasClients()) {
pdfSet.add(*parg) ;
}
}
if (parg->IsA()->InheritsFrom(RooAbsReal::Class()) &&
!parg->IsA()->InheritsFrom(RooAbsPdf::Class()) &&
!parg->IsA()->InheritsFrom(RooConstVar::Class()) &&
!parg->IsA()->InheritsFrom(RooRealVar::Class())) {
if (!parg->hasClients()) {
funcSet.add(*parg) ;
}
}
if (parg->IsA()->InheritsFrom(RooAbsCategory::Class()) &&
!parg->IsA()->InheritsFrom(RooCategory::Class())) {
if (!parg->hasClients()) {
catfuncSet.add(*parg) ;
}
}
} else {
if (parg->IsA()->InheritsFrom(RooResolutionModel::Class())) {
if (((RooResolutionModel*)parg)->isConvolved()) {
convResoSet.add(*parg) ;
} else {
resoSet.add(*parg) ;
}
}
if (parg->IsA()->InheritsFrom(RooAbsPdf::Class()) &&
!parg->IsA()->InheritsFrom(RooResolutionModel::Class())) {
pdfSet.add(*parg) ;
}
if (parg->IsA()->InheritsFrom(RooAbsReal::Class()) &&
!parg->IsA()->InheritsFrom(RooAbsPdf::Class()) &&
!parg->IsA()->InheritsFrom(RooConstVar::Class()) &&
!parg->IsA()->InheritsFrom(RooRealVar::Class())) {
funcSet.add(*parg) ;
}
if (parg->IsA()->InheritsFrom(RooAbsCategory::Class()) &&
!parg->IsA()->InheritsFrom(RooCategory::Class())) {
catfuncSet.add(*parg) ;
}
}
if (parg->IsA()->InheritsFrom(RooRealVar::Class())) {
varSet.add(*parg) ;
}
if (parg->IsA()->InheritsFrom(RooCategory::Class())) {
varSet.add(*parg) ;
}
}
delete iter ;
RooFit::MsgLevel oldLevel = RooMsgService::instance().globalKillBelow() ;
RooMsgService::instance().setGlobalKillBelow(RooFit::WARNING) ;
if (varSet.getSize()>0) {
varSet.sort() ;
cout << "variables" << endl ;
cout << "---------" << endl ;
cout << varSet << endl ;
cout << endl ;
}
if (pdfSet.getSize()>0) {
cout << "p.d.f.s" << endl ;
cout << "-------" << endl ;
pdfSet.sort() ;
iter = pdfSet.createIterator() ;
while((parg=(RooAbsArg*)iter->Next())) {
if (treeMode) {
parg->printComponentTree() ;
} else {
parg->Print() ;
}
}
delete iter ;
cout << endl ;
}
if (!treeMode) {
if (resoSet.getSize()>0) {
cout << "analytical resolution models" << endl ;
cout << "----------------------------" << endl ;
resoSet.sort() ;
iter = resoSet.createIterator() ;
while((parg=(RooAbsArg*)iter->Next())) {
parg->Print() ;
}
delete iter ;
// iter = convResoSet.createIterator() ;
// while((parg=(RooAbsArg*)iter->Next())) {
// parg->Print() ;
// }
// delete iter ;
cout << endl ;
}
}
if (funcSet.getSize()>0) {
cout << "functions" << endl ;
cout << "--------" << endl ;
funcSet.sort() ;
iter = funcSet.createIterator() ;
while((parg=(RooAbsArg*)iter->Next())) {
if (treeMode) {
parg->printComponentTree() ;
} else {
parg->Print() ;
}
}
delete iter ;
cout << endl ;
}
if (catfuncSet.getSize()>0) {
cout << "category functions" << endl ;
cout << "------------------" << endl ;
catfuncSet.sort() ;
iter = catfuncSet.createIterator() ;
while((parg=(RooAbsArg*)iter->Next())) {
if (treeMode) {
parg->printComponentTree() ;
} else {
parg->Print() ;
}
}
delete iter ;
cout << endl ;
}
if (_dataList.GetSize()>0) {
cout << "datasets" << endl ;
cout << "--------" << endl ;
iter = _dataList.MakeIterator() ;
RooAbsData* data2 ;
while((data2=(RooAbsData*)iter->Next())) {
cout << data2->IsA()->GetName() << "::" << data2->GetName() << *data2->get() << endl ;
}
delete iter ;
cout << endl ;
}
if (_snapshots.GetSize()>0) {
cout << "parameter snapshots" << endl ;
cout << "-------------------" << endl ;
iter = _snapshots.MakeIterator() ;
RooArgSet* snap ;
while((snap=(RooArgSet*)iter->Next())) {
cout << snap->GetName() << " = (" ;
TIterator* aiter = snap->createIterator() ;
RooAbsArg* a ;
Bool_t first(kTRUE) ;
while((a=(RooAbsArg*)aiter->Next())) {
if (first) { first=kFALSE ; } else { cout << "," ; }
cout << a->GetName() << "=" ;
a->printValue(cout) ;
if (a->isConstant()) {
cout << "[C]" ;
}
}
cout << ")" << endl ;
delete aiter ;
}
delete iter ;
cout << endl ;
}
if (_namedSets.size()>0) {
cout << "named sets" << endl ;
cout << "----------" << endl ;
for (map<string,RooArgSet>::const_iterator it = _namedSets.begin() ; it != _namedSets.end() ; it++) {
cout << it->first << ":" << it->second << endl ;
}
cout << endl ;
}
if (_genObjects.GetSize()>0) {
cout << "generic objects" << endl ;
cout << "---------------" << endl ;
iter = _genObjects.MakeIterator() ;
TObject* gobj ;
while((gobj=(TObject*)iter->Next())) {
if (gobj->IsA()==RooTObjWrap::Class()) {
cout << ((RooTObjWrap*)gobj)->obj()->IsA()->GetName() << "::" << gobj->GetName() << endl ;
} else {
cout << gobj->IsA()->GetName() << "::" << gobj->GetName() << endl ;
}
}
delete iter ;
cout << endl ;
}
if (_studyMods.GetSize()>0) {
cout << "study modules" << endl ;
cout << "-------------" << endl ;
iter = _studyMods.MakeIterator() ;
TObject* smobj ;
while((smobj=(TObject*)iter->Next())) {
cout << smobj->IsA()->GetName() << "::" << smobj->GetName() << endl ;
}
delete iter ;
cout << endl ;
}
if (_classes.listOfClassNames().size()>0) {
cout << "embedded class code" << endl ;
cout << "-------------------" << endl ;
cout << _classes.listOfClassNames() << endl ;
cout << endl ;
}
if (_eocache.size()>0) {
cout << "embedded precalculated expensive components" << endl ;
cout << "-------------------------------------------" << endl ;
_eocache.print() ;
}
RooMsgService::instance().setGlobalKillBelow(oldLevel) ;
return ;
}
//_____________________________________________________________________________
void RooWorkspace::CodeRepo::Streamer(TBuffer &R__b)
{
// Custom streamer for the workspace. Stream contents of workspace
// and code repository. When reading, read code repository first
// and compile missing classes before proceeding with streaming
// of workspace contents to avoid errors.
typedef ::RooWorkspace::CodeRepo thisClass;
// Stream an object of class RooWorkspace::CodeRepo.
if (R__b.IsReading()) {
UInt_t R__s, R__c;
R__b.ReadVersion(&R__s, &R__c);
// Stream contents of ClassFiles map
Int_t count(0) ;
R__b >> count ;
while(count--) {
TString name ;
name.Streamer(R__b) ;
_fmap[name]._hext.Streamer(R__b) ;
_fmap[name]._hfile.Streamer(R__b) ;
_fmap[name]._cxxfile.Streamer(R__b) ;
}
// Stream contents of ClassRelInfo map
count=0 ;
R__b >> count ;
while(count--) {
TString name,bname,fbase ;
name.Streamer(R__b) ;
_c2fmap[name]._baseName.Streamer(R__b) ;
_c2fmap[name]._fileBase.Streamer(R__b) ;
}
R__b.CheckByteCount(R__s, R__c, thisClass::IsA());
// Instantiate any classes that are not defined in current session
_compiledOK = !compileClasses() ;
} else {
UInt_t R__c;
R__c = R__b.WriteVersion(thisClass::IsA(), kTRUE);
// Stream contents of ClassFiles map
UInt_t count = _fmap.size() ;
R__b << count ;
map<TString,ClassFiles>::iterator iter = _fmap.begin() ;
while(iter!=_fmap.end()) {
TString key_copy(iter->first) ;
key_copy.Streamer(R__b) ;
iter->second._hext.Streamer(R__b) ;
iter->second._hfile.Streamer(R__b);
iter->second._cxxfile.Streamer(R__b);
++iter ;
}
// Stream contents of ClassRelInfo map
count = _c2fmap.size() ;
R__b << count ;
map<TString,ClassRelInfo>::iterator iter2 = _c2fmap.begin() ;
while(iter2!=_c2fmap.end()) {
TString key_copy(iter2->first) ;
key_copy.Streamer(R__b) ;
iter2->second._baseName.Streamer(R__b) ;
iter2->second._fileBase.Streamer(R__b);
++iter2 ;
}
R__b.SetByteCount(R__c, kTRUE);
}
}
//______________________________________________________________________________
void RooWorkspace::Streamer(TBuffer &R__b)
{
// Stream an object of class RooWorkspace. This is a standard ROOT streamer for the
// I/O part. This custom function exists to detach all external client links
// from the payload prior to writing the payload so that these client links
// are not persisted. (Client links occur if external function objects use
// objects contained in the workspace as input)
// After the actual writing, these client links are restored.
if (R__b.IsReading()) {
R__b.ReadClassBuffer(RooWorkspace::Class(),this);
// Make expensive object cache of all objects point to intermal copy.
// Somehow this doesn't work OK automatically
TIterator* iter = _allOwnedNodes.createIterator() ;
RooAbsArg* node ;
while((node=(RooAbsArg*)iter->Next())) {
node->setExpensiveObjectCache(_eocache) ;
if (node->IsA()->InheritsFrom(RooAbsOptTestStatistic::Class())) {
RooAbsOptTestStatistic* tmp = (RooAbsOptTestStatistic*) node ;
if (tmp->isSealed() && tmp->sealNotice() && strlen(tmp->sealNotice())>0) {
cout << "RooWorkspace::Streamer(" << GetName() << ") " << node->IsA()->GetName() << "::" << node->GetName() << " : " << tmp->sealNotice() << endl ;
}
}
}
delete iter ;
} else {
// Make lists of external clients of WS objects, and remove those links temporarily
map<RooAbsArg*,list<RooAbsArg*> > extClients, extValueClients, extShapeClients ;
TIterator* iter = _allOwnedNodes.createIterator() ;
RooAbsArg* tmparg ;
while((tmparg=(RooAbsArg*)iter->Next())) {
// Loop over client list of this arg
TIterator* clientIter = tmparg->_clientList.MakeIterator() ;
RooAbsArg* client ;
while((client=(RooAbsArg*)clientIter->Next())) {
if (!_allOwnedNodes.containsInstance(*client)) {
while(tmparg->_clientList.refCount(client)>0) {
tmparg->_clientList.Remove(client) ;
extClients[tmparg].push_back(client) ;
}
}
}
delete clientIter ;
// Loop over value client list of this arg
TIterator* vclientIter = tmparg->_clientListValue.MakeIterator() ;
RooAbsArg* vclient ;
while((vclient=(RooAbsArg*)vclientIter->Next())) {
if (!_allOwnedNodes.containsInstance(*vclient)) {
cxcoutD(ObjectHandling) << "RooWorkspace::Streamer(" << GetName() << ") element " << tmparg->GetName()
<< " has external value client link to " << vclient << " (" << vclient->GetName() << ") with ref count " << tmparg->_clientListValue.refCount(vclient) << endl ;
while(tmparg->_clientListValue.refCount(vclient)>0) {
tmparg->_clientListValue.Remove(vclient) ;
extValueClients[tmparg].push_back(vclient) ;
}
}
}
delete vclientIter ;
// Loop over shape client list of this arg
TIterator* sclientIter = tmparg->_clientListShape.MakeIterator() ;
RooAbsArg* sclient ;
while((sclient=(RooAbsArg*)sclientIter->Next())) {
if (!_allOwnedNodes.containsInstance(*sclient)) {
cxcoutD(ObjectHandling) << "RooWorkspace::Streamer(" << GetName() << ") element " << tmparg->GetName()
<< " has external shape client link to " << sclient << " (" << sclient->GetName() << ") with ref count " << tmparg->_clientListShape.refCount(sclient) << endl ;
while(tmparg->_clientListShape.refCount(sclient)>0) {
tmparg->_clientListShape.Remove(sclient) ;
extShapeClients[tmparg].push_back(sclient) ;
}
}
}
delete sclientIter ;
}
delete iter ;
R__b.WriteClassBuffer(RooWorkspace::Class(),this);
// Reinstate clients here
for (map<RooAbsArg*,list<RooAbsArg*> >::iterator iterx = extClients.begin() ; iterx!=extClients.end() ; iterx++) {
for (list<RooAbsArg*>::iterator citer = iterx->second.begin() ; citer!=iterx->second.end() ; citer++) {
iterx->first->_clientList.Add(*citer) ;
}
}
for (map<RooAbsArg*,list<RooAbsArg*> >::iterator iterx = extValueClients.begin() ; iterx!=extValueClients.end() ; iterx++) {
for (list<RooAbsArg*>::iterator citer = iterx->second.begin() ; citer!=iterx->second.end() ; citer++) {
iterx->first->_clientListValue.Add(*citer) ;
}
}
for (map<RooAbsArg*,list<RooAbsArg*> >::iterator iterx = extShapeClients.begin() ; iterx!=extShapeClients.end() ; iterx++) {
for (list<RooAbsArg*>::iterator citer = iterx->second.begin() ; citer!=iterx->second.end() ; citer++) {
iterx->first->_clientListShape.Add(*citer) ;
}
}
}
}
//_____________________________________________________________________________
std::string RooWorkspace::CodeRepo::listOfClassNames() const
{
// Return STL string with last of class names contained in the code repository
string ret ;
map<TString,ClassRelInfo>::const_iterator iter = _c2fmap.begin() ;
while(iter!=_c2fmap.end()) {
if (ret.size()>0) {
ret += ", " ;
}
ret += iter->first ;
++iter ;
}
return ret ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::CodeRepo::compileClasses()
{
// For all classes in the workspace for which no class definition is
// found in the ROOT class table extract source code stored in code
// repository into temporary directory set by
// setClassFileExportDir(), compile classes and link them with
// current ROOT session. If a compilation error occurs print
// instructions for user how to fix errors and recover workspace and
// abort import procedure.
Bool_t haveDir=kFALSE ;
// Retrieve name of directory in which to export code files
string dirName = Form(_classFileExportDir.c_str(),_wspace->uuid().AsString(),_wspace->GetName()) ;
// Process all class entries in repository
map<TString,ClassRelInfo>::iterator iter = _c2fmap.begin() ;
while(iter!=_c2fmap.end()) {
oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() now processing class " << iter->first.Data() << endl ;
// If class is already known, don't load
if (gClassTable->GetDict(iter->first.Data())) {
oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() Embedded class "
<< iter->first << " already in ROOT class table, skipping" << endl ;
++iter ;
continue ;
}
// Check that export directory exists
if (!haveDir) {
// If not, make local directory to extract files
if (!gSystem->AccessPathName(dirName.c_str())) {
oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() reusing code export directory " << dirName.c_str()
<< " to extract coded embedded in workspace" << endl ;
} else {
if (gSystem->MakeDirectory(dirName.c_str())==0) {
oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() creating code export directory " << dirName.c_str()
<< " to extract coded embedded in workspace" << endl ;
} else {
oocoutE(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() ERROR creating code export directory " << dirName.c_str()
<< " to extract coded embedded in workspace" << endl ;
return kFALSE ;
}
}
haveDir=kTRUE ;
}
// Navigate from class to file
ClassFiles& cfinfo = _fmap[iter->second._fileBase] ;
oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() now processing file with base " << iter->second._fileBase << endl ;
// If file is already processed, skip to next class
if (cfinfo._extracted) {
oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() file with base name " << iter->second._fileBase
<< " has already been extracted, skipping to next class" << endl ;
continue ;
}
// Check if identical declaration file (header) is already written
Bool_t needDeclWrite=kTRUE ;
string fdname = Form("%s/%s.%s",dirName.c_str(),iter->second._fileBase.Data(),cfinfo._hext.Data()) ;
ifstream ifdecl(fdname.c_str()) ;
if (ifdecl) {
TString contents ;
char buf[1024] ;
while(ifdecl.getline(buf,1024)) {
contents += buf ;
contents += "\n" ;
}
UInt_t crcFile = RooAbsArg::crc32(contents.Data()) ;
UInt_t crcWS = RooAbsArg::crc32(cfinfo._hfile.Data()) ;
needDeclWrite = (crcFile!=crcWS) ;
}
// Write declaration file if required
if (needDeclWrite) {
oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() Extracting declaration code of class " << iter->first << ", file " << fdname << endl ;
ofstream fdecl(fdname.c_str()) ;
if (!fdecl) {
oocoutE(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() ERROR opening file"
<< fdname << " for writing" << endl ;
return kFALSE ;
}
fdecl << cfinfo._hfile ;
fdecl.close() ;
}
// Check if identical implementation file is already written
Bool_t needImplWrite=kTRUE ;
string finame = Form("%s/%s.cxx",dirName.c_str(),iter->second._fileBase.Data()) ;
ifstream ifimpl(finame.c_str()) ;
if (ifimpl) {
TString contents ;
char buf[1024] ;
while(ifimpl.getline(buf,1024)) {
contents += buf ;
contents += "\n" ;
}
UInt_t crcFile = RooAbsArg::crc32(contents.Data()) ;
UInt_t crcWS = RooAbsArg::crc32(cfinfo._cxxfile.Data()) ;
needImplWrite = (crcFile!=crcWS) ;
}
// Write implementation file if required
if (needImplWrite) {
oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() Extracting implementation code of class " << iter->first << ", file " << finame << endl ;
ofstream fimpl(finame.c_str()) ;
if (!fimpl) {
oocoutE(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() ERROR opening file"
<< finame << " for writing" << endl ;
return kFALSE ;
}
fimpl << cfinfo._cxxfile ;
fimpl.close() ;
}
// Mark this file as extracted
cfinfo._extracted = kTRUE ;
oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() marking code unit " << iter->second._fileBase << " as extracted" << endl ;
// Compile class
oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() Compiling code unit " << iter->second._fileBase.Data() << " to define class " << iter->first << endl ;
Bool_t ok = gSystem->CompileMacro(finame.c_str(),"k") ;
if (!ok) {
oocoutE(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() ERROR compiling class " << iter->first.Data() << ", to fix this you can do the following: " << endl
<< " 1) Fix extracted source code files in directory " << dirName.c_str() << "/" << endl
<< " 2) In clean ROOT session compiled fixed classes by hand using '.x " << dirName.c_str() << "/ClassName.cxx+'" << endl
<< " 3) Reopen file with RooWorkspace with broken source code in UPDATE mode. Access RooWorkspace to force loading of class" << endl
<< " Broken instances in workspace will _not_ be compiled, instead precompiled fixed instances will be used." << endl
<< " 4) Reimport fixed code in workspace using 'RooWorkspace::importClassCode(\"*\",kTRUE)' method, Write() updated workspace to file and close file" << endl
<< " 5) Reopen file in clean ROOT session to confirm that problems are fixed" << endl ;
return kFALSE ;
}
++iter ;
}
return kTRUE ;
}
//_____________________________________________________________________________
void RooWorkspace::WSDir::InternalAppend(TObject* obj)
{
// Internal access to TDirectory append method
#if ROOT_VERSION_CODE <= ROOT_VERSION(5,19,02)
TDirectory::Append(obj) ;
#else
TDirectory::Append(obj,kFALSE) ;
#endif
}
//_____________________________________________________________________________
#if ROOT_VERSION_CODE <= ROOT_VERSION(5,19,02)
void RooWorkspace::WSDir::Add(TObject* obj)
#else
void RooWorkspace::WSDir::Add(TObject* obj,Bool_t)
#endif
{
// Overload TDirectory interface method to prohibit insertion of objects in read-only directory workspace representation
if (dynamic_cast<RooAbsArg*>(obj) || dynamic_cast<RooAbsData*>(obj)) {
coutE(ObjectHandling) << "RooWorkspace::WSDir::Add(" << GetName() << ") ERROR: Directory is read-only representation of a RooWorkspace, use RooWorkspace::import() to add objects" << endl ;
} else {
InternalAppend(obj) ;
}
}
//_____________________________________________________________________________
#if ROOT_VERSION_CODE <= ROOT_VERSION(5,19,02)
void RooWorkspace::WSDir::Append(TObject* obj)
#else
void RooWorkspace::WSDir::Append(TObject* obj,Bool_t)
#endif
{
// Overload TDirectory interface method to prohibit insertion of objects in read-only directory workspace representation
if (dynamic_cast<RooAbsArg*>(obj) || dynamic_cast<RooAbsData*>(obj)) {
coutE(ObjectHandling) << "RooWorkspace::WSDir::Add(" << GetName() << ") ERROR: Directory is read-only representation of a RooWorkspace, use RooWorkspace::import() to add objects" << endl ;
} else {
InternalAppend(obj) ;
}
}
//_____________________________________________________________________________
void RooWorkspace::exportToCint(const char* nsname)
{
// Activate export of workspace symbols to CINT in a namespace with given name. If no name
// is given the namespace will have the same name as the workspace
// If export is already active, do nothing
if (_doExport) {
coutE(ObjectHandling) << "RooWorkspace::exportToCint(" << GetName() << ") WARNING: repeated calls to exportToCint() have no effect" << endl ;
return ;
}
// Set flag so that future import to workspace are automatically exported to CINT
_doExport = kTRUE ;
// If no name is provided choose name of workspace
if (!nsname) nsname = GetName() ;
_exportNSName = nsname ;
coutI(ObjectHandling) << "RooWorkspace::exportToCint(" << GetName()
<< ") INFO: references to all objects in this workspace will be created in CINT in 'namespace " << _exportNSName << "'" << endl ;
// Export present contents of workspace to CINT
TIterator* iter = _allOwnedNodes.createIterator() ;
TObject* wobj ;
while((wobj=iter->Next())) {
exportObj(wobj) ;
}
delete iter ;
iter = _dataList.MakeIterator() ;
while((wobj=iter->Next())) {
exportObj(wobj) ;
}
delete iter ;
}
//_____________________________________________________________________________
void RooWorkspace::exportObj(TObject* wobj)
{
// Export reference to given workspace object to CINT
// Do nothing if export flag is not set
if (!_doExport) return ;
// Do not export RooConstVars
if (wobj->IsA() == RooConstVar::Class()) {
return ;
}
// Determine if object name is a valid C++ identifier name
// Do not export objects that have names that are not valid C++ identifiers
if (!isValidCPPID(wobj->GetName())) {
cxcoutD(ObjectHandling) << "RooWorkspace::exportObj(" << GetName() << ") INFO: Workspace object name " << wobj->GetName() << " is not a valid C++ identifier and is not exported to CINT" << endl ;
return ;
}
// Declare correctly typed reference to object in CINT in the namespace associated with this workspace
string cintExpr = Form("namespace %s { %s& %s = *(%s *)%p ; }",_exportNSName.c_str(),wobj->IsA()->GetName(),wobj->GetName(),wobj->IsA()->GetName(),wobj) ;
gROOT->ProcessLine(cintExpr.c_str()) ;
}
//_____________________________________________________________________________
Bool_t RooWorkspace::isValidCPPID(const char* name)
{
// Return true if given name is a valid C++ identifier name
string oname(name) ;
if (isdigit(oname[0])) {
return kFALSE ;
} else {
for (UInt_t i=0 ; i<oname.size() ; i++) {
char c = oname[i] ;
if (!isalnum(c) && (c!='_')) {
return kFALSE ;
}
}
}
return kTRUE ;
}
//_____________________________________________________________________________
void RooWorkspace::unExport()
{
// Delete exported reference in CINT namespace
char buf[1024] ;
TIterator* iter = _allOwnedNodes.createIterator() ;
TObject* wobj ;
while((wobj=iter->Next())) {
if (isValidCPPID(wobj->GetName())) {
strlcpy(buf,Form("%s::%s",_exportNSName.c_str(),wobj->GetName()),1024) ;
G__deletevariable(buf) ;
}
}
delete iter ;
}
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...