9#include "G4Threading.hh"
10#include "G4UImanager.hh"
11#include "G4UnitsTable.hh"
30bool scalarOptionIsTrue(
const std::shared_ptr<GOptions>& gopts,
const std::string& name) {
31 if (gopts ==
nullptr) {
return false; }
33 std::string value = gopts->getOptionalScalarString(name).value_or(
"");
34 std::transform(value.begin(), value.end(), value.begin(),
35 [](
unsigned char c) { return static_cast<char>(std::tolower(c)); });
37 if (value ==
"true" || value ==
"yes" || value ==
"on" || value ==
"1") {
40 if (value ==
"false" || value ==
"no" || value ==
"off" || value ==
"0" || value ==
"null") {
45 <<
" accepts only true/false/yes/no/on/off/1/0." << std::endl;
49std::string rootExtentForFieldCommand(
const std::shared_ptr<GOptions>& gopts) {
50 if (gopts ==
nullptr) {
return ""; }
52 std::string rootDefinition = gopts->getRequiredScalarString(
"root");
53 for (
auto& c : rootDefinition) {
54 if (c ==
',') { c =
' '; }
58 if (tokens.size() < 5 || tokens[0] !=
"G4Box") {
return ""; }
63 if (dx <= 0 || dy <= 0 || dz <= 0) {
return ""; }
65 std::ostringstream command;
66 command <<
"/vis/set/extentForField "
67 << -dx <<
" " << dx <<
" "
68 << -dy <<
" " << dy <<
" "
69 << -dz <<
" " << dz <<
" mm";
77 int get_nthreads(
const std::shared_ptr<GOptions>& gopts,
const std::shared_ptr<GLogger>& log) {
78 int useThreads = gopts->getRequiredScalarInt(
"nthreads");
81 int ncores = G4Threading::G4GetNumberOfCores();
86 if (useThreads == 0 || useThreads > ncores) useThreads = ncores;
88 log->info(0,
"Using %1 threads out of %2 available cores.", useThreads, ncores);
93 std::vector<std::string>
verbosity_commands([[maybe_unused]]
const std::shared_ptr<GOptions>& gopts,
94 [[maybe_unused]]
const std::shared_ptr<GLogger>& log) {
95 std::vector<std::string> cmds;
99 cmds.emplace_back(
"/control/verbose 0");
100 cmds.emplace_back(
"/hit/verbose 0");
102 cmds.emplace_back(
"/process/verbose 0");
103 cmds.emplace_back(
"/process/setVerbose 0 all");
104 cmds.emplace_back(
"/process/had/verbose 0");
105 cmds.emplace_back(
"/process/had/deex/verbose 0");
106 cmds.emplace_back(
"/process/had/cascade 0");
107 cmds.emplace_back(
"/process/em/verbose 0");
108 cmds.emplace_back(
"/process/eLoss/verbose 0");
110 cmds.emplace_back(
"/tracking/verbose 0");
111 cmds.emplace_back(
"/geometry/navigator/verbose 0");
113 cmds.emplace_back(
"/event/verbose 0");
114 cmds.emplace_back(
"/event/stack/verbose 0");
116 cmds.emplace_back(
"/cuts/verbose 0");
118 cmds.emplace_back(
"/run/particle/verbose 0");
119 cmds.emplace_back(
"/run/verbose 0");
121 cmds.emplace_back(
"/material/verbose 0");
123 cmds.emplace_back(
"/vis/verbose 0");
124 cmds.emplace_back(
"/particle/verbose 0");
133 [[maybe_unused]]
const std::shared_ptr<GLogger>& log,
134 bool configure_visualization) {
136 auto check_overlaps = gopts->getRequiredScalarInt(
"check_overlaps");
137 auto gui = gopts->getSwitch(
"gui");
140 std::vector<std::string> cmds;
144 if (check_overlaps == 2) {
145 log->info(0,
"Running /geometry/test/run with 50 points.");
146 cmds.emplace_back(
"/geometry/test/resolution 50");
147 cmds.emplace_back(
"/geometry/test/run");
149 else if (check_overlaps >= 100) {
150 log->info(0,
"Running /geometry/test/run with %1 points.", check_overlaps);
151 cmds.emplace_back(
"/geometry/test/resolution " + std::to_string(check_overlaps));
152 cmds.emplace_back(
"/geometry/test/run");
158 if (gui && !configure_visualization) {
return cmds; }
163 cmds.emplace_back(
"/run/initialize");
165 if (!configure_visualization)
return cmds;
169 for (
const auto& command : g4SceneProperties.
scene_commands(gopts)) {
170 cmds.emplace_back(command);
174 if (!gui && g4view.driver !=
"TOOLSSG_OFFSCREEN")
return cmds;
177 if (g4view.driver !=
"TOOLSSG_OFFSCREEN") {
180 const double toDegrees = 180.0 / std::numbers::pi;
185 if (lightThetaValue == 0.0 && lightPhiValue == 0.0) {
186 lightThetaValue = thetaValue;
187 lightPhiValue = phiValue;
191 cmds.emplace_back(
"/vis/viewer/set/autoRefresh false");
192 cmds.emplace_back(
"/vis/viewer/set/viewpointThetaPhi " + std::to_string(thetaValue) +
" " + std::to_string(phiValue));
193 cmds.emplace_back(
"/vis/viewer/set/lightsThetaPhi " + std::to_string(lightThetaValue) +
" " + std::to_string(lightPhiValue));
197 cmds.emplace_back(
"/vis/scene/add/trajectories smooth");
198 cmds.emplace_back(
"/vis/modeling/trajectories/create/drawByCharge");
199 cmds.emplace_back(
"/vis/modeling/trajectories/drawByCharge-0/default/setDrawStepPts true");
200 cmds.emplace_back(
"/vis/modeling/trajectories/drawByCharge-0/default/setStepPtsSize 2");
202 cmds.emplace_back(
"/vis/modeling/trajectories/create/drawByParticleID");
203 cmds.emplace_back(
"/vis/modeling/trajectories/drawByParticleID-0/set opticalphoton cyan");
205 cmds.emplace_back(
"/vis/scene/add/hits");
206 cmds.emplace_back(
"/vis/scene/endOfEventAction accumulate 10000");
207 cmds.push_back(
"/vis/viewer/set/background " + g4view.background);
208 cmds.push_back(
"/vis/viewer/set/numberOfCloudPoints " + std::to_string(g4view.cloudPoints));
210 for (
const auto& command : g4SceneProperties.
addSceneDecorations(gopts)) { cmds.emplace_back(command); }
211 for (
const auto& command : g4SceneProperties.
addSceneTexts(gopts)) { cmds.emplace_back(command); }
212 if (decorations.eventID) { cmds.emplace_back(
"/vis/scene/add/eventID"); }
214 if (scalarOptionIsTrue(gopts,
"show_auxiliary_edges")) {
215 cmds.emplace_back(
"/vis/viewer/set/auxiliaryEdge 1");
216 cmds.emplace_back(
"/vis/viewer/set/hiddenEdge 1");
219 const int fieldLinePoints = gopts->getRequiredScalarInt(
"show_field_lines");
220 if (fieldLinePoints > 0) {
221 if (
const auto extent = rootExtentForFieldCommand(gopts); !extent.empty()) {
222 cmds.emplace_back(extent);
224 cmds.emplace_back(
"/vis/scene/add/magneticField " + std::to_string(fieldLinePoints));
228 if (g4view.driver !=
"TOOLSSG_OFFSCREEN") {
230 cmds.emplace_back(
"/vis/viewer/set/autoRefresh true");
231 cmds.emplace_back(
"/vis/viewer/flush");
240 const std::shared_ptr<GLogger>& log,
const std::vector<std::string>& commands) {
241 auto* g4uim = G4UImanager::GetUIpointer();
244 for (
const auto& cmd : commands) {
245 log->info(2,
"Executing UIManager command: %1", cmd);
246 g4uim->ApplyCommand(cmd);
250 void execute_macro(
const std::string& filename,
const std::shared_ptr<GLogger>& log) {
251 std::error_code error;
252 if (!std::filesystem::is_regular_file(filename, error) || !std::ifstream(filename)) {
253 log->error(EXIT_FAILURE,
"Cannot read Geant4 macro file: %1", filename);
256 log->info(0,
"Executing Geant4 macro: %1", filename);
257 auto* uim = G4UImanager::GetUIpointer();
259 uim->ExecuteMacroFile(filename.c_str());
260 if (
const auto status = uim->GetLastReturnCode(); status != 0) {
261 log->error(EXIT_FAILURE,
"Geant4 macro failed: %1 (command status %2)", filename, status);
276 auto randomEngineName = gopts->getRequiredScalarString(
"randomEngine");
277 auto configuredSeed = gopts->getOptionalScalarInt(
"seed");
282 if (!configuredSeed) {
283 auto timed = time(NULL);
284 auto clockd = clock();
285 auto getpidi = getpid();
286 seed = (G4int)( timed - clockd - getpidi );
287 log->info(1,
"Using random seed %1", seed);
289 seed = *configuredSeed;
290 log->info(1,
"User defined seed %1", seed);
298 if (randomEngineName ==
"DRand48Engine")
299 G4Random::setTheEngine(
new CLHEP::DRand48Engine(seed));
300 else if (randomEngineName ==
"DualRand")
301 G4Random::setTheEngine(
new CLHEP::DualRand(seed));
302 else if (randomEngineName ==
"Hurd160Engine")
303 G4Random::setTheEngine(
new CLHEP::Hurd160Engine(seed));
304 else if (randomEngineName ==
"HepJamesRandom")
305 G4Random::setTheEngine(
new CLHEP::HepJamesRandom(seed));
306 else if (randomEngineName ==
"MTwistEngine")
307 G4Random::setTheEngine(
new CLHEP::MTwistEngine(seed));
308 else if (randomEngineName ==
"MixMaxRng")
309 G4Random::setTheEngine(
new CLHEP::MixMaxRng(seed));
310 else if (randomEngineName ==
"RandEngine")
311 G4Random::setTheEngine(
new CLHEP::RandEngine(seed));
312 else if (randomEngineName ==
"RanecuEngine")
313 G4Random::setTheEngine(
new CLHEP::RanecuEngine(seed));
314 else if (randomEngineName ==
"Ranlux64Engine")
315 G4Random::setTheEngine(
new CLHEP::Ranlux64Engine(seed));
316 else if (randomEngineName ==
"RanluxEngine")
317 G4Random::setTheEngine(
new CLHEP::RanluxEngine(seed));
318 else if (randomEngineName ==
"RanshiEngine")
319 G4Random::setTheEngine(
new CLHEP::RanshiEngine(seed));
320 else if (randomEngineName ==
"Hurd288Engine")
321 G4Random::setTheEngine(
new CLHEP::Hurd288Engine(seed));
322 else if (randomEngineName ==
"TripleRand")
323 G4Random::setTheEngine(
new CLHEP::TripleRand(seed));
326 "Random engine >%1< not found. Exiting.", randomEngineName);
330 log->info(0,
"Starting random engine %1 with seed %2", randomEngineName, seed);
331 G4Random::setTheSeed(seed);
std::vector< std::string > addSceneTexts(const std::shared_ptr< GOptions > &gopts)
std::vector< std::string > addSceneDecorations(const std::shared_ptr< GOptions > &gopts)
std::vector< std::string > scene_commands(const std::shared_ptr< GOptions > &gopts)
Conventional constants used by GEMC utility helpers.
Utility helpers for runtime setup, command preparation, and random-engine initialization.
constexpr int EC__RANDOMENGINENOTFOUND
Error code used when the configured random engine name is not recognized.
void define_new_gemc_units()
std::vector< std::string > initial_commands(const std::shared_ptr< GOptions > &gopts, const std::shared_ptr< GLogger > &log, bool configure_visualization)
Build a list of Geant4 UI commands needed at startup.
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.
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.
void execute_macro(const std::string &filename, const std::shared_ptr< GLogger > &log)
Execute a Geant4 macro file, terminating with an error if it cannot complete.
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.
G4Light getG4Light(const std::shared_ptr< GOptions > &gopts)
G4View getG4View(const std::shared_ptr< GOptions > &gopts)
G4Camera getG4Camera(const std::shared_ptr< GOptions > &gopts)
G4Decorations getG4Decorations(const std::shared_ptr< GOptions > &gopts)
constexpr G4double milligray
constexpr G4double nanogray
constexpr G4double microgray
constexpr G4double picogray
GEMC runtime setup, command, and translation utilities.
constexpr int EC__NOOPTIONFOUND
double getG4Number(const string &v, bool warnIfNotUnit=false)
vector< std::string > getStringVectorFromString(const std::string &input)
constexpr char FATALERRORL[]