Belle II Software development
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
24using namespace std;
25using namespace Belle2;
26
27
28/*
29Some code for simple globing from
30http://stackoverflow.com/questions/8401777/simple-glob-in-c-on-unix-system
31In RootInput this is handled by ROOT
32*/
33#include <glob.h>
34#include <vector>
35#include <string>
36vector<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//-----------------------------------------------------------------
53REG_MODULE(B2BIIMdstInput);
54
55//-----------------------------------------------------------------
56// Implementation
57//-----------------------------------------------------------------
58
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
87std::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 this 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.
std::vector< std::string > getEntrySequencesOverride() const
Returns the number sequences (e.g.
Definition: Environment.h:73
const std::vector< std::string > & getInputFilesOverride() const
Return overriden input file names, or empty vector if none were set.
Definition: Environment.h:115
const std::string & getExternalsPath() const
Returns the path which points to the externals directory of the framework.
Definition: Environment.h:61
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.
STL namespace.