DD4hep  1.31.0
Detector Description Toolkit for High Energy Physics
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
DetectorCheck.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 #include <DD4hep/Detector.h>
16 #include <DD4hep/Printout.h>
17 #include <DD4hep/Factories.h>
18 #include <DD4hep/IDDescriptor.h>
19 #include <DD4hep/VolumeManager.h>
20 #include <DD4hep/DetectorTools.h>
21 #include <DD4hep/MatrixHelpers.h>
24 
25 // C/C++ include files
26 #include <cstdlib>
27 
28 using namespace dd4hep;
29 
31 namespace dd4hep { namespace detail { namespace tools {
33  std::string elementPath(const PlacementPath& nodes, bool reverse= false);
34  } } }
35 
36 namespace {
37 
39 
57  struct DetectorCheck {
58  using StructureElements = std::map<DetElement, size_t>;
59  using Chain = detail::tools::PlacementPath;
61 
63  struct FND {
64  const std::string& test;
65  FND(const std::string& c) : test(c) {}
66  bool operator()(const VolIDs::value_type& c) const { return c.first == test; }
67  };
68  struct counters {
69  size_t elements { 0 };
70  size_t errors { 0 };
71  void reset() { elements = errors = 0; }
72  counters& operator+=(const counters& c) {
73  elements += c.elements;
74  errors += c.errors;
75  return *this;
76  }
77  };
78 
79  Detector& description;
80  AlignmentsNominalMap m_mapping;
81  DetElement m_current_detector;
82  SensitiveDetector m_current_sensitive;
83  IDDescriptor m_current_iddesc;
84  VolumeManager m_volMgr;
85  DetElement m_det;
86  std::string m_name { "GeometryCheck" };
87 
88  counters m_place_counters, m_sens_counters, m_geo_counters, m_struct_counters;
89  StructureElements m_structure_elements;
90 
91  bool check_structure { false };
92  bool check_geometry { false };
93  bool check_placements { false };
94  bool check_volmgr { false };
95  bool check_sensitive { false };
96  bool ignore_detector { false };
97 
98  SensitiveDetector get_current_sensitive_detector();
99 
101  DetectorCheck(Detector& description);
103  virtual ~DetectorCheck() = default;
104 
106  void checkManagerSingleVolume(DetElement e, PlacedVolume pv, const VolIDs& child_ids, const Chain& chain);
108  void checkManagerVolumeTree(DetElement e, PlacedVolume pv, VolIDs ids, const Chain& chain, size_t depth, size_t mx_depth);
109 
111  void checkSingleVolume(DetElement e, PlacedVolume pv);
113  void checkVolumeTree(DetElement e, PlacedVolume pv);
114 
116  bool checkDetElement(const std::string& path, DetElement detector, PlacedVolume pv);
118  bool checkDetElementTree(const std::string& path, DetElement detector, PlacedVolume pv);
119 
120  void execute(DetElement sdet, size_t depth);
121 
123  static long run(Detector& description,int argc,char** argv);
124  static void help(int argc,char** argv);
125  };
126  const char* tag_fail(size_t errs) {
127  return errs==0 ? "PASSED" : "FAILED";
128  }
129 }
130 
131 
133 DetectorCheck::DetectorCheck(Detector& desc)
134  : description(desc), m_mapping(desc.world())
135 {
136 }
137 
138 SensitiveDetector DetectorCheck::get_current_sensitive_detector() {
139  DetElement de = m_current_detector;
140  m_current_sensitive = description.sensitiveDetector(de.name());
141  m_current_iddesc = IDDescriptor();
142  if ( m_current_sensitive.isValid() ) {
143  m_current_iddesc = m_current_sensitive.readout().idSpec();
144  }
145  return m_current_sensitive;
146 }
147 
148 void DetectorCheck::execute(DetElement sdet, size_t depth) {
149  const char* line = "============================";
150  struct counters count_volmgr_sens, count_volmgr_place;
151  struct counters total, count_struct;
152  struct counters count_geo, count_geo_sens;
153 
154  if ( !sdet.isValid() ) {
155  ++m_place_counters.errors;
156  except("VolumeMgrTest", "The detector element is not known to the geometry.");
157  return;
158  }
159 
160  m_det = sdet;
161  m_current_detector = m_det;
162 
164  if ( check_sensitive || check_volmgr ) {
165  if ( m_det == m_det.world() ) {
166  m_current_sensitive = SensitiveDetector();
167  m_current_iddesc = IDDescriptor();
168  }
169  else {
170  m_current_sensitive = description.sensitiveDetector(m_det.name());
171  if ( !m_current_sensitive.isValid() ) {
172  printout(ERROR, m_name,
173  "The sensitive detector of subdetector %s "
174  "is not known to the geometry.", m_det.name());
175  return;
176  }
177  m_current_iddesc = m_current_sensitive.readout().idSpec();
178  }
179  }
181  if ( check_structure ) {
182  printout(ALWAYS, m_name, "%s%s Executing STRUCTURE test %s%s", line, line, line, line);
183  PlacedVolume pv = m_det.placement();
184  checkDetElementTree(m_det.path(), m_det, pv);
185  count_struct.elements = m_structure_elements.size();
186  count_struct.errors = m_struct_counters.errors;
187  total += count_struct;
188  m_structure_elements.clear();
189  m_struct_counters.reset();
190  }
191  if ( check_geometry ) {
192  printout(ALWAYS, m_name, "%s%s Executing GEOMETRY test %s%s", line, line, line, line);
193  PlacedVolume pv = m_det.placement();
194  checkVolumeTree(m_det, pv);
195  count_geo = m_geo_counters;
196  count_geo_sens = m_sens_counters;
197  total += count_geo_sens;
198  total += count_geo;
199  m_sens_counters.reset();
200  m_geo_counters.reset();
201  }
202 
203  if ( check_volmgr ) {
204  Chain chain;
205  PlacedVolume pv = m_det.placement();
206  VolIDs ids;
207 
208  printout(ALWAYS, m_name, "%s%s Executing VOLUME MANAGER test %s%s", line, line, line, line);
209  chain.emplace_back(pv);
210  m_volMgr = description.volumeManager();
211  if ( !m_volMgr.isValid() ) {
212  printout(ERROR, m_name, "Volume manager is not instantiated. Required for test!");
213  return;
214  }
215  if ( pv.volume() != description.worldVolume() ) {
216  ids = pv.volIDs();
217  }
218  m_sens_counters.reset();
219  m_current_detector = m_det;
220  checkManagerVolumeTree(m_det, pv, std::move(ids), chain, 1, depth);
221  count_volmgr_place = m_place_counters;
222  count_volmgr_sens = m_sens_counters;
223  total += count_volmgr_place;
224  total += count_volmgr_sens;
225  m_place_counters.reset();
226  m_sens_counters.reset();
227  }
228 
229  if ( check_structure ) {
230  printout(count_struct.errors > 0 ? ERROR : ALWAYS,
231  m_name, "+++ %s: Checked %10ld structure elements. Num.Errors:%6ld (structure test)",
232  tag_fail(count_struct.errors), count_struct.elements, count_struct.errors);
233  }
234  if ( check_geometry ) {
235  if ( check_sensitive ) {
236  printout(count_geo_sens.errors > 0 ? ERROR : ALWAYS,
237  m_name, "+++ %s: Checked %10ld sensitive elements. Num.Errors:%6ld (geometry test)",
238  tag_fail(count_geo_sens.errors), count_geo_sens.elements, count_geo_sens.errors);
239  }
240  printout(count_geo.errors > 0 ? ERROR : ALWAYS,
241  m_name, "+++ %s: Checked %10ld placements. Num.Errors:%6ld (geometry test)",
242  tag_fail(count_geo.errors), count_geo.elements, count_geo.errors);
243  }
244  if ( check_volmgr ) {
245  if ( check_sensitive ) {
246  printout(count_volmgr_sens.errors > 0 ? ERROR : ALWAYS,
247  m_name, "+++ %s: Checked %10ld sensitive elements. Num.Errors:%6ld (phys.VolID test)",
248  tag_fail(count_volmgr_sens.errors), count_volmgr_sens.elements, count_volmgr_sens.errors);
249  }
250  printout(count_volmgr_place.errors > 0 ? ERROR : ALWAYS,
251  m_name, "+++ %s: Checked %10ld sensitive placements. Num.Errors:%6ld (phys.VolID test)",
252  tag_fail(count_volmgr_place.errors), count_volmgr_sens.elements, count_volmgr_place.errors);
253  }
254  printout(ALWAYS, m_name, "+++ %s: Checked a total of %11ld elements. Num.Errors:%6ld (Some elements checked twice)",
255  tag_fail(total.errors), total.elements, total.errors);
256 }
257 
259 bool DetectorCheck::checkDetElement(const std::string& path, DetElement detector, PlacedVolume pv) {
260  bool det_valid = true;
261  bool parent_valid = true;
262  bool place_valid = true;
263  bool det_place_valid = true;
264  bool vol_valid = true;
265  auto nerrs = m_struct_counters.errors;
266  const char* de_path = detector.path().c_str();
267 
268  if ( !pv.isValid() ) {
269  printout(ERROR, m_name, "Invalid DetElement placement: %s", de_path);
270  ++m_struct_counters.errors;
271  place_valid = false;
272  }
273  if ( detector.path() != path ) {
274  printout(ERROR, m_name, "Invalid DetElement [path mismatch]: %s <> %s",
275  de_path, path.c_str());
276  ++m_struct_counters.errors;
277  }
278  if ( !detector.parent().isValid() && detector.world() != detector ) {
279  printout(ERROR, m_name, "Invalid DetElement [No parent]: %s", de_path);
280  ++m_struct_counters.errors;
281  parent_valid = false;
282  }
283  if ( !detector.placement().isValid() ) {
284  printout(ERROR, m_name, "Invalid DetElement [No placement]: %s", de_path);
285  ++m_struct_counters.errors;
286  det_place_valid = false;
287  }
288  else if ( !detector.volume().isValid() ) {
289  printout(ERROR, m_name, "Invalid DetElement [No volume]: %s", de_path);
290  ++m_struct_counters.errors;
291  vol_valid = false;
292  }
293  if ( detector.placement().isValid() && detector.placement() != pv ) {
294  printout(ERROR, m_name, "Invalid DetElement [Mismatched placement]: %s", de_path);
295  ++m_struct_counters.errors;
296  det_place_valid = false;
297  }
298  auto count = ++m_structure_elements[detector];
299  if ( count > 1 ) {
300  DetElement par = detector.parent();
301  printout(ERROR, m_name, "DetElement %s parent: %s is placed %ld times! Only single placement allowed.",
302  de_path, par.isValid() ? par.path().c_str() : "", m_structure_elements[detector]);
303  ++m_struct_counters.errors;
304  }
305  Alignment ideal = detector.nominal();
306  if ( !ideal.isValid() ) {
307  printout(ERROR, m_name, "Invalid DetElement [No ideal alignment]: %s", de_path);
308  ++m_struct_counters.errors;
309  }
310  Alignment survey = detector.survey();
311  if ( !survey.isValid() ) {
312  printout(ERROR, m_name, "Invalid DetElement [No survey alignment]: %s", de_path);
313  ++m_struct_counters.errors;
314  }
315  if ( ideal.isValid() ) {
316  const TGeoHMatrix& matrix = ideal.worldTransformation();
317  if ( matrix.IsIdentity() ) {
318  }
319  }
320  printout(nerrs != m_struct_counters.errors ? ERROR : INFO, m_name,
321  "DetElement %s [%s] parent: %s placement: %s [%s] volume: %s",
322  path.c_str(), yes_no(det_valid), yes_no(parent_valid), yes_no(det_place_valid),
323  yes_no(place_valid), yes_no(vol_valid));
324  return nerrs == m_struct_counters.errors;
325 }
326 
328 bool DetectorCheck::checkDetElementTree(const std::string& path, DetElement detector, PlacedVolume pv) {
329  auto nerrs = m_struct_counters.errors;
330  if ( !detector.isValid() ) {
331  printout(ERROR, m_name, "Invalid DetElement seen: %s", path.c_str());
332  ++m_struct_counters.errors;
333  return false;
334  }
335  bool is_world = detector == detector.world();
337  checkDetElement(path, detector, pv);
339  for ( const auto& c : detector.children() ) {
340  DetElement de = c.second;
341  if ( is_world ) {
342  m_current_sensitive = SensitiveDetector();
343  m_current_iddesc = IDDescriptor();
344  m_current_detector = de;
345  }
346  if ( de.parent().isValid() && de.parent() != detector ) {
347  printout(ERROR, m_name, "Invalid DetElement [Parent mismatch]: %s", de.path().c_str());
348  printout(ERROR, m_name, " apparent parent: %s structural parent: %s",
349  de.parent().path().c_str(), detector.path().c_str());
350  ++m_struct_counters.errors;
351  }
353  checkDetElementTree(path + "/" + c.first, de, de.placement());
354  }
355  return nerrs == m_struct_counters.errors;
356 }
357 
359 void DetectorCheck::checkSingleVolume(DetElement e, PlacedVolume pv) {
360 
361  ++m_geo_counters.elements;
363  if ( !e.isValid() ) {
364  printout(ERROR, m_name, "Invalid DetElement [Invalid handle]");
365  ++m_geo_counters.errors;
366  }
368  if ( !pv.isValid() ) {
369  printout(ERROR, m_name, "Invalid PlacedVolume [Invalid handle] DetElement: %s", e.path().c_str());
370  ++m_geo_counters.errors;
371  }
372  Volume vol = pv.volume();
374  if ( !vol.isValid() ) {
375  printout(ERROR, m_name, "Invalid Volume [Invalid handle] DetElement: %s", e.path().c_str());
376  ++m_geo_counters.errors;
377  return;
378  }
380  if ( check_sensitive && vol.isSensitive() ) {
382  ++m_sens_counters.elements;
383  if ( !sdv.isValid() ) {
384  printout(ERROR, m_name, "Invalid SensitiveDetector DetElement: %s", e.path().c_str());
385  ++m_sens_counters.errors;
386  }
387  SensitiveDetector sdd = get_current_sensitive_detector();
388  if ( sdd != sdv ) {
389  printout(ERROR, m_name, "Inconsistent sensitive detectors for DetElement: %s", e.path().c_str());
390  ++m_sens_counters.errors;
391  }
392  }
393 }
394 
396 void DetectorCheck::checkVolumeTree(DetElement detector, PlacedVolume pv) {
397  const TGeoNode* current = pv.ptr();
398  TObjArray* nodes = current->GetNodes();
399  int num_children = nodes ? nodes->GetEntriesFast() : 0;
400  bool is_world = detector == description.world();
401 
403  checkSingleVolume(detector, pv);
405  for(int i=0; i < num_children; ++i) {
406  TGeoNode* node = (TGeoNode*)nodes->At(i);
407  PlacedVolume place(node);
408  DetElement de = detector;
409 
410  if ( is_world ) {
411  m_current_detector = de;
412  get_current_sensitive_detector();
413  }
414 
416  for ( const auto& c : detector.children() ) {
417  if ( c.second.placement() == place ) {
418  de = c.second;
419  break;
420  }
421  }
422  checkVolumeTree(de, place);
423  if ( is_world ) {
424  m_current_sensitive = SensitiveDetector();
425  m_current_iddesc = IDDescriptor();
426  }
427  }
428 }
429 
431 void DetectorCheck::checkManagerSingleVolume(DetElement detector, PlacedVolume pv, const VolIDs& child_ids, const Chain& chain) {
432  std::stringstream err, log;
433  VolumeID det_vol_id = detector.volumeID();
434  VolumeID vid = det_vol_id;
435  DetElement top_sdet, det_elem;
436  VolumeManagerContext* mgr_ctxt = 0;
437 
438  ++m_place_counters.elements;
439 
440  try {
441  vid = m_current_iddesc.encode(child_ids);
442  top_sdet = m_volMgr.lookupDetector(vid);
443  det_elem = m_volMgr.lookupDetElement(vid);
444  mgr_ctxt = m_volMgr.lookupContext(vid);
445 
446  if ( pv.volume().isSensitive() ) {
447  PlacedVolume det_place = m_volMgr.lookupDetElementPlacement(vid);
448  ++m_sens_counters.elements;
449  if ( !ignore_detector && pv.ptr() != det_place.ptr() ) {
450  err << "VolumeMgrTest: Wrong placement "
451  << " got " << det_place.name() << " (" << (void*)det_place.ptr() << ")"
452  << " instead of " << pv.name() << " (" << (void*)pv.ptr() << ") "
453  << " vid:" << volumeID(vid);
454  ++m_place_counters.errors;
455  }
456  else if ( top_sdet.ptr() != detector.ptr() ) {
457  top_sdet = m_volMgr.lookupDetector(vid);
458  err << "VolumeMgrTest: Wrong associated sub-detector element vid=" << volumeID(vid)
459  << " got " << top_sdet.path() << " (" << (void*)top_sdet.ptr() << ") "
460  << " instead of " << detector.path() << " (" << (void*)detector.ptr() << ")"
461  << " vid:" << volumeID(vid);
462  ++m_place_counters.errors;
463  }
464  else if ( !detail::tools::isParentElement(detector,det_elem) ) {
465  // This is sort of a bit wischi-waschi....
466  err << "VolumeMgrTest: Wrong associated detector element vid=" << volumeID(vid)
467  << " got " << det_elem.path() << " (" << (void*)det_elem.ptr() << ") "
468  << " instead of " << detector.path() << " (" << (void*)detector.ptr() << ")"
469  << " vid:" << volumeID(vid);
470  ++m_place_counters.errors;
471  }
472  else if ( top_sdet.ptr() != m_det.ptr() ) {
473  err << "VolumeMgrTest: Wrong associated detector "
474  << " vid:" << volumeID(vid);
475  ++m_place_counters.errors;
476  }
477  }
478  }
479  catch(const std::exception& ex) {
480  err << "Lookup " << pv.name() << " id:" << volumeID(vid)
481  << " path:" << detector.path() << " error:" << ex.what();
482  ++m_place_counters.errors;
483  }
484 
485  if ( pv.volume().isSensitive() || (0 != det_vol_id) ) {
486  std::string id_desc;
487  log << "Volume:" << std::setw(50) << std::left << pv.name();
488  if ( pv.volume().isSensitive() ) {
490  log << " IDDesc:" << (char*)(dsc.ptr() == m_current_iddesc.ptr() ? "OK " : "BAD");
491  if ( dsc.ptr() != m_current_iddesc.ptr() ) ++m_place_counters.errors;
492  }
493  else {
494  log << std::setw(11) << " ";
495  }
496  id_desc = m_current_iddesc.str(vid);
497  log << " [" << char(pv.volume().isSensitive() ? 'S' : 'N') << "] " << std::right
498  << " vid:" << volumeID(vid)
499  << " " << id_desc;
500  if ( !err.str().empty() ) {
501  printout(ERROR, m_det.name(),err.str()+" "+log.str());
502  //throw std::runtime_error(err.str());
503  return;
504  }
505  id_desc = m_current_iddesc.str(det_elem.volumeID());
506  printout(INFO, m_det.name(),log.str());
507  printout(INFO, m_det.name(), " Elt:%-64s vid:%s %s Parent-OK:%3s",
508  det_elem.path().c_str(),volumeID(det_elem.volumeID()).c_str(),
509  id_desc.c_str(),
510  yes_no(detail::tools::isParentElement(detector,det_elem)));
511 
512  try {
513  if ( pv.volume().isSensitive() ) {
514  TGeoHMatrix trafo;
515  for (size_t i = chain.size()-1; i > 0; --i) {
516  //for (size_t i = 0; i<chain.size(); ++i ) {
517  const TGeoMatrix* mat = chain[i]->GetMatrix();
518  trafo.MultiplyLeft(mat);
519  }
520  for (size_t i = chain.size(); i > 0; --i) {
521  const TGeoMatrix* mat = chain[i-1]->GetMatrix();
522  if ( printLevel() <= INFO ) {
523  ::printf("Placement [%d] VolID:%s\t\t",int(i),chain[i-1].volIDs().str().c_str());
524  mat->Print();
525  }
526  }
527  det_elem = m_volMgr.lookupDetElement(vid);
528  if ( printLevel() <= INFO ) {
529  ::printf("Computed Trafo (from placements):\t\t");
530  trafo.Print();
531  ::printf("DetElement Trafo: %s [%s]\t\t",
532  det_elem.path().c_str(),volumeID(det_elem.volumeID()).c_str());
533  det_elem.nominal().worldTransformation().Print();
534  ::printf("VolumeMgr Trafo: %s [%s]\t\t",det_elem.path().c_str(),volumeID(vid).c_str());
535  m_volMgr.worldTransformation(m_mapping,vid).Print();
536  }
537 
539  if ( 0 == mgr_ctxt ) {
540  printout(ERROR, m_det.name(), "VOLUME_MANAGER FAILED: Could not find entry for vid:%s.",
541  volumeID(vid).c_str());
542  ++m_place_counters.errors;
543  }
544 
546  if ( &det_elem.nominal().worldTransformation() != &m_volMgr.worldTransformation(m_mapping,det_elem.volumeID()) )
547  {
548  printout(ERROR, m_det.name(), "DETELEMENT_PERSISTENCY FAILED: World transformation have DIFFERET pointer!");
549  ++m_place_counters.errors;
550  }
551 
552  if ( !ignore_detector ) {
553  if ( pv.ptr() == det_elem.placement().ptr() ) {
554  // The computed transformation 'trafo' MUST be equal to:
555  // m_volMgr.worldTransformation(vid) AND det_elem.nominal().worldTransformation()
556  int res1 = detail::matrix::_matrixEqual(trafo, det_elem.nominal().worldTransformation());
557  int res2 = detail::matrix::_matrixEqual(trafo, m_volMgr.worldTransformation(m_mapping,vid));
559  printout(ERROR, m_det.name(), "DETELEMENT_PLACEMENT FAILED: World transformation DIFFER.");
560  ++m_place_counters.errors;
561  }
562  else {
563  printout(INFO, m_det.name(), "DETELEMENT_PLACEMENT: PASSED. All matrices equal: %s",
564  volumeID(vid).c_str());
565  }
566  }
567  else {
568  // The computed transformation 'trafo' MUST be equal to:
569  // m_volMgr.worldTransformation(vid)
570  // The det_elem.nominal().worldTransformation() however is DIFFERENT!
571  int res2 = detail::matrix::_matrixEqual(trafo, m_volMgr.worldTransformation(m_mapping,vid));
572  if ( res2 != detail::matrix::MATRICES_EQUAL ) {
573  printout(ERROR, m_det.name(), "VOLUME_PLACEMENT FAILED: World transformation DIFFER.");
574  ++m_place_counters.errors;
575  }
576  else {
577  printout(INFO, m_det.name(), "VOLUME_PLACEMENT: PASSED. All matrices equal: %s",
578  volumeID(vid).c_str());
579  }
580  }
581  }
582  }
583  }
584  catch(const std::exception& ex) {
585  err << "Matrix " << pv.name() << " id:" << volumeID(vid)
586  << " path:" << detector.path() << " error:" << ex.what();
587  ++m_place_counters.errors;
588  }
589 
590  }
591 }
592 
594 void DetectorCheck::checkManagerVolumeTree(DetElement detector, PlacedVolume pv, VolIDs ids, const Chain& chain,
595  size_t depth, size_t mx_depth)
596 {
597  if ( depth <= mx_depth ) {
598  const TGeoNode* current = pv.ptr();
599  TObjArray* nodes = current->GetNodes();
600  int num_children = nodes ? nodes->GetEntriesFast() : 0;
601  bool is_world = detector == description.world();
602 
603  for(int i=0; i<num_children; ++i) {
604  TGeoNode* node = (TGeoNode*)nodes->At(i);
605  PlacedVolume place(node);
606  VolIDs child_ids(ids);
607  Chain child_chain(chain);
608  DetElement de = detector;
609  if ( is_world ) {
611  for ( const auto& c : detector.children() ) {
612  if ( c.second.placement() == place ) {
613  de = c.second;
614  break;
615  }
616  }
617  m_current_detector = de;
618  get_current_sensitive_detector();
619  }
620  place.access(); // Test validity
621  child_chain.emplace_back(place);
622  child_ids.insert(child_ids.end(), place.volIDs().begin(), place.volIDs().end());
623  checkManagerSingleVolume(de, place, child_ids, child_chain);
624  checkManagerVolumeTree(de, place, std::move(child_ids), child_chain, depth+1, mx_depth);
625  }
626  }
627 }
628 
629 void DetectorCheck::help(int argc,char** argv) {
630  std::cout
631  <<
632  "DD4hep_DetectorCheck -option [-option] \n"
633  " -help Print this help message \n"
634  " -name <subdetector name> Name of the subdetector to be checked \n"
635  " \"ALL\" or \"all\": loop over known subdetectors\n"
636  " \"world\" start from the mother of all... \n"
637  " -structure Check structural tree consistency \n"
638  " -geometry Check geometry tree consistency \n"
639  " -sensitve Check consistency between detector and volume \n"
640  " settings of sensitive detectors. \n"
641  " -volmgr Check volume manager entries against volIDs of \n"
642  " sensitive volume placements. \n\n"
643  " NOTE: Option requires proper PhysVolID setup \n"
644  " of the sensitive volume placements ! \n"
645  " -ignore_detector Ignore DetElement placement check for -volmgr \n"
646  << std::endl;
647  std::cout << "Arguments: " << std::endl;
648  for(int iarg=0; iarg<argc;++iarg) {
649  std::cout << "Argument[" << iarg << "] = " << argv[iarg] << std::endl;
650  }
651  ::exit(EINVAL);
652 }
653 
655 long DetectorCheck::run(Detector& description,int argc,char** argv) {
656  std::string name;
657  bool volmgr = false;
658  bool geometry = false;
659  bool structure = false;
660  bool sensitive = false;
661  bool placements = false;
662  bool ignore_de = false;
663  printout(ALWAYS, "DetectorCheck", "++ Processing plugin...");
664  for(int iarg=0; iarg<argc;++iarg) {
665  if ( argv[iarg] == 0 ) break;
666  if ( ::strncasecmp(argv[iarg], "-name",4) == 0 && (iarg+1) < argc )
667  name = argv[++iarg];
668  else if ( ::strncasecmp(argv[iarg], "-structure",4) == 0 )
669  structure = true;
670  else if ( ::strncasecmp(argv[iarg], "-placements",4) == 0 )
671  placements = true;
672  else if ( ::strncasecmp(argv[iarg], "-volmgr",4) == 0 )
673  volmgr = true;
674  else if ( ::strncasecmp(argv[iarg], "-geometry",4) == 0 )
675  geometry = true;
676  else if ( ::strncasecmp(argv[iarg], "-sensitive",4) == 0 )
677  sensitive = true;
678  else if ( ::strncasecmp(argv[iarg], "-ignore_detelement",4) == 0 )
679  ignore_de = true;
680  else if ( ::strncasecmp(argv[iarg], "-help",4) == 0 )
681  help(argc, argv);
682  else
683  help(argc, argv);
684  }
685  if ( argc == 0 ) help(argc, argv);
686  if ( !name.empty() ) {
687  DetectorCheck test(description);
688  if ( name == "all" || name == "All" || name == "ALL" ) {
689  for (const auto& det : description.detectors() ) {
690  printout(INFO, "DetectorCheck", "++ Processing subdetector: %s", det.second.name());
691  test.check_structure = structure;
692  test.check_placements = placements;
693  test.check_volmgr = volmgr;
694  test.check_geometry = geometry;
695  test.check_sensitive = sensitive;
696  test.ignore_detector = ignore_de;
697  test.execute(det.second, 9999);
698  }
699  return 1;
700  }
701  DetElement det = (::strcasecmp(name.c_str(), "world") == 0)
702  ? description.world() : description.detector(name);
703  printout(INFO, "DetectorCheck", "++ Processing subdetector: %s",name.c_str());
704  test.check_structure = structure;
705  test.check_placements = placements;
706  test.check_volmgr = volmgr;
707  test.check_geometry = geometry;
708  test.check_sensitive = sensitive;
709  test.ignore_detector = ignore_de;
710  test.execute(det, 9999);
711  }
712  return 1;
713 }
714 
715 DECLARE_APPLY(DD4hep_DetectorCheck,DetectorCheck::run)
716 
717 long run_VolumeMgrTest(Detector& description,int argc, const char*const* argv) {
719  const char* args[] = {"-name", argc > 0 ? argv[0] : "world", "-structure", "-geometry", "-volmgr", 0 };
720  return DetectorCheck::run(description, 6, (char**)args);
721 }
722 DECLARE_APPLY(DD4hep_VolumeMgrTest,run_VolumeMgrTest)
dd4hep::DetElement::children
const Children & children() const
Access to the list of children.
Definition: DetElement.cpp:207
dd4hep::DetElement::path
const std::string & path() const
Path of the detector element (not necessarily identical to placement path!)
Definition: DetElement.cpp:158
dd4hep::Detector::world
virtual DetElement world() const =0
Return reference to the top-most (world) detector element.
dd4hep::Detector::detector
virtual DetElement detector(const std::string &name) const =0
Retrieve a subdetector element by its name from the detector description.
dd4hep::SensitiveDetector
Handle class to hold the information of a sensitive detector.
Definition: DetElement.h:43
dd4hep::DetElement::parent
DetElement parent() const
Access to the detector elements's parent.
Definition: DetElement.cpp:239
MatrixHelpers.h
Detector.h
dd4hep::AlignmentsNominalMap
An implementation of the ConditionsMap interface to fall back to nominal alignment.
Definition: AlignmentsNominalMap.h:44
dd4hep::exception
void exception(const std::string &src, const std::string &msg)
Definition: RootDictionary.h:69
dd4hep::PlacedVolume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:164
dd4hep::Detector::detectors
virtual const HandleMap & detectors() const =0
Accessor to the map of sub-detectors.
dd4hep::DetElement::placement
PlacedVolume placement() const
Access to the physical volume of this detector element.
Definition: DetElement.cpp:321
VolumeManagerInterna.h
dd4hep::IDDescriptor
Class implementing the ID encoding of the detector response.
Definition: IDDescriptor.h:36
DECLARE_APPLY
#define DECLARE_APPLY(name, func)
Definition: Factories.h:281
AlignmentsNominalMap.h
dd4hep::Handle::isValid
bool isValid() const
Check the validity of the object held by the handle.
Definition: Handle.h:126
dd4hep::Volume::isSensitive
bool isSensitive() const
Accessor if volume is sensitive (ie. is attached to a sensitive detector)
Definition: Volumes.cpp:1322
dd4hep::DetElement::volumeID
VolumeID volumeID() const
The cached VolumeID of this subdetector element.
Definition: DetElement.cpp:344
Factories.h
dd4hep::Handle::name
const char * name() const
Access the object name (or "" if not supported by the object)
help
void help(std::string argv0)
Definition: listcomponents.cpp:29
dd4hep::detail::printf
std::size_t printf(const char *fmt,...)
Definition: Printout.cpp:97
VolumeManager.h
run_VolumeMgrTest
long run_VolumeMgrTest(Detector &description, int argc, const char *const *argv)
Action routine to execute the test for backwards compatibility.
Definition: DetectorCheck.cpp:718
dd4hep::DetElement
Handle class describing a detector element.
Definition: DetElement.h:187
dd4hep::PlacedVolumeExtension::VolIDs
Volume ID container.
Definition: Volumes.h:89
dd4hep::Volume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:371
dd4hep::detail::matrix::MATRICES_EQUAL
@ MATRICES_EQUAL
Definition: MatrixHelpers.h:121
dd4hep::VolumeManager
Class to support the retrieval of detector elements and volumes given a valid identifier.
Definition: VolumeManager.h:135
dd4hep::DetElement::volume
Volume volume() const
Access to the logical volume of the detector element's placement.
Definition: DetElement.cpp:352
dd4hep::Alignment::worldTransformation
const TGeoHMatrix & worldTransformation() const
Create cached matrix to transform to world coordinates.
Definition: Alignments.cpp:68
DetectorTools.h
dd4hep::IDDescriptor::str
std::string str(VolumeID vid) const
Decode volume IDs and return string reprensentation for debugging purposes.
Definition: IDDescriptor.cpp:174
dd4hep::Alignment
Main handle class to hold an alignment object.
Definition: Alignments.h:115
dd4hep::DetElement::nominal
Alignment nominal() const
Access to the constant ideal (nominal) alignment information.
Definition: DetElement.cpp:185
dd4hep::PlacedVolume::VolIDs
PlacedVolumeExtension::VolIDs VolIDs
Definition: Volumes.h:167
dd4hep::sim::IDDescriptor
IDDescriptor IDDescriptor
Definition: LCIOConversions.cpp:69
dd4hep::detail::tools::isParentElement
bool isParentElement(DetElement parent, DetElement child)
Find path between the child element and the parent element.
Definition: DetectorTools.cpp:58
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:208
IDDescriptor.h
dd4hep::Handle::ptr
T * ptr() const
Access to the held object.
Definition: Handle.h:151
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
det
DetElement::Object * det
Definition: AlignmentsCalculator.cpp:66
dd4hep::SensitiveDetector::readout
Readout readout() const
Access readout structure of the sensitive detector.
Definition: DetElement.cpp:420
dd4hep::detail::tools::PlacementPath
std::vector< PlacedVolume > PlacementPath
Definition: DetectorTools.h:39
dd4hep::PlacedVolume::volume
Volume volume() const
Logical volume of this placement.
Definition: Volumes.cpp:468
dd4hep::PlacedVolumeExtension::VolIDs::insert
std::pair< std::vector< VolID >::iterator, bool > insert(const std::string &name, int value)
Insert new entry.
Definition: Volumes.cpp:422
dd4hep::VolumeManagerContext
This structure describes the cached data for one placement held by the volume manager.
Definition: VolumeManager.h:50
dd4hep::Detector
The main interface to the dd4hep detector description package.
Definition: Detector.h:90
dd4hep::detail::matrix::_matrixEqual
int _matrixEqual(const TGeoMatrix &left, const TGeoMatrix &right)
Check matrices for equality.
Definition: MatrixHelpers.cpp:277
dd4hep::Readout::idSpec
IDDescriptor idSpec() const
Access IDDescription structure.
Definition: Readout.cpp:112
dd4hep::PlacedVolume::volIDs
const PlacedVolumeExtension::VolIDs & volIDs() const
Access to the volume IDs.
Definition: Volumes.cpp:496
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
dd4hep::DetElement::survey
Alignment survey() const
Access to the constant survey alignment information.
Definition: DetElement.cpp:198
Printout.h
dd4hep::Volume::sensitiveDetector
Handle< NamedObject > sensitiveDetector() const
Access to the handle to the sensitive detector.
Definition: Volumes.cpp:1316