Check tracking geometry volumes.
515 {
516
517
518
519 std::vector<const Acts::TrackingVolume*> volumeVec{};
520 std::vector<const Acts::Surface*> passiveSurfaces{};
521
522 std::unordered_set<const Acts::TrackingVolume*> overlapVolumes{};
523 std::unordered_set<const Acts::Surface*> overlapSurfaces{};
524
525
526
527 trackingGeometry.visitVolumes([&](const Acts::TrackingVolume* vol) {
528
529 if(vol->volumeBounds().type() == Acts::VolumeBounds::BoundsType::eCylinder){
530 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Fetch "<<vol->surfaces().size()
531 <<" passive surfaces from "<<vol->volumeName()<<".");
532 std::ranges::for_each(vol->surfaces(), [&](const Acts::Surface& surf){
533 ATH_MSG_VERBOSE(" --- "<<surf.type()<<" @"<<Amg::toString(surf.center(gctx.context()))
534 <<" "<<surf.bounds());
535 passiveSurfaces.push_back(&surf);
536 });
537 return;
538 }
539 const auto* placement = dynamic_cast<const ActsTrk::VolumePlacement*>(vol->volumePlacement());
540
542 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Skip volume "
543 <<vol->volumeName()<<".");
544 return;
545 }
546 volumeVec.push_back(vol);
547 });
548
550 << passiveSurfaces.size()<< " passive surfaces");
551 {
552 Acts::ObjVisualization3D visualHelper{};
553 std::ranges::for_each(passiveSurfaces,
554 [&visualHelper, &gctx](const Acts::Surface* surface) {
555 Acts::GeometryView3D::drawSurface(visualHelper, *surface, gctx.
context());
556 });
557 visualHelper.write("MsTrackTest_passiveSurfaces.obj");
558
559 }
561 for(std::size_t vIdx = 0; vIdx < volumeVec.size(); ++vIdx) {
562 const Acts::TrackingVolume* testVol{volumeVec.at(vIdx)};
564
565 std::vector<const Acts::TrackingVolume*> overlaps{};
566 const std::vector<Amg::Vector3D> edges =
cornerPoints(gctx, *testVol);
567
568 for(const auto& surface : testVol->surfaces()) {
569
571 <<" / "<<surface.geometryId() <<" in volume "<<testVol->volumeName());
573 if(!testVol->inside(gctx.
context(), edge, 0.01)) {
574 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The "<<surface.type()<<
"-surface "
576 <<surface.geometryId() <<" @vertex point "
579 <<" is outside the parent volume: " << testVol->volumeName()
581 <<", "<<testVol->volumeBounds());
582 overlapSurfaces.insert(&surface);
583 overlapVolumes.insert(testVol);
585 retCode = StatusCode::FAILURE;
586 }
587 }
588 }
589 }
590
591
592 for (const Acts::TrackingVolume& child : testVol->volumes()) {
594 if(!testVol->inside(gctx.
context(), edge, 0.01)){
595 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The children volume's "
596 << child.volumeName() <<
" vertex point " <<
Amg::toString(edge)
597 <<" is outside the parent volume" << testVol->volumeName());
598 return StatusCode::FAILURE;
599 }
600 }
601 }
603 if (!testVol->motherVolume()->isAlignable() &&
m_dumpObjs) {
604 std::vector<const Acts::Surface*> surfaces = extractSurfaces(*testVol);
605 const Identifier volId =
identify(*surfaces.front());
607 saveEnvelope(gctx, std::format(
"TrackingVolume_{:}{:}{:}{:}_{:}",
609 std::abs(
eta),
eta > 0 ?
'A' :
'C',
611 *testVol, surfaces , chamberVolumes(*testVol));
612
613 }
614
615 for (std::size_t vIdx1 = 0 ; vIdx1 < vIdx; ++vIdx1) {
616 const Acts::TrackingVolume* overlapTest{volumeVec.at(vIdx1)};
617 if (overlapTest->motherVolume() == testVol ||
618 testVol->motherVolume() == overlapTest){
619 continue;
620 }
622 overlaps.push_back(overlapTest);
623 std::ranges::copy(extractSurfaces(*testVol),
624 std::inserter(overlapSurfaces, overlapSurfaces.begin()));
625 std::ranges::copy(extractSurfaces(*overlapTest),
626 std::inserter(overlapSurfaces, overlapSurfaces.begin()));
627 }
628 }
629
630
631 const Identifier volId =
identify(*extractSurfaces(*testVol).front());
632 double volHalfR{0.}, volHalfZ{0.};
638 } else {
641 }
643 const double rMin = center.perp() - volHalfR;
644
645
646 const double rMax = (testVol->localToGlobalTransform(gctx.
context()) *(
647 halfX * Amg::Vector3D::UnitX() +
648 volHalfR * Amg::Vector3D::Unit(1 +
isBarrel))).perp();
649
650 double zMin = center.z() - volHalfZ;
651 double zMax = center.z() + volHalfZ;
653 if (testVol->volumeBounds().type() == Acts::VolumeBounds::eDiamond) {
654 zMin = 1._km; zMax = -1._km;
656 zMin = std::min(zMin,
p.z());
657 zMax = std::max(zMax,
p.z());
658 }
659 }
660
661 for(std::size_t i = 0;
i < passiveSurfaces.size(); ++
i) {
662
663 const Acts::Surface* surf = passiveSurfaces[
i];
664
666 if(surf->type() == Acts::Surface::SurfaceType::Cylinder) {
667 using BoundEnum = Acts::CylinderBounds::BoundValues;
668 const auto& bounds = static_cast<const Acts::CylinderBounds&>(surf->bounds());
669 const double passiveR = bounds.get(BoundEnum::eR);
670 const double passiveZ = bounds.get(BoundEnum:: eHalfLengthZ);
671 if (rMin < passiveR || rMax > passiveR){
672 continue;
673 }
674 if (passiveZ < zMin || -passiveZ > zMax) {
675 continue;
676 }
677 } else if(surf->type() == Acts::Surface::SurfaceType::Disc){
678 using BoundEnum = Acts::RadialBounds::BoundValues;
679 const auto& bounds = static_cast<const Acts::RadialBounds&>(surf->bounds());
680 if (center.z() < zMin || center.z() > zMax) {
681 continue;
682 }
683 const double surfRMax = bounds.get(BoundEnum::eMaxR);
684 const double surfRMin = bounds.get(BoundEnum::eMinR);
685 if (surfRMax < rMin || surfRMin > rMax){
686 continue;
687 }
688
689 } else {
690 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
691 <<", "<< surf->name() <<" is not a cylinder surface or disc");
692 return StatusCode::FAILURE;
693 }
694
696 << testVol->volumeName() << " overlaps with the surface "
697 << surf->name() << " with geo id" << surf->geometryId()
698 <<" -- volume radius: ["<<rMin<<";"<<rMax<<"] z: ["<<zMin<<";"<<zMax<<"]"
699 <<" "<<surf->bounds());
701 retCode = StatusCode::FAILURE;
702 }
703 overlapSurfaces.insert(surf);
704 overlapVolumes.insert(testVol);
705
706
707 }
708
709 if(overlaps.empty()) {
710 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - No overlaps detected for the volume "<<testVol->volumeName());
711 continue;
712 }
713
714 overlapVolumes.insert(overlaps.begin(), overlaps.end());
715 overlapVolumes.insert(testVol);
716
717 std::stringstream overlapStream{};
718 overlapStream<<__func__<<"() "<<__LINE__<<" - The volume "
719 <<testVol->volumeName() << " overlaps with: "<<std::endl;
720
721 for(const Acts::TrackingVolume* overlap: overlaps){
722 overlapStream<<" --- Volume: " << overlap->volumeName()<<", "<<overlap->volumeBounds()
724 }
726 }
727
728
729 for(std::size_t i = 0;
i < passiveSurfaces.size(); ++
i) {
730 const Acts::Surface* surf = passiveSurfaces[
i];
732 for(std::size_t j = i+1;
j < passiveSurfaces.size(); ++
j) {
733 const Acts::Surface* testSurf = passiveSurfaces[
j];
734 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Checking passive surface "<<surf->name()<<
" geo id "<<surf->geometryId()
735 <<" with passive surface "<<testSurf->name()<<" geo id "<<testSurf->geometryId());
736 if(testSurf->geometryId().volume() != surf->geometryId().volume()){
737 continue;
738 }
739 if(surf->type() == Acts::Surface::SurfaceType::Cylinder){
740 using BoundEnum = Acts::CylinderBounds::BoundValues;
741 const auto& bounds = static_cast<const Acts::CylinderBounds&>(surf->bounds());
742 double passiveR = bounds.get(BoundEnum::eR);
743 double passiveZ = bounds.get(BoundEnum:: eHalfLengthZ);
744 bool overlap = checkOverlapWithCylinder(gctx.
context(), testSurf, center, passiveR, passiveZ);
745 if(overlap) {
746 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<<surf->name()<<
"geo id "<<surf->geometryId()
747 <<" overlaps with surface "<<testSurf->name()<<"geo id "<<testSurf->geometryId()
748 <<" in the same volume "<<surf->geometryId().volume());
749 overlapSurfaces.insert(surf);
750 overlapSurfaces.insert(testSurf);
752 retCode = StatusCode::FAILURE;
753 }
754 }
755 }else if(surf->type() == Acts::Surface::SurfaceType::Disc){
756 using BoundEnum = Acts::RadialBounds::BoundValues;
757 const auto& bounds = static_cast<const Acts::RadialBounds&>(surf->bounds());
758 bool overlap = checkOverlapWithDisc(gctx.
context(), testSurf, center, bounds.get(BoundEnum::eMaxR));
759 if(overlap) {
760 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<<surf->name()<<
"geo id "<<surf->geometryId()
761 <<" overlaps with surface "<<testSurf->name()<<"geo id "<<testSurf->geometryId()
762 <<" in the same volume "<<surf->geometryId().volume());
763 overlapSurfaces.insert(surf);
764 overlapSurfaces.insert(testSurf);
766 retCode = StatusCode::FAILURE;
767 }
768 }
769 } else {
770 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
771 <<", "<< surf->name() <<" is not a cylinder surface or disc");
772 return StatusCode::FAILURE;
773 }
774 }
775 }
776
777 if (overlapVolumes.size() || overlapSurfaces.size()) {
778 const Acts::Volume* refVolume = (*overlapVolumes.begin());
779 std::vector<const Acts::Volume*> childVols{};
780 childVols.insert(childVols.begin(),std::next(overlapVolumes.begin()), overlapVolumes.end());
781 std::vector<const Acts::Surface*> childSurfs{overlapSurfaces.begin(), overlapSurfaces.end()};
782 saveEnvelope(gctx,
"TrackingGeometryOverlaps", *refVolume,
783 childSurfs, childVols);
784 }
785
786
787 if(overlapVolumes.empty()) {
788 ATH_MSG_ALWAYS(
"No overlaps detected in the tracking geometry!!");
790 retCode = StatusCode::FAILURE;
791 }
792 return retCode;
793 }
Scalar eta() const
pseudorapidity method
#define ATH_MSG_ALWAYS(x,...)
#define ATH_MSG_VERBOSE(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.