ATLAS Offline Software
Loading...
Searching...
No Matches
MuonChamberToolTest.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#if defined(FLATTEN) && defined(__GNUC__)
6// Avoid warning in dbg build
7#pragma GCC optimize "-fno-var-tracking-assignments"
8#endif
9
10#include "MuonChamberToolTest.h"
11
19
21#include "GaudiKernel/SystemOfUnits.h"
22
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"
32
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"
39
41
42#include <format>
43
44using namespace Acts::UnitLiterals;
45using namespace Muon::MuonStationIndex;
46
47namespace{
48 constexpr double tolerance = 10. *Gaudi::Units::micrometer;
49
50 std::vector<std::shared_ptr<const Acts::Volume>> chamberVolumes(const MuonGMR4::SpectrometerSector& sector) {
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(); });
54 return vols;
55 }
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());
61 }
62 return children;
63 }
64
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());
70 }
71 return surfaces;
72 }
73
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);
79 }
80 });
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());
84 }
85 return surfaces;
86 }
87
88 Identifier identify(const Acts::Surface& surface) {
89 const auto* detEl = dynamic_cast<const ActsTrk::ISurfacePlacement*>(surface.surfacePlacement());
90 return detEl ? detEl->identify(): Identifier{};
91 }
92
93 bool checkOverlapWithCylinder(const Acts::GeometryContext& gctx,
94 const Acts::Surface* testSurf,
95 const Amg::Vector3D& center, double radius, double halfZ){
96
97 //cylinder-cylinder overlap check
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());
105 //the cylinders do not overlap
106 if (dr > testR + radius ||
107 (dr <= Acts::s_epsilon && std::abs(testR-radius) > Acts::s_epsilon) ||
108 (dz > halfZ + testBounds.get(BoundEnum::eHalfLengthZ))) {
109 return false;
110 }
111 } else if (testSurf->type() == Acts::Surface::SurfaceType::Disc) {
112 // Handle disc overlap logic
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());
117 //cylinder and disc do not overlap
118 if (dz > halfZ || (dz < halfZ && bounds.get(BoundEnum::eMaxR) < (radius))) {
119 return false;
120 }
121 } else {
122 std::cerr << "Overlap check with surface type " << testSurf->type() << " is not implemented yet\n";
123 return false;
124 }
125 return true;
126 }
127
128 bool checkOverlapWithDisc(const Acts::GeometryContext& gctx,
129 const Acts::Surface* testSurf,
130 const Amg::Vector3D& center, double radius){
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());
137 //the cylinder and the disc do not overlap
138 if (dz > testBounds.get(BoundEnum::eHalfLengthZ) ||
139 (dz < testBounds.get(BoundEnum::eHalfLengthZ) && radius < testR)) {
140 return false;
141 }
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());
148 //the discs do not overlap
149 if (dz > Acts::s_epsilon ||
150 dr > (radius+bounds.get(BoundEnum::eMaxR))){
151 return false;
152 }
153 } else {
154 std::cerr << "Overlap check with surface type " << testSurf->type() << " is not implemented yet\n";
155 return false;
156 }
157 return true;
158 }
159}
160
161namespace MuonGMR4 {
162
164 ATH_CHECK(m_idHelperSvc.retrieve());
165 ATH_CHECK(m_geoCtxKey.initialize());
166 ATH_CHECK(detStore()->retrieve(m_detMgr));
168 return StatusCode::SUCCESS;
169 }
170#if defined(FLATTEN) && defined(__GNUC__)
171// We compile this function with optimization, even in debug builds; otherwise,
172// the heavy use of Eigen makes it too slow. However, from here we may call
173// to out-of-line Eigen code that is linked from other DSOs; in that case,
174// it would not be optimized. Avoid this by forcing all Eigen code
175// to be inlined here if possible.
176[[gnu::flatten]]
177#endif
179 const Acts::Volume& boundVol,
180 const Amg::Vector3D& point,
181 const std::string& descr,
182 const Identifier& channelId) const {
183 // Explicitly inline Volume::inside here so that it gets
184 // flattened in debug builds. Gives a significant speedup.
185 //if (boundVol.inside(gctx.context(), point, tolerance)) {
186 const Amg::Vector3D locPos{boundVol.globalToLocalTransform(gctx.context()) * point};
187 const Acts::VolumeBounds& bounds{boundVol.volumeBounds()};
188 if (bounds.inside(locPos, tolerance)) {
189 ATH_MSG_VERBOSE("In channel "<<m_idHelperSvc->toString(channelId)
190 <<", point "<<descr <<" is inside of the chamber "
191 <<std::endl<<bounds<<std::endl
192 <<"Local position:" <<Amg::toString(locPos));
193 return StatusCode::SUCCESS;
194 }
195 ATH_MSG_ERROR("In channel "<<m_idHelperSvc->toString(channelId) <<", the point "
196 << descr <<" "<<Amg::toString(point)<<" is not part of the chamber volume."
197 <<std::endl<<bounds<<", local position "
198 <<Amg::toString(locPos));
199 const double shortX = MuonGMR4::halfXlowY(bounds);
200 const double longX = MuonGMR4::halfXhighY(bounds);
201 const double halfY = MuonGMR4::halfY(bounds);
202 const Amg::Vector3D dir = Amg::Vector3D {Acts::copySign(longX - shortX, locPos.x()),
203 2.*halfY,0.}.unit();
204 const Amg::Vector3D pos{Acts::copySign(shortX, locPos.x()), -halfY, 0.};
205
206 const Amg::Vector3D sameY = Acts::PlanarHelper::intersectPlane(pos, dir, Amg::Vector3D::UnitY(),
207 locPos.y()).position();
208 ATH_MSG_ALWAYS("Inclanation angle "<<Amg::toString(dir)<<", "<<dir.phi()<<", reference edge: "
209 <<Amg::toString(pos) <<", edge point: "<<Amg::toString(sameY));
210 return StatusCode::FAILURE;
211 }
212
214 const Chamber& envelope) const {
215 std::shared_ptr<Acts::Volume> boundVol = envelope.boundingVolume();
216 const Chamber::ReadoutSet reEles = envelope.readoutEles();
217 for(const MuonReadoutElement* readOut : reEles) {
218 if (readOut->chamber() != &envelope) {
219 ATH_MSG_ERROR("Mismatch in the chamber association "<<m_idHelperSvc->toStringDetEl(readOut->identify())
220 <<std::endl<<(*readOut->chamber())<<std::endl<<envelope);
221 return StatusCode::FAILURE;
222 }
223 switch (readOut->detectorType()) {
225 const auto* detEle = static_cast<const TgcReadoutElement*>(readOut);
226 ATH_CHECK(testReadoutEle(gctx, *detEle, *boundVol));
227 break;
229 const auto* detEle = static_cast<const MdtReadoutElement*>(readOut);
230 ATH_CHECK(testReadoutEle(gctx, *detEle, *boundVol));
231 break;
233 const auto* detEle = static_cast<const RpcReadoutElement*>(readOut);
234 ATH_CHECK(testReadoutEle(gctx, *detEle, *boundVol));
235 break;
237 const auto* detEle = static_cast<const MmReadoutElement*>(readOut);
238 ATH_CHECK(testReadoutEle(gctx, *detEle, *boundVol));
239 break;
241 const auto* detEle = static_cast<const sTgcReadoutElement*>(readOut);
242 ATH_CHECK(testReadoutEle(gctx, *detEle, *boundVol));
243 break;
244 } default: {
245 ATH_MSG_ERROR("Who came up with putting "<<readOut->detectorType()<<" into the MS");
246 return StatusCode::FAILURE;
247 }
248 }
249 ATH_CHECK(testReadoutSurfaces(gctx, *readOut, *boundVol));
250 }
251 ATH_MSG_DEBUG("All "<<reEles.size()<<" readout elements are embedded in "<<envelope);
252 return StatusCode::SUCCESS;
253 }
254
255 std::vector<Amg::Vector3D> MuonChamberToolTest::cornerPoints(const ActsTrk::GeometryContext& gctx,
256 const Acts::Volume& volume) const {
257
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()));
265 }
266 auto [begin, end] = std::ranges::unique(edges, [](const Amg::Vector3D& a, const Amg::Vector3D& b) {
267 return (a - b).mag2() < 1._mm;
268 });
269 edges.erase(begin, end);
270 return edges;
271 }
272 std::vector<Amg::Vector3D> MuonChamberToolTest::cornerPoints(const ActsTrk::GeometryContext& gctx,
273 const Acts::Surface& surface) const {
274 return surface.polyhedronRepresentation(gctx.context(), 10).vertices;
275 }
276#if defined(FLATTEN) && defined(__GNUC__)
277// We compile this function with optimization, even in debug builds; otherwise,
278// the heavy use of Eigen makes it too slow. However, from here we may call
279// to out-of-line Eigen code that is linked from other DSOs; in that case,
280// it would not be optimized. Avoid this by forcing all Eigen code
281// to be inlined here if possible.
282[[gnu::flatten]]
283#endif
285 const std::vector<Amg::Vector3D>& chamberEdges,
286 const Acts::Volume& volume) const {
287
289 const Amg::Vector3D center{volume.center(gctx.context())};
290 double minDist = 1._km;
291 for (const Amg::Vector3D& edge : chamberEdges) {
292 minDist = std::min(minDist, (edge - center).mag());
293 }
296 if (std::ranges::none_of(volume.volumeBounds().values(),
297 [minDist](const double bound){
298 return minDist < 2.5*bound;
299 })) {
300 return false;
301 }
302 const double stepLength = 1. / m_overlapSamples;
303
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) {
308 for (unsigned step = 0 ; step <= m_overlapSamples; ++step) {
309 const double section = stepLength * step;
310 const Amg::Vector3D testPoint = section* chamberEdges[edge1] + (1. -section) *chamberEdges[edge2];
311 // Using acts::Volume::inside is horribly slow in dbg builds.
312 // Using the bounds method directly is much faster.
313 if (volBounds.inside (transform * testPoint)) {
314 return true;
315 }
316 }
317 }
318 }
319 return false;
320 }
322
323 std::vector<const MuonReadoutElement*> allRE = m_detMgr->getAllReadoutElements();
325 const ChamberSet chambers = m_detMgr->getAllChambers();
326 ATH_MSG_INFO("Fetched "<<chambers.size()<<" chambers.");
327 std::vector<const Chamber*> chamberVec{chambers.begin(), chambers.end()};
328
329 const auto missChamb = std::ranges::find_if(allRE, [&chamberVec](const MuonGMR4::MuonReadoutElement* re){
330 return std::ranges::find(chamberVec, re->chamber()) == chamberVec.end();
331 });
332 if (missChamb != allRE.end()) {
333 ATH_MSG_ERROR("The chamber "<<(*(*missChamb)->chamber())<<" is not in the chamber set");
334 return StatusCode::FAILURE;
335 }
336
337 // Retrieve bounds here rather than inside the loop below,
338 // so we only need to do it O(N) rather than O(N^2) times.
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());
343 }
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];
349 if (m_dumpObjs) {
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()));
357 }
358 ATH_CHECK(allReadoutInEnvelope(gctx, chamber));
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) {
364 continue;
365 }
366 const Chamber* overlapTest{chamberVec[chIdx1]};
367 if (hasOverlap(gctx, chambCorners, *chamberBoundsVec[chIdx1])) {
368 overlaps.push_back(overlapTest);
369 }
370 }
371 if (overlaps.empty()) {
372 continue;
373 }
374 overlapstream<<"The chamber "<<chamber<<" overlaps with "<<std::endl;
375 for (const Chamber* itOverlaps : overlaps) {
376 overlapstream<<" *** "<<(*itOverlaps)<<std::endl;
377 }
378 overlapstream<<std::endl<<std::endl;
379 overlapChambers.insert(overlaps.begin(), overlaps.end());
380 overlapChambers.insert(chamberVec[chIdx]);
381 }
382 if (!overlapChambers.empty()) {
383 Acts::ObjVisualization3D visualHelper{};
384 for (const Chamber* hasOverlap: overlapChambers) {
385 Acts::GeometryView3D::drawVolume(visualHelper, *hasOverlap->boundingVolume(), gctx.context());
386 visualHelper.write(m_overlapChambObj.value());
387 }
388 if (m_ignoreOverlapCh) {
389 ATH_MSG_WARNING(overlapstream.str());
390 } else {
391 ATH_MSG_ERROR(overlapstream.str());
392 }
393 }
394 ATH_MSG_INFO("Chamber test completed. Found "<<overlapChambers.size()<<" overlapping chambers");
395 return overlapChambers.empty() || m_ignoreOverlapCh ? StatusCode::SUCCESS : StatusCode::FAILURE;
396 }
397
399
400 std::vector<const MuonReadoutElement*> allREs = m_detMgr->getAllReadoutElements();
401 using SectorSet = MuonDetectorManager::MuonSectorSet;
402 const SectorSet sectors = m_detMgr->getAllSectors();
403
404 for (const MuonReadoutElement* re : allREs) {
405 if (!re->msSector()) {
406 ATH_MSG_ERROR("The readout element "<<m_idHelperSvc->toStringDetEl(re->identify())<<" does not have any sector associated ");
407 return StatusCode::FAILURE;
408 }
409 const SpectrometerSector* sectorFromDet = m_detMgr->getSectorEnvelope(re->chamberIndex(),
410 m_idHelperSvc->sector(re->identify()),
411 re->stationEta());
412 if (sectorFromDet != re->msSector()) {
413 ATH_MSG_ERROR("The sector attached to "<<m_idHelperSvc->toStringDetEl(re->identify())
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;
417 }
418 if (!Acts::rangeContainsValue(sectors, sectorFromDet)){
419 ATH_MSG_ERROR("The sector "<<(*sectorFromDet)<<" is not part of the sector set");
420 return StatusCode::FAILURE;
421 }
422 }
423
424 ATH_MSG_INFO(__func__<<"() "<<__LINE__<<" - Fetched "<<sectors.size()<<" sectors. ");
425 for (const SpectrometerSector* sector : sectors) {
426 if (m_dumpObjs) {
427 const auto subVols = chamberVolumes(*sector);
428 saveEnvelope(gctx, std::format("Sector_{:}{:}{:}",
429 sector->chamberIndex(),
430 sector->side() >0? 'A' :'C',
431 sector->stationPhi() ),
432 *sector->boundingVolume(),
433 extractSurfaces(sector->readoutEles()),
434 Acts::unpackSmartPointers(subVols));
435 }
436 const std::shared_ptr<Acts::Volume> secVolume = sector->boundingVolume();
437 for (const SpectrometerSector::ChamberPtr& chamber : sector->chambers()){
438 for (const auto&[edgeCount, edge] :
439 Acts::enumerate(cornerPoints(gctx, *chamber->boundingVolume()))) {
440 ATH_CHECK(pointInside(gctx, *secVolume, edge, std::format("Edge {:}", edgeCount+1),
441 chamber->readoutEles().front()->identify()));
442 }
443 }
444 }
445 ATH_MSG_INFO(__func__<<"() "<<__LINE__<<" - Sector envelope test completed.");
446 return StatusCode::SUCCESS;
447 }
449 const Acts::TrackingVolume& volume) const {
450 if (!volume.isAlignable()) {
451 return StatusCode::SUCCESS;
452 }
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()) {
457 continue;
458 }
459 portals.push_back(portal.surface().getSharedPtr());
460 }
461 const auto unAlignedPortals = volume.volumeBounds().orientedSurfaces(volume.localToGlobalTransform(geoCtx));
462
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;
467 }
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;
476 }
477 const Acts::Transform3& uTrf{unAlignedPortals[p].surface->localToGlobalTransform(geoCtx)};
478 const Acts::Transform3& aTrf{portals[p]->localToGlobalTransform(geoCtx)};
479
480 if (!Amg::isIdentity(uTrf * aTrf.inverse())) {
481 ATH_MSG_ERROR(__func__<<"() "<<__LINE__
482 <<" - The unaligned and aligned portals don't end up at the same point \n"
483 <<" -- aligned: "<<Amg::toString(aTrf)<<"\n"<<" -- unaligned: "<<Amg::toString(uTrf));
484 retCode = StatusCode::FAILURE;
485 }
486 }
487 return retCode;
488 }
489
490
492 const Acts::TrackingGeometry& trackingGeometry) const {
493
494 //visit the volumes and check the overlaps with the other volumes in the tracking geometry
495 // also check overlaps between volumes and surfaces (e.g surfaces where the passive material is mapped)
496 std::vector<const Acts::TrackingVolume*> volumeVec{};
497 std::vector<const Acts::Surface*> passiveSurfaces{};
498
499 std::unordered_set<const Acts::TrackingVolume*> overlapVolumes{};
500 std::unordered_set<const Acts::Surface*> overlapSurfaces{};
501
502 //keep onyl the chamber volumes - not the cylinders
503 trackingGeometry.visitVolumes([&](const Acts::TrackingVolume* vol) {
504 //for the cylinder type volumes , fetch the inner surfaces only (e.g passive material surfaces)
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);
512 });
513 return;
514 }
515 const auto* placement = dynamic_cast<const ActsTrk::VolumePlacement*>(vol->volumePlacement());
516 // Not a senitive muon volume
517 if (!placement || !MuonGMR4::isMuon(placement->detectorType())) {
518 ATH_MSG_DEBUG("checkTrackingGeometry() "<<__LINE__<<" - Skip volume "
519 <<vol->volumeName()<<".");
520 return;
521 }
522 volumeVec.push_back(vol);
523 });
524
525 ATH_MSG_INFO(__func__<<"() "<<__LINE__<<" - Fetched "
526 << passiveSurfaces.size()<< " passive surfaces");
527 {
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());
532 });
533 visualHelper.write("MsTrackTest_passiveSurfaces.obj");
534
535 }
536 StatusCode retCode = StatusCode::SUCCESS;
537 for(std::size_t vIdx = 0; vIdx < volumeVec.size(); ++vIdx) {
538 const Acts::TrackingVolume* testVol{volumeVec.at(vIdx)};
539 ATH_CHECK(checkPortals(gctx, *testVol));
540
541 std::vector<const Acts::TrackingVolume*> overlaps{};
542 const std::vector<Amg::Vector3D> edges = cornerPoints(gctx, *testVol);
543
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());
547 for(const Amg::Vector3D& edge : cornerPoints(gctx, surface)) {
548 if(!testVol->inside(gctx.context(), edge, 0.01)) {
549 ATH_MSG_ERROR(__func__<<"() "<<__LINE__<<" - The "<<surface.type()<<"-surface "
550 << m_idHelperSvc->toString(identify(surface))<<" / "
551 <<surface.geometryId() <<" @vertex point "
552 <<Amg::toString(testVol->globalToLocalTransform(gctx.context()) *edge)<<", local: "
553 <<Amg::toString(surface.localToGlobalTransform(gctx.context()).inverse() * edge)
554 <<" is outside the parent volume: " << testVol->volumeName()
555 <<", "<<Amg::toString(testVol->localToGlobalTransform(gctx.context()))
556 <<", "<<testVol->volumeBounds());
557 overlapSurfaces.insert(&surface);
558 overlapVolumes.insert(testVol);
559 if (!m_ignoreOutsideSurf) {
560 retCode = StatusCode::FAILURE;
561 }
562 }
563 }
564 }
565
566 //check if the child volume is entirely enclosed by the mother volume
567 for (const Acts::TrackingVolume& child : testVol->volumes()) {
568 for(const auto& edge : cornerPoints(gctx, child)){
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;
574 }
575 }
576 }
578 if (!testVol->motherVolume()->isAlignable() && m_dumpObjs) {
579 std::vector<const Acts::Surface*> surfaces = extractSurfaces(*testVol);
580 const Identifier volId = identify(*surfaces.front());
581 const int eta = m_idHelperSvc->stationEta(volId);
582 saveEnvelope(gctx, std::format("TrackingVolume_{:}{:}{:}{:}_{:}",
583 m_idHelperSvc->chamberIndex(volId),
584 std::abs(eta), eta > 0 ? 'A' : 'C',
585 m_idHelperSvc->stationPhi(volId), vIdx),
586 *testVol, surfaces , chamberVolumes(*testVol));
587
588 }
589 // Check that there is not overlap with other volumes
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){
594 continue;
595 }
596 if (hasOverlap(gctx, edges, *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()));
602 }
603 }
604 /*check if the tracking volume overlaps with surfaces of the tracking geometry
605 (e.g cylinders of the barrel where material is mapped) */
606 const Identifier volId = identify(*extractSurfaces(*testVol).front());
607 double volHalfR{0.}, volHalfZ{0.};
608 const double halfX = MuonGMR4::halfXhighY(testVol->volumeBounds());
609 const bool isBarrel = Muon::MuonStationIndex::isBarrel(m_idHelperSvc->chamberIndex(volId));
610 if (isBarrel){
611 volHalfR = MuonGMR4::halfZ(testVol->volumeBounds());
612 volHalfZ = MuonGMR4::halfY(testVol->volumeBounds());
613 } else {
614 volHalfZ = MuonGMR4::halfZ(testVol->volumeBounds());
615 volHalfR = MuonGMR4::halfY(testVol->volumeBounds());
616 }
617 const Amg::Vector3D center{testVol->center(gctx.context())};
618 const double rMin = center.perp() - volHalfR;
619 // Calculate the global r from the local half X which is always along phi
620 // and the halfR which is along Y (Z) for endcap (barrel) chambers.
621 const double rMax = (testVol->localToGlobalTransform(gctx.context()) *(
622 halfX * Amg::Vector3D::UnitX() +
623 volHalfR * Amg::Vector3D::Unit(1 + isBarrel))).perp();
624
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;
630 for (const Amg::Vector3D& p : cornerPoints(gctx, *testVol)){
631 zMin = std::min(zMin, p.z());
632 zMax = std::max(zMax, p.z());
633 }
634 }
635
636 for(std::size_t i = 0; i < passiveSurfaces.size(); ++i) {
637
638 const Acts::Surface* surf = passiveSurfaces[i];
639
640 const Amg::Vector3D center = surf->center(gctx.context());
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){
647 continue;
648 }
649 if (passiveZ < zMin || -passiveZ > zMax) {
650 continue;
651 }
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) {
656 continue;
657 }
658 const double surfRMax = bounds.get(BoundEnum::eMaxR);
659 const double surfRMin = bounds.get(BoundEnum::eMinR);
660 if (surfRMax < rMin || surfRMin > rMax){
661 continue;
662 }
663 // continue;
664 } else {
665 ATH_MSG_ERROR(__func__<<"() "<<__LINE__<<" - The surface "<< surf->geometryId()
666 <<", "<< surf->name() <<" is not a cylinder surface or disc");
667 return StatusCode::FAILURE;
668 }
669
670 ATH_MSG_ERROR(__func__<<"() "<<__LINE__<<" - The volume "
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());
675 if (m_ignoreOutsideSurf) {
676 retCode = StatusCode::FAILURE;
677 }
678 overlapSurfaces.insert(surf);
679 overlapVolumes.insert(testVol);
680
681
682 }
683
684 if(overlaps.empty()) {
685 ATH_MSG_DEBUG(__func__<<"() "<<__LINE__<<" - No overlaps detected for the volume "<<testVol->volumeName());
686 continue;
687 }
688
689 overlapVolumes.insert(overlaps.begin(), overlaps.end());
690 overlapVolumes.insert(testVol);
691
692 std::stringstream overlapStream{};
693 overlapStream<<__func__<<"() "<<__LINE__<<" - The volume "
694 <<testVol->volumeName() << " overlaps with: "<<std::endl;
695
696 for(const Acts::TrackingVolume* overlap: overlaps){
697 overlapStream<<" --- Volume: " << overlap->volumeName()<<", "<<overlap->volumeBounds()
698 <<", "<<Amg::toString(overlap->localToGlobalTransform(gctx.context()))<<std::endl;;
699 }
700 ATH_MSG_ALWAYS(overlapStream.str());
701 }
702
703 //check passive surfaces overlaps with each other
704 for(std::size_t i = 0; i < passiveSurfaces.size(); ++i) {
705 const Acts::Surface* surf = passiveSurfaces[i];
706 const Amg::Vector3D center = surf->center(gctx.context());
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()){
712 continue;
713 }
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);
720 if(overlap) {
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);
726 if (!m_ignoreOutsideSurf) {
727 retCode = StatusCode::FAILURE;
728 }
729 }
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));
734 if(overlap) {
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);
740 if (!m_ignoreOutsideSurf) {
741 retCode = StatusCode::FAILURE;
742 }
743 }
744 } else {
745 ATH_MSG_ERROR(__func__<<"() "<<__LINE__<<" - The surface "<< surf->geometryId()
746 <<", "<< surf->name() <<" is not a cylinder surface or disc");
747 return StatusCode::FAILURE;
748 }
749 }
750 }
751
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);
759 }
760
761
762 if(overlapVolumes.empty()) {
763 ATH_MSG_ALWAYS("No overlaps detected in the tracking geometry!!");
764 } else if (!m_ignoreOverlapCh) {
765 retCode = StatusCode::FAILURE;
766 }
767 return retCode;
768 }
769
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());
778
779 });
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);
783 });
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));
787 }
788
789 StatusCode MuonChamberToolTest::execute(const EventContext& ctx) const {
790 const ActsTrk::GeometryContext* gctx{nullptr};
791 ATH_CHECK(SG::get(gctx, m_geoCtxKey, ctx));
794 ATH_CHECK(checkChambers(*gctx));
795 ATH_CHECK(checkTrackingGeometry(*gctx, *m_trackingGeometrySvc->trackingGeometry()));
796 return StatusCode::SUCCESS;
797 }
799 const MdtReadoutElement& mdtMl,
800 const Acts::Volume& detVol) const {
801 ATH_MSG_VERBOSE("Test whether "<<m_idHelperSvc->toStringDetEl(mdtMl.identify())<<std::endl<<mdtMl.getParameters());
802
803 for (unsigned int layer = 1; layer <= mdtMl.numLayers(); ++layer) {
804 for (unsigned int tube = 1; tube <= mdtMl.numTubesInLay(); ++tube) {
805 const IdentifierHash idHash = mdtMl.measurementHash(layer, tube);
806 if (!mdtMl.isValid(idHash)) {
807 continue;
808 }
809 const Acts::Transform3& locToGlob{mdtMl.localToGlobalTransform(gctx, idHash)};
810 const Identifier measId{mdtMl.measurementId(idHash)};
811
812 ATH_CHECK(pointInside(gctx, detVol, mdtMl.globalTubePos(gctx, idHash), "tube center", measId));
813
814 ATH_CHECK(pointInside(gctx, detVol, mdtMl.readOutPos(gctx, idHash), "tube readout", measId));
815 ATH_CHECK(pointInside(gctx, detVol, mdtMl.highVoltPos(gctx, idHash), "tube HV", measId));
816
817 ATH_CHECK(pointInside(gctx, detVol, locToGlob*(-mdtMl.innerTubeRadius() * Amg::Vector3D::UnitX()),
818 "bottom of the tube box", measId));
819 ATH_CHECK(pointInside(gctx, detVol, locToGlob*(mdtMl.innerTubeRadius() * Amg::Vector3D::UnitX()),
820 "sealing of the tube box", measId));
821
822 ATH_CHECK(pointInside(gctx, detVol, locToGlob*(-mdtMl.innerTubeRadius() * Amg::Vector3D::UnitY()),
823 "wall to the previous tube", measId));
824 ATH_CHECK(pointInside(gctx, detVol, locToGlob*(-mdtMl.innerTubeRadius() * Amg::Vector3D::UnitY()),
825 "wall to the next tube", measId));
826 }
827 }
828 return StatusCode::SUCCESS;
829 }
831 const MuonReadoutElement& element,
832 const Acts::Volume& boundVol) const {
833
834 const Acts::Transform3& invTrf{boundVol.globalToLocalTransform(gctx.context())};
835 for (const auto& surf : element.getSurfaces()) {
836 if(element.detectorType() == ActsTrk::DetectorType::Mdt &&
837 surf->type() != Acts::Surface::SurfaceType::Straw) {
838 continue;
839 }
840 if (surf->geometryId() == Acts::GeometryIdentifier{}) {
841 ATH_MSG_ERROR("The surface "<<surf->bounds()<<" is not part of the tracking geometry "
842 <<m_idHelperSvc->toString(identify(*surf)));
843 return StatusCode::FAILURE;
844 }
845 for (const Amg::Vector3D& vertex : cornerPoints(gctx, *surf)) {
846 const Amg::Vector3D lVertex = invTrf * vertex;
847 if (!boundVol.volumeBounds().inside(lVertex, tolerance)) {
848 ATH_MSG_ERROR("The vertex "<<Amg::toString(lVertex)<<" is outside of the bounds "
849 <<boundVol.volumeBounds()<<". The vertex belongs to "
850 <<m_idHelperSvc->toString(identify(*surf))<<"/"<<surf->geometryId());
851 return StatusCode::FAILURE;
852 }
853 }
854 }
855 return StatusCode::SUCCESS;
856 }
858 const RpcReadoutElement& rpc,
859 const Acts::Volume& detVol) const {
860
861 ATH_MSG_VERBOSE("Test whether "<<m_idHelperSvc->toStringDetEl(rpc.identify())<<std::endl
862 <<rpc.getParameters()<<" is contained in the envelope ");
863
864 const RpcIdHelper& idHelper{m_idHelperSvc->rpcIdHelper()};
865 for (unsigned int gasGap = 1 ; gasGap <= rpc.nGasGaps(); ++gasGap) {
866 for (int doubletPhi = rpc.doubletPhi(); doubletPhi <= rpc.doubletPhiMax(); ++doubletPhi){
867 for (bool measPhi : {false, true}) {
868 const int nStrips = measPhi ? rpc.nPhiStrips() : rpc.nEtaStrips();
869 for (int strip = 1; strip <= nStrips; ++strip) {
870 const Identifier stripId = idHelper.channelID(rpc.identify(),rpc.doubletZ(),
871 doubletPhi, gasGap, measPhi, strip);
872 ATH_CHECK(pointInside(gctx, detVol, rpc.stripPosition(gctx, stripId), "center", stripId));
873 ATH_CHECK(pointInside(gctx, detVol, rpc.leftStripEdge(gctx, stripId), "right edge", stripId));
874 ATH_CHECK(pointInside(gctx, detVol, rpc.rightStripEdge(gctx, stripId), "left edge", stripId));
875 }
876 }
877 }
878 }
879 return StatusCode::SUCCESS;
880 }
882 const TgcReadoutElement& tgc,
883 const Acts::Volume& detVol) const {
884 for (unsigned int gasGap = 1; gasGap <= tgc.nGasGaps(); ++gasGap){
885 for (bool isStrip : {false}) {
886 const IdentifierHash layHash = tgc.constructHash(0, gasGap, isStrip);
887 const unsigned int nChannel = tgc.numChannels(layHash);
888 for (unsigned int channel = 1; channel <= nChannel ; ++channel) {
889 const IdentifierHash measHash = tgc.constructHash(channel, gasGap, isStrip);
890 ATH_CHECK(pointInside(gctx, detVol, tgc.channelPosition(gctx, measHash),
891 "center", tgc.measurementId(measHash)));
892 }
893 }
894 }
895 return StatusCode::SUCCESS;
896 }
898 const MmReadoutElement& mm,
899 const Acts::Volume& detVol) const {
900
901 const MmIdHelper& idHelper{m_idHelperSvc->mmIdHelper()};
902 for(unsigned int gasGap = 1; gasGap <= mm.nGasGaps(); ++gasGap){
903 IdentifierHash gasGapHash = MmReadoutElement::createHash(gasGap,0);
904 unsigned int firstStrip = mm.firstStrip(gasGapHash);
905 for(unsigned int strip = firstStrip; strip <= mm.numStrips(gasGapHash); ++strip){
906 const Identifier stripId = idHelper.channelID(mm.identify(), mm.multilayer(), gasGap, strip);
907 ATH_CHECK(pointInside(gctx, detVol, mm.stripPosition(gctx, stripId), "center", stripId));
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));
910 }
911 }
912 return StatusCode::SUCCESS;
913 }
914
916 const sTgcReadoutElement& stgc,
917 const Acts::Volume& detVol) const{
918 const sTgcIdHelper& idHelper{m_idHelperSvc->stgcIdHelper()};
919 for(unsigned int gasGap = 1; gasGap <= stgc.numLayers(); ++gasGap) {
920
921 for(unsigned int nch = 1; nch <= stgc.nChTypes(); ++nch){
922 IdentifierHash gasGapHash = sTgcReadoutElement::createHash(gasGap, nch, 0, 0);
923 const unsigned int nStrips = stgc.numChannels(gasGapHash);
925
926 for(unsigned int strip = 1; strip <= nStrips; ++strip){
927 const Identifier stripId = idHelper.channelID(stgc.identify(), stgc.multilayer(), gasGap, nch, strip);
928 const IdentifierHash stripHash = stgc.measurementHash(stripId);
929 ATH_CHECK(pointInside(gctx, detVol, stgc.globalChannelPosition(gctx, stripHash), "channel position", stripId));
930
932 ATH_CHECK(pointInside(gctx, detVol, stgc.rightStripEdge(gctx, stripHash), "channel position", stripId));
933 ATH_CHECK(pointInside(gctx, detVol, stgc.leftStripEdge(gctx, stripHash), "channel position", stripId));
934 }
935 }
936 }
937 }
938 return StatusCode::SUCCESS;
939
940 }
941}
942
const std::regex re(r_e)
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,...)
static Double_t a
void section(const std::string &sec)
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.
Definition Chamber.h:29
const ReadoutSet & readoutEles() const
Returns the list of contained readout elements.
Definition Chamber.cxx:98
std::vector< const MuonReadoutElement * > ReadoutSet
Define the list of read out elements of the chamber.
Definition Chamber.h:32
std::shared_ptr< Acts::Volume > boundingVolume() const
Returns the Acts::Volume representation of the chamber.
Definition Chamber.cxx:82
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)
const MuonDetectorManager * m_detMgr
Gaudi::Property< bool > m_ignoreOverlapCh
The overlap of chamber volumes does not lead to a failure.
ActsTrk::GeoContextReadKey_t m_geoCtxKey
StatusCode checkEnvelopes(const ActsTrk::GeometryContext &gctx) const
Check envelopes.
StatusCode checkPortals(const ActsTrk::GeometryContext &gctx, const Acts::TrackingVolume &volume) const
StatusCode execute(const EventContext &ctx) const override
StatusCode checkChambers(const ActsTrk::GeometryContext &gctx) const
Check whether the chamber envelopes are consistent.
StatusCode pointInside(const ActsTrk::GeometryContext &gctx, const Acts::Volume &boundVol, const Amg::Vector3D &point, const std::string &descr, const Identifier &channelId) const
Checks whether the point is inside of an envelope object, i.e.
void saveEnvelope(const ActsTrk::GeometryContext &gctx, const std::string &envName, const Acts::Volume &envelopeVol, const std::vector< const Acts::Surface * > &assocSurfaces, const std::vector< const Acts::Volume * > &subVolumes={}) const
Gaudi::Property< bool > m_dumpObjs
Dump the chambers & sectors as separate obj files.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Gaudi::Property< std::string > m_overlapChambObj
Name of the chamber output obj file.
StatusCode allReadoutInEnvelope(const ActsTrk::GeometryContext &ctx, const Chamber &envelope) const
Checks whether the readout elements of an enevelope are completely embedded into the envelope.
StatusCode testReadoutSurfaces(const ActsTrk::GeometryContext &gctx, const MuonReadoutElement &element, const Acts::Volume &boundVol) const
Tests whether all surfaces defined by the readout element have a valid geometry identifier and whethe...
Gaudi::Property< unsigned > m_overlapSamples
Number of points to scan along the lines between two volume corners to check whether they belong to a...
StatusCode testReadoutEle(const ActsTrk::GeometryContext &gctx, const MdtReadoutElement &readOutEle, const Acts::Volume &boundVol) const
Checks whether all channels of a given readout element are fully covered by the envelope.
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
Gaudi::Property< bool > m_ignoreOutsideSurf
The exceeding surfaces does not lead to a failure.
StatusCode checkTrackingGeometry(const ActsTrk::GeometryContext &gctx, const Acts::TrackingGeometry &trackingGeometry) const
Check tracking geometry volumes.
std::vector< Amg::Vector3D > cornerPoints(const ActsTrk::GeometryContext &gctx, const Acts::Volume &volume) const
Returns the edge points from a trapezoidal / cuboid /diamond volume.
bool hasOverlap(const ActsTrk::GeometryContext &gctx, const std::vector< Amg::Vector3D > &chamberEdges, const Acts::Volume &volume) const
Checks whether the edge points from a trapezoid/cuboid/diamond form a volume overlapping with the giv...
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.
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.
@ sTgc
Micromegas (NSW).
@ Rpc
Monitored Drift Tubes.
@ Mdt
MuonSpectrometer.
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.