Check tracking geometry volumes.
492 {
493
494
495
496 std::vector<const Acts::TrackingVolume*> volumeVec{};
497 std::vector<const Acts::Surface*> passiveSurfaces{};
498
499 std::unordered_set<const Acts::TrackingVolume*> overlapVolumes{};
500 std::unordered_set<const Acts::Surface*> overlapSurfaces{};
501
502
503 trackingGeometry.visitVolumes([&](const Acts::TrackingVolume* vol) {
504
505 if(vol->volumeBounds().type() == Acts::VolumeBounds::BoundsType::eCylinder){
506 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Fetch "<<vol->surfaces().size()
507 <<" passive surfaces from "<<vol->volumeName()<<".");
508 std::ranges::for_each(vol->surfaces(), [&](const Acts::Surface& surf){
509 ATH_MSG_VERBOSE(" --- "<<surf.type()<<" @"<<Amg::toString(surf.center(gctx.context()))
510 <<" "<<surf.bounds());
511 passiveSurfaces.push_back(&surf);
512 });
513 return;
514 }
515 const auto* placement = dynamic_cast<const ActsTrk::VolumePlacement*>(vol->volumePlacement());
516
518 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Skip volume "
519 <<vol->volumeName()<<".");
520 return;
521 }
522 volumeVec.push_back(vol);
523 });
524
526 << passiveSurfaces.size()<< " passive surfaces");
527 {
528 Acts::ObjVisualization3D visualHelper{};
529 std::ranges::for_each(passiveSurfaces,
530 [&visualHelper, &gctx](const Acts::Surface* surface) {
531 Acts::GeometryView3D::drawSurface(visualHelper, *surface, gctx.
context());
532 });
533 visualHelper.write("MsTrackTest_passiveSurfaces.obj");
534
535 }
537 for(std::size_t vIdx = 0; vIdx < volumeVec.size(); ++vIdx) {
538 const Acts::TrackingVolume* testVol{volumeVec.at(vIdx)};
540
541 std::vector<const Acts::TrackingVolume*> overlaps{};
542 const std::vector<Amg::Vector3D> edges =
cornerPoints(gctx, *testVol);
543
544 for(const auto& surface : testVol->surfaces()) {
546 <<" / "<<surface.geometryId() <<" in volume "<<testVol->volumeName());
548 if(!testVol->inside(gctx.
context(), edge, 0.01)) {
549 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The "<<surface.type()<<
"-surface "
551 <<surface.geometryId() <<" @vertex point "
554 <<" is outside the parent volume: " << testVol->volumeName()
556 <<", "<<testVol->volumeBounds());
557 overlapSurfaces.insert(&surface);
558 overlapVolumes.insert(testVol);
560 retCode = StatusCode::FAILURE;
561 }
562 }
563 }
564 }
565
566
567 for (const Acts::TrackingVolume& child : testVol->volumes()) {
569 if(!testVol->inside(gctx.
context(), edge, 0.01)){
570 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The children volume's "
571 << child.volumeName() <<
" vertex point " <<
Amg::toString(edge)
572 <<" is outside the parent volume" << testVol->volumeName());
573 return StatusCode::FAILURE;
574 }
575 }
576 }
578 if (!testVol->motherVolume()->isAlignable() &&
m_dumpObjs) {
579 std::vector<const Acts::Surface*> surfaces = extractSurfaces(*testVol);
580 const Identifier volId =
identify(*surfaces.front());
582 saveEnvelope(gctx, std::format(
"TrackingVolume_{:}{:}{:}{:}_{:}",
584 std::abs(
eta),
eta > 0 ?
'A' :
'C',
586 *testVol, surfaces , chamberVolumes(*testVol));
587
588 }
589
590 for (std::size_t vIdx1 = 0 ; vIdx1 < vIdx; ++vIdx1) {
591 const Acts::TrackingVolume* overlapTest{volumeVec.at(vIdx1)};
592 if (overlapTest->motherVolume() == testVol ||
593 testVol->motherVolume() == overlapTest){
594 continue;
595 }
597 overlaps.push_back(overlapTest);
598 std::ranges::copy(extractSurfaces(*testVol),
599 std::inserter(overlapSurfaces, overlapSurfaces.begin()));
600 std::ranges::copy(extractSurfaces(*overlapTest),
601 std::inserter(overlapSurfaces, overlapSurfaces.begin()));
602 }
603 }
604
605
606 const Identifier volId =
identify(*extractSurfaces(*testVol).front());
607 double volHalfR{0.}, volHalfZ{0.};
613 } else {
616 }
618 const double rMin = center.perp() - volHalfR;
619
620
621 const double rMax = (testVol->localToGlobalTransform(gctx.
context()) *(
622 halfX * Amg::Vector3D::UnitX() +
623 volHalfR * Amg::Vector3D::Unit(1 +
isBarrel))).perp();
624
625 double zMin = center.z() - volHalfZ;
626 double zMax = center.z() + volHalfZ;
628 if (testVol->volumeBounds().type() == Acts::VolumeBounds::eDiamond) {
629 zMin = 1._km; zMax = -1._km;
631 zMin = std::min(zMin,
p.z());
632 zMax = std::max(zMax,
p.z());
633 }
634 }
635
636 for(std::size_t i = 0;
i < passiveSurfaces.size(); ++
i) {
637
638 const Acts::Surface* surf = passiveSurfaces[
i];
639
641 if(surf->type() == Acts::Surface::SurfaceType::Cylinder) {
642 using BoundEnum = Acts::CylinderBounds::BoundValues;
643 const auto& bounds = static_cast<const Acts::CylinderBounds&>(surf->bounds());
644 const double passiveR = bounds.get(BoundEnum::eR);
645 const double passiveZ = bounds.get(BoundEnum:: eHalfLengthZ);
646 if (rMin < passiveR || rMax > passiveR){
647 continue;
648 }
649 if (passiveZ < zMin || -passiveZ > zMax) {
650 continue;
651 }
652 } else if(surf->type() == Acts::Surface::SurfaceType::Disc){
653 using BoundEnum = Acts::RadialBounds::BoundValues;
654 const auto& bounds = static_cast<const Acts::RadialBounds&>(surf->bounds());
655 if (center.z() < zMin || center.z() > zMax) {
656 continue;
657 }
658 const double surfRMax = bounds.get(BoundEnum::eMaxR);
659 const double surfRMin = bounds.get(BoundEnum::eMinR);
660 if (surfRMax < rMin || surfRMin > rMax){
661 continue;
662 }
663
664 } else {
665 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
666 <<", "<< surf->name() <<" is not a cylinder surface or disc");
667 return StatusCode::FAILURE;
668 }
669
671 << testVol->volumeName() << " overlaps with the surface "
672 << surf->name() << " with geo id" << surf->geometryId()
673 <<" -- volume radius: ["<<rMin<<";"<<rMax<<"] z: ["<<zMin<<";"<<zMax<<"]"
674 <<" "<<surf->bounds());
676 retCode = StatusCode::FAILURE;
677 }
678 overlapSurfaces.insert(surf);
679 overlapVolumes.insert(testVol);
680
681
682 }
683
684 if(overlaps.empty()) {
685 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - No overlaps detected for the volume "<<testVol->volumeName());
686 continue;
687 }
688
689 overlapVolumes.insert(overlaps.begin(), overlaps.end());
690 overlapVolumes.insert(testVol);
691
692 std::stringstream overlapStream{};
693 overlapStream<<__func__<<"() "<<__LINE__<<" - The volume "
694 <<testVol->volumeName() << " overlaps with: "<<std::endl;
695
696 for(const Acts::TrackingVolume* overlap: overlaps){
697 overlapStream<<" --- Volume: " << overlap->volumeName()<<", "<<overlap->volumeBounds()
699 }
701 }
702
703
704 for(std::size_t i = 0;
i < passiveSurfaces.size(); ++
i) {
705 const Acts::Surface* surf = passiveSurfaces[
i];
707 for(std::size_t j = i+1;
j < passiveSurfaces.size(); ++
j) {
708 const Acts::Surface* testSurf = passiveSurfaces[
j];
709 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Checking passive surface "<<surf->name()<<
" geo id "<<surf->geometryId()
710 <<" with passive surface "<<testSurf->name()<<" geo id "<<testSurf->geometryId());
711 if(testSurf->geometryId().volume() != surf->geometryId().volume()){
712 continue;
713 }
714 if(surf->type() == Acts::Surface::SurfaceType::Cylinder){
715 using BoundEnum = Acts::CylinderBounds::BoundValues;
716 const auto& bounds = static_cast<const Acts::CylinderBounds&>(surf->bounds());
717 double passiveR = bounds.get(BoundEnum::eR);
718 double passiveZ = bounds.get(BoundEnum:: eHalfLengthZ);
719 bool overlap = checkOverlapWithCylinder(gctx.
context(), testSurf, center, passiveR, passiveZ);
720 if(overlap) {
721 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<<surf->name()<<
"geo id "<<surf->geometryId()
722 <<" overlaps with surface "<<testSurf->name()<<"geo id "<<testSurf->geometryId()
723 <<" in the same volume "<<surf->geometryId().volume());
724 overlapSurfaces.insert(surf);
725 overlapSurfaces.insert(testSurf);
727 retCode = StatusCode::FAILURE;
728 }
729 }
730 }else if(surf->type() == Acts::Surface::SurfaceType::Disc){
731 using BoundEnum = Acts::RadialBounds::BoundValues;
732 const auto& bounds = static_cast<const Acts::RadialBounds&>(surf->bounds());
733 bool overlap = checkOverlapWithDisc(gctx.
context(), testSurf, center, bounds.get(BoundEnum::eMaxR));
734 if(overlap) {
735 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<<surf->name()<<
"geo id "<<surf->geometryId()
736 <<" overlaps with surface "<<testSurf->name()<<"geo id "<<testSurf->geometryId()
737 <<" in the same volume "<<surf->geometryId().volume());
738 overlapSurfaces.insert(surf);
739 overlapSurfaces.insert(testSurf);
741 retCode = StatusCode::FAILURE;
742 }
743 }
744 } else {
745 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
746 <<", "<< surf->name() <<" is not a cylinder surface or disc");
747 return StatusCode::FAILURE;
748 }
749 }
750 }
751
752 if (overlapVolumes.size() || overlapSurfaces.size()) {
753 const Acts::Volume* refVolume = (*overlapVolumes.begin());
754 std::vector<const Acts::Volume*> childVols{};
755 childVols.insert(childVols.begin(),std::next(overlapVolumes.begin()), overlapVolumes.end());
756 std::vector<const Acts::Surface*> childSurfs{overlapSurfaces.begin(), overlapSurfaces.end()};
757 saveEnvelope(gctx,
"TrackingGeometryOverlaps", *refVolume,
758 childSurfs, childVols);
759 }
760
761
762 if(overlapVolumes.empty()) {
763 ATH_MSG_ALWAYS(
"No overlaps detected in the tracking geometry!!");
765 retCode = StatusCode::FAILURE;
766 }
767 return retCode;
768 }
Scalar eta() const
pseudorapidity method
#define ATH_MSG_ALWAYS(x,...)
#define ATH_MSG_VERBOSE(x,...)
Eigen::Matrix< double, 3, 1 > Vector3D
double halfY(const Acts::VolumeBounds &bounds)
Returns the half-Y length for the parsed volume bounds (Trapezoid/ Cuboid).
bool isMuon(const ActsTrk::DetectorType type)
Returns whether the parsed type is muon.
double halfZ(const Acts::VolumeBounds &bounds)
Returns the half-Z length for the parsed volume bounds (Trapezoid/ Cuboid).
double halfXhighY(const Acts::VolumeBounds &bounds)
Returns the half-Y length @ posiive Y for the parsed volume bounds (Trapezoid/ Cuboid).
bool isBarrel(const ChIndex index)
Returns true if the chamber index points to a barrel chamber.
float j(const xAOD::IParticle &, const xAOD::TrackMeasurementValidation &hit, const Eigen::Matrix3d &jab_inv)
const Identifier & identify(const UncalibratedMeasurement *meas)
Returns the associated identifier from the muon measurement.