DD4hep  1.28.0
Detector Description Toolkit for High Energy Physics
DetectorTools.cpp
Go to the documentation of this file.
1 //==========================================================================
2 // AIDA Detector description implementation
3 //--------------------------------------------------------------------------
4 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
5 // All rights reserved.
6 //
7 // For the licensing terms see $DD4hepINSTALL/LICENSE.
8 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
9 //
10 // Author : M.Frank
11 //
12 //==========================================================================
13 
14 // Framework include files
15 #define DETECTORTOOLS_CPP
17 #include <DD4hep/Printout.h>
18 #include <DD4hep/Detector.h>
20 
21 // C/C++ include files
22 #include <stdexcept>
23 #include <memory>
24 
25 // ROOT include files
26 #include <TGeoMatrix.h>
27 
29 namespace dd4hep {
30 
32 
36  namespace detail { namespace tools {
38  std::string elementPath(const PlacementPath& nodes, bool reverse);
42  void elementPath(DetElement elt, PlacementPath& nodes);
44  void elementPath(DetElement parent, DetElement element, PlacementPath& nodes);
46  bool findChild(PlacedVolume parent, PlacedVolume child, PlacementPath& path);
47 
48 
49  // Internal helper
50  static void makePlacementPath(PlacementPath det_nodes, PlacementPath& all_nodes);
51  }}
52 }
53 
54 using namespace dd4hep;
55 
58  if ( parent.isValid() && child.isValid() ) {
59  if ( parent.ptr() == child.ptr() ) return true;
60  for(DetElement par=child; par.isValid(); par=par.parent()) {
61  if ( par.ptr() == parent.ptr() ) return true;
62  }
63  }
64  throw std::runtime_error("Search for parent detector element with invalid handles not allowed.");
65 }
66 
69  if ( parent.isValid() && child.isValid() ) {
70  // Check self
71  if ( parent.ptr() == child.ptr() ) {
72  path.emplace_back(child);
73  return true;
74  }
75  TIter next(parent->GetVolume()->GetNodes());
76  // Now check next layer children
77  for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
78  if ( daughter == child.ptr() ) {
79  path.emplace_back(daughter);
80  return true;
81  }
82  }
83  next.Reset();
84  // Finally crawl down the tree
85  for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
86  PlacementPath sub_path;
87  bool res = findChild(daughter, child, sub_path);
88  if (res) {
89  path.insert(path.end(), sub_path.begin(), sub_path.end());
90  path.emplace_back(daughter);
91  return res;
92  }
93  }
94  }
95  return false;
96 }
97 
99 static bool findChildByName(PlacedVolume parent, PlacedVolume child, detail::tools::PlacementPath& path) {
100  if ( parent.isValid() && child.isValid() ) {
101  // Check self
102  if ( 0 == ::strcmp(parent.ptr()->GetName(),child.ptr()->GetName()) ) {
103  path.emplace_back(child);
104  return true;
105  }
106  TIter next(parent->GetVolume()->GetNodes());
107  // Now check next layer children
108  for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
109  if ( 0 == ::strcmp(daughter->GetName(),child.ptr()->GetName()) ) {
110  path.emplace_back(daughter);
111  return true;
112  }
113  }
114  next.Reset();
115  // Finally crawl down the tree
116  for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
118  bool res = findChildByName(daughter, child, sub_path);
119  if (res) {
120  path.insert(path.end(), sub_path.begin(), sub_path.end());
121  path.emplace_back(daughter);
122  return res;
123  }
124  }
125  }
126  return false;
127 }
128 
131  for(DetElement par = element; par.isValid(); par = par.parent())
132  detectors.emplace_back(par);
133 }
134 
137  detectors.clear();
138  if ( parent.isValid() && child.isValid() ) {
139  if ( parent.ptr() == child.ptr() ) {
140  detectors.emplace_back(child);
141  return;
142  }
143  ElementPath elements;
144  for(DetElement par = child; par.isValid(); par = par.parent()) {
145  elements.emplace_back(par);
146  if ( par.ptr() == parent.ptr() ) {
147  detectors = elements;
148  return;
149  }
150  }
151  throw std::runtime_error(std::string("The detector element ")+parent.name()+std::string(" is no parent of ")+child.name());
152  }
153  throw std::runtime_error("Search for parent detector element with invalid handles not allowed.");
154 }
155 
158  for(DetElement par = element; par.isValid(); par = par.parent()) {
159  PlacedVolume pv = par.placement();
160  if ( pv.isValid() ) {
161  det_nodes.emplace_back(pv);
162  }
163  if ( par.ptr() == parent.ptr() ) return;
164  }
165  throw std::runtime_error(std::string("The detector element ")+parent.name()+std::string(" is no parent of ")+element.name());
166 }
167 
170  for(DetElement par = element; par.isValid(); par = par.parent()) {
171  PlacedVolume pv = par.placement();
172  if ( pv.isValid() ) {
173  det_nodes.emplace_back(pv);
174  }
175  }
176 }
177 
179 std::string detail::tools::elementPath(const PlacementPath& nodes, bool reverse) {
180  std::string path = "";
181  if ( reverse ) {
182  for(auto i=nodes.rbegin(); i != nodes.rend(); ++i)
183  path += "/" + std::string((*i).name());
184  }
185  else {
186  for(auto i=begin(nodes); i != end(nodes); ++i)
187  path += "/" + std::string((*i)->GetName());
188  }
189  return path;
190 }
191 
193 std::string detail::tools::elementPath(const ElementPath& nodes, bool reverse) {
194  std::string path = "";
195  if ( reverse ) {
196  for(ElementPath::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
197  path += "/" + std::string((*i)->GetName());
198  }
199  else {
200  for(ElementPath::const_iterator i=nodes.begin();i!=nodes.end();++i)
201  path += "/" + std::string((*i)->GetName());
202  }
203  return path;
204 }
205 
208  ElementPath nodes;
209  elementPath(element,nodes);
210  return elementPath(nodes);
211 }
212 
214 DetElement detail::tools::findElement(const Detector& description, const std::string& path) {
215  return findDaughterElement(description.world(),path);
216 }
217 
219 DetElement detail::tools::findDaughterElement(DetElement parent, const std::string& subpath) {
220  if ( parent.isValid() ) {
221  size_t idx = subpath.find('/',1);
222  if ( subpath[0] == '/' ) {
223  DetElement top = topElement(parent);
224  if ( idx == std::string::npos ) return top;
225  return findDaughterElement(top,subpath.substr(idx+1));
226  }
227  if ( idx == std::string::npos )
228  return parent.child(subpath);
229  std::string name = subpath.substr(0,idx);
230  DetElement node = parent.child(name);
231  if ( node.isValid() ) {
232  return findDaughterElement(node,subpath.substr(idx+1));
233  }
234  throw std::runtime_error("dd4hep: DetElement "+parent.path()+" has no child named:"+name+" [No such child]");
235  }
236  throw std::runtime_error("dd4hep: Cannot determine child with path "+subpath+" from invalid parent [invalid handle]");
237 }
238 
241  if ( child.isValid() ) {
242  if ( child.parent().isValid() )
243  return topElement(child.parent());
244  return child;
245  }
246  throw std::runtime_error("dd4hep: DetElement cannot determine top parent (world) [invalid handle]");
247 }
248 
249 static void detail::tools::makePlacementPath(PlacementPath det_nodes, PlacementPath& all_nodes) {
250  for (size_t i = 0, n = det_nodes.size(); n > 0 && i < n-1; ++i) {
251  if (!findChildByName(det_nodes[i + 1], det_nodes[i], all_nodes)) {
252  throw std::runtime_error("dd4hep: DetElement cannot determine placement path of "
253  + std::string(det_nodes[i].name()) + " [internal error]");
254  }
255  }
256  if ( det_nodes.size() > 0 ) {
257  all_nodes.emplace_back(det_nodes.back());
258  }
259 }
260 
263  PlacementPath det_nodes;
264  elementPath(element,det_nodes);
265  makePlacementPath(det_nodes, all_nodes);
266 }
267 
270  PlacementPath det_nodes;
271  elementPath(parent,element,det_nodes);
272  makePlacementPath(det_nodes, all_nodes);
273 }
274 
277  PlacementPath path;
278  placementPath(element,path);
279  return placementPath(path);
280 }
281 
283 std::string detail::tools::placementPath(const PlacementPath& nodes, bool reverse) {
284  std::string path = "";
285  if ( reverse ) {
286  for(PlacementPath::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
287  path += "/" + std::string((*i)->GetName());
288  }
289  else {
290  for(PlacementPath::const_iterator i=nodes.begin();i!=nodes.end();++i)
291  path += "/" + std::string((*i)->GetName());
292  }
293  return path;
294 }
295 
297 std::string detail::tools::placementPath(const std::vector<const TGeoNode*>& nodes, bool reverse) {
298  std::string path = "";
299  if ( reverse ) {
300  for(std::vector<const TGeoNode*>::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
301  path += "/" + std::string((*i)->GetName());
302  return path;
303  }
304  for( const auto* n : nodes )
305  path += "/" + std::string(n->GetName());
306  return path;
307 }
308 
310 void detail::tools::placementTrafo(const PlacementPath& nodes, bool inverse, TGeoHMatrix*& mat) {
311  if ( !mat ) mat = new TGeoHMatrix(*gGeoIdentity);
312  placementTrafo(nodes,inverse,*mat);
313 }
314 
316 void detail::tools::placementTrafo(const PlacementPath& nodes, bool inverse, TGeoHMatrix& mat) {
317  mat = *gGeoIdentity;
318  if (nodes.size() > 0) {
319  for (size_t i = 0, n=nodes.size(); n>0 && i < n-1; ++i) {
320  const PlacedVolume& p = nodes[i];
321  mat.MultiplyLeft(p->GetMatrix());
322  }
323  if ( inverse ) mat = mat.Inverse();
324  }
325 }
326 
328 PlacedVolume detail::tools::findNode(PlacedVolume top_place, const std::string& place) {
329  TGeoNode* top = top_place.ptr();
330  const char* path = place.c_str();
331  // Check if a geometry path is valid without changing the state of the navigator.
332  Int_t length = strlen(path);
333  if (!length) return 0;
334  TString spath = path;
335  TGeoVolume *vol;
336  // Check first occurance of a '/'
337  Int_t ind1 = spath.Index("/");
338  if (ind1<0) {
339  // No '/' so we check directly the path against the name of the top
340  if ( strcmp(path,top->GetName()) ) return 0;
341  return top;
342  }
343  Int_t ind2 = ind1;
344  Bool_t end = kFALSE;
345  if (ind1>0) ind1 = -1; // no trailing '/'
346  else ind2 = spath.Index("/", ind1+1);
347 
348  if (ind2<0) ind2 = length;
349  TString name(spath(ind1+1, ind2-ind1-1));
350  if ( name == top->GetName() ) {
351  if (ind2>=length-1) return top;
352  ind1 = ind2;
353  }
354  else {
355  return 0;
356  }
357  TGeoNode *node = top;
358  // Deeper than just top level
359  while (!end) {
360  ind2 = spath.Index("/", ind1+1);
361  if (ind2<0) {
362  ind2 = length;
363  end = kTRUE;
364  }
365  vol = node->GetVolume();
366  name = spath(ind1+1, ind2-ind1-1);
367  node = vol->GetNode(name.Data());
368  if (!node)
369  return 0;
370  else if (ind2>=length-1)
371  return node;
372  ind1 = ind2;
373  }
374  return node;
375 }
376 
379  std::stringstream log;
380  for( const auto& v : ids )
381  log << v.first << "=" << v.second << "; ";
382  return log.str();
383 }
384 
386 std::string detail::tools::toString(const IDDescriptor& dsc, const PlacedVolume::VolIDs& ids, VolumeID code) {
387  std::stringstream log;
388  for( const auto& id : ids ) {
389  const BitFieldElement* f = dsc.field(id.first);
390  VolumeID value = f->value(code);
391  log << id.first << "=" << id.second << "," << value << " [" << f->offset() << "," << f->width() << "] ";
392  }
393  return log.str();
394 }
395 
397 std::vector<std::string> detail::tools::pathElements(const std::string& path) {
398  std::vector<std::string> result;
399  if ( !path.empty() ) {
400  std::string tmp = path[0]=='/' ? path.substr(1) : path;
401  for(size_t idx=tmp.find('/'); idx != std::string::npos; idx=tmp.find('/')) {
402  std::string val = tmp.substr(0,idx);
403  result.emplace_back(val);
404  tmp = tmp.length()>idx ? tmp.substr(idx+1) : std::string();
405  }
406  if ( !tmp.empty() ) {
407  result.emplace_back(tmp);
408  }
409  }
410  return result;
411 }
dd4hep::DetElement::path
const std::string & path() const
Path of the detector element (not necessarily identical to placement path!)
Definition: DetElement.cpp:157
dd4hep::DDSegmentation::BitFieldElement::offset
unsigned offset() const
Definition: BitFieldCoder.h:64
dd4hep::Detector::world
virtual DetElement world() const =0
Return reference to the top-most (world) detector element.
dd4hep::DDSegmentation::BitFieldElement
Helper class for BitFieldCoder that corresponds to one field value.
Definition: BitFieldCoder.h:32
dd4hep::detail::tools::ElementPath
std::vector< DetElement > ElementPath
Definition: DetectorTools.h:38
v
View * v
Definition: MultiView.cpp:28
dd4hep::DetElement::parent
DetElement parent() const
Access to the detector elements's parent.
Definition: DetElement.cpp:238
Detector.h
dd4hep::IDDescriptor::field
const BitFieldElement * field(const std::string &field_name) const
Get the field descriptor of one field by name.
Definition: IDDescriptor.cpp:96
dd4hep::PlacedVolume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:173
dd4hep::detail::tools::placementPath
std::string placementPath(DetElement element)
Assemble the placement path from a given detector element to the world volume.
Definition: DetectorTools.cpp:276
dd4hep::IDDescriptor
Class implementing the ID encoding of the detector response.
Definition: IDDescriptor.h:37
dd4hep::DDSegmentation::BitFieldElement::value
FieldID value(CellID bitfield) const
calculate this field's value given an external 64 bit bitmap
Definition: BitFieldCoder.cpp:45
dd4hep::Handle::isValid
bool isValid() const
Check the validity of the object held by the handle.
Definition: Handle.h:128
DetectorInterna.h
dd4hep::Handle::name
const char * name() const
Access the object name (or "" if not supported by the object)
dd4hep::detail::tools::findDaughterElement
DetElement findDaughterElement(DetElement parent, const std::string &subpath)
Find DetElement as child of a parent by its relative or absolute path.
Definition: DetectorTools.cpp:219
dd4hep::detail::tools::findElement
DetElement findElement(const Detector &description, const std::string &path)
Find DetElement as child of the top level volume by its absolute path.
Definition: DetectorTools.cpp:214
dd4hep::detail::tools::placementTrafo
void placementTrafo(const PlacementPath &nodes, bool inverse, TGeoHMatrix *&mat)
Update cached matrix to transform to positions to an upper level Placement.
Definition: DetectorTools.cpp:310
dd4hep::DetElement
Handle class describing a detector element.
Definition: DetElement.h:188
dd4hep::PlacedVolumeExtension::VolIDs
Volume ID container.
Definition: Volumes.h:88
dd4hep::detail::tools::findChild
bool findChild(PlacedVolume parent, PlacedVolume child, PlacementPath &path)
Find Child of PlacedVolume and assemble on the fly the path of PlacedVolumes.
Definition: DetectorTools.cpp:68
DetectorTools.h
dd4hep::DDSegmentation::BitFieldElement::width
unsigned width() const
Definition: BitFieldCoder.h:67
dd4hep::detail::tools::elementPath
void elementPath(DetElement parent, DetElement element, PlacementPath &nodes)
Collect detector elements placements to the parent detector element [no holes!].
Definition: DetectorTools.cpp:157
ElementPath
detail::tools::ElementPath ElementPath
Definition: DetectorInterna.cpp:30
dd4hep::detail::tools::isParentElement
bool isParentElement(DetElement parent, DetElement child)
Find path between the child element and the parent element.
Definition: DetectorTools.cpp:57
detectors
DetectorMap detectors
Definition: AlignmentsCalculator.cpp:79
dd4hep::detail::tools::findNode
PlacedVolume findNode(PlacedVolume top_place, const std::string &place)
Find a given node in the hierarchy starting from the top node (absolute placement!...
Definition: DetectorTools.cpp:328
dd4hep::detail::tools::pathElements
std::vector< std::string > pathElements(const std::string &path)
Extract all the path elements from a path.
Definition: DetectorTools.cpp:397
VolumeID
dd4hep::DDSegmentation::VolumeID VolumeID
Definition: SegmentationDictionary.h:48
dd4hep::detail::tools::elementPath
std::string elementPath(DetElement element)
Assemble the path of a particular detector element.
Definition: DetectorTools.cpp:207
dd4hep::Handle::ptr
T * ptr() const
Access to the held object.
Definition: Handle.h:153
dd4hep::detail::tools::topElement
DetElement topElement(DetElement child)
Determine top level element (=world) for any element walking up the detector element tree.
Definition: DetectorTools.cpp:240
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
dd4hep::DetElement::child
DetElement child(const std::string &name) const
Access to individual children by name.
Definition: DetElement.cpp:211
dd4hep::detail::tools::toString
std::string toString(const PlacedVolume::VolIDs &ids)
Convert VolumeID to string.
Definition: DetectorTools.cpp:378
dd4hep::detail::tools::PlacementPath
std::vector< PlacedVolume > PlacementPath
Definition: DetectorTools.h:39
dd4hep::Detector
The main interface to the dd4hep detector description package.
Definition: Detector.h:90
PlacementPath
detail::tools::PlacementPath PlacementPath
Definition: DetectorInterna.cpp:29
Printout.h