Skip to content

Commit fef5b9c

Browse files
committed
added generated and generated_tracked to the various streamers
1 parent 5ede81f commit fef5b9c

30 files changed

Lines changed: 1254 additions & 46 deletions

actions/event/gEventAction.cc

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,31 @@
77

88
// gemc
99
#include "event/gEventDataCollection.h"
10+
#include "../generator/gPrimaryGeneratorAction.h"
11+
12+
namespace {
13+
GGeneratedParticleBank make_generated_particle_bank(const GParticleRecordEvent& particles) {
14+
GGeneratedParticleBank bank;
15+
bank.reserve(particles.size());
16+
17+
for (const auto& particle : particles) {
18+
bank.push_back({
19+
particle.name,
20+
particle.pid,
21+
particle.type,
22+
particle.multiplicity,
23+
particle.p,
24+
particle.theta,
25+
particle.phi,
26+
particle.vx,
27+
particle.vy,
28+
particle.vz
29+
});
30+
}
31+
32+
return bank;
33+
}
34+
}
1035

1136

1237
// Construct the event action and keep access to shared configuration plus the
@@ -39,16 +64,24 @@ void GEventAction::EndOfEventAction([[maybe_unused]] const G4Event* event) {
3964
// Count each processed event once, even when it produces no payload.
4065
run_action->increment_run_events_processed();
4166

42-
auto* const hcs_this_event = event->GetHCofThisEvent();
43-
if (hcs_this_event == nullptr) {
44-
return;
45-
}
46-
4767
const auto thread_id = G4Threading::G4GetThreadId();
4868
const auto event_id = event->GetEventID();
4969

5070
auto gevent_header = std::make_unique<GEventHeader>(goptions, event_id, thread_id);
5171
auto eventDataCollection = std::make_shared<GEventDataCollection>(goptions, std::move(gevent_header));
72+
eventDataCollection->setGeneratedParticles(
73+
make_generated_particle_bank(GPrimaryGeneratorAction::currentGeneratedParticleRecords()));
74+
eventDataCollection->setGeneratedTrackedParticles(
75+
make_generated_particle_bank(GPrimaryGeneratorAction::currentGeneratedTrackedParticleRecords()));
76+
77+
auto* const hcs_this_event = event->GetHCofThisEvent();
78+
if (hcs_this_event == nullptr) {
79+
if (!eventDataCollection->getGeneratedParticles().empty() ||
80+
!eventDataCollection->getGeneratedTrackedParticles().empty()) {
81+
publish_event_data(eventDataCollection);
82+
}
83+
return;
84+
}
5285

5386
const auto digi_map = run_action->get_digitization_routines_map();
5487
if (digi_map == nullptr) {
@@ -128,7 +161,9 @@ void GEventAction::EndOfEventAction([[maybe_unused]] const G4Event* event) {
128161
}
129162

130163
// Publish event-mode output once, after all collections have been processed.
131-
if (has_event_mode_payload) {
164+
if (has_event_mode_payload ||
165+
!eventDataCollection->getGeneratedParticles().empty() ||
166+
!eventDataCollection->getGeneratedTrackedParticles().empty()) {
132167
publish_event_data(eventDataCollection);
133168
}
134169
}
@@ -139,6 +174,10 @@ void GEventAction::publish_event_data(const std::shared_ptr<GEventDataCollection
139174
return;
140175
}
141176

177+
if (!run_action->has_streamer_threads_map()) {
178+
return;
179+
}
180+
142181
const auto gstreamers_threads_map = run_action->get_streamer_threads_map();
143182
if (gstreamers_threads_map == nullptr) {
144183
log->error(ERR_STREAMERMAP_NOT_EXISTING, FUNCTION_NAME,
@@ -155,4 +194,4 @@ void GEventAction::publish_event_data(const std::shared_ptr<GEventDataCollection
155194

156195
gstreamer->publishEventData(event_data);
157196
}
158-
}
197+
}

actions/generator/gPrimaryGeneratorAction.cc

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,29 @@
66
// geant4
77
#include "G4Event.hh"
88

9+
thread_local GParticleEvent GPrimaryGeneratorAction::current_generated_particles;
10+
thread_local GParticleEvent GPrimaryGeneratorAction::current_generated_tracked_particles;
11+
thread_local GParticleRecordEvent GPrimaryGeneratorAction::current_generated_particle_records;
12+
thread_local GParticleRecordEvent GPrimaryGeneratorAction::current_generated_tracked_particle_records;
13+
14+
namespace {
15+
GParticleRecord make_particle_record(const GparticlePtr& particle) {
16+
if (particle == nullptr) { return {}; }
17+
const auto& vertex = particle->getVertex();
18+
return {
19+
particle->getName(),
20+
particle->getPid(),
21+
particle->getGeneratorType(),
22+
particle->getMultiplicity(),
23+
particle->getMomentum(),
24+
particle->getTheta(),
25+
particle->getPhi(),
26+
vertex.x(),
27+
vertex.y(),
28+
vertex.z()
29+
};
30+
}
31+
}
932

1033
// Build the primary-generator action, load the configured particle definitions,
1134
// and guarantee a valid fallback particle when no explicit configuration is present.
@@ -16,8 +39,9 @@ GPrimaryGeneratorAction::GPrimaryGeneratorAction(std::shared_ptr<GOptions> gopts
1639
// definitions are event records and are selected by Geant4 event id.
1740
gparticles = gparticle::getGParticlesFromOption(gopts, log);
1841
gparticleFileEvents = gparticle::getGParticleEventsFromSources(gopts, log);
42+
allGparticleFileRecordEvents = gparticle::getGParticleRecordEventsFromSources(gopts, log);
1943

20-
if (gparticles.empty() && gparticleFileEvents.empty()) {
44+
if (gparticles.empty() && allGparticleFileRecordEvents.empty()) {
2145
// Fall back to a default particle definition so the generator remains usable
2246
// even when no explicit particle configuration was provided.
2347
auto default_particle = Gparticle::create_default_gparticle(log);
@@ -30,14 +54,44 @@ GPrimaryGeneratorAction::GPrimaryGeneratorAction(std::shared_ptr<GOptions> gopts
3054
// For each configured particle definition, configure the shared particle gun and
3155
// inject the corresponding primary information into the current event.
3256
void GPrimaryGeneratorAction::GeneratePrimaries(G4Event* anEvent) {
57+
current_generated_particles.clear();
58+
current_generated_tracked_particles.clear();
59+
current_generated_particle_records.clear();
60+
current_generated_tracked_particle_records.clear();
61+
62+
current_generated_particles.insert(current_generated_particles.end(), gparticles.begin(), gparticles.end());
63+
current_generated_tracked_particles.insert(current_generated_tracked_particles.end(), gparticles.begin(), gparticles.end());
64+
current_generated_particle_records.reserve(gparticles.size());
65+
current_generated_tracked_particle_records.reserve(gparticles.size());
66+
for (const auto& gparticle : gparticles) {
67+
current_generated_particle_records.emplace_back(make_particle_record(gparticle));
68+
current_generated_tracked_particle_records.emplace_back(make_particle_record(gparticle));
69+
}
70+
71+
const auto event_id = anEvent->GetEventID();
72+
if (event_id >= 0 && static_cast<size_t>(event_id) < allGparticleFileRecordEvents.size()) {
73+
const auto& event_particles = allGparticleFileRecordEvents[static_cast<size_t>(event_id)];
74+
current_generated_particle_records.insert(current_generated_particle_records.end(),
75+
event_particles.begin(),
76+
event_particles.end());
77+
}
78+
if (event_id >= 0 && static_cast<size_t>(event_id) < gparticleFileEvents.size()) {
79+
const auto& event_particles = gparticleFileEvents[static_cast<size_t>(event_id)];
80+
current_generated_tracked_particles.insert(current_generated_tracked_particles.end(),
81+
event_particles.begin(),
82+
event_particles.end());
83+
for (const auto& gparticle : event_particles) {
84+
current_generated_tracked_particle_records.emplace_back(make_particle_record(gparticle));
85+
}
86+
}
87+
3388
for (const auto& gparticle : gparticles) {
3489

3590
if (gparticle != nullptr) {
3691
gparticle->shootParticle(gparticleGun.get(), anEvent);
3792
}
3893
}
3994

40-
const auto event_id = anEvent->GetEventID();
4195
if (event_id >= 0 && static_cast<size_t>(event_id) < gparticleFileEvents.size()) {
4296
log->info(2, "Generating gparticlefile event ", event_id,
4397
" with ", gparticleFileEvents[static_cast<size_t>(event_id)].size(),
@@ -50,3 +104,19 @@ void GPrimaryGeneratorAction::GeneratePrimaries(G4Event* anEvent) {
50104
}
51105
}
52106
}
107+
108+
const GParticleEvent& GPrimaryGeneratorAction::currentGeneratedParticles() {
109+
return current_generated_particles;
110+
}
111+
112+
const GParticleEvent& GPrimaryGeneratorAction::currentGeneratedTrackedParticles() {
113+
return current_generated_tracked_particles;
114+
}
115+
116+
const GParticleRecordEvent& GPrimaryGeneratorAction::currentGeneratedParticleRecords() {
117+
return current_generated_particle_records;
118+
}
119+
120+
const GParticleRecordEvent& GPrimaryGeneratorAction::currentGeneratedTrackedParticleRecords() {
121+
return current_generated_tracked_particle_records;
122+
}

actions/generator/gPrimaryGeneratorAction.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ inline GOptions defineOptions() {
5252
*
5353
* This class is the GEMC implementation of the Geant4 primary-generator action.
5454
* It owns a \c G4ParticleGun and a list of configured Gparticle objects.
55+
* Inline particles from \c -gparticle are generated for every event, while
56+
* \c -gparticlefile sources are indexed by Geant4 event id.
5557
*
5658
* For every event, \ref GPrimaryGeneratorAction::GeneratePrimaries "GeneratePrimaries()"
5759
* iterates over the configured particle definitions and delegates the actual shooting
@@ -61,6 +63,11 @@ inline GOptions defineOptions() {
6163
* If no particle definitions are found in the configuration, the constructor creates
6264
* a default particle so the simulation still has a valid primary source.
6365
*
66+
* The class also exposes thread-local generated-particle snapshots for event
67+
* output. The \c generated snapshot includes inline particles and all parsed
68+
* file rows. The \c generated_tracked snapshot includes inline particles and
69+
* only the file rows propagated in Geant4.
70+
*
6471
* @ingroup gactions_module
6572
*/
6673
class GPrimaryGeneratorAction : public GBase<GPrimaryGeneratorAction>, public G4VUserPrimaryGeneratorAction {
@@ -98,6 +105,43 @@ class GPrimaryGeneratorAction : public GBase<GPrimaryGeneratorAction>, public G4
98105
*/
99106
void GeneratePrimaries(G4Event* event) override;
100107

108+
/**
109+
* \brief Returns the current event's Geant4-propagated generated particles.
110+
*
111+
* \return Thread-local generated particles for the active event.
112+
*/
113+
static const GParticleEvent& currentGeneratedParticles();
114+
115+
/**
116+
* \brief Returns the current event's Geant4-tracked generated particles.
117+
*
118+
* This view contains inline particles and file-backed particles propagated
119+
* in Geant4.
120+
*
121+
* \return Thread-local tracked generated particles for the active event.
122+
*/
123+
static const GParticleEvent& currentGeneratedTrackedParticles();
124+
125+
/**
126+
* \brief Returns the current event's full generated-particle records.
127+
*
128+
* This is the source for the \c generated output bank. It includes inline
129+
* particles and every parsed file-backed particle row.
130+
*
131+
* \return Thread-local generated-particle records for the active event.
132+
*/
133+
static const GParticleRecordEvent& currentGeneratedParticleRecords();
134+
135+
/**
136+
* \brief Returns the current event's Geant4-tracked generated-particle records.
137+
*
138+
* This is the source for the \c generated_tracked output bank. It includes
139+
* inline particles and only file-backed particles propagated in Geant4.
140+
*
141+
* \return Thread-local tracked generated-particle records for the active event.
142+
*/
143+
static const GParticleRecordEvent& currentGeneratedTrackedParticleRecords();
144+
101145
private:
102146
/**
103147
* \brief Particle-gun instance used to materialize configured primaries into the event.
@@ -124,4 +168,24 @@ class GPrimaryGeneratorAction : public GBase<GPrimaryGeneratorAction>, public G4
124168
* matching file event record.
125169
*/
126170
GParticleEvents gparticleFileEvents;
171+
172+
/**
173+
* \brief File-backed generated-particle records, indexed by Geant4 event id.
174+
*
175+
* This record view preserves all parsed file particles for the
176+
* \c generated output bank, including rows that are not propagated in Geant4.
177+
*/
178+
GParticleRecordEvents allGparticleFileRecordEvents;
179+
180+
/// \brief Thread-local \ref GParticleEvent snapshot for the current event.
181+
static thread_local GParticleEvent current_generated_particles;
182+
183+
/// \brief Thread-local tracked \ref GParticleEvent snapshot for the current event.
184+
static thread_local GParticleEvent current_generated_tracked_particles;
185+
186+
/// \brief Thread-local full generated-particle record snapshot for the current event.
187+
static thread_local GParticleRecordEvent current_generated_particle_records;
188+
189+
/// \brief Thread-local tracked generated-particle record snapshot for the current event.
190+
static thread_local GParticleRecordEvent current_generated_tracked_particle_records;
127191
};

actions/run/gRunAction.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ void GRunAction::BeginOfRunAction(const G4Run *aRun) {
7373
" digitization_routines_map is null - streamer mode detection skipped.");
7474
}
7575

76+
for (const auto& streamer_definition : gstreamer::getGStreamerDefinition(goptions)) {
77+
if (streamer_definition.type == "event") {
78+
need_a_thread_streamer = true;
79+
break;
80+
}
81+
}
82+
7683

7784
// Worker threads own event-mode publication, so they lazily build and open
7885
// thread-local streamers only when at least one event-mode digitizer exists.

actions/run/gRunAction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ class GRunAction : public GBase<GRunAction>, public G4UserRunAction
114114
return gstreamer_threads_map;
115115
}
116116

117+
[[nodiscard]] bool has_streamer_threads_map() const {
118+
return gstreamer_threads_map != nullptr;
119+
}
120+
117121
/**
118122
* \brief Adds one run-mode digitized payload to the current thread run-data collection.
119123
*

ci/env.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ cores=$(getconf _NPROCESSORS_ONLN 2>/dev/null || nproc)
113113
jobs=$((cores < 16 ? cores : 16))
114114

115115
mkdir -p $log_dir
116-
setup_log=$log_dir/setup.log
117-
compile_log=$log_dir/build.log
118-
install_log=$log_dir/install.log
119-
test_log=$log_dir/test.log
120-
gemc_install_show=$log_dir/gemc.log
116+
setup_log=$log_dir/01_setup.log
117+
compile_log=$log_dir/02_build.log
118+
install_log=$log_dir/03_install.log
119+
gemc_install_show=$log_dir/04_show_install.log
120+
test_log=$log_dir/05_tests.log
121121

122122
touch $setup_log $compile_log $install_log $test_log
123123
echo

examples/basic/simple_flux/simple_flux.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
target_dz = 20
1717
target_radius = 5
18-
gvolume = GVolume("Target")
18+
gvolume = GVolume("target")
1919
gvolume.mother = "root"
2020
gvolume.description = "Simple Carbon Target"
2121
gvolume.make_tube(0, target_radius, target_dz, 0, 360)

0 commit comments

Comments
 (0)