ATLAS Offline Software
PadDesign.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 #ifndef MUONREADOUTGEOMETRYR4_PADDESIGN_ICC
5 #define MUONREADOUTGEOMETRYR4_PADDESIGN_ICC
6 
7 #include <MuonReadoutGeometryR4/PadDesign.h>
8 
9 namespace MuonGMR4 {
10  using CheckVector2D = PadDesign::CheckVector2D;
11  inline int PadDesign::numPads() const { return m_numPadPhi * m_numPadEta; }
12  inline double PadDesign::firstPadPhiDiv() const { return m_firstPadPhiDiv; }
13  inline int PadDesign::numPadPhi() const { return m_numPadPhi; }
14  inline double PadDesign::anglePadPhi() const { return m_anglePadPhi; }
15  inline double PadDesign::padPhiShift() const { return m_padPhiShift; }
16  inline double PadDesign::firstPadHeight() const { return m_firstPadHeight; }
17  inline int PadDesign::numPadEta() const { return m_numPadEta; }
18  inline double PadDesign::padHeight() const { return m_padHeight; }
19  inline int PadDesign::maxPadEta() const { return m_maxPadEta; }
20  inline int PadDesign::padNumber(const int channel) const {
21  int padEta = padEtaPhi(channel).first;
22  int padPhi = padEtaPhi(channel).second;
23  int padNumber = (padPhi - 1) * maxPadEta() + padEta;
24  return padNumber;
25  };
26  inline std::pair<int, int> PadDesign::padEtaPhi(const int channel) const {
27  int padEta = (channel -1) % numPadEta() + 1;
28  int padPhi = (channel -1) / numPadEta() + 1;
29  if (channel < 0 || padEta > numPadEta() || padPhi > numPadPhi()) {
30  ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" Pad channel " << channel << " is out of range. Maximum range: " << numPads());
31  ATH_MSG_DEBUG(__FILE__<<":"<<__LINE__<<" Pad channel: "<< channel<< " padEta: "<<padEta<<" numPadEta: "<<numPadEta()<<" padPhi "<<padPhi<<" numPadPhi: "<<numPadPhi()<<" total pads "<<numPads());
32  return std::make_pair(0, 0);
33  }
34  return std::make_pair(padEta, padPhi);
35  }
36  inline int PadDesign::padEta(const int channel) const {
37  return padEtaPhi(channel).first;
38  }
39  inline int PadDesign::padPhi(const int channel) const {
40  return padEtaPhi(channel).second;
41  }
42  inline double PadDesign::beamlineRadius() const {
43  return m_radius;
44  }
45 
46  using localCornerArray = std::array<Amg::Vector2D, 4>;
47  inline localCornerArray PadDesign::padCorners(const int channel) const {
48  return padCorners(padEtaPhi(channel));
49  }
50  inline Amg::Vector2D PadDesign::stripPosition(int channel) const {
51  if (padEta(channel) == 0 || padPhi(channel) == 0) {
52  ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" The pad number "<<channel
53  <<" is out of range. Maximum range: " << numPads());
54  return Amg::Vector2D::Zero();
55  }
56  localCornerArray Corners = padCorners(channel);
57  Amg::Vector2D padCenter = 0.25 * (Corners[botLeft] + Corners[botRight] + Corners[topLeft] + Corners[topRight]);
58  return padCenter;
59  }
60  inline std::pair<int, int> PadDesign::channelNumber(const Amg::Vector2D& hitPos) const {
61  /// distance from the short edge to the hit. No change for L3 since the center is at the center of the gas gap.
62  double hitY = halfWidth() + hitPos.y();
63  /// Variables to store padEta information
64  double padEtaDouble{0.};
65  int padEta{0};
66  /// Applying neagtive of staggering to the hit in Phi direction
67  double locPhi = std::atan2(-hitPos.x(), (beamlineRadius() + hitPos.y())) / Gaudi::Units::deg;
68  double locMaxPhi = std::atan2(maxActiveX(hitPos.y()), (beamlineRadius() + hitPos.y())) / Gaudi::Units::deg;
69  double shiftedX = hitPos.x() - padPhiShift() * std::cos(locPhi * Gaudi::Units::deg);
70  double shiftedLocPhi = std::atan2(-shiftedX, (beamlineRadius() + hitPos.y())) / Gaudi::Units::deg;
71  /// Booleans to define bounds
72  bool bottomHalf = (hitY < 0);
73  bool outsidePhiRange = (std::abs(locPhi) > locMaxPhi) || (std::abs(shiftedLocPhi) > locMaxPhi);
74  /// Evaluating Eta of the pad where the hit is contained
75  if(insideBoundaries(hitPos) && !bottomHalf) {
76  if (hitY > firstPadHeight()) {
77  /// + 1 for ignoring the firstPadRow and another + 1 because remainder means hit is in the next row (eg. 3.1 = 4)
78  padEtaDouble = ((hitY - firstPadHeight()) / padHeight()) + 2;
79  padEta = padEtaDouble;
80  }
81  else if (hitY > 0) {
82  padEta = 1;
83  }
84  }
85  else {
86  ATH_MSG_WARNING("The failed Hit: "<< Amg::toString(hitPos, 2) << " is outside the trapezoid bounds. "<< "HitY: " << hitY);
87  }
88  /// Variables to store padPhi information
89  double padPhiDouble{0.};
90  int padPhi{0};
91  /// Hits on the pads near the side edges of the trapezoid are shifted but
92  /// the pads are not hence, those hits must be corrected.
93  if (outsidePhiRange) {
94  padPhiDouble = (locPhi - firstPadPhiDiv()) / anglePadPhi();
95  ATH_MSG_DEBUG("The Hit: "<< Amg::toString(hitPos, 2) << " is out of bounds." << " maxActive X: " << maxActiveX(hitPos.y()));
96  ATH_MSG_DEBUG("HitPhi: "<< locPhi << " MaxPhi: " << locMaxPhi << " Staggered Hit phi: " << shiftedLocPhi);
97  }
98  else {
99  padPhiDouble = (shiftedLocPhi - firstPadPhiDiv()) / anglePadPhi();
100  }
101  /// +1 for the firstPadColumn to be 1, and another +1 because remainder means hit is in the next column (eg. 2.1 = 3)
102  padPhi = padPhiDouble + 2;
103  /// Adjusting the padEta and padPhi bounds
104  if (padEta == numPadEta() + 1) { padEta -= 1; }
105  if (padPhi == 0) { padPhi = 1; }
106  if (padPhi == numPadPhi() + 1) { padPhi = numPadPhi(); }
107  /// Final check on bounds
108  bool etaOutsideRange = (padEta > numPadEta());
109  bool phiOutsideRange = (padPhi < 0 || padPhi > numPadPhi() + 1);
110  if(etaOutsideRange or phiOutsideRange) {
111  ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" "<<__func__<<"() Given hit: "<<Amg::toString(hitPos, 2)<< " gives pad (Eta, Phi): ("
112  <<padEta<<", "<<padPhi<<") out of range. Maximum Range: ("<< numPadEta()<<", "<<numPadPhi()<<").");
113  return std::make_pair(0, 0);
114  }
115  else {
116  return std::make_pair(padEta, padPhi);
117  }
118  }
119  inline double PadDesign::maxActiveX(const double locY) const {
120  if (std::abs(locY) > halfWidth()) {
121  ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" Local Y of the hit: "<<locY
122  <<" is out of range. Maximum range: "<<halfWidth());
123  return -1;
124  }
125  double halfSectorAngle = 0.5 * sectorAngle() * Gaudi::Units::deg;
126  if(yCutout()) {
127  if (locY > (halfWidth() - yCutout())) {
128  return longHalfHeight();
129  }
130  return longHalfHeight() + locY * std::tan(halfSectorAngle);
131  }
132  return longHalfHeight() - (halfWidth() - locY) * std::tan(halfSectorAngle);
133  }
134  inline double PadDesign::sectorAngle() const {
135  double sectorAngle = 2 * std::atan2(shortHalfHeight(), (beamlineRadius() - halfWidth())) / Gaudi::Units::deg;;
136  if (sectorAngle > (m_largeSectorAngle - 5) && sectorAngle < (m_largeSectorAngle + 5)) {
137  return m_largeSectorAngle;
138  }
139  else if (sectorAngle > (m_smallSectorAngle - 5) && sectorAngle < (m_smallSectorAngle + 5)) {
140  return m_smallSectorAngle;
141  }
142  else {
143  ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" Dimensions of the given gasGap result into invalid sector opening angle: "<<
144  sectorAngle<<" angle should be around 17 for small and 28 for large sector.");
145  return 0;
146  }
147  }
148 }
149 #endif