File indexing completed on 2025-07-05 08:13:37
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <DD4hep/Detector.h>
0016 #include <DD4hep/Printout.h>
0017 #include <DD4hep/Factories.h>
0018 #include <DD4hep/IDDescriptor.h>
0019 #include <DD4hep/VolumeManager.h>
0020 #include <DD4hep/DetectorTools.h>
0021 #include <DD4hep/MatrixHelpers.h>
0022 #include <DD4hep/AlignmentsNominalMap.h>
0023 #include <DD4hep/detail/VolumeManagerInterna.h>
0024
0025
0026 #include <cstdlib>
0027
0028 using namespace dd4hep;
0029
0030
0031 namespace dd4hep { namespace detail { namespace tools {
0032
0033 std::string elementPath(const PlacementPath& nodes, bool reverse= false);
0034 } } }
0035
0036 namespace {
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 struct DetectorCheck {
0058 using StructureElements = std::map<DetElement, size_t>;
0059 using Chain = detail::tools::PlacementPath;
0060 using VolIDs = PlacedVolume::VolIDs;
0061
0062
0063 struct FND {
0064 const std::string& test;
0065 FND(const std::string& c) : test(c) {}
0066 bool operator()(const VolIDs::value_type& c) const { return c.first == test; }
0067 };
0068 struct counters {
0069 size_t elements { 0 };
0070 size_t errors { 0 };
0071 void reset() { elements = errors = 0; }
0072 counters& operator+=(const counters& c) {
0073 elements += c.elements;
0074 errors += c.errors;
0075 return *this;
0076 }
0077 };
0078
0079 Detector& description;
0080 AlignmentsNominalMap m_mapping;
0081 DetElement m_current_detector;
0082 SensitiveDetector m_current_sensitive;
0083 IDDescriptor m_current_iddesc;
0084 VolumeManager m_volMgr;
0085 DetElement m_det;
0086 std::string m_name { "GeometryCheck" };
0087
0088 counters m_place_counters, m_sens_counters, m_geo_counters, m_struct_counters;
0089 StructureElements m_structure_elements;
0090
0091 bool check_structure { false };
0092 bool check_geometry { false };
0093 bool check_placements { false };
0094 bool check_volmgr { false };
0095 bool check_sensitive { false };
0096 bool ignore_detector { false };
0097
0098 SensitiveDetector get_current_sensitive_detector();
0099
0100
0101 DetectorCheck(Detector& description);
0102
0103 virtual ~DetectorCheck() = default;
0104
0105
0106 void checkManagerSingleVolume(DetElement e, PlacedVolume pv, const VolIDs& child_ids, const Chain& chain);
0107
0108 void checkManagerVolumeTree(DetElement e, PlacedVolume pv, VolIDs ids, const Chain& chain, size_t depth, size_t mx_depth);
0109
0110
0111 void checkSingleVolume(DetElement e, PlacedVolume pv);
0112
0113 void checkVolumeTree(DetElement e, PlacedVolume pv);
0114
0115
0116 bool checkDetElement(const std::string& path, DetElement detector, PlacedVolume pv);
0117
0118 bool checkDetElementTree(const std::string& path, DetElement detector, PlacedVolume pv);
0119
0120 void execute(DetElement sdet, size_t depth);
0121
0122
0123 static long run(Detector& description,int argc,char** argv);
0124 static void help(int argc,char** argv);
0125 };
0126 const char* tag_fail(size_t errs) {
0127 return errs==0 ? "PASSED" : "FAILED";
0128 }
0129 }
0130
0131
0132
0133 DetectorCheck::DetectorCheck(Detector& desc)
0134 : description(desc), m_mapping(desc.world())
0135 {
0136 }
0137
0138 SensitiveDetector DetectorCheck::get_current_sensitive_detector() {
0139 DetElement de = m_current_detector;
0140 m_current_sensitive = description.sensitiveDetector(de.name());
0141 m_current_iddesc = IDDescriptor();
0142 if ( m_current_sensitive.isValid() ) {
0143 m_current_iddesc = m_current_sensitive.readout().idSpec();
0144 }
0145 return m_current_sensitive;
0146 }
0147
0148 void DetectorCheck::execute(DetElement sdet, size_t depth) {
0149 const char* line = "============================";
0150 struct counters count_volmgr_sens, count_volmgr_place;
0151 struct counters total, count_struct;
0152 struct counters count_geo, count_geo_sens;
0153
0154 if ( !sdet.isValid() ) {
0155 ++m_place_counters.errors;
0156 except("VolumeMgrTest", "The detector element is not known to the geometry.");
0157 return;
0158 }
0159
0160 m_det = sdet;
0161 m_current_detector = m_det;
0162
0163
0164 if ( check_sensitive || check_volmgr ) {
0165 if ( m_det == m_det.world() ) {
0166 m_current_sensitive = SensitiveDetector();
0167 m_current_iddesc = IDDescriptor();
0168 }
0169 else {
0170 m_current_sensitive = description.sensitiveDetector(m_det.name());
0171 if ( !m_current_sensitive.isValid() ) {
0172 printout(ERROR, m_name,
0173 "The sensitive detector of subdetector %s "
0174 "is not known to the geometry.", m_det.name());
0175 return;
0176 }
0177 m_current_iddesc = m_current_sensitive.readout().idSpec();
0178 }
0179 }
0180
0181 if ( check_structure ) {
0182 printout(ALWAYS, m_name, "%s%s Executing STRUCTURE test %s%s", line, line, line, line);
0183 PlacedVolume pv = m_det.placement();
0184 checkDetElementTree(m_det.path(), m_det, pv);
0185 count_struct.elements = m_structure_elements.size();
0186 count_struct.errors = m_struct_counters.errors;
0187 total += count_struct;
0188 m_structure_elements.clear();
0189 m_struct_counters.reset();
0190 }
0191 if ( check_geometry ) {
0192 printout(ALWAYS, m_name, "%s%s Executing GEOMETRY test %s%s", line, line, line, line);
0193 PlacedVolume pv = m_det.placement();
0194 checkVolumeTree(m_det, pv);
0195 count_geo = m_geo_counters;
0196 count_geo_sens = m_sens_counters;
0197 total += count_geo_sens;
0198 total += count_geo;
0199 m_sens_counters.reset();
0200 m_geo_counters.reset();
0201 }
0202
0203 if ( check_volmgr ) {
0204 Chain chain;
0205 PlacedVolume pv = m_det.placement();
0206 VolIDs ids;
0207
0208 printout(ALWAYS, m_name, "%s%s Executing VOLUME MANAGER test %s%s", line, line, line, line);
0209 chain.emplace_back(pv);
0210 m_volMgr = description.volumeManager();
0211 if ( !m_volMgr.isValid() ) {
0212 printout(ERROR, m_name, "Volume manager is not instantiated. Required for test!");
0213 return;
0214 }
0215 if ( pv.volume() != description.worldVolume() ) {
0216 ids = pv.volIDs();
0217 }
0218 m_sens_counters.reset();
0219 m_current_detector = m_det;
0220 checkManagerVolumeTree(m_det, pv, std::move(ids), chain, 1, depth);
0221 count_volmgr_place = m_place_counters;
0222 count_volmgr_sens = m_sens_counters;
0223 total += count_volmgr_place;
0224 total += count_volmgr_sens;
0225 m_place_counters.reset();
0226 m_sens_counters.reset();
0227 }
0228
0229 if ( check_structure ) {
0230 printout(count_struct.errors > 0 ? ERROR : ALWAYS,
0231 m_name, "+++ %s: Checked %10ld structure elements. Num.Errors:%6ld (structure test)",
0232 tag_fail(count_struct.errors), count_struct.elements, count_struct.errors);
0233 }
0234 if ( check_geometry ) {
0235 if ( check_sensitive ) {
0236 printout(count_geo_sens.errors > 0 ? ERROR : ALWAYS,
0237 m_name, "+++ %s: Checked %10ld sensitive elements. Num.Errors:%6ld (geometry test)",
0238 tag_fail(count_geo_sens.errors), count_geo_sens.elements, count_geo_sens.errors);
0239 }
0240 printout(count_geo.errors > 0 ? ERROR : ALWAYS,
0241 m_name, "+++ %s: Checked %10ld placements. Num.Errors:%6ld (geometry test)",
0242 tag_fail(count_geo.errors), count_geo.elements, count_geo.errors);
0243 }
0244 if ( check_volmgr ) {
0245 if ( check_sensitive ) {
0246 printout(count_volmgr_sens.errors > 0 ? ERROR : ALWAYS,
0247 m_name, "+++ %s: Checked %10ld sensitive elements. Num.Errors:%6ld (phys.VolID test)",
0248 tag_fail(count_volmgr_sens.errors), count_volmgr_sens.elements, count_volmgr_sens.errors);
0249 }
0250 printout(count_volmgr_place.errors > 0 ? ERROR : ALWAYS,
0251 m_name, "+++ %s: Checked %10ld sensitive placements. Num.Errors:%6ld (phys.VolID test)",
0252 tag_fail(count_volmgr_place.errors), count_volmgr_sens.elements, count_volmgr_place.errors);
0253 }
0254 printout(ALWAYS, m_name, "+++ %s: Checked a total of %11ld elements. Num.Errors:%6ld (Some elements checked twice)",
0255 tag_fail(total.errors), total.elements, total.errors);
0256 }
0257
0258
0259 bool DetectorCheck::checkDetElement(const std::string& path, DetElement detector, PlacedVolume pv) {
0260 bool det_valid = true;
0261 bool parent_valid = true;
0262 bool place_valid = true;
0263 bool det_place_valid = true;
0264 bool vol_valid = true;
0265 auto nerrs = m_struct_counters.errors;
0266 const char* de_path = detector.path().c_str();
0267
0268 if ( !pv.isValid() ) {
0269 printout(ERROR, m_name, "Invalid DetElement placement: %s", de_path);
0270 ++m_struct_counters.errors;
0271 place_valid = false;
0272 }
0273 if ( detector.path() != path ) {
0274 printout(ERROR, m_name, "Invalid DetElement [path mismatch]: %s <> %s",
0275 de_path, path.c_str());
0276 ++m_struct_counters.errors;
0277 }
0278 if ( !detector.parent().isValid() && detector.world() != detector ) {
0279 printout(ERROR, m_name, "Invalid DetElement [No parent]: %s", de_path);
0280 ++m_struct_counters.errors;
0281 parent_valid = false;
0282 }
0283 if ( !detector.placement().isValid() ) {
0284 printout(ERROR, m_name, "Invalid DetElement [No placement]: %s", de_path);
0285 ++m_struct_counters.errors;
0286 det_place_valid = false;
0287 }
0288 else if ( !detector.volume().isValid() ) {
0289 printout(ERROR, m_name, "Invalid DetElement [No volume]: %s", de_path);
0290 ++m_struct_counters.errors;
0291 vol_valid = false;
0292 }
0293 if ( detector.placement().isValid() && detector.placement() != pv ) {
0294 printout(ERROR, m_name, "Invalid DetElement [Mismatched placement]: %s", de_path);
0295 ++m_struct_counters.errors;
0296 det_place_valid = false;
0297 }
0298 auto count = ++m_structure_elements[detector];
0299 if ( count > 1 ) {
0300 DetElement par = detector.parent();
0301 printout(ERROR, m_name, "DetElement %s parent: %s is placed %ld times! Only single placement allowed.",
0302 de_path, par.isValid() ? par.path().c_str() : "", m_structure_elements[detector]);
0303 ++m_struct_counters.errors;
0304 }
0305 Alignment ideal = detector.nominal();
0306 if ( !ideal.isValid() ) {
0307 printout(ERROR, m_name, "Invalid DetElement [No ideal alignment]: %s", de_path);
0308 ++m_struct_counters.errors;
0309 }
0310 Alignment survey = detector.survey();
0311 if ( !survey.isValid() ) {
0312 printout(ERROR, m_name, "Invalid DetElement [No survey alignment]: %s", de_path);
0313 ++m_struct_counters.errors;
0314 }
0315 if ( ideal.isValid() ) {
0316 const TGeoHMatrix& matrix = ideal.worldTransformation();
0317 if ( matrix.IsIdentity() ) {
0318 }
0319 }
0320 printout(nerrs != m_struct_counters.errors ? ERROR : INFO, m_name,
0321 "DetElement %s [%s] parent: %s placement: %s [%s] volume: %s",
0322 path.c_str(), yes_no(det_valid), yes_no(parent_valid), yes_no(det_place_valid),
0323 yes_no(place_valid), yes_no(vol_valid));
0324 return nerrs == m_struct_counters.errors;
0325 }
0326
0327
0328 bool DetectorCheck::checkDetElementTree(const std::string& path, DetElement detector, PlacedVolume pv) {
0329 auto nerrs = m_struct_counters.errors;
0330 if ( !detector.isValid() ) {
0331 printout(ERROR, m_name, "Invalid DetElement seen: %s", path.c_str());
0332 ++m_struct_counters.errors;
0333 return false;
0334 }
0335 bool is_world = detector == detector.world();
0336
0337 checkDetElement(path, detector, pv);
0338
0339 for ( const auto& c : detector.children() ) {
0340 DetElement de = c.second;
0341 if ( is_world ) {
0342 m_current_sensitive = SensitiveDetector();
0343 m_current_iddesc = IDDescriptor();
0344 m_current_detector = de;
0345 }
0346 if ( de.parent().isValid() && de.parent() != detector ) {
0347 printout(ERROR, m_name, "Invalid DetElement [Parent mismatch]: %s", de.path().c_str());
0348 printout(ERROR, m_name, " apparent parent: %s structural parent: %s",
0349 de.parent().path().c_str(), detector.path().c_str());
0350 ++m_struct_counters.errors;
0351 }
0352
0353 checkDetElementTree(path + "/" + c.first, de, de.placement());
0354 }
0355 return nerrs == m_struct_counters.errors;
0356 }
0357
0358
0359 void DetectorCheck::checkSingleVolume(DetElement e, PlacedVolume pv) {
0360
0361 ++m_geo_counters.elements;
0362
0363 if ( !e.isValid() ) {
0364 printout(ERROR, m_name, "Invalid DetElement [Invalid handle]");
0365 ++m_geo_counters.errors;
0366 }
0367
0368 if ( !pv.isValid() ) {
0369 printout(ERROR, m_name, "Invalid PlacedVolume [Invalid handle] DetElement: %s", e.path().c_str());
0370 ++m_geo_counters.errors;
0371 }
0372 Volume vol = pv.volume();
0373
0374 if ( !vol.isValid() ) {
0375 printout(ERROR, m_name, "Invalid Volume [Invalid handle] DetElement: %s", e.path().c_str());
0376 ++m_geo_counters.errors;
0377 return;
0378 }
0379
0380 if ( check_sensitive && vol.isSensitive() ) {
0381 SensitiveDetector sdv = vol.sensitiveDetector();
0382 ++m_sens_counters.elements;
0383 if ( !sdv.isValid() ) {
0384 printout(ERROR, m_name, "Invalid SensitiveDetector DetElement: %s", e.path().c_str());
0385 ++m_sens_counters.errors;
0386 }
0387 SensitiveDetector sdd = get_current_sensitive_detector();
0388 if ( sdd != sdv ) {
0389 printout(ERROR, m_name, "Inconsistent sensitive detectors for DetElement: %s", e.path().c_str());
0390 ++m_sens_counters.errors;
0391 }
0392 }
0393 }
0394
0395
0396 void DetectorCheck::checkVolumeTree(DetElement detector, PlacedVolume pv) {
0397 const TGeoNode* current = pv.ptr();
0398 TObjArray* nodes = current->GetNodes();
0399 int num_children = nodes ? nodes->GetEntriesFast() : 0;
0400 bool is_world = detector == description.world();
0401
0402
0403 checkSingleVolume(detector, pv);
0404
0405 for(int i=0; i < num_children; ++i) {
0406 TGeoNode* node = (TGeoNode*)nodes->At(i);
0407 PlacedVolume place(node);
0408 DetElement de = detector;
0409
0410 if ( is_world ) {
0411 m_current_detector = de;
0412 get_current_sensitive_detector();
0413 }
0414
0415
0416 for ( const auto& c : detector.children() ) {
0417 if ( c.second.placement() == place ) {
0418 de = c.second;
0419 break;
0420 }
0421 }
0422 checkVolumeTree(de, place);
0423 if ( is_world ) {
0424 m_current_sensitive = SensitiveDetector();
0425 m_current_iddesc = IDDescriptor();
0426 }
0427 }
0428 }
0429
0430
0431 void DetectorCheck::checkManagerSingleVolume(DetElement detector, PlacedVolume pv, const VolIDs& child_ids, const Chain& chain) {
0432 std::stringstream err, log;
0433 VolumeID det_vol_id = detector.volumeID();
0434 VolumeID vid = det_vol_id;
0435 DetElement top_sdet, det_elem;
0436 VolumeManagerContext* mgr_ctxt = 0;
0437
0438 ++m_place_counters.elements;
0439
0440 try {
0441 vid = m_current_iddesc.encode(child_ids);
0442 top_sdet = m_volMgr.lookupDetector(vid);
0443 det_elem = m_volMgr.lookupDetElement(vid);
0444 mgr_ctxt = m_volMgr.lookupContext(vid);
0445
0446 if ( pv.volume().isSensitive() ) {
0447 PlacedVolume det_place = m_volMgr.lookupDetElementPlacement(vid);
0448 ++m_sens_counters.elements;
0449 if ( !ignore_detector && pv.ptr() != det_place.ptr() ) {
0450 err << "VolumeMgrTest: Wrong placement "
0451 << " got " << det_place.name() << " (" << (void*)det_place.ptr() << ")"
0452 << " instead of " << pv.name() << " (" << (void*)pv.ptr() << ") "
0453 << " vid:" << volumeID(vid);
0454 ++m_place_counters.errors;
0455 }
0456 else if ( top_sdet.ptr() != detector.ptr() ) {
0457 top_sdet = m_volMgr.lookupDetector(vid);
0458 err << "VolumeMgrTest: Wrong associated sub-detector element vid=" << volumeID(vid)
0459 << " got " << top_sdet.path() << " (" << (void*)top_sdet.ptr() << ") "
0460 << " instead of " << detector.path() << " (" << (void*)detector.ptr() << ")"
0461 << " vid:" << volumeID(vid);
0462 ++m_place_counters.errors;
0463 }
0464 else if ( !detail::tools::isParentElement(detector,det_elem) ) {
0465
0466 err << "VolumeMgrTest: Wrong associated detector element vid=" << volumeID(vid)
0467 << " got " << det_elem.path() << " (" << (void*)det_elem.ptr() << ") "
0468 << " instead of " << detector.path() << " (" << (void*)detector.ptr() << ")"
0469 << " vid:" << volumeID(vid);
0470 ++m_place_counters.errors;
0471 }
0472 else if ( top_sdet.ptr() != m_det.ptr() ) {
0473 err << "VolumeMgrTest: Wrong associated detector "
0474 << " vid:" << volumeID(vid);
0475 ++m_place_counters.errors;
0476 }
0477 }
0478 }
0479 catch(const std::exception& ex) {
0480 err << "Lookup " << pv.name() << " id:" << volumeID(vid)
0481 << " path:" << detector.path() << " error:" << ex.what();
0482 ++m_place_counters.errors;
0483 }
0484
0485 if ( pv.volume().isSensitive() || (0 != det_vol_id) ) {
0486 std::string id_desc;
0487 log << "Volume:" << std::setw(50) << std::left << pv.name();
0488 if ( pv.volume().isSensitive() ) {
0489 IDDescriptor dsc = SensitiveDetector(pv.volume().sensitiveDetector()).readout().idSpec();
0490 log << " IDDesc:" << (char*)(dsc.ptr() == m_current_iddesc.ptr() ? "OK " : "BAD");
0491 if ( dsc.ptr() != m_current_iddesc.ptr() ) ++m_place_counters.errors;
0492 }
0493 else {
0494 log << std::setw(11) << " ";
0495 }
0496 id_desc = m_current_iddesc.str(vid);
0497 log << " [" << char(pv.volume().isSensitive() ? 'S' : 'N') << "] " << std::right
0498 << " vid:" << volumeID(vid)
0499 << " " << id_desc;
0500 if ( !err.str().empty() ) {
0501 printout(ERROR, m_det.name(),err.str()+" "+log.str());
0502
0503 return;
0504 }
0505 id_desc = m_current_iddesc.str(det_elem.volumeID());
0506 printout(INFO, m_det.name(),log.str());
0507 printout(INFO, m_det.name(), " Elt:%-64s vid:%s %s Parent-OK:%3s",
0508 det_elem.path().c_str(),volumeID(det_elem.volumeID()).c_str(),
0509 id_desc.c_str(),
0510 yes_no(detail::tools::isParentElement(detector,det_elem)));
0511
0512 try {
0513 if ( pv.volume().isSensitive() ) {
0514 TGeoHMatrix trafo;
0515 for (size_t i = chain.size()-1; i > 0; --i) {
0516
0517 const TGeoMatrix* mat = chain[i]->GetMatrix();
0518 trafo.MultiplyLeft(mat);
0519 }
0520 for (size_t i = chain.size(); i > 0; --i) {
0521 const TGeoMatrix* mat = chain[i-1]->GetMatrix();
0522 if ( printLevel() <= INFO ) {
0523 ::printf("Placement [%d] VolID:%s\t\t",int(i),chain[i-1].volIDs().str().c_str());
0524 mat->Print();
0525 }
0526 }
0527 det_elem = m_volMgr.lookupDetElement(vid);
0528 if ( printLevel() <= INFO ) {
0529 ::printf("Computed Trafo (from placements):\t\t");
0530 trafo.Print();
0531 ::printf("DetElement Trafo: %s [%s]\t\t",
0532 det_elem.path().c_str(),volumeID(det_elem.volumeID()).c_str());
0533 det_elem.nominal().worldTransformation().Print();
0534 ::printf("VolumeMgr Trafo: %s [%s]\t\t",det_elem.path().c_str(),volumeID(vid).c_str());
0535 m_volMgr.worldTransformation(m_mapping,vid).Print();
0536 }
0537
0538
0539 if ( 0 == mgr_ctxt ) {
0540 printout(ERROR, m_det.name(), "VOLUME_MANAGER FAILED: Could not find entry for vid:%s.",
0541 volumeID(vid).c_str());
0542 ++m_place_counters.errors;
0543 }
0544
0545
0546 if ( &det_elem.nominal().worldTransformation() != &m_volMgr.worldTransformation(m_mapping,det_elem.volumeID()) )
0547 {
0548 printout(ERROR, m_det.name(), "DETELEMENT_PERSISTENCY FAILED: World transformation have DIFFERET pointer!");
0549 ++m_place_counters.errors;
0550 }
0551
0552 if ( !ignore_detector ) {
0553 if ( pv.ptr() == det_elem.placement().ptr() ) {
0554
0555
0556 int res1 = detail::matrix::_matrixEqual(trafo, det_elem.nominal().worldTransformation());
0557 int res2 = detail::matrix::_matrixEqual(trafo, m_volMgr.worldTransformation(m_mapping,vid));
0558 if ( res1 != detail::matrix::MATRICES_EQUAL || res2 != detail::matrix::MATRICES_EQUAL ) {
0559 printout(ERROR, m_det.name(), "DETELEMENT_PLACEMENT FAILED: World transformation DIFFER.");
0560 ++m_place_counters.errors;
0561 }
0562 else {
0563 printout(INFO, m_det.name(), "DETELEMENT_PLACEMENT: PASSED. All matrices equal: %s",
0564 volumeID(vid).c_str());
0565 }
0566 }
0567 else {
0568
0569
0570
0571 int res2 = detail::matrix::_matrixEqual(trafo, m_volMgr.worldTransformation(m_mapping,vid));
0572 if ( res2 != detail::matrix::MATRICES_EQUAL ) {
0573 printout(ERROR, m_det.name(), "VOLUME_PLACEMENT FAILED: World transformation DIFFER.");
0574 ++m_place_counters.errors;
0575 }
0576 else {
0577 printout(INFO, m_det.name(), "VOLUME_PLACEMENT: PASSED. All matrices equal: %s",
0578 volumeID(vid).c_str());
0579 }
0580 }
0581 }
0582 }
0583 }
0584 catch(const std::exception& ex) {
0585 err << "Matrix " << pv.name() << " id:" << volumeID(vid)
0586 << " path:" << detector.path() << " error:" << ex.what();
0587 ++m_place_counters.errors;
0588 }
0589
0590 }
0591 }
0592
0593
0594 void DetectorCheck::checkManagerVolumeTree(DetElement detector, PlacedVolume pv, VolIDs ids, const Chain& chain,
0595 size_t depth, size_t mx_depth)
0596 {
0597 if ( depth <= mx_depth ) {
0598 const TGeoNode* current = pv.ptr();
0599 TObjArray* nodes = current->GetNodes();
0600 int num_children = nodes ? nodes->GetEntriesFast() : 0;
0601 bool is_world = detector == description.world();
0602
0603 for(int i=0; i<num_children; ++i) {
0604 TGeoNode* node = (TGeoNode*)nodes->At(i);
0605 PlacedVolume place(node);
0606 VolIDs child_ids(ids);
0607 Chain child_chain(chain);
0608 DetElement de = detector;
0609 if ( is_world ) {
0610
0611 for ( const auto& c : detector.children() ) {
0612 if ( c.second.placement() == place ) {
0613 de = c.second;
0614 break;
0615 }
0616 }
0617 m_current_detector = de;
0618 get_current_sensitive_detector();
0619 }
0620 place.access();
0621 child_chain.emplace_back(place);
0622 child_ids.insert(child_ids.end(), place.volIDs().begin(), place.volIDs().end());
0623 checkManagerSingleVolume(de, place, child_ids, child_chain);
0624 checkManagerVolumeTree(de, place, std::move(child_ids), child_chain, depth+1, mx_depth);
0625 }
0626 }
0627 }
0628
0629 void DetectorCheck::help(int argc,char** argv) {
0630 std::cout
0631 <<
0632 "DD4hep_DetectorCheck -option [-option] \n"
0633 " -help Print this help message \n"
0634 " -name <subdetector name> Name of the subdetector to be checked \n"
0635 " \"ALL\" or \"all\": loop over known subdetectors\n"
0636 " \"world\" start from the mother of all... \n"
0637 " -structure Check structural tree consistency \n"
0638 " -geometry Check geometry tree consistency \n"
0639 " -sensitve Check consistency between detector and volume \n"
0640 " settings of sensitive detectors. \n"
0641 " -volmgr Check volume manager entries against volIDs of \n"
0642 " sensitive volume placements. \n\n"
0643 " NOTE: Option requires proper PhysVolID setup \n"
0644 " of the sensitive volume placements ! \n"
0645 " -ignore_detector Ignore DetElement placement check for -volmgr \n"
0646 << std::endl;
0647 std::cout << "Arguments: " << std::endl;
0648 for(int iarg=0; iarg<argc;++iarg) {
0649 std::cout << "Argument[" << iarg << "] = " << argv[iarg] << std::endl;
0650 }
0651 ::exit(EINVAL);
0652 }
0653
0654
0655 long DetectorCheck::run(Detector& description,int argc,char** argv) {
0656 std::string name;
0657 bool volmgr = false;
0658 bool geometry = false;
0659 bool structure = false;
0660 bool sensitive = false;
0661 bool placements = false;
0662 bool ignore_de = false;
0663 printout(ALWAYS, "DetectorCheck", "++ Processing plugin...");
0664 for(int iarg=0; iarg<argc;++iarg) {
0665 if ( argv[iarg] == 0 ) break;
0666 if ( ::strncasecmp(argv[iarg], "-name",4) == 0 && (iarg+1) < argc )
0667 name = argv[++iarg];
0668 else if ( ::strncasecmp(argv[iarg], "-structure",4) == 0 )
0669 structure = true;
0670 else if ( ::strncasecmp(argv[iarg], "-placements",4) == 0 )
0671 placements = true;
0672 else if ( ::strncasecmp(argv[iarg], "-volmgr",4) == 0 )
0673 volmgr = true;
0674 else if ( ::strncasecmp(argv[iarg], "-geometry",4) == 0 )
0675 geometry = true;
0676 else if ( ::strncasecmp(argv[iarg], "-sensitive",4) == 0 )
0677 sensitive = true;
0678 else if ( ::strncasecmp(argv[iarg], "-ignore_detelement",4) == 0 )
0679 ignore_de = true;
0680 else if ( ::strncasecmp(argv[iarg], "-help",4) == 0 )
0681 help(argc, argv);
0682 else
0683 help(argc, argv);
0684 }
0685 if ( argc == 0 ) help(argc, argv);
0686 if ( !name.empty() ) {
0687 DetectorCheck test(description);
0688 if ( name == "all" || name == "All" || name == "ALL" ) {
0689 for (const auto& det : description.detectors() ) {
0690 printout(INFO, "DetectorCheck", "++ Processing subdetector: %s", det.second.name());
0691 test.check_structure = structure;
0692 test.check_placements = placements;
0693 test.check_volmgr = volmgr;
0694 test.check_geometry = geometry;
0695 test.check_sensitive = sensitive;
0696 test.ignore_detector = ignore_de;
0697 test.execute(det.second, 9999);
0698 }
0699 return 1;
0700 }
0701 DetElement det = (::strcasecmp(name.c_str(), "world") == 0)
0702 ? description.world() : description.detector(name);
0703 printout(INFO, "DetectorCheck", "++ Processing subdetector: %s",name.c_str());
0704 test.check_structure = structure;
0705 test.check_placements = placements;
0706 test.check_volmgr = volmgr;
0707 test.check_geometry = geometry;
0708 test.check_sensitive = sensitive;
0709 test.ignore_detector = ignore_de;
0710 test.execute(det, 9999);
0711 }
0712 return 1;
0713 }
0714
0715 DECLARE_APPLY(DD4hep_DetectorCheck,DetectorCheck::run)
0716
0717
0718 long run_VolumeMgrTest(Detector& description,int argc, const char*const* argv) {
0719 const char* args[] = {"-name", argc > 0 ? argv[0] : "world", "-structure", "-geometry", "-volmgr", 0 };
0720 return DetectorCheck::run(description, 6, (char**)args);
0721 }
0722 DECLARE_APPLY(DD4hep_VolumeMgrTest,run_VolumeMgrTest)