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 using namespace std;
13 
14 namespace myXml {
15 XMLNodePointer_t FindChildByName(TXMLEngine xml, XMLNodePointer_t node, const TString& name) {
16  XMLNodePointer_t child = xml.GetChild(node);
17  while (child) {
18  TString childName = xml.GetNodeName(child);
19  if (childName.EqualTo(name)) {
20  return child;
21  }
22  child = xml.GetNext(child);
23  }
24  return nullptr;
25 }
26 TString GetNodeAttribute(TXMLEngine xml, XMLNodePointer_t node, const TString& attributeName) {
27  XMLAttrPointer_t attr = xml.GetFirstAttr(node);
28  while (attr) {
29  if (TString(xml.GetAttrName(attr)).EqualTo(attributeName)) {
30  TString refName = xml.GetAttrValue(attr);
31  return refName;
32  }
33  attr = xml.GetNextAttr(attr);
34  }
35  return {};
36 }
37 void AddVolumesRecursively(vector<TString>* physicalNames, vector<TString>* logicalNames,
38  const vector<TString>& children, map<TString, TString>& nameTable,
39  map<TString, vector<TString>>& childrenTable, const TString& name = "") {
40  if (children.empty()) {
41  physicalNames->push_back(name);
42  const auto logicalVolumeName = nameTable[name];
43  logicalNames->push_back(logicalVolumeName);
44  return;
45  }
46  for (const auto& childName : children) {
47  const auto newName = name + "_" + childName;
48  nameTable[newName] = nameTable[childName]; // needed to retrieve logical volume name
49  AddVolumesRecursively(physicalNames, logicalNames, childrenTable[nameTable[childName]], nameTable,
50  childrenTable, newName);
51  }
52 }
53 } // namespace myXml
54 
55 void TRestGeant4GeometryInfo::PopulateFromGdml(const TString& gdmlFilename) {
56  /*
57  * Fills 'fGdmlNewPhysicalNames' with physical volume names generated from GDML
58  */
59  cout << "TRestGeant4GeometryInfo::PopulateFromGdml - " << gdmlFilename << endl;
60  // Geometry must be in GDML
61  TXMLEngine xml;
62  XMLDocPointer_t xmldoc = xml.ParseFile(gdmlFilename.Data());
63  if (!xmldoc) {
64  cout << "TRestGeant4GeometryInfo::PopulateFromGdml - GDML file " << gdmlFilename.Data()
65  << " not found" << endl;
66  exit(1);
67  }
68  map<TString, TString> nameTable;
69  map<TString, vector<TString>> childrenTable;
70  XMLNodePointer_t mainNode = xml.DocGetRootElement(xmldoc);
71  XMLNodePointer_t structure = myXml::FindChildByName(xml, mainNode, "structure");
72  XMLNodePointer_t child = xml.GetChild(structure);
73  while (child) {
74  TString name = xml.GetNodeName(child);
75  TString volumeName = myXml::GetNodeAttribute(xml, child, "name");
76  auto physicalVolumeNode = xml.GetChild(child);
77  childrenTable[volumeName] = {};
78  while (physicalVolumeNode) {
79  auto physicalVolumeName = myXml::GetNodeAttribute(xml, physicalVolumeNode, "name");
80  auto volumeRefNode = xml.GetChild(physicalVolumeNode);
81  while (volumeRefNode) {
82  TString volumeRefNodeName = xml.GetNodeName(volumeRefNode);
83  if (volumeRefNodeName.EqualTo("volumeref")) {
84  TString refName = myXml::GetNodeAttribute(xml, volumeRefNode, "ref");
85  nameTable[physicalVolumeName] = refName;
86  childrenTable[volumeName].push_back(physicalVolumeName);
87  }
88  volumeRefNode = xml.GetNext(volumeRefNode);
89  }
90  physicalVolumeNode = xml.GetNext(physicalVolumeNode);
91  }
92  child = xml.GetNext(child);
93  }
94 
95  string worldVolumeName = "world";
96  if (childrenTable.count(worldVolumeName) == 0) {
97  worldVolumeName = "World";
98  if (childrenTable.count(worldVolumeName) == 0) {
99  cout << "Could not find world volume in GDML, please name it either 'World' or 'world'";
100  exit(1);
101  }
102  }
103 
104  fGdmlNewPhysicalNames.clear();
105  fGdmlLogicalNames.clear();
106  for (const auto& topName : childrenTable[worldVolumeName]) {
107  auto children = childrenTable[nameTable[topName]];
108  myXml::AddVolumesRecursively(&fGdmlNewPhysicalNames, &fGdmlLogicalNames, children, nameTable,
109  childrenTable, topName);
110  }
111 
112  xml.FreeDoc(xmldoc);
113 
114  // Checks
115  if (fGdmlNewPhysicalNames.empty()) {
116  cout << "TRestGeant4GeometryInfo::PopulateFromGdml - ERROR - No physical volumes have been added!"
117  << endl;
118  exit(1);
119  }
120  // Find duplicates
121  set<TString> s;
122  for (const auto& name : fGdmlNewPhysicalNames) {
123  s.insert(name);
124  }
125  if (s.size() != fGdmlNewPhysicalNames.size()) {
126  cout << "TRestGeant4GeometryInfo::PopulateFromGdml - ERROR - Generated a duplicate name, please "
127  "check assembly"
128  << endl;
129  exit(1);
130  }
131 }
132 
133 TString TRestGeant4GeometryInfo::GetAlternativeNameFromGeant4PhysicalName(
134  const TString& geant4PhysicalName) const {
135  if (fGeant4PhysicalNameToNewPhysicalNameMap.count(geant4PhysicalName) > 0) {
136  return fGeant4PhysicalNameToNewPhysicalNameMap.at(geant4PhysicalName);
137  }
138  return geant4PhysicalName;
139 }
140 
141 TString TRestGeant4GeometryInfo::GetGeant4PhysicalNameFromAlternativeName(
142  const TString& alternativeName) const {
143  for (const auto& kv : fGeant4PhysicalNameToNewPhysicalNameMap) {
144  if (kv.second == alternativeName) {
145  return kv.first;
146  }
147  }
148  return "";
149 }
150 
151 template <typename T, typename U>
152 U GetOrDefaultMapValueFromKey(const map<T, U>* pMap, const T& key) {
153  if (pMap->count(key) > 0) {
154  return pMap->at(key);
155  }
156  return {};
157 }
158 
159 TString TRestGeant4GeometryInfo::GetVolumeFromID(Int_t id) const {
160  return GetOrDefaultMapValueFromKey<Int_t, TString>(&fVolumeNameMap, id);
161 }
162 
163 Int_t TRestGeant4GeometryInfo::GetIDFromVolume(const TString& volumeName) const {
164  if (fVolumeNameReverseMap.count(volumeName) == 0) {
165  // if we do not find the volume we return -1 instead of default (which is 0 and may be confusing)
166  cout << "TRestGeant4GeometryInfo::GetIDFromVolume - volume '" << volumeName << "' not found in store!"
167  << endl;
168  return -1;
169  }
170  return GetOrDefaultMapValueFromKey<TString, Int_t>(&fVolumeNameReverseMap, volumeName);
171 }
172 
173 void TRestGeant4GeometryInfo::InsertVolumeName(Int_t id, const TString& volumeName) {
174  fVolumeNameMap[id] = volumeName;
175  fVolumeNameReverseMap[volumeName] = id;
176 }
177 
178 void TRestGeant4GeometryInfo::Print() const {
179  cout << "Assembly Geometry: " << (fIsAssembly ? "yes" : "no") << endl;
180 
181  const auto physicalVolumes = GetAllPhysicalVolumes();
182  cout << "Physical volumes (" << physicalVolumes.size() << "):" << endl;
183  for (const auto& physical : GetAllPhysicalVolumes()) {
184  auto geant4Name = GetGeant4PhysicalNameFromAlternativeName(physical);
185  const auto& logical = fPhysicalToLogicalVolumeMap.at(physical);
186  const auto& position = GetPosition(physical);
187  cout << "\t- " << (geant4Name == physical ? physical : physical + " (" + geant4Name + ")")
188  << " - ID: " << GetIDFromVolume(physical)
189  << " - Logical: " << fPhysicalToLogicalVolumeMap.at(physical)
190  << " - Material: " << fLogicalToMaterialMap.at(logical) //
191  << " - Position: (" << position.X() << ", " << position.Y() << ", " << position.Z() << ") mm" //
192  << endl;
193  }
194 
195  const auto logicalVolumes = GetAllLogicalVolumes();
196  cout << "Logical volumes (" << logicalVolumes.size() << "):" << endl;
197  for (const auto& logical : logicalVolumes) {
198  cout << "\t- " << logical << endl;
199  }
200 }
201 
202 std::vector<TString> TRestGeant4GeometryInfo::GetAllLogicalVolumes() const {
203  auto volumes = std::vector<TString>();
204 
205  for (const auto& kv : fLogicalToPhysicalMap) {
206  volumes.emplace_back(kv.first);
207  }
208 
209  return volumes;
210 }
211 
212 std::vector<TString> TRestGeant4GeometryInfo::GetAllPhysicalVolumes() const {
213  auto volumes = std::vector<TString>();
214 
215  for (const auto& kv : fPhysicalToLogicalVolumeMap) {
216  volumes.emplace_back(kv.first);
217  }
218 
219  return volumes;
220 }
221 
222 std::vector<TString> TRestGeant4GeometryInfo::GetAllAlternativePhysicalVolumes() const {
223  auto volumes = std::vector<TString>();
224 
225  for (const auto& kv : fPhysicalToLogicalVolumeMap) {
226  volumes.emplace_back(GetAlternativeNameFromGeant4PhysicalName(kv.first));
227  }
228 
229  return volumes;
230 }
231 
232 std::vector<TString> TRestGeant4GeometryInfo::GetAllPhysicalVolumesMatchingExpression(
233  const TString& regularExpression) const {
234  auto volumes = std::vector<TString>();
235 
236  TPRegexp regex(regularExpression);
237 
238  for (const auto& volume : GetAllPhysicalVolumes()) {
239  if (regex.Match(volume)) {
240  volumes.emplace_back(volume);
241  }
242  }
243 
244  return volumes;
245 }
246 
247 std::vector<TString> TRestGeant4GeometryInfo::GetAllLogicalVolumesMatchingExpression(
248  const TString& regularExpression) const {
249  auto volumes = std::vector<TString>();
250 
251  TPRegexp regex(regularExpression);
252 
253  for (const auto& volume : GetAllLogicalVolumes()) {
254  if (regex.Match(volume)) {
255  volumes.emplace_back(volume);
256  }
257  }
258 
259  return volumes;
260 }