Check tracking geometry volumes.
608 {
609
610
611
612 std::vector<const Acts::TrackingVolume*> volumeVec{};
613 std::vector<const Acts::Surface*> passiveSurfaces{};
614
615 std::unordered_set<const Acts::TrackingVolume*> overlapVolumes{};
616 std::unordered_set<const Acts::Surface*> overlapSurfaces{};
617
618
619
620 trackingGeometry.visitVolumes([&](const Acts::TrackingVolume* vol) {
621
622 if(vol->volumeBounds().type() == Acts::VolumeBounds::BoundsType::eCylinder){
623 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Fetch "<<vol->surfaces().size()
624 <<" passive surfaces from "<<vol->volumeName()<<".");
625 std::ranges::for_each(vol->surfaces(), [&](const Acts::Surface& surf){
626 ATH_MSG_VERBOSE(" --- "<<surf.type()<<" @"<<Amg::toString(surf.center(gctx.context()))
627 <<" "<<surf.bounds());
628 passiveSurfaces.push_back(&surf);
629 });
630 return;
631 }
632 const auto* placement = dynamic_cast<const ActsTrk::VolumePlacement*>(vol->volumePlacement());
633
635 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Skip volume "
636 <<vol->volumeName()<<".");
637 return;
638 }
639 volumeVec.push_back(vol);
640 });
641
643 << passiveSurfaces.size()<< " passive surfaces");
644 {
645 Acts::ObjVisualization3D visualHelper{};
646 std::ranges::for_each(passiveSurfaces,
647 [&visualHelper, &gctx](const Acts::Surface* surface) {
648 Acts::GeometryView3D::drawSurface(visualHelper, *surface, gctx.
context());
649 });
650 visualHelper.write("MsTrackTest_passiveSurfaces.obj");
651
652 }
654 for(std::size_t vIdx = 0; vIdx < volumeVec.size(); ++vIdx) {
655 const Acts::TrackingVolume* testVol{volumeVec.at(vIdx)};
657
658 std::vector<const Acts::TrackingVolume*> overlaps{};
659 const std::vector<Amg::Vector3D> edges =
cornerPoints(gctx, *testVol);
660
661 for(const auto& surface : testVol->surfaces()) {
662
663 std::vector<Amg::Vector3D> surfEdges = {};
664 if(surface.type() == Acts::Surface::SurfaceType::Straw){
666 <<" / "<<surface.geometryId() <<" in volume "<<testVol->volumeName());
667
668 auto edges =
cornerPoints(gctx,
dynamic_cast<const Acts::StrawSurface&
>(surface));
669 surfEdges.insert(surfEdges.end() , edges.begin(), edges.end());
670 } else if(surface.type() == Acts::Surface::SurfaceType::Plane){
672 <<" / "<<surface.geometryId() <<" in volume "<<testVol->volumeName());
673
674 auto edges =
cornerPoints(gctx,
dynamic_cast<const Acts::PlaneSurface&
>(surface));
675 surfEdges.insert(surfEdges.end() , edges.begin(), edges.end());
676 } else {
677 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The "<<surface.type()<<
"-surface "
679 <<surface.geometryId() <<" is neither a straw nor a plane surface");
680 return StatusCode::FAILURE;
681 }
682
683 for(const auto& edge : surfEdges) {
684 if(!testVol->inside(gctx.
context(), edge, 0.01)) {
685 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The "<<surface.type()<<
"-surface "
687 <<surface.geometryId() <<" @vertex point "
690 <<" is outside the parent volume: " << testVol->volumeName()
692 <<", "<<testVol->volumeBounds());
693 overlapSurfaces.insert(&surface);
694 overlapVolumes.insert(testVol);
696 retCode = StatusCode::FAILURE;
697 }
698 }
699 }
700 }
701
702
703 for (const Acts::TrackingVolume& child : testVol->volumes()) {
705 if(!testVol->inside(gctx.
context(), edge, 0.01)){
706 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The children volume's "
707 << child.volumeName() <<
" vertex point " <<
Amg::toString(edge)
708 <<" is outside the parent volume" << testVol->volumeName());
709 return StatusCode::FAILURE;
710 }
711 }
712 }
714 if (!testVol->motherVolume()->isAlignable() &&
m_dumpObjs) {
715 std::vector<const Acts::Surface*> surfaces = extractSurfaces(*testVol);
716 const Identifier volId =
identify(*surfaces.front());
718 saveEnvelope(gctx, std::format(
"TrackingVolume_{:}{:}{:}{:}_{:}",
720 std::abs(
eta),
eta > 0 ?
'A' :
'C',
722 *testVol, surfaces , chamberVolumes(*testVol));
723
724 }
725
726 for (std::size_t vIdx1 = 0 ; vIdx1 < vIdx; ++vIdx1) {
727 const Acts::TrackingVolume* overlapTest{volumeVec.at(vIdx1)};
728 if (overlapTest->motherVolume() == testVol ||
729 testVol->motherVolume() == overlapTest){
730 continue;
731 }
733 overlaps.push_back(overlapTest);
734 std::ranges::copy(extractSurfaces(*testVol),
735 std::inserter(overlapSurfaces, overlapSurfaces.begin()));
736 std::ranges::copy(extractSurfaces(*overlapTest),
737 std::inserter(overlapSurfaces, overlapSurfaces.begin()));
738 }
739 }
740
741
742 const Identifier volId =
identify(*extractSurfaces(*testVol).front());
743 double volHalfR{0.}, volHalfZ{0.};
749 } else {
752 }
754 const double rMin = center.perp() - volHalfR;
755
756
757 const double rMax = (testVol->localToGlobalTransform(gctx.
context()) *(
758 halfX * Amg::Vector3D::UnitX() +
759 volHalfR * Amg::Vector3D::Unit(1 +
isBarrel))).perp();
760
761 double zMin = center.z() - volHalfZ;
762 double zMax = center.z() + volHalfZ;
764 if (testVol->volumeBounds().type() == Acts::VolumeBounds::eDiamond) {
765 zMin = 1._km; zMax = -1._km;
767 zMin = std::min(zMin,
p.z());
768 zMax = std::max(zMax,
p.z());
769 }
770 }
771
772 for(std::size_t i = 0;
i < passiveSurfaces.size(); ++
i) {
773
774 const Acts::Surface* surf = passiveSurfaces[
i];
775
777 if(surf->type() == Acts::Surface::SurfaceType::Cylinder) {
778 using BoundEnum = Acts::CylinderBounds::BoundValues;
779 const auto& bounds = static_cast<const Acts::CylinderBounds&>(surf->bounds());
780 const double passiveR = bounds.get(BoundEnum::eR);
781 const double passiveZ = bounds.get(BoundEnum:: eHalfLengthZ);
782 if (rMin < passiveR || rMax > passiveR){
783 continue;
784 }
785 if (passiveZ < zMin || -passiveZ > zMax) {
786 continue;
787 }
788 } else if(surf->type() == Acts::Surface::SurfaceType::Disc){
789 using BoundEnum = Acts::RadialBounds::BoundValues;
790 const auto& bounds = static_cast<const Acts::RadialBounds&>(surf->bounds());
791 if (center.z() < zMin || center.z() > zMax) {
792 continue;
793 }
794 const double surfRMax = bounds.get(BoundEnum::eMaxR);
795 const double surfRMin = bounds.get(BoundEnum::eMinR);
796 if (surfRMax < rMin || surfRMin > rMax){
797 continue;
798 }
799
800 } else {
801 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
802 <<", "<< surf->name() <<" is not a cylinder surface or disc");
803 return StatusCode::FAILURE;
804 }
805
807 << testVol->volumeName() << " overlaps with the surface "
808 << surf->name() << " with geo id" << surf->geometryId()
809 <<" -- volume radius: ["<<rMin<<";"<<rMax<<"] z: ["<<zMin<<";"<<zMax<<"]"
810 <<" "<<surf->bounds());
812 retCode = StatusCode::FAILURE;
813 }
814 overlapSurfaces.insert(surf);
815 overlapVolumes.insert(testVol);
816
817
818 }
819
820 if(overlaps.empty()) {
821 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - No overlaps detected for the volume "<<testVol->volumeName());
822 continue;
823 }
824
825 overlapVolumes.insert(overlaps.begin(), overlaps.end());
826 overlapVolumes.insert(testVol);
827
828 std::stringstream overlapStream{};
829 overlapStream<<__func__<<"() "<<__LINE__<<" - The volume "
830 <<testVol->volumeName() << " overlaps with: "<<std::endl;
831
832 for(const Acts::TrackingVolume* overlap: overlaps){
833 overlapStream<<" --- Volume: " << overlap->volumeName()<<", "<<overlap->volumeBounds()
835 }
837 }
838
839
840 for(std::size_t i = 0;
i < passiveSurfaces.size(); ++
i) {
841 const Acts::Surface* surf = passiveSurfaces[
i];
843 for(std::size_t j = i+1;
j < passiveSurfaces.size(); ++
j) {
844 const Acts::Surface* testSurf = passiveSurfaces[
j];
845 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Checking passive surface "<<surf->name()<<
" geo id "<<surf->geometryId()
846 <<" with passive surface "<<testSurf->name()<<" geo id "<<testSurf->geometryId());
847 if(testSurf->geometryId().volume() != surf->geometryId().volume()){
848 continue;
849 }
850 if(surf->type() == Acts::Surface::SurfaceType::Cylinder){
851 using BoundEnum = Acts::CylinderBounds::BoundValues;
852 const auto& bounds = static_cast<const Acts::CylinderBounds&>(surf->bounds());
853 double passiveR = bounds.get(BoundEnum::eR);
854 double passiveZ = bounds.get(BoundEnum:: eHalfLengthZ);
855 bool overlap = checkOverlapWithCylinder(gctx.
context(), testSurf, center, passiveR, passiveZ);
856 if(overlap) {
857 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<<surf->name()<<
"geo id "<<surf->geometryId()
858 <<" overlaps with surface "<<testSurf->name()<<"geo id "<<testSurf->geometryId()
859 <<" in the same volume "<<surf->geometryId().volume());
860 overlapSurfaces.insert(surf);
861 overlapSurfaces.insert(testSurf);
863 retCode = StatusCode::FAILURE;
864 }
865 }
866 }else if(surf->type() == Acts::Surface::SurfaceType::Disc){
867 using BoundEnum = Acts::RadialBounds::BoundValues;
868 const auto& bounds = static_cast<const Acts::RadialBounds&>(surf->bounds());
869 bool overlap = checkOverlapWithDisc(gctx.
context(), testSurf, center, bounds.get(BoundEnum::eMaxR));
870 if(overlap) {
871 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<<surf->name()<<
"geo id "<<surf->geometryId()
872 <<" overlaps with surface "<<testSurf->name()<<"geo id "<<testSurf->geometryId()
873 <<" in the same volume "<<surf->geometryId().volume());
874 overlapSurfaces.insert(surf);
875 overlapSurfaces.insert(testSurf);
877 retCode = StatusCode::FAILURE;
878 }
879 }
880 } else {
881 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
882 <<", "<< surf->name() <<" is not a cylinder surface or disc");
883 return StatusCode::FAILURE;
884 }
885 }
886 }
887
888 if (overlapVolumes.size() || overlapSurfaces.size()) {
889 const Acts::Volume* refVolume = (*overlapVolumes.begin());
890 std::vector<const Acts::Volume*> childVols{};
891 childVols.insert(childVols.begin(),std::next(overlapVolumes.begin()), overlapVolumes.end());
892 std::vector<const Acts::Surface*> childSurfs{overlapSurfaces.begin(), overlapSurfaces.end()};
893 saveEnvelope(gctx,
"TrackingGeometryOverlaps", *refVolume,
894 childSurfs, childVols);
895 }
896
897
898 if(overlapVolumes.empty()) {
899 ATH_MSG_ALWAYS(
"No overlaps detected in the tracking geometry!!");
901 retCode = StatusCode::FAILURE;
902 }
903 return retCode;
904 }
Scalar eta() const
pseudorapidity method
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_ALWAYS(x)
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.