gsystem
Loading...
Searching...
No Matches
gworld.cc
Go to the documentation of this file.
1// gemc
2#include "gfactory.h"
3#include "gutilities.h"
4
5// gsystem
7#include "gworld.h"
8#include "gmodifier.h"
14
15// See gworld.h for API docs.
16
17// TODO: have getSystems returns the map directly instead of going through the vector
18GWorld::GWorld(const std::shared_ptr<GOptions>& g)
19 : GBase(g, GWORLD_LOGGER),
20 gopts(g) {
21 log->debug(NORMAL, "%1New", SFUNCTION_NAME);
22
23 // 1. Load system descriptors from options and build the internal map.
24 auto gsystems = gsystem::getSystems(gopts);
25 create_gsystemsMap(gsystems);
26
27 // 2. Load volumes/materials through factories, then apply modifiers, then finalize names.
28 load_systems(); // build factories, load volumes
29 load_gmodifiers(); // load & apply modifiers
30 assignG4Names(); // final bookkeeping
31}
32
33
34// Constructor with rvalue reference: perfect for taking ownership of move-only types
35GWorld::GWorld(const std::shared_ptr<GOptions>& g, SystemList gsystems)
36 : GBase(g, GWORLD_LOGGER),
37 gopts(g) {
38 log->debug(NORMAL, "%1From SystemList", SFUNCTION_NAME);
39
40 // 1. Adopt external systems and build internal map.
41 create_gsystemsMap(gsystems);
42
43 // 2. Finish world construction as in the main ctor.
44 load_systems(); // instantiate factories, load volumes
45 load_gmodifiers(); // load modifiers
46 assignG4Names(); // apply modifiers & set G4 names
47}
48
49
50// See gworld.h for API docs.
51std::map<std::string, std::unique_ptr<GSystemFactory>> GWorld::createSystemFactory() {
52 GManager manager(gopts);
53
54 std::map<std::string, std::unique_ptr<GSystemFactory>> factoryMap;
55
56 // Always register & create the SQLite factory (needed for ROOT volumes)
57 manager.RegisterObjectFactory<GSystemSQLiteFactory>(gsystem::GSYSTEMSQLITETFACTORYLABEL, gopts);
58 auto sqliteFactory = std::unique_ptr<GSystemFactory>(
60
61 if (!sqliteFactory) {
62 log->error(
63 gfactory::ERR_FACTORYNOTFOUND, "Failed to create factory <%1>",
65 }
66 factoryMap.emplace(gsystem::GSYSTEMSQLITETFACTORYLABEL, std::move(sqliteFactory));
67
68
69 // Scan all systems and create any missing factories
70 for (auto& [sysName, sysPtr] : *gsystemsMap) {
71 const std::string& facName = sysPtr->getFactoryName();
72
73 if (facName.empty()) {
74 log->error(
76 "Factory name for system <%1> is empty! This system will not be loaded.", sysName);
77 }
78
79 // Already have it? Move on.
80 if (factoryMap.count(facName)) continue;
81
82 //------------------ register the correct concrete class ----------------
84 manager.RegisterObjectFactory<GSystemCADFactory>(facName, gopts);
85 else if (facName == gsystem::GSYSTEMGDMLTFACTORYLABEL)
86 manager.RegisterObjectFactory<GSystemGDMLFactory>(facName, gopts);
87 else if (facName == gsystem::GSYSTEMSQLITETFACTORYLABEL)
88 manager.RegisterObjectFactory<GSystemSQLiteFactory>(facName, gopts);
89 else if (facName == gsystem::GSYSTEMASCIIFACTORYLABEL)
90 manager.RegisterObjectFactory<GSystemTextFactory>(facName, gopts);
91 else {
92 log->error(
93 gfactory::ERR_FACTORYNOTFOUND, "Unrecognized factory name <%1> for system <%2>", facName,
94 sysName);
95 }
96
97 //------------------ create the factory object --------------------------
98 auto facPtr = std::unique_ptr<GSystemFactory>(manager.CreateObject<GSystemFactory>(facName));
99
100 if (!facPtr) {
101 log->error(
102 gfactory::ERR_FACTORYNOTFOUND, "Failed to create factory <%1> for system <%2>", facName,
103 sysName);
104 }
105
106 factoryMap.emplace(facName, std::move(facPtr));
107 }
108
109 // Clean up any temporarily loaded shared libraries
110 manager.clearDLMap();
111
112 // Return by value (NRVO/move) – no leaks, no manual delete
113 return factoryMap;
114}
115
116
117// See gworld.h for API docs.
118GVolume* GWorld::searchForVolume(const std::string& volumeName, const std::string& purpose) const {
119 for (auto& systemPair : *gsystemsMap) {
120 GVolume* thisVolume = systemPair.second->getGVolume(volumeName);
121 if (thisVolume != nullptr) {
122 log->info(1, "gvolume named <%1> found with purpose: %2", volumeName, purpose);
123 return thisVolume;
124 }
125 }
126 // If volume not found, print error and exit.
127 log->error(
128 gsystem::ERR_GVOLUMENOTFOUND, "gvolume named <%1> (%2) not found in gsystemsMap %3", volumeName,
129 purpose, purpose);
130}
131
132
133// See gworld.h for API docs.
134std::vector<std::string> GWorld::getSensitiveDetectorsList() {
135 std::vector<std::string> snames;
136
137 // Walk all volumes and collect digitization identifiers, de-duplicating them.
138 for (auto& systemPair : *gsystemsMap) {
139 for (auto& gvolumePair : systemPair.second->getGVolumesMap()) {
140 const auto& digitization = gvolumePair.second->getDigitization();
141 if (digitization && find(snames.begin(), snames.end(), *digitization) == snames.end()) {
142 snames.push_back(*digitization);
143 }
144 }
145 }
146 return snames;
147}
148
149
150// See gworld.h for API docs.
151void GWorld::create_gsystemsMap(SystemList systems) {
152 // Clearing the map before using it ensures this method can be called by both constructors.
153 gsystemsMap->clear();
154
155 for (auto& sysPtr : systems) {
156 // Keying by filename (without path) keeps map keys stable across different path prefixes.
157 std::string key = gutilities::getFileFromPath(sysPtr->getName());
158 gsystemsMap->emplace(key, sysPtr);
159 }
160}
161
162
163// See gworld.h for API docs.
164void GWorld::load_systems() {
165 const std::string dbhost = gopts->getRequiredScalarString("sql");
166
167 auto systemFactories = createSystemFactory();
168 const bool no_systems_defined = gsystemsMap->empty();
169
170 // For every system, find / create its factory and load volumes
171 const auto yamlFiles = gopts->getYamlFiles();
172
173 for (auto& [sysName, sysPtr] : *gsystemsMap) {
174 const std::string& factoryName = sysPtr->getFactoryName();
175
176 if (factoryName.empty()) {
177 log->error(gfactory::ERR_FACTORYNOTFOUND, "Factory name for system <%1> is empty!", sysName);
178 }
179
180 auto facIt = systemFactories.find(factoryName);
181 if (facIt == systemFactories.end()) {
182 log->error(
183 gfactory::ERR_FACTORYNOTFOUND, "Factory <%1> not found for system <%2>", factoryName, sysName);
184 }
185
186 auto& factory = facIt->second; // std::unique_ptr<GSystemFactory>&
187 if (!factory) {
188 log->error(gfactory::ERR_FACTORYNOTFOUND, "Factory pointer <%1> is nullptr", factoryName);
189 }
190
191 // Feed YAML directories as possible file locations.
192 // This allows factories to find external assets alongside YAML configurations.
193 for (const auto& yaml : yamlFiles) {
194 std::string dir = gutilities::getDirFromPath(yaml);
195 if (dir.empty())
196 log->warning("Directory extracted from YAML <%1> is empty.", yaml);
197 factory->addPossibleFileLocation(dir);
198 }
199
200 // Load & close the system.
201 factory->loadSystem(sysPtr.get());
202 factory->closeSystem();
203 }
204
205
206 // loop over gsystemsMap looking for gsystem::ROOTWORLDGVOLUMENAME
207 auto world_is_defined = false;
208 for (auto& [sysName, sysPtr] : *gsystemsMap) {
209 // for each system run getGVolume(gsystem::ROOTWORLDGVOLUMENAME)
210 if (sysPtr->getGVolume(gsystem::ROOTWORLDGVOLUMENAME) != nullptr) {
211 log->info(1, "ROOT world volume found in system <%1>", sysName);
212 world_is_defined = true;
213 }
214 }
215
216 if (!world_is_defined) {
217 // Inject the ROOT “world” volume, if not already present.
218 // This ensures downstream volume placement always has a valid top-level mother.
219 const std::string worldVolumeDefinition =
220 gopts->getRequiredScalarString(gsystem::ROOTWORLDGVOLUMENAME);
221
222 auto rootSystem = std::make_shared<GSystem>(
223 gopts, // logger
224 dbhost,
225 gsystem::ROOTWORLDGVOLUMENAME, // name + path
227 "all", // experiment
228 1, // runNo
229 "default" // variation
230 );
231 rootSystem->addROOTVolume(worldVolumeDefinition);
232
233 if (no_systems_defined) {
234 std::vector<std::string> viewerBoxPars = {
235 "viewer_box", // 01 name
236 "G4Box", // 02 type
237 "1*m, 1*m, 1*m", // 03 parameters
238 "G4_AIR", // 04 material
240 gsystem::DEFAULTPOSITION, // 06 position
241 gsystem::DEFAULTROTATION, // 07 rotation
242 gsystem::DEFAULTG4PLACEMENTTYPE, // 08 Geant4 placement
243 guts::SERIALIZED_NULL_TOKEN, // 09 electromagnetic field
244 "1", // 10 visible
245 "0", // 11 style: wireframe
246 "ffcc33", // 12 color
247 "1", // 13 opacity
248 guts::SERIALIZED_NULL_TOKEN, // 14 digitization
249 guts::SERIALIZED_NULL_TOKEN, // 15 gidentity
250 guts::SERIALIZED_NULL_TOKEN, // 16 copyOf
251 guts::SERIALIZED_NULL_TOKEN, // 17 solidsOpr
252 guts::SERIALIZED_NULL_TOKEN, // 18 mirror
253 "1", // 19 exist flag
254 "default visible volume for field-only visualization"
255 };
256 rootSystem->addGVolume(viewerBoxPars);
257 }
258
259 (*gsystemsMap)[gsystem::ROOTWORLDGVOLUMENAME] = rootSystem;
260 }
261
262 // systemFactories goes out of scope -> all factories destroyed cleanly
263}
264
265
266// See gworld.h for API docs.
267void GWorld::load_gmodifiers() {
268 // Build the map <volumeName → shared_ptr<GModifier>>
269 for (const auto& mod : gsystem::getModifiers(gopts)) // returns vector<GModifier>
270 {
271 auto modPtr = std::make_shared<GModifier>(mod);
272 gmodifiersMap.emplace(modPtr->getName(), modPtr);
273 }
274
275 // Apply every modifier to its target volume
276 for (auto& [volumeName, modPtr] : gmodifiersMap) // modPtr is shared_ptr<GModifier>
277 {
278 // Will exit if not found:
279 GVolume* vol = searchForVolume(volumeName,
280 " is marked for modifications");
281
282 vol->applyShift(modPtr->getShift());
283 vol->applyTilt(modPtr->getTilts());
284 vol->modifyExistence(modPtr->getExistence());
285
286 log->info(2, "g-modifying volume <%1> with modifier: %2", volumeName, *modPtr);
287 log->info(2, "After modifications:%1", *vol);
288 }
289}
290
291
292// See gworld.h for API docs.
293void GWorld::assignG4Names() {
294 for (auto& systemPair : *gsystemsMap) {
295 for (auto& [volumeName, gvolume] : systemPair.second->getGVolumesMap()) {
296 // Skip if the volume's mother is "akasha" (top-level marker) or if this is the ROOT world volume itself.
297 std::string motherVolumeName = gvolume->getMotherName();
298 if (motherVolumeName != gsystem::MOTHEROFUSALL && volumeName != gsystem::ROOTWORLDGVOLUMENAME) {
299 // Mother lookup is required to build fully-qualified mother name.
300 auto motherVolume = searchForVolume(motherVolumeName, "mother of <" + gvolume->getName() + ">");
301 std::string g4name = gvolume->getSystem() + gsystem::GSYSTEM_DELIMITER + volumeName;
302 std::string g4motherName = motherVolume->getSystem() + gsystem::GSYSTEM_DELIMITER + motherVolumeName;
303
304 // ROOT mother is a special case: its Geant4 name is exactly gsystem::ROOTWORLDGVOLUMENAME.
305 if (motherVolumeName == gsystem::ROOTWORLDGVOLUMENAME) { g4motherName = gsystem::ROOTWORLDGVOLUMENAME; }
306
307 gvolume->assignG4Names(g4name, g4motherName);
308 }
309 else {
310 // Top-level volumes are assigned ROOT/world and akasha markers.
312 }
313 }
314 }
315}
GBase(const std::shared_ptr< GOptions > &gopt, std::string logger_name="")
std::shared_ptr< GLogger > log
Abstract base class for loading a GSystem from a specific source.
Load a GSystem from a sqlite database.
Geometry volume record loaded into a GSystem.
Definition gvolume.h:36
void applyTilt(std::optional< std::string > t)
Apply an additional rotation to this volume.
Definition gvolume.h:245
void applyShift(std::optional< std::string > s)
Apply an additional translation to this volume.
Definition gvolume.h:235
void modifyExistence(bool e)
Enable or disable this volume in the final assembled world.
Definition gvolume.h:255
std::vector< std::string > getSensitiveDetectorsList()
Collect the list of sensitive detector identifiers.
Definition gworld.cc:134
GWorld(const std::shared_ptr< GOptions > &gopts)
Construct the world from configuration.
Definition gworld.cc:18
#define SFUNCTION_NAME
NORMAL
Conventions and shared constants for the detector-system module.
std::vector< SystemPtr > SystemList
Definition gsystem.h:280
constexpr const char * GWORLD_LOGGER
constexpr int ERR_FACTORYNOTFOUND
constexpr char GSYSTEMGDMLTFACTORYLABEL[]
constexpr char DEFAULTG4PLACEMENTTYPE[]
constexpr char GSYSTEMCADTFACTORYLABEL[]
constexpr char GSYSTEM_DELIMITER[]
Delimiter used to build fully-qualified names (system/name).
constexpr char DEFAULTROTATION[]
constexpr char GSYSTEMSQLITETFACTORYLABEL[]
constexpr char MOTHEROFUSALL[]
Special mother-name marker for the top-level world root.
constexpr char DEFAULTPOSITION[]
constexpr char GSYSTEMASCIIFACTORYLABEL[]
std::vector< GModifier > getModifiers(const std::shared_ptr< GOptions > &gopts)
Build a list of volume modifiers from options.
constexpr char ROOTWORLDGVOLUMENAME[]
Canonical name for the ROOT/world gvolume entry.
SystemList getSystems(const std::shared_ptr< GOptions > &gopts)
Build a list of systems from options.
constexpr int ERR_GVOLUMENOTFOUND
string getDirFromPath(const std::string &path)
string getFileFromPath(const std::string &path)
constexpr char SERIALIZED_NULL_TOKEN[]