LDMX Software
Process.cxx
Go to the documentation of this file.
1
6#include "Framework/Process.h"
7
8#include <iostream>
9
10#include "Framework/Event.h"
11#include "Framework/EventFile.h"
13#include "Framework/Exception/Exception.h"
14#include "Framework/Logger.h"
15#include "Framework/NtupleManager.h"
17#include "Framework/RunHeader.h"
18#include "TFile.h"
19#include "TROOT.h"
20
21namespace framework {
22
24 : conditions_{*this} {
25 config_ = configuration;
26
27 passname_ = configuration.getParameter<std::string>("passName", "");
28 histoFilename_ = configuration.getParameter<std::string>("histogramFile", "");
29
30 maxTries_ = configuration.getParameter<int>("maxTriesPerEvent", 1);
31 eventLimit_ = configuration.getParameter<int>("maxEvents", -1);
32 totalEvents_ = configuration.getParameter<int>("totalEvents", -1);
33 logFrequency_ = configuration.getParameter<int>("logFrequency", -1);
35 configuration.getParameter<int>("compressionSetting", 9);
37 configuration.getParameter<bool>("skipCorruptedInputFiles", false);
38
40 configuration.getParameter<std::vector<std::string>>("inputFiles", {});
42 configuration.getParameter<std::vector<std::string>>("outputFiles", {});
44 configuration.getParameter<std::vector<std::string>>("keep", {});
45
46 eventHeader_ = 0;
47
48 // set up the logging for this run
49 logging::open(
50 configuration.getParameter<framework::config::Parameters>("logger", {}));
51
52 auto run{configuration.getParameter<int>("run", -1)};
53 if (run > 0) runForGeneration_ = run;
54
55 auto libs{
56 configuration.getParameter<std::vector<std::string>>("libraries", {})};
57 std::for_each(libs.begin(), libs.end(), [](auto &lib) {
58 PluginFactory::getInstance().loadLibrary(lib);
59 });
60
62 configuration.getParameter<bool>("skimDefaultIsKeep", true));
63 auto skimRules{
64 configuration.getParameter<std::vector<std::string>>("skimRules", {})};
65 for (size_t i = 0; i < skimRules.size(); i += 2) {
66 storageController_.addRule(skimRules[i], skimRules[i + 1]);
67 }
68
69 auto sequence{
70 configuration.getParameter<std::vector<framework::config::Parameters>>(
71 "sequence", {})};
72 if (sequence.empty() &&
73 configuration.getParameter<bool>("testingMode", false)) {
74 EXCEPTION_RAISE(
75 "NoSeq",
76 "No sequence has been defined. What should I be doing?\nUse "
77 "p.sequence to tell me what processors to run.");
78 }
79 for (auto proc : sequence) {
80 auto className{proc.getParameter<std::string>("className")};
81 auto instanceName{proc.getParameter<std::string>("instanceName")};
83 className, instanceName, *this);
84 if (ep == 0) {
85 EXCEPTION_RAISE(
86 "UnableToCreate",
87 "Unable to create instance '" + instanceName + "' of class '" +
88 className +
89 "'. Did you load the library that this class is apart of?");
90 }
91 auto histograms{
92 proc.getParameter<std::vector<framework::config::Parameters>>(
93 "histograms", {})};
94 if (!histograms.empty()) {
96 ep->createHistograms(histograms);
97 }
98 ep->configure(proc);
99 sequence_.push_back(ep);
100 }
101
102 auto conditionsObjectProviders{
103 configuration.getParameter<std::vector<framework::config::Parameters>>(
104 "conditionsObjectProviders", {})};
105 for (auto cop : conditionsObjectProviders) {
106 auto className{cop.getParameter<std::string>("className")};
107 auto objectName{cop.getParameter<std::string>("objectName")};
108 auto tagName{cop.getParameter<std::string>("tagName")};
109
110 conditions_.createConditionsObjectProvider(className, objectName, tagName,
111 cop);
112 }
113
114 bool logPerformance =
115 configuration.getParameter<bool>("logPerformance", false);
116 if (logPerformance) {
117 std::vector<std::string> names{sequence_.size()};
118 for (std::size_t i{0}; i < sequence_.size(); i++) {
119 names[i] = sequence_[i]->getName();
120 }
122 new performance::Tracker(makeHistoDirectory("performance"), names);
123 }
124}
125
127 // need to delete the performance object so that it is
128 // written before we close the histogram file below
129 if (performance_) delete performance_;
130 for (EventProcessor *ep : sequence_) {
131 delete ep;
132 }
133 if (histoTFile_) {
134 histoTFile_->Write();
135 delete histoTFile_;
136 histoTFile_ = 0;
137 }
138}
139
142
143 // Counter to keep track of the number of events that have been
144 // procesed
145 auto n_events_processed{0};
146
147 // make sure the ntuple manager is in a blank state
149
150 // event bus for this process
151 Event theEvent(passname_);
152 // the EventHeader object is created with the event bus as
153 // one of its members, we obtain a pointer for the header
154 // here so we can share it with the conditions system
155 eventHeader_ = theEvent.getEventHeaderPtr();
157
158 // Start by notifying everyone that modules processing is beginning
159 std::size_t i_proc{0};
160 if (performance_)
161 performance_->start(performance::Callback::onProcessStart, 0);
163 for (auto module : sequence_) {
164 i_proc++;
165 if (performance_)
166 performance_->start(performance::Callback::onProcessStart, i_proc);
167 module->onProcessStart();
168 if (performance_)
169 performance_->stop(performance::Callback::onProcessStart, i_proc);
170 }
171 if (performance_)
172 performance_->stop(performance::Callback::onProcessStart, 0);
173
174 // If we have no input files, but do have an event number, run for
175 // that number of events and generate an output file.
176 if (inputFiles_.empty() && eventLimit_ > 0) {
177 if (outputFiles_.empty()) {
178 EXCEPTION_RAISE("InvalidConfig",
179 "No input files or output files were given.");
180 } else if (outputFiles_.size() > 1) {
181 ldmx_log(warn) << "Several output files given with no input files. "
182 << "Only the first output file '" << outputFiles_.at(0)
183 << "' will be used.";
184 }
185 std::string outputFileName = outputFiles_.at(0);
186
187 // Configure the event file to create an output file with no parent. This
188 // requires setting the parameters isOutputFile and isSingleOutput to true.
189 EventFile outFile(config_, outputFileName, nullptr, true, true, false);
190 onFileOpen(outFile);
191 outFile.setupEvent(&theEvent);
192
193 for (auto rule : dropKeepRules_) outFile.addDrop(rule);
194
196 runHeader.setRunStart(std::time(nullptr)); // set run starting
197 runHeader_ = &runHeader; // give handle to run header to process
198 outFile.writeRunHeader(runHeader); // add run header to file
199
200 newRun(runHeader);
201
202 int totalTries = 0; // total number of tries for entire run
203 int numTries = 0; // number of tries for the current event number
204 int event_limit = eventLimit_;
205 if (totalEvents_ > 0) {
206 // Have a warning at the first event
207 if (numTries == 0)
208 ldmx_log(warn) << "The totalEvents was set, so maxEvents and "
209 "maxTriesPerEvent will be ignored!";
210 event_limit = totalEvents_;
211 }
212 while (n_events_processed < event_limit) {
213 totalTries++;
214 numTries++;
215
216 ldmx::EventHeader &eh = theEvent.getEventHeader();
218 eh.setEventNumber(n_events_processed + 1);
219 eh.setTimestamp(TTimeStamp());
220
221 // reset the storage controller state
224
225 bool completed = process(n_events_processed, numTries, theEvent);
226
227 outFile.nextEvent(storageController_.keepEvent(completed));
228
229 // reset try counter only on successfully completed events
230 if (completed) numTries = 0;
231
232 // we use modulo here insetad of >= because we want to carry
233 // the number of tries across the number of events processed boundary
234 // totalEvents_ is set let's not exit until that's reached
235 if (completed or (totalEvents_ < 0 and numTries % maxTries_ == 0)) {
236 n_events_processed++; // increment events made
237 NtupleManager::getInstance().fill(); // fill ntuples
238 }
239
241 }
242
243 onFileClose(outFile);
244
245 runHeader.setRunEnd(std::time(nullptr));
246 runHeader.setNumTries(totalTries);
247 ldmx_log(info) << runHeader;
248 outFile.writeRunTree();
249
250 // Give a warning that this filter has very low efficiency
251 if (n_events_processed < totalTries / 10000) { // integer division is okay
252 ldmx_log(warn)
253 << "Less than 1 event out of every 10k events tried was accepted!";
254 ldmx_log(warn)
255 << "This could be an issue with your filtering and biasing procedure "
256 "since this is incredibly inefficient.";
257 }
258
259 } else {
260 // there are input files
261
262 EventFile *outFile(0);
263
264 bool singleOutput = false;
265 if (outputFiles_.size() == 1) {
266 singleOutput = true;
267 } else if (!outputFiles_.empty() and
268 outputFiles_.size() != inputFiles_.size()) {
269 EXCEPTION_RAISE("Process",
270 "Unable to handle case of different number of input and "
271 "output files (other than zero/one ouput file).");
272 }
273
274 // next, loop through the files
275 int ifile = 0;
276 int wasRun = -1;
277 for (auto infilename : inputFiles_) {
278 EventFile inFile(config_, infilename);
279 if (inFile.isCorrupted()) {
281 ldmx_log(warn) << "Input file '" << infilename
282 << "' was found to be corrupted. Skipping.";
283 continue;
284 } else {
285 EXCEPTION_RAISE(
286 "BadCode",
287 "We should never get here. "
288 "EventFile is corrupted but we aren't skipping corrupted inputs. "
289 "EventFile should be throwing its own exceptions in this case.");
290 }
291 }
292
293 ldmx_log(info) << "Opening file " << infilename;
294 onFileOpen(inFile);
295
296 // configure event file that will be iterated over
297 EventFile *masterFile;
298 if (!outputFiles_.empty()) {
299 // setup new output file if either
300 // 1) we are not in single output mode
301 // 2) this is the first input file
302 if (!singleOutput or ifile == 0) {
303 // setup new output file
304 outFile = new EventFile(config_, outputFiles_[ifile], &inFile,
305 singleOutput);
306 ifile++;
307
308 // setup theEvent we will iterate over
309 if (outFile) {
310 outFile->setupEvent(&theEvent);
311 masterFile = outFile;
312 } else {
313 EXCEPTION_RAISE("Process", "Unable to construct output file for " +
314 outputFiles_[ifile]);
315 }
316
317 for (auto rule : dropKeepRules_) outFile->addDrop(rule);
318
319 } else {
320 // all other input files
321 outFile->updateParent(&inFile);
322 masterFile = outFile;
323
324 } // check if in singleOutput mode
325
326 } else {
327 // empty output file list, use inputFile as master file
328 inFile.setupEvent(&theEvent);
329 masterFile = &inFile;
330 }
331
332 bool event_completed = true;
333 while (masterFile->nextEvent(
334 storageController_.keepEvent(event_completed)) &&
335 (eventLimit_ < 0 || (n_events_processed) < eventLimit_)) {
336 // clean up for storage control calculation
339
340 // notify for new run if necessary
341 if (theEvent.getEventHeader().getRun() != wasRun) {
342 wasRun = theEvent.getEventHeader().getRun();
343 ldmx::RunHeader *rh{masterFile->getRunHeaderPtr(wasRun)};
344 if (rh != nullptr) {
345 runHeader_ = rh;
346 ldmx_log(info) << "Got new run header from '"
347 << masterFile->getFileName() << "' ...\n"
348 << *runHeader_;
350 } else {
351 ldmx_log(warn) << "Run header for run " << wasRun
352 << " was not found!";
353 }
354 }
355
356 event_completed = process(n_events_processed, 1, theEvent);
357
358 if (event_completed) NtupleManager::getInstance().fill();
360
361 n_events_processed++;
362 } // loop through events
363
364 bool leave_early{false};
365 if (eventLimit_ > 0 && n_events_processed == eventLimit_) {
366 ldmx_log(info) << "Reached event limit of " << eventLimit_ << " events";
367 leave_early = true;
368 }
369
370 if (eventLimit_ == 0 && n_events_processed > eventLimit_) {
371 ldmx_log(warn) << "Processing interrupted";
372 leave_early = true;
373 }
374
375 ldmx_log(info) << "Closing file " << infilename;
376 onFileClose(inFile);
377
378 // Reset the event in case of multiple input files
379 theEvent.onEndOfFile();
380
381 if (outFile and !singleOutput) {
382 outFile->writeRunTree();
383 delete outFile;
384 outFile = nullptr;
385 }
386
387 if (leave_early) {
388 break;
389 }
390 } // loop through input files
391
392 if (outFile) {
393 // close outFile
394 // outFile would survive to here in single output mode
395 outFile->writeRunTree();
396 delete outFile;
397 outFile = nullptr;
398 }
399
400 } // are there input files? if-else tree
401
402 // finally, notify everyone that we are stopping
403 if (performance_) performance_->start(performance::Callback::onProcessEnd, 0);
404 i_proc = 0;
405 for (auto module : sequence_) {
406 i_proc++;
407 if (performance_)
408 performance_->start(performance::Callback::onProcessEnd, i_proc);
409 module->onProcessEnd();
410 if (performance_)
411 performance_->stop(performance::Callback::onProcessEnd, i_proc);
412 }
413 if (performance_) performance_->stop(performance::Callback::onProcessEnd, 0);
414
415 // we're done so let's close up the logging
416 logging::close();
418}
419
422}
423
424TDirectory *Process::makeHistoDirectory(const std::string &dirName) {
425 auto owner{openHistoFile()};
426 TDirectory *child = owner->mkdir((char *)dirName.c_str());
427 if (child) child->cd();
428 return child;
429}
430
432 TDirectory *owner{nullptr};
433
434 if (histoFilename_.empty()) {
435 // trying to write histograms/ntuples but no file defined
436 EXCEPTION_RAISE(
437 "NoHistFileName",
438 "You did not provide the necessary histogram file name to "
439 "put your histograms (or performance data) in.\n Provide this "
440 "name in the python configuration with 'p.histogramFile = "
441 "\"myHistFile.root\"' where p is the Process object.");
442 } else if (histoTFile_ == nullptr) {
443 histoTFile_ = new TFile(histoFilename_.c_str(), "RECREATE");
444 owner = histoTFile_;
445 } else
446 owner = histoTFile_;
447 owner->cd();
448
449 return owner;
450}
451
453 // Producers are allowed to put parameters into
454 // the run header through 'beforeNewRun' method
455 if (performance_) performance_->start(performance::Callback::beforeNewRun, 0);
456 std::size_t i_proc{0};
457 for (auto module : sequence_) {
458 i_proc++;
459 if (dynamic_cast<Producer *>(module)) {
460 if (performance_)
461 performance_->start(performance::Callback::beforeNewRun, i_proc);
462 dynamic_cast<Producer *>(module)->beforeNewRun(header);
463 if (performance_)
464 performance_->stop(performance::Callback::beforeNewRun, i_proc);
465 }
466 }
467 if (performance_) performance_->stop(performance::Callback::beforeNewRun, 0);
468 // now run header has been modified by Producers,
469 // it is valid to read from for everyone else in 'onNewRun'
470 if (performance_) performance_->start(performance::Callback::onNewRun, 0);
471 conditions_.onNewRun(header);
472 i_proc = 0;
473 for (auto module : sequence_) {
474 i_proc++;
475 if (performance_)
476 performance_->start(performance::Callback::onNewRun, i_proc);
477 module->onNewRun(header);
478 if (performance_)
479 performance_->stop(performance::Callback::onNewRun, i_proc);
480 }
481 if (performance_) performance_->stop(performance::Callback::onNewRun, 0);
482}
483
484bool Process::process(int n, int n_try, Event &event) const {
485 if ((logFrequency_ != -1) && ((n + 1) % logFrequency_ == 0) && (n_try < 2)) {
486 // only printout event counter if we've enabled log frequency, the event
487 // matches the frequency and we are on the first try
488 TTimeStamp t;
489 ldmx_log(info) << "Processing " << n + 1 << " Run "
490 << event.getEventHeader().getRun() << " Event "
491 << event.getEventHeader().getEventNumber() << " ("
492 << t.AsString("lc") << ")";
493 }
494
495 if (performance_) performance_->start(performance::Callback::process, 0);
496 std::size_t i_proc{0};
497 try {
498 for (auto module : sequence_) {
499 i_proc++;
500 if (performance_)
501 performance_->start(performance::Callback::process, i_proc);
502 if (dynamic_cast<Producer *>(module)) {
503 (dynamic_cast<Producer *>(module))->produce(event);
504 } else if (dynamic_cast<Analyzer *>(module)) {
505 (dynamic_cast<Analyzer *>(module))->analyze(event);
506 }
507 if (performance_)
508 performance_->stop(performance::Callback::process, i_proc);
509 }
510 } catch (AbortEventException &) {
511 if (performance_) {
512 performance_->stop(performance::Callback::process, i_proc);
513 performance_->stop(performance::Callback::process, 0);
514 performance_->end_event(false);
515 }
516 return false;
517 }
518 if (performance_) {
519 performance_->stop(performance::Callback::process, 0);
520 performance_->end_event(true);
521 }
522 return true;
523}
524
526 if (performance_) performance_->start(performance::Callback::onFileOpen, 0);
527 std::size_t i_proc{0};
528 for (auto module : sequence_) {
529 i_proc++;
530 if (performance_)
531 performance_->start(performance::Callback::onFileOpen, i_proc);
532 module->onFileOpen(file);
533 if (performance_)
534 performance_->stop(performance::Callback::onFileOpen, i_proc);
535 }
536 if (performance_) performance_->stop(performance::Callback::onFileOpen, 0);
537}
538
540 if (performance_) performance_->start(performance::Callback::onFileClose, 0);
541 std::size_t i_proc{0};
542 for (auto module : sequence_) {
543 i_proc++;
544 if (performance_)
545 performance_->start(performance::Callback::onFileClose, i_proc);
546 module->onFileClose(file);
547 if (performance_)
548 performance_->stop(performance::Callback::onFileClose, i_proc);
549 }
550 if (performance_) performance_->stop(performance::Callback::onFileClose, 0);
551}
552
553} // namespace framework
Base classes for all user event processing components to extend.
Class implementing an event buffer system for storing event data.
Class which provides a singleton module factory that creates EventProcessor objects.
Class which represents the process under execution.
Specific exception used to abort an event.
Base class for a module which does not produce a data product.
void onProcessStart()
Calls onProcessStart for all ConditionsObjectProviders.
void onNewRun(ldmx::RunHeader &)
Calls onNewRun for all ConditionsObjectProviders.
void createConditionsObjectProvider(const std::string &classname, const std::string &instancename, const std::string &tagname, const framework::config::Parameters &params)
Create a ConditionsObjectProvider given the information.
This class manages all ROOT file input/output operations.
Definition EventFile.h:26
void updateParent(EventFile *parent)
Change pointer to different parent file.
const std::string & getFileName()
Definition EventFile.h:258
void addDrop(const std::string &rule)
Add a rule for dropping collections from the output.
void setupEvent(Event *evt)
Set an Event object containing the event data to work with this file.
void writeRunTree()
Write the map of run headers to the file as a TTree of RunHeader.
bool nextEvent(bool storeCurrentEvent=true)
Prepare the next event.
ldmx::RunHeader * getRunHeaderPtr(int runNumber)
Update the RunHeader for a given run, if it exists in the input file.
void writeRunHeader(ldmx::RunHeader &runHeader)
Write the run header into the run map.
bool isCorrupted() const
Check if the file we have is corrupted.
Base class for all event processing components.
virtual void configure(framework::config::Parameters &parameters)
Callback for the EventProcessor to configure itself from the given set of parameters.
void createHistograms(const std::vector< framework::config::Parameters > &histos)
Internal function which is used to create histograms passed from the python configuration @parma hist...
TDirectory * getHistoDirectory()
Access/create a directory in the histogram file for this event processor to create histograms and ana...
Implements an event buffer system for storing event data.
Definition Event.h:41
int getEventNumber() const
Get the event number.
Definition Event.h:70
void onEndOfFile()
Perform end of file action.
Definition Event.cxx:172
ldmx::EventHeader & getEventHeader()
Get the event header.
Definition Event.h:58
const ldmx::EventHeader * getEventHeaderPtr()
Get the event header as a pointer.
Definition Event.h:64
void clear()
Reset all of the variables to their limits.
static NtupleManager & getInstance()
void reset()
Reset NtupleManager to blank state.
EventProcessor * createEventProcessor(const std::string &classname, const std::string &moduleInstanceName, Process &process)
Make an event processor.
static PluginFactory & getInstance()
Get the factory instance.
std::vector< EventProcessor * > sequence_
Ordered list of EventProcessors to execute.
Definition Process.h:197
std::vector< std::string > outputFiles_
List of output file names.
Definition Process.h:207
ldmx::RunHeader * runHeader_
Pointer to the current RunHeader, used for Conditions information.
Definition Process.h:231
bool skipCorruptedInputFiles_
allow the Process to skip input files that are corrupted
Definition Process.h:191
std::vector< std::string > dropKeepRules_
Set of drop/keep rules.
Definition Process.h:219
void run()
Run the process.
Definition Process.cxx:140
void newRun(ldmx::RunHeader &header)
Run through the processors and let them know that we are starting a new run.
Definition Process.cxx:452
std::string histoFilename_
Filename for histograms and other user products.
Definition Process.h:225
StorageControl storageController_
Storage controller.
Definition Process.h:194
TDirectory * openHistoFile()
Open a ROOT TFile to write histograms and TTrees.
Definition Process.cxx:431
int totalEvents_
Number of events we'd like to produce independetly of the number of tries it would take.
Definition Process.h:180
int maxTries_
Maximum number of attempts to make before giving up on an event.
Definition Process.h:186
~Process()
Class Destructor.
Definition Process.cxx:126
void onFileClose(EventFile &file) const
File is begin closed.
Definition Process.cxx:539
std::vector< std::string > inputFiles_
List of input files to process.
Definition Process.h:204
TDirectory * makeHistoDirectory(const std::string &dirName)
Construct a TDirectory* for the given module.
Definition Process.cxx:424
std::string passname_
Processing pass name.
Definition Process.h:172
performance::Tracker * performance_
class with calls backs to track performance measurements of software
Definition Process.h:237
const ldmx::EventHeader * eventHeader_
Pointer to the current EventHeader, used for Conditions information.
Definition Process.h:228
int compressionSetting_
Compression setting to pass to output files.
Definition Process.h:216
bool process(int n, int n_tries, Event &event) const
Process the input event through the sequence of processors.
Definition Process.cxx:484
int logFrequency_
The frequency with which event info is printed.
Definition Process.h:183
int runForGeneration_
Run number to use if generating events.
Definition Process.h:222
Process()
Private dummy constructor We hide it here because it shouldn't be used anywhere else.
Definition Process.h:133
void onFileOpen(EventFile &file) const
File is being opened.
Definition Process.cxx:525
Conditions conditions_
Set of ConditionsProviders.
Definition Process.h:200
int eventLimit_
Limit on events to process.
Definition Process.h:175
int getRunNumber() const
Get the current run number or the run number to be used when initiating new events from the job.
Definition Process.cxx:420
framework::config::Parameters config_
The parameters used to configure this class.
Definition Process.h:169
TFile * histoTFile_
TFile for histograms and other user products.
Definition Process.h:234
Base class for a module which produces a data product.
void setDefaultKeep(bool keep)
Set the default state.
bool keepEvent(bool event_completed) const
Determine if the current event should be kept, based on the defined rules.
void addRule(const std::string &processor_pat, const std::string &purpose_pat)
Add a listening rule.
void resetEventState()
Reset the event-by-event state.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:27
T getParameter(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:89
static void set(int n)
set the event number in the current Formatter
Definition Logger.cxx:160
Class to interface between framework::Process and various measurements that can eventually be written...
Definition Tracker.h:20
void start(Callback cb, std::size_t i_proc)
start the timer for a specific callback and specific processor
Definition Tracker.cxx:90
void end_event(bool completed)
inform us that we finished an event (and whether it was completed or not)
Definition Tracker.cxx:98
void stop(Callback cb, std::size_t i_proc)
stop the timer for a specific callback and specific processor
Definition Tracker.cxx:94
void absolute_start()
literally first line of Process::run
Definition Tracker.cxx:86
void absolute_stop()
literally last line of Process::run (if run compeletes without error)
Definition Tracker.cxx:88
Provides header information an event such as event number and timestamp.
Definition EventHeader.h:44
int getRun() const
Return the run number.
Definition EventHeader.h:84
void setEventNumber(int eventNumber)
Set the event number.
void setRun(int run)
Set the run number.
void setTimestamp(const TTimeStamp &timestamp)
Set the timestamp.
Run-specific configuration and data stored in its own output TTree alongside the event TTree in the o...
Definition RunHeader.h:54
void setRunEnd(const int runEnd)
Set the end time of the run in seconds since epoch.
Definition RunHeader.h:121
void setRunStart(const int runStart)
Set the run start time in seconds since epoch.
Definition RunHeader.h:107
void setNumTries(const int numTries)
Set the total number of tries that were done during the production of this run.
Definition RunHeader.h:141
All classes in the ldmx-sw project use this namespace.
Definition PerfDict.cxx:45