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