Back to index

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; 
} 
 
 
 

Back to index