utilities
Loading...
Searching...
No Matches
gemcUtilities.cc
Go to the documentation of this file.
1#include "gemcUtilities.h"
2#include "gemcConventions.h"
3
4// Implementation notes:
5// - Doxygen documentation is kept authoritative in gemcUtilities.h.
6// - This file only provides brief, non-Doxygen comments to clarify intent and flow.
7
8// geant4 headers
9#include "G4Threading.hh"
10#include "G4UImanager.hh"
11
12// gemc
13#include "glogger.h"
14#include "gtouchable.h"
15
16namespace gemc {
17
18// return the number of cores from options.
19// if 0 is given, returns max number of available cores
20int get_nthreads(const std::shared_ptr<GOptions>& gopts, const std::shared_ptr<GLogger>& log) {
21 int useThreads = gopts->getScalarInt("nthreads");
22
23 // Geant4 provides a platform-specific core count helper.
24 int ncores = G4Threading::G4GetNumberOfCores();
25
26 // Clamp user request:
27 // - 0 means "use all available cores"
28 // - values larger than available cores are clamped
29 if (useThreads == 0 || useThreads > ncores) useThreads = ncores;
30
31 log->info(0, "Using ", useThreads, " threads out of ", ncores, " available cores.");
32
33 return useThreads;
34}
35
36std::vector<std::string> verbosity_commands([[maybe_unused]] const std::shared_ptr<GOptions>& gopts, [[maybe_unused]] const std::shared_ptr<GLogger>& log) {
37 std::vector<std::string> cmds;
38
39 // --- Always-quiet commands ---
40 // These commands reduce Geant4 output noise for typical production runs.
41 cmds.emplace_back("/control/verbose 0");
42 cmds.emplace_back("/hit/verbose 0");
43
44 cmds.emplace_back("/process/verbose 0");
45 cmds.emplace_back("/process/setVerbose 0 all");
46 cmds.emplace_back("/process/had/verbose 0");
47 cmds.emplace_back("/process/had/deex/verbose 0");
48 cmds.emplace_back("/process/had/cascade 0");
49 cmds.emplace_back("/process/em/verbose 0");
50 cmds.emplace_back("/process/eLoss/verbose 0");
51
52 cmds.emplace_back("/tracking/verbose 0");
53 cmds.emplace_back("/geometry/navigator/verbose 0");
54
55 cmds.emplace_back("/event/verbose 0");
56 cmds.emplace_back("/event/stack/verbose 0");
57
58 cmds.emplace_back("/cuts/verbose 0");
59
60 cmds.emplace_back("/run/particle/verbose 0");
61 cmds.emplace_back("/run/verbose 0");
62
63 cmds.emplace_back("/material/verbose 0");
64
65 cmds.emplace_back("/vis/verbose 0");
66 cmds.emplace_back("/particle/verbose 0");
67
68 // cmds.emplace_back("/control/cout/ignoreInitializationCout 1");
69 // cmds.emplace_back("/control/cout/useBuffer 1"); // keep MT output tidy?
70
71 return cmds;
72}
73
74std::vector<std::string> initial_commands(const std::shared_ptr<GOptions>& gopts, [[maybe_unused]] const std::shared_ptr<GLogger>& log) {
75 // check_overlaps is typically provided by the Geant4 system options set.
76 auto check_overlaps = gopts->getScalarInt("check_overlaps"); // notice: from g4system options
77 auto gui = gopts->getSwitch("gui");
78
79 std::vector<std::string> cmds;
80
81 // Batch mode: optionally schedule geometry overlap checks before initialization.
82 // Geant4 overlap checks use the current "/geometry/test/..." configuration.
83 if (check_overlaps == 2) {
84 log->info(0, "Running /geometry/test/run with 50 points.");
85 cmds.emplace_back("/geometry/test/resolution 50");
86 cmds.emplace_back("/geometry/test/run");
87 }
88 else if (check_overlaps >= 100) {
89 log->info(0, "Running /geometry/test/run with ", check_overlaps, " points.");
90 cmds.emplace_back("/geometry/test/resolution " + std::to_string(check_overlaps));
91 cmds.emplace_back("/geometry/test/run");
92 }
93
94 // A re-initialize is required when:
95 // - physics changes
96 // - geometry changes
97 cmds.emplace_back("/run/initialize");
98
99 // If there is no GUI, initialization commands are sufficient.
100 if (!gui) return cmds;
101
102 // GUI mode: set up a minimal visualization scene with trajectories and hits.
103 cmds.emplace_back("/vis/drawVolume");
104
105 // Disable auto refresh and quieten vis messages whilst scene and trajectories are established.
106 cmds.emplace_back("/vis/viewer/set/autoRefresh false");
107 cmds.emplace_back("/vis/viewer/set/viewpointVector -1 0 0");
108 cmds.emplace_back("/vis/viewer/set/lightsVector -1 0 0");
109
110 cmds.emplace_back("/vis/scene/add/trajectories smooth");
111 cmds.emplace_back("/vis/modeling/trajectories/create/drawByCharge");
112 cmds.emplace_back("/vis/modeling/trajectories/drawByCharge-0/default/setDrawStepPts true");
113 cmds.emplace_back("/vis/modeling/trajectories/drawByCharge-0/default/setStepPtsSize 2");
114 cmds.emplace_back("/vis/scene/add/hits");
115 cmds.emplace_back("/vis/scene/endOfEventAction accumulate 10000");
116
117 // Background colors and root volume are the same.
118 cmds.push_back("/vis/viewer/set/background 0.46666667 0.53333333 0.6");
119
120 // Re-enable refresh and flush once configuration is complete.
121 cmds.emplace_back("/vis/viewer/set/autoRefresh true");
122 cmds.emplace_back("/vis/viewer/flush");
123
124 return cmds;
125}
126
127// initialize G4MTRunManager
128void run_manager_commands([[maybe_unused]] const std::shared_ptr<GOptions>& gopts, const std::shared_ptr<GLogger>& log, const std::vector<std::string>& commands) {
129 auto* g4uim = G4UImanager::GetUIpointer();
130
131 // Apply commands sequentially so the UI manager sees the same order as a macro file.
132 for (const auto& cmd : commands) {
133 log->info(2, "Executing UIManager command: ", cmd);
134 g4uim->ApplyCommand(cmd);
135 }
136}
137
138#include <unistd.h> // needed for get_pid
139
140void start_random_engine(const std::shared_ptr<GOptions>& gopts, const std::shared_ptr<GLogger>& log) {
141 auto randomEngineName = gopts->getScalarString("randomEngine");
142 auto seed = gopts->getScalarInt("seed");
143
144 // If the user did not set a seed, derive one using several fast-changing sources.
145 // This helps reduce accidental seed reuse across runs.
146 if (seed == SEEDNOTSET) {
147 auto timed = time(NULL);
148 auto clockd = clock();
149 auto getpidi = getpid();
150 seed = (G4int)(timed - clockd - getpidi);
151 }
152
153 // The names come from the CLHEP library, can be found with
154 // grep ": public HepRandomEngine" *.h $CLHEP_BASE_DIR/include/CLHEP/Random/* | awk -Fclass '{print $2}' | awk -F: '{print $1}'
155 //
156 // Select the engine implementation based on the configured string.
157 if (randomEngineName == "DRand48Engine")
158 G4Random::setTheEngine(new CLHEP::DRand48Engine(seed));
159 else if (randomEngineName == "DualRand")
160 G4Random::setTheEngine(new CLHEP::DualRand);
161 else if (randomEngineName == "Hurd160Engine")
162 G4Random::setTheEngine(new CLHEP::Hurd160Engine);
163 else if (randomEngineName == "HepJamesRandom")
164 G4Random::setTheEngine(new CLHEP::HepJamesRandom);
165 else if (randomEngineName == "MTwistEngine")
166 G4Random::setTheEngine(new CLHEP::MTwistEngine);
167 else if (randomEngineName == "MixMaxRng")
168 G4Random::setTheEngine(new CLHEP::MixMaxRng(seed));
169 else if (randomEngineName == "RandEngine")
170 G4Random::setTheEngine(new CLHEP::RandEngine);
171 else if (randomEngineName == "RanecuEngine")
172 G4Random::setTheEngine(new CLHEP::RanecuEngine);
173 else if (randomEngineName == "Ranlux64Engine")
174 G4Random::setTheEngine(new CLHEP::Ranlux64Engine);
175 else if (randomEngineName == "RanluxEngine")
176 G4Random::setTheEngine(new CLHEP::RanluxEngine);
177 else if (randomEngineName == "RanshiEngine")
178 G4Random::setTheEngine(new CLHEP::RanshiEngine);
179 else if (randomEngineName == "Hurd288Engine")
180 G4Random::setTheEngine(new CLHEP::Hurd288Engine);
181 else if (randomEngineName == "TripleRand")
182 G4Random::setTheEngine(new CLHEP::TripleRand);
183 else { log->error(EC__RANDOMENGINENOTFOUND, "Random engine >", randomEngineName, "< not found. Exiting."); }
184
185 // Apply the seed after selecting the engine so the engine instance is active.
186 log->info(0, "Starting random engine ", randomEngineName, " with seed ", seed);
187 G4Random::setTheSeed(seed);
188}
189
190}
Conventional constants used by GEMC utility helpers.
Utility helpers for runtime setup, command preparation, and random-engine initialization.
#define SEEDNOTSET
Sentinel value used to mark that the random seed has not been explicitly set.
#define EC__RANDOMENGINENOTFOUND
Error code used when the configured random engine name is not recognized.
void start_random_engine(const std::shared_ptr< GOptions > &gopts, const std::shared_ptr< GLogger > &log)
Select and start the random engine, then seed it.
std::vector< std::string > verbosity_commands(const std::shared_ptr< GOptions > &gopts, const std::shared_ptr< GLogger > &log)
Build a list of Geant4 UI commands that reduce verbosity across subsystems.
std::vector< std::string > initial_commands(const std::shared_ptr< GOptions > &gopts, const std::shared_ptr< GLogger > &log)
Build a list of Geant4 UI commands needed at startup.
void run_manager_commands(const std::shared_ptr< GOptions > &gopts, const std::shared_ptr< GLogger > &log, const std::vector< std::string > &commands)
Execute a sequence of Geant4 UI commands through the UI manager.
int get_nthreads(const std::shared_ptr< GOptions > &gopts, const std::shared_ptr< GLogger > &log)
Determine the number of worker threads to use for the run.