Belle II Software  release-08-00-03
RootOutputModule.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 <boost/python.hpp>
10 
11 #include <framework/modules/rootio/RootOutputModule.h>
12 
13 #include <framework/io/RootIOUtilities.h>
14 #include <framework/core/FileCatalog.h>
15 #include <framework/core/MetadataService.h>
16 #include <framework/core/RandomNumbers.h>
17 #include <framework/database/Database.h>
18 // needed for complex module parameter
19 #include <framework/core/ModuleParam.templateDetails.h>
20 #include <framework/utilities/EnvironmentVariables.h>
21 
22 #include <boost/filesystem/path.hpp>
23 #include <boost/filesystem/operations.hpp>
24 #include <boost/format.hpp>
25 #include <boost/algorithm/string.hpp>
26 
27 #include <TClonesArray.h>
28 
29 #include <nlohmann/json.hpp>
30 
31 #include <memory>
32 #include <regex>
33 
34 
35 using namespace std;
36 using namespace Belle2;
37 using namespace RootIOUtilities;
38 
39 //-----------------------------------------------------------------
40 // Register the Module
41 //-----------------------------------------------------------------
42 REG_MODULE(RootOutput);
43 
44 //-----------------------------------------------------------------
45 // Implementation
46 //-----------------------------------------------------------------
47 
48 RootOutputModule::RootOutputModule() : Module(), m_file(nullptr), m_tree{0}, m_experimentLow(1), m_runLow(0),
49  m_eventLow(0), m_experimentHigh(0), m_runHigh(0), m_eventHigh(0)
50 {
51  //Set module properties
52  setDescription("Writes DataStore objects into a .root file. Data is stored in a TTree 'tree' for event-dependent and in 'persistent' for peristent data. You can use RootInput to read the files back into basf2.");
54 
55  //Parameter definition
56  addParam("outputFileName", m_outputFileName, "Name of the output file. Can be overridden using the -o argument to basf2.",
57  string("RootOutput.root"));
58  addParam("ignoreCommandLineOverride", m_ignoreCommandLineOverride,
59  "Ignore override of file name via command line argument -o. Useful if you have multiple output modules in one path.", false);
60  addParam("compressionLevel", m_compressionLevel,
61  "0 for no, 1 for low, 9 for high compression. Level 1 usually reduces size by >50%, higher levels have no noticeable effect. On typical hard disks, disabling compression reduces write time by 10-20 %, but almost doubles read time, so you probably should leave this turned on.",
63  addParam("compressionAlgorithm", m_compressionAlgorithm,
64  "Set the Compression algorithm. Recommended values are 0 for default, 1 for zlib and 4 for lz4\n\n"
65  ".. versionadded:: release-03-00-00", m_compressionAlgorithm);
66  addParam("splitLevel", m_splitLevel,
67  "Branch split level: determines up to which depth object members will be saved in separate sub-branches in the tree. For arrays or objects with custom streamers, -1 is used instead to ensure the streamers are used. The default (99) usually gives the highest read performance with RootInput.",
68  99);
69  addParam("updateFileCatalog", m_updateFileCatalog, R"DOC(
70 Flag that specifies whether the file metadata catalog is updated or created.
71 This is only necessary in special cases and can always be done afterwards using
72 ``b2file-catalog-add filename.root``"
73 
74 (You can also set the ``BELLE2_FILECATALOG`` environment variable to NONE to get
75 the same effect as setting this to false))DOC", false);
76 
77  vector<string> emptyvector;
79  "Names of event durability branches to be saved. Empty means all branches. Objects with c_DontWriteOut flag added here will also be saved. (EventMetaData is always saved)",
80  emptyvector);
82  "Names of persistent durability branches to be saved. Empty means all branches. Objects with c_DontWriteOut flag added here will also be saved. (FileMetaData is always saved)",
83  emptyvector);
85  "Add additional event branch names without the need to specify all branchnames.",
86  emptyvector);
88  "Add additional persistent branch names without the need to specify all branchnames.",
89  emptyvector);
91  "Names of event durability branches NOT to be saved. Branches also in branchNames are not saved.", emptyvector);
93  "Names of persistent durability branches NOT to be saved. Branches also in branchNamesPersistent are not saved.", emptyvector);
94  addParam("autoFlushSize", m_autoflush,
95  "Value for TTree SetAutoFlush(): a positive value tells ROOT to flush all baskets to disk after n entries, a negative value to flush after -n bytes",
96  -10000000);
97  addParam("autoSaveSize", m_autosave,
98  "Value for TTree SetAutoSave(): a positive value tells ROOT to write the TTree metadata after n entries, a negative value to write the metadata after -n bytes",
99  -10000000);
100  addParam("basketSize", m_basketsize, "Basketsize for Branches in the Tree in bytes", 32000);
101  addParam("additionalDataDescription", m_additionalDataDescription, "Additional dictionary of "
102  "name->value pairs to be added to the file metadata to describe the data",
104  addParam("buildIndex", m_buildIndex, "Build Event Index for faster finding of events by exp/run/event number", m_buildIndex);
105  addParam("keepParents", m_keepParents, "Keep parents files of input files, input files will not be added as output file's parents",
106  m_keepParents);
107  addParam("outputSplitSize", m_outputSplitSize, R"DOC(
108 If given split the output file once the file has reached the given size in MB.
109 If set the filename will end in ``.f{index:05d}.root``. So if for example
110 ``outputFileName`` is set to "RootOutput.root" then the files will be named
111 ``RootOutput.f00000.root``, ``RootOutput.f00001.root``,
112 ``RootOutput.f00002.root``, ...
113 
114 All created output files are complete and independent files and can
115 subsequently processed completely independent.
116 
117 Note:
118  The output files will be approximately of the size given by
119  ``outputSplitSize`` but they will be slightly larger since
120  additional information has to be written at the end of the file. If necessary
121  please account for this. Also, using ``buildIndex=False`` might be beneficial
122  to reduce the overshoot.
123 
124 Warning:
125  This will set the amount of generated events stored in the file metadata to
126  zero as it is not possible to determine which fraction ends up in which
127  output file.
128 
129 .. versionadded:: release-03-00-00
130 )DOC", m_outputSplitSize);
131 }
132 
133 
135 
137 {
138  //ROOT has a default maximum size of 100GB for trees??? For larger trees it creates a new file and does other things that finally produce crashes.
139  //Let's set this to 100PB, that should last a bit longer.
140  TTree::SetMaxTreeSize(1000 * 1000 * 100000000000LL);
141 
142  //create a file level metadata object in the data store
143  m_fileMetaData.registerInDataStore();
144  //and make sure we have event meta data
145  m_eventMetaData.isRequired();
146 
147  //check outputSplitSize
148  if (m_outputSplitSize) {
149  if (*m_outputSplitSize == 0) B2ERROR("outputSplitSize must be set to a positive value");
150  // Warn is splitsize is >= 1TB ... because this seems weirdly like size was given in bytes
151  if (*m_outputSplitSize >= 1024*1024) B2WARNING("outputSplitSize set to " << *m_outputSplitSize << " MB, please make sure the units are correct");
152  // convert to bytes
153  *m_outputSplitSize *= 1024 * 1024;
154  }
155 
156  getFileNames();
157 
158  // Now check if the file has a protocol like file:// or http:// in front
159  std::regex protocol("^([A-Za-z]*)://");
160  if(std::smatch m; std::regex_search(m_outputFileName, m, protocol)) {
161  if(m[1] == "file") {
162  // file protocol: treat as local and just remove it from the filename
163  m_outputFileName = std::regex_replace(m_outputFileName, protocol, "");
164  } else {
165  // any other protocol: not local, don't create directories
166  m_regularFile = false;
167  }
168  }
169  openFile();
170 }
171 
173 {
174  // Since we open a new file, we also have to reset the number of full events
175  m_nFullEvents = 0;
176  // Continue with opening the file
177  TDirectory* dir = gDirectory;
178  boost::filesystem::path out{m_outputFileName};
179  if (m_outputSplitSize) {
180  // Mangle the filename to add the fNNNNN part. However we need to be
181  // careful since the file name could be non-local and have some options or
182  // anchor information attached (like
183  // http://mydomain.org/filename.root?foo=bar#baz). So use "TUrl" *sigh* to
184  // do the parsing and only replace the extension of the file part.
185  TUrl fileUrl(m_outputFileName.c_str(), m_regularFile);
186  boost::filesystem::path file{fileUrl.GetFile()};
187  file.replace_extension((boost::format("f%05d.root") % m_fileIndex).str());
188  fileUrl.SetFile(file.c_str());
189  // In case of regular files we don't want the protocol or anything, just the file
190  out = m_regularFile? fileUrl.GetFileAndOptions() : fileUrl.GetUrl();
191  }
192  m_file = TFile::Open(out.c_str(), "RECREATE", "basf2 Event File");
193  if ((!m_file || m_file->IsZombie()) && m_regularFile) {
194  //try creating necessary directories since this is a local file
195  auto dirpath = out.parent_path();
196 
197  if (boost::filesystem::create_directories(dirpath)) {
198  B2INFO("Created missing directory " << dirpath << ".");
199  //try again
200  m_file = TFile::Open(out.c_str(), "RECREATE", "basf2 Event File");
201  }
202 
203  }
204  if (!m_file || m_file->IsZombie()) {
205  B2FATAL("Couldn't open file " << out << " for writing!");
206  }
207  m_file->SetCompressionAlgorithm(m_compressionAlgorithm);
208  m_file->SetCompressionLevel(m_compressionLevel);
209 
210  for (int durability = 0; durability < DataStore::c_NDurabilityTypes; durability++) {
212  set<string> branchList;
213  for (const auto& pair : map)
214  branchList.insert(pair.first);
215  //skip branches the user doesn't want
216  branchList = filterBranches(branchList, m_branchNames[durability], m_excludeBranchNames[durability], durability);
217 
218  //create the tree and branches
219  m_tree[durability] = new TTree(c_treeNames[durability].c_str(), c_treeNames[durability].c_str());
220  m_tree[durability]->SetAutoFlush(m_autoflush);
221  m_tree[durability]->SetAutoSave(m_autosave);
222  for (auto & iter : map) {
223  const std::string& branchName = iter.first;
224  //skip transient entries (allow overriding via branchNames)
225  if (iter.second.dontWriteOut
226  && find(m_branchNames[durability].begin(), m_branchNames[durability].end(), branchName) == m_branchNames[durability].end()
227  && find(m_additionalBranchNames[durability].begin(), m_additionalBranchNames[durability].end(),
228  branchName) == m_additionalBranchNames[durability].end())
229  continue;
230  //skip branches the user doesn't want
231  if (branchList.count(branchName) == 0) {
232  //make sure FileMetaData and EventMetaData are always included in the output
233  if (((branchName != "FileMetaData") || (durability == DataStore::c_Event)) &&
234  ((branchName != "EventMetaData") || (durability == DataStore::c_Persistent))) {
235  continue;
236  }
237  }
238 
239  // Warn for anything other than FileMetaData and ProcessStatistics ...
240  if(durability == DataStore::c_Persistent and m_outputSplitSize and m_fileIndex==0 and
241  (branchName != "FileMetaData" and branchName != "ProcessStatistics")) {
242  B2WARNING("Persistent branches might not be stored as expected when splitting the output by size" << LogVar("branch", branchName));
243  }
244 
245  TClass* entryClass = iter.second.objClass;
246 
247  //I want to do this in the input module, but I apparently I cannot disable reading those branches.
248  //isabling reading the branch by not calling SetBranchAddress() for it results in the following crashes. Calling SetBranchStatus(..., 0) doesn't help, either.
249  //reported to ROOT devs, let's see if it gets fixed.
250  //
251  //HasDictionary() is a new function in root 6
252  //using it instead of GetClassInfo() avoids having to parse header files (and
253  //the associated memory cost)
254  if (!entryClass->HasDictionary()) {
255  if (m_fileIndex == 0) {
256  B2WARNING("No dictionary found, object will not be saved (This is probably an obsolete class that is still present in the input file.)"
257  << LogVar("class", entryClass->GetName()) << LogVar("branch", branchName));
258  }
259  continue;
260  }
261 
262  if (!hasStreamer(entryClass)) {
263  B2ERROR("The version number in the ClassDef() macro must be at least 1 to enable I/O!" << LogVar("class", entryClass->GetName()));
264  }
265 
266  int splitLevel = m_splitLevel;
267  if (hasCustomStreamer(entryClass)) {
268  B2DEBUG(38, "Class has custom streamer, setting split level -1 for this branch." << LogVar("class", entryClass->GetName()));
269 
270  splitLevel = -1;
271  if (iter.second.isArray) {
272  //for arrays, we also don't want TClonesArray to go around our streamer
273  static_cast<TClonesArray*>(iter.second.object)->BypassStreamer(kFALSE);
274  }
275  }
276  m_tree[durability]->Branch(branchName.c_str(), &iter.second.object, m_basketsize, splitLevel);
277  m_entries[durability].push_back(&iter.second);
278  B2DEBUG(39, "The branch " << branchName << " was created.");
279 
280  //Tell DataStore that we are using this entry
281  if (m_fileIndex == 0) {
282  DataStore::Instance().optionalInput(StoreAccessorBase(branchName, (DataStore::EDurability)durability, entryClass,
283  iter.second.isArray));
284  }
285  }
286  }
287 
288  dir->cd();
289  if (m_outputSplitSize) {
290  B2INFO(getName() << ": Opened " << (m_fileIndex > 0 ? "new " : "") << "file for writing" << LogVar("filename", out));
291  }
292 }
293 
294 
296 {
297  // if we closed after last event ... make a new one
298  if (!m_file)
299  openFile();
300 
301  if (!m_keepParents) {
302  if (m_fileMetaData) {
303  m_eventMetaData->setParentLfn(m_fileMetaData->getLfn());
304  }
305  }
306 
307  //fill Event data
309 
310  if (m_fileMetaData) {
311  if (m_keepParents) {
312  for (int iparent = 0; iparent < m_fileMetaData->getNParents(); iparent++) {
313  string lfn = m_fileMetaData->getParent(iparent);
314  if (!lfn.empty() && (m_parentLfns.empty() || (m_parentLfns.back() != lfn))) {
315  m_parentLfns.push_back(lfn);
316  }
317  }
318  } else {
319  string lfn = m_fileMetaData->getLfn();
320  if (!lfn.empty() && (m_parentLfns.empty() || (m_parentLfns.back() != lfn))) {
321  m_parentLfns.push_back(lfn);
322  }
323  }
324  }
325 
326  // keep track of file level metadata
327  unsigned long experiment = m_eventMetaData->getExperiment();
328  unsigned long run = m_eventMetaData->getRun();
329  unsigned long event = m_eventMetaData->getEvent();
330  if (m_experimentLow > m_experimentHigh) { //starting condition
331  m_experimentLow = m_experimentHigh = experiment;
332  m_runLow = m_runHigh = run;
334  } else {
335  if ((experiment < m_experimentLow) || ((experiment == m_experimentLow) && ((run < m_runLow) || ((run == m_runLow)
336  && (event < m_eventLow))))) {
337  m_experimentLow = experiment;
338  m_runLow = run;
339  m_eventLow = event;
340  }
341  if ((experiment > m_experimentHigh) || ((experiment == m_experimentHigh) && ((run > m_runHigh) || ((run == m_runHigh)
342  && (event > m_eventHigh))))) {
343  m_experimentHigh = experiment;
344  m_runHigh = run;
345  m_eventHigh = event;
346  }
347  }
348 
349  // check if the event is a full event or not: if yes, increase the counter
350  if (m_eventMetaData->getErrorFlag() == 0) // no error flag -> this is a full event
351  m_nFullEvents++;
352 
353  // check if we need to split the file
354  if (m_outputSplitSize and (uint64_t)m_file->GetEND() > *m_outputSplitSize) {
355  // close file and open new one
356  B2INFO(getName() << ": Output size limit reached, closing file ...");
357  closeFile();
358  }
359 }
360 
362 {
363  bool isMC = (m_fileMetaData) ? m_fileMetaData->isMC() : true;
364  m_fileMetaData.create(true);
365  if (!isMC) m_fileMetaData->declareRealData();
366 
367  if (m_tree[DataStore::c_Event]) {
368  //create an index for the event tree
369  TTree* tree = m_tree[DataStore::c_Event];
370  unsigned long numEntries = tree->GetEntries();
371  m_fileMetaData->setNFullEvents(m_nFullEvents);
372  if (m_buildIndex && numEntries > 0) {
373  if (numEntries > 10000000) {
374  //10M events correspond to about 240MB for the TTreeIndex object. for more than ~45M entries this causes crashes, broken files :(
375  B2WARNING("Not building TTree index because of large number of events. The index object would conflict with ROOT limits on object size and cause problems.");
376  } else if (tree->GetBranch("EventMetaData")) {
377  tree->SetBranchAddress("EventMetaData", nullptr);
379  }
380  }
381 
382  m_fileMetaData->setNEvents(numEntries);
384  //starting condition so apparently no events at all
385  m_fileMetaData->setLow(-1, -1, 0);
386  m_fileMetaData->setHigh(-1, -1, 0);
387  } else {
390  }
391  }
392 
393  //fill more file level metadata
394  m_fileMetaData->setParents(m_parentLfns);
396  m_fileMetaData->setRandomSeed(RandomNumbers::getSeed());
397  m_fileMetaData->setSteering(Environment::Instance().getSteering());
398  auto mcEvents = Environment::Instance().getNumberOfMCEvents();
399  if(m_outputSplitSize and mcEvents > 0) {
400  if(m_fileIndex == 0) B2WARNING("Number of MC Events cannot be saved when splitting output files by size, setting to 0");
401  mcEvents = 0;
402  }
403  m_fileMetaData->setMcEvents(mcEvents);
404  m_fileMetaData->setDatabaseGlobalTag(Database::Instance().getGlobalTags());
405  for (const auto& item : m_additionalDataDescription) {
406  m_fileMetaData->setDataDescription(item.first, item.second);
407  }
408  // Set the LFN to the filename: if it's a URL to directly, otherwise make sure it's absolute
409  std::string lfn = m_file->GetName();
410  if(m_regularFile) {
411  lfn = boost::filesystem::absolute(lfn, boost::filesystem::initial_path()).string();
412  }
413  // Format LFN if BELLE2_LFN_FORMATSTRING is set
414  std::string format = EnvironmentVariables::get("BELLE2_LFN_FORMATSTRING", "");
415  if (!format.empty()) {
416  auto format_filename = boost::python::import("B2Tools.format").attr("format_filename");
417  lfn = boost::python::extract<std::string>(format_filename(format, m_outputFileName, m_fileMetaData->getJsonStr()));
418  }
419  m_fileMetaData->setLfn(lfn);
420  //register the file in the catalog
421  if (m_updateFileCatalog) {
423  }
425 }
426 
427 
429 {
430  closeFile();
431 }
432 
434 {
435  if(!m_file) return;
436  //get pointer to file level metadata
437  std::unique_ptr<FileMetaData> old;
438  if (m_fileMetaData) old = std::make_unique<FileMetaData>(*m_fileMetaData);
439 
441 
442  //fill Persistent data
444 
445  // restore old file meta data if it existed
446  if (old) *m_fileMetaData = *old;
447  old.reset();
448 
449  //write the trees
450  TDirectory* dir = gDirectory;
451  m_file->cd();
452  for (int durability = 0; durability < DataStore::c_NDurabilityTypes; ++durability) {
453  if (m_tree[durability]) {
454  B2DEBUG(30, "Write TTree " << c_treeNames[durability]);
455  m_tree[durability]->Write(c_treeNames[durability].c_str(), TObject::kWriteDelete);
456  delete m_tree[durability];
457  }
458  m_tree[durability] = nullptr;
459  }
460  dir->cd();
461 
462  const std::string filename = m_file->GetName();
463  if (m_outputSplitSize) {
464  B2INFO(getName() << ": Finished writing file." << LogVar("filename", filename));
465  }
466  delete m_file;
467  m_file = nullptr;
468 
469  // and now add it to the metadata service as it's fully written
471 
472  // reset some variables
473  for (auto & entry : m_entries) {
474  entry.clear();
475  }
476  m_parentLfns.clear();
477  m_experimentLow = 1;
478  m_experimentHigh = 0;
479  m_runLow = 0;
480  m_runHigh = 0;
481  m_eventLow = 0;
482  m_eventHigh = 0;
483  // and increase index of next file
484  ++m_fileIndex;
485 }
486 
487 
489 {
490  if (!m_tree[durability]) return;
491 
492  TTree& tree = *m_tree[durability];
493  for(auto* entry: m_entries[durability]) {
494  // Check for entries whose object was not created and mark them as invalid.
495  // We still have to write them in the file due to the structure we have. This could be done better
496  if (!entry->ptr) {
497  entry->object->SetBit(kInvalidObject);
498  }
499  //FIXME: Do we need this? in theory no but it crashes in parallel processing otherwise ¯\_(ツ)_/¯
500  tree.SetBranchAddress(entry->name.c_str(), &entry->object);
501  }
502  tree.Fill();
503  for (auto* entry: m_entries[durability]) {
504  entry->object->ResetBit(kInvalidObject);
505  }
506 
507  const bool writeError = m_file->TestBit(TFile::kWriteError);
508  if (writeError) {
509  //m_file deleted first so we have a chance of closing it (though that will probably fail)
510  const std::string filename = m_file->GetName();
511  delete m_file;
512  B2FATAL("A write error occured while saving '" << filename << "', please check if enough disk space is available.");
513  }
514 }
StoreEntryMap & getStoreEntryMap(EDurability durability)
Get a reference to the object/array map.
Definition: DataStore.h:325
static const int c_NDurabilityTypes
Number of Durability Types.
Definition: DataStore.h:63
EDurability
Durability types.
Definition: DataStore.h:58
@ c_Persistent
Object is available during entire execution time.
Definition: DataStore.h:60
@ c_Event
Different object in each event, all objects/arrays are invalidated after event() function has been ca...
Definition: DataStore.h:59
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:54
bool optionalInput(const StoreAccessorBase &accessor)
Register the given object/array as an optional input.
Definition: DataStore.cc:739
std::map< std::string, StoreEntry > StoreEntryMap
Map for StoreEntries.
Definition: DataStore.h:87
unsigned int getNumberOfMCEvents() const
Number of generated events (from EventInfoSetter).
Definition: Environment.h:94
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:29
static FileCatalog & Instance()
Static method to get a reference to the FileCatalog instance.
Definition: FileCatalog.cc:23
virtual bool registerFile(const std::string &fileName, FileMetaData &metaData, const std::string &oldLFN="")
Register a file in the (local) file catalog.
Definition: FileCatalog.cc:90
void addRootOutputFile(const std::string &fileName, const FileMetaData *metaData=nullptr)
Add the metadata of a root output file.
static MetadataService & Instance()
Static method to get a reference to the MetadataService instance.
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_Output
This module is an output module (writes data).
Definition: Module.h:79
const std::string & getName() const
Returns the name of the module.
Definition: Module.h:187
static std::string getSeed()
Get the random number generator seed.
Definition: RandomNumbers.h:92
unsigned long m_experimentLow
Lowest experiment number.
std::vector< DataStore::StoreEntry * > m_entries[DataStore::c_NDurabilityTypes]
Vector of DataStore entries that are written to the output.
unsigned long m_experimentHigh
Highest experiment number.
unsigned long m_eventLow
Lowest event number in lowest run.
void fillFileMetaData()
Create and fill FileMetaData object.
int m_autosave
Number of entries (if >0) or number of bytes (if <0) after which write the tree metadata to disk.
bool m_regularFile
Whether this is a regular, local file where we can actually create directories.
unsigned long m_runLow
Lowest run number.
int m_compressionAlgorithm
TFile compression algorithm.
virtual void event() override
Write data in c_Event DataStore maps.
bool m_buildIndex
Whether or not we want to build an event index.
bool m_keepParents
Whether to keep parents same as that of input file.
virtual void terminate() override
Write data in the c_Persistent DataStore maps.
FileMetaData m_outputFileMetaData
File meta data finally stored in the output file.
TTree * m_tree[DataStore::c_NDurabilityTypes]
TTree for output.
unsigned int m_nFullEvents
Number of full events (aka number of events without an error flag)
unsigned long m_runHigh
Highest run number.
StoreObjPtr< EventMetaData > m_eventMetaData
Pointer to the event meta data.
std::vector< std::string > m_excludeBranchNames[DataStore::c_NDurabilityTypes]
Array for names of branches that should NOT be written out.
int m_basketsize
basket size for each branch in the file in bytes
std::vector< std::string > m_additionalBranchNames[DataStore::c_NDurabilityTypes]
Array of names of branches that should be written out although they are not flagged for writeout.
virtual void initialize() override
Setting up of various stuff.
TFile * m_file
TFile for output.
int m_fileIndex
Keep track of the file index: if we split files than we add '.f{fileIndex:05d}' in front of the ROOT ...
void fillTree(DataStore::EDurability durability)
Fill TTree.
bool m_ignoreCommandLineOverride
Ignore filename override from command line.
void closeFile()
Finalize the output file.
std::optional< uint64_t > m_outputSplitSize
Maximum output file size in MB.
int m_compressionLevel
TFile compression level.
int m_autoflush
Number of entries (if >0) or number of bytes (if <0) after which to flush all baskets to disk.
bool m_updateFileCatalog
Flag to enable or disable the update of the metadata catalog.
int m_splitLevel
Branch split level.
void openFile()
Open the next output file.
unsigned long m_eventHigh
Highest event number in highest run.
virtual ~RootOutputModule()
Destructor.
std::map< std::string, std::string > m_additionalDataDescription
Map of additional metadata to be added to the output file.
virtual std::vector< std::string > getFileNames(bool outputFiles=true) override
Set the used output file, taking into account -o argument to basf2.
std::vector< std::string > m_parentLfns
Vector of parent file LFNs.
std::vector< std::string > m_branchNames[DataStore::c_NDurabilityTypes]
Array for names of branches that should be written out.
StoreObjPtr< FileMetaData > m_fileMetaData
Pointer to the file meta data.
std::string m_outputFileName
Name for output file.
Base class for StoreObjPtr and StoreArray for easier common treatment.
Class to store variables with their name which were sent to the logging service.
static std::string get(const std::string &name, const std::string &fallback="")
Get the value of an environment variable or the given fallback value if the variable is not set.
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
static Database & Instance()
Instance of a singleton Database.
Definition: Database.cc:42
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
bool hasCustomStreamer(const TClass *cl)
Returns true if and only if 'cl' has a user-defined streamer.
const std::string c_treeNames[]
Names of trees.
const std::string c_SteerExcludeBranchNames[]
Steering parameter names for m_excludeBranchNames.
const std::string c_SteerBranchNames[]
Steering parameter names for m_branchNames.
void setCreationData(FileMetaData &metadata)
Fill the creation info of a file meta data: site, user, data.
std::set< std::string > filterBranches(const std::set< std::string > &branchesToFilter, const std::vector< std::string > &branches, const std::vector< std::string > &excludeBranches, int durability, bool quiet=false)
Given a list of input branches and lists of branches to include/exclude, returns a list of branches t...
const std::string c_SteerAdditionalBranchNames[]
Steering parameter names for m_additionalBranchNames.
void buildIndex(TTree *tree)
Build TTreeIndex on tree (assumes EventMetaData branch exists there).
bool hasStreamer(const TClass *cl)
Returns true if and only if 'cl' or one of its bases has I/O streamers.
Abstract base class for different kinds of events.