ATLAS Offline Software
Loading...
Searching...
No Matches
MuonDetDescr/MuonReadoutGeometry/src/TgcReadoutElement.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <GaudiKernel/IMessageSvc.h>
8#include <cassert>
9#include <cstdlib>
10
11#include <cmath>
12#include <ostream>
13
15
17
23
24#define THROW_EXCEPT(MESSAGE) \
25 { \
26 std::stringstream except_sstr{}; \
27 except_sstr<<__FILE__<<":"<<__LINE__<<" ("; \
28 except_sstr<<idHelperSvc()->toString(identify())<<") "; \
29 except_sstr<<MESSAGE; \
30 throw std::runtime_error(except_sstr.str()); \
31 }
32
33namespace MuonGM {
34
35 TgcReadoutElement::TgcReadoutElement(GeoVFullPhysVol* pv, const std::string& stName, MuonDetectorManager* mgr) :
36 MuonClusterReadoutElement(pv, mgr, Trk::DetectorElemType::Tgc) {
37 setStationName(stName);
38 // get the setting of the caching flag from the manager
39 }
40 void TgcReadoutElement::setPlaneZ(double value, int gasGap) { m_gasPlaneZ[gasGap - 1] = value; }
41 void TgcReadoutElement::setReadOutName(const std::string& rName) { m_readout_name = rName; }
42 void TgcReadoutElement::setReadOutParams(GeoModel::TransientConstSharedPtr <TgcReadoutParams> pars) {
43 m_readoutParams = std::move(pars);
44 }
45 void TgcReadoutElement::setFrameThickness(const double frameH, const double frameAB) {
46 m_frameH = frameH;
47 m_frameAB = frameAB;
48 }
50 return m_gasPlaneZ[gg - 1] * Amg::Vector3D::UnitX();
51 }
52
53 double TgcReadoutElement::length() const { return getRsize() - 2. * frameZwidth(); }
54 double TgcReadoutElement::frameZwidth() const { return m_frameH; }
55 double TgcReadoutElement::frameXwidth() const { return m_frameAB; }
56 double TgcReadoutElement::wireGangBottomX(int gasGap, int gang) const {
57#ifndef NDEBUG
58 if (!validGang(gasGap, gang)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & wire gang "<<gang<<" given.");
59#endif
60 return wireGangLocalX(gasGap, gang) - 0.5* gangRadialLength(gasGap, gang);
61 }
62
63 double TgcReadoutElement::wireGangTopX(int gasGap, int gang) const {
64#ifndef NDEBUG
65 if (!validGang(gasGap, gang)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & wire gang "<<gang<<" given.");
66#endif
67 return wireGangLocalX(gasGap, gang) + 0.5 * gangRadialLength(gasGap, gang);
68 }
69
70 // Access to wire gang dimensions (simple trapezoid with length along z)
71
72 double TgcReadoutElement::gangRadialLength(int gasGap, int gang) const {
73#ifndef NDEBUG
74 if (!validGang(gasGap, gang)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & wire gang "<<gang<<" given.");
75#endif
76 return wirePitch() * nWires(gasGap, gang);
77 }
78
79 double TgcReadoutElement::gangShortWidth(int gasGap, int gang) const {
80#ifndef NDEBUG
81 if (!validGang(gasGap, gang)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & wire gang "<<gang<<" given.");
82#endif
83 return chamberWidth(wireGangBottomX(gasGap, gang)) - frameXwidth() * 2.;
84 }
85
86 double TgcReadoutElement::gangLongWidth(int gasGap, int gang) const {
87#ifndef NDEBUG
88 if (!validGang(gasGap, gang)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & wire gang "<<gang<<" given.");
89#endif
90 return chamberWidth(wireGangTopX(gasGap, gang)) - frameXwidth() * 2.;
91 }
92 double TgcReadoutElement::gangCentralWidth(int gasGap, int gang) const {
93#ifndef NDEBUG
94 if (!validGang(gasGap, gang)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & wire gang "<<gang<<" given.");
95#endif
96 return chamberWidth(wireGangLocalX(gasGap, gang)) - frameXwidth() * 2.;
97 }
98
100 // number of strips in exclusive phi coverage of a chamber in T[1-3] and T4
101 constexpr std::array<double, 4> nDivInChamberPhi{29.5, 29.5, 29.5, 31.5};
102 double dphi{0.};
103
104 int iStation = CxxUtils::atoi(&getStationType()[1]);
105 if (iStation != 4 || getStationType()[2] != 'E') { // except for station T4E
106 dphi = 360. * CLHEP::degree / (nPhiChambers()) / nDivInChamberPhi[iStation - 1];
107 } else { // T4E
108 dphi = 360. * CLHEP::degree / 36. / nDivInChamberPhi[iStation - 1];
109 }
110 return dphi;
111 }
112
113 double TgcReadoutElement::stripDeltaPhi(int gasGap, int strip) const {
114 double dphi = stripDeltaPhi();
115 // half strip
116 if ((strip >= 31 && ((getStationEta() > 0 && gasGap == 1) || (getStationEta() < 0 && gasGap != 1))) ||
117 (strip <= 2 && ((getStationEta() > 0 && gasGap != 1) || (getStationEta() < 0 && gasGap == 1))))
118 dphi = dphi / 2.;
119
120 return dphi;
121 }
122
123 double TgcReadoutElement::stripCenterLocX(int gasGap, int strip, double z) const {
124#ifndef NDEBUG
125 if (!validStrip(gasGap, strip)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & strip "<<strip<<" given.");
126#endif
127 const auto [flip, pickStrip] = stripNumberToFetch(gasGap, strip);
128 return flip * stripLocalX(gasGap, pickStrip, z, m_readoutParams->stripCenter(pickStrip, gasGap));
129 }
130 double TgcReadoutElement::stripLowEdgeLocX(int gasGap, int strip, double z) const {
131#ifndef NDEBUG
132 if (!validStrip(gasGap, strip)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & wire strip "<<strip<<" given.");
133#endif
134 const auto [flip, pickStrip] = stripNumberToFetch(gasGap, strip);
135 ATH_MSG_VERBOSE(__func__<<"() "<<idHelperSvc()->toStringDetEl(identify())
136 <<", gasGap: "<<gasGap<<", strip: "<<strip<<", pickStrip: "<<pickStrip);
137 return flip * stripLocalX(gasGap, pickStrip, z, 0.5*(stripPosOnLargeBase(pickStrip, gasGap) + stripPosOnShortBase(pickStrip, gasGap)));
138 }
139
140 double TgcReadoutElement::stripHighEdgeLocX(int gasGap, int strip, double z) const {
141#ifndef NDEBUG
142 if (!validStrip(gasGap, strip)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & strip "<<strip<<" given.");
143#endif
144 const int nextStrip = strip +1;
145 auto [flip, pickStrip] = stripNumberToFetch(gasGap, nextStrip);
146 pickStrip += (nextStrip != pickStrip);
147 ATH_MSG_VERBOSE(__func__<<"() "<<idHelperSvc()->toStringDetEl(identify())
148 <<", gasGap: "<<gasGap<<", strip: "<<strip<<", pickStrip: "<<pickStrip);
149 return flip * stripLocalX(gasGap, pickStrip, z, 0.5*(stripPosOnLargeBase(pickStrip, gasGap) + stripPosOnShortBase(pickStrip, gasGap)));
150 }
151
152 double TgcReadoutElement::stripWidth(int gasGap, int strip) const {
154 return std::abs(stripShortWidth(gasGap, strip) + stripLongWidth(gasGap, strip)) / 2.;
155 }
156 double TgcReadoutElement::stripShortWidth(int gasGap, int strip) const {
157 // projection of strip on local X axis at min(Z)
158#ifndef NDEBUG
159 if (!validStrip(gasGap, strip)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & strip "<<strip<<" given.");
160#endif
161 if ((getStationEta() > 0 && gasGap == 1) || (getStationEta() < 0 && gasGap != 1) || m_readoutParams->nStripLayers() > 1) {
162 return stripPosOnShortBase(strip + 1, gasGap) - stripPosOnShortBase(strip, gasGap);
163 } else {
164 return -(stripPosOnShortBase(33 - strip, gasGap) - stripPosOnShortBase(33 - (strip - 1), gasGap));
165 }
166 }
167
168 double TgcReadoutElement::stripLongWidth(int gasGap, int strip) const {
169 // projection of strip on local X axis at max(Z)
170#ifndef NDEBUG
171 if (!validStrip(gasGap, strip)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & strip "<<strip<<" given.");
172#endif
173
174 if ((getStationEta() > 0 && gasGap == 1) || (getStationEta() < 0 && gasGap != 1) || m_readoutParams->nStripLayers() > 1) {
175 return stripPosOnLargeBase(strip + 1, gasGap) - stripPosOnLargeBase(strip, gasGap);
176 } else {
177 return -(stripPosOnLargeBase(33 - strip, gasGap) - stripPosOnLargeBase(33 - (strip - 1), gasGap));
178 }
179 }
180
181
182 double TgcReadoutElement::stripPitch(int gasGap, int strip) const {
183 return stripPitch(gasGap, strip, 0.);
184 }
185
186 double TgcReadoutElement::stripPitch(int gasGap, int strip, double z) const {
188 #ifndef NDEBUG
189 if (!validStrip(gasGap, strip)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" & strip "<<strip<<" given.");
190 #endif
191 if (1 < strip && strip < 32) {
192 double stripCurrCen = stripCenterLocX(gasGap, strip, z);
193 double stripNextCen = stripCenterLocX(gasGap, strip + 1, z);
194 double stripPrevCen = stripCenterLocX(gasGap, strip - 1, z);
195 return std::max(stripNextCen - stripCurrCen , stripCurrCen - stripPrevCen);
196 } else if (strip == 1) {
197 return stripCenterLocX(gasGap, strip + 1, z) - stripCenterLocX(gasGap, strip, z);
198 } else if (strip == 32) {
199 return stripCenterLocX(gasGap, strip, z) - stripCenterLocX(gasGap, strip - 1, z);
200 }
201 return 0.;
202 }
203
204 // Monte Carlo debug (returns strip or gang corresponding with the position)
205 int TgcReadoutElement::findGang(int gasGap, const Amg::Vector3D& localPos) const {
206#ifndef NDEBUG
207 if (!validGap(gasGap)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" given.");
208#endif
209 double z = localPos.z();
210 for (int gang = 1; gang <= nWireGangs(gasGap); ++gang) {
211 if (z < wireGangTopX(gasGap, gang)) return gang;
212 }
213 return nWireGangs(gasGap);
214 }
215
216 int TgcReadoutElement::findStrip(int gasGap, const Amg::Vector3D& localPos) const {
217#ifndef NDEBUG
218 if (!validGap(gasGap)) THROW_EXCEPT("Invalid gasGap "<<gasGap<<" given.");
219#endif
220 double x = localPos.x();
221 double z = localPos.z();
222 for (int strip = 1; strip <= nStrips(gasGap); ++strip) {
223 if (stripLowEdgeLocX(gasGap, strip, z) < x && x < stripHighEdgeLocX(gasGap, strip, z)) return strip;
224 }
225 return nStrips(gasGap);
226 }
227
228 bool TgcReadoutElement::validGap(int gasGap) const {
229 bool isValid = (1 <= gasGap && gasGap <= nGasGaps());
230 if (!isValid) {
231 ATH_MSG_WARNING( " gas gap is out of range; limits are 1-" << nGasGaps() );
232 }
233 return isValid;
234 }
235
236 bool TgcReadoutElement::validGang(int gasGap, int gang) const {
237 return validGap(gasGap) && (1 <= gang && gang <= (nWireGangs(gasGap) + 1));
238 }
239
240 bool TgcReadoutElement::validStrip(int gasGap, int strip) const {
241 return validGap(gasGap) && (1 <= strip && strip <= nStrips(gasGap));
242 }
243
245 if (m_surfaceData) {
246 ATH_MSG_WARNING( "calling fillCache on an already filled cache" );
247 return;
248 }
249 m_surfaceData = std::make_unique<SurfaceData>();
251 m_locMinPhi = -std::atan2((getLongSsize() - getSsize()) / 2, length());
252 m_locMaxPhi = std::atan2((getLongSsize() - getSsize()) / 2, length());
253
254 // loop over all gas gaps
255 for (int gp = 1; gp <= nGasGaps(); ++gp) {
256 // loop over phi/eta projections
257 for (bool isStrip : {false, true}) {
258 Identifier id = m_idHelper.channelID(identify(), gp, isStrip, 1);
259 const Amg::Translation3D xfp{localGasGapPos(gp)};
260 Amg::Transform3D trans3D = absTransform() * xfp;
261 Amg::RotationMatrix3D muonTRotation(trans3D.rotation());
262 Amg::RotationMatrix3D surfaceTRotation{Amg::RotationMatrix3D::Identity()};
263 surfaceTRotation.col(0) = muonTRotation.col(1);
264 surfaceTRotation.col(1) = muonTRotation.col(2);
265 surfaceTRotation.col(2) = muonTRotation.col(0);
266 Amg::Transform3D trans(surfaceTRotation);
267 if (!isStrip) trans = trans * Amg::getRotateZ3D(M_PI / 2);
268 Amg::Translation3D t(trans3D.translation());
269 trans.pretranslate(trans3D.translation());
270 m_surfaceData->m_layerTransforms.push_back(std::move(trans));
271 m_surfaceData->m_layerSurfaces.emplace_back(std::make_unique<Trk::PlaneSurface>(*this, id));
272
273 if (isStrip) {
274 m_surfaceData->m_layerCenters.push_back(m_surfaceData->m_layerTransforms.back().translation());
275 m_surfaceData->m_layerNormals.push_back(m_surfaceData->m_layerTransforms.back().linear() * Amg::Vector3D::UnitZ());
276 }
277 }
278 }
279
280 m_surfaceData->m_surfBounds.emplace_back(std::make_unique<Trk::TrapezoidBounds>(getSsize() / 2.,
281 getLongSsize() / 2.,
282 getRsize() / 2.)); // phi measurement
283 m_surfaceData->m_surfBounds.emplace_back(std::make_unique<Trk::RotatedTrapezoidBounds>(getRsize() / 2.,
284 getSsize() / 2.,
285 getLongSsize() / 2.)); // eta measurement
286 }
287
289 int gasGap = m_idHelper.gasGap(id);
290 if (gasGap < 1 || gasGap > nGasGaps()) return false;
291
292 int isStrip = m_idHelper.isStrip(id);
293 int ch = m_idHelper.channel(id);
294 if (isStrip == 0) {
295 if (ch < 1 || ch > nWireGangs(gasGap)) return false;
296 } else if (isStrip == 1) {
297 if (ch < 1 || ch > nStrips(gasGap)) return false;
298 } else
299 return false;
300
301 return true;
302 }
303
305 THROW_EXCEPT("distanceToReadout() -- method not implemented");
306 return 0.;
307 }
309 THROW_EXCEPT("stripNumber() -- method not implemented");
310 return 0. ;
311 }
314 Amg::Vector3D gpos = channelPos(id);
315 if (!surface(id).globalToLocal(gpos, gpos, pos)) {
316 ATH_MSG_WARNING( " stripPosition:: globalToLocal failed " <<Amg::toString(surface(id).transform().inverse() * gpos,2));
317 return false;
318 }
319 return true;
320 }
322 const Amg::Vector3D& etaHitPos,
323 const Amg::Vector3D& phiHitPos) const {
324
325
326 const Amg::Transform3D globToLoc{transform(stripId).inverse()};
327 const Amg::Vector3D lEtaHitPos = globToLoc * etaHitPos;
328 const Amg::Vector3D lPhiHitPos = globToLoc * phiHitPos;
329 const Amg::Vector3D phiHitDir = localStripDir(stripId);
330
331 ATH_MSG_VERBOSE("local space piont 2D "<<idHelperSvc()->toString(stripId)
332 <<"eta hit: "<<Amg::toString(lEtaHitPos)<<" phi hit:"<<Amg::toString(lPhiHitPos)
333 <<"phi dir: "<<Amg::toString(phiHitDir));
334 return lPhiHitPos +
335 Amg::intersect<3>(lEtaHitPos, Amg::Vector3D::UnitX(), lPhiHitPos, phiHitDir).value_or(0) * phiHitDir;
336
337 }
338 bool TgcReadoutElement::spacePointPosition(const Identifier& phiId, const Identifier& etaId, Amg::Vector2D& pos) const {
339 Amg::Vector3D gpos{Amg::Vector3D::Zero()};
340 if (!spacePointPosition(phiId, etaId, gpos) ||
341 !surface(phiId).globalToLocal(gpos, gpos, pos)) {
342 ATH_MSG_WARNING( " stripPosition:: globalToLocal failed " << Amg::toString(surface(phiId).transform().inverse() * gpos,2));
343 return false;
344 }
345 return true;
346 }
347 bool TgcReadoutElement::spacePointPosition(const Identifier& phiId, const Identifier& etaId, Amg::Vector3D& pos) const {
348 // get orientation angle of strip to rotate back from local frame to strip
349 if (nStrips(m_idHelper.gasGap(phiId)) <= 1) {
350 ATH_MSG_VERBOSE("No strips defined for plane "<<idHelperSvc()->toString(phiId));
351 pos = Amg::Vector3D::Zero();
352 return false;
353 }
354 pos = transform(phiId) * localSpacePoint(phiId, channelPos(etaId), channelPos(phiId));
355 return true;
356 }
357
358} // namespace MuonGM
359#undef THROW_EXCEPT
#define M_PI
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition AtlasPID.h:878
#define x
#define z
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
std::unique_ptr< SurfaceData > m_surfaceData
MuonClusterReadoutElement(GeoVFullPhysVol *pv, MuonDetectorManager *mgr, Trk::DetectorElemType detType)
virtual const Amg::Transform3D & transform() const override
Return local to global transform.
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
Identifier identify() const override final
Returns the ATLAS Identifier of the MuonReadOutElement.
int findGang(int gasGap, const Amg::Vector3D &extPos) const
Returns the gang number that's closest to the given external position.
GeoModel::TransientConstSharedPtr< TgcReadoutParams > m_readoutParams
int nWireGangs(int gasGap) const
Returns the number of wire gangs (Random grouping of wires) in a given gas gap.
void setReadOutParams(GeoModel::TransientConstSharedPtr< TgcReadoutParams > pars)
void setFrameThickness(const double frameH, const double frameAB)
virtual double distanceToReadout(const Amg::Vector2D &pos, const Identifier &id) const override
distance to readout.
virtual bool stripPosition(const Identifier &id, Amg::Vector2D &pos) const override
strip position If the strip number is outside the range of valid strips, the function will return fal...
std::pair< double, int > stripNumberToFetch(int gasGap, int inStrip) const
Returns whether a strip needs to be flipped and the final strip number parsed to the TgcReadoutParams...
Amg::Vector3D channelPos(const Identifier &id) const
Returns the position of the active channel (wireGang or strip)
double stripLocalX(const int gasGap, const int stripNum, const double locY, const double refPoint) const
Returns the local X given the reference point E.g.
double stripHighEdgeLocX(int gasGap, int strip, double radialPos) const
Returns the local X of the right edge of the strip at a given local radial position.
int findStrip(int gasGap, const Amg::Vector3D &extPos) const
Returns the strip number that's closest to the given external position.
double stripPitch(int gasGap, int strip) const
Returns the pitch of the given strip in gasGap i.
virtual bool spacePointPosition(const Identifier &phiId, const Identifier &etaId, Amg::Vector2D &pos) const override
space point position for a given pair of phi and eta identifiers The LocalPosition is expressed in th...
double stripPosOnShortBase(int strip, int gasGap) const
virtual int stripNumber(const Amg::Vector2D &pos, const Identifier &id) const override final
strip number corresponding to local position.
double gangShortWidth(int gasGap, int gang) const
Returns the length of the most bottom wire in the gang.
double chamberWidth(double z) const
double wireGangLocalX(const int gasGap, const int gangNum) const
Returns the local X of the wire gang in gasGap i.
bool validStrip(int gasGap, int strip) const
Returns whether the strip in the given gasgap is within the allowed range.
double gangCentralWidth(int gasGap, int gang) const
Returns the length of the central wire in the gang.
Amg::Vector3D localSpacePoint(const Identifier &stripId, const Amg::Vector3D &etaHitPos, const Amg::Vector3D &phiHitPos) const
double stripWidth(int gasGap, int strip) const
Returns the width of a given strip in the gasGap i.
double stripPosOnLargeBase(int strip, int gasGap) const
Amg::Vector3D localStripDir(int gasGap, int strip) const
Returns the local strip direction of a strip.
double stripLowEdgeLocX(int gasGap, int strip, double radialPos) const
Returns the local X of the left edge of the strip at a given local radial position.
TgcReadoutElement(GeoVFullPhysVol *pv, const std::string &stName, MuonDetectorManager *mgr)
double gangLongWidth(int gasGap, int gang) const
Returns the length of the most top wire in the gang.
double stripCenterLocX(int gasGap, int strip, double radialPos) const
Returns the local X of the strip center at a given local radial position.
double gangRadialLength(int gasGap, int gang) const
Returns the length of the wire gang along the radial direction [pitch x N_{wire}^{gang}...
int nGasGaps() const
Returns the number of gas gaps associated with the readout element (2 or 3)
int nWires(int gasGap) const
Returns the total number of wires in a given gas gap.
bool validGang(int gasGap, int wireGang) const
Returns whether the wire gang in the given gasgap is within the allowed range.
double wireGangTopX(int gasGap, int gangNum) const
Returns the local X of the top wire in the wireGang i in gasGap j.
Amg::Vector3D localGasGapPos(int gg) const
Returns the local position of the gasGap in the AMDB coordinate system.
double physicalDistanceFromBase() const
double wireGangBottomX(int gasGap, int gangNum) const
Returns the local X of the bottom wire in the wireGang i in gasGap j.
int nStrips(int gasGap) const
Returns the number of strips in a given gas gap.
virtual bool containsId(const Identifier &id) const override
void setPlaneZ(double value, int gasGap)
Set the local Z coordinate of the i-th gasGap [1-3].
double wirePitch() const
Returns the pitch of the wires.
bool validGap(int gasGap) const
Returns whether the gasGap is within the allowed range [1-nGasGaps()].
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 3, 3 > RotationMatrix3D
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Eigen::Translation< double, 3 > Translation3D
int atoi(std::string_view str)
Helper functions to unpack numbers decoded in string into integers and doubles The strings are requir...
Ensure that the Athena extensions are properly loaded.
Definition GeoMuonHits.h:27
Ensure that the ATLAS eigen extensions are properly loaded.