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