10#include "G4LogicalVolume.hh"
11#include "G4NistManager.hh"
12#include "G4PVPlacement.hh"
13#include "G4RunManagerFactory.hh"
14#include "G4Threading.hh"
15#include "G4UserEventAction.hh"
16#include "G4VUserActionInitialization.hh"
17#include "G4VUserDetectorConstruction.hh"
27constexpr int stress_events = 512;
28constexpr int stress_multiplicity = 32;
31 std::atomic<int> checked_events{0};
32 std::atomic<int> invalid_events{0};
33 std::atomic<unsigned int> worker_mask{0};
36class EmptyDetectorConstruction final :
public G4VUserDetectorConstruction {
38 G4VPhysicalVolume* Construct()
override {
39 auto* material = G4NistManager::Instance()->FindOrBuildMaterial(
"G4_Galactic");
40 auto* solid =
new G4Box(
"generator_stress_world", 1 * CLHEP::m, 1 * CLHEP::m, 1 * CLHEP::m);
41 auto* logical =
new G4LogicalVolume(solid, material,
"generator_stress_world");
42 return new G4PVPlacement(
nullptr, {}, logical,
"generator_stress_world",
nullptr,
false, 0);
46class RuntimeRecordCheckingAction final :
public G4UserEventAction {
48 explicit RuntimeRecordCheckingAction(std::shared_ptr<StressResults> results) : results_(std::move(results)) {}
50 void EndOfEventAction(
const G4Event* event)
override {
51 const auto worker_id = G4Threading::G4GetThreadId();
52 if (worker_id >= 0 && worker_id < 4) {
53 results_->worker_mask.fetch_or(1U << worker_id, std::memory_order_relaxed);
56 if (records.size() != stress_multiplicity ||
57 event->GetNumberOfPrimaryVertex() != stress_multiplicity) {
58 results_->invalid_events.fetch_add(1, std::memory_order_relaxed);
60 results_->checked_events.fetch_add(1, std::memory_order_relaxed);
64 std::shared_ptr<StressResults> results_;
67class SharedGeneratorActionInitialization final :
public G4VUserActionInitialization {
69 SharedGeneratorActionInitialization(std::shared_ptr<GOptions> options,
70 std::shared_ptr<std::vector<GparticlePtr>> particles,
71 std::shared_ptr<StressResults> results) :
72 options_(std::move(options)), particles_(std::move(particles)), results_(std::move(results)) {}
74 void Build()
const override {
75 SetUserAction(
new GPrimaryGeneratorAction(options_, particles_));
76 SetUserAction(
new RuntimeRecordCheckingAction(results_));
80 std::shared_ptr<GOptions> options_;
81 std::shared_ptr<std::vector<GparticlePtr>> particles_;
82 std::shared_ptr<StressResults> results_;
86int main(
int argc,
char* argv[]) {
90 auto gopts = std::make_shared<GOptions>(argc, argv, option_definitions);
93 auto runManager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::Default);
94 runManager->SetNumberOfThreads(4);
95 runManager->SetUserInitialization(
new QBBC);
98 if (source_events.size() != 11) {
99 std::cerr <<
"Expected 11 gparticlefile events, got " << source_events.size() <<
'\n';
106 for (
size_t event_index = 0; event_index < source_events.size(); event_index++) {
107 G4Event
event(
static_cast<G4int
>(event_index));
110 const auto expected_vertices =
static_cast<G4int
>(
111 inline_particles.size() + source_events[event_index].size());
112 if (
event.GetNumberOfPrimaryVertex() != expected_vertices) {
113 std::cerr <<
"Event " << event_index <<
" expected " << expected_vertices
114 <<
" primary vertices, got " <<
event.GetNumberOfPrimaryVertex() <<
'\n';
119 if (tracked_records.size() !=
static_cast<size_t>(expected_vertices)) {
120 std::cerr <<
"Event " << event_index <<
" expected " << expected_vertices
121 <<
" tracked runtime records, got " << tracked_records.size() <<
'\n';
129 char* stress_argv[] = {argv[0],
nullptr};
132 auto stress_options = std::make_shared<GOptions>(1, stress_argv, stress_definitions);
134 auto stress_particles = std::make_shared<std::vector<GparticlePtr>>();
135 stress_particles->emplace_back(std::make_shared<Gparticle>(
136 "geantino", stress_multiplicity, 1000 * CLHEP::MeV, 0,
"uniform",
137 90 * CLHEP::deg, 0,
"uniform", 0, 360 * CLHEP::deg,
138 0, 0, 0, 0, 0, 0,
"uniform", stress_log));
139 auto stress_results = std::make_shared<StressResults>();
141 runManager->SetUserInitialization(
new EmptyDetectorConstruction());
142 runManager->SetUserInitialization(
143 new SharedGeneratorActionInitialization(stress_options, stress_particles, stress_results));
144 runManager->Initialize();
145 runManager->BeamOn(stress_events);
147 constexpr unsigned int expected_worker_mask = (1U << 4U) - 1U;
148 if (stress_results->checked_events.load(std::memory_order_relaxed) != stress_events ||
149 stress_results->invalid_events.load(std::memory_order_relaxed) != 0 ||
150 stress_results->worker_mask.load(std::memory_order_relaxed) != expected_worker_mask) {
151 std::cerr <<
"Shared-generator stress test checked "
152 << stress_results->checked_events.load(std::memory_order_relaxed) <<
" of " << stress_events
153 <<
" events and found " << stress_results->invalid_events.load(std::memory_order_relaxed)
154 <<
" invalid worker-local record sets; worker mask: "
155 << stress_results->worker_mask.load(std::memory_order_relaxed) <<
'\n';
Generates the primary vertices for each Geant4 event.
static const GParticleRecordEvent & currentGeneratedTrackedParticleRecords()
Returns the current event's Geant4-tracked generated-particle records.
void GeneratePrimaries(G4Event *event) override
Generates the primary content for one event.
Declares GPrimaryGeneratorAction, the primary-particle generation action for the GEMC actions module.
constexpr const char * GPRIMARYGENERATORACTION_LOGGER
vector< GparticlePtr > getGParticlesFromOption(const std::shared_ptr< GOptions > &gopts, std::shared_ptr< GLogger > &logger)
GParticleEvents getGParticleEventsFromSources(const std::shared_ptr< GOptions > &gopts, std::shared_ptr< GLogger > &logger, bool propagated_only=true)
GOptions defineOptions()
Returns the options associated with the primary-generator action scope.
int main(int argc, char *argv[])