Belle II Software  release-05-02-19
B2BIIMdstInputModule.cc
1 //+
2 // File : B2BIIMdstInutModule.cc
3 // Description : A module to read panther records in basf2
4 //
5 // Author : Ryosuke Itoh, IPNS, KEK
6 // Date : 16 - Feb - 2015
7 //
8 // Contributors: Anze Zupanc, Martin Ritter
9 //-
10 
11 #include <b2bii/modules/B2BIIMdstInput/B2BIIMdstInputModule.h>
12 
13 #include <framework/core/Environment.h>
14 #include <framework/utilities/FileSystem.h>
15 #include <framework/database/Configuration.h>
16 
17 // Belle tables
18 #include "belle_legacy/tables/belletdf.h"
19 
20 // Belle II dataobjects
21 #include <framework/utilities/NumberSequence.h>
22 
23 #include <cstdlib>
24 #include <algorithm>
25 
26 using namespace std;
27 using namespace Belle2;
28 
29 
30 /*
31 Some code for simple globing from
32 http://stackoverflow.com/questions/8401777/simple-glob-in-c-on-unix-system
33 In RootInput this is handled by ROOT
34 */
35 #include <glob.h>
36 #include <vector>
37 #include <string>
38 vector<string> globbing(const vector<string>& patterns)
39 {
40  vector<string> ret;
41  for (const auto& pat : patterns) {
42  glob_t glob_result;
43  glob(pat.c_str(), GLOB_TILDE, NULL, &glob_result);
44  for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) {
45  ret.push_back(string(glob_result.gl_pathv[i]));
46  }
47  globfree(&glob_result);
48  }
49  return ret;
50 }
51 
52 //-----------------------------------------------------------------
53 // Register the Module
54 //-----------------------------------------------------------------
55 REG_MODULE(B2BIIMdstInput)
56 
57 //-----------------------------------------------------------------
58 // Implementation
59 //-----------------------------------------------------------------
60 
62 {
63  //Set module properties
64  setDescription("Module to read Belle MDST files.");
65  setPropertyFlags(c_Input);
66 
67  m_nevt = -1;
68  m_current_file_position = -1;
69  m_current_file_entry = -1;
70 
71  //Parameter definition
72  addParam("inputFileName", m_inputFileName, "Belle MDST input file name. "
73  "For more than one file use inputFileNames", std::string(""));
74  addParam("inputFileNames" , m_inputFileNames, "Belle MDST input file names.",
75  m_inputFileNames);
76 
77  std::vector<std::string> emptyvector;
78  addParam("entrySequences", m_entrySequences,
79  "The number sequences (e.g. 23:42,101) defining the entries which are processed for each inputFileName."
80  "Must be specified exactly once for each file to be opened."
81  "The first event has the number 0.", emptyvector);
82 }
83 
84 
85 B2BIIMdstInputModule::~B2BIIMdstInputModule()
86 {
87 }
88 
89 std::vector<std::string> B2BIIMdstInputModule::getInputFiles() const
90 {
91  std::vector<std::string> inputFiles = Environment::Instance().getInputFilesOverride();
92  if (!inputFiles.empty()) {
93  return inputFiles;
94  }
95  inputFiles = m_inputFileNames;
96  if (!m_inputFileName.empty())
97  inputFiles.push_back(m_inputFileName);
98  return inputFiles;
99 }
100 
101 void B2BIIMdstInputModule::initialize()
102 {
103  m_inputFileNames = globbing(getInputFiles());
104 
105  auto entrySequencesOverride = Environment::Instance().getEntrySequencesOverride();
106  if (entrySequencesOverride.size() > 0)
107  m_entrySequences = entrySequencesOverride;
108 
109  //Check if there is at least one filename provided
110  if (m_inputFileNames.empty()) {
111  B2FATAL("Empty list of files supplied, cannot continue");
112  }
113 
114  if (m_entrySequences.size() > 0 and m_inputFileNames.size() != m_entrySequences.size()) {
115  B2FATAL("Number of provided filenames does not match the number of given entrySequences parameters: len(inputFileNames) = "
116  << m_inputFileNames.size() << " len(entrySequences) = " << m_entrySequences.size());
117  }
118 
119  //Ok we have files. Since vectors can only remove efficiently from the back
120  //we reverse the order and read the files from back to front.
121  std::reverse(m_inputFileNames.begin(), m_inputFileNames.end());
122 
123  // check environment
124  const char* table_dir = getenv("PANTHER_TABLE_DIR");
125  if (!table_dir or !FileSystem::isDir(table_dir)) {
126  string fixed_table_dir = Environment::Instance().getExternalsPath() + "/share/belle_legacy/panther";
127  B2WARNING("PANTHER_TABLE_DIR environment variable not set correctly. This is a known problem with externals v00-05-09, using " <<
128  fixed_table_dir << " instead.");
129  if (!FileSystem::isDir(fixed_table_dir))
130  B2FATAL("Path " << fixed_table_dir << " does not exist, your externals setup seems broken.");
131  setenv("PANTHER_TABLE_DIR", fixed_table_dir.c_str(), 1); //overwrite existing value
132  }
133 
134 
135  // Initialize Panther
136  BsInit(0);
137 
138  // Initialize Belle II DataStore
139  initializeDataStore();
140 
141  // open the first file
142  openNextFile();
143 
144  // Also, make sure we register a filemetadata object. We don't have most information
145  // to go into it but we need it for real/MC flag
146  m_fileMetadata.registerInDataStore();
147 }
148 
149 void B2BIIMdstInputModule::initializeDataStore()
150 {
151  B2DEBUG(99, "[B2BIIMdstInputModule::initializeDataStore] initialization of DataStore started");
152 
153  m_evtMetaData.registerInDataStore();
154 
155  B2DEBUG(99, "[B2BIIMdstInputModule::initializeDataStore] initialization of DataStore ended");
156 }
157 
158 
159 void B2BIIMdstInputModule::beginRun()
160 {
161  B2DEBUG(99, "B2BIIMdstInput: beginRun called.");
162 }
163 
164 bool B2BIIMdstInputModule::openNextFile()
165 {
166  // delete existing FileIO
167  BsClrTab(BBS_CLEAR_ALL);
168  delete m_fd;
169  m_fd = nullptr;
170 
171  // check if we have more files to read
172  if (m_inputFileNames.empty()) return false;
173  // if so, get the last one from the list and remove it.
174  const std::string name = m_inputFileNames.back();
175  m_inputFileNames.pop_back();
176 
177  // Open data file
178  m_fd = new Belle::Panther_FileIO(name.c_str(), BBS_READ);
179 
180  // Read first record (does not contain event data)
181  if (m_fd->read() == -1) {
182  B2FATAL("Couldn't read file '" << name << "'!");
183  }
184  m_nevt++;
185  m_current_file_position++;
186  m_current_file_entry = -1;
187 
188  if (m_entrySequences.size() > 0)
189  // exclude ":" since this case is not considered in generate_number_sequence
190  if (m_entrySequences[m_current_file_position] != ":") {
191  m_valid_entries_in_current_file = generate_number_sequence(m_entrySequences[m_current_file_position]);
192  }
193  return true;
194 }
195 
196 bool B2BIIMdstInputModule::readNextEvent()
197 {
198 
199  do {
200  m_current_file_entry++;
201  // read event
202  int rectype = -1;
203  while (rectype < 0 && rectype != -2) {
204  //clear all previous event data before reading!
205  BsClrTab(BBS_CLEAR);
206  rectype = m_fd->read();
207  if (rectype == -1) {
208  B2ERROR("Error while reading panther tables! Record skipped.");
209  }
210  }
211  if (rectype == -2) { // EoF detected
212  B2DEBUG(99, "[B2BIIMdstInputModule::Conversion] Conversion stopped at event #" << m_nevt << ". EOF detected!");
213  return false;
214  }
215 
216  } while (m_entrySequences.size() > 0
217  and (m_entrySequences[m_current_file_position] != ":"
218  and m_valid_entries_in_current_file.find(m_current_file_entry) == m_valid_entries_in_current_file.end()));
219 
220  return true;
221 }
222 
223 void B2BIIMdstInputModule::event()
224 {
225  m_nevt++;
226 
227  // Fill EventMetaData
228  StoreObjPtr<EventMetaData> evtmetadata;
229 
230  // Read next event: We try to read the next event from the current file
231  // if thist fails, open the next file and try again
232  // if we cannot open the next file then stop processing
233  while (!readNextEvent()) {
234  if (!openNextFile()) {
235  B2DEBUG(99, "[B2BIIMdstInputModule::Conversion] Conversion stopped at event #" << m_nevt << ". No more files");
236  return;
237  }
238  }
239  evtmetadata.create();
240 
241  // Convert the Belle_event -> EventMetaData
242  // Get Belle_event_Manager
243  Belle::Belle_event_Manager& evman = Belle::Belle_event_Manager::get_manager();
244  Belle::Belle_event& evt = evman[0];
245 
246  // Check if RUNHEAD is available if not create one using the event.
247  // Basf did something similar in Record::convert_to_begin_run.
248  // Some files are missing the RUNHEAD for unknown reasons.
249  Belle::Belle_runhead_Manager& rhdmgr = Belle::Belle_runhead_Manager::get_manager();
250  Belle::Belle_runhead_Manager::const_iterator belleevt = rhdmgr.begin();
251 
252  B2DEBUG(90, "Event number " << m_nevt);
253  if (belleevt == rhdmgr.end() || not(*belleevt)) {
254  B2WARNING("Missing RUNHEAD: Creating RUNHEAD from Event. This is as far as we know fine and handled correctly.");
255 
256  Belle::Belle_runhead& bgr = rhdmgr.add();
257  bgr.ExpMC(evt.ExpMC());
258  bgr.ExpNo(evt.ExpNo());
259  bgr.RunNo(evt.RunNo());
260  bgr.Time(evt.Time());
261  bgr.Date(evt.Date());
262  bgr.Field(evt.MagFieldID());
263  bgr.MaxField(evt.BField());
264  bgr.Type(0); // basf used 0, and the debug output below of valid entries returned 0 as well
265  bgr.ELER(evt.ELER());
266  bgr.EHER(evt.EHER());
267 
268  // In basf the BELLE_RUNHEAD which is created like this is not cleared anymore
269  // m_fd->non_clear("BELLE_RUNHEAD");
270  // However, I think in this case we are going to miss reinitializing the BELLE_RUNHEAD
271  // at the beginning of a new run without a BELLE_RUNHEAD, I'm not sure how this was handled
272  // in basf. I think it is safest to recreate the BELLE_RUNHEAD for each event which is missing
273  // the BELLE_RUNHEAD
274 
275  } else {
276  Belle::Belle_runhead& bgr = rhdmgr[0];
277  B2DEBUG(90, "ExpMC " << bgr.ExpMC() << " " << evt.ExpMC());
278  B2DEBUG(90, "ExpNo " << bgr.ExpNo() << " " << evt.ExpNo());
279  B2DEBUG(90, "RunNo " << bgr.RunNo() << " " << evt.RunNo());
280  B2DEBUG(90, "Time " << bgr.Time() << " " << evt.Time());
281  B2DEBUG(90, "Date " << bgr.Date() << " " << evt.Date());
282  B2DEBUG(90, "Field " << bgr.Field() << " " << evt.MagFieldID());
283  B2DEBUG(90, "MaxField " << bgr.MaxField() << " " << evt.BField());
284  B2DEBUG(90, "Type " << bgr.Type());
285  B2DEBUG(90, "ELER " << bgr.ELER() << " " << evt.ELER());
286  B2DEBUG(90, "EHER " << bgr.EHER() << " " << evt.EHER());
287  }
288 
289  // set exp/run/evt numbers
290  evtmetadata->setExperiment(evt.ExpNo());
291  evtmetadata->setRun(evt.RunNo());
292  evtmetadata->setEvent(evt.EvtNo() & 0x0fffffff);
293 
294  // set generated weight (>0 for MC; <0 for real DATA)
295  bool realData = evt.ExpMC() != 2;
296  evtmetadata->setGeneratedWeight(realData ? -1.0 : 1.0);
297 
298  // no file metadata yet? apparently first event, make sure the real/MC data flag is correct
299  if (!m_fileMetadata) {
300  m_fileMetadata.create();
301  if (realData) m_fileMetadata->declareRealData();
302  // this happens for the first event so now is a good time to tell the framework
303  // which globaltags we want to use ...
304  std::string tag = realData ? "B2BII" : "B2BII_MC";
305  Conditions::Configuration::getInstance().setInputGlobaltags({tag});
306  } else {
307  // Make sure we don't process real data and MC in the same process
308  if (realData == m_fileMetadata->isMC()) {
309  B2FATAL("Information whether we process real or simulated data has changed. Refusing to continue");
310  }
311  }
312 
313  B2DEBUG(90, "[B2BIIMdstInputModule] Convert exp/run/evt: " << evt.ExpNo() << "/" << evt.RunNo() << "/" << int(
314  evt.EvtNo() & 0x0fffffff));
315 }
316 
317 void B2BIIMdstInputModule::endRun()
318 {
319  B2INFO("B2BIIMdstInput: endRun done.");
320 }
321 
322 
323 void B2BIIMdstInputModule::terminate()
324 {
325  delete m_fd;
326  B2INFO("B2BIIMdstInput: terminate called");
327 }
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::generate_number_sequence
std::set< int64_t > generate_number_sequence(const std::string &str)
Generate a sequence of numbers defined by a string.
Definition: NumberSequence.cc:30
Belle2::B2BIIMdstInputModule
Module reads Belle MDST files and converts Belle_event record to Belle II EventMetaData StoreObjectPo...
Definition: B2BIIMdstInputModule.h:35
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2::ProcType::c_Input
@ c_Input
Input Process.
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::StoreObjPtr
Type-safe access to single objects in the data store.
Definition: ParticleList.h:33