eventDispenser
Loading...
Searching...
No Matches
eventDispenser.cc
Go to the documentation of this file.
1// Implements EventDispenser: run-weight parsing, event distribution, and per-run dispatch through Geant4.
2//
3// Doxygen documentation for the public API is maintained in eventDispenser.h.
4// This implementation file keeps only short, non-Doxygen summaries and inline clarifying comments.
5
8#include "eventDispenser.h"
10
11// c++
12#include <fstream>
13#include <random>
14#include <utility>
15
16// geant4
17#include "G4UImanager.hh"
18
19using namespace std;
20
21// Constructor summary:
22// - Reads configuration (number of events, run number, optional run-weight file).
23// - Builds runWeights/runEvents/listOfRuns when weights are provided.
24// - Otherwise, falls back to single-run mode.
25EventDispenser::EventDispenser(const std::shared_ptr<GOptions>& gopt,
26 const std::shared_ptr<const gdynamicdigitization::dRoutinesMap>& gdynamicDigitizationMap)
27 : GBase(gopt, EVENTDISPENSER_LOGGER), gDigitizationMap(gdynamicDigitizationMap) {
28 // Retrieve configuration parameters from GOptions.
29 string filename = gopt->getScalarString("run_weights");
30 userRunno = gopt->getScalarInt("run");
31 neventsToProcess = gopt->getScalarInt("n");
32
33 // If there are no events to process, keep the object in an initialized-but-idle state.
34 if (neventsToProcess == 0) return;
35
36 // If no file is provided, use the user-specified run number (single-run mode).
37 if (filename == UNINITIALIZEDSTRINGQUANTITY && neventsToProcess > 0) {
38 runEvents[userRunno] = neventsToProcess;
39 return;
40 }
41 else {
42 // Multi-run mode: a filename was specified; attempt to open the run weights input file.
43 ifstream in(filename.c_str());
44 if (!in) {
45 // Keep behavior unchanged: log error and continue with an empty distribution.
47 "Error: can't open run weights input file >", filename, "<. Check your spelling. Exiting.");
48 }
49 else {
50 log->info(1, "Loading run weights from ", filename);
51
52 // Read "run weight" pairs, one per line.
53 // The order of insertion into listOfRuns reflects the file order and may be used by clients.
54 int run;
55 double weight;
56 while (in >> run >> weight) {
57 listOfRuns.push_back(run);
58 runWeights[run] = weight;
59 runEvents[run] = 0; // initialize per-run counters before distribution
60 }
61
62 // Distribute the total number of events among runs according to their weights.
63 distributeEvents(neventsToProcess);
64 }
65 in.close();
66
67 // Log summary information: overall distribution table.
68 log->info(0, "EventDispenser initialized with ", neventsToProcess, " events distributed among ",
69 runWeights.size(), " runs:");
70 log->info(0, " run\t weight\t n. events");
71 for (const auto& weight : runWeights) {
72 log->info(0, " ", weight.first, "\t ", weight.second, "\t ", runEvents[weight.first]);
73 }
74 }
75}
76
77
78// setNumberOfEvents summary:
79// - Clears any existing distribution and assigns all events to the user-selected run number.
80void EventDispenser::setNumberOfEvents(int nevents_to_process) {
81 runEvents.clear();
82 runEvents[userRunno] = nevents_to_process;
83}
84
85
86// distributeEvents summary:
87// - Performs stochastic sampling to convert runWeights into integer runEvents counts.
88void EventDispenser::distributeEvents(int nevents_to_process) {
89 // Set up a random number generator drawing from U[0, 1].
90 random_device randomDevice;
91 mt19937 generator(randomDevice());
92 uniform_real_distribution<> randomDistribution(0, 1);
93
94 // For each event, select a run by comparing a random draw to the cumulative weight intervals.
95 // This assumes runWeights values represent fractions or relative weights normalized to sum to 1.
96 for (int i = 0; i < nevents_to_process; i++) {
97 double randomNumber = randomDistribution(generator);
98
99 double cumulativeWeight = 0;
100 for (const auto& weight : runWeights) {
101 cumulativeWeight += weight.second;
102 if (randomNumber <= cumulativeWeight) {
103 runEvents[weight.first]++;
104 break;
105 }
106 }
107 }
108}
109
110
111// getTotalNumberOfEvents summary:
112// - Sums all per-run event counts from runEvents.
114 int totalEvents = 0;
115 for (auto rEvents : runEvents) { totalEvents += rEvents.second; }
116 return totalEvents;
117}
118
119
120// processEvents summary:
121// - Iterates the run allocation.
122// - For each run, loads run-dependent constants/TT via digitization routines (if run changed).
123// - Dispatches the events to Geant4 via \c /run/beamOn.
125 // Get the Geant4 UI manager pointer used to apply macro commands.
126 G4UImanager* g4uim = G4UImanager::GetUIpointer();
127
128 // Iterate over each run in the run events map.
129 for (auto& run : runEvents) {
130 int runNumber = run.first;
131 int nevents = run.second;
132
133 // Load constants and translation tables if the run number has changed.
134 if (runNumber != currentRunno) {
135 // Iterate the (plugin name -> digitization routine) map.
136 // digiRoutine is a std::shared_ptr<GDynamicDigitization>.
137 for (const auto& [plugin, digiRoutine] : *gDigitizationMap) {
138 log->debug(NORMAL, FUNCTION_NAME, "Calling ", plugin, " loadConstants for run ", runNumber);
139 if (digiRoutine->loadConstants(runNumber, variation) == false) {
141 "Failed to load constants for ", plugin, " for run ", runNumber, " with variation ",
142 variation);
143 }
144
145 log->debug(NORMAL, FUNCTION_NAME, "Calling ", plugin, " loadTT for run ", runNumber);
146 if (digiRoutine->loadTT(runNumber, variation) == false) {
148 "Failed to load translation table for ", plugin, " for run ", runNumber,
149 " with variation ", variation);
150 }
151 }
152 currentRunno = runNumber;
153 }
154
155 log->info(1, "Starting run ", runNumber, " with ", nevents, " events.");
156
157 // Dispatch all events for this run in a single call.
158 // The command string is a standard Geant4 UI command: \c /run/beamOn <N>.
159 log->info(1, "Processing ", nevents, " events in one go");
160 g4uim->ApplyCommand("/run/beamOn " + to_string(nevents));
161
162 log->info(1, "Run ", runNumber, " done with ", nevents, " events");
163 }
164
165 return 1;
166}
int processEvents()
Processes all runs by initializing digitization routines and dispatching events.
EventDispenser(const std::shared_ptr< GOptions > &gopt, const std::shared_ptr< const gdynamicdigitization::dRoutinesMap > &gdynamicDigitizationMap)
Constructs an EventDispenser and prepares the run event distribution.
void setNumberOfEvents(int nevts)
Sets the total number of events to process in single-run mode.
int getTotalNumberOfEvents() const
Computes the total number of events across all runs.
std::shared_ptr< GLogger > log
void debug(debug_type type, Args &&... args) const
void info(int level, Args &&... args) const
void error(int exit_code, Args &&... args) const
Event Dispenser module error-code conventions.
#define ERR_EVENTDISTRIBUTIONFILENOTFOUND
Run-weight file could not be opened/read.
Declares the EventDispenser class.
Public declaration of the Event Dispenser module command-line / configuration options.
constexpr const char * EVENTDISPENSER_LOGGER
Logger name used by this module when creating a GLogger through the base infrastructure.
constexpr int ERR_LOADCONSTANTFAIL
constexpr int ERR_LOADTTFAIL
#define FUNCTION_NAME
NORMAL
#define UNINITIALIZEDSTRINGQUANTITY
constexpr const char * to_string(randomModel m) noexcept