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