Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
root_merge.cc
Go to the documentation of this file.
1 /*
2 
3  This macro will add histograms from a list of root files and write them
4  to a target root file. The target file is newly created and must not be
5  identical to one of the source files.
6 
7  Author: Sven A. Schmidt, sven.schmidt@cern.ch
8  Date: 13.2.2001
9 
10  This code is based on the hadd.C example by Rene Brun and Dirk Geppert,
11  which had a problem with directories more than one level deep.
12  (see macro hadd_old.C for this previous implementation).
13 
14  The macro from Sven has been enhanced by
15  Anne-Sylvie Nicollerat <Anne-Sylvie.Nicollerat@cern.ch>
16  to automatically add Trees (via a chain of trees).
17 
18  To use this macro, modify the file names in function hadd.
19 
20  NB: This macro is provided as a tutorial.
21  Use $ROOTSYS/bin/hadd to merge many histogram files
22 
23  */
24 
25 #include <stdlib.h>
26 
27 #include <string>
28 #include <iostream>
29 #include <iomanip>
30 using namespace std;
31 
32 #include <TChain.h>
33 #include <TFile.h>
34 #include <TH1.h>
35 #include <TTree.h>
36 #include <TKey.h>
37 #include <Riostream.h>
38 
39 TList *FileList;
40 TFile *Target;
41 
42 const char *OUTPUT_FILENAME = "merged.root";
43 
44 void Usage(void);
45 void ParseCommandLineArguments(int narg, char* argv[]);
46 void MergeRootfile( TDirectory *target, TList *sourcelist );
47 
48 //--------------
49 // main
50 //--------------
51 int main(int narg, char* argv[])
52 {
53  // create empty list of input files
54  FileList = new TList();
55 
56  // Parse command line to fill list
57  ParseCommandLineArguments(narg, argv);
58 
59  // Open ROOT file for output
60  Target = new TFile(OUTPUT_FILENAME,"RECREATE","Produced by root_merge");
61  cout<<"Opened ROOT file \""<<OUTPUT_FILENAME<<"\" ..."<<endl;
62 
63  // Merge input files into output file
65 
66  // Close output file
67  Target->Write();
68  delete Target;
69  cout<<endl<<"Closed ROOT file: "<<OUTPUT_FILENAME<<endl;
70 
71  return 0;
72 }
73 
74 //--------------
75 // Usage
76 //--------------
77 void Usage(void)
78 {
79  cout<<endl;
80  cout<<" root_merge [options] infput_file1 input_file2 input_file3 ..."<<endl;
81  cout<<endl;
82  cout<<"options:"<<endl;
83  cout<<" -o filename set output filename (def:"<<OUTPUT_FILENAME<<")"<<endl;
84  cout<<" -h Print this usage statement"<<endl;
85  cout<<endl;
86  cout<<endl;
87 
88  exit(0);
89 }
90 
91 //--------------
92 // ParseCommandLineArguments
93 //--------------
94 void ParseCommandLineArguments(int narg, char* argv[])
95 {
96  if(narg==1)Usage();
97 
98  for(int i=1; i<narg; i++){
99  if(argv[i][0] == '-'){
100  switch(argv[i][1]){
101  case 'o':
102  i++;
103  OUTPUT_FILENAME = argv[i];
104  break;
105  case 'h':
106  Usage();
107  break;
108  default:
109  cout<<"Unknown option \""<<argv[i]<<"\". Aborting."<<endl;
110  exit(-1);
111  }
112  }else{
113  FileList->Add( TFile::Open(argv[i]));
114  }
115  }
116 }
117 
118 #if 0
119 void hadd() {
120  // in an interactive ROOT session, edit the file names
121  // Target and FileList, then
122  // root > .L hadd.C
123  // root > hadd()
124 
125  Target = TFile::Open( "result.root", "RECREATE" );
126 
127  FileList = new TList();
128  FileList->Add( TFile::Open("hsimple1.root") );
129  FileList->Add( TFile::Open("hsimple2.root") );
130 
132 
133 }
134 #endif
135 
136 //--------------
137 // MergeRootfile
138 //--------------
139 void MergeRootfile( TDirectory *target, TList *sourcelist ) {
140 
141  // cout << "Target path: " << target->GetPath() << endl;
142  TString path( (char*)strstr( target->GetPath(), ":" ) );
143  path.Remove( 0, 2 );
144 
145  TFile *first_source = (TFile*)sourcelist->First();
146  first_source->cd( path );
147  TDirectory *current_sourcedir = gDirectory;
148 
149  // loop over all keys in this directory
150  TChain *globChain = 0;
151  TIter nextkey( current_sourcedir->GetListOfKeys() );
152  TKey *key;
153  while ( (key = (TKey*)nextkey())) {
154 
155  // read object from first source file
156  first_source->cd( path );
157  TObject *obj = key->ReadObj();
158 
159  if ( obj->IsA()->InheritsFrom( "TH1" ) ) {
160  // descendant of TH1 -> merge it
161 
162  // cout << "Merging histogram " << obj->GetName() << endl;
163  TH1 *h1 = (TH1*)obj;
164 
165  // loop over all source files and add the content of the
166  // correspondant histogram to the one pointed to by "h1"
167  TFile *nextsource = (TFile*)sourcelist->After( first_source );
168  while ( nextsource ) {
169 
170  // make sure we are at the correct directory level by cd'ing to path
171  nextsource->cd( path );
172  TH1 *h2 = (TH1*)gDirectory->Get( h1->GetName() );
173  if ( h2 ) {
174  h1->Add( h2 );
175  delete h2; // don't know if this is necessary, i.e. if
176  // h2 is created by the call to gDirectory above.
177  }
178 
179  nextsource = (TFile*)sourcelist->After( nextsource );
180  }
181  }
182  else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {
183 
184  // loop over all source files create a chain of Trees "globChain"
185  const char* obj_name= obj->GetName();
186 
187  globChain = new TChain(obj_name);
188  globChain->Add(first_source->GetName());
189  TFile *nextsource = (TFile*)sourcelist->After( first_source );
190  // const char* file_name = nextsource->GetName();
191  // cout << "file name " << file_name << endl;
192  while ( nextsource ) {
193 
194  globChain->Add(nextsource->GetName());
195  nextsource = (TFile*)sourcelist->After( nextsource );
196  }
197 
198  } else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
199  // it's a subdirectory
200 
201  cout << "Found subdirectory " << obj->GetName() << endl;
202 
203  // create a new subdir of same name and title in the target file
204  target->cd();
205  TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
206 
207  // newdir is now the starting point of another round of merging
208  // newdir still knows its depth within the target file via
209  // GetPath(), so we can still figure out where we are in the recursion
210  MergeRootfile( newdir, sourcelist );
211 
212  } else {
213 
214  // object is of no type that we know or can handle
215  cout << "Unknown object type, name: "
216  << obj->GetName() << " title: " << obj->GetTitle() << endl;
217  }
218 
219  // now write the merged histogram (which is "in" obj) to the target file
220  // note that this will just store obj in the current directory level,
221  // which is not persistent until the complete directory itself is stored
222  // by "target->Write()" below
223  if ( obj ) {
224  target->cd();
225 
226  //!!if the object is a tree, it is stored in globChain...
227  if (obj->IsA()->InheritsFrom( "TTree" ) && globChain)
228  globChain->Write( key->GetName() );
229  else
230  obj->Write( key->GetName() );
231  }
232 
233  } // while ( ( TKey *key = (TKey*)nextkey() ) )
234 
235  // save modifications to target file
236  target->Write();
237 
238 }
239 
240 
string OUTPUT_FILENAME
Definition: hd_root.cc:17
TList * FileList
Definition: root_merge.cc:39
void MergeRootfile(TDirectory *target, TList *sourcelist)
Definition: root_merge.cc:139
void ParseCommandLineArguments(int &narg, char *argv[])
Definition: hd_dump.cc:124
TFile * Target
Definition: root_merge.cc:40
void Usage(JApplication &app)
Definition: hd_ana.cc:33
int main(int argc, char *argv[])
Definition: gendoc.cc:6