5#if defined(FLATTEN) && defined(__GNUC__)
7#pragma GCC optimize "-fno-var-tracking-assignments"
21#include <GaudiKernel/SystemOfUnits.h>
23#include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
24#include "Acts/Geometry/TrackingGeometry.hpp"
25#include "Acts/Geometry/DiamondVolumeBounds.hpp"
26#include "Acts/Surfaces/TrapezoidBounds.hpp"
27#include "Acts/Surfaces/CylinderBounds.hpp"
28#include "Acts/Surfaces/RadialBounds.hpp"
29#include "Acts/Surfaces/CylinderSurface.hpp"
30#include "Acts/Surfaces/DiscSurface.hpp"
31#include "Acts/Geometry/VolumePlacementBase.hpp"
33#include "Acts/Visualization/ObjVisualization3D.hpp"
34#include "Acts/Visualization/GeometryView3D.hpp"
35#include "Acts/Definitions/Units.hpp"
41using namespace Acts::UnitLiterals;
45 constexpr double tolerance = 10. *Gaudi::Units::micrometer;
49 std::vector<std::shared_ptr<const Acts::Volume>> vols{};
50 std::ranges::transform(sector.
chambers(),std::back_inserter(vols),
51 [&gctx](
const auto& ch){ return ch->boundingVolume(gctx); });
54 std::vector<const Acts::Volume*> chamberVolumes(
const Acts::TrackingVolume& vol) {
55 std::vector<const Acts::Volume*>
children {};
56 for (
const Acts::TrackingVolume& childVol : vol.volumes()) {
57 std::vector<const Acts::Volume*> grandChildren = chamberVolumes(childVol);
63 std::vector<const Acts::Surface*> extractSurfaces(
const std::vector<const MuonGMR4::MuonReadoutElement*>& reEles){
64 std::vector<const Acts::Surface*> surfaces{};
65 for (
const auto*
re : reEles) {
66 std::ranges::transform(
re->getSurfaces(), std::back_inserter(surfaces),
67 [](
const std::shared_ptr<Acts::Surface>& surface) { return surface.get() ; });
72 std::vector<const Acts::Surface*> extractSurfaces(
const Acts::TrackingVolume& volume) {
73 std::vector<const Acts::Surface*> surfaces{};
74 std::ranges::for_each(volume.surfaces(), [&surfaces](
const Acts::Surface& surface){
75 if (surface.isSensitive()) {
76 surfaces.push_back(&surface);
79 for (
const Acts::TrackingVolume& subVol : volume.volumes()) {
80 std::vector<const Acts::Surface*> childSurfaces = extractSurfaces(subVol);
81 surfaces.insert(surfaces.end(), childSurfaces.begin(), childSurfaces.end());
92 bool checkOverlapWithCylinder(
const Acts::GeometryContext& gctx,
93 const Acts::Surface* testSurf,
97 if (testSurf->type() == Acts::Surface::SurfaceType::Cylinder) {
98 const auto& testBounds =
static_cast<const Acts::CylinderBounds&
>(testSurf->bounds());
99 using BoundEnum = Acts::CylinderBounds::BoundValues;
100 const double testR = testBounds.get(BoundEnum::eR);
101 const auto& testCenter = testSurf->center(gctx);
102 double dr = std::abs(testCenter.perp() - center.perp());
103 double dz = std::abs(testCenter.z() - center.z());
105 if (dr > testR + radius ||
106 (dr <= Acts::s_epsilon && std::abs(testR-radius) > Acts::s_epsilon) ||
107 (dz > halfZ + testBounds.get(BoundEnum::eHalfLengthZ))) {
110 }
else if (testSurf->type() == Acts::Surface::SurfaceType::Disc) {
112 using BoundEnum = Acts::RadialBounds::BoundValues;
113 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(testSurf->bounds());
114 const auto& testCenter = testSurf->center(gctx);
115 double dz = std::abs(testCenter.z() - center.z());
118 (dz < halfZ && bounds.get(BoundEnum::eMaxR) < (radius))) {
122 std::cerr <<
"Overlap check with surface type " << testSurf->type() <<
" is not implemented yet\n";
128 bool checkOverlapWithDisc(
const Acts::GeometryContext& gctx,
129 const Acts::Surface* testSurf,
131 if (testSurf->type() == Acts::Surface::SurfaceType::Cylinder) {
132 const auto& testBounds =
static_cast<const Acts::CylinderBounds&
>(testSurf->bounds());
133 using BoundEnum = Acts::CylinderBounds::BoundValues;
134 const double testR = testBounds.get(BoundEnum::eR);
135 const auto& testCenter = testSurf->center(gctx);
136 double dz = std::abs(testCenter.z() - center.z());
138 if (dz > testBounds.get(BoundEnum::eHalfLengthZ) ||
139 (dz < testBounds.get(BoundEnum::eHalfLengthZ) && radius < testR)) {
142 }
else if (testSurf->type() == Acts::Surface::SurfaceType::Disc) {
143 using BoundEnum = Acts::RadialBounds::BoundValues;
144 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(testSurf->bounds());
145 const auto& testCenter = testSurf->center(gctx);
146 double dz = std::abs(testCenter.z() - center.z());
147 double dr = std::abs(testCenter.perp() - center.perp());
149 if (dz > Acts::s_epsilon ||
150 dr > (radius+bounds.get(BoundEnum::eMaxR))){
154 std::cerr <<
"Overlap check with surface type " << testSurf->type() <<
" is not implemented yet\n";
168 return StatusCode::SUCCESS;
170 template <
class EnvelopeType>
171#if defined(FLATTEN) && defined(__GNUC__)
180 const EnvelopeType& chamb,
181 const Acts::Volume& boundVol,
183 const std::string& descr,
190 if (boundVol.volumeBounds().inside(locPos,
tolerance)) {
192 <<
", point "<<descr <<
" is inside of the chamber "<<std::endl<<chamb<<std::endl
194 return StatusCode::SUCCESS;
198 planeTrapezoid.
defineTrapezoid(chamb.halfXShort(), chamb.halfXLong(), chamb.halfY());
199 planeTrapezoid.
setLevel(MSG::VERBOSE);
201 static const Eigen::Rotation2D axisSwap{90. *Gaudi::Units::deg};
202 if (std::abs(locPos.z()) - chamb.halfZ() < -
tolerance &&
204 return StatusCode::SUCCESS;
208 << descr <<
" "<<
Amg::toString(point)<<
" is not part of the chamber volume."
209 <<std::endl<<std::endl<<chamb<<std::endl<<
"Local position "<<
Amg::toString(locPos)
210 <<
", "<<planeTrapezoid
213 return StatusCode::FAILURE;
217 const Acts::TrackingVolume& volume,
219 const std::string& descr,
222 return StatusCode::SUCCESS;
226 <<
" is not part of the chamber volume. The corners of the volume are:");
230 return StatusCode::FAILURE;
233 template <
class EnvelopeType>
235 const EnvelopeType& envelope)
const {
236 std::shared_ptr<Acts::Volume> boundVol = envelope.boundingVolume(gctx);
239 if constexpr (std::is_same_v<EnvelopeType, SpectrometerSector>) {
240 if (readOut->msSector() != &envelope) {
242 <<std::endl<<(*readOut->msSector())<<std::endl<<envelope);
243 return StatusCode::FAILURE;
245 }
else if constexpr (std::is_same_v<EnvelopeType, Chamber>) {
246 if (readOut->chamber() != &envelope) {
248 <<std::endl<<(*readOut->chamber())<<std::endl<<envelope);
249 return StatusCode::FAILURE;
252 switch (readOut->detectorType()) {
274 ATH_MSG_ERROR(
"Who came up with putting "<<readOut->detectorType()<<
" into the MS");
275 return StatusCode::FAILURE;
279 ATH_MSG_DEBUG(
"All "<<reEles.size()<<
" readout elements are embedded in "<<envelope);
280 return StatusCode::SUCCESS;
284 const Acts::Volume& volume)
const {
286 const auto& bounds = volume.volumeBounds();
287 unsigned int edgeIdx{0};
289 if(bounds.type() == Acts::VolumeBounds::BoundsType::eDiamond){
290 const auto& diamondBounds =
static_cast<const Acts::DiamondVolumeBounds&
>(bounds);
291 using BoundEnum = Acts::DiamondVolumeBounds::BoundValues;
292 std::vector<Amg::Vector3D> edges(12, Amg::Vector3D::Zero());
293 double xCord{0.}, yCord{0};
294 for(
double signX : {-1.,1.}){
295 for(
double signY : {-1., 0., 1.}){
296 for(
double signZ : {-1.,1.}){
298 xCord = diamondBounds.get(BoundEnum::eHalfLengthX2);
300 xCord = diamondBounds.get(BoundEnum::eHalfLengthX1);
301 yCord = diamondBounds.get(BoundEnum::eLengthY1);
303 xCord = diamondBounds.get(BoundEnum::eHalfLengthX3);
304 yCord = diamondBounds.get(BoundEnum::eLengthY2);
309 signZ*diamondBounds.get(BoundEnum::eHalfLengthZ)};
310 edges[edgeIdx] = volume.localToGlobalTransform(gctx.
context())*edge;
319 std::vector<Amg::Vector3D> edges{};
321 for (
const double signX : {-1., 1.}) {
322 for (
const double signY : { -1., 1.}) {
323 for (
const double signZ: {-1., 1.}) {
327 edges.push_back(volume.localToGlobalTransform(gctx.
context()) * edge);
338 using BoundEnum = Acts::LineBounds::BoundValues;
339 const auto& bounds =
static_cast<const Acts::LineBounds&
>(surface.bounds());
340 unsigned int edgeIdx{0};
343 for (
const double signX : {-1., 1.}) {
344 for (
const double signY : { -1., 1.}) {
345 for (
const double signZ: {-1., 1.}) {
347 signY*bounds.get(BoundEnum::eR),
348 signZ*bounds.get(BoundEnum::eHalfLengthZ)};
349 edges[edgeIdx] = surface.localToGlobalTransform(gctx.
context()) * edge;
359 if(surface.bounds().type() == Acts::SurfaceBounds::BoundsType::eRectangle) {
360 const Acts::RectangleBounds& bounds =
static_cast<const Acts::RectangleBounds&
>(surface.bounds());
361 using BoundEnum = Acts::RectangleBounds::BoundValues;
363 unsigned int edgeIdx{0};
364 for(
const double signX : {-1., 1.}) {
365 for (
const double signY : { -1., 1.}) {
366 const Amg::Vector3D edge{signX < 0 ? bounds.get(BoundEnum::eMinX) : bounds.get(BoundEnum::eMaxX),
367 signY < 0 ? bounds.get(BoundEnum::eMinY) : bounds.get(BoundEnum::eMaxY), 0.};
368 edges[edgeIdx] = surface.localToGlobalTransform(gctx.
context()) * edge;
373 }
else if(surface.bounds().type() == Acts::SurfaceBounds::BoundsType::eTrapezoid) {
374 using BoundEnum = Acts::TrapezoidBounds::BoundValues;
375 const auto& bounds =
static_cast<const Acts::TrapezoidBounds&
>(surface.bounds());
376 unsigned int edgeIdx{0};
379 for (
const double signX : {-1., 1.}) {
380 for (
const double signY : { -1., 1.}) {
382 Amg::Vector3D(signX*bounds.get(signY < 0 ? BoundEnum::eHalfLengthXnegY : BoundEnum::eHalfLengthXposY),
383 signY*bounds.get(BoundEnum::eHalfLengthY), 0.)};
385 edges[edgeIdx] = surface.localToGlobalTransform(gctx.
context()) * edge;
392 ATH_MSG_ERROR(
"The surface bounds are neither a rectangle nor a trapezoid, this is not supported yet");
398#if defined(FLATTEN) && defined(__GNUC__)
407 const std::vector<Amg::Vector3D>& chamberEdges,
408 const Acts::Volume& volume)
const {
412 double minDist = 1._km;
414 minDist = std::min(minDist, (edge - center).
mag());
418 if (std::ranges::none_of(volume.volumeBounds().values(),
419 [minDist](
const double bound){
420 return minDist < 2.5*bound;
426 const Acts::VolumeBounds& volBounds = volume.volumeBounds();
427 const Acts::Transform3& transform = volume.globalToLocalTransform(gctx.
context());
428 for (
unsigned edge1 = 1; edge1 < chamberEdges.size(); ++edge1) {
429 for (
unsigned edge2 = 0; edge2 < edge1; ++edge2) {
431 const double section = stepLength * step;
435 if (volBounds.inside (transform * testPoint)) {
445 std::vector<const MuonReadoutElement*> allRE =
m_detMgr->getAllReadoutElements();
448 ATH_MSG_INFO(
"Fetched "<<chambers.size()<<
" chambers.");
449 std::vector<const Chamber*> chamberVec{chambers.begin(), chambers.end()};
452 return std::ranges::find(chamberVec,
re->chamber()) == chamberVec.end();
454 if (missChamb != allRE.end()) {
455 ATH_MSG_ERROR(
"The chamber "<<(*(*missChamb)->chamber())<<
" is not in the chamber set");
456 return StatusCode::FAILURE;
461 std::vector<std::shared_ptr<Acts::Volume> > chamberBoundsVec;
462 chamberBoundsVec.reserve (chamberVec.size());
463 for (
const Chamber* ch : chamberVec)
464 chamberBoundsVec.push_back (ch->boundingVolume(gctx));
466 std::set<const Chamber*> overlapChambers{};
467 std::stringstream overlapstream{};
468 for (std::size_t chIdx = 0; chIdx< chamberVec.size(); ++chIdx) {
469 const Chamber& chamber{*chamberVec[chIdx]};
470 const Acts::Volume& chamberBounds = *chamberBoundsVec[chIdx];
472 saveEnvelope(gctx, std::format(
"Chamber_{:}{:}{:}{:}{:}",
473 chamber.detectorType(),
474 chName(chamber.chamberIndex()),
475 std::abs(chamber.stationEta()),
476 chamber.stationEta() > 0 ?
'A' :
'C',
477 chamber.stationPhi()),
478 chamberBounds, extractSurfaces(chamber.readoutEles()));
481 const std::vector<Amg::Vector3D> chambCorners =
cornerPoints(gctx, chamberBounds);
483 std::vector<const Chamber*> overlaps{};
484 for (std::size_t chIdx1 = 0; chIdx1<chamberVec.size(); ++chIdx1) {
485 if (chIdx == chIdx1) {
488 const Chamber* overlapTest{chamberVec[chIdx1]};
489 if (
hasOverlap(gctx, chambCorners, *chamberBoundsVec[chIdx1])) {
490 overlaps.push_back(overlapTest);
493 if (overlaps.empty()) {
496 overlapstream<<
"The chamber "<<chamber<<
" overlaps with "<<std::endl;
497 for (
const Chamber* itOverlaps : overlaps) {
498 overlapstream<<
" *** "<<(*itOverlaps)<<std::endl;
500 overlapstream<<std::endl<<std::endl;
501 overlapChambers.insert(overlaps.begin(), overlaps.end());
502 overlapChambers.insert(chamberVec[chIdx]);
504 if (!overlapChambers.empty()) {
505 Acts::ObjVisualization3D visualHelper{};
507 Acts::GeometryView3D::drawVolume(visualHelper, *
hasOverlap->boundingVolume(gctx), gctx.
context());
516 ATH_MSG_INFO(
"Chamber test completed. Found "<<overlapChambers.size()<<
" overlapping chambers");
517 return overlapChambers.empty() ||
m_ignoreOverlapCh ? StatusCode::SUCCESS : StatusCode::FAILURE;
522 std::vector<const MuonReadoutElement*> allREs =
m_detMgr->getAllReadoutElements();
524 if (!
re->msSector()) {
526 return StatusCode::FAILURE;
531 if (sectorFromDet !=
re->msSector()) {
534 <<
" is not the one attached to the readout geometry \n"<<(*
re->msSector())<<
"\n"<<(*sectorFromDet));
535 return StatusCode::FAILURE;
539 const SectorSet sectors =
m_detMgr->getAllSectors();
540 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Fetched "<<sectors.size()<<
" sectors. ");
543 const auto subVols = chamberVolumes(gctx, *sector);
545 chName(sector->chamberIndex()),
546 sector->side() >0?
'A' :
'C',
547 sector->stationPhi() ),
548 *sector->boundingVolume(gctx),
549 extractSurfaces(sector->readoutEles()),
550 Acts::unpackSmartPointers(subVols));
553 const std::shared_ptr<Acts::Volume> secVolume = sector->boundingVolume(gctx);
555 const std::vector<Amg::Vector3D> edges =
cornerPoints(gctx, *chamber->boundingVolume(gctx));
556 unsigned int edgeCount{0};
559 chamber->readoutEles().front()->identify()));
563 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Sector envelope test completed.");
564 return StatusCode::SUCCESS;
567 const Acts::TrackingVolume& volume)
const {
568 if (!volume.isAlignable()) {
569 return StatusCode::SUCCESS;
571 const Acts::GeometryContext geoCtx = gctx.
context();
572 std::vector<std::shared_ptr<const Acts::Surface>> portals{};
573 for (
const Acts::Portal& portal : volume.portals()) {
574 if (portal.surface().geometryId().withBoundary(0) != volume.geometryId()) {
577 portals.push_back(portal.surface().getSharedPtr());
579 const auto unAlignedPortals = volume.volumeBounds().orientedSurfaces(volume.localToGlobalTransform(geoCtx));
581 if (unAlignedPortals.size() != portals.size()) {
582 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The size of the aligned and unaligned portals don't match for volume "
583 <<volume.volumeName()<<
". Aligned: "<<portals.size()<<
", unaligned: "<<unAlignedPortals.size());
584 return StatusCode::FAILURE;
586 StatusCode retCode = StatusCode::SUCCESS;
587 for (std::size_t p =0 ; p < portals.size(); ++p){
589 if (portals[p]->bounds() != unAlignedPortals[p].surface->bounds()) {
590 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The bounds of the "<<p
591 <<
"-th portal differ:\n -- aligned: "<<portals[p]->bounds()
592 <<
"\n -- unaligned: "<<unAlignedPortals[p].surface->bounds());
593 retCode = StatusCode::FAILURE;
595 const Amg::Transform3D& uTrf{unAlignedPortals[p].surface->localToGlobalTransform(geoCtx)};
600 <<
" - The unaligned and aligned portals don't end up at the same point \n"
602 retCode = StatusCode::FAILURE;
610 const Acts::TrackingGeometry& trackingGeometry)
const {
614 std::vector<const Acts::TrackingVolume*> volumeVec{};
615 std::vector<const Acts::Surface*> passiveSurfaces{};
617 std::unordered_set<const Acts::TrackingVolume*> overlapVolumes{};
618 std::unordered_set<const Acts::Surface*> overlapSurfaces{};
622 trackingGeometry.visitVolumes([&](
const Acts::TrackingVolume* vol) {
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);
637 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Skip volume "
638 <<vol->volumeName()<<
".");
641 volumeVec.push_back(vol);
645 << passiveSurfaces.size()<<
" passive surfaces");
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());
652 visualHelper.write(
"MsTrackTest_passiveSurfaces.obj");
655 StatusCode retCode = StatusCode::SUCCESS;
656 for(std::size_t vIdx = 0; vIdx < volumeVec.size(); ++vIdx) {
657 const Acts::TrackingVolume* testVol{volumeVec.at(vIdx)};
660 std::vector<const Acts::TrackingVolume*> overlaps{};
661 const std::vector<Amg::Vector3D> edges =
cornerPoints(gctx, *testVol);
663 for(
const auto& surface : testVol->surfaces()) {
665 std::vector<Amg::Vector3D> surfEdges = {};
666 if(surface.type() == Acts::Surface::SurfaceType::Straw){
667 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__<<
" Checking "<<surface.type()<<
" surface "<<identify(surface)
668 <<
" / "<<surface.geometryId() <<
" in volume "<<testVol->volumeName());
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){
673 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__<<
" Checking "<<surface.type()<<
" surface "<<identify(surface)
674 <<
" / "<<surface.geometryId() <<
" in volume "<<testVol->volumeName());
676 auto edges =
cornerPoints(gctx,
dynamic_cast<const Acts::PlaneSurface&
>(surface));
677 surfEdges.insert(surfEdges.end() , edges.begin(), edges.end());
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;
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;
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;
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));
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){
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()));
744 const Identifier volId = identify(*extractSurfaces(*testVol).front());
745 double volHalfR{0.}, volHalfZ{0.};
756 const double rMin = center.perp() - volHalfR;
759 const double rMax = (testVol->localToGlobalTransform(gctx.
context()) *(
760 halfX * Amg::Vector3D::UnitX() +
761 volHalfR * Amg::Vector3D::Unit(1 +
isBarrel))).perp();
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());
774 for(std::size_t i = 0; i < passiveSurfaces.size(); ++i) {
776 const Acts::Surface* surf = passiveSurfaces[i];
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){
787 if (passiveZ < zMin || -passiveZ > zMax) {
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) {
796 const double surfRMax = bounds.get(BoundEnum::eMaxR);
797 const double surfRMin = bounds.get(BoundEnum::eMinR);
798 if (surfRMax < rMin || surfRMin > rMax){
803 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
804 <<
", "<< surf->name() <<
" is not a cylinder surface or disc");
805 return StatusCode::FAILURE;
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;
816 overlapSurfaces.insert(surf);
817 overlapVolumes.insert(testVol);
822 if(overlaps.empty()) {
823 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - No overlaps detected for the volume "<<testVol->volumeName());
827 overlapVolumes.insert(overlaps.begin(), overlaps.end());
828 overlapVolumes.insert(testVol);
830 std::stringstream overlapStream{};
831 overlapStream<<__func__<<
"() "<<__LINE__<<
" - The volume "
832 <<testVol->volumeName() <<
" overlaps with: "<<std::endl;
834 for(
const Acts::TrackingVolume* overlap: overlaps){
835 overlapStream<<
" --- Volume: " << overlap->volumeName()<<
", "<<overlap->volumeBounds()
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()){
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);
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;
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));
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;
883 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
884 <<
", "<< surf->name() <<
" is not a cylinder surface or disc");
885 return StatusCode::FAILURE;
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);
900 if(overlapVolumes.empty()) {
901 ATH_MSG_ALWAYS(
"No overlaps detected in the tracking geometry!!");
903 retCode = StatusCode::FAILURE;
909 const std::string& envName,
910 const Acts::Volume& envelopeVol,
911 const std::vector<const Acts::Surface*>& assocSurfaces,
912 const std::vector<const Acts::Volume*>& subVols)
const {
913 Acts::ObjVisualization3D visualHelper{};
914 std::ranges::for_each(assocSurfaces, [&visualHelper, &gctx](
const Acts::Surface* surface) {
915 Acts::GeometryView3D::drawSurface(visualHelper, *surface, gctx.
context());
918 std::ranges::for_each(subVols, [&visualHelper, &gctx](
const Acts::Volume* subVol) {
919 Acts::GeometryView3D::drawVolume(visualHelper,*subVol, gctx.
context(), Amg::Transform3D::Identity(),
920 Acts::s_viewPassive);
922 Acts::GeometryView3D::drawVolume(visualHelper, envelopeVol, gctx.
context());
923 ATH_MSG_DEBUG(
"Save new envelope 'MsTrackTest_"<<envName<<
".obj'");
924 visualHelper.write(std::format(
"MsTrackTest_{:}.obj", envName));
935 return StatusCode::SUCCESS;
937 template <
class EnvelopeType>
940 const EnvelopeType& chamber,
941 const Acts::Volume& detVol)
const {
944 for (
unsigned int layer = 1; layer <= mdtMl.
numLayers(); ++layer) {
945 for (
unsigned int tube = 1; tube <= mdtMl.
numTubesInLay(); ++tube) {
959 "bottom of the tube box", measId));
961 "sealing of the tube box", measId));
964 "wall to the previous tube", measId));
966 "wall to the next tube", measId));
969 return StatusCode::SUCCESS;
971 template<
class EnvelopeType>
974 const EnvelopeType& chamber,
975 const Acts::Volume& detVol)
const {
980 for (
unsigned int gasGap = 1 ; gasGap <= rpc.
nGasGaps(); ++gasGap) {
982 for (
bool measPhi : {
false,
true}) {
986 doubletPhi, gasGap, measPhi,
strip);
994 return StatusCode::SUCCESS;
996 template <
class EnevelopeType>
999 const EnevelopeType& chamber,
1000 const Acts::Volume& detVol)
const {
1001 for (
unsigned int gasGap = 1; gasGap <= tgc.
nGasGaps(); ++gasGap){
1002 for (
bool isStrip : {
false}) {
1004 const unsigned int nChannel = tgc.
numChannels(layHash);
1005 for (
unsigned int channel = 1; channel <= nChannel ; ++channel) {
1012 return StatusCode::SUCCESS;
1014 template <
class EnevelopeType>
1017 const EnevelopeType& chamber,
1018 const Acts::Volume& detVol)
const {
1021 for(
unsigned int gasGap = 1; gasGap <= mm.nGasGaps(); ++gasGap){
1023 unsigned int firstStrip = mm.firstStrip(gasGapHash);
1024 for(
unsigned int strip = firstStrip;
strip <= mm.numStrips(gasGapHash); ++
strip){
1026 ATH_CHECK(
pointInside(gctx, chamber, detVol, mm.stripPosition(gctx, stripId),
"center", stripId));
1027 ATH_CHECK(
pointInside(gctx, chamber, detVol, mm.leftStripEdge(gctx, mm.measurementHash(stripId)),
"left edge", stripId));
1028 ATH_CHECK(
pointInside(gctx, chamber, detVol, mm.rightStripEdge(gctx, mm.measurementHash(stripId)),
"right edge", stripId));
1032 return StatusCode::SUCCESS;
1034 template <
class EnvelopeType>
1037 const EnvelopeType& chamber,
1038 const Acts::Volume& detVol)
const{
1041 for(
unsigned int gasGap = 1; gasGap <= stgc.
numLayers(); ++gasGap){
1043 for(
unsigned int nch = 1; nch <= stgc.
nChTypes(); ++nch){
1045 const unsigned int nStrips = stgc.
numChannels(gasGapHash);
1060 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
Extension of the interface of the Acts::SurfacePlacementBase for ATLAS.
virtual Identifier identify() const =0
Return the ATLAS identifier of the surface.
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.
Identifier identify() const override final
Return the ATLAS identifier.
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &ctx) const override final
Returns the transformation from the local coordinate system of the readout element into the global AT...
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)
Rotate the coordinate system by an angle around the 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.