DD4hep  1.35.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 <sstream>
24 #include <string>
25 
26 // ROOT include files
27 #include <TGeoMatrix.h>
28 
30 namespace dd4hep {
31 
33 
37  namespace detail { namespace tools {
39  std::string elementPath(const PlacementPath& nodes, bool reverse);
43  void elementPath(DetElement elt, PlacementPath& nodes);
45  void elementPath(DetElement parent, DetElement element, PlacementPath& nodes);
47  bool findChild(PlacedVolume parent, PlacedVolume child, PlacementPath& path);
48 
49 
50  // Internal helper
51  static void makePlacementPath(PlacementPath det_nodes, PlacementPath& all_nodes);
52  }}
53 }
54 
55 using namespace dd4hep;
56 
59  if ( parent.isValid() && child.isValid() ) {
60  if ( parent.ptr() == child.ptr() ) return true;
61  for(DetElement par=child; par.isValid(); par=par.parent()) {
62  if ( par.ptr() == parent.ptr() ) return true;
63  }
64  }
65  throw std::runtime_error("Search for parent detector element with invalid handles not allowed.");
66 }
67 
70  if ( parent.isValid() && child.isValid() ) {
71  // Check self
72  if ( parent.ptr() == child.ptr() ) {
73  path.emplace_back(child);
74  return true;
75  }
76  TIter next(parent->GetVolume()->GetNodes());
77  // Now check next layer children
78  for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
79  if ( daughter == child.ptr() ) {
80  path.emplace_back(daughter);
81  return true;
82  }
83  }
84  next.Reset();
85  // Finally crawl down the tree
86  for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
87  PlacementPath sub_path;
88  bool res = findChild(daughter, child, sub_path);
89  if (res) {
90  path.insert(path.end(), sub_path.begin(), sub_path.end());
91  path.emplace_back(daughter);
92  return res;
93  }
94  }
95  }
96  return false;
97 }
98 
100 static bool findChildByName(PlacedVolume parent, PlacedVolume child, detail::tools::PlacementPath& path) {
101  if ( parent.isValid() && child.isValid() ) {
102  // Check self
103  if ( 0 == ::strcmp(parent.ptr()->GetName(),child.ptr()->GetName()) ) {
104  path.emplace_back(child);
105  return true;
106  }
107  TIter next(parent->GetVolume()->GetNodes());
108  // Now check next layer children
109  for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
110  if ( 0 == ::strcmp(daughter->GetName(),child.ptr()->GetName()) ) {
111  path.emplace_back(daughter);
112  return true;
113  }
114  }
115  next.Reset();
116  // Finally crawl down the tree
117  for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
119  bool res = findChildByName(daughter, child, sub_path);
120  if (res) {
121  path.insert(path.end(), sub_path.begin(), sub_path.end());
122  path.emplace_back(daughter);
123  return res;
124  }
125  }
126  }
127  return false;
128 }
129 
132  for(DetElement par = element; par.isValid(); par = par.parent())
133  detectors.emplace_back(par);
134 }
135 
138  detectors.clear();
139  if ( parent.isValid() && child.isValid() ) {
140  if ( parent.ptr() == child.ptr() ) {
141  detectors.emplace_back(child);
142  return;
143  }
144  ElementPath elements;
145  for(DetElement par = child; par.isValid(); par = par.parent()) {
146  elements.emplace_back(par);
147  if ( par.ptr() == parent.ptr() ) {
148  detectors = elements;
149  return;
150  }
151  }
152  throw std::runtime_error(std::string("The detector element ")+parent.name()+std::string(" is no parent of ")+child.name());
153  }
154  throw std::runtime_error("Search for parent detector element with invalid handles not allowed.");
155 }
156 
159  if( element.isValid() ) {
160  if( !parent.isValid() ) {
161  parent = element.world();
162  }
163  for( DetElement par = element; par.isValid(); par = par.parent() ) {
164  PlacedVolume pv = par.placement();
165  if ( pv.isValid() ) {
166  det_nodes.emplace_back(pv);
167  }
168  if ( par.ptr() == parent.ptr() ) return;
169  }
170  throw std::runtime_error(("The detector element "+std::string(parent.name())+" is no parent of ")+element.name());
171  }
172  throw std::runtime_error("Cannot access element path [Invalid DetElement]");
173 }
174 
177  for(DetElement par = element; par.isValid(); par = par.parent()) {
178  PlacedVolume pv = par.placement();
179  if ( pv.isValid() ) {
180  det_nodes.emplace_back(pv);
181  }
182  }
183 }
184 
186 std::string detail::tools::elementPath(const PlacementPath& nodes, bool reverse) {
187  std::string path = "";
188  if ( reverse ) {
189  for(auto i=nodes.rbegin(); i != nodes.rend(); ++i)
190  path += "/" + std::string((*i).name());
191  }
192  else {
193  for(auto i=begin(nodes); i != end(nodes); ++i)
194  path += "/" + std::string((*i)->GetName());
195  }
196  return path;
197 }
198 
200 std::string detail::tools::elementPath(const ElementPath& nodes, bool reverse) {
201  std::string path = "";
202  if ( reverse ) {
203  for(ElementPath::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
204  path += "/" + std::string((*i)->GetName());
205  }
206  else {
207  for(ElementPath::const_iterator i=nodes.begin();i!=nodes.end();++i)
208  path += "/" + std::string((*i)->GetName());
209  }
210  return path;
211 }
212 
215  ElementPath nodes;
216  elementPath(element,nodes);
217  return elementPath(nodes);
218 }
219 
221 DetElement detail::tools::findElement(const Detector& description, const std::string& path) {
222  return findDaughterElement(description.world(),path);
223 }
224 
226 DetElement detail::tools::findDaughterElement(DetElement parent, const std::string& subpath) {
227  if ( parent.isValid() ) {
228  size_t idx = subpath.find('/',1);
229  if ( subpath[0] == '/' ) {
230  DetElement top = topElement(parent);
231  if ( idx == std::string::npos ) return top;
232  return findDaughterElement(top,subpath.substr(idx+1));
233  }
234  if ( idx == std::string::npos )
235  return parent.child(subpath);
236  std::string name = subpath.substr(0,idx);
237  DetElement node = parent.child(name);
238  if ( node.isValid() ) {
239  return findDaughterElement(node,subpath.substr(idx+1));
240  }
241  throw std::runtime_error("dd4hep: DetElement "+parent.path()+" has no child named:"+name+" [No such child]");
242  }
243  throw std::runtime_error("dd4hep: Cannot determine child with path "+subpath+" from invalid parent [invalid handle]");
244 }
245 
248  if ( child.isValid() ) {
249  if ( child.parent().isValid() )
250  return topElement(child.parent());
251  return child;
252  }
253  throw std::runtime_error("dd4hep: DetElement cannot determine top parent (world) [invalid handle]");
254 }
255 
256 static void detail::tools::makePlacementPath(PlacementPath det_nodes, PlacementPath& all_nodes) {
257  for (size_t i = 0, n = det_nodes.size(); n > 0 && i < n-1; ++i) {
258  if (!findChildByName(det_nodes[i + 1], det_nodes[i], all_nodes)) {
259  throw std::runtime_error("dd4hep: DetElement cannot determine placement path of "
260  + std::string(det_nodes[i].name()) + " [internal error]");
261  }
262  }
263  if ( det_nodes.size() > 0 ) {
264  all_nodes.emplace_back(det_nodes.back());
265  }
266 }
267 
270  PlacementPath det_nodes;
271  elementPath(element,det_nodes);
272  makePlacementPath(std::move(det_nodes), all_nodes);
273 }
274 
277  PlacementPath det_nodes;
278  elementPath(parent,element,det_nodes);
279  makePlacementPath(std::move(det_nodes), all_nodes);
280 }
281 
284  PlacementPath path;
285  placementPath(element,path);
286  return placementPath(std::move(path));
287 }
288 
290 std::string detail::tools::placementPath(const PlacementPath& nodes, bool reverse) {
291  std::string path = "";
292  if ( reverse ) {
293  for(PlacementPath::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
294  path += "/" + std::string((*i)->GetName());
295  }
296  else {
297  for(PlacementPath::const_iterator i=nodes.begin();i!=nodes.end();++i)
298  path += "/" + std::string((*i)->GetName());
299  }
300  return path;
301 }
302 
304 std::string detail::tools::placementPath(const std::vector<const TGeoNode*>& nodes, bool reverse) {
305  std::string path = "";
306  if ( reverse ) {
307  for(std::vector<const TGeoNode*>::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
308  path += "/" + std::string((*i)->GetName());
309  return path;
310  }
311  for( const auto* n : nodes )
312  path += "/" + std::string(n->GetName());
313  return path;
314 }
315 
317 void detail::tools::placementTrafo(const PlacementPath& nodes, bool inverse, TGeoHMatrix*& mat) {
318  if ( !mat ) mat = new TGeoHMatrix(*gGeoIdentity);
319  placementTrafo(nodes,inverse,*mat);
320 }
321 
323 void detail::tools::placementTrafo(const PlacementPath& nodes, bool inverse, TGeoHMatrix& mat) {
324  mat = *gGeoIdentity;
325  if (nodes.size() > 0) {
326  for (size_t i = 0, n=nodes.size(); n>0 && i < n-1; ++i) {
327  const PlacedVolume& p = nodes[i];
328  mat.MultiplyLeft(p->GetMatrix());
329  }
330  if ( inverse ) mat = mat.Inverse();
331  }
332 }
333 
335 PlacedVolume detail::tools::findNode(PlacedVolume top_place, const std::string& place) {
336  TGeoNode* top = top_place.ptr();
337  const char* path = place.c_str();
338  // Check if a geometry path is valid without changing the state of the navigator.
339  Int_t length = strlen(path);
340  if (!length) return 0;
341  TString spath = path;
342  TGeoVolume *vol;
343  // Check first occurance of a '/'
344  Int_t ind1 = spath.Index("/");
345  if (ind1<0) {
346  // No '/' so we check directly the path against the name of the top
347  if ( strcmp(path,top->GetName()) ) return 0;
348  return top;
349  }
350  Int_t ind2 = ind1;
351  Bool_t end = kFALSE;
352  if (ind1>0) ind1 = -1; // no trailing '/'
353  else ind2 = spath.Index("/", ind1+1);
354 
355  if (ind2<0) ind2 = length;
356  TString name(spath(ind1+1, ind2-ind1-1));
357  if ( name == top->GetName() ) {
358  if (ind2>=length-1) return top;
359  ind1 = ind2;
360  }
361  else {
362  return 0;
363  }
364  TGeoNode *node = top;
365  // Deeper than just top level
366  while (!end) {
367  ind2 = spath.Index("/", ind1+1);
368  if (ind2<0) {
369  ind2 = length;
370  end = kTRUE;
371  }
372  vol = node->GetVolume();
373  name = spath(ind1+1, ind2-ind1-1);
374  node = vol->GetNode(name.Data());
375  if (!node)
376  return 0;
377  else if (ind2>=length-1)
378  return node;
379  ind1 = ind2;
380  }
381  return node;
382 }
383 
386  std::stringstream log;
387  for( const auto& v : ids )
388  log << v.first << "=" << v.second << "; ";
389  return log.str();
390 }
391 
393 std::string detail::tools::toString(const IDDescriptor& dsc, const PlacedVolume::VolIDs& ids, VolumeID code) {
394  std::stringstream log;
395  for( const auto& id : ids ) {
396  const BitFieldElement* f = dsc.field(id.first);
397  VolumeID value = f->value(code);
398  log << id.first << "=" << id.second << "," << value << " [" << f->offset() << "," << f->width() << "] ";
399  }
400  return log.str();
401 }
402 
404 std::vector<std::string> detail::tools::pathElements(const std::string& path) {
405  std::vector<std::string> result;
406  if ( !path.empty() ) {
407  std::string tmp = path[0]=='/' ? path.substr(1) : path;
408  for(size_t idx=tmp.find('/'); idx != std::string::npos; idx=tmp.find('/')) {
409  std::string val = tmp.substr(0,idx);
410  result.emplace_back(val);
411  tmp = tmp.length()>idx ? tmp.substr(idx+1) : std::string();
412  }
413  if ( !tmp.empty() ) {
414  result.emplace_back(tmp);
415  }
416  }
417  return result;
418 }
dd4hep::DetElement::path
const std::string & path() const
Path of the detector element (not necessarily identical to placement path!)
Definition: DetElement.cpp:158
dd4hep::DDSegmentation::BitFieldElement::offset
unsigned offset() const
Definition: BitFieldCoder.h:63
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:31
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:239
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:164
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:283
dd4hep::IDDescriptor
Class implementing the ID encoding of the detector response.
Definition: IDDescriptor.h:36
dd4hep::DDSegmentation::BitFieldElement::value
FieldID value(CellID bitfield) const
calculate this field's value given an external 64 bit bitmap
Definition: BitFieldCoder.cpp:56
dd4hep::Handle::isValid
bool isValid() const
Check the validity of the object held by the handle.
Definition: Handle.h:126
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:226
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:221
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:317
dd4hep::DetElement
Handle class describing a detector element.
Definition: DetElement.h:187
dd4hep::PlacedVolumeExtension::VolIDs
Volume ID container.
Definition: Volumes.h:89
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:69
DetectorTools.h
dd4hep::DDSegmentation::BitFieldElement::width
unsigned width() const
Definition: BitFieldCoder.h:66
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:158
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:58
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:335
dd4hep::detail::tools::pathElements
std::vector< std::string > pathElements(const std::string &path)
Extract all the path elements from a path.
Definition: DetectorTools.cpp:404
VolumeID
dd4hep::DDSegmentation::VolumeID VolumeID
Definition: SegmentationDictionary.h:50
dd4hep::detail::tools::elementPath
std::string elementPath(DetElement element)
Assemble the path of a particular detector element.
Definition: DetectorTools.cpp:214
dd4hep::Handle::ptr
T * ptr() const
Access to the held object.
Definition: Handle.h:151
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:247
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:212
dd4hep::detail::tools::toString
std::string toString(const PlacedVolume::VolIDs &ids)
Convert VolumeID to string.
Definition: DetectorTools.cpp:385
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
dd4hep::DetElement::world
DetElement world() const
Access to the world object. Only possible once the geometry is closed.
Definition: DetElement.cpp:245
Printout.h