Belle II Software  release-08-01-10
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 
59 B2BIIMdstInputModule::B2BIIMdstInputModule() : Module()
60 {
61  //Set module properties
62  setDescription("Module to read Belle MDST files.");
64 
65  m_nevt = -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.",
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 
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 
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
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 
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 
158 {
159  B2DEBUG(99, "B2BIIMdstInput: beginRun called.");
160 }
161 
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++;
185 
186  if (m_entrySequences.size() > 0)
187  // exclude ":" since this case is not considered in generate_number_sequence
190  }
191  return true;
192 }
193 
195 {
196 
197  do {
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
217 
218  return true;
219 }
220 
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";
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 
316 {
317  B2INFO("B2BIIMdstInput: endRun done.");
318 }
319 
320 
322 {
323  delete m_fd;
324  B2INFO("B2BIIMdstInput: terminate called");
325 }
int m_nevt
Global event counter.
virtual ~B2BIIMdstInputModule() override
Destructor.
int m_current_file_entry
Entry counter in current file.
bool readNextEvent()
Read the next event from the currently open file.
virtual void initialize() override
Initialize the module.
virtual void event() override
Called for each event.
virtual void endRun() override
Called when the current run finished.
virtual void terminate() override
Terminates the module.
std::string m_inputFileName
Input MDST file name for backwards compatibility.
Belle::Panther_FileIO * m_fd
PantherFile.
std::vector< std::string > m_inputFileNames
List of input MDST filenames.
bool openNextFile()
Open the next file from the list of files.
StoreObjPtr< EventMetaData > m_evtMetaData
event meta data Object pointer
virtual void beginRun() override
Called when a new run is started.
std::set< int64_t > m_valid_entries_in_current_file
Entries numbers which are valid for the current file.
void initializeDataStore()
Initializes Belle II DataStore.
StoreObjPtr< FileMetaData > m_fileMetadata
File metadata to declare if we process real data or simulated data.
std::vector< std::string > getInputFiles() const
Get list of input files, taking -i command line overrides into account.
std::vector< std::string > m_entrySequences
The number sequences (e.g.
static Configuration & getInstance()
Get a reference to the instance which will be used when the Database is initialized.
void setInputGlobaltags(const std::vector< std::string > &inputTags)
To be called by input modules with the tags to be added from input files.
const std::vector< std::string > & getInputFilesOverride() const
Return overriden input file names, or empty vector if none were set.
Definition: Environment.h:103
const std::string & getExternalsPath() const
Returns the path which points to the externals directory of the framework.
Definition: Environment.h:60
std::vector< std::string > getEntrySequencesOverride() const
Returns the number sequences (e.g.
Definition: Environment.h:72
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:28
static bool isDir(const std::string &filename)
Check if filename points to an existing directory.
Definition: FileSystem.cc:51
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_Input
This module is an input module (reads data).
Definition: Module.h:78
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:96
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
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
Abstract base class for different kinds of events.