gdata
Loading...
Searching...
No Matches
run_example.cc
Go to the documentation of this file.
1
15
30
62
63// gdata
66
67// gemc
68#include "glogger.h"
69#include "gthreads.h"
70
71// C++
72#include <atomic>
73#include <cstdlib>
74#include <map>
75#include <mutex>
76#include <sstream>
77#include <string>
78#include <vector>
79
91template <typename MapType>
92static std::string map_to_string(const MapType& m) {
93 std::ostringstream os;
94 os << "{";
95 bool first = true;
96 for (const auto& [k, v] : m) {
97 if (!first) os << ", ";
98 first = false;
99 os << k << "=" << v;
100 }
101 os << "}";
102 return os.str();
103}
104
118using PerDetectorDoubles = std::map<std::string, std::map<std::string, double>>;
119
127using PerDetectorInts = std::map<std::string, std::map<std::string, long long>>;
128
144static auto generate_events_in_threads(int nevents,
145 int nthreads,
146 const std::shared_ptr<GOptions>& gopt,
147 const std::shared_ptr<GLogger>& log)
148 -> std::vector<std::shared_ptr<GEventDataCollection>> {
149 std::mutex collectorMtx;
150 std::vector<std::shared_ptr<GEventDataCollection>> collected;
151 collected.reserve(static_cast<size_t>(nevents));
152
153 std::atomic<int> next{1};
154
155 std::vector<jthread_alias> pool;
156 pool.reserve(nthreads);
157
158 for (int tid = 0; tid < nthreads; ++tid) {
159 pool.emplace_back([&, tid] {
160 log->info(0, "worker %1 started", tid);
161
162 int localCount = 0;
163 thread_local std::vector<std::shared_ptr<GEventDataCollection>> localEvents;
164 localEvents.clear();
165
166 while (true) {
167 int evn = next.fetch_add(1, std::memory_order_relaxed);
168 if (evn > nevents) break;
169
170 auto edc = GEventDataCollection::create(gopt);
171
172 // Extend the event so integration covers more than the minimal factory-generated content.
173 edc->addDetectorDigitizedData("ctof", GDigitizedData::create(gopt));
174 edc->addDetectorTrueInfoData("ctof", GTrueInfoData::create(gopt));
175
176 edc->addDetectorDigitizedData("ec", GDigitizedData::create(gopt));
177 edc->addDetectorTrueInfoData("ec", GTrueInfoData::create(gopt));
178
179 localEvents.emplace_back(edc);
180 ++localCount;
181 }
182
183 {
184 std::scoped_lock lk(collectorMtx);
185 for (auto& evt : localEvents) { collected.emplace_back(evt); }
186 localEvents.clear();
187 }
188
189 log->info(0, "worker %1 processed %2 events", tid, localCount);
190 });
191 }
192
193 return collected;
194}
195
214static void compute_reference_sums(const std::vector<std::shared_ptr<GEventDataCollection>>& events,
215 PerDetectorDoubles& truth_ref,
216 PerDetectorInts& digi_int_ref,
217 PerDetectorDoubles& digi_dbl_ref) {
218 for (const auto& edc : events) {
219 if (!edc) continue;
220
221 const auto& dcm = edc->getDataCollectionMap();
222 for (const auto& [sdName, det] : dcm) {
223 if (!det) continue;
224
225 // Truth-side accumulation: all numeric truth observables are summed directly.
226 for (const auto& th : det->getTrueInfoData()) {
227 if (!th) continue;
228 for (const auto& [k, v] : th->getDoubleVariablesMap()) {
229 truth_ref[sdName][k] += v;
230 }
231 }
232
233 // Digitized-side accumulation: only non-SRO observables are part of the reference sums.
234 for (const auto& dh : det->getDigitizedData()) {
235 if (!dh) continue;
236
237 for (const auto& [k, v] : dh->getIntObservablesMap(0)) {
238 digi_int_ref[sdName][k] += static_cast<long long>(v);
239 }
240 for (const auto& [k, v] : dh->getDblObservablesMap(0)) {
241 digi_dbl_ref[sdName][k] += v;
242 }
243 }
244 }
245 }
246}
247
259static auto integrate_into_run(const std::vector<std::shared_ptr<GEventDataCollection>>& events,
260 const std::shared_ptr<GOptions>& gopt)
261 -> std::shared_ptr<GRunDataCollection> {
262 auto grun_header = std::make_unique<GRunHeader>(gopt, 1); // Run id 1, thread id default -1.
263 auto run_data = std::make_shared<GRunDataCollection>(gopt, std::move(grun_header));
264
265 for (const auto& edc : events) {
266 if (!edc) continue;
267 run_data->collect_event_data_collection(edc);
268 }
269
270 return run_data;
271}
272
291static void validate_run_against_reference(const std::shared_ptr<GRunDataCollection>& run_data,
292 const PerDetectorDoubles& truth_ref,
293 const PerDetectorInts& digi_int_ref,
294 const PerDetectorDoubles& digi_dbl_ref,
295 const std::shared_ptr<GLogger>& log) {
296 log->info(0, "============================================================");
297 log->info(0, "RUN SUMMARY (integrated): runID=%1", run_data->getRunNumber());
298 log->info(0, "============================================================");
299
300 const auto& rmap = run_data->getDataCollectionMap();
301 if (rmap.empty()) {
302 log->info(0, "Run data map is empty (no detectors integrated).");
303 return;
304 }
305
306 for (const auto& [sdName, det] : rmap) {
307 if (!det) continue;
308
309 const auto& truthVec = det->getTrueInfoData();
310 const auto& digiVec = det->getDigitizedData();
311
312 log->info(
313 0, "Detector <%1>: integrated truth entries=%2 integrated digitized entries=%3", sdName,
314 truthVec.size(), digiVec.size());
315
316 // Truth integrated entry.
317 if (!truthVec.empty() && truthVec.front()) {
318 const auto integrated_truth = truthVec.front()->getDoubleVariablesMap();
319 log->info(0, " integrated truth doubles: %1", map_to_string(integrated_truth));
320
321 const auto it_ref_det = truth_ref.find(sdName);
322 if (it_ref_det != truth_ref.end()) {
323 for (const auto& [k, refv] : it_ref_det->second) {
324 const auto itv = integrated_truth.find(k);
325 const double got = (itv == integrated_truth.end()) ? 0.0 : itv->second;
326 if (got != refv) {
327 log->info(0, " MISMATCH truth <%1>::%2 got=%3 ref=%4", sdName, k, got, refv);
328 }
329 }
330 }
331 else {
332 log->info(0, " NOTE: no reference truth sums found for detector <%1>.", sdName);
333 }
334 }
335 else {
336 log->info(0, " integrated truth: <none>");
337 }
338
339 // Digitized integrated entry.
340 if (!digiVec.empty() && digiVec.front()) {
341 const auto ints_non_sro = digiVec.front()->getIntObservablesMap(0);
342 const auto dbls_non_sro = digiVec.front()->getDblObservablesMap(0);
343
344 log->info(0, " integrated digi int non-SRO: %1", map_to_string(ints_non_sro));
345 log->info(0, " integrated digi dbl non-SRO: %1", map_to_string(dbls_non_sro));
346
347 const auto ints_sro = digiVec.front()->getIntObservablesMap(1);
348 const auto dbls_sro = digiVec.front()->getDblObservablesMap(1);
349 log->info(0, " integrated digi int SRO: %1", map_to_string(ints_sro));
350 log->info(0, " integrated digi dbl SRO: %1", map_to_string(dbls_sro));
351
352 const auto it_int_ref_det = digi_int_ref.find(sdName);
353 if (it_int_ref_det != digi_int_ref.end()) {
354 for (const auto& [k, refv] : it_int_ref_det->second) {
355 const auto itv = ints_non_sro.find(k);
356 const long long got = (itv == ints_non_sro.end()) ? 0LL : static_cast<long long>(itv->second);
357 if (got != refv) {
358 log->info(0, " MISMATCH digi-int <%1>::%2 got=%3 ref=%4", sdName, k, got, refv);
359 }
360 }
361 }
362 else {
363 log->info(0, " NOTE: no reference digitized-int sums found for detector <%1>.", sdName);
364 }
365
366 const auto it_dbl_ref_det = digi_dbl_ref.find(sdName);
367 if (it_dbl_ref_det != digi_dbl_ref.end()) {
368 for (const auto& [k, refv] : it_dbl_ref_det->second) {
369 const auto itv = dbls_non_sro.find(k);
370 const double got = (itv == dbls_non_sro.end()) ? 0.0 : itv->second;
371 if (got != refv) {
372 log->info(0, " MISMATCH digi-dbl <%1>::%2 got=%3 ref=%4", sdName, k, got, refv);
373 }
374 }
375 }
376 else {
377 log->info(0, " NOTE: no reference digitized-double sums found for detector <%1>.", sdName);
378 }
379 }
380 else {
381 log->info(0, " integrated digitized: <none>");
382 }
383 }
384}
385
401int main(int argc, char* argv[]) {
402 auto gopts = std::make_shared<GOptions>(argc, argv, grun_data::defineOptions());
403 auto log = std::make_shared<GLogger>(gopts, SFUNCTION_NAME, GRUNDATA_LOGGER);
404
405 constexpr int nevents = 20;
406 constexpr int nthreads = 4;
407
408 auto events = generate_events_in_threads(nevents, nthreads, gopts, log);
409 log->info(0, "Generated %1 events.", events.size());
410
411 PerDetectorDoubles truth_ref;
412 PerDetectorInts digi_int_ref;
413 PerDetectorDoubles digi_dbl_ref;
414 compute_reference_sums(events, truth_ref, digi_int_ref, digi_dbl_ref);
415
416 auto runData = integrate_into_run(events, gopts);
417 validate_run_against_reference(runData, truth_ref, digi_int_ref, digi_dbl_ref, log);
418
419 return EXIT_SUCCESS;
420}
421
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.
Defines GRunDataCollection, the run-level aggregation of detector data.
constexpr const char * GRUNDATA_LOGGER
#define SFUNCTION_NAME
auto defineOptions() -> GOptions
Aggregates the option groups needed by run-level data containers.
std::map< std::string, std::map< std::string, long long > > PerDetectorInts
Per-detector map of integer-like reference sums used by the example.
std::map< std::string, std::map< std::string, double > > PerDetectorDoubles
Per-detector map of floating-point reference sums used by the example.
int main(int argc, char *argv[])