gdata
Loading...
Searching...
No Matches
event_example.cc
Go to the documentation of this file.
1
15
36
70
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 const auto electronicsTime = dh->getTimeAtElectronics();
198 log->info(0, " timeAtElectronics() = ",
199 electronicsTime ? std::to_string(*electronicsTime) : "not available");
200 }
201 }
202}
203
219static void validate_event_structure(const std::shared_ptr<GEventDataCollection>& edc,
220 const std::shared_ptr<GLogger>& log) {
221 const auto& dcm = edc->getDataCollectionMap();
222 if (dcm.empty()) {
223 log->info(0, "VALIDATION: event ", edc->getEventNumber(), " has no detectors (unexpected in this example).");
224 return;
225 }
226
227 for (const auto& [sdName, det] : dcm) {
228 if (!det) {
229 log->info(0, "VALIDATION: detector <", sdName, "> has null GDataCollection pointer.");
230 continue;
231 }
232
233 const auto& truthHits = det->getTrueInfoData();
234 const auto& digiHits = det->getDigitizedData();
235
236 for (size_t i = 0; i < truthHits.size(); ++i) {
237 if (!truthHits[i]) log->info(0, "VALIDATION: detector <", sdName, "> truth hit ", i, " is null.");
238 }
239 for (size_t i = 0; i < digiHits.size(); ++i) {
240 if (!digiHits[i]) log->info(0, "VALIDATION: detector <", sdName, "> digitized hit ", i, " is null.");
241 }
242
243 // Matching truth and digitized counts are often expected by example producers, even though the API allows them to differ.
244 if (truthHits.size() != digiHits.size()) {
245 log->info(0, "VALIDATION: detector <", sdName, "> truthHits(", truthHits.size(),
246 ") != digitizedHits(", digiHits.size(), ") in event ", edc->getEventNumber());
247 }
248 }
249}
250
269static auto run_simulation_in_threads(int nevents,
270 int nthreads,
271 const std::shared_ptr<GOptions>& gopt,
272 const std::shared_ptr<GLogger>& log)
273 -> std::vector<std::shared_ptr<GEventDataCollection>> {
274 std::mutex collectorMtx;
275 std::vector<std::shared_ptr<GEventDataCollection>> collected;
276 collected.reserve(static_cast<size_t>(nevents));
277
278 // Thread-safe event counter local to this example run.
279 std::atomic<int> next{1};
280
281 // Thread pool. The alias joins on destruction.
282 std::vector<jthread_alias> pool;
283 pool.reserve(nthreads);
284
285 for (int tid = 0; tid < nthreads; ++tid) {
286 pool.emplace_back([&, tid] {
287 log->info(0, "worker ", tid, " started");
288
289 int localCount = 0;
290
291 // Thread-local staging buffer reduces lock contention on the shared collector vector.
292 thread_local std::vector<std::shared_ptr<GEventDataCollection>> localEvents;
293 localEvents.clear();
294
295 while (true) {
296 int evn = next.fetch_add(1, std::memory_order_relaxed);
297 if (evn > nevents) { break; }
298
299 // Create one event container. The factory inserts one dummy hit for detector "ctof".
300 auto edc = GEventDataCollection::create(gopt);
301
302 // Extend the event so the example exercises more than the minimal factory path.
303
304 // Add a second hit under the existing detector key.
305 edc->addDetectorDigitizedData("ctof", GDigitizedData::create(gopt));
306 edc->addDetectorTrueInfoData("ctof", GTrueInfoData::create(gopt));
307
308 // Add a second detector with one hit pair.
309 edc->addDetectorDigitizedData("ec", GDigitizedData::create(gopt));
310 edc->addDetectorTrueInfoData("ec", GTrueInfoData::create(gopt));
311
312 localEvents.emplace_back(edc);
313 ++localCount;
314 }
315
316 {
317 std::scoped_lock lk(collectorMtx);
318 for (auto& evt : localEvents) { collected.emplace_back(evt); }
319 localEvents.clear();
320 }
321
322 log->info(0, "worker ", tid, " processed ", localCount, " events");
323 });
324 }
325
326 return collected;
327}
328
346int main(int argc, char* argv[]) {
347 // Aggregate options for event-level data collection.
348 auto gopts = std::make_shared<GOptions>(argc, argv, gevent_data::defineOptions());
349
350 // Event-data logger.
351 auto log = std::make_shared<GLogger>(gopts, SFUNCTION_NAME, GEVENTDATA_LOGGER);
352
353 // Keep these small by default so the example output remains readable.
354 constexpr int nevents = 5;
355 constexpr int nthreads = 4;
356
357 auto events = run_simulation_in_threads(nevents, nthreads, gopts, log);
358
359 // Inspect and validate each generated event container.
360 for (const auto& edc : events) {
361 if (!edc) continue;
362 validate_event_structure(edc, log);
363 dump_event(edc, log);
364 }
365
366 log->info(0, "Generated ", events.size(), " event containers.");
367
368 return EXIT_SUCCESS;
369}
370
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[])