2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
4 #ifndef MUONREADOUTGEOMETRYR4_PADDESIGN_ICC
5 #define MUONREADOUTGEOMETRYR4_PADDESIGN_ICC
7 #include <MuonReadoutGeometryR4/PadDesign.h>
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;
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);
34 return std::make_pair(padEta, padPhi);
36 inline int PadDesign::padEta(const int channel) const {
37 return padEtaPhi(channel).first;
39 inline int PadDesign::padPhi(const int channel) const {
40 return padEtaPhi(channel).second;
42 inline double PadDesign::beamlineRadius() const {
46 using localCornerArray = std::array<Amg::Vector2D, 4>;
47 inline localCornerArray PadDesign::padCorners(const int channel) const {
48 return padCorners(padEtaPhi(channel));
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();
56 localCornerArray Corners = padCorners(channel);
57 Amg::Vector2D padCenter = 0.25 * (Corners[botLeft] + Corners[botRight] + Corners[topLeft] + Corners[topRight]);
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.};
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;
86 ATH_MSG_WARNING("The failed Hit: "<< Amg::toString(hitPos, 2) << " is outside the trapezoid bounds. "<< "HitY: " << hitY);
88 /// Variables to store padPhi information
89 double padPhiDouble{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);
99 padPhiDouble = (shiftedLocPhi - firstPadPhiDiv()) / anglePadPhi();
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);
116 return std::make_pair(padEta, padPhi);
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());
125 double halfSectorAngle = 0.5 * sectorAngle() * Gaudi::Units::deg;
127 if (locY > (halfWidth() - yCutout())) {
128 return longHalfHeight();
130 return longHalfHeight() + locY * std::tan(halfSectorAngle);
132 return longHalfHeight() - (halfWidth() - locY) * std::tan(halfSectorAngle);
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;
139 else if (sectorAngle > (m_smallSectorAngle - 5) && sectorAngle < (m_smallSectorAngle + 5)) {
140 return m_smallSectorAngle;
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.");