2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
4 #ifndef MUONREADOUTGEOMETRYR4_STRIPDESIGN_ICC
5 #define MUONREADOUTGEOMETRYR4_STRIPDESIGN_ICC
7 #define SET_DIRECTION(METHOD, DIRVEC, FROM, TO) \
8 inline const Amg::Vector2D& StripDesign::METHOD() const { \
10 DIRVEC.set(std::make_unique<Amg::Vector2D>((TO-FROM).unit())); \
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; }
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)
33 inline double StripDesign::lenTopEdge() const {
34 return isFlipped() ? 2.*(longHalfHeight() + m_cutLongEdge): m_lenSlopEdge;
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(); }
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();
54 inline CheckVector2D StripDesign::leftInterSect(int stripCh, bool uncapped) const {
55 /// Nominal strip position position
56 return leftInterSect(stripPosition(stripCh), uncapped);
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()) {
63 /// We expect lambda to be positive
64 const std::optional<double> lambda = Amg::intersect<2>(stripPos, m_stripDir, cornerTopLeft(), edgeDirTop());
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));
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));
84 return std::make_optional<Amg::Vector2D>(edgePos + (*top_line) * edgeDir);
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());
91 return std::make_optional<Amg::Vector2D>(std::move(isect));
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());
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));
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 ");
113 return std::make_optional<Amg::Vector2D>(edgePos + (*bottom_line) * edgeDir);
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());
120 return std::make_optional<Amg::Vector2D>(std::move(isect));
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()<<"]");
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");
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);
142 inline CheckVector2D StripDesign::rightInterSect(int stripCh, bool uncapped) const {
143 return rightInterSect(stripPosition(stripCh), uncapped);
146 inline CheckVector2D StripDesign::stripCenter(int stripCh) const {
147 CheckVector2D botIsect{}, topIsect{};
148 if (!(botIsect = leftInterSect(stripCh)) || !(topIsect = rightInterSect(stripCh))){
151 return std::make_optional<Amg::Vector2D>(0.5 *(std::move(*botIsect) + std::move(*topIsect)));
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()<<"]");
161 CheckVector2D cen{stripCenter(stripCh)};
162 if (!cen) return std::nullopt;
163 return std::make_optional<Amg::Vector2D>(m_etaToStereo * std::move(*cen));
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()<<"]");
172 CheckVector2D iSect{leftInterSect(stripCh)};
173 if (!iSect) return std::nullopt;
174 return std::make_optional<Amg::Vector2D>(m_etaToStereo * std::move(*iSect));
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()<<"]");
183 CheckVector2D iSect{rightInterSect(stripCh)};
184 if (!iSect) return std::nullopt;
185 return std::make_optional<Amg::Vector2D>(m_etaToStereo * std::move(*iSect));
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();
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());
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()<<".");
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());
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()));
218 return chNum + firstStripNumber();
221 inline bool StripDesign::insideTrapezoid(const Amg::Vector2D& extPos) const {
222 return insideBoundaries(m_stereoToEta * extPos);
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;