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#include <GaudiKernel/SystemOfUnits.h>
20
21#include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
22#include "Acts/Geometry/TrackingGeometry.hpp"
23#include "Acts/Geometry/DiamondVolumeBounds.hpp"
24#include "Acts/Surfaces/TrapezoidBounds.hpp"
25#include "Acts/Surfaces/CylinderBounds.hpp"
26#include "Acts/Surfaces/RadialBounds.hpp"
27#include "Acts/Surfaces/CylinderSurface.hpp"
28#include "Acts/Surfaces/DiscSurface.hpp"
29
30#include "Acts/Visualization/ObjVisualization3D.hpp"
31#include "Acts/Visualization/GeometryView3D.hpp"
32#include "Acts/Definitions/Units.hpp"
33
35
36#include <format>
37
38using namespace Acts::UnitLiterals;
39using namespace Muon::MuonStationIndex;
40
41namespace{
42 constexpr double tolerance = 10. *Gaudi::Units::micrometer;
43
44 std::vector<std::shared_ptr<Acts::Volume>> chamberVolumes(const ActsTrk::GeometryContext& gctx,
45 const MuonGMR4::SpectrometerSector& sector) {
46 std::vector<std::shared_ptr<Acts::Volume>> vols{};
47 std::ranges::transform(sector.chambers(),std::back_inserter(vols),
48 [&gctx](const auto& ch){ return ch->boundingVolume(gctx); });
49 return vols;
50 }
51}
52
53namespace MuonGMR4 {
54
56 ATH_CHECK(m_idHelperSvc.retrieve());
57 ATH_CHECK(m_geoCtxKey.initialize());
59 ATH_CHECK(detStore()->retrieve(m_detMgr));
60 return StatusCode::SUCCESS;
61 }
62 template <class EnvelopeType>
63#if defined(FLATTEN) && defined(__GNUC__)
64// We compile this function with optimization, even in debug builds; otherwise,
65// the heavy use of Eigen makes it too slow. However, from here we may call
66// to out-of-line Eigen code that is linked from other DSOs; in that case,
67// it would not be optimized. Avoid this by forcing all Eigen code
68// to be inlined here if possible.
69[[gnu::flatten]]
70#endif
72 const EnvelopeType& chamb,
73 const Acts::Volume& boundVol,
74 const Amg::Vector3D& point,
75 const std::string& descr,
76 const Identifier& channelId) const {
77
78 // Explicitly inline Volume::inside here so that it gets
79 // flattened in debug builds. Gives a significant speedup.
80 //if (boundVol.inside(gctx.context(), point, tolerance)) {
81 const Amg::Vector3D locPos{boundVol.globalToLocalTransform(gctx.context()) * point};
82 if (boundVol.volumeBounds().inside(locPos,tolerance)) {
83 ATH_MSG_VERBOSE("In channel "<<m_idHelperSvc->toString(channelId)
84 <<", point "<<descr <<" is inside of the chamber "<<std::endl<<chamb<<std::endl
85 <<"Local position:" <<Amg::toString(boundVol.globalToLocalTransform(gctx.context()) * point));
86 return StatusCode::SUCCESS;
87 }
88
89 StripDesign planeTrapezoid{};
90 planeTrapezoid.defineTrapezoid(chamb.halfXShort(), chamb.halfXLong(), chamb.halfY());
91 planeTrapezoid.setLevel(MSG::VERBOSE);
93 static const Eigen::Rotation2D axisSwap{90. *Gaudi::Units::deg};
94 if (std::abs(locPos.z()) - chamb.halfZ() < -tolerance &&
95 planeTrapezoid.insideTrapezoid(axisSwap*locPos.block<2,1>(0,0))) {
96 return StatusCode::SUCCESS;
97 }
98 planeTrapezoid.defineStripLayout(locPos.y() * Amg::Vector2D::UnitX(), 1, 1, 1);
99 ATH_MSG_FATAL("In channel "<<m_idHelperSvc->toString(channelId) <<", the point "
100 << descr <<" "<<Amg::toString(point)<<" is not part of the chamber volume."
101 <<std::endl<<std::endl<<chamb<<std::endl<<"Local position "<<Amg::toString(locPos)
102 <<", "<<planeTrapezoid
103 <<", box left edge: "<<Amg::toString(planeTrapezoid.leftEdge(1).value_or(Amg::Vector2D::Zero()))
104 <<", box right edge "<<Amg::toString(planeTrapezoid.rightEdge(1).value_or(Amg::Vector2D::Zero())));
105 return StatusCode::FAILURE;
106 }
107
109 const Acts::TrackingVolume& volume,
110 const Amg::Vector3D& point,
111 const std::string& descr,
112 const Identifier& chamberId) const {
113 if (volume.inside(gctx.context(), point, tolerance)) {
114 return StatusCode::SUCCESS;
115 }
116 const std::vector<Amg::Vector3D> volumeCorners = cornerPoints(gctx, volume);
117 ATH_MSG_FATAL("In channel "<<m_idHelperSvc->toString(chamberId) <<", the point "
118 << descr <<" "<<Amg::toString(volume.globalToLocalTransform(gctx.context())* point)
119 <<" is not part of the chamber volume. The corners of the volume are:");
120 for(const auto& corner : volumeCorners) {
121 ATH_MSG_FATAL(" "<<Amg::toString(volume.globalToLocalTransform(gctx.context())*corner));
122 }
123 return StatusCode::FAILURE;
124 }
125
126 template <class EnvelopeType>
128 const EnvelopeType& envelope) const {
129 std::shared_ptr<Acts::Volume> boundVol = envelope.boundingVolume(gctx);
130 const Chamber::ReadoutSet reEles = envelope.readoutEles();
131 for(const MuonReadoutElement* readOut : reEles) {
132 if constexpr (std::is_same_v<EnvelopeType, SpectrometerSector>) {
133 if (readOut->msSector() != &envelope) {
134 ATH_MSG_FATAL("Mismatch in the sector association "<<m_idHelperSvc->toStringDetEl(readOut->identify())
135 <<std::endl<<(*readOut->msSector())<<std::endl<<envelope);
136 return StatusCode::FAILURE;
137 }
138 } else if constexpr (std::is_same_v<EnvelopeType, Chamber>) {
139 if (readOut->chamber() != &envelope) {
140 ATH_MSG_FATAL("Mismatch in the chamber association "<<m_idHelperSvc->toStringDetEl(readOut->identify())
141 <<std::endl<<(*readOut->chamber())<<std::endl<<envelope);
142 return StatusCode::FAILURE;
143 }
144 }
145 switch (readOut->detectorType()) {
147 const auto* detEle = static_cast<const TgcReadoutElement*>(readOut);
148 ATH_CHECK(testReadoutEle(gctx, *detEle, envelope, *boundVol));
149 break;
151 const auto* detEle = static_cast<const MdtReadoutElement*>(readOut);
152 ATH_CHECK(testReadoutEle(gctx, *detEle, envelope, *boundVol));
153 break;
155 const auto* detEle = static_cast<const RpcReadoutElement*>(readOut);
156 ATH_CHECK(testReadoutEle(gctx, *detEle, envelope, *boundVol));
157 break;
159 const auto* detEle = static_cast<const MmReadoutElement*>(readOut);
160 ATH_CHECK(testReadoutEle(gctx, *detEle, envelope, *boundVol));
161 break;
163 const auto* detEle = static_cast<const sTgcReadoutElement*>(readOut);
164 ATH_CHECK(testReadoutEle(gctx, *detEle, envelope, *boundVol));
165 break;
166 } default: {
167 ATH_MSG_FATAL("Who came up with putting "<<ActsTrk::to_string(readOut->detectorType())
168 <<" into the MS");
169 return StatusCode::FAILURE;
170 }
171 }
172 }
173 ATH_MSG_DEBUG("All "<<reEles.size()<<" readout elements are embedded in "<<envelope);
174 return StatusCode::SUCCESS;
175 }
176
177 std::vector<Amg::Vector3D> MuonChamberToolTest::cornerPoints(const ActsTrk::GeometryContext& gctx, const Acts::Volume& volume) const {
178
179 const auto& bounds = volume.volumeBounds();
180 unsigned int edgeIdx{0};
181 //diamond volume bounds case - there are 12 edges
182 if(bounds.type() == Acts::VolumeBounds::BoundsType::eDiamond){
183 const auto& diamondBounds = static_cast<const Acts::DiamondVolumeBounds&>(bounds);
184 using BoundEnum = Acts::DiamondVolumeBounds::BoundValues;
185 std::vector<Amg::Vector3D> edges(12, Amg::Vector3D::Zero());
186 double xCord{0};
187 double yCord{0};
188 for(double signX : {-1.,1.}){
189 for(double signY : {-1., 0., 1.}){
190 for(double signZ : {-1.,1.}){
191 if(signY == 0){
192 xCord = diamondBounds.get(BoundEnum::eHalfLengthX2);
193 }else if(signY < 0){
194 xCord = diamondBounds.get(BoundEnum::eHalfLengthX1);
195 yCord = diamondBounds.get(BoundEnum::eLengthY1);
196
197 }else{
198 xCord = diamondBounds.get(BoundEnum::eHalfLengthX3);
199 yCord = diamondBounds.get(BoundEnum::eLengthY2);
200
201 }
202
203 const Amg::Vector3D edge{signX*xCord,
204 signY*yCord,
205 signZ*diamondBounds.get(BoundEnum::eHalfLengthZ)};
206 edges[edgeIdx] = volume.localToGlobalTransform(gctx.context())*edge;
207 edgeIdx++;
208 }
209 }
210 }
211
212 return edges;
213 }
214
215 //trapezoid or rectangular bounds case
216 std::vector<Amg::Vector3D> edges(8, Amg::Vector3D::Zero());
217 ATH_MSG_VERBOSE("Fetch volume bounds "<<Amg::toString(volume.localToGlobalTransform(gctx.context())));
218 for (const double signX : {-1., 1.}) {
219 for (const double signY : { -1., 1.}) {
220 for (const double signZ: {-1., 1.}) {
221 const Amg::Vector3D edge{signX* (signY>0 ? MuonGMR4::halfXhighY(bounds) : MuonGMR4::halfXlowY(bounds)),
222 signY*MuonGMR4::halfY(bounds),
223 signZ*MuonGMR4::halfZ(bounds)};
224 edges[edgeIdx] = volume.localToGlobalTransform(gctx.context()) * edge;
225 ATH_MSG_VERBOSE("Local edge "<<Amg::toString(edge)<<", global edge: "<<Amg::toString(edges[edgeIdx]));
226 ++edgeIdx;
227 }
228 }
229 }
230 return edges;
231 }
232
233 std::array<Amg::Vector3D, 8> MuonChamberToolTest::cornerPoints(const ActsTrk::GeometryContext& gctx, const Acts::StrawSurface& surface) const {
234 std::array<Amg::Vector3D, 8> edges{make_array<Amg::Vector3D,8>(Amg::Vector3D::Zero())};
235 using BoundEnum = Acts::LineBounds::BoundValues;
236 const auto& bounds = static_cast<const Acts::LineBounds&>(surface.bounds());
237 unsigned int edgeIdx{0};
238
239 ATH_MSG_VERBOSE("Fetch volume bounds "<<Amg::toString(surface.localToGlobalTransform(gctx.context())));
240 for (const double signX : {-1., 1.}) {
241 for (const double signY : { -1., 1.}) {
242 for (const double signZ: {-1., 1.}) {
243 const Amg::Vector3D edge{signX*bounds.get(BoundEnum::eR),
244 signY*bounds.get(BoundEnum::eR),
245 signZ*bounds.get(BoundEnum::eHalfLengthZ)};
246 edges[edgeIdx] = surface.localToGlobalTransform(gctx.context()) * edge;
247 ++edgeIdx;
248 }
249 }
250 }
251 return edges;
252 }
253
254 std::array<Amg::Vector3D, 4> MuonChamberToolTest::cornerPoints(const ActsTrk::GeometryContext& gctx, const Acts::PlaneSurface& surface) const {
255 std::array<Amg::Vector3D, 4> edges{make_array<Amg::Vector3D,4>(Amg::Vector3D::Zero())};
256 if(surface.bounds().type() == Acts::SurfaceBounds::BoundsType::eRectangle) { //RPC surfaces are rectangles
257 const Acts::RectangleBounds& bounds = static_cast<const Acts::RectangleBounds&>(surface.bounds());
258 using BoundEnum = Acts::RectangleBounds::BoundValues;
259
260 unsigned int edgeIdx{0};
261 for(const double signX : {-1., 1.}) {
262 for (const double signY : { -1., 1.}) {
263 const Amg::Vector3D edge{signX < 0 ? bounds.get(BoundEnum::eMinX) : bounds.get(BoundEnum::eMaxX),
264 signY < 0 ? bounds.get(BoundEnum::eMinY) : bounds.get(BoundEnum::eMaxY), 0.};
265 edges[edgeIdx] = surface.localToGlobalTransform(gctx.context()) * edge;
266 ++edgeIdx;
267 }
268 }
269 return edges;
270 } else if(surface.bounds().type() == Acts::SurfaceBounds::BoundsType::eTrapezoid) {
271 using BoundEnum = Acts::TrapezoidBounds::BoundValues;
272 const auto& bounds = static_cast<const Acts::TrapezoidBounds&>(surface.bounds());
273 unsigned int edgeIdx{0};
274
275 ATH_MSG_VERBOSE("Fetch volume bounds "<<Amg::toString(surface.localToGlobalTransform(gctx.context())));
276 for (const double signX : {-1., 1.}) {
277 for (const double signY : { -1., 1.}) {
278 const Amg::Vector3D edge{Amg::getRotateZ3D(-1.*bounds.get(BoundEnum::eRotationAngle)) *
279 Amg::Vector3D(signX*bounds.get(signY < 0 ? BoundEnum::eHalfLengthXnegY : BoundEnum::eHalfLengthXposY),
280 signY*bounds.get(BoundEnum::eHalfLengthY), 0.)};
281
282 edges[edgeIdx] = surface.localToGlobalTransform(gctx.context()) * edge;
283 ++edgeIdx;
284 }
285 }
286
287 return edges;
288 } else {
289 ATH_MSG_FATAL("The surface bounds are neither a rectangle nor a trapezoid, this is not supported yet");
290 return edges;
291 }
292 }
293
294
295#if defined(FLATTEN) && defined(__GNUC__)
296// We compile this function with optimization, even in debug builds; otherwise,
297// the heavy use of Eigen makes it too slow. However, from here we may call
298// to out-of-line Eigen code that is linked from other DSOs; in that case,
299// it would not be optimized. Avoid this by forcing all Eigen code
300// to be inlined here if possible.
301[[gnu::flatten]]
302#endif
304 const std::vector<Amg::Vector3D>& chamberEdges,
305 const Acts::Volume& volume) const {
306
308 const Amg::Vector3D center{volume.center(gctx.context())};
309 double minDist = 1._km;
310 for (const Amg::Vector3D& edge : chamberEdges) {
311 minDist = std::min(minDist, (edge - center).mag());
312 }
315 if (std::ranges::none_of(volume.volumeBounds().values(),
316 [minDist](const double bound){
317 return minDist < 2.5*bound;
318 })) {
319 return false;
320 }
321 const double stepLength = 1. / m_overlapSamples;
322
323 const Acts::VolumeBounds& volBounds = volume.volumeBounds();
324 const Acts::Transform3& transform = volume.globalToLocalTransform(gctx.context());
325 for (unsigned edge1 = 1; edge1 < chamberEdges.size(); ++edge1) {
326 for (unsigned edge2 = 0; edge2 < edge1; ++edge2) {
327 for (unsigned step = 0 ; step <= m_overlapSamples; ++step) {
328 const double section = stepLength * step;
329 const Amg::Vector3D testPoint = section* chamberEdges[edge1] + (1. -section) *chamberEdges[edge2];
330 // Using acts::Volume::inside is horribly slow in dbg builds.
331 // Using the bounds method directly is much faster.
332 //if (volume.inside (gctx.context(), testPoint)) {
333 if (volBounds.inside (transform * testPoint)) {
334 return true;
335 }
336 }
337 }
338 }
339 return false;
340 }
342
343 std::vector<const MuonReadoutElement*> allRE = m_detMgr->getAllReadoutElements();
345 const ChamberSet chambers = m_detMgr->getAllChambers();
346 ATH_MSG_INFO("Fetched "<<chambers.size()<<" chambers.");
347 std::vector<const Chamber*> chamberVec{chambers.begin(), chambers.end()};
348
349 const auto missChamb = std::ranges::find_if(allRE, [&chamberVec](const MuonGMR4::MuonReadoutElement* re){
350 return std::ranges::find(chamberVec, re->chamber()) == chamberVec.end();
351 });
352 if (missChamb != allRE.end()) {
353 ATH_MSG_FATAL("The chamber "<<(*(*missChamb)->chamber())<<" is not in the chamber set");
354 return StatusCode::FAILURE;
355 }
356
357 // Retrieve bounds here rather than inside the loop below,
358 // so we only need to do it O(N) rather than O(N^2) times.
359 std::vector<std::shared_ptr<Acts::Volume> > chamberBoundsVec;
360 chamberBoundsVec.reserve (chamberVec.size());
361 for (const Chamber* ch : chamberVec)
362 chamberBoundsVec.push_back (ch->boundingVolume(gctx));
363
364 std::set<const Chamber*> overlapChambers{};
365 std::stringstream overlapstream{};
366 for (std::size_t chIdx = 0; chIdx< chamberVec.size(); ++chIdx) {
367 const Chamber& chamber{*chamberVec[chIdx]};
368 const Acts::Volume& chamberBounds = *chamberBoundsVec[chIdx];
369 if (m_dumpObjs) {
370 saveEnvelope(gctx, std::format("Chamber_{:}{:}{:}{:}{:}",
371 ActsTrk::to_string(chamber.detectorType()),
372 chName(chamber.chamberIndex()),
373 Acts::abs(chamber.stationEta()),
374 chamber.stationEta() > 0 ? 'A' : 'C',
375 chamber.stationPhi()),
376 chamberBounds, chamber.readoutEles());
377 }
378 ATH_CHECK(allReadoutInEnvelope(gctx, chamber));
379 const std::vector<Amg::Vector3D> chambCorners = cornerPoints(gctx, chamberBounds);
381 std::vector<const Chamber*> overlaps{};
382 for (std::size_t chIdx1 = 0; chIdx1<chamberVec.size(); ++chIdx1) {
383 if (chIdx == chIdx1) {
384 continue;
385 }
386 const Chamber* overlapTest{chamberVec[chIdx1]};
387 if (hasOverlap(gctx, chambCorners, *chamberBoundsVec[chIdx1])) {
388 overlaps.push_back(overlapTest);
389 }
390 }
391 if (overlaps.empty()) {
392 continue;
393 }
394 overlapstream<<"The chamber "<<chamber<<" overlaps with "<<std::endl;
395 for (const Chamber* itOverlaps : overlaps) {
396 overlapstream<<" *** "<<(*itOverlaps)<<std::endl;
397 }
398 overlapstream<<std::endl<<std::endl;
399 overlapChambers.insert(overlaps.begin(), overlaps.end());
400 overlapChambers.insert(chamberVec[chIdx]);
401 }
402 if (!overlapChambers.empty()) {
403 Acts::ObjVisualization3D visualHelper{};
404 for (const Chamber* hasOverlap: overlapChambers) {
405 Acts::GeometryView3D::drawVolume(visualHelper, *hasOverlap->boundingVolume(gctx), gctx.context());
406 visualHelper.write(m_overlapChambObj.value());
407 }
408 if (m_ignoreOverlapCh) {
409 ATH_MSG_WARNING(overlapstream.str());
410 } else {
411 ATH_MSG_FATAL(overlapstream.str());
412 }
413 }
414 return overlapChambers.empty() || m_ignoreOverlapCh ? StatusCode::SUCCESS : StatusCode::FAILURE;
415 }
416
418
419 std::vector<const MuonReadoutElement*> allREs = m_detMgr->getAllReadoutElements();
420 for (const MuonReadoutElement* re : allREs) {
421 if (!re->msSector()) {
422 ATH_MSG_FATAL("The readout element "<<m_idHelperSvc->toStringDetEl(re->identify())<<" does not have any sector associated ");
423 return StatusCode::FAILURE;
424 }
425 const SpectrometerSector* sectorFromDet = m_detMgr->getSectorEnvelope(re->chamberIndex(),
426 m_idHelperSvc->sector(re->identify()),
427 re->stationEta());
428 if (sectorFromDet != re->msSector()) {
429 ATH_MSG_FATAL("The sector attached to "<<m_idHelperSvc->toStringDetEl(re->identify())
430 <<", chIdx: "<<chName(re->chamberIndex())<<", sector: "<<m_idHelperSvc->sector(re->identify())
431 <<" is not the one attached to the readout geometry \n"<<(*re->msSector())<<"\n"<<(*sectorFromDet));
432 return StatusCode::FAILURE;
433 }
434 }
435 using SectorSet = MuonDetectorManager::MuonSectorSet;
436 const SectorSet sectors = m_detMgr->getAllSectors();
437 ATH_MSG_INFO("Fetched "<<sectors.size()<<" sectors. ");
438 for (const SpectrometerSector* sector : sectors) {
439 if (m_dumpObjs) {
440 saveEnvelope(gctx, std::format("Sector_{:}{:}{:}",
441 chName(sector->chamberIndex()),
442 sector->side() >0? 'A' :'C',
443 sector->stationPhi() ),
444 *sector->boundingVolume(gctx), sector->readoutEles(),
445 chamberVolumes(gctx, *sector));
446 }
447 ATH_CHECK(allReadoutInEnvelope(gctx, *sector));
448 const std::shared_ptr<Acts::Volume> secVolume = sector->boundingVolume(gctx);
449 for (const SpectrometerSector::ChamberPtr& chamber : sector->chambers()){
450 const std::vector<Amg::Vector3D> edges = cornerPoints(gctx, *chamber->boundingVolume(gctx));
451 unsigned int edgeCount{0};
452 for (const Amg::Vector3D& edge : edges) {
453 ATH_CHECK(pointInside(gctx, *sector, *secVolume, edge, std::format("Edge {:}", ++edgeCount),
454 chamber->readoutEles().front()->identify()));
455 }
456 }
457 }
458 return StatusCode::SUCCESS;
459 }
460
462 std::shared_ptr<const Acts::TrackingGeometry>& trackingGeometry) const {
463
464 //visit the volumes and check the overlaps with the other volumes in the tracking geometry
465 // also check overlaps between volumes and surfaces (e.g surfaces where the passive material is mapped)
466 std::vector<const Acts::TrackingVolume*> volumeVec{};
467 std::vector<const Acts::TrackingVolume*> overlapVolumes{};
468 std::vector<const Acts::Surface*> surfacesVec{};
469 //keep onyl the chamber volumes - not the cylinders
470 trackingGeometry->visitVolumes([&](const Acts::TrackingVolume* vol){
471 //for the cylinder type volumes , fetch the inner surfaces only (e.g passive material surfaces)
472 if(vol->volumeBounds().type() == Acts::VolumeBounds::BoundsType::eCylinder){
473 std::ranges::for_each(vol->surfaces(), [&](const auto& surf){
474 surfacesVec.push_back(&surf);
475 });
476 return;
477 }
478 //dump the tracking volumes into obj
479 if(m_dumpObjs){
480 Acts::ObjVisualization3D visualHelper{};
481 for(const auto& surf : vol->surfaces()){
482 Acts::GeometryView3D::drawSurface(visualHelper, surf, gctx.context());
483 }
484 std::string volName = vol->volumeName();
485 Acts::GeometryView3D::drawVolume(visualHelper, *vol, gctx.context());
486 ATH_MSG_DEBUG("Save new tracking volume 'MsTrackingVol_"<<volName<<".obj'");
487 visualHelper.write(std::format("MsTrackingVol_{:}.obj", volName));
488
489 }
490 volumeVec.push_back(vol);
491
492 });
493
494 ATH_MSG_VERBOSE("Fetched "<< surfacesVec.size()<< "surfaces");
495
496
497 for(std::size_t vIdx = 0; vIdx < volumeVec.size(); vIdx++){
498 const Acts::TrackingVolume* testVol{volumeVec[vIdx]};
499 std::vector<const Acts::TrackingVolume*> overlaps{};
500 const std::vector<Amg::Vector3D> edges = cornerPoints(gctx, *testVol);
501 const auto childrenVol = testVol->volumes();
502 const auto innerSurfaces = testVol->surfaces();
503
504 for(const auto& surface : innerSurfaces){
505 //only plane or straw surfaces expected
506 std::vector<Amg::Vector3D> surfEdges = {};
507 if(const auto* strawSurf = dynamic_cast<const Acts::StrawSurface*>(&surface)){
508 ATH_MSG_VERBOSE("Checking straw surface "<<surface.geometryId()
509 <<" in volume "<<testVol->volumeName());
510
511 auto edges = cornerPoints(gctx, *strawSurf);
512 surfEdges = {edges.begin(), edges.end()};
513 }else if(const auto* planeSurf = dynamic_cast<const Acts::PlaneSurface*>(&surface)){
514 ATH_MSG_VERBOSE("Checking plane surface "<<surface.geometryId()
515 <<" in volume "<<testVol->volumeName());
516
517 auto edges = cornerPoints(gctx, *planeSurf);
518 surfEdges = {edges.begin(), edges.end()};
519 } else{
520 ATH_MSG_FATAL("The surface "<< surface.geometryId()
521 <<" is neither a straw nor a plane surface");
522 return StatusCode::FAILURE;
523 }
524
525
526 for(const auto& edge : surfEdges){
527 if(!(testVol->inside(gctx.context(), edge,0.01))){
528 ATH_MSG_FATAL("The surface " << surface.geometryId() <<" at vertex point " <<Amg::toString(edge)
529 <<" is outside the parent volume" << testVol->volumeName());
530 return m_ignoreOutsideSurf ? StatusCode::SUCCESS : StatusCode::FAILURE;
531
532 }
533 }
534 }
535
536 //check if this test volume overlaps with the other volumes in the tracking geometry
537 for(std::size_t vIdx1 = 0 ; vIdx1 < volumeVec.size(); vIdx1++){
538 bool isChild = std::ranges::find_if(childrenVol,
539 [&](const Acts::TrackingVolume& tv){ return &tv == volumeVec[vIdx1]; }
540 ) != childrenVol.end();
541
542 bool isMother = (testVol->motherVolume() == volumeVec[vIdx1]);
543
544 if(vIdx1 == vIdx || isMother){
545 continue;
546 }
547 //check if the child volume is entirely enclosed by the mother volume
548 if(isChild){
549 std::vector<Amg::Vector3D> childEdges = cornerPoints(gctx,*volumeVec[vIdx1]);
550 for(const auto& edge : childEdges){
551 if(!(testVol->inside(gctx.context(), edge, 0.01))){
552 ATH_MSG_FATAL("The children volume's " << volumeVec[vIdx1]->volumeName()
553 <<" vertex point " <<Amg::toString(edge)
554 <<" is outside the parent volume" << testVol->volumeName());
555 return StatusCode::FAILURE;
556 }
557 }
558 continue;
559
560 }
561 if(hasOverlap(gctx, edges, *volumeVec[vIdx1])){
562 overlaps.push_back(volumeVec[vIdx1]);
563 }
564 }
565
566 //check if the tracking volume overlaps with surfaces of the tracking geometry (e.g cylinders of the barrel where material is mapped)
567 auto [min,max] = std::ranges::minmax_element(edges, [&](const auto& cornerA, const auto& cornerB){
568 return cornerA.perp() < cornerB.perp();
569 });
570 double rmin{min->perp()};
571 double rmax{max->perp()};
572 bool hasoverlap{false};
573 for(const auto& surf : surfacesVec){
574 double radius{0.};
575 double halfZ{0.};
576 ATH_MSG_VERBOSE("Checking surface "<<surf->name()<< " , "<<surf->geometryId());
577 if(const auto* cylSurf = dynamic_cast<const Acts::CylinderSurface*>(surf)){
578 using BoundEnum = Acts::CylinderBounds::BoundValues;
579 const auto& bounds = static_cast<const Acts::CylinderBounds&>(cylSurf->bounds());
580 const auto& center = cylSurf->center(gctx.context());
581 radius = bounds.get(BoundEnum::eR);
582 halfZ = bounds.get(BoundEnum:: eHalfLengthZ);
583 //check for overlap in R in case the surface and the volume have overlapping Z position
584 if(center.z() + halfZ > min->z()){
585 hasoverlap = (radius > rmin && radius < rmax);
586 }
587 }else if(const auto* discSurf = dynamic_cast<const Acts::DiscSurface*>(surf)){
588 using BoundEnum = Acts::RadialBounds::BoundValues;
589 const auto& bounds = static_cast<const Acts::RadialBounds&>(discSurf->bounds());
590 const auto& center = discSurf->center(gctx.context());
591 radius = bounds.get(BoundEnum::eMaxR);
592 //these are endcap passive discsc - witht the endcap chambers check if there is overlap in Z
593 // with the barrel check if there is overlap in R and Z
594 if(center.z() > min->z() && center.z() < max->z()){
595 hasoverlap = (radius > rmin && radius < rmax);
596 }
597
598 }else{
599 ATH_MSG_FATAL("The surface "<< surf->geometryId()<<", "<< surf->name()
600 <<" is not a cylinder surface or disc - i dont expect any other type at the moment");
601 return StatusCode::FAILURE;
602 }
603
604 if(hasoverlap){
605 ATH_MSG_FATAL("The volume " << testVol->volumeName() << "overlaps with the surface "<< surf->name() << "with geo id" << surf->geometryId());
606 }
607
608 }
609
610 if(overlaps.empty()){
611 ATH_MSG_DEBUG("No overlaps detected for the volume "<<testVol->volumeName());
612 continue;
613 }else{
614 overlapVolumes.push_back(testVol);
615 ATH_MSG_ALWAYS("The volume " << testVol->volumeName() << " overlaps with: ");
616 for(const auto& overlap: overlaps){
617 ATH_MSG_ALWAYS(" Volume: " << overlap->volumeName());
618 }
619 }
620 }
621 if(overlapVolumes.empty()){
622 ATH_MSG_ALWAYS("No overlaps detected in the tracking geometry!!");
623 }
624 return overlapVolumes.empty() || m_ignoreOverlapCh ? StatusCode::SUCCESS : StatusCode::FAILURE;
625 }
626
628 const std::string& envName,
629 const Acts::Volume& envelopeVol,
630 const std::vector<const MuonGMR4::MuonReadoutElement*>& assocRE,
631 const std::vector<std::shared_ptr<Acts::Volume>>& subVols) const {
632 Acts::ObjVisualization3D visualHelper{};
633 std::ranges::for_each(assocRE, [&visualHelper, &gctx](const MuonReadoutElement* re){
634 std::ranges::for_each(re->getSurfaces(),[&visualHelper, &gctx](const std::shared_ptr<Acts::Surface>& surface){
635 Acts::GeometryView3D::drawSurface(visualHelper, *surface, gctx.context());
636 });
637 });
638 std::ranges::for_each(subVols, [&visualHelper, &gctx](const std::shared_ptr<Acts::Volume>& subVol ){
639 Acts::GeometryView3D::drawVolume(visualHelper,*subVol, gctx.context(), Amg::Transform3D::Identity(),
640 Acts::s_viewPassive);
641 });
642 Acts::GeometryView3D::drawVolume(visualHelper, envelopeVol, gctx.context());
643 ATH_MSG_DEBUG("Save new envelope 'MsTrackTest_"<<envName<<".obj'");
644 visualHelper.write(std::format("MsTrackTest_{:}.obj", envName));
645 }
646
647 StatusCode MuonChamberToolTest::execute(const EventContext& ctx) const {
648 const ActsTrk::GeometryContext* gctx{nullptr};
649 ATH_CHECK(SG::get(gctx, m_geoCtxKey, ctx));
650 std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry = m_trackingGeometrySvc->trackingGeometry();
652 ATH_CHECK(checkChambers(*gctx));
654 ATH_CHECK(checkTrackingGeometry(*gctx, trackingGeometry));
655
656 return StatusCode::SUCCESS;
657 }
658 template <class EnvelopeType>
660 const MdtReadoutElement& mdtMl,
661 const EnvelopeType& chamber,
662 const Acts::Volume& detVol) const {
663 ATH_MSG_VERBOSE("Test whether "<<m_idHelperSvc->toStringDetEl(mdtMl.identify())<<std::endl<<mdtMl.getParameters());
664
665 for (unsigned int layer = 1; layer <= mdtMl.numLayers(); ++layer) {
666 for (unsigned int tube = 1; tube <= mdtMl.numTubesInLay(); ++tube) {
667 const IdentifierHash idHash = mdtMl.measurementHash(layer, tube);
668 if (!mdtMl.isValid(idHash)){
669 continue;
670 }
671 const Amg::Transform3D& locToGlob{mdtMl.localToGlobalTransform(gctx, idHash)};
672 const Identifier measId{mdtMl.measurementId(idHash)};
673
674 ATH_CHECK(pointInside(gctx, chamber, detVol, mdtMl.globalTubePos(gctx, idHash), "tube center", measId));
675
676 ATH_CHECK(pointInside(gctx, chamber, detVol, mdtMl.readOutPos(gctx, idHash), "tube readout", measId));
677 ATH_CHECK(pointInside(gctx, chamber, detVol, mdtMl.highVoltPos(gctx, idHash), "tube HV", measId));
678
679 ATH_CHECK(pointInside(gctx, chamber, detVol, locToGlob*(-mdtMl.innerTubeRadius() * Amg::Vector3D::UnitX()),
680 "bottom of the tube box", measId));
681 ATH_CHECK(pointInside(gctx, chamber, detVol, locToGlob*(mdtMl.innerTubeRadius() * Amg::Vector3D::UnitX()),
682 "sealing of the tube box", measId));
683
684 ATH_CHECK(pointInside(gctx, chamber, detVol, locToGlob*(-mdtMl.innerTubeRadius() * Amg::Vector3D::UnitY()),
685 "wall to the previous tube", measId));
686 ATH_CHECK(pointInside(gctx, chamber, detVol, locToGlob*(-mdtMl.innerTubeRadius() * Amg::Vector3D::UnitY()),
687 "wall to the next tube", measId));
688 }
689 }
690 return StatusCode::SUCCESS;
691 }
692 template<class EnvelopeType>
694 const RpcReadoutElement& rpc,
695 const EnvelopeType& chamber,
696 const Acts::Volume& detVol) const {
697
698 ATH_MSG_VERBOSE("Test whether "<<m_idHelperSvc->toStringDetEl(rpc.identify())<<std::endl<<rpc.getParameters());
699
700 const RpcIdHelper& idHelper{m_idHelperSvc->rpcIdHelper()};
701 for (unsigned int gasGap = 1 ; gasGap <= rpc.nGasGaps(); ++gasGap) {
702 for (int doubletPhi = rpc.doubletPhi(); doubletPhi <= rpc.doubletPhiMax(); ++doubletPhi){
703 for (bool measPhi : {false, true}) {
704 const int nStrips = measPhi ? rpc.nPhiStrips() : rpc.nEtaStrips();
705 for (int strip = 1; strip <= nStrips; ++strip) {
706 const Identifier stripId = idHelper.channelID(rpc.identify(),rpc.doubletZ(),
707 doubletPhi, gasGap, measPhi, strip);
708 ATH_CHECK(pointInside(gctx, chamber, detVol, rpc.stripPosition(gctx, stripId), "center", stripId));
709 ATH_CHECK(pointInside(gctx, chamber, detVol, rpc.leftStripEdge(gctx, stripId), "right edge", stripId));
710 ATH_CHECK(pointInside(gctx, chamber, detVol, rpc.rightStripEdge(gctx, stripId), "left edge", stripId));
711 }
712 }
713 }
714 }
715 return StatusCode::SUCCESS;
716 }
717 template <class EnevelopeType>
719 const TgcReadoutElement& tgc,
720 const EnevelopeType& chamber,
721 const Acts::Volume& detVol) const {
722 for (unsigned int gasGap = 1; gasGap <= tgc.nGasGaps(); ++gasGap){
723 for (bool isStrip : {false}) {
724 const IdentifierHash layHash = tgc.constructHash(0, gasGap, isStrip);
725 const unsigned int nChannel = tgc.numChannels(layHash);
726 for (unsigned int channel = 1; channel <= nChannel ; ++channel) {
727 const IdentifierHash measHash = tgc.constructHash(channel, gasGap, isStrip);
728 ATH_CHECK(pointInside(gctx, chamber, detVol, tgc.channelPosition(gctx, measHash),
729 "center", tgc.measurementId(measHash)));
730 }
731 }
732 }
733 return StatusCode::SUCCESS;
734 }
735 template <class EnevelopeType>
737 const MmReadoutElement& mm,
738 const EnevelopeType& chamber,
739 const Acts::Volume& detVol) const {
740
741 const MmIdHelper& idHelper{m_idHelperSvc->mmIdHelper()};
742 for(unsigned int gasGap = 1; gasGap <= mm.nGasGaps(); ++gasGap){
743 IdentifierHash gasGapHash = MmReadoutElement::createHash(gasGap,0);
744 unsigned int firstStrip = mm.firstStrip(gasGapHash);
745 for(unsigned int strip = firstStrip; strip <= mm.numStrips(gasGapHash); ++strip){
746 const Identifier stripId = idHelper.channelID(mm.identify(), mm.multilayer(), gasGap, strip);
747 ATH_CHECK(pointInside(gctx, chamber, detVol, mm.stripPosition(gctx, stripId), "center", stripId));
748 ATH_CHECK(pointInside(gctx, chamber, detVol, mm.leftStripEdge(gctx, mm.measurementHash(stripId)), "left edge", stripId));
749 ATH_CHECK(pointInside(gctx, chamber, detVol, mm.rightStripEdge(gctx, mm.measurementHash(stripId)), "right edge", stripId));
750 }
751 }
752
753 return StatusCode::SUCCESS;
754 }
755 template <class EnvelopeType>
757 const sTgcReadoutElement& stgc,
758 const EnvelopeType& chamber,
759 const Acts::Volume& detVol) const{
760
761 const sTgcIdHelper& idHelper{m_idHelperSvc->stgcIdHelper()};
762 for(unsigned int gasGap = 1; gasGap <= stgc.numLayers(); ++gasGap){
763
764 for(unsigned int nch = 1; nch <= stgc.nChTypes(); ++nch){
765 IdentifierHash gasGapHash = sTgcReadoutElement::createHash(gasGap, nch, 0, 0);
766 const unsigned int nStrips = stgc.numChannels(gasGapHash);
768
769 for(unsigned int strip = 1; strip <= nStrips; ++strip){
770 const Identifier stripId = idHelper.channelID(stgc.identify(), stgc.multilayer(), gasGap, nch, strip);
771 const IdentifierHash stripHash = stgc.measurementHash(stripId);
772 ATH_CHECK(pointInside(gctx, chamber, detVol, stgc.globalChannelPosition(gctx, stripHash), "channel position", stripId));
773
775 ATH_CHECK(pointInside(gctx, chamber, detVol, stgc.rightStripEdge(gctx, stripHash), "channel position", stripId));
776 ATH_CHECK(pointInside(gctx, chamber, detVol, stgc.leftStripEdge(gctx, stripHash), "channel position", stripId));
777 }
778 }
779 }
780 }
781 return StatusCode::SUCCESS;
782
783 }
784}
785
const boost::regex re(r_e)
Scalar mag() const
mag method
constexpr std::array< T, N > make_array(const T &def_val)
Helper function to initialize in-place arrays with non-zero values.
Definition ArrayHelper.h:10
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_ALWAYS(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
void section(const std::string &sec)
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
Acts::GeometryContext context() const
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.
Definition Chamber.h:29
std::vector< const MuonReadoutElement * > ReadoutSet
Define the list of read out elements of the chamber.
Definition Chamber.h:32
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.
StatusCode checkEnvelopes(const ActsTrk::GeometryContext &gctx) const
Check envelopes.
void saveEnvelope(const ActsTrk::GeometryContext &gctx, const std::string &envName, const Acts::Volume &envelopeVol, const std::vector< const MuonGMR4::MuonReadoutElement * > &assocRE, const std::vector< std::shared_ptr< Acts::Volume > > &subVolumes={}) const
StatusCode execute(const EventContext &ctx) const override
StatusCode checkChambers(const ActsTrk::GeometryContext &gctx) const
Check whether the chamber envelopes are consistent.
Gaudi::Property< bool > m_dumpObjs
Dump the chambers & sectors as separate obj files.
StatusCode pointInside(const ActsTrk::GeometryContext &gctx, const EnvelopeType &envelope, 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.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Gaudi::Property< std::string > m_overlapChambObj
Name of the chamber output obj file.
StatusCode checkTrackingGeometry(const ActsTrk::GeometryContext &gctx, std::shared_ptr< const Acts::TrackingGeometry > &trackingGeometry) const
Check tracking geometry volumes.
StatusCode testReadoutEle(const ActsTrk::GeometryContext &gctx, const MdtReadoutElement &readOutEle, const EnvelopeType &envelope, const Acts::Volume &boundVol) const
Checks whether all channels of a given readout element are fully covered by the envelope.
Gaudi::Property< unsigned > m_overlapSamples
Number of points to scan along the lines between two volume corners to check whether they belong to a...
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
Gaudi::Property< bool > m_ignoreOutsideSurf
The exceeding surfaces does not lead to a failure.
StatusCode allReadoutInEnvelope(const ActsTrk::GeometryContext &ctx, const EnvelopeType &envelope) const
Checks whether the readout elements of an enevelope are completely embedded into the envelope.
SG::ReadHandleKey< ActsTrk::GeometryContext > m_geoCtxKey
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.
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &ctx) const
Returns the transformation from the local coordinate system of the readout element into the global AT...
Identifier identify() const override final
Return the ATLAS identifier.
unsigned nPhiStrips() const
Number of strips measuring the phi coordinate.
Amg::Vector3D leftStripEdge(const ActsTrk::GeometryContext &ctx, const Identifier &measId) const
Returns the global posiition of the strip edge at positive local Y.
int doubletZ() const
Returns the doublet Z field of the MuonReadoutElement identifier.
int doubletPhi() const
Returns the doublet Phi field of the MuonReadoutElement identifier.
Amg::Vector3D rightStripEdge(const ActsTrk::GeometryContext &ctx, const Identifier &measId) const
Returns the global position of the strip edge at negative local Y.
unsigned nEtaStrips() const
Number of strips measuring the eta coordinate.
int doubletPhiMax() const
Returns the maximum phi panel.
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
std::string to_string(const DetectorType &type)
@ 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.
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
The ReadoutGeomCnvAlg converts the Run4 Readout geometry build from the GeoModelXML into the legacy M...
double halfY(const Acts::VolumeBounds &bounds)
Returns the half-Y length for the parsed volume bounds (Trapezoid/ Cuboid)
SpectrometerSector::ChamberSet ChamberSet
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)
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.