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