5#include "TRestGeant4GeometryInfo.h"
12#include "TRestStringHelper.h"
17XMLNodePointer_t FindChildByName(TXMLEngine xml, XMLNodePointer_t node,
const TString& name) {
18 XMLNodePointer_t child = xml.GetChild(node);
20 TString childName = xml.GetNodeName(child);
21 if (childName.EqualTo(name)) {
24 child = xml.GetNext(child);
28TString GetNodeAttribute(TXMLEngine xml, XMLNodePointer_t node,
const TString& attributeName) {
29 XMLAttrPointer_t attr = xml.GetFirstAttr(node);
31 if (TString(xml.GetAttrName(attr)).EqualTo(attributeName)) {
32 TString refName = xml.GetAttrValue(attr);
35 attr = xml.GetNextAttr(attr);
39XMLNodePointer_t GetChildByAttributeValue(TXMLEngine xml, XMLNodePointer_t node,
const TString& attributeName,
40 const TString& attributeValue) {
41 XMLNodePointer_t child = xml.GetChild(node);
43 TString childAttributeValue = GetNodeAttribute(xml, child, attributeName);
44 if (childAttributeValue.EqualTo(attributeValue)) {
47 child = xml.GetNext(child);
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);
61 for (
const auto& childName : children) {
62 const auto newName = name + separator + childName;
63 nameTable[newName] = nameTable[childName];
64 AddVolumesRecursively(physicalNames, logicalNames, childrenTable[nameTable[childName]], nameTable,
65 childrenTable, newName, separator);
70void TRestGeant4GeometryInfo::PopulateFromGdml(
const TString& gdmlFilename) {
74 cout <<
"TRestGeant4GeometryInfo::PopulateFromGdml - " << gdmlFilename << endl;
77 XMLDocPointer_t xmldoc = xml.ParseFile(gdmlFilename.Data());
79 cout <<
"TRestGeant4GeometryInfo::PopulateFromGdml - GDML file " << gdmlFilename.Data()
80 <<
" not found" << endl;
83 XMLNodePointer_t mainNode = xml.DocGetRootElement(xmldoc);
84 XMLNodePointer_t structure = myXml::FindChildByName(xml, mainNode,
"structure");
85 XMLNodePointer_t child = xml.GetChild(structure);
92 size_t assemblyCounter = 0;
93 map<TString, TString> gdmlToGeant4AssemblyNameMap;
94 map<TString, size_t> gdmlAssemblyNameToImprintCounterMap;
95 RESTDebug <<
"Searching for assemblies..." << RESTendl;
97 TString name = xml.GetNodeName(child);
98 if (!name.EqualTo(
"assembly")) {
99 child = xml.GetNext(child);
102 TString assemblyName = myXml::GetNodeAttribute(xml, child,
"name");
103 gdmlToGeant4AssemblyNameMap[assemblyName] =
104 "av_" + to_string(++assemblyCounter);
105 gdmlAssemblyNameToImprintCounterMap[assemblyName] = 0;
106 RESTDebug <<
"Assembly found: " << assemblyName <<
" → " << gdmlToGeant4AssemblyNameMap[assemblyName]
113 bool hasNestedAssemblies =
false;
114 std::map<TString, TString> childrenGeant4toGdmlMap;
115 size_t childrenPVCounter = 0;
116 auto physicalVolumeNode =
118 while (physicalVolumeNode) {
119 auto physicalVolumeName = myXml::GetNodeAttribute(xml, physicalVolumeNode,
"name");
121 xml.GetChild(physicalVolumeNode);
122 while (volumeRefNode) {
123 TString volumeRefNodeName =
124 xml.GetNodeName(volumeRefNode);
125 if (volumeRefNodeName.EqualTo(
"volumeref")) {
127 myXml::GetNodeAttribute(xml, volumeRefNode,
"ref");
130 to_string(childrenPVCounter++);
131 childrenGeant4toGdmlMap[geant4Name] = physicalVolumeName;
132 if (gdmlToGeant4AssemblyNameMap.count(refName) > 0) {
133 hasNestedAssemblies =
true;
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."
145 volumeRefNode = xml.GetNext(volumeRefNode);
147 physicalVolumeNode = xml.GetNext(physicalVolumeNode);
150 child = xml.GetNext(child);
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);
167 while (physicalVolumeNode) {
168 auto physicalVolumeName = myXml::GetNodeAttribute(xml, physicalVolumeNode,
"name");
170 xml.GetChild(physicalVolumeNode);
171 while (volumeRefNode) {
172 TString volumeRefNodeName =
173 xml.GetNodeName(volumeRefNode);
174 if (volumeRefNodeName.EqualTo(
"volumeref")) {
176 myXml::GetNodeAttribute(xml, volumeRefNode,
"ref");
177 if (gdmlToGeant4AssemblyNameMap.count(refName) > 0) {
179 TString newGodFatherAssemblyName = godFatherAssemblyName;
180 if (newGodFatherAssemblyName.IsNull()) {
182 newGodFatherAssemblyName = refName;
184 size_t imprintCounter =
185 ++gdmlAssemblyNameToImprintCounterMap[newGodFatherAssemblyName];
186 TString imprint = gdmlToGeant4AssemblyNameMap[newGodFatherAssemblyName] +
187 "_impr_" + to_string(imprintCounter);
189 pathSoFar + (pathSoFar.IsNull() ?
"" : fPathSeparator) + physicalVolumeName;
194 myXml::GetChildByAttributeValue(xml, structure,
"name", refName);
195 ProcessNestedAssembliesRecursively(assemblyNode, newGodFatherAssemblyName, path);
200 myXml::GetChildByAttributeValue(xml, structure,
"name", refName);
201 ProcessNestedAssembliesRecursively(assemblyNode,
"",
"");
204 volumeRefNode = xml.GetNext(volumeRefNode);
206 physicalVolumeNode = xml.GetNext(physicalVolumeNode);
212 auto worldNode = myXml::GetChildByAttributeValue(xml, structure,
"name",
"world");
214 worldNode = myXml::GetChildByAttributeValue(xml, structure,
"name",
"World");
216 cout <<
"Could not find world volume in GDML, please name it either 'World' or 'world'" << endl;
220 TString godFatherAssemblyName =
"";
221 TString pathSoFar =
"";
222 ProcessNestedAssembliesRecursively(worldNode, godFatherAssemblyName, pathSoFar);
225 map<TString, TString> nameTable;
226 map<TString, vector<TString>> childrenTable;
227 child = xml.GetChild(structure);
229 TString name = xml.GetNodeName(child);
230 TString volumeName = myXml::GetNodeAttribute(xml, child,
"name");
231 auto physicalVolumeNode =
233 childrenTable[volumeName] = {};
234 while (physicalVolumeNode) {
235 auto physicalVolumeName = myXml::GetNodeAttribute(xml, physicalVolumeNode,
"name");
237 xml.GetChild(physicalVolumeNode);
238 while (volumeRefNode) {
239 TString volumeRefNodeName =
240 xml.GetNodeName(volumeRefNode);
241 if (volumeRefNodeName.EqualTo(
"volumeref")) {
243 myXml::GetNodeAttribute(xml, volumeRefNode,
"ref");
244 nameTable[physicalVolumeName] = refName;
245 childrenTable[volumeName].push_back(physicalVolumeName);
246 if (gdmlToGeant4AssemblyNameMap.count(refName) > 0) {
250 volumeRefNode = xml.GetNext(volumeRefNode);
252 physicalVolumeNode = xml.GetNext(physicalVolumeNode);
254 child = xml.GetNext(child);
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'";
268 for (
const auto& topName : childrenTable[worldVolumeName]) {
269 auto children = childrenTable[nameTable[topName]];
271 childrenTable, topName, fPathSeparator);
278 cout <<
"TRestGeant4GeometryInfo::PopulateFromGdml - ERROR - No physical volumes have been added!"
288 cout <<
"TRestGeant4GeometryInfo::PopulateFromGdml - ERROR - Generated a duplicate name, please "
336 std::string convertedPath = geant4Path.Data();
340 convertedPath =
Replace(convertedPath, (gvName +
"_").Data(), (gdmlName + fPathSeparator).Data());
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());
355 return TString(convertedPath);
370 const TString& geant4PhysicalName)
const {
372 if (kv.second.EqualTo(geant4PhysicalName)) {
376 return geant4PhysicalName;
390 const TString& geant4PhysicalName)
const {
391 set<TString> alternativeNames;
393 if (kv.second.EqualTo(geant4PhysicalName)) {
394 alternativeNames.insert(kv.first);
397 return alternativeNames;
400TString TRestGeant4GeometryInfo::GetGeant4PhysicalNameFromAlternativeName(
401 const TString& alternativeName)
const {
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);
416TString TRestGeant4GeometryInfo::GetVolumeFromID(Int_t
id)
const {
417 return GetOrDefaultMapValueFromKey<Int_t, TString>(&fVolumeNameMap,
id);
420Int_t TRestGeant4GeometryInfo::GetIDFromVolume(
const TString& volumeName)
const {
421 if (fVolumeNameReverseMap.count(volumeName) == 0) {
423 cout <<
"TRestGeant4GeometryInfo::GetIDFromVolume - volume '" << volumeName <<
"' not found in store!"
427 return GetOrDefaultMapValueFromKey<TString, Int_t>(&fVolumeNameReverseMap, volumeName);
430void TRestGeant4GeometryInfo::InsertVolumeName(Int_t
id,
const TString& volumeName) {
431 fVolumeNameMap[id] = volumeName;
432 fVolumeNameReverseMap[volumeName] = id;
435void TRestGeant4GeometryInfo::Print(
bool multiLine)
const {
436 cout <<
"Assembly Geometry: " << (fIsAssembly ?
"yes" :
"no") << endl;
439 cout <<
"Physical volumes (" << physicalVolumes.size() <<
"):" << endl;
441 auto geant4Name = GetGeant4PhysicalNameFromAlternativeName(physical);
445 cout <<
"\t- " << (geant4Name == physical ? physical : physical +
" (" + geant4Name +
")")
447 cout <<
"\t\tID: " << GetIDFromVolume(physical) << endl;
450 cout <<
"\t\tPosition: (" << position.X() <<
", " << position.Y() <<
", " << position.Z()
454 cout <<
"\t- " << (geant4Name == physical ? physical : physical +
" (" + geant4Name +
")")
455 <<
" - ID: " << GetIDFromVolume(physical)
458 <<
" - Position: (" << position.X() <<
", " << position.Y() <<
", " << position.Z()
465 cout <<
"Logical volumes (" << logicalVolumes.size() <<
"):" << endl;
466 for (
const auto& logical : logicalVolumes) {
467 cout <<
"\t- " << logical << endl;
477 auto volumes = std::vector<TString>();
480 volumes.emplace_back(kv.first);
492 auto volumes = std::vector<TString>();
495 volumes.emplace_back(kv.first);
507 auto volumes = std::vector<TString>();
510 volumes.emplace_back(kv.first);
523 const TString& regularExpression)
const {
524 auto volumes = std::vector<TString>();
526 TPRegexp regex(regularExpression);
529 if (regex.Match(volume)) {
530 volumes.emplace_back(volume);
544 const TString& regularExpression)
const {
545 auto volumes = std::vector<TString>();
547 TPRegexp regex(regularExpression);
550 if (regex.Match(volume)) {
551 volumes.emplace_back(volume);
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.