8#include "G4Threading.hh"
10std::mutex GRunAction::completed_run_data_mutex;
11GRunAction::CompletedRunData GRunAction::completed_worker_run_data;
17 std::shared_ptr<gdynamicdigitization::dRoutinesMap> digi_map,
18 std::shared_ptr<GAnalysisAccumulator> analyzer,
21 digitization_routines_map(std::move(digi_map)),
22 analysis_accumulator(std::move(analyzer)),
23 sro_factory(std::move(sro)) {
24 const auto desc = std::to_string(G4Threading::G4GetThreadId());
30G4Run *GRunAction::GenerateRun() {
38void GRunAction::BeginOfRunAction(
const G4Run *aRun) {
39 const auto thread_id = G4Threading::G4GetThreadId();
40 const auto run = aRun->GetRunID();
42 auto run_header = std::make_unique<GRunHeader>(goptions, run, thread_id);
43 run_data = std::make_unique<GRunDataCollection>(goptions, std::move(run_header));
44 if (analysis_accumulator !=
nullptr) {
45 analysis_run_number = analysis_accumulator->currentRunNumber();
46 analysis_shard = std::make_unique<GAnalysisShard>();
49 const auto neventsThisRun = aRun->GetNumberOfEventToBeProcessed();
50 if (sro_factory && IsMaster()) {
51 try { sro_factory->begin_run(run,
static_cast<GSROEventId>(neventsThisRun)); }
52 catch (
const std::exception& error) {
58 need_a_thread_streamer =
false;
59 need_a_run_streamer =
false;
63 if (digitization_routines_map !=
nullptr) {
64 for (
const auto &[plugin, digiRoutine]: *digitization_routines_map) {
65 if (digiRoutine ==
nullptr) {
68 FUNCTION_NAME, plugin);
71 if (digiRoutine->collection_mode() == CollectionMode::event) {
72 need_a_thread_streamer =
true;
73 }
else if (digiRoutine->collection_mode() == CollectionMode::run) {
74 to_normalize[plugin] = digiRoutine->variables_to_normalize();
75 need_a_run_streamer =
true;
81 "%1 digitization_routines_map is null - streamer mode detection skipped.", FUNCTION_NAME);
85 if (streamer_definition.type ==
"event") {
86 need_a_thread_streamer =
true;
94 if (!IsMaster() && need_a_thread_streamer) {
95 if (gstreamer_threads_map ==
nullptr) {
96 log->info(1,
"Defining thread gstreamers for run %1 in thread %2", run, thread_id);
100 if (gstreamer_threads_map ==
nullptr) {
102 1,
"%1 gstreamer_threads_map is null in thread %2 - cannot open connections.", FUNCTION_NAME,
106 for (
const auto &[name, gstreamer]: *gstreamer_threads_map) {
107 if (gstreamer ==
nullptr) {
113 if (!gstreamer->openConnection()) {
116 "Failed to open connection for GStreamer %1 in thread %2", name, thread_id);
121 "%1Worker thread [%2]: opening connection for %3%4%5 for run %6. Number of events to be "
122 "processed: %7", FUNCTION_NAME, thread_id,
guts::KGRN, name,
guts::RST, run, neventsThisRun);
127 else if (IsMaster() && need_a_run_streamer) {
128 if (gstreamer_run_map ==
nullptr) {
129 log->info(1,
"Defining run gstreamers for run %1", run);
133 if (gstreamer_run_map ==
nullptr) {
135 1,
"%1 gstreamer_run_map is null in master thread - cannot open connections.", FUNCTION_NAME);
138 for (
const auto &[name, gstreamer]: *gstreamer_run_map) {
139 if (gstreamer ==
nullptr) {
144 if (!gstreamer->openConnection()) {
147 "Failed to open connection for GStreamer in master thread %1", name);
152 "%1Master Thread: opening connection for %2%3%4 for run %5. Number of events to be "
160void GRunAction::EndOfRunAction(
const G4Run *aRun) {
161 const auto thread_id = G4Threading::G4GetThreadId();
162 const auto runNumber = aRun->GetRunID();
163 const std::string what_am_i = IsMaster() ?
"Master" :
"Worker";
165 if (sro_factory && IsMaster()) {
166 try { sro_factory->finish_run(aRun->GetNumberOfEvent() == aRun->GetNumberOfEventToBeProcessed()); }
167 catch (
const std::exception& error) {
173 if (!IsMaster() && need_a_thread_streamer) {
174 if (gstreamer_threads_map ==
nullptr) {
177 "%1 gstreamer_map is null in thread %2 - cannot close connections.", FUNCTION_NAME, thread_id);
179 for (
const auto &[name, gstreamer]: *gstreamer_threads_map) {
181 2,
"%1 %2 [%3], for run %4 closing connection for gstreamer %5", FUNCTION_NAME, what_am_i,
182 thread_id, runNumber, name);
184 if (gstreamer ==
nullptr) {
190 if (!gstreamer->closeConnection()) {
191 log->error(1,
"Failed to close connection for GStreamer %1 in thread %2", name, thread_id);
198 if (analysis_accumulator !=
nullptr && analysis_shard !=
nullptr) {
199 if (!analysis_shard->empty()) { analysis_accumulator->merge(std::move(*analysis_shard)); }
200 analysis_shard.reset();
208 if (need_a_run_streamer) { stash_worker_run_data(); }
212 if (IsMaster() && need_a_run_streamer) {
215 auto completed_run_data = take_completed_worker_run_data();
217 2,
"%1 master collected %2 worker run_data object(s) for run %3", FUNCTION_NAME,
218 static_cast<int>(completed_run_data.size()), runNumber);
220 std::shared_ptr<GRunDataCollection> merged_run_data;
222 for (
auto &worker_run_data: completed_run_data) {
223 if (worker_run_data ==
nullptr) {
229 if (merged_run_data ==
nullptr) {
230 auto merged_header = std::make_unique<GRunHeader>(goptions, runNumber, thread_id);
231 merged_run_data = std::make_shared<GRunDataCollection>(goptions, std::move(merged_header));
234 merged_run_data->merge(*worker_run_data);
238 if (merged_run_data !=
nullptr) {
239 publish_run_data(merged_run_data);
242 if (gstreamer_run_map ==
nullptr) {
245 "%1 gstreamer_map is null in master thread - cannot close connections.", FUNCTION_NAME);
248 for (
const auto &[name, gstreamer]: *gstreamer_run_map) {
250 2,
"%1 %2 for run %3 closing connection for gstreamer %4", FUNCTION_NAME, what_am_i, runNumber,
253 if (gstreamer ==
nullptr) {
258 if (!gstreamer->closeConnection()) {
259 log->error(1,
"Failed to close connection for GStreamer %1 in master thread", name);
268void GRunAction::stash_worker_run_data() {
269 if (run_data ==
nullptr) {
273 std::scoped_lock lock(completed_run_data_mutex);
274 completed_worker_run_data.emplace_back(std::move(run_data));
278auto GRunAction::take_completed_worker_run_data() -> CompletedRunData {
279 std::scoped_lock lock(completed_run_data_mutex);
281 auto result = std::move(completed_worker_run_data);
282 completed_worker_run_data.clear();
289void GRunAction::publish_run_data(
const std::shared_ptr<GRunDataCollection> &run_data_collaction)
const {
290 if (run_data_collaction ==
nullptr) {
296 if (gstreamer_run_map ==
nullptr) {
299 "%1 no run streamer map available - run data will not be published.", FUNCTION_NAME);
305 normalize_run_data(run_data_collaction);
307 for (
const auto &[name, gstreamer]: *gstreamer_run_map) {
308 if (gstreamer ==
nullptr) {
311 FUNCTION_NAME, name);
314 gstreamer->publishRunData(run_data_collaction);
319void GRunAction::normalize_run_data(
const std::shared_ptr<GRunDataCollection> &run_data_collaction)
const {
320 if (run_data_collaction ==
nullptr) {
326 const int events_processed = run_data_collaction->get_events_processed();
327 if (events_processed <= 0) {
328 log->warning(
"%1 events_processed is %2 - skipping normalization.", FUNCTION_NAME, events_processed);
332 const double norm =
static_cast<double>(events_processed);
334 for (
auto &[sdName, dataCollection]: run_data_collaction->getMutableDataCollectionMap()) {
335 if (dataCollection ==
nullptr) {
336 log->warning(
"%1 detector %2 has null data collection - skipping.", FUNCTION_NAME, sdName);
340 auto &digitizedData = dataCollection->getMutableDigitizedData();
341 if (digitizedData.empty() || digitizedData.front() ==
nullptr) {
345 auto &digitized = digitizedData.front();
349 auto it = to_normalize.find(sdName);
350 if (it != to_normalize.end()) {
351 for (
const auto &varName: it->second) {
352 const auto intVars = digitized->getIntObservablesMap(0);
353 const auto intIt = intVars.find(varName);
354 if (intIt != intVars.end()) {
355 digitized->includeVariable(varName,
static_cast<double>(intIt->second) / norm);
359 const auto dblVars = digitized->getDblObservablesMap(0);
360 const auto dblIt = dblVars.find(varName);
361 if (dblIt != dblVars.end()) {
362 digitized->includeVariable(varName, dblIt->second / norm);
GBase(const std::shared_ptr< GOptions > &gopt, std::string logger_name="")
std::shared_ptr< GLogger > log
GRunAction(std::shared_ptr< GOptions > gopts, std::shared_ptr< gdynamicdigitization::dRoutinesMap > digi_map, std::shared_ptr< GAnalysisAccumulator > analysis_accumulator=nullptr, std::shared_ptr< GSROFactory > sro_factory=nullptr)
Constructs the run action.
Thread-local run object created by the GEMC run action.
Declares GRunAction, the run-lifecycle action for the GEMC actions module.
constexpr const char * GRUNACTION_LOGGER
Declares GRun, the thread-local run container used by the GEMC actions module.
std::uint64_t GSROEventId
Defines error codes used by the GEMC actions module.
std::shared_ptr< const gstreamersMap > gstreamersMapPtr(const std::shared_ptr< GOptions > &gopts, int thread_id=-1)
vector< GStreamerDefinition > getGStreamerDefinition(const std::shared_ptr< GOptions > &gopts)
constexpr int ERR_GDIGIMAP_NOT_EXISTING
constexpr int ERR_STREAMERMAP_NOT_EXISTING
constexpr int ERR_GRUNACTION_NOT_EXISTING
constexpr int ERR_PUBLISH_ERROR