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) {
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, SFUNCTION_NAME, "From SystemList");
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>(GSYSTEMSQLITETFACTORYLABEL, gopts);
58 auto sqliteFactory = std::unique_ptr<GSystemFactory>(
59 manager.CreateObject<GSystemFactory>(GSYSTEMSQLITETFACTORYLABEL));
60
61 if (!sqliteFactory) {
62 log->error(ERR_FACTORYNOTFOUND,
63 "Failed to create factory <", GSYSTEMSQLITETFACTORYLABEL, ">");
64 }
65 factoryMap.emplace(GSYSTEMSQLITETFACTORYLABEL, std::move(sqliteFactory));
66
67
68 // Scan all systems and create any missing factories
69 for (auto& [sysName, sysPtr] : *gsystemsMap) {
70 const std::string& facName = sysPtr->getFactoryName();
71
72 if (facName.empty()) {
73 log->error(ERR_FACTORYNOTFOUND,
74 "Factory name for system <", sysName,
75 "> is empty! This system will not be loaded.");
76 }
77
78 // Already have it? Move on.
79 if (factoryMap.count(facName)) continue;
80
81 //------------------ register the correct concrete class ----------------
82 if (facName == GSYSTEMCADTFACTORYLABEL)
83 manager.RegisterObjectFactory<GSystemCADFactory>(facName, gopts);
84 else if (facName == GSYSTEMGDMLTFACTORYLABEL)
85 manager.RegisterObjectFactory<GSystemGDMLFactory>(facName, gopts);
86 else if (facName == GSYSTEMSQLITETFACTORYLABEL)
87 manager.RegisterObjectFactory<GSystemSQLiteFactory>(facName, gopts);
88 else if (facName == GSYSTEMASCIIFACTORYLABEL)
89 manager.RegisterObjectFactory<GSystemTextFactory>(facName, gopts);
90 else {
91 log->error(ERR_FACTORYNOTFOUND,
92 "Unrecognized factory name <", facName,
93 "> for system <", sysName, ">");
94 }
95
96 //------------------ create the factory object --------------------------
97 auto facPtr = std::unique_ptr<GSystemFactory>(manager.CreateObject<GSystemFactory>(facName));
98
99 if (!facPtr) {
100 log->error(ERR_FACTORYNOTFOUND,
101 "Failed to create factory <", facName,
102 "> for system <", sysName, ">");
103 }
104
105 factoryMap.emplace(facName, std::move(facPtr));
106 }
107
108 // Clean up any temporarily loaded shared libraries
109 manager.clearDLMap();
110
111 // Return by value (NRVO/move) – no leaks, no manual delete
112 return factoryMap;
113}
114
115
116// See gworld.h for API docs.
117GVolume* GWorld::searchForVolume(const std::string& volumeName, const std::string& purpose) const {
118 for (auto& systemPair : *gsystemsMap) {
119 GVolume* thisVolume = systemPair.second->getGVolume(volumeName);
120 if (thisVolume != nullptr) {
121 log->info(1, "gvolume named <", volumeName, "> found with purpose: ", purpose);
122 return thisVolume;
123 }
124 }
125 // If volume not found, print error and exit.
127 "gvolume named <", volumeName, "> (", purpose, ") not found in gsystemsMap ", purpose);
128}
129
130
131// See gworld.h for API docs.
132std::vector<std::string> GWorld::getSensitiveDetectorsList() {
133 std::vector<std::string> snames;
134
135 // Walk all volumes and collect digitization identifiers, de-duplicating them.
136 for (auto& systemPair : *gsystemsMap) {
137 for (auto& gvolumePair : systemPair.second->getGVolumesMap()) {
138 std::string digitization = gvolumePair.second->getDigitization();
139 if (digitization != "" && digitization != UNINITIALIZEDSTRINGQUANTITY) {
140 if (find(snames.begin(), snames.end(), digitization) == snames.end())
141 snames.push_back(digitization);
142 }
143 }
144 }
145 return snames;
146}
147
148
149// See gworld.h for API docs.
150void GWorld::create_gsystemsMap(SystemList systems) {
151 // Clearing the map before using it ensures this method can be called by both constructors.
152 gsystemsMap->clear();
153
154 for (auto& sysPtr : systems) {
155 // Keying by filename (without path) keeps map keys stable across different path prefixes.
156 std::string key = gutilities::getFileFromPath(sysPtr->getName());
157 gsystemsMap->emplace(key, sysPtr);
158 }
159}
160
161
162// See gworld.h for API docs.
163void GWorld::load_systems() {
164 const std::string dbhost = gopts->getScalarString("sql");
165
166 auto systemFactories = createSystemFactory();
167
168 // For every system, find / create its factory and load volumes
169 const auto yamlFiles = gopts->getYamlFiles();
170
171 for (auto& [sysName, sysPtr] : *gsystemsMap) {
172 const std::string& factoryName = sysPtr->getFactoryName();
173
174 if (factoryName.empty()) {
175 log->error(ERR_FACTORYNOTFOUND,
176 "Factory name for system <", sysName, "> is empty!");
177 }
178
179 auto facIt = systemFactories.find(factoryName);
180 if (facIt == systemFactories.end()) {
181 log->error(ERR_FACTORYNOTFOUND,
182 "Factory <", factoryName, "> not found for system <", sysName, ">");
183 }
184
185 auto& factory = facIt->second; // std::unique_ptr<GSystemFactory>&
186 if (!factory) {
187 log->error(ERR_FACTORYNOTFOUND,
188 "Factory pointer <", factoryName, "> is nullptr");
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 <", yaml, "> is empty.");
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 ROOTWORLDGVOLUMENAME
207 auto world_is_defined = false;
208 for (auto& [sysName, sysPtr] : *gsystemsMap) {
209 // for each system run getGVolume(ROOTWORLDGVOLUMENAME)
210 if (sysPtr->getGVolume(ROOTWORLDGVOLUMENAME) != nullptr) {
211 log->info(1, "ROOT world volume found in system <", 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 = gopts->getScalarString(ROOTWORLDGVOLUMENAME);
220
221 auto rootSystem = std::make_shared<GSystem>(
222 gopts, // logger
223 dbhost,
224 ROOTWORLDGVOLUMENAME, // name + path
226 "all", // experiment
227 1, // runNo
228 "default" // variation
229 );
230 rootSystem->addROOTVolume(worldVolumeDefinition);
231
232 (*gsystemsMap)[ROOTWORLDGVOLUMENAME] = rootSystem;
233 }
234
235 // systemFactories goes out of scope -> all factories destroyed cleanly
236}
237
238
239// See gworld.h for API docs.
240void GWorld::load_gmodifiers() {
241 // Build the map <volumeName → shared_ptr<GModifier>>
242 for (const auto& mod : gsystem::getModifiers(gopts)) // returns vector<GModifier>
243 {
244 auto modPtr = std::make_shared<GModifier>(mod);
245 gmodifiersMap.emplace(modPtr->getName(), modPtr);
246 }
247
248 // Apply every modifier to its target volume
249 for (auto& [volumeName, modPtr] : gmodifiersMap) // modPtr is shared_ptr<GModifier>
250 {
251 // Will exit if not found:
252 GVolume* vol = searchForVolume(volumeName,
253 " is marked for modifications");
254
255 vol->applyShift(modPtr->getShift());
256 vol->applyTilt(modPtr->getTilts());
257 vol->modifyExistence(modPtr->getExistence());
258
259 log->info(2, "g-modifying volume <", volumeName,
260 "> with modifier: ", *modPtr);
261 log->info(2, "After modifications:", *vol);
262 }
263}
264
265
266// See gworld.h for API docs.
267void GWorld::assignG4Names() {
268 for (auto& systemPair : *gsystemsMap) {
269 for (auto& [volumeName, gvolume] : systemPair.second->getGVolumesMap()) {
270 // Skip if the volume's mother is "akasha" (top-level marker) or if this is the ROOT world volume itself.
271 std::string motherVolumeName = gvolume->getMotherName();
272 if (motherVolumeName != MOTHEROFUSALL && volumeName != ROOTWORLDGVOLUMENAME) {
273 // Mother lookup is required to build fully-qualified mother name.
274 auto motherVolume = searchForVolume(motherVolumeName, "mother of <" + gvolume->getName() + ">");
275 std::string g4name = gvolume->getSystem() + GSYSTEM_DELIMITER + volumeName;
276 std::string g4motherName = motherVolume->getSystem() + GSYSTEM_DELIMITER + motherVolumeName;
277
278 // ROOT mother is a special case: its Geant4 name is exactly ROOTWORLDGVOLUMENAME.
279 if (motherVolumeName == ROOTWORLDGVOLUMENAME) { g4motherName = ROOTWORLDGVOLUMENAME; }
280
281 gvolume->assignG4Names(g4name, g4motherName);
282 }
283 else {
284 // Top-level volumes are assigned ROOT/world and akasha markers.
285 gvolume->assignG4Names(ROOTWORLDGVOLUMENAME, MOTHEROFUSALL);
286 }
287 }
288 }
289}
std::shared_ptr< GLogger > log
void warning(Args &&... args) const
void debug(debug_type type, Args &&... args) const
void info(int level, Args &&... args) const
void error(int exit_code, Args &&... args) const
std::string getScalarString(const std::string &tag) const
std::vector< std::string > getYamlFiles() const
Load a system from CAD assets (e.g. STL) found in a directory.
Abstract base class for loading a GSystem from a specific source.
Placeholder factory for GDML-based systems.
Load a GSystem from a sqlite database.
Load a system from ASCII text files.
Geometry volume record loaded into a GSystem.
Definition gvolume.h:33
void modifyExistence(bool e)
Enable or disable this volume in the final assembled world.
Definition gvolume.h:236
void applyTilt(std::string t)
Apply an additional rotation to this volume.
Definition gvolume.h:226
void applyShift(std::string s)
Apply an additional translation to this volume.
Definition gvolume.h:216
std::vector< std::string > getSensitiveDetectorsList()
Collect the list of sensitive detector identifiers.
Definition gworld.cc:132
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.
#define GSYSTEMSQLITETFACTORYLABEL
#define GSYSTEMCADTFACTORYLABEL
#define GSYSTEMASCIIFACTORYLABEL
#define GSYSTEM_DELIMITER
Delimiter used to build fully-qualified names (system/name).
#define ERR_GVOLUMENOTFOUND
#define ROOTWORLDGVOLUMENAME
Canonical name for the ROOT/world gvolume entry.
#define MOTHEROFUSALL
Special mother-name marker for the top-level world root.
#define GSYSTEMGDMLTFACTORYLABEL
std::vector< SystemPtr > SystemList
Definition gsystem.h:237
constexpr const char * GWORLD_LOGGER
#define UNINITIALIZEDSTRINGQUANTITY
std::vector< GModifier > getModifiers(const std::shared_ptr< GOptions > &gopts)
Build a list of volume modifiers from options.
SystemList getSystems(const std::shared_ptr< GOptions > &gopts)
Build a list of systems from options.
string getDirFromPath(const std::string &path)
string getFileFromPath(const std::string &path)