Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MergeFiles.C
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MergeFiles.C
1 // ----------------------------------------------------------------------------
2 // 'MergeFiles.C'
3 // Derek Anderson
4 // 09.25.2020
5 //
6 // Merges root files. Adapted from code
7 // by Nihar Sahoo.
8 // ----------------------------------------------------------------------------
9 
10 #include <fstream>
11 #include <string.h>
12 #include "TChain.h"
13 #include "TFile.h"
14 #include "TH1.h"
15 #include "TTree.h"
16 #include "TKey.h"
17 #include "Riostream.h"
18 
19 
20 
21 // forward declaration of 'MergeRootFile(TDirectory*, TList*)'
22 void MergeRootfile(TDirectory *target, TList *sourcelist);
23 
24 
25 
26 void MergeFiles(const Int_t nFiles=100, const TString filelist= "file.list", const TString outputrootfiles ="test.root") {
27 
28  ifstream files;
29  //files.open("file2.list");
30  files.open(filelist);
31 
32  char file_stm[800];
33  int line=0;
34 
35  TList *FileList;
36  TFile *Target;
37 
38 
39  TString filename_output;
40  TString chain_;
41  Int_t start_num = 0;
42  Int_t end_num = 4;
43 
44  Target = TFile::Open(outputrootfiles, "RECREATE");
45  FileList = new TList();
46 
47  while(files.good()) {
48  files >> file_stm;
49 
50  // quick fix [Derek, 06.02.2017]
51  if ((line + 1) > nFiles) {
52  cout << "WARNING: Whoah there, tiger! Only need " << nFiles << " files!\n"
53  << " Moving on to processing files."
54  << endl;
55  break;
56  }
57 
58  //___________________
59 
60  TFile f(file_stm);
61 
62  // Target = TFile::Open( chain_, "RECREATE" );
63 
64 
65  Bool_t fOk = f.IsZombie();
66  cout<<"file# "<<line<<" "<< file_stm<<" zombi= "<<fOk<<endl;
67 
68  if(!fOk)
69  {
70  FileList->Add(TFile::Open(file_stm));
71  }
72 
73 
74 
75  if (!files.good()) break;
76  line++;
77  }
78  MergeRootfile( Target, FileList );
79 
80 
81 } // end 'TriggerResolutionStudy_MergeFiles(Int_t, TString, TString)'
82 
83 
84 
85 void MergeRootfile( TDirectory *target, TList *sourcelist ) {
86 
87  // cout << "Target path: " << target->GetPath() << endl;
88  TString path( (char*)strstr( target->GetPath(), ":" ) );
89  path.Remove( 0, 2 );
90 
91  TFile *first_source = (TFile*)sourcelist->First();
92  first_source->cd( path );
93  TDirectory *current_sourcedir = gDirectory;
94  //gain time, do not add the objects in the list in memory
95  Bool_t status = TH1::AddDirectoryStatus();
96  TH1::AddDirectory(kFALSE);
97 
98  // loop over all keys in this directory
99  TChain *globChain = 0;
100  TIter nextkey( current_sourcedir->GetListOfKeys() );
101  TKey *key, *oldkey=0;
102  while ( (key = (TKey*)nextkey())) {
103 
104  //keep only the highest cycle number for each key
105  if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;
106 
107  // read object from first source file
108  first_source->cd( path );
109  TObject *obj = key->ReadObj();
110 
111  if ( obj->IsA()->InheritsFrom( TH1::Class() ) ) {
112  // descendant of TH1 -> merge it
113 
114  // cout << "Merging histogram " << obj->GetName() << endl;
115  TH1 *h1 = (TH1*)obj;
116 
117  // loop over all source files and add the content of the
118  // correspondant histogram to the one pointed to by "h1"
119  TFile *nextsource = (TFile*)sourcelist->After( first_source );
120  while ( nextsource ) {
121 
122  // make sure we are at the correct directory level by cd'ing to path
123  nextsource->cd( path );
124  TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(h1->GetName());
125  if (key2) {
126  TH1 *h2 = (TH1*)key2->ReadObj();
127  h1->Add( h2 );
128  delete h2;
129  }
130 
131  nextsource = (TFile*)sourcelist->After( nextsource );
132  }
133  }
134  else if ( obj->IsA()->InheritsFrom( TTree::Class() ) ) {
135 
136  // loop over all source files create a chain of Trees "globChain"
137  const char* obj_name= obj->GetName();
138 
139  globChain = new TChain(obj_name);
140  globChain->Add(first_source->GetName());
141  TFile *nextsource = (TFile*)sourcelist->After( first_source );
142  // const char* file_name = nextsource->GetName();
143  // cout << "file name " << file_name << endl;
144  while ( nextsource ) {
145 
146  globChain->Add(nextsource->GetName());
147  nextsource = (TFile*)sourcelist->After( nextsource );
148  }
149 
150  } else if ( obj->IsA()->InheritsFrom( TDirectory::Class() ) ) {
151  // it's a subdirectory
152 
153  cout << "Found subdirectory " << obj->GetName() << endl;
154 
155  // create a new subdir of same name and title in the target file
156  target->cd();
157  TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
158 
159  // newdir is now the starting point of another round of merging
160  // newdir still knows its depth within the target file via
161  // GetPath(), so we can still figure out where we are in the recursion
162  MergeRootfile( newdir, sourcelist );
163 
164  } else {
165 
166  // object is of no type that we know or can handle
167  cout << "Unknown object type, name: "
168  << obj->GetName() << " title: " << obj->GetTitle() << endl;
169  }
170 
171  // now write the merged histogram (which is "in" obj) to the target file
172  // note that this will just store obj in the current directory level,
173  // which is not persistent until the complete directory itself is stored
174  // by "target->Write()" below
175  if ( obj ) {
176  target->cd();
177 
179  if(obj->IsA()->InheritsFrom( TTree::Class() ))
180  globChain->Merge(target->GetFile(),0,"keep");
181  else
182  obj->Write( key->GetName() );
183  }
184 
185  } // while ( ( TKey *key = (TKey*)nextkey() ) )
186 
187  // save modifications to target file
188  target->SaveSelf(kTRUE);
189  TH1::AddDirectory(status);
190 } // end 'MergeRootFiles(TDirectory*, TList*)'
191 
192 // end ------------------------------------------------------------------------