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;
48 std::vector<std::shared_ptr<const Acts::Volume>> vols{};
49 std::ranges::transform(sector.
chambers(),std::back_inserter(vols),
50 [](
const auto& ch){ return ch->boundingVolume(); });
53 std::vector<const Acts::Volume*> chamberVolumes(
const Acts::TrackingVolume& vol) {
54 std::vector<const Acts::Volume*> children {};
55 for (
const Acts::TrackingVolume& childVol : vol.volumes()) {
56 std::vector<const Acts::Volume*> grandChildren = chamberVolumes(childVol);
57 children.insert(children.end(), grandChildren.begin(), grandChildren.end());
62 std::vector<const Acts::Surface*> extractSurfaces(
const std::vector<const MuonGMR4::MuonReadoutElement*>& reEles){
63 std::vector<const Acts::Surface*> surfaces{};
64 for (
const auto*
re : reEles) {
65 std::ranges::transform(
re->getSurfaces(), std::back_inserter(surfaces),
66 [](
const std::shared_ptr<Acts::Surface>& surface) { return surface.get() ; });
71 std::vector<const Acts::Surface*> extractSurfaces(
const Acts::TrackingVolume& volume) {
72 std::vector<const Acts::Surface*> surfaces{};
73 std::ranges::for_each(volume.surfaces(), [&surfaces](
const Acts::Surface& surface){
74 if (surface.isSensitive()) {
75 surfaces.push_back(&surface);
78 for (
const Acts::TrackingVolume& subVol : volume.volumes()) {
79 std::vector<const Acts::Surface*> childSurfaces = extractSurfaces(subVol);
80 surfaces.insert(surfaces.end(), childSurfaces.begin(), childSurfaces.end());
91 bool checkOverlapWithCylinder(
const Acts::GeometryContext& gctx,
92 const Acts::Surface* testSurf,
96 if (testSurf->type() == Acts::Surface::SurfaceType::Cylinder) {
97 const auto& testBounds =
static_cast<const Acts::CylinderBounds&
>(testSurf->bounds());
98 using BoundEnum = Acts::CylinderBounds::BoundValues;
99 const double testR = testBounds.get(BoundEnum::eR);
100 const auto& testCenter = testSurf->center(gctx);
101 double dr = std::abs(testCenter.perp() - center.perp());
102 double dz = std::abs(testCenter.z() - center.z());
104 if (dr > testR + radius ||
105 (dr <= Acts::s_epsilon && std::abs(testR-radius) > Acts::s_epsilon) ||
106 (dz > halfZ + testBounds.get(BoundEnum::eHalfLengthZ))) {
109 }
else if (testSurf->type() == Acts::Surface::SurfaceType::Disc) {
111 using BoundEnum = Acts::RadialBounds::BoundValues;
112 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(testSurf->bounds());
113 const auto& testCenter = testSurf->center(gctx);
114 double dz = std::abs(testCenter.z() - center.z());
117 (dz < halfZ && bounds.get(BoundEnum::eMaxR) < (radius))) {
121 std::cerr <<
"Overlap check with surface type " << testSurf->type() <<
" is not implemented yet\n";
127 bool checkOverlapWithDisc(
const Acts::GeometryContext& gctx,
128 const Acts::Surface* testSurf,
130 if (testSurf->type() == Acts::Surface::SurfaceType::Cylinder) {
131 const auto& testBounds =
static_cast<const Acts::CylinderBounds&
>(testSurf->bounds());
132 using BoundEnum = Acts::CylinderBounds::BoundValues;
133 const double testR = testBounds.get(BoundEnum::eR);
134 const auto& testCenter = testSurf->center(gctx);
135 double dz = std::abs(testCenter.z() - center.z());
137 if (dz > testBounds.get(BoundEnum::eHalfLengthZ) ||
138 (dz < testBounds.get(BoundEnum::eHalfLengthZ) && radius < testR)) {
141 }
else if (testSurf->type() == Acts::Surface::SurfaceType::Disc) {
142 using BoundEnum = Acts::RadialBounds::BoundValues;
143 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(testSurf->bounds());
144 const auto& testCenter = testSurf->center(gctx);
145 double dz = std::abs(testCenter.z() - center.z());
146 double dr = std::abs(testCenter.perp() - center.perp());
148 if (dz > Acts::s_epsilon ||
149 dr > (radius+bounds.get(BoundEnum::eMaxR))){
153 std::cerr <<
"Overlap check with surface type " << testSurf->type() <<
" is not implemented yet\n";
167 return StatusCode::SUCCESS;
169 template <
class EnvelopeType>
170#if defined(FLATTEN) && defined(__GNUC__)
179 const EnvelopeType& chamb,
180 const Acts::Volume& boundVol,
182 const std::string& descr,
189 if (boundVol.volumeBounds().inside(locPos,
tolerance)) {
191 <<
", point "<<descr <<
" is inside of the chamber "<<std::endl<<chamb<<std::endl
193 return StatusCode::SUCCESS;
197 planeTrapezoid.
defineTrapezoid(chamb.halfXShort(), chamb.halfXLong(), chamb.halfY());
198 planeTrapezoid.
setLevel(MSG::VERBOSE);
200 static const Eigen::Rotation2D axisSwap{90. *Gaudi::Units::deg};
201 if (std::abs(locPos.z()) - chamb.halfZ() < -
tolerance &&
203 return StatusCode::SUCCESS;
207 << descr <<
" "<<
Amg::toString(point)<<
" is not part of the chamber volume."
208 <<std::endl<<std::endl<<chamb<<std::endl<<
"Local position "<<
Amg::toString(locPos)
209 <<
", "<<planeTrapezoid
212 return StatusCode::FAILURE;
216 const Acts::TrackingVolume& volume,
218 const std::string& descr,
221 return StatusCode::SUCCESS;
225 <<
" is not part of the chamber volume. The corners of the volume are:");
229 return StatusCode::FAILURE;
232 template <
class EnvelopeType>
234 const EnvelopeType& envelope)
const {
235 std::shared_ptr<Acts::Volume> boundVol = envelope.boundingVolume();
238 if constexpr (std::is_same_v<EnvelopeType, SpectrometerSector>) {
239 if (readOut->msSector() != &envelope) {
241 <<std::endl<<(*readOut->msSector())<<std::endl<<envelope);
242 return StatusCode::FAILURE;
244 }
else if constexpr (std::is_same_v<EnvelopeType, Chamber>) {
245 if (readOut->chamber() != &envelope) {
247 <<std::endl<<(*readOut->chamber())<<std::endl<<envelope);
248 return StatusCode::FAILURE;
251 switch (readOut->detectorType()) {
273 ATH_MSG_ERROR(
"Who came up with putting "<<readOut->detectorType()<<
" into the MS");
274 return StatusCode::FAILURE;
278 ATH_MSG_DEBUG(
"All "<<reEles.size()<<
" readout elements are embedded in "<<envelope);
279 return StatusCode::SUCCESS;
283 const Acts::Volume& volume)
const {
285 std::vector<Amg::Vector3D> edges{};
286 const Acts::VolumeBounds& bounds{volume.volumeBounds()};
287 const Acts::Transform3& trf{volume.localToGlobalTransform(gctx.
context())};
288 for (
const Acts::OrientedSurface& boundary : bounds.orientedSurfaces(trf)) {
289 std::vector<Amg::Vector3D> corners =
cornerPoints(gctx, *boundary.surface);
290 edges.insert(edges.end(), std::make_move_iterator(corners.begin()),
291 std::make_move_iterator(corners.end()));
294 return (
a - b).mag2() < 1._mm;
296 edges.erase(begin, end);
300 const Acts::Surface& surface)
const {
301 return surface.polyhedronRepresentation(gctx.
context(), 10).vertices;
303#if defined(FLATTEN) && defined(__GNUC__)
312 const std::vector<Amg::Vector3D>& chamberEdges,
313 const Acts::Volume& volume)
const {
317 double minDist = 1._km;
319 minDist = std::min(minDist, (edge - center).
mag());
323 if (std::ranges::none_of(volume.volumeBounds().values(),
324 [minDist](
const double bound){
325 return minDist < 2.5*bound;
331 const Acts::VolumeBounds& volBounds = volume.volumeBounds();
332 const Acts::Transform3& transform = volume.globalToLocalTransform(gctx.
context());
333 for (
unsigned edge1 = 1; edge1 < chamberEdges.size(); ++edge1) {
334 for (
unsigned edge2 = 0; edge2 < edge1; ++edge2) {
336 const double section = stepLength * step;
340 if (volBounds.inside (transform * testPoint)) {
350 std::vector<const MuonReadoutElement*> allRE =
m_detMgr->getAllReadoutElements();
353 ATH_MSG_INFO(
"Fetched "<<chambers.size()<<
" chambers.");
354 std::vector<const Chamber*> chamberVec{chambers.begin(), chambers.end()};
357 return std::ranges::find(chamberVec,
re->chamber()) == chamberVec.end();
359 if (missChamb != allRE.end()) {
360 ATH_MSG_ERROR(
"The chamber "<<(*(*missChamb)->chamber())<<
" is not in the chamber set");
361 return StatusCode::FAILURE;
366 std::vector<std::shared_ptr<Acts::Volume> > chamberBoundsVec;
367 chamberBoundsVec.reserve (chamberVec.size());
368 for (
const Chamber* ch : chamberVec) {
369 chamberBoundsVec.push_back(ch->boundingVolume());
371 std::set<const Chamber*> overlapChambers{};
372 std::stringstream overlapstream{};
373 for (std::size_t chIdx = 0; chIdx< chamberVec.size(); ++chIdx) {
374 const Chamber& chamber{*chamberVec[chIdx]};
375 const Acts::Volume& chamberBounds = *chamberBoundsVec[chIdx];
377 saveEnvelope(gctx, std::format(
"Chamber_{:}{:}{:}{:}{:}",
378 chamber.detectorType(),
379 chName(chamber.chamberIndex()),
380 std::abs(chamber.stationEta()),
381 chamber.stationEta() > 0 ?
'A' :
'C',
382 chamber.stationPhi()),
383 chamberBounds, extractSurfaces(chamber.readoutEles()));
386 const std::vector<Amg::Vector3D> chambCorners =
cornerPoints(gctx, chamberBounds);
388 std::vector<const Chamber*> overlaps{};
389 for (std::size_t chIdx1 = 0; chIdx1<chamberVec.size(); ++chIdx1) {
390 if (chIdx == chIdx1) {
393 const Chamber* overlapTest{chamberVec[chIdx1]};
394 if (
hasOverlap(gctx, chambCorners, *chamberBoundsVec[chIdx1])) {
395 overlaps.push_back(overlapTest);
398 if (overlaps.empty()) {
401 overlapstream<<
"The chamber "<<chamber<<
" overlaps with "<<std::endl;
402 for (
const Chamber* itOverlaps : overlaps) {
403 overlapstream<<
" *** "<<(*itOverlaps)<<std::endl;
405 overlapstream<<std::endl<<std::endl;
406 overlapChambers.insert(overlaps.begin(), overlaps.end());
407 overlapChambers.insert(chamberVec[chIdx]);
409 if (!overlapChambers.empty()) {
410 Acts::ObjVisualization3D visualHelper{};
412 Acts::GeometryView3D::drawVolume(visualHelper, *
hasOverlap->boundingVolume(), gctx.
context());
421 ATH_MSG_INFO(
"Chamber test completed. Found "<<overlapChambers.size()<<
" overlapping chambers");
422 return overlapChambers.empty() ||
m_ignoreOverlapCh ? StatusCode::SUCCESS : StatusCode::FAILURE;
427 std::vector<const MuonReadoutElement*> allREs =
m_detMgr->getAllReadoutElements();
429 if (!
re->msSector()) {
431 return StatusCode::FAILURE;
436 if (sectorFromDet !=
re->msSector()) {
439 <<
" is not the one attached to the readout geometry \n"<<(*
re->msSector())<<
"\n"<<(*sectorFromDet));
440 return StatusCode::FAILURE;
444 const SectorSet sectors =
m_detMgr->getAllSectors();
445 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Fetched "<<sectors.size()<<
" sectors. ");
448 const auto subVols = chamberVolumes(*sector);
450 chName(sector->chamberIndex()),
451 sector->side() >0?
'A' :
'C',
452 sector->stationPhi() ),
453 *sector->boundingVolume(),
454 extractSurfaces(sector->readoutEles()),
455 Acts::unpackSmartPointers(subVols));
458 const std::shared_ptr<Acts::Volume> secVolume = sector->boundingVolume();
460 const std::vector<Amg::Vector3D> edges =
cornerPoints(gctx, *chamber->boundingVolume());
461 unsigned int edgeCount{0};
464 chamber->readoutEles().front()->identify()));
468 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Sector envelope test completed.");
469 return StatusCode::SUCCESS;
472 const Acts::TrackingVolume& volume)
const {
473 if (!volume.isAlignable()) {
474 return StatusCode::SUCCESS;
476 const Acts::GeometryContext geoCtx = gctx.
context();
477 std::vector<std::shared_ptr<const Acts::Surface>> portals{};
478 for (
const Acts::Portal& portal : volume.portals()) {
479 if (portal.surface().geometryId().withBoundary(0) != volume.geometryId()) {
482 portals.push_back(portal.surface().getSharedPtr());
484 const auto unAlignedPortals = volume.volumeBounds().orientedSurfaces(volume.localToGlobalTransform(geoCtx));
486 if (unAlignedPortals.size() != portals.size()) {
487 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The size of the aligned and unaligned portals don't match for volume "
488 <<volume.volumeName()<<
". Aligned: "<<portals.size()<<
", unaligned: "<<unAlignedPortals.size());
489 return StatusCode::FAILURE;
491 StatusCode retCode = StatusCode::SUCCESS;
492 for (std::size_t p =0 ; p < portals.size(); ++p){
494 if (portals[p]->bounds() != unAlignedPortals[p].surface->bounds()) {
495 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The bounds of the "<<p
496 <<
"-th portal differ:\n -- aligned: "<<portals[p]->bounds()
497 <<
"\n -- unaligned: "<<unAlignedPortals[p].surface->bounds());
498 retCode = StatusCode::FAILURE;
500 const Amg::Transform3D& uTrf{unAlignedPortals[p].surface->localToGlobalTransform(geoCtx)};
505 <<
" - The unaligned and aligned portals don't end up at the same point \n"
507 retCode = StatusCode::FAILURE;
515 const Acts::TrackingGeometry& trackingGeometry)
const {
519 std::vector<const Acts::TrackingVolume*> volumeVec{};
520 std::vector<const Acts::Surface*> passiveSurfaces{};
522 std::unordered_set<const Acts::TrackingVolume*> overlapVolumes{};
523 std::unordered_set<const Acts::Surface*> overlapSurfaces{};
527 trackingGeometry.visitVolumes([&](
const Acts::TrackingVolume* vol) {
529 if(vol->volumeBounds().type() == Acts::VolumeBounds::BoundsType::eCylinder){
530 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Fetch "<<vol->surfaces().size()
531 <<
" passive surfaces from "<<vol->volumeName()<<
".");
532 std::ranges::for_each(vol->surfaces(), [&](
const Acts::Surface& surf){
533 ATH_MSG_VERBOSE(
" --- "<<surf.type()<<
" @"<<Amg::toString(surf.center(gctx.context()))
534 <<
" "<<surf.bounds());
535 passiveSurfaces.push_back(&surf);
542 ATH_MSG_DEBUG(
"checkTrackingGeometry() "<<__LINE__<<
" - Skip volume "
543 <<vol->volumeName()<<
".");
546 volumeVec.push_back(vol);
550 << passiveSurfaces.size()<<
" passive surfaces");
552 Acts::ObjVisualization3D visualHelper{};
553 std::ranges::for_each(passiveSurfaces,
554 [&visualHelper, &gctx](
const Acts::Surface* surface) {
555 Acts::GeometryView3D::drawSurface(visualHelper, *surface, gctx.
context());
557 visualHelper.write(
"MsTrackTest_passiveSurfaces.obj");
560 StatusCode retCode = StatusCode::SUCCESS;
561 for(std::size_t vIdx = 0; vIdx < volumeVec.size(); ++vIdx) {
562 const Acts::TrackingVolume* testVol{volumeVec.at(vIdx)};
565 std::vector<const Acts::TrackingVolume*> overlaps{};
566 const std::vector<Amg::Vector3D> edges =
cornerPoints(gctx, *testVol);
568 for(
const auto& surface : testVol->surfaces()) {
570 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__<<
" Checking "<<surface.type()<<
" surface "<<identify(surface)
571 <<
" / "<<surface.geometryId() <<
" in volume "<<testVol->volumeName());
573 if(!testVol->inside(gctx.
context(), edge, 0.01)) {
574 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The "<<surface.type()<<
"-surface "
576 <<surface.geometryId() <<
" @vertex point "
579 <<
" is outside the parent volume: " << testVol->volumeName()
581 <<
", "<<testVol->volumeBounds());
582 overlapSurfaces.insert(&surface);
583 overlapVolumes.insert(testVol);
585 retCode = StatusCode::FAILURE;
592 for (
const Acts::TrackingVolume& child : testVol->volumes()) {
594 if(!testVol->inside(gctx.
context(), edge, 0.01)){
595 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The children volume's "
596 << child.volumeName() <<
" vertex point " <<
Amg::toString(edge)
597 <<
" is outside the parent volume" << testVol->volumeName());
598 return StatusCode::FAILURE;
603 if (!testVol->motherVolume()->isAlignable() &&
m_dumpObjs) {
604 std::vector<const Acts::Surface*> surfaces = extractSurfaces(*testVol);
605 const Identifier volId = identify(*surfaces.front());
607 saveEnvelope(gctx, std::format(
"TrackingVolume_{:}{:}{:}{:}_{:}",
609 std::abs(
eta),
eta > 0 ?
'A' :
'C',
611 *testVol, surfaces , chamberVolumes(*testVol));
615 for (std::size_t vIdx1 = 0 ; vIdx1 < vIdx; ++vIdx1) {
616 const Acts::TrackingVolume* overlapTest{volumeVec.at(vIdx1)};
617 if (overlapTest->motherVolume() == testVol ||
618 testVol->motherVolume() == overlapTest){
622 overlaps.push_back(overlapTest);
623 std::ranges::copy(extractSurfaces(*testVol),
624 std::inserter(overlapSurfaces, overlapSurfaces.begin()));
625 std::ranges::copy(extractSurfaces(*overlapTest),
626 std::inserter(overlapSurfaces, overlapSurfaces.begin()));
631 const Identifier volId = identify(*extractSurfaces(*testVol).front());
632 double volHalfR{0.}, volHalfZ{0.};
643 const double rMin = center.perp() - volHalfR;
646 const double rMax = (testVol->localToGlobalTransform(gctx.
context()) *(
647 halfX * Amg::Vector3D::UnitX() +
648 volHalfR * Amg::Vector3D::Unit(1 +
isBarrel))).perp();
650 double zMin = center.z() - volHalfZ;
651 double zMax = center.z() + volHalfZ;
653 if (testVol->volumeBounds().type() == Acts::VolumeBounds::eDiamond) {
654 zMin = 1._km; zMax = -1._km;
656 zMin = std::min(zMin, p.z());
657 zMax = std::max(zMax, p.z());
661 for(std::size_t i = 0; i < passiveSurfaces.size(); ++i) {
663 const Acts::Surface* surf = passiveSurfaces[i];
666 if(surf->type() == Acts::Surface::SurfaceType::Cylinder) {
667 using BoundEnum = Acts::CylinderBounds::BoundValues;
668 const auto& bounds =
static_cast<const Acts::CylinderBounds&
>(surf->bounds());
669 const double passiveR = bounds.get(BoundEnum::eR);
670 const double passiveZ = bounds.get(BoundEnum:: eHalfLengthZ);
671 if (rMin < passiveR || rMax > passiveR){
674 if (passiveZ < zMin || -passiveZ > zMax) {
677 }
else if(surf->type() == Acts::Surface::SurfaceType::Disc){
678 using BoundEnum = Acts::RadialBounds::BoundValues;
679 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(surf->bounds());
680 if (center.z() < zMin || center.z() > zMax) {
683 const double surfRMax = bounds.get(BoundEnum::eMaxR);
684 const double surfRMin = bounds.get(BoundEnum::eMinR);
685 if (surfRMax < rMin || surfRMin > rMax){
690 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
691 <<
", "<< surf->name() <<
" is not a cylinder surface or disc");
692 return StatusCode::FAILURE;
696 << testVol->volumeName() <<
" overlaps with the surface "
697 << surf->name() <<
" with geo id" << surf->geometryId()
698 <<
" -- volume radius: ["<<rMin<<
";"<<rMax<<
"] z: ["<<zMin<<
";"<<zMax<<
"]"
699 <<
" "<<surf->bounds());
701 retCode = StatusCode::FAILURE;
703 overlapSurfaces.insert(surf);
704 overlapVolumes.insert(testVol);
709 if(overlaps.empty()) {
710 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - No overlaps detected for the volume "<<testVol->volumeName());
714 overlapVolumes.insert(overlaps.begin(), overlaps.end());
715 overlapVolumes.insert(testVol);
717 std::stringstream overlapStream{};
718 overlapStream<<__func__<<
"() "<<__LINE__<<
" - The volume "
719 <<testVol->volumeName() <<
" overlaps with: "<<std::endl;
721 for(
const Acts::TrackingVolume* overlap: overlaps){
722 overlapStream<<
" --- Volume: " << overlap->volumeName()<<
", "<<overlap->volumeBounds()
729 for(std::size_t i = 0; i < passiveSurfaces.size(); ++i) {
730 const Acts::Surface* surf = passiveSurfaces[i];
732 for(std::size_t j = i+1; j < passiveSurfaces.size(); ++j) {
733 const Acts::Surface* testSurf = passiveSurfaces[j];
734 ATH_MSG_INFO(__func__<<
"() "<<__LINE__<<
" - Checking passive surface "<<surf->name()<<
" geo id "<<surf->geometryId()
735 <<
" with passive surface "<<testSurf->name()<<
" geo id "<<testSurf->geometryId());
736 if(testSurf->geometryId().volume() != surf->geometryId().volume()){
739 if(surf->type() == Acts::Surface::SurfaceType::Cylinder){
740 using BoundEnum = Acts::CylinderBounds::BoundValues;
741 const auto& bounds =
static_cast<const Acts::CylinderBounds&
>(surf->bounds());
742 double passiveR = bounds.get(BoundEnum::eR);
743 double passiveZ = bounds.get(BoundEnum:: eHalfLengthZ);
744 bool overlap = checkOverlapWithCylinder(gctx.
context(), testSurf, center, passiveR, passiveZ);
746 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<<surf->name()<<
"geo id "<<surf->geometryId()
747 <<
" overlaps with surface "<<testSurf->name()<<
"geo id "<<testSurf->geometryId()
748 <<
" in the same volume "<<surf->geometryId().volume());
749 overlapSurfaces.insert(surf);
750 overlapSurfaces.insert(testSurf);
752 retCode = StatusCode::FAILURE;
755 }
else if(surf->type() == Acts::Surface::SurfaceType::Disc){
756 using BoundEnum = Acts::RadialBounds::BoundValues;
757 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(surf->bounds());
758 bool overlap = checkOverlapWithDisc(gctx.
context(), testSurf, center, bounds.get(BoundEnum::eMaxR));
760 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<<surf->name()<<
"geo id "<<surf->geometryId()
761 <<
" overlaps with surface "<<testSurf->name()<<
"geo id "<<testSurf->geometryId()
762 <<
" in the same volume "<<surf->geometryId().volume());
763 overlapSurfaces.insert(surf);
764 overlapSurfaces.insert(testSurf);
766 retCode = StatusCode::FAILURE;
770 ATH_MSG_ERROR(__func__<<
"() "<<__LINE__<<
" - The surface "<< surf->geometryId()
771 <<
", "<< surf->name() <<
" is not a cylinder surface or disc");
772 return StatusCode::FAILURE;
777 if (overlapVolumes.size() || overlapSurfaces.size()) {
778 const Acts::Volume* refVolume = (*overlapVolumes.begin());
779 std::vector<const Acts::Volume*> childVols{};
780 childVols.insert(childVols.begin(),std::next(overlapVolumes.begin()), overlapVolumes.end());
781 std::vector<const Acts::Surface*> childSurfs{overlapSurfaces.begin(), overlapSurfaces.end()};
782 saveEnvelope(gctx,
"TrackingGeometryOverlaps", *refVolume,
783 childSurfs, childVols);
787 if(overlapVolumes.empty()) {
788 ATH_MSG_ALWAYS(
"No overlaps detected in the tracking geometry!!");
790 retCode = StatusCode::FAILURE;
796 const std::string& envName,
797 const Acts::Volume& envelopeVol,
798 const std::vector<const Acts::Surface*>& assocSurfaces,
799 const std::vector<const Acts::Volume*>& subVols)
const {
800 Acts::ObjVisualization3D visualHelper{};
801 std::ranges::for_each(assocSurfaces, [&visualHelper, &gctx](
const Acts::Surface* surface) {
802 Acts::GeometryView3D::drawSurface(visualHelper, *surface, gctx.
context());
805 std::ranges::for_each(subVols, [&visualHelper, &gctx](
const Acts::Volume* subVol) {
806 Acts::GeometryView3D::drawVolume(visualHelper,*subVol, gctx.
context(), Amg::Isometry3D::Identity(),
807 Acts::s_viewPassive);
809 Acts::GeometryView3D::drawVolume(visualHelper, envelopeVol, gctx.
context());
810 ATH_MSG_DEBUG(
"Save new envelope 'MsTrackTest_"<<envName<<
".obj'");
811 visualHelper.write(std::format(
"MsTrackTest_{:}.obj", envName));
822 return StatusCode::SUCCESS;
824 template <
class EnvelopeType>
827 const EnvelopeType& chamber,
828 const Acts::Volume& detVol)
const {
831 for (
unsigned int layer = 1; layer <= mdtMl.
numLayers(); ++layer) {
832 for (
unsigned int tube = 1; tube <= mdtMl.
numTubesInLay(); ++tube) {
846 "bottom of the tube box", measId));
848 "sealing of the tube box", measId));
851 "wall to the previous tube", measId));
853 "wall to the next tube", measId));
856 return StatusCode::SUCCESS;
858 template<
class EnvelopeType>
861 const EnvelopeType& chamber,
862 const Acts::Volume& detVol)
const {
867 for (
unsigned int gasGap = 1 ; gasGap <= rpc.
nGasGaps(); ++gasGap) {
869 for (
bool measPhi : {
false,
true}) {
873 doubletPhi, gasGap, measPhi,
strip);
881 return StatusCode::SUCCESS;
883 template <
class EnevelopeType>
886 const EnevelopeType& chamber,
887 const Acts::Volume& detVol)
const {
888 for (
unsigned int gasGap = 1; gasGap <= tgc.
nGasGaps(); ++gasGap){
889 for (
bool isStrip : {
false}) {
891 const unsigned int nChannel = tgc.
numChannels(layHash);
892 for (
unsigned int channel = 1; channel <= nChannel ; ++channel) {
899 return StatusCode::SUCCESS;
901 template <
class EnevelopeType>
904 const EnevelopeType& chamber,
905 const Acts::Volume& detVol)
const {
908 for(
unsigned int gasGap = 1; gasGap <= mm.nGasGaps(); ++gasGap){
910 unsigned int firstStrip = mm.firstStrip(gasGapHash);
911 for(
unsigned int strip = firstStrip;
strip <= mm.numStrips(gasGapHash); ++
strip){
913 ATH_CHECK(
pointInside(gctx, chamber, detVol, mm.stripPosition(gctx, stripId),
"center", stripId));
914 ATH_CHECK(
pointInside(gctx, chamber, detVol, mm.leftStripEdge(gctx, mm.measurementHash(stripId)),
"left edge", stripId));
915 ATH_CHECK(
pointInside(gctx, chamber, detVol, mm.rightStripEdge(gctx, mm.measurementHash(stripId)),
"right edge", stripId));
919 return StatusCode::SUCCESS;
921 template <
class EnvelopeType>
924 const EnvelopeType& chamber,
925 const Acts::Volume& detVol)
const{
928 for(
unsigned int gasGap = 1; gasGap <= stgc.
numLayers(); ++gasGap){
930 for(
unsigned int nch = 1; nch <= stgc.
nChTypes(); ++nch){
932 const unsigned int nStrips = stgc.
numChannels(gasGapHash);
947 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
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.
const Amg::Isometry3D & localToGlobalTransform(const ActsTrk::GeometryContext &ctx) const override final
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.
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).
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.