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"
36#include "Acts/Utilities/Helpers.hpp"
37#include "Acts/Utilities/Enumerate.hpp"
38#include "Acts/Surfaces/detail/PlanarHelper.hpp"
44using namespace Acts::UnitLiterals;
48 constexpr double tolerance = 10. *Gaudi::Units::micrometer;
51 std::vector<std::shared_ptr<const Acts::Volume>> vols{};
52 std::ranges::transform(sector.
chambers(),std::back_inserter(vols),
53 [](
const auto& ch){ return ch->boundingVolume(); });
56 std::vector<const Acts::Volume*> chamberVolumes(
const Acts::TrackingVolume& vol) {
57 std::vector<const Acts::Volume*> children {};
58 for (
const Acts::TrackingVolume& childVol : vol.volumes()) {
59 std::vector<const Acts::Volume*> grandChildren = chamberVolumes(childVol);
60 children.insert(children.end(), grandChildren.begin(), grandChildren.end());
65 std::vector<const Acts::Surface*> extractSurfaces(std::span<const MuonGMR4::MuonReadoutElement* const> reEles){
66 std::vector<const Acts::Surface*> surfaces{};
67 for (
const auto*
re : reEles) {
68 auto reSurfaces = Acts::unpackSmartPointers(
re->getSurfaces());
69 surfaces.insert(surfaces.end(), reSurfaces.begin(), reSurfaces.end());
74 std::vector<const Acts::Surface*> extractSurfaces(
const Acts::TrackingVolume& volume) {
75 std::vector<const Acts::Surface*> surfaces{};
76 std::ranges::for_each(volume.surfaces(), [&surfaces](
const Acts::Surface& surface){
77 if (surface.isSensitive()) {
78 surfaces.push_back(&surface);
81 for (
const Acts::TrackingVolume& subVol : volume.volumes()) {
82 std::vector<const Acts::Surface*> childSurfaces = extractSurfaces(subVol);
83 surfaces.insert(surfaces.end(), childSurfaces.begin(), childSurfaces.end());
93 bool checkOverlapWithCylinder(
const Acts::GeometryContext& gctx,
94 const Acts::Surface* testSurf,
98 if (testSurf->type() == Acts::Surface::SurfaceType::Cylinder) {
99 const auto& testBounds =
static_cast<const Acts::CylinderBounds&
>(testSurf->bounds());
100 using BoundEnum = Acts::CylinderBounds::BoundValues;
101 const double testR = testBounds.get(BoundEnum::eR);
102 const auto& testCenter = testSurf->center(gctx);
103 double dr = std::abs(testCenter.perp() - center.perp());
104 double dz = std::abs(testCenter.z() - center.z());
106 if (dr > testR + radius ||
107 (dr <= Acts::s_epsilon && std::abs(testR-radius) > Acts::s_epsilon) ||
108 (dz > halfZ + testBounds.get(BoundEnum::eHalfLengthZ))) {
111 }
else if (testSurf->type() == Acts::Surface::SurfaceType::Disc) {
113 using BoundEnum = Acts::RadialBounds::BoundValues;
114 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(testSurf->bounds());
115 const auto& testCenter = testSurf->center(gctx);
116 double dz = std::abs(testCenter.z() - center.z());
118 if (dz > halfZ || (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#if defined(FLATTEN) && defined(__GNUC__)
179 const Acts::Volume& boundVol,
181 const std::string& descr,
187 const Acts::VolumeBounds& bounds{boundVol.volumeBounds()};
190 <<
", point "<<descr <<
" is inside of the chamber "
191 <<std::endl<<bounds<<std::endl
193 return StatusCode::SUCCESS;
196 << descr <<
" "<<
Amg::toString(point)<<
" is not part of the chamber volume."
197 <<std::endl<<bounds<<
", local position "
206 const Amg::Vector3D sameY = Acts::PlanarHelper::intersectPlane(pos, dir, Amg::Vector3D::UnitY(),
207 locPos.y()).position();
210 return StatusCode::FAILURE;
214 const Chamber& envelope)
const {
215 std::shared_ptr<Acts::Volume> boundVol = envelope.
boundingVolume();
218 if (readOut->chamber() != &envelope) {
220 <<std::endl<<(*readOut->chamber())<<std::endl<<envelope);
221 return StatusCode::FAILURE;
223 switch (readOut->detectorType()) {
245 ATH_MSG_ERROR(
"Who came up with putting "<<readOut->detectorType()<<
" into the MS");
246 return StatusCode::FAILURE;
251 ATH_MSG_DEBUG(
"All "<<reEles.size()<<
" readout elements are embedded in "<<envelope);
252 return StatusCode::SUCCESS;
256 const Acts::Volume& volume)
const {
258 std::vector<Amg::Vector3D> edges{};
259 const Acts::VolumeBounds& bounds{volume.volumeBounds()};
260 const Acts::Transform3& trf{volume.localToGlobalTransform(gctx.
context())};
261 for (
const Acts::OrientedSurface& boundary : bounds.orientedSurfaces(trf)) {
262 std::vector<Amg::Vector3D> corners =
cornerPoints(gctx, *boundary.surface);
263 edges.insert(edges.end(), std::make_move_iterator(corners.begin()),
264 std::make_move_iterator(corners.end()));
267 return (
a - b).mag2() < 1._mm;
269 edges.erase(begin, end);
273 const Acts::Surface& surface)
const {
274 return surface.polyhedronRepresentation(gctx.
context(), 10).vertices;
276#if defined(FLATTEN) && defined(__GNUC__)
285 const std::vector<Amg::Vector3D>& chamberEdges,
286 const Acts::Volume& volume)
const {
290 double minDist = 1._km;
292 minDist = std::min(minDist, (edge - center).
mag());
296 if (std::ranges::none_of(volume.volumeBounds().values(),
297 [minDist](
const double bound){
298 return minDist < 2.5*bound;
304 const Acts::VolumeBounds& volBounds = volume.volumeBounds();
305 const Acts::Transform3& transform = volume.globalToLocalTransform(gctx.
context());
306 for (
unsigned edge1 = 1; edge1 < chamberEdges.size(); ++edge1) {
307 for (
unsigned edge2 = 0; edge2 < edge1; ++edge2) {
309 const double section = stepLength * step;
313 if (volBounds.inside (transform * testPoint)) {
323 std::vector<const MuonReadoutElement*> allRE =
m_detMgr->getAllReadoutElements();
326 ATH_MSG_INFO(
"Fetched "<<chambers.size()<<
" chambers.");
327 std::vector<const Chamber*> chamberVec{chambers.begin(), chambers.end()};
330 return std::ranges::find(chamberVec,
re->chamber()) == chamberVec.end();
332 if (missChamb != allRE.end()) {
333 ATH_MSG_ERROR(
"The chamber "<<(*(*missChamb)->chamber())<<
" is not in the chamber set");
334 return StatusCode::FAILURE;
339 std::vector<std::shared_ptr<Acts::Volume> > chamberBoundsVec;
340 chamberBoundsVec.reserve (chamberVec.size());
341 for (
const Chamber* ch : chamberVec) {
342 chamberBoundsVec.push_back(ch->boundingVolume());
344 std::set<const Chamber*> overlapChambers{};
345 std::stringstream overlapstream{};
346 for (std::size_t chIdx = 0; chIdx< chamberVec.size(); ++chIdx) {
347 const Chamber& chamber{*chamberVec[chIdx]};
348 const Acts::Volume& chamberBounds = *chamberBoundsVec[chIdx];
350 saveEnvelope(gctx, std::format(
"Chamber_{:}{:}{:}{:}{:}",
351 chamber.detectorType(),
352 chamber.chamberIndex(),
353 std::abs(chamber.stationEta()),
354 chamber.stationEta() > 0 ?
'A' :
'C',
355 chamber.stationPhi()),
356 chamberBounds, extractSurfaces(chamber.readoutEles()));
359 const std::vector<Amg::Vector3D> chambCorners =
cornerPoints(gctx, chamberBounds);
361 std::vector<const Chamber*> overlaps{};
362 for (std::size_t chIdx1 = 0; chIdx1<chamberVec.size(); ++chIdx1) {
363 if (chIdx == chIdx1) {
366 const Chamber* overlapTest{chamberVec[chIdx1]};
367 if (
hasOverlap(gctx, chambCorners, *chamberBoundsVec[chIdx1])) {
368 overlaps.push_back(overlapTest);
371 if (overlaps.empty()) {
374 overlapstream<<
"The chamber "<<chamber<<
" overlaps with "<<std::endl;
375 for (
const Chamber* itOverlaps : overlaps) {
376 overlapstream<<
" *** "<<(*itOverlaps)<<std::endl;
378 overlapstream<<std::endl<<std::endl;
379 overlapChambers.insert(overlaps.begin(), overlaps.end());
380 overlapChambers.insert(chamberVec[chIdx]);
382 if (!overlapChambers.empty()) {
383 Acts::ObjVisualization3D visualHelper{};
385 Acts::GeometryView3D::drawVolume(visualHelper, *
hasOverlap->boundingVolume(), gctx.
context());
394 ATH_MSG_INFO(
"Chamber test completed. Found "<<overlapChambers.size()<<
" overlapping chambers");
395 return overlapChambers.empty() ||
m_ignoreOverlapCh ? StatusCode::SUCCESS : StatusCode::FAILURE;
400 std::vector<const MuonReadoutElement*> allREs =
m_detMgr->getAllReadoutElements();
402 const SectorSet sectors =
m_detMgr->getAllSectors();
405 if (!
re->msSector()) {
407 return StatusCode::FAILURE;
412 if (sectorFromDet !=
re->msSector()) {
414 <<
", chIdx: "<<
re->chamberIndex()<<
", sector: "<<
m_idHelperSvc->sector(
re->identify())
415 <<
" is not the one attached to the readout geometry \n"<<(*
re->msSector())<<
"\n"<<(*sectorFromDet));
416 return StatusCode::FAILURE;
418 if (!Acts::rangeContainsValue(sectors, sectorFromDet)){
419 ATH_MSG_ERROR(
"The sector "<<(*sectorFromDet)<<
" is not part of the sector set");
420 return StatusCode::FAILURE;
424 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Fetched "<<sectors.size()<<
" sectors. ");
427 const auto subVols = chamberVolumes(*sector);
429 sector->chamberIndex(),
430 sector->side() >0?
'A' :
'C',
431 sector->stationPhi() ),
432 *sector->boundingVolume(),
433 extractSurfaces(sector->readoutEles()),
434 Acts::unpackSmartPointers(subVols));
436 const std::shared_ptr<Acts::Volume> secVolume = sector->boundingVolume();
438 for (
const auto&[edgeCount, edge] :
439 Acts::enumerate(
cornerPoints(gctx, *chamber->boundingVolume()))) {
441 chamber->readoutEles().front()->identify()));
445 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Sector envelope test completed.");
446 return StatusCode::SUCCESS;
449 const Acts::TrackingVolume& volume)
const {
450 if (!volume.isAlignable()) {
451 return StatusCode::SUCCESS;
453 const Acts::GeometryContext geoCtx = gctx.
context();
454 std::vector<std::shared_ptr<const Acts::Surface>> portals{};
455 for (
const Acts::Portal& portal : volume.portals()) {
456 if (portal.surface().geometryId().withBoundary(0) != volume.geometryId()) {
459 portals.push_back(portal.surface().getSharedPtr());
461 const auto unAlignedPortals = volume.volumeBounds().orientedSurfaces(volume.localToGlobalTransform(geoCtx));
463 if (unAlignedPortals.size() != portals.size()) {
464 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The size of the aligned and unaligned portals don't match for volume "
465 <<volume.volumeName()<<
". Aligned: "<<portals.size()<<
", unaligned: "<<unAlignedPortals.size());
466 return StatusCode::FAILURE;
468 StatusCode retCode = StatusCode::SUCCESS;
469 for (std::size_t p =0 ; p < portals.size(); ++p){
471 if (portals[p]->bounds() != unAlignedPortals[p].surface->bounds()) {
472 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The bounds of the "<<p
473 <<
"-th portal differ:\n -- aligned: "<<portals[p]->bounds()
474 <<
"\n -- unaligned: "<<unAlignedPortals[p].surface->bounds());
475 retCode = StatusCode::FAILURE;
477 const Acts::Transform3& uTrf{unAlignedPortals[p].surface->localToGlobalTransform(geoCtx)};
478 const Acts::Transform3& aTrf{portals[p]->localToGlobalTransform(geoCtx)};
482 <<
" - The unaligned and aligned portals don't end up at the same point \n"
484 retCode = StatusCode::FAILURE;
492 const Acts::TrackingGeometry& trackingGeometry)
const {
496 std::vector<const Acts::TrackingVolume*> volumeVec{};
497 std::vector<const Acts::Surface*> passiveSurfaces{};
499 std::unordered_set<const Acts::TrackingVolume*> overlapVolumes{};
500 std::unordered_set<const Acts::Surface*> overlapSurfaces{};
503 trackingGeometry.visitVolumes([&](
const Acts::TrackingVolume* vol) {
505 if(vol->volumeBounds().type() == Acts::VolumeBounds::BoundsType::eCylinder){
506 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Fetch "<<vol->surfaces().size()
507 <<
" passive surfaces from "<<vol->volumeName()<<
".");
508 std::ranges::for_each(vol->surfaces(), [&](
const Acts::Surface& surf){
509 ATH_MSG_VERBOSE(
" --- "<<surf.type()<<
" @"<<Amg::toString(surf.center(gctx.context()))
510 <<
" "<<surf.bounds());
511 passiveSurfaces.push_back(&surf);
518 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Skip volume "
519 <<vol->volumeName()<<
".");
522 volumeVec.push_back(vol);
526 << passiveSurfaces.size()<<
" passive surfaces");
528 Acts::ObjVisualization3D visualHelper{};
529 std::ranges::for_each(passiveSurfaces,
530 [&visualHelper, &gctx](
const Acts::Surface* surface) {
531 Acts::GeometryView3D::drawSurface(visualHelper, *surface, gctx.
context());
533 visualHelper.write(
"MsTrackTest_passiveSurfaces.obj");
536 StatusCode retCode = StatusCode::SUCCESS;
537 for(std::size_t vIdx = 0; vIdx < volumeVec.size(); ++vIdx) {
538 const Acts::TrackingVolume* testVol{volumeVec.at(vIdx)};
541 std::vector<const Acts::TrackingVolume*> overlaps{};
542 const std::vector<Amg::Vector3D> edges =
cornerPoints(gctx, *testVol);
544 for(
const auto& surface : testVol->surfaces()) {
545 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__<<
" Checking "<<surface.type()<<
" surface "<<identify(surface)
546 <<
" / "<<surface.geometryId() <<
" in volume "<<testVol->volumeName());
548 if(!testVol->inside(gctx.
context(), edge, 0.01)) {
549 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The "<<surface.type()<<
"-surface "
551 <<surface.geometryId() <<
" @vertex point "
554 <<
" is outside the parent volume: " << testVol->volumeName()
556 <<
", "<<testVol->volumeBounds());
557 overlapSurfaces.insert(&surface);
558 overlapVolumes.insert(testVol);
560 retCode = StatusCode::FAILURE;
567 for (
const Acts::TrackingVolume& child : testVol->volumes()) {
569 if(!testVol->inside(gctx.
context(), edge, 0.01)){
570 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The children volume's "
571 << child.volumeName() <<
" vertex point " <<
Amg::toString(edge)
572 <<
" is outside the parent volume" << testVol->volumeName());
573 return StatusCode::FAILURE;
578 if (!testVol->motherVolume()->isAlignable() &&
m_dumpObjs) {
579 std::vector<const Acts::Surface*> surfaces = extractSurfaces(*testVol);
580 const Identifier volId = identify(*surfaces.front());
582 saveEnvelope(gctx, std::format(
"TrackingVolume_{:}{:}{:}{:}_{:}",
584 std::abs(
eta),
eta > 0 ?
'A' :
'C',
586 *testVol, surfaces , chamberVolumes(*testVol));
590 for (std::size_t vIdx1 = 0 ; vIdx1 < vIdx; ++vIdx1) {
591 const Acts::TrackingVolume* overlapTest{volumeVec.at(vIdx1)};
592 if (overlapTest->motherVolume() == testVol ||
593 testVol->motherVolume() == overlapTest){
597 overlaps.push_back(overlapTest);
598 std::ranges::copy(extractSurfaces(*testVol),
599 std::inserter(overlapSurfaces, overlapSurfaces.begin()));
600 std::ranges::copy(extractSurfaces(*overlapTest),
601 std::inserter(overlapSurfaces, overlapSurfaces.begin()));
606 const Identifier volId = identify(*extractSurfaces(*testVol).front());
607 double volHalfR{0.}, volHalfZ{0.};
618 const double rMin = center.perp() - volHalfR;
621 const double rMax = (testVol->localToGlobalTransform(gctx.
context()) *(
622 halfX * Amg::Vector3D::UnitX() +
623 volHalfR * Amg::Vector3D::Unit(1 +
isBarrel))).perp();
625 double zMin = center.z() - volHalfZ;
626 double zMax = center.z() + volHalfZ;
628 if (testVol->volumeBounds().type() == Acts::VolumeBounds::eDiamond) {
629 zMin = 1._km; zMax = -1._km;
631 zMin = std::min(zMin, p.z());
632 zMax = std::max(zMax, p.z());
636 for(std::size_t i = 0; i < passiveSurfaces.size(); ++i) {
638 const Acts::Surface* surf = passiveSurfaces[i];
641 if(surf->type() == Acts::Surface::SurfaceType::Cylinder) {
642 using BoundEnum = Acts::CylinderBounds::BoundValues;
643 const auto& bounds =
static_cast<const Acts::CylinderBounds&
>(surf->bounds());
644 const double passiveR = bounds.get(BoundEnum::eR);
645 const double passiveZ = bounds.get(BoundEnum:: eHalfLengthZ);
646 if (rMin < passiveR || rMax > passiveR){
649 if (passiveZ < zMin || -passiveZ > zMax) {
652 }
else if(surf->type() == Acts::Surface::SurfaceType::Disc){
653 using BoundEnum = Acts::RadialBounds::BoundValues;
654 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(surf->bounds());
655 if (center.z() < zMin || center.z() > zMax) {
658 const double surfRMax = bounds.get(BoundEnum::eMaxR);
659 const double surfRMin = bounds.get(BoundEnum::eMinR);
660 if (surfRMax < rMin || surfRMin > rMax){
665 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
666 <<
", "<< surf->name() <<
" is not a cylinder surface or disc");
667 return StatusCode::FAILURE;
671 << testVol->volumeName() <<
" overlaps with the surface "
672 << surf->name() <<
" with geo id" << surf->geometryId()
673 <<
" -- volume radius: ["<<rMin<<
";"<<rMax<<
"] z: ["<<zMin<<
";"<<zMax<<
"]"
674 <<
" "<<surf->bounds());
676 retCode = StatusCode::FAILURE;
678 overlapSurfaces.insert(surf);
679 overlapVolumes.insert(testVol);
684 if(overlaps.empty()) {
685 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - No overlaps detected for the volume "<<testVol->volumeName());
689 overlapVolumes.insert(overlaps.begin(), overlaps.end());
690 overlapVolumes.insert(testVol);
692 std::stringstream overlapStream{};
693 overlapStream<<__func__<<
"() "<<__LINE__<<
" - The volume "
694 <<testVol->volumeName() <<
" overlaps with: "<<std::endl;
696 for(
const Acts::TrackingVolume* overlap: overlaps){
697 overlapStream<<
" --- Volume: " << overlap->volumeName()<<
", "<<overlap->volumeBounds()
704 for(std::size_t i = 0; i < passiveSurfaces.size(); ++i) {
705 const Acts::Surface* surf = passiveSurfaces[i];
707 for(std::size_t j = i+1; j < passiveSurfaces.size(); ++j) {
708 const Acts::Surface* testSurf = passiveSurfaces[j];
709 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Checking passive surface "<<surf->name()<<
" geo id "<<surf->geometryId()
710 <<
" with passive surface "<<testSurf->name()<<
" geo id "<<testSurf->geometryId());
711 if(testSurf->geometryId().volume() != surf->geometryId().volume()){
714 if(surf->type() == Acts::Surface::SurfaceType::Cylinder){
715 using BoundEnum = Acts::CylinderBounds::BoundValues;
716 const auto& bounds =
static_cast<const Acts::CylinderBounds&
>(surf->bounds());
717 double passiveR = bounds.get(BoundEnum::eR);
718 double passiveZ = bounds.get(BoundEnum:: eHalfLengthZ);
719 bool overlap = checkOverlapWithCylinder(gctx.
context(), testSurf, center, passiveR, passiveZ);
721 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<<surf->name()<<
"geo id "<<surf->geometryId()
722 <<
" overlaps with surface "<<testSurf->name()<<
"geo id "<<testSurf->geometryId()
723 <<
" in the same volume "<<surf->geometryId().volume());
724 overlapSurfaces.insert(surf);
725 overlapSurfaces.insert(testSurf);
727 retCode = StatusCode::FAILURE;
730 }
else if(surf->type() == Acts::Surface::SurfaceType::Disc){
731 using BoundEnum = Acts::RadialBounds::BoundValues;
732 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(surf->bounds());
733 bool overlap = checkOverlapWithDisc(gctx.
context(), testSurf, center, bounds.get(BoundEnum::eMaxR));
735 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<<surf->name()<<
"geo id "<<surf->geometryId()
736 <<
" overlaps with surface "<<testSurf->name()<<
"geo id "<<testSurf->geometryId()
737 <<
" in the same volume "<<surf->geometryId().volume());
738 overlapSurfaces.insert(surf);
739 overlapSurfaces.insert(testSurf);
741 retCode = StatusCode::FAILURE;
745 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
746 <<
", "<< surf->name() <<
" is not a cylinder surface or disc");
747 return StatusCode::FAILURE;
752 if (overlapVolumes.size() || overlapSurfaces.size()) {
753 const Acts::Volume* refVolume = (*overlapVolumes.begin());
754 std::vector<const Acts::Volume*> childVols{};
755 childVols.insert(childVols.begin(),std::next(overlapVolumes.begin()), overlapVolumes.end());
756 std::vector<const Acts::Surface*> childSurfs{overlapSurfaces.begin(), overlapSurfaces.end()};
757 saveEnvelope(gctx,
"TrackingGeometryOverlaps", *refVolume,
758 childSurfs, childVols);
762 if(overlapVolumes.empty()) {
763 ATH_MSG_ALWAYS(
"No overlaps detected in the tracking geometry!!");
765 retCode = StatusCode::FAILURE;
771 const std::string& envName,
772 const Acts::Volume& envelopeVol,
773 const std::vector<const Acts::Surface*>& assocSurfaces,
774 const std::vector<const Acts::Volume*>& subVols)
const {
775 Acts::ObjVisualization3D visualHelper{};
776 std::ranges::for_each(assocSurfaces, [&visualHelper, &gctx](
const Acts::Surface* surface) {
777 Acts::GeometryView3D::drawSurface(visualHelper, *surface, gctx.
context());
780 std::ranges::for_each(subVols, [&visualHelper, &gctx](
const Acts::Volume* subVol) {
781 Acts::GeometryView3D::drawVolume(visualHelper,*subVol, gctx.
context(), Acts::Transform3::Identity(),
782 Acts::s_viewPassive);
784 Acts::GeometryView3D::drawVolume(visualHelper, envelopeVol, gctx.
context());
785 ATH_MSG_DEBUG(
"Save new envelope 'ChamberGeoTest_"<<envName<<
".obj'");
786 visualHelper.write(std::format(
"ChamberGeoTest_{:}.obj", envName));
796 return StatusCode::SUCCESS;
800 const Acts::Volume& detVol)
const {
803 for (
unsigned int layer = 1; layer <= mdtMl.
numLayers(); ++layer) {
804 for (
unsigned int tube = 1; tube <= mdtMl.
numTubesInLay(); ++tube) {
818 "bottom of the tube box", measId));
820 "sealing of the tube box", measId));
823 "wall to the previous tube", measId));
825 "wall to the next tube", measId));
828 return StatusCode::SUCCESS;
832 const Acts::Volume& boundVol)
const {
834 const Acts::Transform3& invTrf{boundVol.globalToLocalTransform(gctx.
context())};
837 surf->type() != Acts::Surface::SurfaceType::Straw) {
840 if (surf->geometryId() == Acts::GeometryIdentifier{}) {
841 ATH_MSG_ERROR(
"The surface "<<surf->bounds()<<
" is not part of the tracking geometry "
843 return StatusCode::FAILURE;
847 if (!boundVol.volumeBounds().inside(lVertex,
tolerance)) {
849 <<boundVol.volumeBounds()<<
". The vertex belongs to "
850 <<
m_idHelperSvc->toString(identify(*surf))<<
"/"<<surf->geometryId());
851 return StatusCode::FAILURE;
855 return StatusCode::SUCCESS;
859 const Acts::Volume& detVol)
const {
865 for (
unsigned int gasGap = 1 ; gasGap <= rpc.
nGasGaps(); ++gasGap) {
867 for (
bool measPhi : {
false,
true}) {
871 doubletPhi, gasGap, measPhi,
strip);
879 return StatusCode::SUCCESS;
883 const Acts::Volume& detVol)
const {
884 for (
unsigned int gasGap = 1; gasGap <= tgc.
nGasGaps(); ++gasGap){
885 for (
bool isStrip : {
false}) {
887 const unsigned int nChannel = tgc.
numChannels(layHash);
888 for (
unsigned int channel = 1; channel <= nChannel ; ++channel) {
895 return StatusCode::SUCCESS;
899 const Acts::Volume& detVol)
const {
902 for(
unsigned int gasGap = 1; gasGap <= mm.nGasGaps(); ++gasGap){
904 unsigned int firstStrip = mm.firstStrip(gasGapHash);
905 for(
unsigned int strip = firstStrip;
strip <= mm.numStrips(gasGapHash); ++
strip){
908 ATH_CHECK(
pointInside(gctx, detVol, mm.leftStripEdge(gctx, mm.measurementHash(stripId)),
"left edge", stripId));
909 ATH_CHECK(
pointInside(gctx, detVol, mm.rightStripEdge(gctx, mm.measurementHash(stripId)),
"right edge", stripId));
912 return StatusCode::SUCCESS;
917 const Acts::Volume& detVol)
const{
919 for(
unsigned int gasGap = 1; gasGap <= stgc.
numLayers(); ++gasGap) {
921 for(
unsigned int nch = 1; nch <= stgc.
nChTypes(); ++nch){
923 const unsigned int nStrips = stgc.
numChannels(gasGapHash);
938 return StatusCode::SUCCESS;
Scalar eta() const
pseudorapidity method
Scalar mag() const
mag method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_ALWAYS(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
Acts::GeometryContext context() const
virtual DetectorType detectorType() const =0
Returns the detector element type.
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
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.
const ReadoutSet & readoutEles() const
Returns the list of contained readout elements.
std::vector< const MuonReadoutElement * > ReadoutSet
Define the list of read out elements of the chamber.
std::shared_ptr< Acts::Volume > boundingVolume() const
Returns the Acts::Volume representation 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.
std::vector< std::shared_ptr< Acts::Surface > > getSurfaces() const
Returns all surfaces that are associated with the active readout planes.
Identifier identify() const override final
Return the ATLAS identifier.
const Acts::Transform3 & 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
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.
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 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.