ROOT logo
  //macro to add histogram files
  //NOTE: This macro is kept for back compatibility only.
  //Use instead the executable $ROOTSYS/bin/hadd
  //
  //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.
  //
  //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.
  //(see macro hadd_old.C for this previous implementation).
  //
  //The macro from Sven has been enhanced by 
  //   Anne-Sylvie Nicollerat <Anne-Sylvie.Nicollerat@cern.ch>
  // to automatically add Trees (via a chain of trees).
  //
  //To use this macro, modify the file names in function hadd.
  //
  //NB: This macro is provided as a tutorial.
  //    Use $ROOTSYS/bin/hadd to merge many histogram files



#include <string.h>
#include "TChain.h"
#include "TFile.h"
#include "TH1.h"
#include "TTree.h"
#include "TKey.h"
#include "Riostream.h"

TList *FileList;
TFile *Target;

void MergeRootfile( TDirectory *target, TList *sourcelist );


void hadd() {
   // in an interactive ROOT session, edit the file names
   // Target and FileList, then
   // root > .L hadd.C
   // root > hadd()
   
  Target = TFile::Open( "result.root", "RECREATE" );
  
  FileList = new TList();
  FileList->Add( TFile::Open("hsimple1.root") );
  FileList->Add( TFile::Open("hsimple2.root") );
  
  MergeRootfile( Target, FileList );

}   

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;
  //gain time, do not add the objects in the list in memory
  Bool_t status = TH1::AddDirectoryStatus();
  TH1::AddDirectory(kFALSE);

  // loop over all keys in this directory
  TChain *globChain = 0;
  TIter nextkey( current_sourcedir->GetListOfKeys() );
  TKey *key, *oldkey=0;
  while ( (key = (TKey*)nextkey())) {

    //keep only the highest cycle number for each key
    if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;

    // 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 );
        TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(h1->GetName());
        if (key2) {
           TH1 *h2 = (TH1*)key2->ReadObj();
           h1->Add( h2 );
           delete h2;
        }

        nextsource = (TFile*)sourcelist->After( nextsource );
      }
    }
    else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {
      
      // loop over all source files create a chain of Trees "globChain"
      const char* obj_name= obj->GetName();

      globChain = new TChain(obj_name);
      globChain->Add(first_source->GetName());
      TFile *nextsource = (TFile*)sourcelist->After( first_source );
      //      const char* file_name = nextsource->GetName();
      // cout << "file name  " << file_name << endl;
     while ( nextsource ) {
     	  
       globChain->Add(nextsource->GetName());
       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();

      //!!if the object is a tree, it is stored in globChain...
	if(obj->IsA()->InheritsFrom( "TTree" ))
          globChain->Merge(target->GetFile(),0,"keep");
	else
	obj->Write( key->GetName() );
    }

  } // while ( ( TKey *key = (TKey*)nextkey() ) )

  // save modifications to target file
  target->SaveSelf(kTRUE);
  TH1::AddDirectory(status);
}
 hadd.C:1
 hadd.C:2
 hadd.C:3
 hadd.C:4
 hadd.C:5
 hadd.C:6
 hadd.C:7
 hadd.C:8
 hadd.C:9
 hadd.C:10
 hadd.C:11
 hadd.C:12
 hadd.C:13
 hadd.C:14
 hadd.C:15
 hadd.C:16
 hadd.C:17
 hadd.C:18
 hadd.C:19
 hadd.C:20
 hadd.C:21
 hadd.C:22
 hadd.C:23
 hadd.C:24
 hadd.C:25
 hadd.C:26
 hadd.C:27
 hadd.C:28
 hadd.C:29
 hadd.C:30
 hadd.C:31
 hadd.C:32
 hadd.C:33
 hadd.C:34
 hadd.C:35
 hadd.C:36
 hadd.C:37
 hadd.C:38
 hadd.C:39
 hadd.C:40
 hadd.C:41
 hadd.C:42
 hadd.C:43
 hadd.C:44
 hadd.C:45
 hadd.C:46
 hadd.C:47
 hadd.C:48
 hadd.C:49
 hadd.C:50
 hadd.C:51
 hadd.C:52
 hadd.C:53
 hadd.C:54
 hadd.C:55
 hadd.C:56
 hadd.C:57
 hadd.C:58
 hadd.C:59
 hadd.C:60
 hadd.C:61
 hadd.C:62
 hadd.C:63
 hadd.C:64
 hadd.C:65
 hadd.C:66
 hadd.C:67
 hadd.C:68
 hadd.C:69
 hadd.C:70
 hadd.C:71
 hadd.C:72
 hadd.C:73
 hadd.C:74
 hadd.C:75
 hadd.C:76
 hadd.C:77
 hadd.C:78
 hadd.C:79
 hadd.C:80
 hadd.C:81
 hadd.C:82
 hadd.C:83
 hadd.C:84
 hadd.C:85
 hadd.C:86
 hadd.C:87
 hadd.C:88
 hadd.C:89
 hadd.C:90
 hadd.C:91
 hadd.C:92
 hadd.C:93
 hadd.C:94
 hadd.C:95
 hadd.C:96
 hadd.C:97
 hadd.C:98
 hadd.C:99
 hadd.C:100
 hadd.C:101
 hadd.C:102
 hadd.C:103
 hadd.C:104
 hadd.C:105
 hadd.C:106
 hadd.C:107
 hadd.C:108
 hadd.C:109
 hadd.C:110
 hadd.C:111
 hadd.C:112
 hadd.C:113
 hadd.C:114
 hadd.C:115
 hadd.C:116
 hadd.C:117
 hadd.C:118
 hadd.C:119
 hadd.C:120
 hadd.C:121
 hadd.C:122
 hadd.C:123
 hadd.C:124
 hadd.C:125
 hadd.C:126
 hadd.C:127
 hadd.C:128
 hadd.C:129
 hadd.C:130
 hadd.C:131
 hadd.C:132
 hadd.C:133
 hadd.C:134
 hadd.C:135
 hadd.C:136
 hadd.C:137
 hadd.C:138
 hadd.C:139
 hadd.C:140
 hadd.C:141
 hadd.C:142
 hadd.C:143
 hadd.C:144
 hadd.C:145
 hadd.C:146
 hadd.C:147
 hadd.C:148
 hadd.C:149
 hadd.C:150
 hadd.C:151
 hadd.C:152
 hadd.C:153
 hadd.C:154
 hadd.C:155
 hadd.C:156
 hadd.C:157
 hadd.C:158
 hadd.C:159
 hadd.C:160
 hadd.C:161
 hadd.C:162
 hadd.C:163