gdata
Loading...
Searching...
No Matches
event_example.cc
Go to the documentation of this file.
1
71// gdata
72#include "event/gEventDataCollection.h" // Explicit include for the example entry point.
73
74// gemc
75#include "glogger.h"
76#include "gthreads.h"
77
78// C++
79#include <atomic>
80#include <cstdlib>
81#include <map>
82#include <mutex>
83#include <sstream>
84#include <string>
85#include <vector>
86
101template <typename MapType>
102static std::string map_to_string(const MapType& m) {
103 std::ostringstream os;
104 os << "{";
105 bool first = true;
106 for (const auto& [k, v] : m) {
107 if (!first) os << ", ";
108 first = false;
109 os << k << "=" << v;
110 }
111 os << "}";
112 return os.str();
113}
114
134static void dump_event(const std::shared_ptr<GEventDataCollection>& edc, const std::shared_ptr<GLogger>& log) {
135 log->info(0, "------------------------------------------------------------");
136 log->info(0, "Dumping event: local event number = ", edc->getEventNumber());
137 log->info(0, "------------------------------------------------------------");
138
139 const auto& dcm = edc->getDataCollectionMap();
140 if (dcm.empty()) {
141 log->info(0, "Event contains no detector data.");
142 return;
143 }
144
145 for (const auto& [sdName, det] : dcm) {
146 if (!det) {
147 log->info(0, "Detector <", sdName, "> has a null GDataCollection pointer (unexpected).");
148 continue;
149 }
150
151 const auto& truthHits = det->getTrueInfoData();
152 const auto& digiHits = det->getDigitizedData();
153
154 log->info(0, "Detector <", sdName, ">: truthHits=", truthHits.size(), " digitizedHits=", digiHits.size());
155
156 // Truth hits are printed first so the example shows the simulation-side view before the readout-side view.
157 for (size_t i = 0; i < truthHits.size(); ++i) {
158 const auto& th = truthHits[i];
159 if (!th) continue;
160
161 const auto doubles = th->getDoubleVariablesMap();
162 const auto strings = th->getStringVariablesMap();
163
164 auto idString = getIdentityString(th->getIdentity());
165
166 log->info(0, " [truth hit ", i, "] id={",idString, "}");
167 log->info(0, " doubles: ", map_to_string(doubles));
168
169 // Strings are often empty in this toy factory, but the code shows how to inspect them.
170 if (!strings.empty()) {
171 log->info(0, " strings: ", map_to_string(strings));
172 }
173 else {
174 log->info(0, " strings: {} (none)");
175 }
176 }
177
178 // Digitized hits are printed with both SRO and non-SRO filtered views.
179 for (size_t i = 0; i < digiHits.size(); ++i) {
180 const auto& dh = digiHits[i];
181 if (!dh) continue;
182
183 const auto ints_non_sro = dh->getIntObservablesMap(0);
184 const auto ints_sro = dh->getIntObservablesMap(1);
185 const auto dbls_non_sro = dh->getDblObservablesMap(0);
186 const auto dbls_sro_only = dh->getDblObservablesMap(1);
187
188 auto idString = getIdentityString(dh->getIdentity());
189
190 log->info(0, " [digi hit ", i, "] id={",idString, "}");
191 log->info(0, " int non-SRO: ", map_to_string(ints_non_sro));
192 log->info(0, " int SRO: ", map_to_string(ints_sro));
193 log->info(0, " dbl non-SRO: ", map_to_string(dbls_non_sro));
194 log->info(0, " dbl SRO: ", map_to_string(dbls_sro_only));
195
196 // Demonstrate the convenience accessor for one common SRO quantity.
197 log->info(0, " timeAtElectronics() = ", dh->getTimeAtElectronics());
198 }
199 }
200}
201
217static void validate_event_structure(const std::shared_ptr<GEventDataCollection>& edc,
218 const std::shared_ptr<GLogger>& log) {
219 const auto& dcm = edc->getDataCollectionMap();
220 if (dcm.empty()) {
221 log->info(0, "VALIDATION: event ", edc->getEventNumber(), " has no detectors (unexpected in this example).");
222 return;
223 }
224
225 for (const auto& [sdName, det] : dcm) {
226 if (!det) {
227 log->info(0, "VALIDATION: detector <", sdName, "> has null GDataCollection pointer.");
228 continue;
229 }
230
231 const auto& truthHits = det->getTrueInfoData();
232 const auto& digiHits = det->getDigitizedData();
233
234 for (size_t i = 0; i < truthHits.size(); ++i) {
235 if (!truthHits[i]) log->info(0, "VALIDATION: detector <", sdName, "> truth hit ", i, " is null.");
236 }
237 for (size_t i = 0; i < digiHits.size(); ++i) {
238 if (!digiHits[i]) log->info(0, "VALIDATION: detector <", sdName, "> digitized hit ", i, " is null.");
239 }
240
241 // Matching truth and digitized counts are often expected by example producers, even though the API allows them to differ.
242 if (truthHits.size() != digiHits.size()) {
243 log->info(0, "VALIDATION: detector <", sdName, "> truthHits(", truthHits.size(),
244 ") != digitizedHits(", digiHits.size(), ") in event ", edc->getEventNumber());
245 }
246 }
247}
248
267static auto run_simulation_in_threads(int nevents,
268 int nthreads,
269 const std::shared_ptr<GOptions>& gopt,
270 const std::shared_ptr<GLogger>& log)
271 -> std::vector<std::shared_ptr<GEventDataCollection>> {
272 std::mutex collectorMtx;
273 std::vector<std::shared_ptr<GEventDataCollection>> collected;
274 collected.reserve(static_cast<size_t>(nevents));
275
276 // Thread-safe event counter local to this example run.
277 std::atomic<int> next{1};
278
279 // Thread pool. The alias joins on destruction.
280 std::vector<jthread_alias> pool;
281 pool.reserve(nthreads);
282
283 for (int tid = 0; tid < nthreads; ++tid) {
284 pool.emplace_back([&, tid] {
285 log->info(0, "worker ", tid, " started");
286
287 int localCount = 0;
288
289 // Thread-local staging buffer reduces lock contention on the shared collector vector.
290 thread_local std::vector<std::shared_ptr<GEventDataCollection>> localEvents;
291 localEvents.clear();
292
293 while (true) {
294 int evn = next.fetch_add(1, std::memory_order_relaxed);
295 if (evn > nevents) { break; }
296
297 // Create one event container. The factory inserts one dummy hit for detector "ctof".
298 auto edc = GEventDataCollection::create(gopt);
299
300 // Extend the event so the example exercises more than the minimal factory path.
301
302 // Add a second hit under the existing detector key.
303 edc->addDetectorDigitizedData("ctof", GDigitizedData::create(gopt));
304 edc->addDetectorTrueInfoData("ctof", GTrueInfoData::create(gopt));
305
306 // Add a second detector with one hit pair.
307 edc->addDetectorDigitizedData("ec", GDigitizedData::create(gopt));
308 edc->addDetectorTrueInfoData("ec", GTrueInfoData::create(gopt));
309
310 localEvents.emplace_back(edc);
311 ++localCount;
312 }
313
314 {
315 std::scoped_lock lk(collectorMtx);
316 for (auto& evt : localEvents) { collected.emplace_back(evt); }
317 localEvents.clear();
318 }
319
320 log->info(0, "worker ", tid, " processed ", localCount, " events");
321 });
322 }
323
324 return collected;
325}
326
344int main(int argc, char* argv[]) {
345 // Aggregate options for event-level data collection.
346 auto gopts = std::make_shared<GOptions>(argc, argv, gevent_data::defineOptions());
347
348 // Event-data logger.
349 auto log = std::make_shared<GLogger>(gopts, SFUNCTION_NAME, GEVENTDATA_LOGGER);
350
351 // Keep these small by default so the example output remains readable.
352 constexpr int nevents = 5;
353 constexpr int nthreads = 4;
354
355 auto events = run_simulation_in_threads(nevents, nthreads, gopts, log);
356
357 // Inspect and validate each generated event container.
358 for (const auto& edc : events) {
359 if (!edc) continue;
360 validate_event_structure(edc, log);
361 dump_event(edc, log);
362 }
363
364 log->info(0, "Generated ", events.size(), " event containers.");
365
366 return EXIT_SUCCESS;
367}
368
371
static std::unique_ptr< GDigitizedData > create(const std::shared_ptr< GOptions > &gopts)
Creates deterministic example data for tests and examples.
static auto create(const std::shared_ptr< GOptions > &gopts) -> std::shared_ptr< GEventDataCollection >
Creates a minimal example event containing one detector entry and one hit pair.
static std::unique_ptr< GTrueInfoData > create(const std::shared_ptr< GOptions > &gopts)
Creates deterministic example data for tests and examples.
Defines GEventDataCollection, the event-level aggregation of detector hit data.
constexpr const char * GEVENTDATA_LOGGER
std::string getIdentityString(std::vector< GIdentifier > gidentity)
#define SFUNCTION_NAME
auto defineOptions() -> GOptions
Aggregates the option groups needed by event-level data containers.
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[])