5#if defined(FLATTEN) && defined(__GNUC__)
7#pragma GCC optimize "-fno-var-tracking-assignments"
19#include <GaudiKernel/SystemOfUnits.h>
21#include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
22#include "Acts/Geometry/TrackingGeometry.hpp"
23#include "Acts/Geometry/DiamondVolumeBounds.hpp"
24#include "Acts/Surfaces/TrapezoidBounds.hpp"
25#include "Acts/Surfaces/CylinderBounds.hpp"
26#include "Acts/Surfaces/RadialBounds.hpp"
27#include "Acts/Surfaces/CylinderSurface.hpp"
28#include "Acts/Surfaces/DiscSurface.hpp"
29#include "Acts/Geometry/VolumePlacementBase.hpp"
31#include "Acts/Visualization/ObjVisualization3D.hpp"
32#include "Acts/Visualization/GeometryView3D.hpp"
33#include "Acts/Definitions/Units.hpp"
39using namespace Acts::UnitLiterals;
43 constexpr double tolerance = 10. *Gaudi::Units::micrometer;
47 std::vector<std::shared_ptr<const Acts::Volume>> vols{};
48 std::ranges::transform(sector.
chambers(),std::back_inserter(vols),
49 [&gctx](
const auto& ch){ return ch->boundingVolume(gctx); });
52 std::vector<const Acts::Volume*> chamberVolumes(
const Acts::TrackingVolume& vol) {
53 std::vector<const Acts::Volume*>
children {};
54 for (
const Acts::TrackingVolume& childVol : vol.volumes()) {
55 std::vector<const Acts::Volume*> grandChildren = chamberVolumes(childVol);
61 std::vector<const Acts::Surface*> extractSurfaces(
const std::vector<const MuonGMR4::MuonReadoutElement*>& reEles){
62 std::vector<const Acts::Surface*> surfaces{};
63 for (
const auto*
re : reEles) {
64 std::ranges::transform(
re->getSurfaces(), std::back_inserter(surfaces),
65 [](
const std::shared_ptr<Acts::Surface>& surface) { return surface.get() ; });
70 std::vector<const Acts::Surface*> extractSurfaces(
const Acts::TrackingVolume& volume) {
71 std::vector<const Acts::Surface*> surfaces{};
72 std::ranges::for_each(volume.surfaces(), [&surfaces](
const Acts::Surface& surface){
73 if (surface.isSensitive()) {
74 surfaces.push_back(&surface);
77 for (
const Acts::TrackingVolume& subVol : volume.volumes()) {
78 std::vector<const Acts::Surface*> childSurfaces = extractSurfaces(subVol);
79 surfaces.insert(surfaces.end(), childSurfaces.begin(), childSurfaces.end());
90 bool checkOverlapWithCylinder(
const Acts::GeometryContext& gctx,
91 const Acts::Surface* testSurf,
95 if (testSurf->type() == Acts::Surface::SurfaceType::Cylinder) {
96 const auto& testBounds =
static_cast<const Acts::CylinderBounds&
>(testSurf->bounds());
97 using BoundEnum = Acts::CylinderBounds::BoundValues;
98 const double testR = testBounds.get(BoundEnum::eR);
99 const auto& testCenter = testSurf->center(gctx);
100 double dr = std::abs(testCenter.perp() - center.perp());
101 double dz = std::abs(testCenter.z() - center.z());
103 if (dr > testR + radius ||
104 (dr <= Acts::s_epsilon && std::abs(testR-radius) > Acts::s_epsilon) ||
105 (dz > halfZ + testBounds.get(BoundEnum::eHalfLengthZ))) {
108 }
else if (testSurf->type() == Acts::Surface::SurfaceType::Disc) {
110 using BoundEnum = Acts::RadialBounds::BoundValues;
111 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(testSurf->bounds());
112 const auto& testCenter = testSurf->center(gctx);
113 double dz = std::abs(testCenter.z() - center.z());
116 (dz < halfZ && bounds.get(BoundEnum::eMaxR) < (radius))) {
120 std::cerr <<
"Overlap check with surface type " << testSurf->type() <<
" is not implemented yet\n";
126 bool checkOverlapWithDisc(
const Acts::GeometryContext& gctx,
127 const Acts::Surface* testSurf,
129 if (testSurf->type() == Acts::Surface::SurfaceType::Cylinder) {
130 const auto& testBounds =
static_cast<const Acts::CylinderBounds&
>(testSurf->bounds());
131 using BoundEnum = Acts::CylinderBounds::BoundValues;
132 const double testR = testBounds.get(BoundEnum::eR);
133 const auto& testCenter = testSurf->center(gctx);
134 double dz = std::abs(testCenter.z() - center.z());
136 if (dz > testBounds.get(BoundEnum::eHalfLengthZ) ||
137 (dz < testBounds.get(BoundEnum::eHalfLengthZ) && radius < testR)) {
140 }
else if (testSurf->type() == Acts::Surface::SurfaceType::Disc) {
141 using BoundEnum = Acts::RadialBounds::BoundValues;
142 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(testSurf->bounds());
143 const auto& testCenter = testSurf->center(gctx);
144 double dz = std::abs(testCenter.z() - center.z());
145 double dr = std::abs(testCenter.perp() - center.perp());
147 if (dz > Acts::s_epsilon ||
148 dr > (radius+bounds.get(BoundEnum::eMaxR))){
152 std::cerr <<
"Overlap check with surface type " << testSurf->type() <<
" is not implemented yet\n";
166 return StatusCode::SUCCESS;
168 template <
class EnvelopeType>
169#if defined(FLATTEN) && defined(__GNUC__)
178 const EnvelopeType& chamb,
179 const Acts::Volume& boundVol,
181 const std::string& descr,
188 if (boundVol.volumeBounds().inside(locPos,
tolerance)) {
190 <<
", point "<<descr <<
" is inside of the chamber "<<std::endl<<chamb<<std::endl
192 return StatusCode::SUCCESS;
196 planeTrapezoid.
defineTrapezoid(chamb.halfXShort(), chamb.halfXLong(), chamb.halfY());
197 planeTrapezoid.
setLevel(MSG::VERBOSE);
199 static const Eigen::Rotation2D axisSwap{90. *Gaudi::Units::deg};
200 if (std::abs(locPos.z()) - chamb.halfZ() < -
tolerance &&
202 return StatusCode::SUCCESS;
206 << descr <<
" "<<
Amg::toString(point)<<
" is not part of the chamber volume."
207 <<std::endl<<std::endl<<chamb<<std::endl<<
"Local position "<<
Amg::toString(locPos)
208 <<
", "<<planeTrapezoid
211 return StatusCode::FAILURE;
215 const Acts::TrackingVolume& volume,
217 const std::string& descr,
220 return StatusCode::SUCCESS;
224 <<
" is not part of the chamber volume. The corners of the volume are:");
228 return StatusCode::FAILURE;
231 template <
class EnvelopeType>
233 const EnvelopeType& envelope)
const {
234 std::shared_ptr<Acts::Volume> boundVol = envelope.boundingVolume(gctx);
237 if constexpr (std::is_same_v<EnvelopeType, SpectrometerSector>) {
238 if (readOut->msSector() != &envelope) {
240 <<std::endl<<(*readOut->msSector())<<std::endl<<envelope);
241 return StatusCode::FAILURE;
243 }
else if constexpr (std::is_same_v<EnvelopeType, Chamber>) {
244 if (readOut->chamber() != &envelope) {
246 <<std::endl<<(*readOut->chamber())<<std::endl<<envelope);
247 return StatusCode::FAILURE;
250 switch (readOut->detectorType()) {
272 ATH_MSG_ERROR(
"Who came up with putting "<<readOut->detectorType()<<
" into the MS");
273 return StatusCode::FAILURE;
277 ATH_MSG_DEBUG(
"All "<<reEles.size()<<
" readout elements are embedded in "<<envelope);
278 return StatusCode::SUCCESS;
282 const Acts::Volume& volume)
const {
284 const auto& bounds = volume.volumeBounds();
285 unsigned int edgeIdx{0};
287 if(bounds.type() == Acts::VolumeBounds::BoundsType::eDiamond){
288 const auto& diamondBounds =
static_cast<const Acts::DiamondVolumeBounds&
>(bounds);
289 using BoundEnum = Acts::DiamondVolumeBounds::BoundValues;
290 std::vector<Amg::Vector3D> edges(12, Amg::Vector3D::Zero());
291 double xCord{0.}, yCord{0};
292 for(
double signX : {-1.,1.}){
293 for(
double signY : {-1., 0., 1.}){
294 for(
double signZ : {-1.,1.}){
296 xCord = diamondBounds.get(BoundEnum::eHalfLengthX2);
298 xCord = diamondBounds.get(BoundEnum::eHalfLengthX1);
299 yCord = diamondBounds.get(BoundEnum::eLengthY1);
301 xCord = diamondBounds.get(BoundEnum::eHalfLengthX3);
302 yCord = diamondBounds.get(BoundEnum::eLengthY2);
307 signZ*diamondBounds.get(BoundEnum::eHalfLengthZ)};
308 edges[edgeIdx] = volume.localToGlobalTransform(gctx.
context())*edge;
317 std::vector<Amg::Vector3D> edges{};
319 for (
const double signX : {-1., 1.}) {
320 for (
const double signY : { -1., 1.}) {
321 for (
const double signZ: {-1., 1.}) {
325 edges.push_back(volume.localToGlobalTransform(gctx.
context()) * edge);
336 using BoundEnum = Acts::LineBounds::BoundValues;
337 const auto& bounds =
static_cast<const Acts::LineBounds&
>(surface.bounds());
338 unsigned int edgeIdx{0};
341 for (
const double signX : {-1., 1.}) {
342 for (
const double signY : { -1., 1.}) {
343 for (
const double signZ: {-1., 1.}) {
345 signY*bounds.get(BoundEnum::eR),
346 signZ*bounds.get(BoundEnum::eHalfLengthZ)};
347 edges[edgeIdx] = surface.localToGlobalTransform(gctx.
context()) * edge;
357 if(surface.bounds().type() == Acts::SurfaceBounds::BoundsType::eRectangle) {
358 const Acts::RectangleBounds& bounds =
static_cast<const Acts::RectangleBounds&
>(surface.bounds());
359 using BoundEnum = Acts::RectangleBounds::BoundValues;
361 unsigned int edgeIdx{0};
362 for(
const double signX : {-1., 1.}) {
363 for (
const double signY : { -1., 1.}) {
364 const Amg::Vector3D edge{signX < 0 ? bounds.get(BoundEnum::eMinX) : bounds.get(BoundEnum::eMaxX),
365 signY < 0 ? bounds.get(BoundEnum::eMinY) : bounds.get(BoundEnum::eMaxY), 0.};
366 edges[edgeIdx] = surface.localToGlobalTransform(gctx.
context()) * edge;
371 }
else if(surface.bounds().type() == Acts::SurfaceBounds::BoundsType::eTrapezoid) {
372 using BoundEnum = Acts::TrapezoidBounds::BoundValues;
373 const auto& bounds =
static_cast<const Acts::TrapezoidBounds&
>(surface.bounds());
374 unsigned int edgeIdx{0};
377 for (
const double signX : {-1., 1.}) {
378 for (
const double signY : { -1., 1.}) {
380 Amg::Vector3D(signX*bounds.get(signY < 0 ? BoundEnum::eHalfLengthXnegY : BoundEnum::eHalfLengthXposY),
381 signY*bounds.get(BoundEnum::eHalfLengthY), 0.)};
383 edges[edgeIdx] = surface.localToGlobalTransform(gctx.
context()) * edge;
390 ATH_MSG_ERROR(
"The surface bounds are neither a rectangle nor a trapezoid, this is not supported yet");
396#if defined(FLATTEN) && defined(__GNUC__)
405 const std::vector<Amg::Vector3D>& chamberEdges,
406 const Acts::Volume& volume)
const {
410 double minDist = 1._km;
412 minDist = std::min(minDist, (edge - center).
mag());
416 if (std::ranges::none_of(volume.volumeBounds().values(),
417 [minDist](
const double bound){
418 return minDist < 2.5*bound;
424 const Acts::VolumeBounds& volBounds = volume.volumeBounds();
425 const Acts::Transform3& transform = volume.globalToLocalTransform(gctx.
context());
426 for (
unsigned edge1 = 1; edge1 < chamberEdges.size(); ++edge1) {
427 for (
unsigned edge2 = 0; edge2 < edge1; ++edge2) {
429 const double section = stepLength * step;
433 if (volBounds.inside (transform * testPoint)) {
443 std::vector<const MuonReadoutElement*> allRE =
m_detMgr->getAllReadoutElements();
446 ATH_MSG_INFO(
"Fetched "<<chambers.size()<<
" chambers.");
447 std::vector<const Chamber*> chamberVec{chambers.begin(), chambers.end()};
450 return std::ranges::find(chamberVec,
re->chamber()) == chamberVec.end();
452 if (missChamb != allRE.end()) {
453 ATH_MSG_ERROR(
"The chamber "<<(*(*missChamb)->chamber())<<
" is not in the chamber set");
454 return StatusCode::FAILURE;
459 std::vector<std::shared_ptr<Acts::Volume> > chamberBoundsVec;
460 chamberBoundsVec.reserve (chamberVec.size());
461 for (
const Chamber* ch : chamberVec)
462 chamberBoundsVec.push_back (ch->boundingVolume(gctx));
464 std::set<const Chamber*> overlapChambers{};
465 std::stringstream overlapstream{};
466 for (std::size_t chIdx = 0; chIdx< chamberVec.size(); ++chIdx) {
467 const Chamber& chamber{*chamberVec[chIdx]};
468 const Acts::Volume& chamberBounds = *chamberBoundsVec[chIdx];
470 saveEnvelope(gctx, std::format(
"Chamber_{:}{:}{:}{:}{:}",
471 chamber.detectorType(),
472 chName(chamber.chamberIndex()),
473 std::abs(chamber.stationEta()),
474 chamber.stationEta() > 0 ?
'A' :
'C',
475 chamber.stationPhi()),
476 chamberBounds, extractSurfaces(chamber.readoutEles()));
479 const std::vector<Amg::Vector3D> chambCorners =
cornerPoints(gctx, chamberBounds);
481 std::vector<const Chamber*> overlaps{};
482 for (std::size_t chIdx1 = 0; chIdx1<chamberVec.size(); ++chIdx1) {
483 if (chIdx == chIdx1) {
486 const Chamber* overlapTest{chamberVec[chIdx1]};
487 if (
hasOverlap(gctx, chambCorners, *chamberBoundsVec[chIdx1])) {
488 overlaps.push_back(overlapTest);
491 if (overlaps.empty()) {
494 overlapstream<<
"The chamber "<<chamber<<
" overlaps with "<<std::endl;
495 for (
const Chamber* itOverlaps : overlaps) {
496 overlapstream<<
" *** "<<(*itOverlaps)<<std::endl;
498 overlapstream<<std::endl<<std::endl;
499 overlapChambers.insert(overlaps.begin(), overlaps.end());
500 overlapChambers.insert(chamberVec[chIdx]);
502 if (!overlapChambers.empty()) {
503 Acts::ObjVisualization3D visualHelper{};
505 Acts::GeometryView3D::drawVolume(visualHelper, *
hasOverlap->boundingVolume(gctx), gctx.
context());
514 ATH_MSG_INFO(
"Chamber test completed. Found "<<overlapChambers.size()<<
" overlapping chambers");
515 return overlapChambers.empty() ||
m_ignoreOverlapCh ? StatusCode::SUCCESS : StatusCode::FAILURE;
520 std::vector<const MuonReadoutElement*> allREs =
m_detMgr->getAllReadoutElements();
522 if (!
re->msSector()) {
524 return StatusCode::FAILURE;
529 if (sectorFromDet !=
re->msSector()) {
532 <<
" is not the one attached to the readout geometry \n"<<(*
re->msSector())<<
"\n"<<(*sectorFromDet));
533 return StatusCode::FAILURE;
537 const SectorSet sectors =
m_detMgr->getAllSectors();
538 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Fetched "<<sectors.size()<<
" sectors. ");
541 const auto subVols = chamberVolumes(gctx, *sector);
543 chName(sector->chamberIndex()),
544 sector->side() >0?
'A' :
'C',
545 sector->stationPhi() ),
546 *sector->boundingVolume(gctx),
547 extractSurfaces(sector->readoutEles()),
548 Acts::unpackSmartPointers(subVols));
551 const std::shared_ptr<Acts::Volume> secVolume = sector->boundingVolume(gctx);
553 const std::vector<Amg::Vector3D> edges =
cornerPoints(gctx, *chamber->boundingVolume(gctx));
554 unsigned int edgeCount{0};
557 chamber->readoutEles().front()->identify()));
561 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Sector envelope test completed.");
562 return StatusCode::SUCCESS;
565 const Acts::TrackingVolume& volume)
const {
566 if (!volume.isAlignable()) {
567 return StatusCode::SUCCESS;
569 const Acts::GeometryContext geoCtx = gctx.
context();
570 std::vector<std::shared_ptr<const Acts::Surface>> portals{};
571 for (
const Acts::Portal& portal : volume.portals()) {
572 if (portal.surface().geometryId().withBoundary(0) != volume.geometryId()) {
575 portals.push_back(portal.surface().getSharedPtr());
577 const auto unAlignedPortals = volume.volumeBounds().orientedSurfaces(volume.localToGlobalTransform(geoCtx));
579 if (unAlignedPortals.size() != portals.size()) {
580 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The size of the aligned and unaligned portals don't match for volume "
581 <<volume.volumeName()<<
". Aligned: "<<portals.size()<<
", unaligned: "<<unAlignedPortals.size());
582 return StatusCode::FAILURE;
584 StatusCode retCode = StatusCode::SUCCESS;
585 for (std::size_t p =0 ; p < portals.size(); ++p){
587 if (portals[p]->bounds() != unAlignedPortals[p].surface->bounds()) {
588 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The bounds of the "<<p
589 <<
"-th portal differ:\n -- aligned: "<<portals[p]->bounds()
590 <<
"\n -- unaligned: "<<unAlignedPortals[p].surface->bounds());
591 retCode = StatusCode::FAILURE;
593 const Amg::Transform3D& uTrf{unAlignedPortals[p].surface->localToGlobalTransform(geoCtx)};
598 <<
" - The unaligned and aligned portals don't end up at the same point \n"
600 retCode = StatusCode::FAILURE;
608 const Acts::TrackingGeometry& trackingGeometry)
const {
612 std::vector<const Acts::TrackingVolume*> volumeVec{};
613 std::vector<const Acts::Surface*> passiveSurfaces{};
615 std::unordered_set<const Acts::TrackingVolume*> overlapVolumes{};
616 std::unordered_set<const Acts::Surface*> overlapSurfaces{};
620 trackingGeometry.visitVolumes([&](
const Acts::TrackingVolume* vol) {
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);
635 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Skip volume "
636 <<vol->volumeName()<<
".");
639 volumeVec.push_back(vol);
643 << passiveSurfaces.size()<<
" passive surfaces");
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());
650 visualHelper.write(
"MsTrackTest_passiveSurfaces.obj");
653 StatusCode retCode = StatusCode::SUCCESS;
654 for(std::size_t vIdx = 0; vIdx < volumeVec.size(); ++vIdx) {
655 const Acts::TrackingVolume* testVol{volumeVec.at(vIdx)};
658 std::vector<const Acts::TrackingVolume*> overlaps{};
659 const std::vector<Amg::Vector3D> edges =
cornerPoints(gctx, *testVol);
661 for(
const auto& surface : testVol->surfaces()) {
663 std::vector<Amg::Vector3D> surfEdges = {};
664 if(surface.type() == Acts::Surface::SurfaceType::Straw){
665 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__<<
" Checking "<<surface.type()<<
" surface "<<identify(surface)
666 <<
" / "<<surface.geometryId() <<
" in volume "<<testVol->volumeName());
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){
671 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__<<
" Checking "<<surface.type()<<
" surface "<<identify(surface)
672 <<
" / "<<surface.geometryId() <<
" in volume "<<testVol->volumeName());
674 auto edges =
cornerPoints(gctx,
dynamic_cast<const Acts::PlaneSurface&
>(surface));
675 surfEdges.insert(surfEdges.end() , edges.begin(), edges.end());
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;
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;
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;
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));
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){
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()));
742 const Identifier volId = identify(*extractSurfaces(*testVol).front());
743 double volHalfR{0.}, volHalfZ{0.};
754 const double rMin = center.perp() - volHalfR;
757 const double rMax = (testVol->localToGlobalTransform(gctx.
context()) *(
758 halfX * Amg::Vector3D::UnitX() +
759 volHalfR * Amg::Vector3D::Unit(1 +
isBarrel))).perp();
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());
772 for(std::size_t i = 0; i < passiveSurfaces.size(); ++i) {
774 const Acts::Surface* surf = passiveSurfaces[i];
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){
785 if (passiveZ < zMin || -passiveZ > zMax) {
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) {
794 const double surfRMax = bounds.get(BoundEnum::eMaxR);
795 const double surfRMin = bounds.get(BoundEnum::eMinR);
796 if (surfRMax < rMin || surfRMin > rMax){
801 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
802 <<
", "<< surf->name() <<
" is not a cylinder surface or disc");
803 return StatusCode::FAILURE;
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;
814 overlapSurfaces.insert(surf);
815 overlapVolumes.insert(testVol);
820 if(overlaps.empty()) {
821 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - No overlaps detected for the volume "<<testVol->volumeName());
825 overlapVolumes.insert(overlaps.begin(), overlaps.end());
826 overlapVolumes.insert(testVol);
828 std::stringstream overlapStream{};
829 overlapStream<<__func__<<
"() "<<__LINE__<<
" - The volume "
830 <<testVol->volumeName() <<
" overlaps with: "<<std::endl;
832 for(
const Acts::TrackingVolume* overlap: overlaps){
833 overlapStream<<
" --- Volume: " << overlap->volumeName()<<
", "<<overlap->volumeBounds()
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()){
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);
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;
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));
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;
881 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
882 <<
", "<< surf->name() <<
" is not a cylinder surface or disc");
883 return StatusCode::FAILURE;
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);
898 if(overlapVolumes.empty()) {
899 ATH_MSG_ALWAYS(
"No overlaps detected in the tracking geometry!!");
901 retCode = StatusCode::FAILURE;
907 const std::string& envName,
908 const Acts::Volume& envelopeVol,
909 const std::vector<const Acts::Surface*>& assocSurfaces,
910 const std::vector<const Acts::Volume*>& subVols)
const {
911 Acts::ObjVisualization3D visualHelper{};
912 std::ranges::for_each(assocSurfaces, [&visualHelper, &gctx](
const Acts::Surface* surface) {
913 Acts::GeometryView3D::drawSurface(visualHelper, *surface, gctx.
context());
916 std::ranges::for_each(subVols, [&visualHelper, &gctx](
const Acts::Volume* subVol) {
917 Acts::GeometryView3D::drawVolume(visualHelper,*subVol, gctx.
context(), Amg::Transform3D::Identity(),
918 Acts::s_viewPassive);
920 Acts::GeometryView3D::drawVolume(visualHelper, envelopeVol, gctx.
context());
921 ATH_MSG_DEBUG(
"Save new envelope 'MsTrackTest_"<<envName<<
".obj'");
922 visualHelper.write(std::format(
"MsTrackTest_{:}.obj", envName));
933 return StatusCode::SUCCESS;
935 template <
class EnvelopeType>
938 const EnvelopeType& chamber,
939 const Acts::Volume& detVol)
const {
942 for (
unsigned int layer = 1; layer <= mdtMl.
numLayers(); ++layer) {
943 for (
unsigned int tube = 1; tube <= mdtMl.
numTubesInLay(); ++tube) {
957 "bottom of the tube box", measId));
959 "sealing of the tube box", measId));
962 "wall to the previous tube", measId));
964 "wall to the next tube", measId));
967 return StatusCode::SUCCESS;
969 template<
class EnvelopeType>
972 const EnvelopeType& chamber,
973 const Acts::Volume& detVol)
const {
978 for (
unsigned int gasGap = 1 ; gasGap <= rpc.
nGasGaps(); ++gasGap) {
980 for (
bool measPhi : {
false,
true}) {
984 doubletPhi, gasGap, measPhi,
strip);
992 return StatusCode::SUCCESS;
994 template <
class EnevelopeType>
997 const EnevelopeType& chamber,
998 const Acts::Volume& detVol)
const {
999 for (
unsigned int gasGap = 1; gasGap <= tgc.
nGasGaps(); ++gasGap){
1000 for (
bool isStrip : {
false}) {
1002 const unsigned int nChannel = tgc.
numChannels(layHash);
1003 for (
unsigned int channel = 1; channel <= nChannel ; ++channel) {
1010 return StatusCode::SUCCESS;
1012 template <
class EnevelopeType>
1015 const EnevelopeType& chamber,
1016 const Acts::Volume& detVol)
const {
1019 for(
unsigned int gasGap = 1; gasGap <= mm.nGasGaps(); ++gasGap){
1021 unsigned int firstStrip = mm.firstStrip(gasGapHash);
1022 for(
unsigned int strip = firstStrip;
strip <= mm.numStrips(gasGapHash); ++
strip){
1024 ATH_CHECK(
pointInside(gctx, chamber, detVol, mm.stripPosition(gctx, stripId),
"center", stripId));
1025 ATH_CHECK(
pointInside(gctx, chamber, detVol, mm.leftStripEdge(gctx, mm.measurementHash(stripId)),
"left edge", stripId));
1026 ATH_CHECK(
pointInside(gctx, chamber, detVol, mm.rightStripEdge(gctx, mm.measurementHash(stripId)),
"right edge", stripId));
1030 return StatusCode::SUCCESS;
1032 template <
class EnvelopeType>
1035 const EnvelopeType& chamber,
1036 const Acts::Volume& detVol)
const{
1039 for(
unsigned int gasGap = 1; gasGap <= stgc.
numLayers(); ++gasGap){
1041 for(
unsigned int nch = 1; nch <= stgc.
nChTypes(); ++nch){
1043 const unsigned int nStrips = stgc.
numChannels(gasGapHash);
1058 return StatusCode::SUCCESS;
Scalar eta() const
pseudorapidity method
Scalar mag() const
mag method
constexpr std::array< T, N > make_array(const T &def_val)
Helper function to initialize in-place arrays with non-zero values.
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_ALWAYS(x)
#define ATH_MSG_WARNING(x)
Acts::GeometryContext context() const
base class interface providing the bare minimal interface extension.
virtual Identifier identify() const =0
Return the ATLAS identifier.
Implementation to make a (tracking) volume alignable.
const ServiceHandle< StoreGateSvc > & detStore() const
void setLevel(MSG::Level lvl)
Change the current logging level.
This is a "hash" representation of an Identifier.
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channel) const
Chamber represent the volume enclosing a muon station.
std::vector< const MuonReadoutElement * > ReadoutSet
Define the list of read out elements of the chamber.
Readout element to describe the Monitored Drift Tube (Mdt) chambers Mdt chambers usually comrpise out...
Amg::Vector3D highVoltPos(const ActsTrk::GeometryContext &ctx, const Identifier &measId) const
Returns the endpoint of the tube connected to the high voltage in the ATLAS coordinate frame.
unsigned numLayers() const
Returns how many tube layers are inside the multi layer [1;4].
bool isValid(const IdentifierHash &measHash) const
Checks whether the passed meaurement hash corresponds to a valid tube described by the readout elemen...
Amg::Vector3D readOutPos(const ActsTrk::GeometryContext &ctx, const Identifier &measId) const
Returns the endpoint of the tube where the readout card is mounted in the ATLAS coordinate frame.
const parameterBook & getParameters() const
Get a const reference to the parameter book.
Amg::Vector3D globalTubePos(const ActsTrk::GeometryContext &ctx, const Identifier &measId) const
Returns the position of the tube mid point in the ATLAS coordinate frame.
double innerTubeRadius() const
Returns the inner tube radius.
unsigned numTubesInLay() const
Returns the number of tubes in a layer.
static IdentifierHash measurementHash(unsigned layerNumber, unsigned tubeNumber)
Constructs a Measurement hash from layer && tube number.
Identifier measurementId(const IdentifierHash &measHash) const override final
Back conversion of the measurement hash towards a full identifier Tube & layer number are extracted f...
static IdentifierHash createHash(const int gasGap, const int strip)
std::vector< const Chamber * > MuonChamberSet
std::vector< const SpectrometerSector * > MuonSectorSet
MuonReadoutElement is an abstract class representing the geometry of a muon detector.
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &ctx) const
Returns the transformation from the local coordinate system of the readout element into the global AT...
Identifier identify() const override final
Return the ATLAS identifier.
unsigned nPhiStrips() const
Number of strips measuring the phi coordinate.
Amg::Vector3D leftStripEdge(const ActsTrk::GeometryContext &ctx, const Identifier &measId) const
Returns the global posiition of the strip edge at positive local Y.
int doubletZ() const
Returns the doublet Z field of the MuonReadoutElement identifier.
int doubletPhi() const
Returns the doublet Phi field of the MuonReadoutElement identifier.
Amg::Vector3D rightStripEdge(const ActsTrk::GeometryContext &ctx, const Identifier &measId) const
Returns the global position of the strip edge at negative local Y.
unsigned nEtaStrips() const
Number of strips measuring the eta coordinate.
int doubletPhiMax() const
Returns the maximum phi panel.
const parameterBook & getParameters() const
Amg::Vector3D stripPosition(const ActsTrk::GeometryContext &ctx, const Identifier &measId) const
Returns the position of the strip center.
unsigned nGasGaps() const
Returns the number of gasgaps described by this ReadOutElement (usally 2 or 3).
A spectrometer sector forms the envelope of all chambers that are placed in the same MS sector & laye...
const ChamberSet & chambers() const
Returns the associated chambers with this sector.
GeoModel::TransientConstSharedPtr< Chamber > ChamberPtr
void defineStripLayout(Amg::Vector2D &&posFirst, const double stripPitch, const double stripWidth, const int numStrips, const int numFirst=1)
Defines the layout of the strip detector by specifing the position of the first strip w....
CheckVector2D leftEdge(int stripNumb) const
Returns the left edge of the strip (Global numbering scheme).
void defineTrapezoid(double HalfShortY, double HalfLongY, double HalfHeight)
Defines the edges of the trapezoid.
bool insideTrapezoid(const Amg::Vector2D &extPos) const
Checks whether an external point is inside the trapezoidal area.
CheckVector2D rightEdge(int stripNumb) const
Returns the right edge of the strip (Global numbering scheme).
Amg::Vector3D channelPosition(const ActsTrk::GeometryContext &ctx, const Identifier &measId) const
Returns the center of the measurement channel eta measurement: wire gang center phi measurement: stri...
Identifier measurementId(const IdentifierHash &measHash) const override final
Back conversion of the measurement hash to a full Athena Identifier The behaviour is undefined if a l...
static IdentifierHash constructHash(unsigned measCh, unsigned gasGap, const bool isStrip)
Constructs the Hash out of the Identifier fields (channel, gasGap, isStrip).
unsigned numChannels(const IdentifierHash &measHash) const
Returns the number of readout channels.
unsigned nGasGaps() const
Returns the number of gasgaps described by this ReadOutElement (usally 2 or 3).
unsigned numChannels(const IdentifierHash &measHash) const
Returns the number of strips / wires / pads in a given gasGap.
IdentifierHash measurementHash(const Identifier &measId) const override final
Constructs the identifier hash from the full measurement Identifier.
Amg::Vector3D leftStripEdge(const ActsTrk::GeometryContext &ctx, const IdentifierHash &measHash) const
int multilayer() const
Returns the multilayer of the sTgcReadoutElement.
unsigned nChTypes() const
Number of Channel Types.
Amg::Vector3D rightStripEdge(const ActsTrk::GeometryContext &ctx, const IdentifierHash &measHash) const
unsigned numLayers() const
Returns the number of gas gap layers.
ReadoutChannelType
ReadoutChannelType to distinguish the available readout channels Pad - pad readout channel Strip - et...
Amg::Vector3D globalChannelPosition(const ActsTrk::GeometryContext &ctx, const IdentifierHash &measHash) const
Returns the global pad/strip/wireGroup position.
static IdentifierHash createHash(const unsigned gasGap, const unsigned channelType, const unsigned channel, const unsigned wireInGrp=0)
Create a measurement hash from the Identifier fields.
Identifier channelID(int stationName, int stationEta, int stationPhi, int doubletR, int doubletZ, int doubletPhi, int gasGap, int measuresPhi, int strip) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channelType, int channel) const
@ Mm
Maybe not needed in the migration.
@ Tgc
Resitive Plate Chambers.
@ Rpc
Monitored Drift Tubes.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
bool isIdentity(const Amg::Transform3D &trans)
Checks whether the transformation is the Identity transformation.
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
The ReadoutGeomCnvAlg converts the Run4 Readout geometry build from the GeoModelXML into the legacy M...
double halfY(const Acts::VolumeBounds &bounds)
Returns the half-Y length for the parsed volume bounds (Trapezoid/ Cuboid).
SpectrometerSector::ChamberSet ChamberSet
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).
double halfXlowY(const Acts::VolumeBounds &bounds)
Returns the half-X length @ negative Y for the parsed volume bounds (Trapezoid/ Cuboid).
bool isBarrel(const ChIndex index)
Returns true if the chamber index points to a barrel chamber.
const std::string & chName(ChIndex index)
convert ChIndex into a string
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
const Identifier & identify(const UncalibratedMeasurement *meas)
Returns the associated identifier from the muon measurement.