PHNodeIOManager.C
//-----------------------------------------------------------------------------
// $Header: /afs/rhic/phenix/cvsroot/offline/framework/phool/PHNodeIOManager.C,v 1.30 2001/06/29 22:17:52 pinkenbu Exp $
//
// The PHOOL's Software
// Copyright (C) PHENIX collaboration, 1999
//
// Implementation of class PHNodeIOManager
//
// Author: Matthias Messer
//-----------------------------------------------------------------------------
#include "RVersion.h"
#include "PHNodeIOManager.h"
#include "PHCompositeNode.h"
#include "PHNodeIterator.h"
#include "PHIODataNode.h"
#include "TFile.h"
#include "TTree.h"
#include "TBranchObject.h"
#include "TObject.h"
#include "TLeafObject.h"
#include "TClass.h"
#include "TROOT.h"
// Root version taken from RVersion.h
#if ROOT_VERSION_CODE >= ROOT_VERSION(3,01,5)
#include "TBranchElement.h"
#endif
#include <cassert>
PHNodeIOManager::PHNodeIOManager ()
{
file = 0;
tree = 0;
bufSize = 0;
split = 0;
accessMode = PHReadOnly;
CompressionLevel = 0;
isFunctionalFlag = 0 ;
}
PHNodeIOManager::PHNodeIOManager (const PHString& f, const PHAccessType a) : file(0),tree(0)
{
SetCompressionLevel (0);
if (!setFile(f, "titled by PHOOL", a))
{
isFunctionalFlag = 0;
}
else
{
isFunctionalFlag = 1;
}
}
PHNodeIOManager::PHNodeIOManager (const PHString& f, const PHString& title,
const PHAccessType a) : file(0),tree(0)
{
SetCompressionLevel (0);
if (!setFile(f, "titled by PHOOL", a))
{
isFunctionalFlag = 0;
}
else
{
isFunctionalFlag = 1;
}
}
PHNodeIOManager::~PHNodeIOManager ()
{
closeFile ();
}
void
PHNodeIOManager::closeFile ()
{
if (file)
{
if (accessMode == PHWrite)
{
file->Write ();
}
file->Close ();
}
}
PHBoolean
PHNodeIOManager::setFile (const PHString& f, const PHString& title,
const PHAccessType a)
{
filename = f;
bufSize = 8000;
split = 0;
accessMode = a;
switch (accessMode) {
case PHWrite:
file =
new TFile(filename.getString(),"RECREATE", title.getString());
if (!file->IsOpen())
{
return False;
}
file ->SetCompressionLevel(CompressionLevel);
tree = new TTree("T", title.getString());
return True;
break;
case PHReadOnly:
file = new TFile(filename.getString());
tree = 0;
if (!file->IsOpen())
{
return False;
}
selectObjectToRead("*",true) ;
return True;
break;
}
return False;
}
PHBoolean
PHNodeIOManager::write(PHCompositeNode* topNode)
{
//
// The write function of the PHCompositeNode topNode will
// recursively call the write functions of its subnodes,
// thus constructing the path-string which is then stored
// as name of the Root-branch corresponding to the data of
// each PHRootIODataNode.
//
topNode->write(this);
//
// Now all PHRootIODataNodes should have called the write function
// of this I/O-manager and thus created their branch. The tree can
// be filled.
//
if (file && tree)
{
tree->Fill();
eventNumber++;
return True;
}
return False;
}
PHBoolean
PHNodeIOManager::write(TObject** data, const PHString& path)
{
if(file && tree) {
TBranch *thisBranch = tree->GetBranch(path.getString());
if (!thisBranch)
{
/*
Here is were we decide how to save the data in the rrot tree.
split=0(prior to Root3.01/05; needs -1 afterwards for classes with custom
streamers, as our old PHTable(s)) means data are hidden,
interactive T->draw() will not work.
The old wrapped tables seem to need that, with split = 1 they cannot
be read back.
The new PHObjects can be saved either way, but split = 1 makes interactive
display possible
The InheritsFrom seem to work only for one level of inheritance
(which seems to be the case for PHTable, so we use this to
distinguish between table and everything else).
*/
split = 2 ;
if ((*data)->InheritsFrom("PHTable"))
{
#if ROOT_VERSION_CODE >= ROOT_VERSION(3,01,5)
split = -1 ;
#else
split = 0 ;
#endif
}
thisBranch = tree->Branch(path.getString(), (*data)->ClassName(),
data, bufSize, split);
}
else
{
thisBranch->SetAddress(data);
}
return True;
}
return False;
}
PHBoolean
PHNodeIOManager::read(size_t requestedEvent)
{
if (readEventFromFile(requestedEvent))
{
return True;
}
else
{
return False;
}
}
PHCompositeNode*
PHNodeIOManager::read(PHCompositeNode* topNode, size_t requestedEvent)
{
//
// No tree means we have not yet looked at the file,
// so we'll reconstruct the node tree now.
//
if (!tree)
{
topNode = reconstructNodeTree(topNode);
}
//
// If everything worked, there should be a tree now.
//
if (tree && readEventFromFile(requestedEvent))
{
return topNode;
}
else
{
return 0;
}
}
void
PHNodeIOManager::print() const
{
if (file)
{
if (accessMode == PHReadOnly)
{
cout << "PHNodeIOManager reading " << filename << endl;
}
else
{
cout << "PHNodeIOManager writing " << filename << endl;
}
}
if (file && tree)
{
tree->Print();
}
}
string
PHNodeIOManager::getBranchClassName(TBranch* branch)
{
// OK. Here all the game is to find out the name
// of the type contained in this branch.
//
// In ROOT pre-3.01/05 versions, all branches we used
// were of the same type = TBranchObject, so that was easy.
//
// Since version 3.01/05 ROOT introduced new branch style
// with some TBranchElement objects. So far so good.
//
// The problem is that I did not find a common way to
// grab the typename of the object contained in those branches,
// so I hereby use some durty if { } else if { } ...
//
#if ROOT_VERSION_CODE >= ROOT_VERSION(3,01,5)
TBranchElement* be = dynamic_cast<TBranchElement*>(branch) ;
if (be) {
// TBranchElement has a nice GetClassName() method for us :
return be->GetClassName() ;
}
#endif
TBranchObject* bo = dynamic_cast<TBranchObject*>(branch) ;
if (bo) {
// For this one we need to go down a little before
// getting the name...
TLeafObject* leaf = static_cast<TLeafObject*>
(branch->GetLeaf(branch->GetName())) ;
assert(leaf!=0) ;
return leaf->GetTypeName() ;
}
assert(0==1) ;
}
PHBoolean
PHNodeIOManager::readEventFromFile(size_t requestedEvent)
{
//
// Se non c'e niente, non possiamo fare niente.
// Logisch, n'est ce pas?
//
if (!tree)
{
PHMessage("PHNodeIOManager::readEventFromFile", PHError,
"Tree not initialized.");
return False;
}
int bytesRead;
// Due to the current implementation of TBuffer>>(Long_t)
// we need to cd() in the current file before
// trying to fetch any event, otherwise mixing of reading
// 2.25/03 DST with writing some 3.01/05 trees will fail.
TFile* file_ptr = gFile ; // save current gFile
file->cd() ;
if (requestedEvent)
{
if ((bytesRead = tree->GetEvent(requestedEvent)))
{
eventNumber = requestedEvent+1;
}
}
else
{
bytesRead = tree->GetEvent(eventNumber++);
}
gFile = file_ptr ; // recover gFile
if (!bytesRead)
{
return False;
}
return True;
}
int
PHNodeIOManager::readSpecific(size_t requestedEvent, const char* objectName)
{
// objectName should be one of the valid branch name of the "T" TTree, and
// should be one of the branches selected by selectObjectToRead() method.
// No wildcard allowed for the moment.
TBranch* branch = 0 ;
string name = objectName ;
map<string,TBranch*>::const_iterator p = fBranches.find(name) ;
if (p != fBranches.end())
{
branch = p->second ;
if (branch)
{
return branch->GetEvent(requestedEvent);
}
}
else
{
PHMessage("PHNodeIOManager::readSpecific",PHError,
"Unknown object name") ;
}
return 0 ;
}
PHCompositeNode*
PHNodeIOManager::reconstructNodeTree(PHCompositeNode* topNode)
{
tree = (TTree*)file->Get("T");
if (!file || !tree)
{
PHMessage("PHNodeIOManager::reconstructNodeTree", PHError,
"No tree found to read from");
return 0;
}
//
// Select the branches according to objectToRead
//
map<string,PHBoolean>::const_iterator it;
for ( it = objectToRead.begin() ; it != objectToRead.end() ; it++)
{
tree->SetBranchStatus((it->first).c_str(),
static_cast<bool>(it->second));
}
//
// The file contains a TTree with a list of the TBranchObjects attached to it.
//
TObjArray *branchArray = tree->GetListOfBranches();
//
// We need those in the loops down below...
//
size_t i, j;
PHString branchName;
PHPointerList<PHString> nodeNameList;
PHNodeIterator *nodeIter;
//
// If a topNode was given as argument, we can feed the iterator with it.
//
if (topNode)
{
nodeIter = new PHNodeIterator(topNode);
}
//
// Loop over all branches in the tree. Each branch-name contains the full
// 'path' of composite-nodes in the original node tree. We split the name
// and reconstruct the tree.
//
for (i=0; i<(size_t)(branchArray->GetEntriesFast()); i++)
{
branchName = (*branchArray)[i]->GetName();
branchName.split(nodeNameList, "/");
//
// If no topNode was given as argument, make a fresh one.
//
if (!topNode)
{
topNode = new PHCompositeNode(*(nodeNameList[0]));
nodeIter = new PHNodeIterator(topNode);
}
//
// Subsequently try to 'cd' down the node tree as given in the split
// branch name. If the 'cd' was not successful we have to create a
// new node.
//
for (j=1; j<nodeNameList.length()-1; j++)
{
if (!nodeIter->cd(*(nodeNameList[j])))
{
nodeIter->addNode(new PHCompositeNode(*(nodeNameList[j])));
nodeIter->cd(*(nodeNameList[j]));
}
}
TBranch *thisBranch = (TBranch*)((*branchArray)[i]);
// Skip non-selected branches
if (thisBranch->TestBit(kDoNotProcess))
{
continue ;
}
string branchClassName = getBranchClassName(thisBranch) ;
string branchName = thisBranch->GetName() ;
fBranches[branchName] = thisBranch ;
assert(gROOT!=0) ;
TClass* thisClass = gROOT->GetClass(branchClassName.c_str()) ;
assert(thisClass!=0) ;
/* if anyone knows how to handle that, if thisClass is not loaded we coredump later */
if (thisClass)
{
TObject *newTObject = (TObject*)thisClass->New();
PHIODataNode<TObject> *newIODataNode = new PHIODataNode<TObject>(newTObject, *(nodeNameList[nodeNameList.length()-1]));
nodeIter->addNode(newIODataNode);
/*
PHTable is still PHNode default, but for new classes PHNode objecttype has to
be PHObject. So far I couldn't figure out how to get this info through root
(InheritsFrom seems to work only for first level a'la
class newclass : class PHTable
The object type is needed for the reset of the node in PHNodeReset.C where
different functions have to be called depending on the object type
*/
if (thisClass->InheritsFrom("PHTable"))
{
newIODataNode->setObjectType("PHTable");
}
else
{
newIODataNode->setObjectType("PHObject");
}
thisBranch->SetAddress(&(newIODataNode->data));
for (j=1; j<nodeNameList.length()-1; j++)
{
nodeIter->cd("..");
}
}
else
{
cout << "class " << thisClass->GetName()
<< " not found dumping the warp core" <<endl;
}
}
return topNode;
}
void
PHNodeIOManager::selectObjectToRead(const char* objectName, PHBoolean readit)
{
objectToRead[objectName] = readit;
}
PHBoolean
PHNodeIOManager::isSelected(const char* objectName)
{
string name = objectName ;
map<string,TBranch*>::const_iterator p = fBranches.find(name) ;
if ( p != fBranches.end())
{
return True ;
}
else
{
return False ;
}
}
PHBoolean
PHNodeIOManager::SetCompressionLevel(int level)
{
if (level < 0)
{
return False;
}
CompressionLevel = level;
if (file)
{
file ->SetCompressionLevel(CompressionLevel);
}
return True;
}