gdata
Loading...
Searching...
No Matches
run_example.cc
Go to the documentation of this file.
1
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 ", tid, " started");
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 ", tid, " processed ", localCount, " events");
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=", 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(0, "Detector <", sdName, ">: integrated truth entries=", truthVec.size(),
313 " integrated digitized entries=", digiVec.size());
314
315 // Truth integrated entry.
316 if (!truthVec.empty() && truthVec.front()) {
317 const auto integrated_truth = truthVec.front()->getDoubleVariablesMap();
318 log->info(0, " integrated truth doubles: ", map_to_string(integrated_truth));
319
320 const auto it_ref_det = truth_ref.find(sdName);
321 if (it_ref_det != truth_ref.end()) {
322 for (const auto& [k, refv] : it_ref_det->second) {
323 const auto itv = integrated_truth.find(k);
324 const double got = (itv == integrated_truth.end()) ? 0.0 : itv->second;
325 if (got != refv) {
326 log->info(0, " MISMATCH truth <", sdName, ">::", k, " got=", got, " ref=", refv);
327 }
328 }
329 }
330 else {
331 log->info(0, " NOTE: no reference truth sums found for detector <", sdName, ">.");
332 }
333 }
334 else {
335 log->info(0, " integrated truth: <none>");
336 }
337
338 // Digitized integrated entry.
339 if (!digiVec.empty() && digiVec.front()) {
340 const auto ints_non_sro = digiVec.front()->getIntObservablesMap(0);
341 const auto dbls_non_sro = digiVec.front()->getDblObservablesMap(0);
342
343 log->info(0, " integrated digi int non-SRO: ", map_to_string(ints_non_sro));
344 log->info(0, " integrated digi dbl non-SRO: ", map_to_string(dbls_non_sro));
345
346 const auto ints_sro = digiVec.front()->getIntObservablesMap(1);
347 const auto dbls_sro = digiVec.front()->getDblObservablesMap(1);
348 log->info(0, " integrated digi int SRO: ", map_to_string(ints_sro));
349 log->info(0, " integrated digi dbl SRO: ", map_to_string(dbls_sro));
350
351 const auto it_int_ref_det = digi_int_ref.find(sdName);
352 if (it_int_ref_det != digi_int_ref.end()) {
353 for (const auto& [k, refv] : it_int_ref_det->second) {
354 const auto itv = ints_non_sro.find(k);
355 const long long got = (itv == ints_non_sro.end()) ? 0LL : static_cast<long long>(itv->second);
356 if (got != refv) {
357 log->info(0, " MISMATCH digi-int <", sdName, ">::", k, " got=", got, " ref=", refv);
358 }
359 }
360 }
361 else {
362 log->info(0, " NOTE: no reference digitized-int sums found for detector <", sdName, ">.");
363 }
364
365 const auto it_dbl_ref_det = digi_dbl_ref.find(sdName);
366 if (it_dbl_ref_det != digi_dbl_ref.end()) {
367 for (const auto& [k, refv] : it_dbl_ref_det->second) {
368 const auto itv = dbls_non_sro.find(k);
369 const double got = (itv == dbls_non_sro.end()) ? 0.0 : itv->second;
370 if (got != refv) {
371 log->info(0, " MISMATCH digi-dbl <", sdName, ">::", k, " got=", got, " ref=", refv);
372 }
373 }
374 }
375 else {
376 log->info(0, " NOTE: no reference digitized-double sums found for detector <", sdName, ">.");
377 }
378 }
379 else {
380 log->info(0, " integrated digitized: <none>");
381 }
382 }
383}
384
400int main(int argc, char* argv[]) {
401 auto gopts = std::make_shared<GOptions>(argc, argv, grun_data::defineOptions());
402 auto log = std::make_shared<GLogger>(gopts, SFUNCTION_NAME, GRUNDATA_LOGGER);
403
404 constexpr int nevents = 20;
405 constexpr int nthreads = 4;
406
407 auto events = generate_events_in_threads(nevents, nthreads, gopts, log);
408 log->info(0, "Generated ", events.size(), " events.");
409
410 PerDetectorDoubles truth_ref;
411 PerDetectorInts digi_int_ref;
412 PerDetectorDoubles digi_dbl_ref;
413 compute_reference_sums(events, truth_ref, digi_int_ref, digi_dbl_ref);
414
415 auto runData = integrate_into_run(events, gopts);
416 validate_run_against_reference(runData, truth_ref, digi_int_ref, digi_dbl_ref, log);
417
418 return EXIT_SUCCESS;
419}
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[])