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