REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestGeant4GeometryInfo.cxx
1//
2// Created by lobis on 3/5/2022.
3//
4
5#include "TRestGeant4GeometryInfo.h"
6
7#include <TPRegexp.h>
8#include <TXMLEngine.h>
9
10#include <iostream>
11
12#include "TRestStringHelper.h"
13
14using namespace std;
15
16namespace myXml {
17XMLNodePointer_t FindChildByName(TXMLEngine xml, XMLNodePointer_t node, const TString& name) {
18 XMLNodePointer_t child = xml.GetChild(node);
19 while (child) {
20 TString childName = xml.GetNodeName(child);
21 if (childName.EqualTo(name)) {
22 return child;
23 }
24 child = xml.GetNext(child);
25 }
26 return nullptr;
27}
28TString GetNodeAttribute(TXMLEngine xml, XMLNodePointer_t node, const TString& attributeName) {
29 XMLAttrPointer_t attr = xml.GetFirstAttr(node);
30 while (attr) {
31 if (TString(xml.GetAttrName(attr)).EqualTo(attributeName)) {
32 TString refName = xml.GetAttrValue(attr);
33 return refName;
34 }
35 attr = xml.GetNextAttr(attr);
36 }
37 return {};
38}
39XMLNodePointer_t GetChildByAttributeValue(TXMLEngine xml, XMLNodePointer_t node, const TString& attributeName,
40 const TString& attributeValue) {
41 XMLNodePointer_t child = xml.GetChild(node);
42 while (child) {
43 TString childAttributeValue = GetNodeAttribute(xml, child, attributeName);
44 if (childAttributeValue.EqualTo(attributeValue)) {
45 return child;
46 }
47 child = xml.GetNext(child);
48 }
49 return nullptr;
50}
51void AddVolumesRecursively(vector<TString>* physicalNames, vector<TString>* logicalNames,
52 const vector<TString>& children, map<TString, TString>& nameTable,
53 map<TString, vector<TString>>& childrenTable, const TString& name = "",
54 const TString& separator = "_") {
55 if (children.empty()) {
56 physicalNames->push_back(name);
57 const auto logicalVolumeName = nameTable[name];
58 logicalNames->push_back(logicalVolumeName);
59 return;
60 }
61 for (const auto& childName : children) {
62 const auto newName = name + separator + childName;
63 nameTable[newName] = nameTable[childName]; // needed to retrieve logical volume name
64 AddVolumesRecursively(physicalNames, logicalNames, childrenTable[nameTable[childName]], nameTable,
65 childrenTable, newName, separator);
66 }
67}
68} // namespace myXml
69
70void TRestGeant4GeometryInfo::PopulateFromGdml(const TString& gdmlFilename) {
71 /*
72 * Fills 'fGdmlNewPhysicalNames' with physical volume names generated from GDML
73 */
74 cout << "TRestGeant4GeometryInfo::PopulateFromGdml - " << gdmlFilename << endl;
75 // Geometry must be in GDML
76 TXMLEngine xml;
77 XMLDocPointer_t xmldoc = xml.ParseFile(gdmlFilename.Data());
78 if (!xmldoc) {
79 cout << "TRestGeant4GeometryInfo::PopulateFromGdml - GDML file " << gdmlFilename.Data()
80 << " not found" << endl;
81 exit(1);
82 }
83 XMLNodePointer_t mainNode = xml.DocGetRootElement(xmldoc);
84 XMLNodePointer_t structure = myXml::FindChildByName(xml, mainNode, "structure");
85 XMLNodePointer_t child = xml.GetChild(structure);
86
87 /* When a PV is placed from an assembly, its daughter physical volumes are imprinted into the mother
88 volume where you are placing the assembly. This daughter PV are named following the format:
89 "av_WWW_impr_XXX_YYY_ZZZ". This first loop over the gdml structure is to get the map "assemblyName" ->
90 "av_WWW"
91 */
92 size_t assemblyCounter = 0; // track the WWW
93 map<TString, TString> gdmlToGeant4AssemblyNameMap; // e.g. "assemblyName" -> "av_1"
94 map<TString, size_t> gdmlAssemblyNameToImprintCounterMap; // to track the number of imprints per assembly
95 RESTDebug << "Searching for assemblies..." << RESTendl;
96 while (child) { // loop over the direct children of structure (logical volumes and assemblies)
97 TString name = xml.GetNodeName(child); // name of the type of children: "volume" or "assembly"
98 if (!name.EqualTo("assembly")) {
99 child = xml.GetNext(child);
100 continue;
101 }
102 TString assemblyName = myXml::GetNodeAttribute(xml, child, "name");
103 gdmlToGeant4AssemblyNameMap[assemblyName] =
104 "av_" + to_string(++assemblyCounter); // first assembly is av_1
105 gdmlAssemblyNameToImprintCounterMap[assemblyName] = 0; // initialize with the assembly found
106 RESTDebug << "Assembly found: " << assemblyName << " → " << gdmlToGeant4AssemblyNameMap[assemblyName]
107 << RESTendl;
108
109 /* The daughter physical volumes defined after a nested assembly gets the imprint number XXX+1
110 instead of the XXX of its mother assembly imprint (which I think is a bug in Geant4).
111 To avoid having several "av_WWW_impr_XXX+n" pointing to different GDML names,
112 you must define all the daughter PV from normal LV before all the nested assembly PV.*/
113 bool hasNestedAssemblies = false;
114 std::map<TString, TString> childrenGeant4toGdmlMap;
115 size_t childrenPVCounter = 0;
116 auto physicalVolumeNode =
117 xml.GetChild(child); // children of a volume or assembly are physical volumes
118 while (physicalVolumeNode) {
119 auto physicalVolumeName = myXml::GetNodeAttribute(xml, physicalVolumeNode, "name");
120 auto volumeRefNode =
121 xml.GetChild(physicalVolumeNode); // this are volumeref, position and rotation
122 while (volumeRefNode) {
123 TString volumeRefNodeName =
124 xml.GetNodeName(volumeRefNode); // "volumeref", "position" or "rotation"
125 if (volumeRefNodeName.EqualTo("volumeref")) {
126 TString refName =
127 myXml::GetNodeAttribute(xml, volumeRefNode, "ref"); // the logical volume name
128 TString geant4Name =
129 refName + "_pv_" +
130 to_string(childrenPVCounter++); // first pv is logicalVolumeName_pv_0
131 childrenGeant4toGdmlMap[geant4Name] = physicalVolumeName;
132 if (gdmlToGeant4AssemblyNameMap.count(refName) > 0) {
133 hasNestedAssemblies = true;
134 } else {
135 if (hasNestedAssemblies) {
136 RESTError << "TRestGeant4GeometryInfo::PopulateFromGdml - Assembly '"
137 << assemblyName << "' contains physical volumes from normal "
138 << "(i.e. non-assembly) logical volumes defined after physical volumes "
139 << "from assemblies. Due to a Geant4 bug you cannot do this. "
140 << "Please define the physical volumes from the assemblies last."
141 << RESTendl;
142 }
143 }
144 }
145 volumeRefNode = xml.GetNext(volumeRefNode);
146 }
147 physicalVolumeNode = xml.GetNext(physicalVolumeNode);
148 }
149 fGdmlAssemblyToChildrenGeant4ToGdmlPhysicalNameMap[assemblyName] = childrenGeant4toGdmlMap;
150 child = xml.GetNext(child);
151 }
152
153 /*Recursive function to obtain the prefix 'av_WWW_impr_XXX' of the daughters of the assemblies imprints.
154 When a PV is placed from an assembly, its daughter physical volumes are imprinted into the mother
155 volume where you are placing the assembly. This daughter PV are named following the format:
156 "av_WWW_impr_XXX_YYY_ZZZ". But, if one of those daughter PV is itself an assembly, its own daughter PV are
157 named (wrongly in my opinion) "av_WWW_impr_XXX+1_yyy_zzz". This behavior is propagated down the chain
158 to the final child assembly which does not have any daughter assembly. So, the godFatherAssembly is the
159 highest assembly which begins this chain and its "av_WWW" is used for all its consecutive assembly
160 children imprints and each of this assembly children adds +1 to the imprint number of the
161 godFatherAssembly.*/
162 std::function<void(const XMLNodePointer_t, const TString, TString)> ProcessNestedAssembliesRecursively =
163 [&](const XMLNodePointer_t parentNode, const TString godFatherAssemblyName, const TString pathSoFar) {
164 auto physicalVolumeNode = xml.GetChild(parentNode);
165 // godFatherAssemblyName = parentNode logical name // the highest assembly volume in the nested
166 // chain
167 while (physicalVolumeNode) {
168 auto physicalVolumeName = myXml::GetNodeAttribute(xml, physicalVolumeNode, "name");
169 auto volumeRefNode =
170 xml.GetChild(physicalVolumeNode); // this are volumeref, position and rotation
171 while (volumeRefNode) {
172 TString volumeRefNodeName =
173 xml.GetNodeName(volumeRefNode); // "volumeref", "position" or "rotation"
174 if (volumeRefNodeName.EqualTo("volumeref")) {
175 TString refName =
176 myXml::GetNodeAttribute(xml, volumeRefNode, "ref"); // the logical volume name
177 if (gdmlToGeant4AssemblyNameMap.count(refName) > 0) {
178 // it's an assembly
179 TString newGodFatherAssemblyName = godFatherAssemblyName;
180 if (newGodFatherAssemblyName.IsNull()) {
181 // start assembly children chain with this assembly as godFather
182 newGodFatherAssemblyName = refName;
183 }
184 size_t imprintCounter =
185 ++gdmlAssemblyNameToImprintCounterMap[newGodFatherAssemblyName];
186 TString imprint = gdmlToGeant4AssemblyNameMap[newGodFatherAssemblyName] +
187 "_impr_" + to_string(imprintCounter);
188 TString path =
189 pathSoFar + (pathSoFar.IsNull() ? "" : fPathSeparator) + physicalVolumeName;
191 // Continue the assembly children chain with its correspondant godFatherAssembly
192 // and path
193 auto assemblyNode =
194 myXml::GetChildByAttributeValue(xml, structure, "name", refName);
195 ProcessNestedAssembliesRecursively(assemblyNode, newGodFatherAssemblyName, path);
196 } else {
197 // its a regular logical volume
198 // Regular children resets the godFatherAssembly and path
199 auto assemblyNode =
200 myXml::GetChildByAttributeValue(xml, structure, "name", refName);
201 ProcessNestedAssembliesRecursively(assemblyNode, "", "");
202 }
203 }
204 volumeRefNode = xml.GetNext(volumeRefNode);
205 }
206 physicalVolumeNode = xml.GetNext(physicalVolumeNode);
207 }
208 };
209
210 // We loop a second time over the gdml structure to get the imprint of each assembly
211 // into fGeant4AssemblyImprintToGdmlNameMap: e.g. "av_2_impr_5" -> "shielding/vessel"
212 auto worldNode = myXml::GetChildByAttributeValue(xml, structure, "name", "world");
213 if (!worldNode) {
214 worldNode = myXml::GetChildByAttributeValue(xml, structure, "name", "World");
215 if (!worldNode) {
216 cout << "Could not find world volume in GDML, please name it either 'World' or 'world'" << endl;
217 exit(1);
218 }
219 }
220 TString godFatherAssemblyName = ""; // the highest assembly volume in the nested chain
221 TString pathSoFar = ""; // the path for the nested assemblies
222 ProcessNestedAssembliesRecursively(worldNode, godFatherAssemblyName, pathSoFar);
223
224 // We loop a third time over gdml structure to get the physical and logical volumes names
225 map<TString, TString> nameTable;
226 map<TString, vector<TString>> childrenTable;
227 child = xml.GetChild(structure);
228 while (child) { // loop over the direct children of structure (logical volumes and assemblies)
229 TString name = xml.GetNodeName(child); // name of the type of children: "volume" or "assembly"
230 TString volumeName = myXml::GetNodeAttribute(xml, child, "name");
231 auto physicalVolumeNode =
232 xml.GetChild(child); // children of a volume or assembly are physical volumes
233 childrenTable[volumeName] = {};
234 while (physicalVolumeNode) {
235 auto physicalVolumeName = myXml::GetNodeAttribute(xml, physicalVolumeNode, "name");
236 auto volumeRefNode =
237 xml.GetChild(physicalVolumeNode); // this are volumeref, position and rotation
238 while (volumeRefNode) {
239 TString volumeRefNodeName =
240 xml.GetNodeName(volumeRefNode); // "volumeref", "position" or "rotation"
241 if (volumeRefNodeName.EqualTo("volumeref")) {
242 TString refName =
243 myXml::GetNodeAttribute(xml, volumeRefNode, "ref"); // the logical volume name
244 nameTable[physicalVolumeName] = refName;
245 childrenTable[volumeName].push_back(physicalVolumeName);
246 if (gdmlToGeant4AssemblyNameMap.count(refName) > 0) {
247 fGeant4AssemblyImprintToAssemblyLogicalNameMap[physicalVolumeName] = refName;
248 }
249 }
250 volumeRefNode = xml.GetNext(volumeRefNode);
251 }
252 physicalVolumeNode = xml.GetNext(physicalVolumeNode);
253 }
254 child = xml.GetNext(child);
255 }
256
257 string worldVolumeName = "world";
258 if (childrenTable.count(worldVolumeName) == 0) {
259 worldVolumeName = "World";
260 if (childrenTable.count(worldVolumeName) == 0) {
261 cout << "Could not find world volume in GDML, please name it either 'World' or 'world'";
262 exit(1);
263 }
264 }
265
266 fGdmlNewPhysicalNames.clear();
267 fGdmlLogicalNames.clear();
268 for (const auto& topName : childrenTable[worldVolumeName]) {
269 auto children = childrenTable[nameTable[topName]];
270 myXml::AddVolumesRecursively(&fGdmlNewPhysicalNames, &fGdmlLogicalNames, children, nameTable,
271 childrenTable, topName, fPathSeparator);
272 }
273
274 xml.FreeDoc(xmldoc);
275
276 // Checks
277 if (fGdmlNewPhysicalNames.empty()) {
278 cout << "TRestGeant4GeometryInfo::PopulateFromGdml - ERROR - No physical volumes have been added!"
279 << endl;
280 exit(1);
281 }
282 // Find duplicates
283 set<TString> s;
284 for (const auto& name : fGdmlNewPhysicalNames) {
285 s.insert(name);
286 }
287 if (s.size() != fGdmlNewPhysicalNames.size()) {
288 cout << "TRestGeant4GeometryInfo::PopulateFromGdml - ERROR - Generated a duplicate name, please "
289 "check assembly"
290 << endl;
291 exit(1);
292 }
293
294 /*
295 // print gdmlToGeant4AssemblyNameMap
296 cout << "GDML to Geant4 Assembly Name Map:" << endl;
297 for (const auto& kv : gdmlToGeant4AssemblyNameMap) {
298 cout << "\t" << kv.first << " → " << kv.second << endl;
299 }
300
301 //print gdmlAssemblyNameToImprintCounterMap
302 cout << "GDML Assembly Name to Imprint Counter Map:" << endl;
303 for (const auto& kv : gdmlAssemblyNameToImprintCounterMap) {
304 cout << "\t" << kv.first << " → " << kv.second << endl;
305 }
306
307 //print fGeant4AssemblyImprintToGdmlNameMap
308 cout << "GDML Assembly Imprint to GDML Name Map:" << endl;
309 for (const auto& kv : fGeant4AssemblyImprintToGdmlNameMap) {
310 cout << "\t" << kv.first << " → " << kv.second << endl;
311 }
312
313 cout << "GDML assembly children Geant4 to GDML Physical Name Map:" << endl;
314 for (const auto& kv : fGdmlAssemblyToChildrenGeant4ToGdmlPhysicalNameMap) {
315 cout << "\tAssembly: " << kv.first << endl;
316 for (const auto& childKv : kv.second) {
317 cout << "\t\t" << childKv.first << " → " << childKv.second << endl;
318 }
319 }
320
321 cout << "Assembly imprint to Assembly Logical Name Map:" << endl;
322 for (const auto& kv : fGeant4AssemblyImprintToAssemblyLogicalNameMap) {
323 cout << "\t" << kv.first << " → " << kv.second << endl;
324 }
325 */
326}
327
335TString TRestGeant4GeometryInfo::GetAlternativePathFromGeant4Path(const TString& geant4Path) const {
336 std::string convertedPath = geant4Path.Data();
337 // convert the Geant4 assembly imprint convention to GDML name
338 // e.g. av_1_impr_2_childLV_pv_1 → assemblyName/childLV_pv_1
339 for (const auto& [gvName, gdmlName] : fGeant4AssemblyImprintToGdmlNameMap) {
340 convertedPath = Replace(convertedPath, (gvName + "_").Data(), (gdmlName + fPathSeparator).Data());
341 }
342 // convert the children names inside assemblies to physical volume names in GDML
343 // e.g. assemblyName/childLV_pv_1 → assemblyName/childPVname
344 for (const auto& [gvImprint, assemblyLogicalName] : fGeant4AssemblyImprintToAssemblyLogicalNameMap) {
345 auto gvImprintPosition = convertedPath.find(gvImprint.Data());
346 if (gvImprintPosition != std::string::npos) {
347 for (const auto& [childGeant4Name, childGdmlName] :
349 TString toReplace = gvImprint + fPathSeparator + childGeant4Name;
350 TString replaceBy = gvImprint + fPathSeparator + childGdmlName;
351 convertedPath = Replace(convertedPath, toReplace.Data(), replaceBy.Data());
352 }
353 }
354 }
355 return TString(convertedPath);
356}
357
370 const TString& geant4PhysicalName) const {
371 for (const auto& kv : fNewPhysicalToGeant4PhysicalNameMap) {
372 if (kv.second.EqualTo(geant4PhysicalName)) {
373 return kv.first;
374 }
375 }
376 return geant4PhysicalName;
377}
378
390 const TString& geant4PhysicalName) const {
391 set<TString> alternativeNames;
392 for (const auto& kv : fNewPhysicalToGeant4PhysicalNameMap) {
393 if (kv.second.EqualTo(geant4PhysicalName)) {
394 alternativeNames.insert(kv.first);
395 }
396 }
397 return alternativeNames;
398}
399
400TString TRestGeant4GeometryInfo::GetGeant4PhysicalNameFromAlternativeName(
401 const TString& alternativeName) const {
402 if (fNewPhysicalToGeant4PhysicalNameMap.count(alternativeName) > 0) {
403 return fNewPhysicalToGeant4PhysicalNameMap.at(alternativeName);
404 }
405 return "";
406}
407
408template <typename T, typename U>
409U GetOrDefaultMapValueFromKey(const map<T, U>* pMap, const T& key) {
410 if (pMap->count(key) > 0) {
411 return pMap->at(key);
412 }
413 return {};
414}
415
416TString TRestGeant4GeometryInfo::GetVolumeFromID(Int_t id) const {
417 return GetOrDefaultMapValueFromKey<Int_t, TString>(&fVolumeNameMap, id);
418}
419
420Int_t TRestGeant4GeometryInfo::GetIDFromVolume(const TString& volumeName) const {
421 if (fVolumeNameReverseMap.count(volumeName) == 0) {
422 // if we do not find the volume we return -1 instead of default (which is 0 and may be confusing)
423 cout << "TRestGeant4GeometryInfo::GetIDFromVolume - volume '" << volumeName << "' not found in store!"
424 << endl;
425 return -1;
426 }
427 return GetOrDefaultMapValueFromKey<TString, Int_t>(&fVolumeNameReverseMap, volumeName);
428}
429
430void TRestGeant4GeometryInfo::InsertVolumeName(Int_t id, const TString& volumeName) {
431 fVolumeNameMap[id] = volumeName;
432 fVolumeNameReverseMap[volumeName] = id;
433}
434
435void TRestGeant4GeometryInfo::Print(bool multiLine) const {
436 cout << "Assembly Geometry: " << (fIsAssembly ? "yes" : "no") << endl;
437
438 const auto physicalVolumes = GetAllPhysicalVolumes();
439 cout << "Physical volumes (" << physicalVolumes.size() << "):" << endl;
440 for (const auto& physical : GetAllPhysicalVolumes()) {
441 auto geant4Name = GetGeant4PhysicalNameFromAlternativeName(physical);
442 const auto& logical = fPhysicalToLogicalVolumeMap.at(physical);
443 const auto& position = GetPosition(physical);
444 if (multiLine) {
445 cout << "\t- " << (geant4Name == physical ? physical : physical + " (" + geant4Name + ")")
446 << endl;
447 cout << "\t\tID: " << GetIDFromVolume(physical) << endl;
448 cout << "\t\tLogical: " << fPhysicalToLogicalVolumeMap.at(physical) << endl;
449 cout << "\t\tMaterial: " << fLogicalToMaterialMap.at(logical) << endl;
450 cout << "\t\tPosition: (" << position.X() << ", " << position.Y() << ", " << position.Z()
451 << ") mm" << endl;
452 continue;
453 } else {
454 cout << "\t- " << (geant4Name == physical ? physical : physical + " (" + geant4Name + ")")
455 << " - ID: " << GetIDFromVolume(physical)
456 << " - Logical: " << fPhysicalToLogicalVolumeMap.at(physical)
457 << " - Material: " << fLogicalToMaterialMap.at(logical) //
458 << " - Position: (" << position.X() << ", " << position.Y() << ", " << position.Z()
459 << ") mm" //
460 << endl;
461 }
462 }
463
464 const auto logicalVolumes = GetAllLogicalVolumes();
465 cout << "Logical volumes (" << logicalVolumes.size() << "):" << endl;
466 for (const auto& logical : logicalVolumes) {
467 cout << "\t- " << logical << endl;
468 }
469}
470
477 auto volumes = std::vector<TString>();
478
479 for (const auto& kv : fLogicalToPhysicalMap) {
480 volumes.emplace_back(kv.first);
481 }
482
483 return volumes;
484}
485
492 auto volumes = std::vector<TString>();
493
494 for (const auto& kv : fPhysicalToLogicalVolumeMap) {
495 volumes.emplace_back(kv.first);
496 }
497
498 return volumes;
499}
500
507 auto volumes = std::vector<TString>();
508
509 for (const auto& kv : fNewPhysicalToGeant4PhysicalNameMap) {
510 volumes.emplace_back(kv.first);
511 }
512
513 return volumes;
514}
515
523 const TString& regularExpression) const {
524 auto volumes = std::vector<TString>();
525
526 TPRegexp regex(regularExpression);
527
528 for (const auto& volume : GetAllPhysicalVolumes()) {
529 if (regex.Match(volume)) {
530 volumes.emplace_back(volume);
531 }
532 }
533
534 return volumes;
535}
536
544 const TString& regularExpression) const {
545 auto volumes = std::vector<TString>();
546
547 TPRegexp regex(regularExpression);
548
549 for (const auto& volume : GetAllLogicalVolumes()) {
550 if (regex.Match(volume)) {
551 volumes.emplace_back(volume);
552 }
553 }
554
555 return volumes;
556}
std::set< TString > GetAlternativeNamesFromGeant4PhysicalName(const TString &) const
Gets all the alternative physical volume names from the GDML file naming that correspond to a given G...
std::map< TString, TString > fPhysicalToLogicalVolumeMap
Map of GDML physical volume name to its logical volume name.
TString GetAlternativePathFromGeant4Path(const TString &) const
Converts a Geant4 volume path to a GDML volume path. The path is the concatenation of the names of th...
TVector3 GetPosition(const TString &volume) const
Gets the position in world coordinates of a given physical volume.
std::map< TString, std::vector< TString > > fLogicalToPhysicalMap
std::map< TString, TString > fGeant4AssemblyImprintToGdmlNameMap
std::vector< TString > GetAllPhysicalVolumes() const
Gets all the (GDML) physical volume names.
TString GetAlternativeNameFromGeant4PhysicalName(const TString &) const
Gets the alternative physical volume name from the GDML file naming. Note that if a logical volume wi...
std::vector< TString > GetAllAlternativePhysicalVolumes() const
Gets all the alternative (GDML) physical volume names.
std::map< TString, TString > fGeant4AssemblyImprintToAssemblyLogicalNameMap
std::vector< TString > fGdmlLogicalNames
Logical volume names as in the GDML file.
std::vector< TString > GetAllPhysicalVolumesMatchingExpression(const TString &) const
Gets all the (GDML) physical volume names matching a given regular expression.
std::vector< TString > GetAllLogicalVolumes() const
Gets all the logical volume names.
std::vector< TString > GetAllLogicalVolumesMatchingExpression(const TString &) const
Gets all the logical volume names matching a given regular expression.
std::map< TString, std::map< TString, TString > > fGdmlAssemblyToChildrenGeant4ToGdmlPhysicalNameMap
std::vector< TString > fGdmlNewPhysicalNames
Physical volume names as in the GDML file.
std::map< TString, TString > fNewPhysicalToGeant4PhysicalNameMap
Map from new physical volume names (unique) to Geant4 physical volume names (not always unique)
std::map< TString, TString > fLogicalToMaterialMap
Map of logical volume name to its material name.
std::string Replace(std::string in, std::string thisString, std::string byThisString, size_t fromPosition=0, Int_t N=0)
Replace any occurences of thisSring by byThisString inside string in.