Belle II Software development
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/format.hpp>
23#include <boost/algorithm/string.hpp>
24
25#include <TClonesArray.h>
26
27#include <regex>
28#include <filesystem>
29
30using namespace std;
31using namespace Belle2;
32using namespace RootIOUtilities;
33
34//-----------------------------------------------------------------
35// Register the Module
36//-----------------------------------------------------------------
37REG_MODULE(RootOutput);
38
39//-----------------------------------------------------------------
40// Implementation
41//-----------------------------------------------------------------
42
43RootOutputModule::RootOutputModule() : Module(), m_file(nullptr), m_tree{0}, m_experimentLow(1), m_runLow(0),
44 m_eventLow(0), m_experimentHigh(0), m_runHigh(0), m_eventHigh(0)
45{
46 //Set module properties
47 setDescription("Writes DataStore objects into a .root file. Data is stored in a TTree 'tree' for event-dependent and in 'persistent' for persistent data. You can use RootInput to read the files back into basf2.");
49
50 //Parameter definition
51 addParam("outputFileName", m_outputFileName, "Name of the output file. Can be overridden using the -o argument to basf2.",
52 string("RootOutput.root"));
53 addParam("ignoreCommandLineOverride", m_ignoreCommandLineOverride,
54 "Ignore override of file name via command line argument -o. Useful if you have multiple output modules in one path.", false);
55 addParam("compressionLevel", m_compressionLevel,
56 "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.",
58 addParam("compressionAlgorithm", m_compressionAlgorithm,
59 "Set the Compression algorithm. Recommended values are 0 for default, 1 for zlib and 4 for lz4\n\n"
60 ".. versionadded:: release-03-00-00", m_compressionAlgorithm);
61 addParam("splitLevel", m_splitLevel,
62 "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.",
63 99);
64 addParam("updateFileCatalog", m_updateFileCatalog, R"DOC(
65Flag that specifies whether the file metadata catalog is updated or created.
66This is only necessary in special cases and can always be done afterwards using
67``b2file-catalog-add filename.root``"
68
69(You can also set the ``BELLE2_FILECATALOG`` environment variable to NONE to get
70the same effect as setting this to false))DOC", false);
71
72 vector<string> emptyvector;
74 "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)",
75 emptyvector);
77 "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)",
78 emptyvector);
80 "Add additional event branch names without the need to specify all branchnames.",
81 emptyvector);
83 "Add additional persistent branch names without the need to specify all branchnames.",
84 emptyvector);
86 "Names of event durability branches NOT to be saved. Branches also in branchNames are not saved.", emptyvector);
88 "Names of persistent durability branches NOT to be saved. Branches also in branchNamesPersistent are not saved.", emptyvector);
89 addParam("autoFlushSize", m_autoflush,
90 "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",
91 -10000000);
92 addParam("autoSaveSize", m_autosave,
93 "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",
94 -10000000);
95 addParam("basketSize", m_basketsize, "Basketsize for Branches in the Tree in bytes", 32000);
96 addParam("additionalDataDescription", m_additionalDataDescription, "Additional dictionary of "
97 "name->value pairs to be added to the file metadata to describe the data",
99 addParam("buildIndex", m_buildIndex, "Build Event Index for faster finding of events by exp/run/event number", m_buildIndex);
100 addParam("keepParents", m_keepParents, "Keep parents files of input files, input files will not be added as output file's parents",
102 addParam("outputSplitSize", m_outputSplitSize, R"DOC(
103If given split the output file once the file has reached the given size in MB.
104If set the filename will end in ``.f{index:05d}.root``. So if for example
105``outputFileName`` is set to "RootOutput.root" then the files will be named
106``RootOutput.f00000.root``, ``RootOutput.f00001.root``,
107``RootOutput.f00002.root``, ...
108
109All created output files are complete and independent files and can
110subsequently processed completely independent.
111
112Note:
113 The output files will be approximately of the size given by
114 ``outputSplitSize`` but they will be slightly larger since
115 additional information has to be written at the end of the file. If necessary
116 please account for this. Also, using ``buildIndex=False`` might be beneficial
117 to reduce the overshoot.
118
119Warning:
120 This will set the amount of generated events stored in the file metadata to
121 zero as it is not possible to determine which fraction ends up in which
122 output file.
123
124.. versionadded:: release-03-00-00
125)DOC", m_outputSplitSize);
126
128}
129
130
132{
134}
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 //make sure we have event meta data
143 m_eventMetaData.isRequired();
144
145 //check outputSplitSize
146 if (m_outputSplitSize) {
147 if (*m_outputSplitSize == 0) B2ERROR("outputSplitSize must be set to a positive value");
148 // Warn is splitsize is >= 1TB ... because this seems weirdly like size was given in bytes
149 if (*m_outputSplitSize >= 1024*1024) B2WARNING("outputSplitSize set to " << *m_outputSplitSize << " MB, please make sure the units are correct");
150 // convert to bytes
151 *m_outputSplitSize *= 1024 * 1024;
152 }
153
154 getFileNames();
155
156 // Now check if the file has a protocol like file:// or http:// in front
157 std::regex protocol("^([A-Za-z]*)://");
158 if(std::smatch m; std::regex_search(m_outputFileName, m, protocol)) {
159 if(m[1] == "file") {
160 // file protocol: treat as local and just remove it from the filename
161 m_outputFileName = std::regex_replace(m_outputFileName, protocol, "");
162 } else {
163 // any other protocol: not local, don't create directories
164 m_regularFile = false;
165 }
166 }
167 openFile();
168}
169
171{
172 // Since we open a new file, we also have to reset the number of full events
173 m_nFullEvents = 0;
174 // Continue with opening the file
175 TDirectory* dir = gDirectory;
176 std::filesystem::path out{m_outputFileName};
177 if (m_outputSplitSize) {
178 // Mangle the filename to add the fNNNNN part. However we need to be
179 // careful since the file name could be non-local and have some options or
180 // anchor information attached (like
181 // http://mydomain.org/filename.root?foo=bar#baz). So use "TUrl" *sigh* to
182 // do the parsing and only replace the extension of the file part.
183 TUrl fileUrl(m_outputFileName.c_str(), m_regularFile);
184 std::filesystem::path file{fileUrl.GetFile()};
185 file.replace_extension((boost::format("f%05d.root") % m_fileIndex).str());
186 fileUrl.SetFile(file.c_str());
187 // In case of regular files we don't want the protocol or anything, just the file
188 out = m_regularFile? fileUrl.GetFileAndOptions() : fileUrl.GetUrl();
189 }
190 m_file = TFile::Open(out.c_str(), "RECREATE", "basf2 Event File");
191 if ((!m_file || m_file->IsZombie()) && m_regularFile) {
192 //try creating necessary directories since this is a local file
193 auto dirpath = out.parent_path();
194
195 if (std::filesystem::create_directories(dirpath)) {
196 B2INFO("Created missing directory " << dirpath << ".");
197 //try again
198 m_file = TFile::Open(out.c_str(), "RECREATE", "basf2 Event File");
199 }
200
201 }
202 if (!m_file || m_file->IsZombie()) {
203 B2FATAL("Couldn't open file " << out << " for writing!");
204 }
205 m_file->SetCompressionAlgorithm(m_compressionAlgorithm);
206 m_file->SetCompressionLevel(m_compressionLevel);
207
208 for (int durability = 0; durability < DataStore::c_NDurabilityTypes; durability++) {
210 set<string> branchList;
211 for (const auto& pair : map)
212 branchList.insert(pair.first);
213 //skip branches the user doesn't want
214 branchList = filterBranches(branchList, m_branchNames[durability], m_excludeBranchNames[durability], durability);
215
216 //create the tree and branches
217 m_tree[durability] = new TTree(c_treeNames[durability].c_str(), c_treeNames[durability].c_str());
218 m_tree[durability]->SetAutoFlush(m_autoflush);
219 m_tree[durability]->SetAutoSave(m_autosave);
220 for (auto & iter : map) {
221 const std::string& branchName = iter.first;
222 //skip transient entries (allow overriding via branchNames)
223 if (iter.second.dontWriteOut
224 && find(m_branchNames[durability].begin(), m_branchNames[durability].end(), branchName) == m_branchNames[durability].end()
225 && find(m_additionalBranchNames[durability].begin(), m_additionalBranchNames[durability].end(),
226 branchName) == m_additionalBranchNames[durability].end())
227 continue;
228 //skip branches the user doesn't want
229 if (branchList.count(branchName) == 0) {
230 //make sure FileMetaData and EventMetaData are always included in the output
231 if (((branchName != "FileMetaData") || (durability == DataStore::c_Event)) &&
232 ((branchName != "EventMetaData") || (durability == DataStore::c_Persistent))) {
233 continue;
234 }
235 }
236
237 // Warn for anything other than FileMetaData and ProcessStatistics ...
238 if(durability == DataStore::c_Persistent and m_outputSplitSize and m_fileIndex==0 and
239 (branchName != "FileMetaData" and branchName != "ProcessStatistics")) {
240 B2WARNING("Persistent branches might not be stored as expected when splitting the output by size" << LogVar("branch", branchName));
241 }
242
243 TClass* entryClass = iter.second.objClass;
244
245 //I want to do this in the input module, but I apparently I cannot disable reading those branches.
246 //isabling reading the branch by not calling SetBranchAddress() for it results in the following crashes. Calling SetBranchStatus(..., 0) doesn't help, either.
247 //reported to ROOT devs, let's see if it gets fixed.
248 //
249 //HasDictionary() is a new function in root 6
250 //using it instead of GetClassInfo() avoids having to parse header files (and
251 //the associated memory cost)
252 if (!entryClass->HasDictionary()) {
253 if (m_fileIndex == 0) {
254 B2WARNING("No dictionary found, object will not be saved (This is probably an obsolete class that is still present in the input file.)"
255 << LogVar("class", entryClass->GetName()) << LogVar("branch", branchName));
256 }
257 continue;
258 }
259
260 if (!hasStreamer(entryClass)) {
261 B2ERROR("The version number in the ClassDef() macro must be at least 1 to enable I/O!" << LogVar("class", entryClass->GetName()));
262 }
263
264 int splitLevel = m_splitLevel;
265 if (hasCustomStreamer(entryClass)) {
266 B2DEBUG(38, "Class has custom streamer, setting split level -1 for this branch." << LogVar("class", entryClass->GetName()));
267
268 splitLevel = -1;
269 if (iter.second.isArray) {
270 //for arrays, we also don't want TClonesArray to go around our streamer
271 static_cast<TClonesArray*>(iter.second.object)->BypassStreamer(kFALSE);
272 }
273 }
274 m_tree[durability]->Branch(branchName.c_str(), &iter.second.object, m_basketsize, splitLevel);
275 m_entries[durability].push_back(&iter.second);
276 B2DEBUG(39, "The branch " << branchName << " was created.");
277
278 //Tell DataStore that we are using this entry
279 if (m_fileIndex == 0) {
281 iter.second.isArray));
282 }
283 }
284 }
285
286 // set the address of the FileMetaData branch for the output to a separate one from the input
287 TBranch* fileMetaDataBranch = m_tree[DataStore::c_Persistent]->GetBranch("FileMetaData");
288 if (fileMetaDataBranch) {
289 fileMetaDataBranch->SetAddress(&m_outputFileMetaData);
290 } else {
292 }
293
294 dir->cd();
295 if (m_outputSplitSize) {
296 B2INFO(getName() << ": Opened " << (m_fileIndex > 0 ? "new " : "") << "file for writing" << LogVar("filename", out));
297 }
298}
299
300
302{
303 // if we closed after last event ... make a new one
304 if (!m_file)
305 openFile();
306
307 if (!m_keepParents) {
308 if (m_fileMetaData) {
309 m_eventMetaData->setParentLfn(m_fileMetaData->getLfn());
310 }
311 }
312
313 //fill Event data
315
316 if (m_fileMetaData) {
317 if (m_keepParents) {
318 for (int iparent = 0; iparent < m_fileMetaData->getNParents(); iparent++) {
319 string lfn = m_fileMetaData->getParent(iparent);
320 if (!lfn.empty() && (m_parentLfns.empty() || (m_parentLfns.back() != lfn))) {
321 m_parentLfns.push_back(lfn);
322 }
323 }
324 } else {
325 string lfn = m_fileMetaData->getLfn();
326 if (!lfn.empty() && (m_parentLfns.empty() || (m_parentLfns.back() != lfn))) {
327 m_parentLfns.push_back(lfn);
328 }
329 }
330 }
331
332 // keep track of file level metadata
333 unsigned long experiment = m_eventMetaData->getExperiment();
334 unsigned long run = m_eventMetaData->getRun();
335 unsigned long event = m_eventMetaData->getEvent();
336 if (m_experimentLow > m_experimentHigh) { //starting condition
337 m_experimentLow = m_experimentHigh = experiment;
338 m_runLow = m_runHigh = run;
340 } else {
341 if ((experiment < m_experimentLow) || ((experiment == m_experimentLow) && ((run < m_runLow) || ((run == m_runLow)
342 && (event < m_eventLow))))) {
343 m_experimentLow = experiment;
344 m_runLow = run;
346 }
347 if ((experiment > m_experimentHigh) || ((experiment == m_experimentHigh) && ((run > m_runHigh) || ((run == m_runHigh)
348 && (event > m_eventHigh))))) {
349 m_experimentHigh = experiment;
350 m_runHigh = run;
352 }
353 }
354
355 // check if the event is a full event or not: if yes, increase the counter
356 if (m_eventMetaData->getErrorFlag() == 0) // no error flag -> this is a full event
358
359 // check if we need to split the file
360 if (m_outputSplitSize and (uint64_t)m_file->GetEND() > *m_outputSplitSize) {
361 // close file and open new one
362 B2INFO(getName() << ": Output size limit reached, closing file ...");
363 closeFile();
364 }
365}
366
368{
369 bool isMC = (m_fileMetaData) ? m_fileMetaData->isMC() : true;
372
374 //create an index for the event tree
375 TTree* tree = m_tree[DataStore::c_Event];
376 unsigned long numEntries = tree->GetEntries();
378 if (m_buildIndex && numEntries > 0) {
379 if (numEntries > 10000000) {
380 //10M events correspond to about 240MB for the TTreeIndex object. for more than ~45M entries this causes crashes, broken files :(
381 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.");
382 } else if (tree->GetBranch("EventMetaData")) {
383 tree->SetBranchAddress("EventMetaData", nullptr);
385 }
386 }
387
388 m_outputFileMetaData->setNEvents(numEntries);
390 //starting condition so apparently no events at all
391 m_outputFileMetaData->setLow(-1, -1, 0);
392 m_outputFileMetaData->setHigh(-1, -1, 0);
393 } else {
396 }
397 }
398
399 //fill more file level metadata
404 auto mcEvents = Environment::Instance().getNumberOfMCEvents();
405 if(m_outputSplitSize and mcEvents > 0) {
406 if(m_fileIndex == 0) B2WARNING("Number of MC Events cannot be saved when splitting output files by size, setting to 0");
407 mcEvents = 0;
408 }
411 for (const auto& item : m_additionalDataDescription) {
412 m_outputFileMetaData->setDataDescription(item.first, item.second);
413 }
414 // Set the LFN to the filename: if it's a URL to directly, otherwise make sure it's absolute
415 std::string lfn = m_file->GetName();
416 if(m_regularFile) {
417 lfn = std::filesystem::absolute(lfn).string();
418 }
419 // Format LFN if BELLE2_LFN_FORMATSTRING is set
420 std::string format = EnvironmentVariables::get("BELLE2_LFN_FORMATSTRING", "");
421 if (!format.empty()) {
422 auto format_filename = boost::python::import("B2Tools.format").attr("format_filename");
423 lfn = boost::python::extract<std::string>(format_filename(format, m_outputFileName, m_outputFileMetaData->getJsonStr()));
424 }
426 //register the file in the catalog
429 }
430}
431
432
434{
435 closeFile();
436}
437
439{
440 if(!m_file) return;
441
443
444 //fill Persistent data
446
447 //write the trees
448 TDirectory* dir = gDirectory;
449 m_file->cd();
450 for (int durability = 0; durability < DataStore::c_NDurabilityTypes; ++durability) {
451 if (m_tree[durability]) {
452 B2DEBUG(30, "Write TTree " << c_treeNames[durability]);
453 m_tree[durability]->Write(c_treeNames[durability].c_str(), TObject::kWriteDelete);
454 delete m_tree[durability];
455 }
456 m_tree[durability] = nullptr;
457 }
458 dir->cd();
459
460 const std::string filename = m_file->GetName();
461 if (m_outputSplitSize) {
462 B2INFO(getName() << ": Finished writing file." << LogVar("filename", filename));
463 }
464 delete m_file;
465 m_file = nullptr;
466
467 // and now add it to the metadata service as it's fully written
469
470 // reset some variables
471 for (auto & entry : m_entries) {
472 entry.clear();
473 }
474 m_parentLfns.clear();
475 m_experimentLow = 1;
477 m_runLow = 0;
478 m_runHigh = 0;
479 m_eventLow = 0;
480 m_eventHigh = 0;
481 // and increase index of next file
482 ++m_fileIndex;
483}
484
485
487{
488 if (!m_tree[durability]) return;
489
490 TTree& tree = *m_tree[durability];
491 for(auto* entry: m_entries[durability]) {
492 // Check for entries whose object was not created and mark them as invalid.
493 // We still have to write them in the file due to the structure we have. This could be done better
494 if (!entry->ptr) {
495 entry->object->SetBit(kInvalidObject);
496 }
497 //FIXME: Do we need this? in theory no but it crashes in parallel processing otherwise ¯\_(ツ)_/¯
498 if (entry->name == "FileMetaData") {
499 tree.SetBranchAddress(entry->name.c_str(), &m_outputFileMetaData);
500 } else {
501 tree.SetBranchAddress(entry->name.c_str(), &entry->object);
502 }
503 }
504 tree.Fill();
505 for (auto* entry: m_entries[durability]) {
506 entry->object->ResetBit(kInvalidObject);
507 }
508
509 const bool writeError = m_file->TestBit(TFile::kWriteError);
510 if (writeError) {
511 //m_file deleted first so we have a chance of closing it (though that will probably fail)
512 const std::string filename = m_file->GetName();
513 delete m_file;
514 B2FATAL("A write error occurred while saving '" << filename << "', please check if enough disk space is available.");
515 }
516}
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:53
bool optionalInput(const StoreAccessorBase &accessor)
Register the given object/array as an optional input.
Definition: DataStore.cc:738
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:107
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:28
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
Metadata information about a file.
Definition: FileMetaData.h:29
void setLow(int experiment, int run, unsigned int event)
Lowest experiment, run and event number setter.
Definition: FileMetaData.h:159
void setHigh(int experiment, int run, unsigned int event)
Highest experiment, run and event number setter.
Definition: FileMetaData.h:167
void setRandomSeed(const std::string &seed)
Random seed setter.
Definition: FileMetaData.h:189
void setSteering(const std::string &steering)
Steering file content setter.
Definition: FileMetaData.h:201
void declareRealData()
Declare that this is not generated, but real data.
Definition: FileMetaData.h:300
void setNFullEvents(unsigned int nEvents)
Number of full events setter.
Definition: FileMetaData.h:151
std::string getJsonStr() const
Get a json representation.
void setDatabaseGlobalTag(const std::string &globalTag)
Set the database global tag used when creating this file.
Definition: FileMetaData.h:214
void setLfn(const std::string &lfn)
Setter for LFN.
Definition: FileMetaData.h:139
void setDataDescription(const std::string &key, const std::string &value)
describe the data, if the key exists contents will be overwritten.
Definition: FileMetaData.h:220
void setNEvents(unsigned int nEvents)
Number of events setter.
Definition: FileMetaData.h:145
void setMcEvents(unsigned int nEvents)
Number of generated events setter.
Definition: FileMetaData.h:207
void setParents(const std::vector< std::string > &parents)
Parents setter.
Definition: FileMetaData.h:173
void addRootOutputFile(const std::string &fileName, const FileMetaData *metaData=nullptr, const char *type="RootOutput")
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
const std::string & getName() const
Returns the name of the module.
Definition: Module.h:186
@ c_Output
This module is an output module (writes data).
Definition: Module.h:79
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.
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.
FileMetaData * m_outputFileMetaData
File meta data stored in the output file.
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.
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.
virtual std::vector< std::string > getFileNames(bool outputFiles=true) override
Set the used output file, taking into account -o argument to basf2.
StoreObjPtr< FileMetaData > m_fileMetaData
Pointer to the input 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:559
static Database & Instance()
Instance of a singleton Database.
Definition: Database.cc:41
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:649
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 either EventMetaData branch exists or is a ntuple tree).
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.
STL namespace.