Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
evio_merge_files.cc
Go to the documentation of this file.
1 // $Id:$
2 //
3 // Created Feb. 24, 2015 David Lawrence
4 
5 #include <iostream>
6 #include <fstream>
7 #include <iomanip>
8 #include <vector>
9 using namespace std;
10 
11 #include <signal.h>
12 #include <time.h>
13 #include <stdlib.h>
14 
15 
16 
17 #ifndef _DBG_
18 #define _DBG_ cout<<__FILE__<<":"<<__LINE__<<" "
19 #define _DBG__ cout<<__FILE__<<":"<<__LINE__<<endl
20 #endif
21 
22 void ParseCommandLineArguments(int narg, char* argv[]);
23 void Usage(void);
24 void ctrlCHandle(int x);
25 void Process(unsigned int &NEvents, unsigned int &NEvents_read);
26 
27 static vector<char*> INFILENAMES;
28 static char *OUTFILENAME = NULL;
29 static int QUIT = 0;
30 static int BLOCKSIZE = 10485760; // 10 M
31 static bool VERBOSE = false;
32 
33 //-----------
34 // GetFilesize
35 //-----------
36 ifstream::pos_type GetFilesize(const char* filename)
37 {
38  std::ifstream in(filename, ifstream::ate | ifstream::binary);
39  return in.tellg();
40 }
41 
42 //-----------
43 // main
44 //-----------
45 int main(int narg,char* argv[])
46 {
47  // Set up to catch SIGINTs for graceful exits
48  signal(SIGINT,ctrlCHandle);
49 
50  ParseCommandLineArguments(narg, argv);
51 
52  unsigned int NEvents = 0;
53  unsigned int NEvents_read = 0;
54 
55  // Process all events
56  Process(NEvents, NEvents_read);
57 
58  //cout<<endl;
59  //cout<<" "<<NEvents_read<<" events read, "<<NEvents<<" events written"<<endl;
60 
61  return 0;
62 }
63 
64 //-----------
65 // ParseCommandLineArguments
66 //-----------
67 void ParseCommandLineArguments(int narg, char* argv[])
68 {
69  INFILENAMES.clear();
70 
71  for(int i=1; i<narg; i++){
72  char *ptr = argv[i];
73 
74  if(ptr[0] == '-'){
75  switch(ptr[1]){
76  case 'h': Usage(); break;
77  case 'o': OUTFILENAME=&ptr[2]; break;
78  }
79  }else{
80  INFILENAMES.push_back(argv[i]);
81  }
82  }
83 
84  if(INFILENAMES.size()==0){
85  cout<<endl<<"You must enter a filename!"<<endl<<endl;
86  Usage();
87  }
88 
89  if(OUTFILENAME==NULL){
90  OUTFILENAME = new char[256];
91  sprintf(OUTFILENAME,"merged.evio");
92  }
93 }
94 
95 
96 //-----------
97 // Usage
98 //-----------
99 void Usage(void)
100 {
101  cout<<endl<<"Usage:"<<endl;
102  cout<<" evio_merge_files [-oOutputfile] file1.evio file2.evio ..."<<endl;
103  cout<<endl;
104  cout<<"options:"<<endl;
105  cout<<" -oOutputfile Set output filename (def. merged.evio)"<<endl;
106  cout<<endl;
107  cout<<" This will merge together multiple EVIO files into a single EVIO file."<<endl;
108  cout<<" "<<endl;
109  cout<<" "<<endl;
110  cout<<endl;
111 
112  exit(0);
113 }
114 
115 //-----------------------------------------------------------------
116 // ctrlCHandle
117 //-----------------------------------------------------------------
118 void ctrlCHandle(int x)
119 {
120  QUIT++;
121  cerr<<endl<<"SIGINT received ("<<QUIT<<")....."<<endl;
122 }
123 
124 
125 
126 //-----------
127 // Process
128 //-----------
129 void Process(unsigned int &NEvents, unsigned int &NEvents_read)
130 {
131  // An EVIO file is made of a series of independent blocks, so one should be
132  // able to concatenate EVIO files together, except that the end-of-file
133  // is indicated by an empty EVIO block, i.e., an 8-word EVIO header
134  // with no data payload. Therefore, we concatenate the files leaving
135  // out the end-of-file headers, except for the final files.
136  // This is different than the previous algorithm, which used the standard
137  // EVIO library and required parsing each EVIO event. This new algorithm
138  // should be faster and reduce our dependency on the EVIO library.
139  // Note that the merged files are currently unreliable. We leave this
140  // code in for future development, since the old code currently crashes.
141  // sdobbs, 6/15/2016
142 
143  // Set up a buffer
144  char *buffer = new char[BLOCKSIZE];
145 
146  // Output file
147  cout<<" output file: "<<OUTFILENAME<<endl;
148  ofstream outfile (OUTFILENAME, ios::out|ios::binary);
149  if(!outfile.is_open()) {
150  cerr<<"Could not open output file " << OUTFILENAME << endl;
151  return;
152  }
153 
154  // Open all input files
155  for(unsigned int i=0; i<INFILENAMES.size(); i++){
156  cout << "Opening input file : \"" << INFILENAMES[i] << "\"" << endl;
157  ifstream infile (INFILENAMES[i] , ios::in|ios::binary);
158  if(!infile.is_open()) {
159  cerr<<"Could not open input file " << INFILENAMES[i] << endl;
160  continue;
161  }
162 
163  // figure out the size of the file
164  ifstream::pos_type length_to_read = GetFilesize(INFILENAMES[i]);
165 
166  if(VERBOSE) {
167  cout << "first block" << endl;
168  infile.read(buffer, 32);
169  unsigned int *int_buffer = (unsigned int*)buffer;
170  for(int i=0; i<8; i++)
171  cout << "0x" << hex << int_buffer[i] << endl;
172  infile.seekg(-32, ios_base::cur);
173  }
174  // copy files in blocks to avoid reading in gigs of memory at once
175  while(length_to_read > BLOCKSIZE) {
176  infile.read(buffer, BLOCKSIZE);
177  outfile.write(buffer, BLOCKSIZE);
178  length_to_read -= BLOCKSIZE;
179  }
180  //strip out EOF blocks for all files but the last one
181  if(i+1 != INFILENAMES.size())
182  length_to_read -= 8*4L;
183  infile.read(buffer, length_to_read);
184  outfile.write(buffer, length_to_read);
185 
186  if(VERBOSE) {
187  // dump end
188  cout << "last block" << endl;
189  infile.read(buffer, 32);
190  //unsigned int *int_buffer = (unsigned int*)buffer;
191  unsigned int *int_buffer = (unsigned int*)buffer;
192  for(int i=0; i<8; i++)
193  cout << "0x" << hex << int_buffer[i] << endl;
194  }
195 
196  infile.close();
197  }
198 
199  outfile.close();
200 }
201 
202 #if 0
203 
204 // old code disabled, see description above (sdobbs, 6/15/2016)
205 
206 //-----------
207 // Process
208 //-----------
209 void Process(unsigned int &NEvents, unsigned int &NEvents_read)
210 {
211  // Output file
212  cout<<" output file: "<<OUTFILENAME<<endl;
213  evioFileChannel ochan(OUTFILENAME, "w");
214  ochan.open();
215 
216  // Open all input files
217  vector<evioFileChannel*> ichan;
218  for(unsigned int i=0; i<INFILENAMES.size(); i++){
219  cout << "Opening input file : \"" << INFILENAMES[i] << "\"" << endl;
220  evioFileChannel *ichan = new evioFileChannel(INFILENAMES[i], "r");
221  ichan->open();
222 
223  // Loop until input file runs out of events
224  time_t last_time = time(NULL);
225  while(true){
226 
227  // Read in event from input file, creating a DOM tree
228  try{
229  if(! ichan->read() ) {
230  cout << endl << "No more events in " << INFILENAMES[i] << endl;
231  break;
232  }
233  }catch(evioException e){
234  cerr << e.what() << endl;
235  QUIT=true;
236  break;
237  }
238  evioDOMTree *dom = new evioDOMTree(ichan);
239 
240  if(QUIT) break;
241  NEvents_read++;
242 
243  // Merge DOM Trees into single DOM tree
244  evioDOMTreeP tree=NULL;
245  evioDOMNodeP root=NULL;
246  evioDOMNodeListP nodes = dom->getNodeList();
247  evioDOMNodeList::const_iterator ulIter;
248  for(ulIter=nodes->begin(); ulIter!=nodes->end(); ulIter++) {
249  evioDOMNodeP node = *ulIter;
250  if(node->getParent() != NULL ) continue; // only interested in top-level nodes
251  if(tree==NULL){
252  // Use the first node of the first file as the root node
253  root = node;
254  root->cut(); // remove from input file's DOM
255  tree = new evioDOMTree(root);
256  }else{
257  // Move all daughter nodes of this input file's top-level node
258  // into the root node of the merged event
259  evioDOMNodeListP mynodes = node->getChildren();
260  if(mynodes.get() == NULL) continue;
261  evioDOMNodeList::const_iterator myiter;
262  for(myiter=mynodes->begin(); myiter!=mynodes->end(); myiter++) {
263  try{
264  (*myiter)->move(root);
265  }catch(...){
266  QUIT = true;
267  break;
268  }
269  }
270  if(QUIT) break;
271  }
272  if(QUIT) break;
273  }
274 
275  // Write event to output file
276  if(!QUIT){
277  ochan.write(tree);
278  NEvents++;
279  }
280 
281  // Update ticker
282  time_t now = time(NULL);
283  if(now != last_time){
284  cout<<" "<<NEvents_read<<" events read ("<<NEvents<<" event written) \r";cout.flush();
285  last_time = now;
286  }
287 
288  if(QUIT)break;
289  }
290 
291  // Close input file
292  try{
293  ichan->close();
294  delete ichan;
295  }catch(...){}
296  }
297 
298  // Close output file
299  ochan.close();
300 
301 }
302 
303 #endif
void Process(unsigned int &NEvents, unsigned int &NEvents_read)
Double_t x[NCHANNELS]
Definition: st_tw_resols.C:39
sprintf(text,"Post KinFit Cut")
TString filename
char * OUTFILENAME
TFile * infile
Definition: tw_corr.C:45
TEllipse * e
const bool VERBOSE
void ParseCommandLineArguments(int &narg, char *argv[])
Definition: hd_dump.cc:124
TFile * outfile
Definition: tw_corr.C:46
int QUIT
ifstream::pos_type GetFilesize(const char *filename)
static int BLOCKSIZE
vector< char * > INFILENAMES
void ctrlCHandle(int x)
void Usage(JApplication &app)
Definition: hd_ana.cc:33
int main(int argc, char *argv[])
Definition: gendoc.cc:6