EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
File.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file File.cxx
1 
10 #include "eicsmear/erhic/File.h"
11 
12 #include <fstream>
13 #include <sstream>
14 #include <string>
15 
16 #include <TSystem.h>
17 
18 #include "eicsmear/gzstream.h"
28 
29 #include <HepMC3/Version.h>
30 
31 using std::cout;
32 using std::cerr;
33 using std::endl;
34 
35 
36 static void LogLineParse(std::string line, const std::string searchPattern, std::string& toupdate, const double rescale=1 ){
37  size_t position = line.find(searchPattern);
38  if (position != std::string::npos) {
39  // We found the line.
40  // This should be the first and only occurence. Check.
41  if ( toupdate!="") throw std::runtime_error( "LogLineParse: Found two instances of the search pattern");
42  // Erase the text preceding the value.
43  std::stringstream ss;
44  line.erase(0, position + searchPattern.length());
45  ss.str("");
46  ss.clear();
47  ss << line;
48  // Sometimes this needs rescaling (pb to mb)
49  if ( rescale!=1 ){
50  double v;
51  ss >> v;
52  v /= 1.e6;
53  ss.clear(); ss << v;
54  }
55  ss >> toupdate;
56  } // if
57  return;
58 }
59 
60 namespace erhic {
61 
63 
65 
66 bool LogReaderPythia::Extract(const std::string& file) {
67  // First we get the cross section from the log file.
68  std::ifstream ifs(file.c_str(), std::ios::in);
69 
70  if (!ifs.is_open()) return false;
71 
72  std::string line;
73  std::string normalisation;
74  std::string nEvents;
75  std::string nTrials;
76 
77  while (ifs.good()) {
78  std::getline(ifs, line);
79  LogLineParse( line, "Pythia total cross section normalisation:", normalisation );
80  LogLineParse( line, "Total Number of generated events", nEvents );
81  LogLineParse( line, "Total Number of trials", nTrials );
82  } // while
83 
84  crossSection_.SetString(normalisation.c_str());
85  nEvents_.SetString(nEvents.c_str());
86  nTrials_.SetString(nTrials.c_str());
87  std::cout << "Extracted information from " << file << std::endl;
88  return true;
89 }
90 
91 Int_t LogReaderPythia::Save() const {
92  Int_t byteswritten = 0;
93  byteswritten += crossSection_.Write("crossSection");
94  byteswritten += nEvents_.Write("nEvents");
95  byteswritten += nTrials_.Write("nTrials");
96  return byteswritten;
97 }
98 
99 //
100 // class LogReaderPepsi
101 //
102 
104 
106 
107 bool LogReaderPepsi::Extract(const std::string& file) {
108  // First we get the cross section from the log file.
109  std::ifstream ifs(file.c_str(), std::ios::in);
110  if (!ifs.is_open()) return false;
111  std::string line;
112  std::string normalisation;
113  std::string nEvents;
114  std::string nTrials;
115 
116  while (ifs.good()) {
117  std::getline(ifs, line);
118  // Divide by 1,000,000 to go from pb to microbarn
119  LogLineParse( line, "total cross section in pb from MC simulation", normalisation, 1e-6 );
120  LogLineParse( line, "Total Number of generated events", nEvents );
121  LogLineParse( line, "Total Number of trials", nTrials );
122  } // while
123 
124  crossSection_.SetString(normalisation.c_str());
125  nEvents_.SetString(nEvents.c_str());
126  nTrials_.SetString(nTrials.c_str());
127  std::cout << "Extracted information from " << file << std::endl;
128  return true;
129 }
130 
131 Int_t LogReaderPepsi::Save() const {
132  Int_t byteswritten = 0;
133  byteswritten += crossSection_.Write("crossSection");
134  byteswritten += nEvents_.Write("nEvents");
135  byteswritten += nTrials_.Write("nTrials");
136  return byteswritten;
137 }
138 
139 //
140 // class LogReaderDjangoh
141 //
142 
144 
146 
147 bool LogReaderDjangoh::Extract(const std::string& file) {
148  // First we get the cross section from the log file.
149  std::ifstream ifs(file.c_str(), std::ios::in);
150 
151  if (!ifs.is_open()) return false;
152 
153  std::string line;
154  // There are two places we need to look for cross sections.
155  // As standard, look for the line starting with
156  // Cross-section from HERACLES
157  // Sometimes there will be an additional line starting
158  // Total cross section is now SIGTOT =
159  // *If* this line is present we take the cross section from there,
160  // otherwise use the 'HERACLES' line, which is always present.
161  // Both lines give cross section in pb.
162  const std::string xsecPattern("Cross-section from HERACLES =");
163  const std::string xsecAltPattern("Total cross section is now SIGTOT =");
164  std::string normalisation;
165  std::string nEvents;
166 
167  while (ifs.good()) {
168  std::getline(ifs, line);
169  // Look for normal cross section line, unless the cross section
170  // was already set (via the alternative line, see below).
171  size_t position = line.find(xsecPattern);
172  if (position != std::string::npos && normalisation.empty()) {
173  // We found the line.
174  // Erase the text preceding the cross section.
175  std::stringstream ss;
176  line.erase(0, position + xsecPattern.length());
177  ss << line;
178  double value;
179  // Divide by 1,000,000 to go from pb to microbarn
180  ss >> value;
181  value /= 1.e6;
182  ss.str("");
183  ss.clear();
184  ss << value;
185  ss >> normalisation;
186  } // if
187  position = line.find(xsecAltPattern);
188  // Look for alternative cross section.
189  if (position != std::string::npos) {
190  // We found the line.
191  // Erase the text preceding the cross section.
192  std::stringstream ss;
193  line.erase(0, position + xsecAltPattern.length());
194  ss << line;
195  double value;
196  // Divide by 1,000,000 to go from pb to microbarn
197  ss >> value;
198  value /= 1.e6;
199  ss.str("");
200  ss.clear();
201  ss << value;
202  ss >> normalisation;
203  } // if
204  const std::string searchPattern2("TOTAL EVENT NUMBER");
205  position = line.find(searchPattern2);
206  if (position != std::string::npos) {
207  // We found the line.
208  // Erase the text preceding the cross section.
209  std::stringstream ss;
210  line.erase(0, position + searchPattern2.length());
211  ss.str("");
212  ss.clear();
213  ss << line;
214  ss >> nEvents;
215  } // if
216  } // while
217 
218  crossSection_.SetString(normalisation.c_str());
219  std::cout << crossSection_.GetString().Atof() << std::endl;
220  nEvents_.SetString(nEvents.c_str());
221  std::cout << nEvents_.GetString().Atoi() << std::endl;
222 
223  std::cout << "Extracted information from " << file << std::endl;
224  return true;
225 }
226 
227 Int_t LogReaderDjangoh::Save() const {
228  return
229  crossSection_.Write("crossSection") +
230  nEvents_.Write("nEvents");
231 }
232 
233 
234 bool LogReaderMilou::Extract(const std::string& file) {
235  // First we get the cross section from the log file.
236  std::ifstream ifs(file.c_str(), std::ios::in);
237 
238  if (!ifs.is_open()) return false;
239 
240  std::string line;
241 
242  const std::string nEventPattern("Number of generated events =");
243  const std::string xsecPattern("Total cross-section (nb) :");
244  const std::string errorPattern("Error :");
245 
246  std::string tmp("");
247 
248  std::stringstream ss;
249 
250  while (ifs.good()) {
251  std::getline(ifs, line);
252  ss.str("");
253  ss.clear();
254  // Look for one of the search patterns.
255  if (line.find(nEventPattern) != std::string::npos) {
256  line.erase(0,
257  line.find(nEventPattern) + nEventPattern.length());
258  ss << line;
259  ss >> tmp;
260  nEvents_.SetString(tmp.c_str());
261  } else if (line.find(xsecPattern) != std::string::npos) {
262  line.erase(0,
263  line.find(xsecPattern) + xsecPattern.length());
264  ss << line;
265  ss >> tmp;
266  crossSection_.SetString(tmp.c_str());
267  } else if (line.find(errorPattern) != std::string::npos) {
268  line.erase(0,
269  line.find(errorPattern) + errorPattern.length());
270  ss << line;
271  ss >> tmp;
272  crossSectionError_.SetString(tmp.c_str());
273  } // if
274  } // while
275  // Return true if all the strings are filled, or false if any
276  // of them are empty.
277  return !(nEvents_.GetString().IsNull() ||
278  crossSection_.GetString().IsNull() ||
279  crossSectionError_.GetString().IsNull());
280 }
281 
282 Int_t LogReaderMilou::Save() const {
283  Int_t bytes(0);
284  bytes += nEvents_.Write("nEvents");
285  bytes += crossSection_.Write("crossSection");
286  bytes += crossSectionError_.Write("crossSectionError");
287  return bytes;
288 }
289 
291 : mNEvents("")
292 , mCrossSection("") {
293 }
294 
296 }
297 
299  return new LogReaderGmcTrans;
300 }
301 
302 bool LogReaderGmcTrans::Extract(const std::string& filename) {
303  // Open the file, check for errors.
304  std::ifstream file(filename.c_str(), std::ios::in);
305  if (!file.is_open()) {
306  return false;
307  } // if
308  // The line with the number of generated events ends with this:
309  const std::string eventPattern("generated events (IEVGEN)");
310  // Thw line with the total cross section ends with this:
311  const std::string xsecPattern("total xsec in microbarns after selector");
312  // Read the file line-by-line, looking for the patterns.
313  std::stringstream sstream; // For splitting the string
314  std::string line;
315  while (file.good()) {
316  std::getline(file, line);
317  // Check for number-of-events pattern.
318  if (line.find(eventPattern) != std::string::npos) {
319  // Found it, the number of events is the first word in the line.
320  std::string tmp;
321  sstream.str("");
322  sstream.clear();
323  sstream << line;
324  sstream >> tmp;
325  mNEvents.SetString(tmp.c_str());
326  } // if
327  // Check for total cross section pattern.
328  if (line.find(xsecPattern) != std::string::npos) {
329  std::string tmp;
330  sstream.str("");
331  sstream.clear();
332  sstream << line;
333  sstream >> tmp;
334  mCrossSection.SetString(tmp.c_str());
335  } // if
336  } // while
337  return !(mNEvents.GetString().IsNull() ||
338  mCrossSection.GetString().IsNull());
339 }
340 
341 Int_t LogReaderGmcTrans::Save() const {
342  return mNEvents.Write("nEvents") + mCrossSection.Write("crossSection");
343 }
344 
346  return mNEvents.GetString().Atoi();
347 }
348 
350  return mCrossSection.GetString().Atof();
351 }
352 
354  static LogReaderFactory theInstance;
355  return theInstance;
356 }
357 
365  // The event name will be "EventX" where "X" is the Monte Carlo
366  // generator name.
367  TString name = event.ClassName();
368  name.ReplaceAll("erhic::", "");
369  name.ReplaceAll("Event", "");
370  name.ToLower();
371  return CreateReader(name.Data());
372 }
373 
380 LogReader* LogReaderFactory::CreateReader(const std::string& name) const {
381  // Use TString::ToLower() to convert the input name to all
382  // lower case.
383  TString str(name);
384  str.ToLower();
385  LogReader* reader(NULL);
386  if (prototypes_.find(str.Data()) != prototypes_.end()) {
387  reader = prototypes_.find(str.Data())->second->Create();
388  } // if
389  return reader;
390 }
391 
398 LogReader* LogReaderFactory::CreateReader(std::istream& is) const {
399  std::string line;
400  std::getline(is, line);
401  // Use TString::ToLower() to convert the input name to all
402  // lower case.
403  TString str(line);
404  str.ToLower();
405  LogReader* reader(NULL);
406  if (str.Contains("pythia")) {
407  reader = CreateReader("pythia");
408  } else if (str.Contains("pepsi") || str.Contains("lepto")) {
409  reader = CreateReader("pepsi");
410  } else if (str.Contains("rapgap")) {
411  reader = CreateReader("rapgap");
412  } else if (str.Contains("djangoh")) {
413  reader = CreateReader("djangoh");
414  //} else if (str.Contains("beagle")) {
415  //reader = CreateReader("beagle");
416  } else if (str.Contains("milou")) {
417  reader = CreateReader("milou");
418  } else if (str.Contains("simple")) {
419  reader = CreateReader("simple");
420  } else if (str.Contains("demp")) {
421  reader = CreateReader("demp");
422  } else if (str.Contains("sartre")) {
423  reader = CreateReader("sartre");
424  } // if
425  return reader;
426 }
427 
428 std::string LogReaderFactory::Locate(const std::string& mcFile) const {
429  TString inFileName(mcFile);
430  TString logFileName;
431  std::string extension;
432  if (mcFile.find_last_of('.') != std::string::npos) {
433  extension = mcFile.substr(mcFile.find_last_of('.'));
434  } // if
435  // If the input file is in the current directory, expand the full path:
436  if (std::string(".") == gSystem->DirName(inFileName)) {
437  inFileName.Prepend("/").Prepend(gSystem->pwd());
438  } // if
439 
440  // The standard data directory structure is to have a directory called
441  // TXTFILES containing the Monte Carlo output, and a directory called
442  // LOGFILES containing the corresponding log files. The sub-directory
443  // structure of LOGFILES should match that of TXTFILES.
444  // So, first we'll check if the input path contains TXTFILES, in which
445  // case we just substitute LOGFILES:
446  if (inFileName.Contains("TXTFILES")) {
447  logFileName = inFileName;
448  logFileName.ReplaceAll("TXTFILES", "LOGFILES");
449  logFileName.ReplaceAll(extension.c_str(), ".log");
450  } // if...
451  // Check if the file whose name we have constructed exists.
452  // If not clear the string contents.
453  if (gSystem->AccessPathName(logFileName, kFileExists)) {
454  logFileName.Clear();
455  } // if
456  // OK, that didn't work, so let's just look in the current directory
457  if (logFileName.IsNull()) {
458  logFileName = inFileName;
459  if (extension.empty()) {
460  logFileName.Append(".log");
461  } else {
462  logFileName.ReplaceAll(extension.c_str(), ".log");
463  } // if
464  } // if
465  // Check if the file whose name we have constructed exists.
466  // If not clear the string contents.
467  if (gSystem->AccessPathName(logFileName, kFileExists)) {
468  logFileName.Clear();
469  } // if
470  return logFileName.Data();
471 }
472 
474  prototypes_.insert(std::make_pair("pythia",
475  new LogReaderPythia));
476  prototypes_.insert(std::make_pair("milou",
477  new LogReaderMilou));
478  prototypes_.insert(std::make_pair("pepsi",
479  new LogReaderPepsi));
480  prototypes_.insert(std::make_pair("djangoh",
481  new LogReaderDjangoh));
482  prototypes_.insert(std::make_pair("gmctrans", new LogReaderGmcTrans));
483 }
484 
486  Map::iterator i = prototypes_.begin();
487  for (; i != prototypes_.end(); ++i) {
488  delete i->second;
489  } // for
490 }
491 
492 template<typename T>
493 File<T>::File() : t_(new T) {
494  TString name = t_->ClassName();
495  name.ReplaceAll("erhic::", "");
496  name.ReplaceAll("Event", "");
497  name.ToLower();
498  generatorname = name.Data();
499 }
500 
501 template<typename T>
503  if (t_) {
504  delete t_;
505  t_ = NULL;
506  } // if
507 }
508 
509 template class File<EventDjangoh>;
510 template class File<EventDpmjet>;
511 template class File<EventMilou>;
512 template class File<EventPepsi>;
513 template class File<EventPythia>;
514 template class File<EventBeagle>;
515 template class File<EventRapgap>;
516 template class File<EventGmcTrans>;
517 template class File<EventSimple>;
518 template class File<EventDEMP>;
519 template class File<EventSartre>;
520 // File<EventHepMC> is specialized in the File.h
521 
522 std::string FileType::GetGeneratorName() const {
523  return generatorname;
524 }
525 
526 
527 void FileType::SetGeneratorName(const std::string newname){
528  generatorname = newname;
529  for (auto & c: generatorname) c = tolower(static_cast<unsigned char>(c));
530 }
531 
532 template<typename T>
535 }
536 
538  static FileFactory theInstance;
539  return theInstance;
540 }
541 
542 const FileType* FileFactory::GetFile(const std::string& name) const {
543  FileType* file(NULL);
544  if (prototypes_.find(name) != prototypes_.end()) {
545  file = prototypes_.find(name)->second->Create();
546  if ( TString(name).Contains("hepmc") )file->SetGeneratorName( "hepmc");
547  } // if
548 
549  return file;
550 }
551 
552 const FileType* FileFactory::GetFile(std::shared_ptr<std::istream>& isp, const std::string fileName) const {
553  std::string line;
554 
555  // Note: This "uses up" the first line, subsequent readers
556  // cannot use it anymore.
557  // This leaves a conundrum. The only information passed to
558  // the event factory comes from
559  // EventFromAsciiFactory<erhic::EventHepMC>* CreateEventFactory(std::istream& is) const {
560  // return new EventFromAsciiFactory<erhic::EventHepMC>(is);}
561  // So the class only knows the stream
562  // and the Filetype.
563  // We could
564  // - reset the stream. Seekg, tellg don't work for gzstream, and close/open need the name of the file
565  // which already this class doesnt know
566  // - use globals - no thanks
567  // - Enrich the virtual eventfactory. That seems the most unintrusive way as long as it's a generic
568  // field meant for additional information. That's what we'll use
569 
570 
571  // skip empty lines (thanks, hepmc2...)
572  do {
573  std::getline(*isp, line);
574  } while (line.empty());
575 
576  // Use TString::ToLower() to convert the input name to all
577  // lower case.
578  TString str(line);
579  str.ToLower();
580  const FileType* file(NULL);
581  if (str.Contains("pythia")) {
582  file = GetFile("pythia");
583  } else if (str.Contains("pepsi") || str.Contains("lepto")) {
584  file = GetFile("pepsi");
585  } else if (str.Contains("rapgap")) {
586  file = GetFile("rapgap");
587  } else if (str.Contains("djangoh")) {
588  file = GetFile("djangoh");
589  } else if (str.Contains("milou")) {
590  file = GetFile("milou");
591  } else if (str.Contains("beagle")) {
592  file = GetFile("beagle");
593  } else if (str.Contains("gmctrans")) {
594  file = GetFile("gmctrans");
595  } else if (str.Contains("dpmjet")) {
596  file = GetFile("dpmjet");
597  } else if (str.Contains("simple")) {
598  file = GetFile("simple");
599  } else if (str.Contains("demp")) {
600  file = GetFile("demp");
601  } else if (str.Contains("sartre")) {
602  file = GetFile("sartre");
603  } else if (str.Contains("hepmc")) {
604 
605  // We have to repair the stream by reading it fresh
606  // Open the input file for reading.
607  if ( TString(fileName).EndsWith("gz", TString::kIgnoreCase) ||
608  TString(fileName).EndsWith("zip", TString::kIgnoreCase)){
609 #if HEPMC3_VERSION_CODE < 3002005
610  // Can't accept gzstreams before 3.2.5
611  std::cerr << "HepMC before v 3.2.5 only supports ifstream (no compressed files)." << endl;
612  throw;
613 #endif // HEPMC3_VERSION_CODE < 3002004
614 
615  auto tmp = std::make_shared<igzstream>();
616  tmp->open(fileName.c_str());
617  // Throw a runtime_error if the file could not be opened.
618  if (!tmp->good()) {
619  std::string message("Unable to open file ");
620  throw std::runtime_error(message.append(fileName));
621  } // if
622  isp=tmp;
623  } else {
624  auto tmp = std::make_shared<std::ifstream>();
625  tmp->open(fileName.c_str());
626  // Throw a runtime_error if the file could not be opened.
627  if (!isp->good()) {
628  std::string message("Unable to open file ");
629  throw std::runtime_error(message.append(fileName));
630  } // if
631  isp=tmp;
632  } // if
633  file = GetFile("hepmc");
634  }
635  return file;
636 }
637 
639  prototypes_.insert(std::make_pair("djangoh",
640  new File<EventDjangoh>()));
641  prototypes_.insert(std::make_pair("dpmjet",
642  new File<EventDpmjet>()));
643  prototypes_.insert(std::make_pair("milou",
644  new File<EventMilou>()));
645  prototypes_.insert(std::make_pair("pepsi",
646  new File<EventPepsi>()));
647  prototypes_.insert(std::make_pair("pythia",
648  new File<EventPythia>()));
649  prototypes_.insert(std::make_pair("beagle",
650  new File<EventBeagle>()));
651  prototypes_.insert(std::make_pair("rapgap",
652  new File<EventRapgap>()));
653  prototypes_.insert(std::make_pair("gmctrans",
654  new File<EventGmcTrans>()));
655  prototypes_.insert(std::make_pair("simple",
656  new File<EventSimple>()));
657  prototypes_.insert(std::make_pair("demp",
658  new File<EventDEMP>()));
659  prototypes_.insert(std::make_pair("sartre",
660  new File<EventSartre>()));
661  prototypes_.insert(std::make_pair("hepmc",
662  new File<EventHepMC>()));
663 
664 }
665 
667  Map::iterator i = prototypes_.begin();
668  for (; i != prototypes_.end(); ++i) {
669  if (i->second) delete i->second;
670  } // for
671 }
672 
673 } // namespace erhic