Re: [ROOT] new histogram merger macro

From: Rene Brun (Rene.Brun@cern.ch)
Date: Wed Feb 14 2001 - 12:03:02 MET


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