gdata
Loading...
Searching...
No Matches
event_example.cc
Go to the documentation of this file.
1
65// gdata
66#include "event/gEventDataCollection.h" // explicit include for clarity in the example
67
68// gemc
69#include "glogger.h"
70#include "gthreads.h"
71
72// C++
73#include <atomic>
74#include <cstdlib>
75#include <map>
76#include <mutex>
77#include <sstream>
78#include <string>
79#include <vector>
80
95template <typename MapType>
96static std::string map_to_string(const MapType& m) {
97 std::ostringstream os;
98 os << "{";
99 bool first = true;
100 for (const auto& [k, v] : m) {
101 if (!first) os << ", ";
102 first = false;
103 os << k << "=" << v;
104 }
105 os << "}";
106 return os.str();
107}
108
125static void dump_event(const std::shared_ptr<GEventDataCollection>& edc, const std::shared_ptr<GLogger>& log) {
126 log->info(0, "------------------------------------------------------------");
127 log->info(0, "Dumping event: local event number = ", edc->getEventNumber());
128 log->info(0, "------------------------------------------------------------");
129
130 const auto& dcm = edc->getDataCollectionMap();
131 if (dcm.empty()) {
132 log->info(0, "Event contains no detector data.");
133 return;
134 }
135
136 for (const auto& [sdName, det] : dcm) {
137 if (!det) {
138 log->info(0, "Detector <", sdName, "> has a null GDataCollection pointer (unexpected).");
139 continue;
140 }
141
142 const auto& truthHits = det->getTrueInfoData();
143 const auto& digiHits = det->getDigitizedData();
144
145 log->info(0, "Detector <", sdName, ">: truthHits=", truthHits.size(), " digitizedHits=", digiHits.size());
146
147 // ---- Truth hits
148 for (size_t i = 0; i < truthHits.size(); ++i) {
149 const auto& th = truthHits[i];
150 if (!th) continue;
151
152 const auto doubles = th->getDoubleVariablesMap();
153 const auto strings = th->getStringVariablesMap();
154
155 log->info(0, " [truth hit ", i, "] id={", th->getIdentityString(), "}");
156 log->info(0, " doubles: ", map_to_string(doubles));
157
158 // Strings are often empty in this toy factory, but the code shows how to inspect them.
159 if (!strings.empty()) {
160 log->info(0, " strings: ", map_to_string(strings));
161 }
162 else {
163 log->info(0, " strings: {} (none)");
164 }
165 }
166
167 // ---- Digitized hits
168 for (size_t i = 0; i < digiHits.size(); ++i) {
169 const auto& dh = digiHits[i];
170 if (!dh) continue;
171
172 const auto ints_non_sro = dh->getIntObservablesMap(0);
173 const auto ints_sro = dh->getIntObservablesMap(1);
174 const auto dbls_non_sro = dh->getDblObservablesMap(0);
175 const auto dbls_sro_only = dh->getDblObservablesMap(1);
176
177 log->info(0, " [digi hit ", i, "] id={", dh->getIdentityString(), "}");
178 log->info(0, " int non-SRO: ", map_to_string(ints_non_sro));
179 log->info(0, " int SRO: ", map_to_string(ints_sro));
180 log->info(0, " dbl non-SRO: ", map_to_string(dbls_non_sro));
181 log->info(0, " dbl SRO: ", map_to_string(dbls_sro_only));
182
183 // Convenience accessor demo (shows sentinel if missing).
184 log->info(0, " timeAtElectronics() = ", dh->getTimeAtElectronics());
185 }
186 }
187}
188
203static void validate_event_structure(const std::shared_ptr<GEventDataCollection>& edc,
204 const std::shared_ptr<GLogger>& log) {
205 const auto& dcm = edc->getDataCollectionMap();
206 if (dcm.empty()) {
207 log->info(0, "VALIDATION: event ", edc->getEventNumber(), " has no detectors (unexpected in this example).");
208 return;
209 }
210
211 for (const auto& [sdName, det] : dcm) {
212 if (!det) {
213 log->info(0, "VALIDATION: detector <", sdName, "> has null GDataCollection pointer.");
214 continue;
215 }
216
217 const auto& truthHits = det->getTrueInfoData();
218 const auto& digiHits = det->getDigitizedData();
219
220 for (size_t i = 0; i < truthHits.size(); ++i) {
221 if (!truthHits[i]) log->info(0, "VALIDATION: detector <", sdName, "> truth hit ", i, " is null.");
222 }
223 for (size_t i = 0; i < digiHits.size(); ++i) {
224 if (!digiHits[i]) log->info(0, "VALIDATION: detector <", sdName, "> digitized hit ", i, " is null.");
225 }
226
227 // A common expectation in production is matching truth and digitized hit counts per detector.
228 // This is not enforced by the API (you can add one without the other), but it is a useful
229 // consistency check for this demo-style producer.
230 if (truthHits.size() != digiHits.size()) {
231 log->info(0, "VALIDATION: detector <", sdName, "> truthHits(", truthHits.size(),
232 ") != digitizedHits(", digiHits.size(), ") in event ", edc->getEventNumber());
233 }
234 }
235}
236
251static auto run_simulation_in_threads(int nevents,
252 int nthreads,
253 const std::shared_ptr<GOptions>& gopt,
254 const std::shared_ptr<GLogger>& log)
255 -> std::vector<std::shared_ptr<GEventDataCollection>> {
256 std::mutex collectorMtx;
257 std::vector<std::shared_ptr<GEventDataCollection>> collected;
258 collected.reserve(static_cast<size_t>(nevents));
259
260 // Thread-safe integer event counter starts at 1 (local to this example run).
261 std::atomic<int> next{1};
262
263 // Pool of threads. (jthread_alias joins on destruction.)
264 std::vector<jthread_alias> pool;
265 pool.reserve(nthreads);
266
267 for (int tid = 0; tid < nthreads; ++tid) {
268 pool.emplace_back([&, tid] {
269 log->info(0, "worker ", tid, " started");
270
271 int localCount = 0;
272
273 // Thread-local staging buffer to reduce lock contention on the shared vector.
274 thread_local std::vector<std::shared_ptr<GEventDataCollection>> localEvents;
275 localEvents.clear();
276
277 while (true) {
278 int evn = next.fetch_add(1, std::memory_order_relaxed);
279 if (evn > nevents) { break; }
280
281 // Create one event container (factory inserts one dummy hit for detector "ctof").
282 auto edc = GEventDataCollection::create(gopt);
283
284 // ---- Extend the event with extra content to exercise the API more thoroughly.
285
286 // (1) Add a second hit under the existing detector ("ctof").
287 edc->addDetectorDigitizedData("ctof", GDigitizedData::create(gopt));
288 edc->addDetectorTrueInfoData("ctof", GTrueInfoData::create(gopt));
289
290 // (2) Add a second detector key ("ec") with one hit.
291 edc->addDetectorDigitizedData("ec", GDigitizedData::create(gopt));
292 edc->addDetectorTrueInfoData("ec", GTrueInfoData::create(gopt));
293
294 localEvents.emplace_back(edc);
295 ++localCount;
296 }
297
298 {
299 std::scoped_lock lk(collectorMtx);
300 for (auto& evt : localEvents) { collected.emplace_back(evt); }
301 localEvents.clear();
302 }
303
304 log->info(0, "worker ", tid, " processed ", localCount, " events");
305 });
306 }
307
308 return collected;
309}
310
311int main(int argc, char* argv[]) {
312 // Aggregate options for event-level data collection.
313 auto gopts = std::make_shared<GOptions>(argc, argv, gevent_data::defineOptions());
314
315 // Event-data logger (domain: GEVENTDATA_LOGGER).
316 auto log = std::make_shared<GLogger>(gopts, SFUNCTION_NAME, GEVENTDATA_LOGGER);
317
318 // Keep these small by default so the example output remains readable.
319 constexpr int nevents = 5;
320 constexpr int nthreads = 4;
321
322 auto events = run_simulation_in_threads(nevents, nthreads, gopts, log);
323
324 // Demonstration: inspect and validate each event container.
325 for (const auto& edc : events) {
326 if (!edc) continue;
327 validate_event_structure(edc, log);
328 dump_event(edc, log);
329 }
330
331 log->info(0, "Generated ", events.size(), " event containers.");
332
333 return EXIT_SUCCESS;
334}
335
static std::unique_ptr< GDigitizedData > create(const std::shared_ptr< GOptions > &gopts)
Test/example factory: create a digitized hit with deterministic dummy data.
static auto create(const std::shared_ptr< GOptions > &gopts) -> std::shared_ptr< GEventDataCollection >
Test/example factory: create an event collection with one dummy hit for "ctof".
static std::unique_ptr< GTrueInfoData > create(const std::shared_ptr< GOptions > &gopts)
Test/example factory: create a true-hit object with deterministic dummy data.
Defines GEventDataCollection, event-level aggregation of per-detector hit data.
constexpr const char * GEVENTDATA_LOGGER
#define SFUNCTION_NAME
auto defineOptions() -> GOptions
Aggregated options for event-level data collection.
auto run_simulation_in_threads(int nevents, int nthreads, const std::shared_ptr< GOptions > &gopt, const std::shared_ptr< GLogger > &log, const std::shared_ptr< const gdynamicdigitization::dRoutinesMap > &dynamicRoutinesMap) -> std::vector< std::unique_ptr< GEventDataCollection > >
int main(int argc, char *argv[])