// // HepRootFileManager.cc - implementation the wrapper for the ROOT // histogram package // // HepRootFileManager is a C++ wrapper class that controls the // initialization and creation of histograms and ntuples and allows // them to be written to a file in the Histo format. // // This class is derived from the HepFileManager, and is not an abstract // class. It should be instantiated before any histograms or ntuples - a // pointer to the manager is passed to every histogram and ntuple upon // creation. // // write() writes the managed Histo objects to a file, as does the // destructor. // dumpAllData() and clearAllData() initiate calls of dumpData() or // clearData() to all managed objects. // // History // 20-Aug-1998 Philippe Canal Initial draft // 25-Fev-1999 Philippe Canal Add read-only files // 21-Feb-2000 Walter Brown Improved C++ standard compliance // 19-Mar-2001 Fischler hepFileFormat // // ---------------------------------------------------------------------- #include "ZMutility/ZMenvironment.h" #include #include #include #include USING ( std::string ) #ifndef ISOCXX__ISOCXX #include #endif #include USING( std::deque ) #ifndef HEPTRACE_H #include "HepTuple/HepTrace.h" #endif #ifndef HEPROOTFILEMANAGER_H #include "HepTuple/HepRootFileManager.h" #endif #ifndef HEPROOTHIST1D_H #include "HepTuple/HepRootHist1D.h" #endif #ifndef HEPROOTHIST2D_H #include "HepTuple/HepRootHist2D.h" #endif #ifndef HEPROOTHISTPROF_H #include "HepTuple/HepRootHistProf.h" #endif #ifndef HEPROOTTUPLE_H #include "HepTuple/HepRootNtuple.h" #endif #ifndef HEPDIR_H #include "HepTuple/HepDir.h" #endif #ifndef HEPOBJ_H #include "HepTuple/HepObj.h" #endif #ifndef HEPFILESWITCH_H #include "HepTuple/HepFileSwitch.h" #endif // for sprintf, remove, mkstemp, rename and close #include #include #include #include #include #include #ifdef WIN32 #include "io.h" #endif #ifdef __KCC extern "C" { int mkstemp( char* ); } #endif #include #include #include #include #include #include #include ZM_BEGIN_NAMESPACE( zmht ) /* namespace zmht { */ // ---------------------------------------------------------------------- // // Simple minded wrapper around TFile to insure that it is Write flushed // class HepTFile : public TFile { public: HepTFile(const Text_t* fname, Option_t* option, const Text_t* ftitle, Int_t compress, HepRootFileManager* man ) : TFile( fname, option, ftitle, compress ), man_(man) {}; HepTFile() : TFile() {}; virtual ~HepTFile() { if ( IsWritable() ) Write(0,kOverwrite); man_->filep_ = 0; }; private: HepTFile(const HepTFile &); // per ROOT: Files cannot be copied void operator=(const HepTFile &); HepRootFileManager *man_; }; // Simple wrapper around TBranch to allow access to its protected data // members. We need this because there is a small bug in one of the // TBranch accessor member functions class HepTBranch : public TBranch { public: static void SetDirectory( TBranch* branch, TDirectory* newDir ) { ((HepTBranch*)branch)->fDirectory = newDir; TIter next(branch->GetListOfBranches()); TBranch* subBranch; while((subBranch = (TBranch*)next())) { HepTBranch::SetDirectory( subBranch, newDir); } }; }; #define NOTYET(fctnName) \ ZMthrow(ZMxHepNotYet( \ "Warning: this manager class does not yet fully support the " \ #fctnName " call; some results may be anomalous.", ZMexWARNING)); bool HepRootFileManager::init_done = false; // get this file's simple name static string RootBaseName( const string & fileName ) { return string( fileName, fileName.rfind( '/' ) + 1 #ifdef WIN32 , string::npos #endif ); } // ensure that a path name is enforcing length requirements on root string validHepPath( const string & pathName ) { string s = pathName; if ( HepDir::isAbsPath( s ) ) { if ( s == "//" ) s = "\\"; } return s; } // return the portion of the path that does not contain the file // name // enforcing Histo's length requirement const string RootTopDir( const string & S ) { return RootBaseName( S ); } // Function to set static data member holding the root God object: void HepRootFileManager::initialiseRoot() { static TROOT root( "HepRootFileManager", "HepRootFileManager" ); } static void checkModeSanity( HepFileManager::mode_ & req_mode ) { // Check the validity of the requested file open mode. For the moment, // we only consider modes that are either single members of the mode_ // enum or two members of that enum or'ed together. // Default mode. That's clearly sane. if(req_mode == 0 ) return; // First look at the case of a single req_mode request. // By definition, these are sane. if((req_mode | HepFileManager::HEP_READONLY) == HepFileManager::HEP_READONLY) return; if((req_mode | HepFileManager::HEP_UPDATE ) == HepFileManager::HEP_UPDATE ) return; if((req_mode | HepFileManager::HEP_REFRESH ) == HepFileManager::HEP_REFRESH ) return; if((req_mode | HepFileManager::HEP_REMOVE ) == HepFileManager::HEP_REMOVE ) return; if((req_mode | HepFileManager::HEP_RENAME ) == HepFileManager::HEP_RENAME ) return; // count how many modes are turned on int numBits = 0; int mode = req_mode; while( mode != 0 ) { if( mode & 1 ) ++numBits; mode = (mode >> 1); } if( numBits == 2 ) { // READONLY may not be or'ed with anything else. if((req_mode & HepFileManager::HEP_READONLY) != 0 ) { ZMthrow(ZMxHepIncompatible( string("HEP_READONLY may not be combined with any other mode") +string("\n Resetting mode to HEP_READONLY"))); req_mode = HepFileManager::HEP_READONLY; return; } // REFRESH may be or'ed with anything except READONLY // The READONLY test above has already caught this // REMOVE may be or'ed with REFRESH only if((req_mode & HepFileManager::HEP_REMOVE) != 0 ) { if(req_mode == (HepFileManager::HEP_REMOVE | HepFileManager::HEP_REFRESH)) { return; } else { ZMthrow(ZMxHepIncompatible( string("HEP_REMOVE may only be combined with HEP_REFRESH") +string("\n Resetting mode to HEP_REMOVE only"))); req_mode = HepFileManager::HEP_REMOVE; return; } } // RENAME may be or'ed with REFRESH only if((req_mode & HepFileManager::HEP_RENAME) != 0 ) { if(req_mode == (HepFileManager::HEP_RENAME | HepFileManager::HEP_REFRESH)) { return; } else { ZMthrow(ZMxHepIncompatible( string("HEP_RENAME may only be combined with HEP_REFRESH") +string("\n Resetting mode to HEP_RENAME only"))); req_mode = HepFileManager::HEP_RENAME; return; } } // UPDATE may be or'ed with REFRESH and nothing else if((req_mode & HepFileManager::HEP_UPDATE) != 0 ) { if(req_mode == (HepFileManager::HEP_UPDATE | HepFileManager::HEP_REFRESH)) { return; } else { ZMthrow(ZMxHepIncompatible( string("HEP_UPDATE may only be combined with HEP_REFRESH") +string("\n Resetting mode to HEP_REFRESH only"))); req_mode = HepFileManager::HEP_REFRESH; return; } } return; } else { ZMthrow(ZMxHepUnsupported( string("File open modes may only be OR'ed in pairs"))); return; } } static void removeFile( const string& fName ) { int rc = remove( fName.c_str() ); if( rc != 0 ) { char tmp[20]; sprintf(tmp,"%d",errno); ZMthrow(ZMxHepCantDeleteFile( string("In HepRootFileManager: Cannot delete file ") +string( "\"" ) +fName +string( "\"\n") +string(" RC = ") +string( tmp ))); } } static void renameFile( const string& fName ) { string tempName = fName + string("XXXXXX"); char * temp = new char[1024]; strcpy( temp, tempName.c_str() ); int fd = mkstemp( temp ); if( fd == -1 ) ZMthrow(ZMxHepCantGenerateName( string("In HepRootFileManager: Cannot generate new file name "))); int rc = rename( fName.c_str(), temp ); if( rc != 0 ) { perror("Rename Error"); char tmp[20]; sprintf(tmp,"%d",errno); ZMthrow(ZMxHepCantRenameFile( string("In HepRootFileManager: Cannot rename file ") +string( "\"" ) +fName +string( "\"\n") +string(" RC = ") +string( tmp ))); } delete [] temp; close( fd ); } void HepRootFileManager::init( // constructor body (shared by both constructors) const string& fName, // desired file name HepFileManager::mode req_mode, // desired opening mode const string& rootDir, // desired name of root directory int compression // desired compression level ) { // First of all, check that the req_mode is sensible. checkModeSanity( req_mode ); // one-time class initialization if ( ! init_done & ! TROOT::Initialized() ) { initialiseRoot(); init_done = true; } // check status of this file: if exists, then open it & read its contents; // if non-existent, create it afresh: filemode mode = checkFile( fName ); bool fileExists = ( mode != HEP_ABSENT ); string option; if ( ((req_mode & HEP_READONLY) !=0 ) && (mode == HEP_ALL) ) { mode = HEP_READ; } if( fileExists && ( (req_mode & HEP_REMOVE) != 0 ) ) { removeFile( fName ); fileExists = false; mode = checkFile ( fName ); } if( fileExists && ( (req_mode & HEP_RENAME) != 0 ) ) { renameFile( fName ); fileExists = false; mode = checkFile ( fName ); } if ( fileExists ) { if ( mode == HEP_ALL ) { option = "UPDATE"; if ( (req_mode & HEP_REFRESH) !=0 ) { writeOption_ = TObject::kOverwrite; } } else if ( mode == HEP_READ ) { option = "READ"; setReadOnly ( true ); } else { // mode == HEP_NONE or mode == HEP_WRITE ZMthrow(ZMxHepCantOpenFile(string("in HepRootFileManager: can't ") +string( "open \"" ) +fName+string( "\"\n") )); setReadOnly ( true ); return; } } else { if ( (req_mode & HEP_REFRESH) !=0 ) { writeOption_ = TObject::kOverwrite; } option = "NEW"; } HEP_DEBUG( " Opening \"" << fName << "\" with root \"" << rootDir << "\"" ); // Create root file: filep_ = new HepTFile( fName.c_str(), option.c_str(), "Created for you by HepRootFileManager", compression, this ); if ( filep_ == NULL || ( ! filep_->IsOpen() ) ) { // oops, got a problem! ZMthrow(ZMxHepCantOpenFile(string("in HepRootFileManager: can't ") +string( fileExists ? "open" : "create" ) +string( " \"" ) +fName +string( "\"\n") )); } if ( fileExists ) retrieveExistingItems(); // create file's structure in memory } HepRootFileManager::HepRootFileManager( // constructor const string& fName, // desired file name HepFileManager::mode req_mode, // desired opening mode const string& rootDirName, // desired name of root directory int compression // desired compression level ) : HepFileManager( fName, RootTopDir( ( (rootDirName.length()!=0) ? rootDirName : fName ) ) ), compression_(compression), writeOption_(0) { HEP_DEBUG( "HepRootFileManager::constructor( \"" << fName << "\" )" ); init ( fName, req_mode, rootDirName, compression ); } HepRootFileManager::HepRootFileManager( // constructor const string& fName, // desired file name const string& rootDirName, // desired name of root directory int compression // desired compression level ) : HepFileManager( fName, RootTopDir( ( (rootDirName.length()!=0) ? rootDirName : fName ) ) ), compression_(compression), writeOption_(0) { HEP_DEBUG( "HepRootFileManager::constructor( \"" << fName << "\" )" ); init ( fName, HEP_UPDATE, rootDirName, compression ); } // HepRootFileManager::HepRootFileManager() HepRootFileManager::~HepRootFileManager() { // destructor HEP_DEBUG( "HepRootFileManager::destructor()" ); // Write and delete and done by the TROOT object ! if ( filep_ ) { // write(); if( !isReadOnly() ) { while ( ! objList_.empty() ) { HepObj * o = objList_.back(); if( o->isDirty() ) writeOne( o ); HepRootObj* otmp = dynamic_cast(o); if(otmp == 0) ZMthrow( ZMxHepUnknownHepObj(string( "Object with title ") +o->title()+string(" is not a known HepRootObj"))); delete otmp->data(); objList_.pop_back(); } } delete filep_; }; if ( ! true ) { // NOTE: is there a test we can put here ? ZMthrow(ZMxHepBadIO(string( "HepRootFileManager destructor: unable to properly close ")+fileName())); } } // HepRootFileManager::~HepRootFileManager() void HepRootFileManager::cd( const string & path ) { // change dir HEP_DEBUG( "HepRootFileManager::cd( \"" << path << "\" )" ); // If no path is given, we go the rootdir. if ( path.length() == 0 ) { filep_->cd(); } else { filep_->cd( inFileRootPath(path).c_str() ); } HepFileManager::cd( CurrentRootPath() ); // record the current site } // HepRootFileManager::cd() string HepRootFileManager::inFileRootPath( const string& path ) const { static string newpath; if ( ! HepDir::isAbsPath( path ) ) { newpath = pwd()+dirSep+path; } else { newpath = path; } int firstSep = newpath.find(dirSep, absStart.length() ); if ( firstSep < 0 ) { // we have //filename // let's return the null string! return (""); } // remove the file name portion! newpath.replace( 0, firstSep + 1, ""); return newpath; } const string& HepRootFileManager::CurrentRootPath() const { static string path; path = gDirectory->GetPath(); string::size_type colon = path.find(":"); if( colon != string::npos ) path.replace( 0, colon+1, "" ); int where = path.find(dirSep); path.replace( 0, where, absStart+rootDir() ); int len = path.length(); if ( path[len-1] == '/' ) { path.replace(len-1,len,""); } return path; } void HepRootFileManager::mkdir( const string & path ) { // create a dir HEP_DEBUG( "HepRootFileManager::mkdir( \"" << path << "\" )" ); if ( isReadOnly() ) { ZMthrow(ZMxHepCantWriteFile( fileName() + " is read only. Can not make directory " + path + "." )); return; } string newDir = validHepPath( path ); if (newDir.length() == 0 ) return; string dir = HepDir::dirname(path); string base = HepDir::basename(path); if ( base.length() == path.length() ) { // we just have a directory name not a path base = ""; } TDirectory* olddir= gDirectory; filep_->cd( inFileRootPath(base).c_str() ); gDirectory->mkdir( dir.c_str() ); olddir->cd(); HepFileManager::mkdir(newDir); } // HepRootFileManager::mkdir() string HepRootFileManager::ls( // list a dir const string & path , const string & chopt ) const { string p = validHepPath(path); return HepFileManager::ls(p,chopt); } void HepRootFileManager::rmdir( const string & path, bool recursive ) { // delete a dir HEP_DEBUG( "HepRootFileManager::rmdir( \"" << path << "\" )" ); if ( isReadOnly() ) { ZMthrow(ZMxHepCantWriteFile( fileName() + " is read only. Can not remove directory " + path + "." )); return; } if ( ! recursive ) { // We only remove the directory if it is empty string res = ls(path); // This always contains as a first line the name of the current directory res = res.substr(res.find("\n")+1,res.length()); if ( res.length() != 0 ) { // the directory is not empty. let's fails: ZMthrow(ZMxHepImproperUse("Try to remove a non empty directory. use rmdir(path,true) if this was intended\n")); return; } } TDirectory* olddir= gDirectory; filep_->cd( inFileRootPath(path).c_str() ); TDirectory* newdir = gDirectory; if ( newdir == NULL ) { ZMthrow(ZMxHepImproperUse(string("Try to remove a non existing directory") +path )); } string goner = HepDir::dirname( newdir->GetPath() ) + ";*"; if ( newdir == olddir ) { newdir->cd(".."); olddir = gDirectory; } else { newdir->cd(".."); } filep_->Delete( goner.c_str() ); // remove the object in the HepFileManager even in case of error // because we do not know how much was removed! HepFileManager::rmdir( path, recursive ); olddir->cd(); if ( ! true ) { // NOTE: Is there a way to test success ? ZMthrow(ZMxHepBadIO(string("in HepRootFilemanager failed to remove dir ") +goner)); return; } HEP_DEBUG( " removed \"" << goner << "\"" ); } // HepRootFileManager::rmdir() void HepRootFileManager::rm( int id ) { // delete a histogram or ntuple HEP_DEBUG( "HepRootFileManager::rm( " << id << " )" ); if ( isReadOnly() ) { ZMthrow(ZMxHepCantWriteFile( fileName() + " is read only. Can not remove item." )); return; } HepObjList::const_iterator iter = findObj( id ); if ( iter == objList_.end() ) { char tmp[20]; sprintf(tmp,"%d",id); ZMthrow(ZMxHepBadIO(string("Could not find object with id: ") +tmp)); return; } TDirectory* olddir = gDirectory; filep_->cd( inFileRootPath( (*iter)->dir() ).c_str() ); TDirectory* cwd = gDirectory; cwd->Delete( ((*iter)->title() + ";*").c_str() ); olddir->cd(); // remove the object in the HepFileManager even in case of error // because we do not know how much was removed! HepFileManager::rm( id ); if ( ! true ) { // NOTE: can we have a test here ? char tmp[20]; sprintf(tmp,"%d",id); ZMthrow(ZMxHepBadIO(string("in HepRootFileManager failed to remove item ") +tmp)); return; } } void HepRootFileManager::rm( const string & title ) { // delete a histogram or ntuple HEP_DEBUG( "HepRootFileManager::rm( \"" << title << "\" )" ); if ( isReadOnly() ) { ZMthrow(ZMxHepCantWriteFile( fileName() + " is read only. Can not remove item " + title + "." )); return; } HepObjList::const_iterator iter = findObj( title ); if ( iter == objList_.end() ) { ZMthrow(ZMxHepBadIO(string("could find object with title: ") +title)); return; } TDirectory* olddir = gDirectory; filep_->cd( inFileRootPath( (*iter)->dir() ).c_str() ); TDirectory* cwd = gDirectory; cwd->Delete( ((*iter)->title() + ";*").c_str() ); olddir->cd(); // remove the object in the HepFileManager even in case of error // because we do not know how much was removed! HepFileManager::rm( int( (*iter)->id() ) ); if ( ! true ) { // NOTE: can we have a test here ? ZMthrow(ZMxHepBadIO(string("in HepRootFileManager failed to remove item ") +title)); return; } } void HepRootFileManager::writeDirectory() { // write the managed objects to the file HEP_DEBUG( "HepRootFileManager::writeDirectory()" ); if ( ! isReadOnly () ) { TDirectory* olddir= gDirectory; filep_->cd( inFileRootPath(pwd()).c_str() ); TDirectory* cwd= gDirectory; cwd->Write(0,writeOption_); olddir->cd(); const string path(pwd()); const string sub_path(path+dirSep); int len = sub_path.length(); for ( HepObjList::const_iterator i = objList_.begin() ; i != objList_.end() ; ++i ) { HepObj * o = *i; if ( o->dir() == path || sub_path == (o->dir()).substr(0,len) ) HepFileManager::writeOne( o ); } } } // HepRootFileManager::writeDirectory() int HepRootFileManager::write() { // write the managed objects to the file HEP_DEBUG( "HepRootFileManager::write()" ); if ( ! isReadOnly () ) { for ( HepObjList::const_iterator i = objList_.begin() ; i != objList_.end() ; ++i ) { HepObj * o = *i; writeOne( o ); } // Write out the directory keys HepFileManager::ItemList allDirs = list( HepDir::topname( pwd()),"rD" ); HepFileManager::ItemList::const_iterator it; string path; string oldDir = pwd(); for( it = allDirs.begin(); it != allDirs.end(); it++ ) { path = it->dir+"/"+it->title; cd(path); gDirectory->SaveSelf(kTRUE); } cd(oldDir); // And, finally, write out some file-level stuff filep_->SaveSelf(kTRUE); filep_->WriteStreamerInfo(); filep_->WriteFree(); filep_->WriteHeader(); return 0; } else { return -1; } } // HepRootFileManager::write() void HepRootFileManager::writeOne( HepObj * o ) { HEP_DEBUG( "HepRootFileManager::writeOne( " << o->id() << " )" ); HepRootObj* otmp = dynamic_cast(o); if( otmp == 0 ) ZMthrow( ZMxHepUnknownHepObj( string( "Object with title " ) + o->title() + string( " is not a known HepRootObj" ) ) ); if( o->isDirty() ) { string where = this->pwd(); string dir = o->dir(); this->cd( dir ); otmp->Write(0,writeOption_); this->cd( where ); } HepFileManager::writeOne( o ); } // HepRootFileManager::writeOne() #ifdef LATER void HepRootFileManager::dumpAllData() { // call dumpData() for all listed tuples HepAListIterator i( ntuples_ ); HepRootTuple *p; while ( p = i() ) p->dumpData(); } // HepRootFileManager::dumpAllData() void HepRootFileManager::clearAllData() { // call clearData() for all listed tuples HepAListIterator i( ntuples_ ); HepRootTuple *p; while ( p = i() ) p->clearData(); } // HepRootFileManager::clearAllData() #endif // LATER // Create HepRoot-specific histograms: -------------------------------- // Using title as a key, find the plot with the given title. If it is // not found, create a new plot with the given title, and return that. // The HepRoot ID of the plot is optionally specified by the user. HepHist1D & HepRootFileManager::hist1D( const string& title , const int nBins, const float low, const float high , const int uid ) { if ( isReadOnly() ) { ZMthrow(ZMxHepCantMakeHist( fileName() + " is read-only; " + title + " can not be created." )); return deadHist1D(); } if ( ! checkTitle( title ) ) { ZMthrow(ZMxHepCantMakeHist( string("'")+ title + "' is an invalid object name." )); return deadHist1D(); } if ( findObj( title ) == objList_.end() && findObj( uid ) == objList_.end() ) { cd ( pwd() ); // Histo uid is the HepFileManager id string name = title; TDirectory* olddir= gDirectory; filep_->cd( inFileRootPath(pwd()).c_str() ); HepRootHist1D * h = new HepRootHist1D( this, title, nBins, low, high, uid); olddir->cd(); isInUse( h, true ); isDirty( h, true ); isCreated( h, true ); return *h; } else { ZMthrow(ZMxHepCantMakeHist( "Can not create a hist1D with an existing name or id")); return deadHist1D(); } } HepHist2D & HepRootFileManager::hist2D( const string& title , const int nBinsX, const float lowX, const float highX , const int nBinsY, const float lowY, const float highY , const int uid ) { if ( isReadOnly() ) { ZMthrow(ZMxHepCantMakeHist( fileName() + " is read-only; " + title + " can not be created." )); return deadHist2D(); } if ( ! checkTitle( title ) ) { ZMthrow(ZMxHepCantMakeHist( string("'")+ title + "' is an invalid object name." )); return deadHist2D(); } if ( findObj( title ) == objList_.end() && findObj( uid ) == objList_.end() ) { TDirectory* olddir= gDirectory; filep_->cd( inFileRootPath(pwd()).c_str() ); HepRootHist2D * h = new HepRootHist2D( this, title, nBinsX, lowX, highX, nBinsY, lowY, highY, uid ); olddir->cd(); isInUse( h, true ); isDirty( h, true ); isCreated( h, true ); return *h; } else { ZMthrow(ZMxHepCantMakeHist( "Can not create a hist2D with an existing name or id")); return deadHist2D(); } } HepHistProf & HepRootFileManager::histProf( const string& title , const int nBinsX, const float lowX, const float highX , const float lowY, const float highY , const string& chopt , const int id ) { if ( isReadOnly() ) { ZMthrow(ZMxHepCantMakeHist( fileName() + " is read-only; " + title + " can not be created." )); return deadHistProf(); } if ( ! checkTitle( title ) ) { ZMthrow(ZMxHepCantMakeHist( string("'")+ title + "' is an invalid object name." )); return deadHistProf(); } if ( findObj( title ) == objList_.end() && findObj( id ) == objList_.end() ) { TDirectory* olddir= gDirectory; filep_->cd( inFileRootPath(pwd()).c_str() ); HepRootHistProf * h = new HepRootHistProf( this, title, nBinsX, lowX, highX, lowY, highY, chopt, id ); olddir->cd(); isInUse( h, true ); isDirty( h, true ); isCreated( h, true ); return *h; } else { ZMthrow(ZMxHepCantMakeHist( "Can not create a histProf with an existing name or id")); return deadHistProf(); } } HepHistProf & HepRootFileManager::histProf( const string& title , const int nBinsX, const float lowX, const float highX , const float lowY, const float highY , const int id ) { if ( isReadOnly() ) { ZMthrow(ZMxHepCantMakeHist( fileName() + " is read-only; " + title + " can not be created." )); return deadHistProf(); } if ( ! checkTitle( title ) ) { ZMthrow(ZMxHepCantMakeHist( string("'")+ title + "' is an invalid object name." )); return deadHistProf(); } if ( findObj( title ) == objList_.end() && findObj( id ) == objList_.end() ) { TDirectory* olddir= gDirectory; filep_->cd( inFileRootPath(pwd()).c_str() ); HepRootHistProf * h = new HepRootHistProf( this, title, nBinsX, lowX, highX, lowY, highY, " ", id ); olddir->cd(); isInUse( h, true ); isDirty( h, true ); isCreated( h, true ); return *h; } else { ZMthrow(ZMxHepCantMakeHist( "Can not create a histProf with an existing name or id")); return deadHistProf(); } } // attach to existing histograms: ------------------------------------ HepHist1D & HepRootFileManager::retrieveHist1D( // 1-D const string& title, const int hid ) { HepHist1D & h = HepFileManager::retrieveHist1D( title, hid ); isInUse( &h, true ); return h; } HepHist2D & HepRootFileManager::retrieveHist2D( // 2-D const string& title, const int hid ) { HepHist2D & h = HepFileManager::retrieveHist2D( title, hid ); isInUse( &h, true ); return h; } HepHistProf & HepRootFileManager::retrieveHistProf( // profile plot const string& title, const int hid ) { HepHistProf & h = HepFileManager::retrieveHistProf( title, hid ); isInUse( &h, true ); return h; } // Create HepNtuple HepNtuple & HepRootFileManager::ntuple( // ntuple const string& title, const int id ) { HEP_DEBUG( "HepRootFileManager::ntuple( \"" << title << "\", " << id << " )" ); if ( isReadOnly() ) { ZMthrow(ZMxHepCantMakeNtuple( fileName() + " is read-only; " + title + " can not be created." )); return deadNtuple(); } if ( ! checkTitle( title ) ) { ZMthrow(ZMxHepCantMakeNtuple( string("'")+ title + "' is an invalid object name." )); return deadNtuple(); } if ( findObj( title ) == objList_.end() && findObj( id ) == objList_.end() ) { TDirectory* olddir= gDirectory; filep_->cd( inFileRootPath(pwd()).c_str() ); HepNtuple * t = new HepRootNtuple( this, title, id ); olddir->cd(); isInUse( t, true ); isDirty( t, true ); isCreated( t, true ); return *t; } else { ZMthrow(ZMxHepCantMakeNtuple( "Can not create an Ntuple with an existing name or id")); return deadNtuple(); } } HepNtuple & HepRootFileManager::retrieveNtuple( // Ntuple const string& title, const int hid ) { HepNtuple & h = HepFileManager::retrieveNtuple( title, hid ); isInUse( &h, true ); return h; } // user is finished with the indicated object void HepRootFileManager::release( HepObj & o ) { HEP_DEBUG( "HepRootFileManager::release()" ); HepFileManager::release( o ); } // traverse the directories in the file to create C++ objects for existing // histograms & ntuples: void HepRootFileManager::retrieveExistingItems() { HEP_DEBUG( "HepRootFileManager::retrieveExistingItems()" ); // make a list for the subdirectories STL_DEQUE(TObject*) dirs; TObject* obj; TKey* key; TIter next( gDirectory->GetListOfKeys() ); string previous; while ((key = (TKey *) next())) { obj = key->ReadObj(); // We assume in the following that the list is sorted by // sorted by object and from newer to oldest cycles. if (obj->InheritsFrom("TDirectory")) { // case of directory dirs.push_back( obj ); } else { if ( previous != obj->GetName() ) { HepObj *h; HepRootNtuple *th; if (obj->InheritsFrom("TH2")) { // case of TH2 h = new HepRootHist2D( this, (TH1*) obj ); isDirty( h, false ); isCreated( h, true ); previous = obj->GetName(); } else if (obj->InheritsFrom("TProfile")) {// case of TProfile h = new HepRootHistProf( this, (TProfile*) obj ); isDirty( h, false ); isCreated( h, true ); previous = obj->GetName(); } else if (obj->InheritsFrom("TH1")) { // case of TH1 or TProfile h = new HepRootHist1D( this, (TH1*) obj ); isDirty( h, false ); isCreated( h, true ); previous = obj->GetName(); } else if (obj->InheritsFrom("TTree")) { //case of a TTree or TNtuple h = th = new HepRootNtuple( this, (TTree*) obj ); // and restore a lot of dirty details about it's internal structure. if( ! th->restoreNtuple() ) { ZMthrow(ZMxHepCantMakeNtuple(string("Failed to restore Ntuple with title")+ obj->GetName() )); } isDirty( h, false ); isCreated( h, true ); previous = obj->GetName(); } else { // case of unsupported data types // just ignore it for now. } } else { // Presumably an older cycle of something we've already seen. delete obj; } } } // end of for each items // call this function for each subdirectory in the list while ( ! dirs.empty() ) { TDirectory * curr = gDirectory; TDirectory * next = (TDirectory*) dirs.front(); mkdir_( next->GetName() ); // create the internal representation cd ( next->GetName() ); gDirectory = next; // change to given directory retrieveExistingItems(); // handle histograms & ntuples there dirs.pop_front(); // free up list resource cd ( ".." ); gDirectory = curr; // back to remembered directory } } // HepRootFileManager::retrieveExistingItems() // ************************************ // // ******* Return pointer to TFile **** // // ************************************ // TFile * HepRootFileManager::file() const { return filep_; } HepTupleFileFormat HepRootFileManager::hepFileFormat() const { return HEPTUPLE_ROOT; } bool HepRootFileManager::switchFile( const string& newFileName, const bool resetHists ) { // Clone the full directory structure of the current output file onto // a new output file, redirect all existing, managed objects to it and // close the current output file std::vector strays; // Tobject's we don't know what to do with TFile* holdp = filep_; bool status = true; // Flush out eveything in memory write(); // Instantiate a new TFile object with the same user specified // parameters as the original TFile object TFile* filep2 = new HepTFile( newFileName.c_str(), filep_->GetOption(), "Created for you by HepRootFileManager", filep_->GetCompressionLevel(), this ); // Reproduce the Root file directory structure status = status && cloneDir( filep_, filep2, strays, resetHists ); // Update the TFile pointer and delete the old TFile object delete holdp; filep_ = filep2; HepFileManager::switchFile( newFileName, resetHists ); return status; } bool HepRootFileManager::switchFile( const string& newFileName, const bool resetHists, HepFileSwitch& userHandler ) { // Clone the full directory structure of the current output file onto // a new output file, redirect all existing, managed objects to it and // close the current output file std::vector strays; // Tobject's we don't recognize go here TFile* holdp = filep_; bool status = true; // Flush out eveything in memory write(); // Instantiate a new TFile object with the same user specified // parameters as the original TFile object TFile* filep2 = new HepTFile( newFileName.c_str(), filep_->GetOption(), "Created for you by HepRootFileManager", filep_->GetCompressionLevel(), this ); // Reproduce the Root file directory structure status = status && cloneDir( filep_, filep2, strays, resetHists ); // If the list of stray TObject* is not empty, pass it along to the // user's handler for disposition. if( !strays.empty() ) userHandler.strayObjectHandler( strays ); // Update the TFile pointer and delete the old TFile object delete holdp; filep_ = filep2; HepFileManager::switchFile( newFileName, resetHists ); return status; } bool HepRootFileManager::cloneDir( TDirectory* oldFile, TDirectory* newFile, std::vector& strays, bool resetHists ) { TObject* obj; TH1* hnew = 0; TDirectory* dold = 0; TDirectory* dnew = 0; TTree* tnew = 0; TBranch* branch = 0; bool status = true; // Iterate over all the objects on the old TFile object and make equivalent // objects on the new one. Reset histograms or not as requested by the user. TIter next( oldFile->GetList() ); while( (obj = (TObject*)next()) ) { if( obj->InheritsFrom("TDirectory") ) { dold = (TDirectory*)obj; dnew = newFile->mkdir( dold->GetName(), dold->GetName() ); status = status && cloneDir( dold, dnew, strays, resetHists ); } else if( obj->InheritsFrom("TH1") ) { hnew = (TH1*)obj; if( resetHists ) hnew->Reset(); hnew->SetDirectory(newFile); } else if( obj->InheritsFrom("TTree") ) { tnew = (TTree*)obj; tnew->SetDirectory(newFile); tnew->Reset(); TIter nextb(tnew->GetListOfBranches()); while((branch = (TBranch*)nextb())) { HepTBranch::SetDirectory( branch, newFile ); } } else { strays.push_back((void*)obj); // Make a note of these to pass back to the user status = false; } } return status; } // ************************************ // // ******* Dead Object creators ******* // // ************************************ // HepNtuple& HepRootFileManager::deadNtuple() const { return HepRootFileManager::deadRootNtuple(); } HepHist1D& HepRootFileManager::deadHist1D() const { return HepRootFileManager::deadRootHist1D(); } HepHist2D& HepRootFileManager::deadHist2D() const { return HepRootFileManager::deadRootHist2D(); } HepHistProf& HepRootFileManager::deadHistProf() const { return HepRootFileManager::deadRootHistProf(); } HepRootNtuple& HepRootFileManager::deadRootNtuple() { static HepRootNtuple deadRoot; return deadRoot; } HepRootHist1D& HepRootFileManager::deadRootHist1D() { static HepRootHist1D deadRoot; return deadRoot; } HepRootHist2D& HepRootFileManager::deadRootHist2D() { static HepRootHist2D deadRoot; return deadRoot; } HepRootHistProf& HepRootFileManager::deadRootHistProf() { static HepRootHistProf deadRoot; return deadRoot; } ZM_END_NAMESPACE( zmht ) /* } // namespace zmht */