ATLAS Offline Software
StripDesign.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_STRIPDESIGN_ICC
5 #define MUONREADOUTGEOMETRYR4_STRIPDESIGN_ICC
6 
7 #define SET_DIRECTION(METHOD, DIRVEC, FROM, TO) \
8  inline const Amg::Vector2D& StripDesign::METHOD() const { \
9  if (!DIRVEC) { \
10  DIRVEC.set(std::make_unique<Amg::Vector2D>((TO-FROM).unit())); \
11  } \
12  return (*DIRVEC); \
13  }
14 
15 namespace MuonGMR4 {
16  using CheckVector2D = StripDesign::CheckVector2D;
17  inline const Amg::Vector2D& StripDesign::cornerBotLeft() const { return m_bottomLeft; }
18  inline const Amg::Vector2D& StripDesign::cornerBotRight() const { return m_bottomRight; }
19  inline const Amg::Vector2D& StripDesign::cornerTopLeft() const { return m_topLeft; }
20  inline const Amg::Vector2D& StripDesign::cornerTopRight() const { return m_topRight; }
21  inline const Amg::Vector2D& StripDesign::stripNormal() const { return m_stripNormal; }
22  inline const Amg::Vector2D& StripDesign::stripDir() const { return m_stripDir; }
23  inline const Amg::Vector2D& StripDesign::firstStripPos() const { return m_firstStripPos; }
24 
25 /// Additional Functions for Diamonds
26  inline double StripDesign::yCutout() const { return m_yCutout; }
27 /// ==============================================================================================
28  SET_DIRECTION(edgeDirTop, m_dirTopEdge, m_topLeft, m_topRight)
29  SET_DIRECTION(edgeDirBottom, m_dirBotEdge, m_bottomLeft, m_bottomRight)
30  SET_DIRECTION(edgeDirLeft, m_dirLeftEdge, m_topLeft, m_bottomLeft)
31  SET_DIRECTION(edgeDirRight, m_dirRightEdge, m_topRight, m_bottomRight)
32 
33  inline double StripDesign::lenTopEdge() const {
34  return isFlipped() ? 2.*(longHalfHeight() + m_cutLongEdge): m_lenSlopEdge;
35  }
36  inline double StripDesign::lenLeftEdge() const {return isFlipped() ? m_lenSlopEdge : 2.* shortHalfHeight();}
37  inline double StripDesign::lenBottomEdge() const { return isFlipped() ? 2.* shortHalfHeight() : m_lenSlopEdge; }
38  inline double StripDesign::lenRightEdge() const{ return isFlipped() ? m_lenSlopEdge : 2.* longHalfHeight(); }
39 
40  inline double StripDesign::stripPitch() const { return m_stripPitch; }
41  inline double StripDesign::stripWidth() const { return m_stripWidth; }
42  inline double StripDesign::halfWidth() const { return m_halfX; }
43  inline double StripDesign::shortHalfHeight() const { return m_shortHalfY; }
44  inline double StripDesign::longHalfHeight() const { return m_longHalfY; }
45  inline int StripDesign::numStrips() const { return m_numStrips; }
46  inline bool StripDesign::hasStereoAngle() const { return m_hasStereo; }
47  inline bool StripDesign::isFlipped() const { return m_isFlipped; }
48  inline double StripDesign::stereoAngle() const {return m_stereoAngle; }
49  inline int StripDesign::firstStripNumber() const { return m_channelShift; }
50  inline Amg::Vector2D StripDesign::stripPosition(int stripCh) const {
51  return m_firstStripPos + (1.*stripCh) * stripPitch() * Amg::Vector2D::UnitX();
52  }
53 
54  inline CheckVector2D StripDesign::leftInterSect(int stripCh, bool uncapped) const {
55  /// Nominal strip position position
56  return leftInterSect(stripPosition(stripCh), uncapped);
57  }
58  inline CheckVector2D StripDesign::leftInterSect(const Amg::Vector2D& stripPos, bool uncapped) const {
59  /// Flipped diamonds may not exceed the halfLength along the x-coordinate
60  if (yCutout() && isFlipped() && std::abs(stripPos.x()) > longHalfHeight()) {
61  return std::nullopt;
62  }
63  /// We expect lambda to be positive
64  const std::optional<double> lambda = Amg::intersect<2>(stripPos, m_stripDir, cornerTopLeft(), edgeDirTop());
65  if (!lambda) {
66  ATH_MSG_WARNING("The strip "<<Amg::toString(stripPos, 2)
67  <<" does not intersect the top edge "<<Amg::toString(cornerTopLeft(), 2)
68  <<" + lambda "<<Amg::toString(edgeDirTop(), 2));
69  return std::nullopt;
70  }
71  /// If the channel is a stereo channel && lambda is either smaller than 0 or longer
72  /// than the bottom edge, then it's a routed strip
73  if (!uncapped && ((*lambda) < 0 || (*lambda) > lenTopEdge())) {
74  const bool pickLeft = (*lambda) < 0;
75  const Amg::Vector2D& edgePos{pickLeft ? cornerTopLeft() : cornerTopRight()};
76  const Amg::Vector2D& edgeDir{pickLeft ? edgeDirLeft() : edgeDirRight()};
77  const double edgeLen = pickLeft ? lenLeftEdge(): lenRightEdge();
78  const std::optional<double> top_line = Amg::intersect<2>(stripPos, m_stripDir, edgePos, edgeDir);
79  if (!top_line || (*top_line) <0. || (*top_line) > edgeLen) {
80  ATH_MSG_DEBUG(__func__<<"() The strip "<<Amg::toString(stripPos, 2)
81  <<" does not intersect with the edge "<<Amg::toString(edgePos));
82  return std::nullopt;
83  }
84  return std::make_optional<Amg::Vector2D>(edgePos + (*top_line) * edgeDir);
85  }
86  Amg::Vector2D isect = cornerTopLeft() + (*lambda) * edgeDirTop();
87  /// In case of diamonds, ensure that the trapezoid is cut on the upper half
88  if (!uncapped && yCutout() && !isFlipped()) {
89  isect.y() = std::min(isect.y(), longHalfHeight());
90  }
91  return std::make_optional<Amg::Vector2D>(std::move(isect));
92  }
93  inline CheckVector2D StripDesign::rightInterSect(const Amg::Vector2D& stripPos, bool uncapped) const {
94  std::optional<double> lambda = Amg::intersect<2>(stripPos, m_stripDir, cornerBotLeft(), edgeDirBottom());
95  if (!lambda) {
96  ATH_MSG_WARNING("The strip "<<Amg::toString(stripPos,2)
97  <<" does not intersect the left edge "<<Amg::toString(cornerBotLeft(), 2)
98  <<" + lambda "<<Amg::toString(edgeDirBottom(), 2));
99  return std::nullopt;
100  }
101  /// If the channel is a stereo channel && lambda is either smaller than 0 or longer
102  /// than the bottom edge, then it's a routed strip
103  if (!uncapped && ( (*lambda) < 0 || (*lambda) > lenBottomEdge())) {
104  const bool selLeftEdge = (*lambda) < 0;
105  const Amg::Vector2D& edgePos{selLeftEdge ? cornerBotLeft() : cornerBotRight()};
106  const Amg::Vector2D& edgeDir{selLeftEdge ? edgeDirLeft() : edgeDirRight()};
107  const double edgeLen{selLeftEdge ? lenLeftEdge() : lenRightEdge()};
108  std::optional<double> bottom_line = Amg::intersect<2>(stripPos, m_stripDir, edgePos, edgeDir);
109  if (!bottom_line || (*bottom_line) > 0 || (*bottom_line) < -edgeLen) {
110  ATH_MSG_DEBUG("The strip "<<Amg::toString(stripPos, 2)<<" does not intersect with the left/right edges ");
111  return std::nullopt;
112  }
113  return std::make_optional<Amg::Vector2D>(edgePos + (*bottom_line) * edgeDir);
114  }
115  Amg::Vector2D isect = cornerBotLeft() + (*lambda) * edgeDirBottom();
116  /// In case of diamonds, ensure that the trapezoid is cut on the upper half
117  if (!uncapped && yCutout() && !isFlipped()) {
118  isect.y() = std::max(isect.y(), -longHalfHeight());
119  }
120  return std::make_optional<Amg::Vector2D>(std::move(isect));
121  }
122  //============================================================================
123  inline double StripDesign::stripLength(int stripNumber) const {
124  const int stripCh = (stripNumber - firstStripNumber());
125  if (stripCh < 0 || stripCh > numStrips()) {
126  ATH_MSG_WARNING("center() -- Invalid strip number given "<<stripNumber<<" allowed range ["
127  <<firstStripNumber()<<";"<<numStrips()<<"]");
128  return 0.;
129  }
130  const Amg::Vector2D strip{stripPosition(stripCh)};
131  CheckVector2D bottomIsect{}, topIsect{};
132  if (!(bottomIsect = rightInterSect(strip)) || !(topIsect = leftInterSect(strip))) {
133  ATH_MSG_WARNING("The strip "<<Amg::toString(strip)<<" is outside of the trapezoid");
134  return 0;
135  }
136  const Amg::Vector2D delta = (*bottomIsect) - (*topIsect);
137  double stripLen = std::hypot(delta.x(), delta.y());
138  ATH_MSG_VERBOSE("Strip "<<stripNumber<<" right edge: "<<Amg::toString((*bottomIsect), 2)
139  <<" left edge: "<<Amg::toString( (*topIsect),2)<<" length: "<<stripLen);
140  return stripLen;
141  }
142  inline CheckVector2D StripDesign::rightInterSect(int stripCh, bool uncapped) const {
143  return rightInterSect(stripPosition(stripCh), uncapped);
144  }
145 
146  inline CheckVector2D StripDesign::stripCenter(int stripCh) const {
147  CheckVector2D botIsect{}, topIsect{};
148  if (!(botIsect = leftInterSect(stripCh)) || !(topIsect = rightInterSect(stripCh))){
149  return std::nullopt;
150  }
151  return std::make_optional<Amg::Vector2D>(0.5 *(std::move(*botIsect) + std::move(*topIsect)));
152  }
153 
154  inline CheckVector2D StripDesign::center(int stripNumber) const {
155  const int stripCh = (stripNumber - firstStripNumber());
156  if (stripCh < 0 || stripCh >= numStrips()) {
157  ATH_MSG_WARNING("center() -- Invalid strip number given "<<stripNumber<<" allowed range ["
158  <<firstStripNumber()<<";"<<numStrips()<<"]");
159  return std::nullopt;
160  }
161  CheckVector2D cen{stripCenter(stripCh)};
162  if (!cen) return std::nullopt;
163  return std::make_optional<Amg::Vector2D>(m_etaToStereo * std::move(*cen));
164  }
165  inline CheckVector2D StripDesign::leftEdge(int stripNumber) const {
166  const int stripCh = (stripNumber - firstStripNumber());
167  if (stripCh < 0 || stripCh >= numStrips()) {
168  ATH_MSG_WARNING("leftEdge() -- Invalid strip number given "<<stripNumber<<" allowed range ["
169  <<firstStripNumber()<<";"<<numStrips()<<"]");
170  return std::nullopt;
171  }
172  CheckVector2D iSect{leftInterSect(stripCh)};
173  if (!iSect) return std::nullopt;
174  return std::make_optional<Amg::Vector2D>(m_etaToStereo * std::move(*iSect));
175  }
176  inline CheckVector2D StripDesign::rightEdge(int stripNumber) const {
177  const int stripCh = (stripNumber - firstStripNumber());
178  if (stripCh < 0 || stripCh >= numStrips()) {
179  ATH_MSG_WARNING("rightEdge() -- Invalid strip number given "<<stripNumber<<" allowed range ["
180  <<firstStripNumber()<<";"<<numStrips()<<"]");
181  return std::nullopt;
182  }
183  CheckVector2D iSect{rightInterSect(stripCh)};
184  if (!iSect) return std::nullopt;
185  return std::make_optional<Amg::Vector2D>(m_etaToStereo * std::move(*iSect));
186  }
187  inline double StripDesign::distanceToStrip(const Amg::Vector2D& pos, int stripNumber) const {
188  CheckVector2D stripCent = center(stripNumber);
189  if (!stripCent) return std::numeric_limits<double>::max();
190  return (pos - (*stripCent)).x();
191  }
192  inline int StripDesign::stripNumber(const Amg::Vector2D& extPos) const {
193  const Amg::Vector2D pos = m_stereoToEta * extPos;
194  std::optional<double> stripDist = Amg::intersect<2>(m_firstStripPos, stripDir(),
195  pos, -Amg::Vector2D::UnitX());
196  if (!stripDist) {
197  return -1;
198  }
199  if ((*stripDist) < -0.5*stripPitch()) {
200  ATH_MSG_VERBOSE("Object "<<Amg::toString(pos)<<" is way before the first strip "<<Amg::toString(m_firstStripPos)
201  <<" distance: "<<(*stripDist)<<", half-pitch: "<<0.5*stripPitch()<<".");
202  return -1;
203  }
204  const double stripPitches = std::abs((*stripDist) / stripPitch());
205  if (stripPitches > (1.*numStrips() - 0.5)) {
206  ATH_MSG_VERBOSE("Object "<<Amg::toString(pos)<<" is not covered by any strip."
207  <<" Virtual strip pitches: "<<stripPitches<<" max strips: "<<numStrips());
208  return -1;
209  }
210  const int chNum = std::min(static_cast<int>(std::round(stripPitches)), numStrips()-1);
211  if (!insideBoundaries(pos)){
212  ATH_MSG_VERBOSE("Object "<<Amg::toString(pos)<<" is outside the active area of the trapezoid. "
213  <<"Distance to strip: "<<stripNormal().dot(pos - (*stripCenter(chNum)))
214  <<","<<stripDir().dot(pos - (*stripCenter(chNum)))
215  <<" stripLength: "<<0.5*stripLength(chNum + firstStripNumber()));
216  return -1;
217  }
218  return chNum + firstStripNumber();
219  }
220 
221  inline bool StripDesign::insideTrapezoid(const Amg::Vector2D& extPos) const {
222  return insideBoundaries(m_stereoToEta * extPos);
223  }
224  inline bool StripDesign::insideBoundaries(const Amg::Vector2D& pos) const {
225  /// One needs to go backward to reach the bottom edge
226  CheckVector2D botIsect = rightInterSect(pos);
227  if (!botIsect || stripDir().dot(pos - (*botIsect)) < 0) return false;
228  CheckVector2D topIsect = leftInterSect(pos);
229  return topIsect && stripDir().dot(pos - (*topIsect)) < 0;
230  }
231 }
232 #undef SET_DIRECTION
233 #endif