Hi Sven I have added your macro to the list of macros in tutorials. I have kept the old macro hadd.c as hadd_old.C Rene Sven Schmidt wrote: > > Hi, > > I follow up on my previous post on the problem of hadd.C (from the > tutorials) failing to merge rootfiles with more than 1 level of > subdirectories. I looked at the code but couldn't find the reason why it > isn't working and so I decided to start from scratch. > > Attached to this message you find a new macro that will merge histograms > with more than one level of subdirectories. > > Have fun, > Sven > > -------------------------------------------------------------------------------- > /* > > This macro will add histograms from a list of root files and write them > to a target root file. The target file is newly created and must not be > identical to one of the source files. > > Syntax: > > hist_add targetfile source1 source2 ... > > Author: Sven A. Schmidt, sven.schmidt@cern.ch > Date: 13.2.2001 > > This code is based on the hadd.C example by Rene Brun and Dirk Geppert, > which had a problem with directories more than one level deep. > > I have tested this macro on rootfiles with one and two dimensional > histograms, and two levels of subdirectories. Feel free to send comments > or bug reports to me. > > */ > > #include <TROOT.h> > #include "TFile.h" > #include "TH1.h" > #include "TTree.h" > #include "TKey.h" > #include <string.h> > #include <iostream.h> > > TROOT Root( "hist_add", "Histogram Merger" ); > > TList *FileList; > TFile *Target; > > void MergeRootfile( TDirectory *target, TList *sourcelist ); > > int main( int argc, char **argv ) { > > FileList = new TList(); > > if ( argc < 4 ) { > cout << "Usage: " << argv[0] << " <target> <source1> <source2> ...\n"; > cout << "supply at least two source files for this to make sense... ;-)\n"; > exit( -1 ); > } > > cout << "Target file: " << argv[1] << endl; > Target = TFile::Open( argv[1], "RECREATE" ); > > for ( int i = 2; i < argc; i++ ) { > cout << "Source file " << i-1 << ": " << argv[i] << endl; > FileList->Add( TFile::Open( argv[i] ) ); > } > > MergeRootfile( Target, FileList ); > > } > > // Merge all files from sourcelist into the target directory. > // The directory level (depth) is determined by the target directory's > // current level > void MergeRootfile( TDirectory *target, TList *sourcelist ) { > > // cout << "Target path: " << target->GetPath() << endl; > TString path( (char*)strstr( target->GetPath(), ":" ) ); > path.Remove( 0, 2 ); > > TFile *first_source = (TFile*)sourcelist->First(); > first_source->cd( path ); > TDirectory *current_sourcedir = gDirectory; > > // loop over all keys in this directory > TIter nextkey( current_sourcedir->GetListOfKeys() ); > while ( TKey *key = (TKey*)nextkey() ) { > > // read object from first source file > first_source->cd( path ); > TObject *obj = key->ReadObj(); > > if ( obj->IsA()->InheritsFrom( "TH1" ) ) { > // descendant of TH1 -> merge it > > // cout << "Merging histogram " << obj->GetName() << endl; > TH1 *h1 = (TH1*)obj; > > // loop over all source files and add the content of the > // correspondant histogram to the one pointed to by "h1" > TFile *nextsource = (TFile*)sourcelist->After( first_source ); > while ( nextsource ) { > > // make sure we are at the correct directory level by cd'ing to path > nextsource->cd( path ); > TH1 *h2 = (TH1*)gDirectory->Get( h1->GetName() ); > if ( h2 ) { > h1->Add( h2 ); > delete h2; // don't know if this is necessary, i.e. if > // h2 is created by the call to gDirectory above. > } > > nextsource = (TFile*)sourcelist->After( nextsource ); > } > > } else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) { > // it's a subdirectory > > cout << "Found subdirectory " << obj->GetName() << endl; > > // create a new subdir of same name and title in the target file > target->cd(); > TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() ); > > // newdir is now the starting point of another round of merging > // newdir still knows its depth within the target file via > // GetPath(), so we can still figure out where we are in the recursion > MergeRootfile( newdir, sourcelist ); > > } else { > // object is of no type that we know or can handle > cout << "Unknown object type, name: " > << obj->GetName() << " title: " << obj->GetTitle() << endl; > } > > // now write the merged histogram (which is "in" obj) to the target file > // note that this will just store obj in the current directory level, > // which is not persistent until the complete directory itself is stored > // by "target->Write()" below > if ( obj ) { > target->cd(); > obj->Write( key->GetName() ); > } > > } // while ( ( TKey *key = (TKey*)nextkey() ) ) > > // save modifications to target file > target->Write(); > > }
This archive was generated by hypermail 2b29 : Tue Jan 01 2002 - 17:50:36 MET