gdynamicDigitization
Loading...
Searching...
No Matches
plugin_load_example.cc
Go to the documentation of this file.
1
2
3// example on how to use the gdynamic library
4
5// gdynamic
8
9// gemc
10#include "gfactory.h"
11#include "event/gEventDataCollection.h"
12
13// TODO: remove when C++20 is widely available
14// ===== portable jthread-like wrapper =========================================
15// If real std::jthread is present, use it. Otherwise, define a minimal shim
16// that joins in the destructor (no stop_token support, but good enough here).
17#if defined(__cpp_lib_jthread) // header exists
18#include <jthread>
19using jthread_alias = std::jthread;
20#else
21// join: pause right here until that thread is finished.
22class jthread_alias : public std::thread {
23public:
24 using std::thread::thread; // inherit all ctors
25 ~jthread_alias() { if (joinable()) join(); }
26 jthread_alias(jthread_alias&&) noexcept = default;
27 jthread_alias& operator=(jthread_alias&&) noexcept = default;
28 // no copy
29 jthread_alias(const jthread_alias&) = delete;
30 jthread_alias& operator=(const jthread_alias&) = delete;
31};
32#endif
33
34const std::string plugin_name = "test_gdynamic_plugin";
35
37 int nthreads,
38 const std::shared_ptr<GOptions>& gopt,
39 const std::shared_ptr<GLogger>& log,
40 const std::shared_ptr<const gdynamicdigitization::dRoutinesMap>& dynamicRoutinesMap) -> std::vector<std::unique_ptr<GEventDataCollection>> {
41 std::mutex collectorMtx;
42 std::vector<std::unique_ptr<GEventDataCollection>> collected;
43
44 // thread-safe integer counter starts at 1.
45 // fetch_add returns the old value *and* bumps.
46 // zero contention: each thread fetches the next free event number.
47 std::atomic<int> next{1};
48
49 // pool of jthreads. jthread joins in its destructor so we don’t need an
50 // explicit loop at the end.
51 // each element represents one worker thread running your event-processing lambda.
52 // std::vector<std::jthread> pool; use this when C++20 is widely available
53 std::vector<jthread_alias> pool; // was std::vector<std::jthread>
54
55 pool.reserve(nthreads);
56
57 for (int tid = 0; tid < nthreads; ++tid) {
58 // The capture [&, tid] gives the thread references to variables like tid
59 pool.emplace_back([&, tid] // capture tid *by value*
60 {
61 // start thread with a lambda
62 log->info(0, "worker ", tid, " started");
63
64 int localCount = 0; // events built by *this* worker
65 thread_local std::vector<std::unique_ptr<GEventDataCollection>> localRunData;
66
67 while (true) {
68 // repeatedly asks the shared atomic counter for “the next unclaimed event
69 // number,” processes that event, stores the result, and goes back for more.
70 // memory_order_relaxed: we only need *atomicity*, no ordering
71 int evn = next.fetch_add(1, std::memory_order_relaxed); // atomically returns the current value and increments it by 1.
72 if (evn > nevents) break; // exit the while loop
73
74 auto gheader = GEventHeader::create(gopt);
75 auto eventData = std::make_unique<GEventDataCollection>(gopt, std::move(gheader));
76
77 // each event has 2 hits
78 for (unsigned i = 1; i < 3; i++) {
79 auto hit = GHit::create(gopt);
80 auto true_data = dynamicRoutinesMap->at(plugin_name)->collectTrueInformation(hit, i);
81 auto digi_data = dynamicRoutinesMap->at(plugin_name)->digitizeHit(hit, i);
82
83 eventData->addDetectorDigitizedData("ctof", std::move(digi_data));
84 eventData->addDetectorTrueInfoData("ctof", std::move(true_data));
85 }
86
87 log->info(0, "worker ", tid, " event ", evn, " has ", eventData->getDataCollectionMap().at("ctof")->getDigitizedData().size(), " digitized hits");
88
89 localRunData.emplace_back(std::move(eventData));
90
91 ++localCount; // tally for this worker
92 }
93
94 // braces to locks the mutex when it's constructed and unlocks when it is destroyed
95 {
96 std::scoped_lock lk(collectorMtx);
97 for (auto& evt : localRunData) {
98 // only collect 2 events total so that the log doesn't go crazy with the destructor
99 if (collected.size() >= 2) break;
100 collected.emplace_back(std::move(evt));
101 }
102 localRunData.clear();
103 }
104
105 log->info(0, "worker ", tid, " processed ", localCount, " events");
106 }); // jthread constructor launches the thread immediately
107 } // pool’s destructor blocks until every jthread has joined
108 return collected;
109}
110
111
112// emulation of a run of events, collecting data in separate threads
113
114
115int main(int argc, char* argv[]) {
116 // Create GOptions using gdata::defineOptions, which aggregates options from gdata and gtouchable.
117 auto gopts = std::make_shared<GOptions>(argc, argv, gdynamicdigitization::defineOptions());
118
119 // duplicate plugin logger here
120 auto log = std::make_shared<GLogger>(gopts, SFUNCTION_NAME, PLUGIN_LOGGER);
121
122 constexpr int nevents = 10;
123 constexpr int nthreads = 8;
124
125 auto dynamicRoutinesMap = gdynamicdigitization::dynamicRoutinesMap({plugin_name}, gopts);
126 if (dynamicRoutinesMap->at(plugin_name)->loadConstants(1, "default") == false) {
127 log->error(1, "Failed to load constants for dynamic routine", plugin_name, "for run number 1 with variation 'default'.");
128 }
129
130 auto runData = run_simulation_in_threads(nevents, nthreads, gopts, log, dynamicRoutinesMap);
131
132 // For demonstration, we'll simply print the event numbers.
133 for (size_t i = 0; i < runData.size(); i++) { log->info(" > Event ", i + 1, " collected with local event number: ", runData[i]->getEventNumber()); }
134
135 return EXIT_SUCCESS;
136}
jthread_alias(jthread_alias &&) noexcept=default
Defines the options for the GDynamicDigitization module.
GOptions defineOptions()
Returns an array of options definitions for the GDynamicDigitization module.
std::shared_ptr< const dRoutinesMap > dynamicRoutinesMap(const std::vector< std::string > &plugin_names, const std::shared_ptr< GOptions > &gopts)
int main(int argc, char *argv[])
const std::string plugin_name
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 > >