ATLAS Offline Software
Loading...
Searching...
No Matches
MuonDetDescr/MuonReadoutGeometry/src/MdtReadoutElement.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5/***************************************************************************
6 The Mdt detector = a multilayer = MDT in amdb
7 ----------------------------------------------------
8 ***************************************************************************/
9
11
12#include <limits>
13#include <utility>
14
15#include "GeoModelKernel/GeoDefinitions.h"
16#include "GeoModelKernel/GeoTube.h"
20#include "GeoModelKernel/throwExcept.h"
21#include "GeoModelHelpers/TransformToStringConverter.h"
22#include "GeoModelHelpers/GeoShapeUtils.h"
23
31
33// From Dan Levin: MDT
34// linear density of wire: lambda=wireLinearDensity=19.3 [gm/cm^3] * PI*
35//(25 *10^-4 )^2 [CLHEP::cm^2] = 378.954 microgram/CLHEP::cm
36// From Dan Levin: MDT
37// wireTen=350 for most chambers, 285 gm for some NIKHEF chambers (BOL ?),
38
39#define verbose_Bline false
40// Typical b-line par values
41// m_bz = 0.01; // 10 microns
42// m_bp = 0.1; // 100 microns
43// m_bn = 0.1; // 100 microns
44// m_sp = 0.001; // 1 micron
45// m_sn = 0.001; // 1 micron
46// m_tw = 0.1; // 100 microns
47// m_pg = 0.1; // 100 microns
48// m_tr = 0.1; // 100 microns
49// m_eg = 1.0e-4; // 100 ppm
50// m_ep = 1.0e-5; // 10 ppm
51// m_en = 1.0e-5; // 10 ppm
52
53namespace {
54 // the tube number of a tube in a tubeLayer in encoded in the GeoSerialIdentifier (modulo maxNTubesPerLayer)
55 constexpr unsigned int const maxNTubesPerLayer = MdtIdHelper::maxNTubesPerLayer;
56} // namespace
57
58namespace MuonGM {
59
60 MdtReadoutElement::MdtReadoutElement(GeoVFullPhysVol* pv, const std::string& stName, MuonDetectorManager* mgr) :
61 MuonReadoutElement(pv, mgr, Trk::DetectorElemType::Mdt) {
62 // get the setting of the caching flag from the manager
63 m_inBarrel = stName[0]== 'B';
64
65 setStationName(stName);
66 }
68 void MdtReadoutElement::setNLayers(const int nl) { m_nlayers = nl; }
70 std::vector<const Trk::Surface*> MdtReadoutElement::surfaces() const {
71 std::vector<const Trk::Surface*> elementSurfaces;
72 elementSurfaces.reserve(m_tubeSurfaces.size() + 1);
73 if (m_associatedSurface) { elementSurfaces.push_back(m_associatedSurface.get()); }
74 for (const auto& s : m_tubeSurfaces) {
75 if (s) elementSurfaces.push_back(s.get());
76 }
77 return elementSurfaces;
78 }
79
80 bool MdtReadoutElement::getWireFirstLocalCoordAlongZ(int tubeLayer, double& coord) const {
81 coord = -9999.;
82 if (tubeLayer > getNLayers() || tubeLayer < 1) return false;
83 coord = m_firstwire_x[tubeLayer - 1];
84 return true;
85 }
86 bool MdtReadoutElement::getWireFirstLocalCoordAlongR(int tubeLayer, double& coord) const {
87 coord = -9999.;
88 if (tubeLayer > getNLayers() || tubeLayer < 1) return false;
89 coord = m_firstwire_y[tubeLayer - 1];
90 return true;
91 }
92
96
97 int ntot_steps = m_nsteps;
98 if (hasCutouts() && manager()->MinimalGeoFlag() == 0) { ntot_steps = m_nlayers * m_ntubesperlayer; }
99 m_tubeBounds.resize(ntot_steps);
100 }
101
102 double MdtReadoutElement::getTubeLengthForCaching(const int tubeLayer, const int tube) const {
103 double nominalTubeLength = 0.;
104 if (barrel())
105 nominalTubeLength = m_Ssize;
106 else {
107 int istep = int((tube - 1) / m_ntubesinastep);
108 if (istep < 0 || istep >= m_nsteps) {
109 ATH_MSG_WARNING( "getTubeLenght for Element with tech. " << getTechnologyType()
110 << " DEid = " << idHelperSvc()->toStringDetEl(identify()) << " called with: tubeL, tube " << tubeLayer << " " << tube
111 << "; step " << istep << " out of range 0-" << m_nsteps - 1 << " m_ntubesinastep " << m_ntubesinastep );
112 istep = 0;
113 }
114 nominalTubeLength = m_tubelength[istep];
115 }
116
117 double tlength = nominalTubeLength;
118
119 if (hasCutouts()) {
120 if (manager()->MinimalGeoFlag() == 0) {
121 ATH_MSG_VERBOSE( " MdtReadoutElement " <<idHelperSvc()->toStringDetEl(identify())
122 << " has cutouts, check for real tube length for tubeLayer, tube " << tubeLayer << " " << tube );
123 PVConstLink cv = getMaterialGeom(); // it is "Multilayer"
124 int nGrandchildren = cv->getNChildVols();
125 if (nGrandchildren <= 0) return tlength;
126 // child vol 0 is foam; 1 to (nGrandchildren-1) should be tubes
127 int ii = (tubeLayer - 1) * m_ntubesperlayer + tube;
128 // BIS78 only (the BIS7 of Run1/2 has no cutouts, thus, this block won't be reached)
129 if ((getStationIndex() == m_stIdx_BIS && std::abs(getStationEta()) == 7)) --ii;
130 if (m_idHelper.isBMG(identify())) {
131 // usually the tube number corresponds to the child number, however for
132 // BMG chambers full tubes are skipped during the building process
133 // therefore the matching needs to be done via the volume ID
134 int packed_id = tube + maxNTubesPerLayer * tubeLayer;
135 int kk = 0;
136 bool found = false;
137 geoGetIds(
138 [&](int id) {
139 if (!found && id == packed_id) {
140 ii = kk;
141 found = true;
142 }
143 ++kk;
144 }, cv);
145 if (found) {
146 ATH_MSG_DEBUG( " MdtReadoutElement tube match found for BMG - input : tube(" << tube << "), layer("
147 << tubeLayer << ") - output match : tube(" << ii % maxNTubesPerLayer << "), layer(" << ii / maxNTubesPerLayer
148 << ")" );
149 }
150 }
151 if (ii >= nGrandchildren) {
152 ATH_MSG_WARNING( " MdtReadoutElement " << idHelperSvc()->toStringDetEl(identify()) << " has cutouts, nChild = " << nGrandchildren
153 << " --- getTubeLength is looking for child with index ii=" << ii << " for tubeL and tube = " << tubeLayer << " "
154 << tube );
155 ATH_MSG_WARNING( "returning nominalTubeLength " );
156 return tlength;
157 }
158 if (ii < 0) {
159 ATH_MSG_WARNING( " MdtReadoutElement " << idHelperSvc()->toStringDetEl(identify()) << " has cutouts, nChild = " << nGrandchildren
160 << " --- getTubeLength is looking for child with index ii=" << ii << " for tubeL and tube = " << tubeLayer << " "
161 << tube );
162 ATH_MSG_WARNING( "returning nominalTubeLength " );
163 return tlength;
164 }
165 PVConstLink physChild = cv->getChildVol(ii);
166 const GeoShape* shape = physChild->getLogVol()->getShape();
167 if (shape == nullptr) return tlength;
168 const GeoTube* theTube = dynamic_cast<const GeoTube*>(shape);
169 if (theTube != nullptr)
170 tlength = 2. * theTube->getZHalfLength();
171 else
172 ATH_MSG_WARNING( "PhysChild with index " << ii
173 << " out of (tubeLayer-1)*m_ntubesperlayer+tube with tubeLayer=" << tubeLayer << " tubes/lay=" << m_ntubesperlayer
174 << " t=" << tube << " for MdtReadoutElement " << idHelperSvc()->toStringDetEl(identify()) );
175 }
176 if (std::abs(tlength - nominalTubeLength) > 0.1) {
177 ATH_MSG_VERBOSE( "Tube " << tube << " in tubeLayer = " << tubeLayer
178 << " is affected by a cutout: eff. length = " << tlength << " while nominal = " << nominalTubeLength
179 << " in station " << idHelperSvc()->toStringDetEl(identify()));
180 } else {
181 ATH_MSG_VERBOSE( "Tube " << tube << " in tubeLayer = " << tubeLayer
182 << " is NOT affected by the cutout: eff. length = " << tlength << " while nominal = " << nominalTubeLength);
183 }
184 }
185 return tlength;
186 }
187
188 double MdtReadoutElement::distanceFromRO(const Amg::Vector3D& x, int tubeLayer, int tube) const {
189 // x is given in the global reference frame
190 const Amg::Vector3D cPos = center(tubeLayer, tube);
191 const Amg::Vector3D roPos = ROPos(tubeLayer, tube);
192 const Amg::Vector3D c_ro = cPos - roPos;
193 const Amg::Vector3D x_ro = x - roPos;
194
195 double scalprod = c_ro.dot(x_ro);
196 double wlen = getWireLength(tubeLayer, tube);
197 if (wlen > 10. * CLHEP::mm)
198 scalprod = std::abs(2. * scalprod / getWireLength(tubeLayer, tube));
199 else {
200 ATH_MSG_WARNING( " Distance of Point " <<Amg::toString(x) << " from RO side cannot be calculated (=0) since wirelength = " << wlen );
201 scalprod = 0.;
202 }
203 return scalprod;
204 }
205
206 int MdtReadoutElement::isAtReadoutSide(const Amg::Vector3D& GlobalHitPosition, int tubeLayer, int tube) const {
207 double distance = distanceFromRO(GlobalHitPosition, tubeLayer, tube);
208 if (distance < 0) {
209 ATH_MSG_WARNING( "isAtReadoutSide() - GlobalHitPosition appears to be outside the tube volume " << distance );
210 return 1;
211 } else if (distance <= getWireLength(tubeLayer, tube) / 2.)
212 return 1;
213 else if (distance < getWireLength(tubeLayer, tube))
214 return -1;
215 else {
216 ATH_MSG_WARNING( "isAtReadoutSide() - GlobalHitPosition appears to be outside the tube volume " << distance );
217 return -1;
218 }
219 }
220 double MdtReadoutElement::RODistanceFromTubeCentre(const int tubeLayer, const int tube) const {
221 return getWireLength(tubeLayer, tube) / 2.;
222 }
223 double MdtReadoutElement::signedRODistanceFromTubeCentre(const int tubeLayer, const int tube) const {
224 // it is a signed quantity:
225 // the sign corresponds to the sign of the z coordinate of the RO endplug in the tube
226 // reference frame
227 int amdb_plus_minus1 = 1;
228 if (!m_zsignRO_tubeFrame.isValid()) {
229 const MuonStation* ms = parentMuonStation();
230 if (std::abs(ms->xAmdbCRO()) > 10.) {
231 Amg::Vector3D tem = ms->xAmdbCRO()* Amg::Vector3D::UnitX();
232 Amg::Transform3D amdbToGlobal{ms->getAmdbLRSToGlobal()};
233 Amg::Vector3D temGlo = amdbToGlobal * tem;
234 Amg::Vector3D ROtubeFrame = nodeform_globalToLocalTransf(tubeLayer, tube) * temGlo;
235 if (ROtubeFrame.z() < 0)
236 m_zsignRO_tubeFrame.set(-1);
237 else
238 m_zsignRO_tubeFrame.set(1);
239 }
240 }
241 // if no CRO in a chamber in AMDB (BIS in layout R), use the standard convention for RO-HV side
242 if (!m_zsignRO_tubeFrame.isValid()) {
243 int sign = 0;
244 if (barrel()) {
245 if (sideA()) {
246 if (largeSector())
247 sign = -1;
248 else
249 sign = 1;
250 } else {
251 if (largeSector())
252 sign = 1;
253 else
254 sign = -1;
255 }
256 // a special case is BIS in sector 12
257 if (getStationName().substr(0, 3) == "BIS" && getStationPhi() == 6) sign = -sign;
258 } else {
259 if (sideA()) {
260 if (largeSector())
261 sign = 1;
262 else
263 sign = -1;
264 } else {
265 if (largeSector())
266 sign = -1;
267 else
268 sign = 1;
269 }
270 }
272 }
273 amdb_plus_minus1 = *m_zsignRO_tubeFrame.ptr();
274 if (amdb_plus_minus1 == 0) {
275 ATH_MSG_WARNING( "Unable to get the sign of RO side; signedRODistancefromTubeCenter returns 0" );
276 }
277
278 return amdb_plus_minus1 * getWireLength(tubeLayer, tube) / 2.;
279 }
280 unsigned MdtReadoutElement::boundHash(const int tubeLayer, const int tube) const{
281 int istep = 0;
282 int ntot_steps = m_nsteps;
283
284 if (hasCutouts() && manager()->MinimalGeoFlag() == 0) {
285 ntot_steps = m_nlayers * m_ntubesperlayer;
286 istep = (tubeLayer - 1) * m_ntubesperlayer + tube - 1;
287 } else {
288 if (endcap()) istep = int((tube - 1) / m_ntubesinastep);
289
290 if (istep < 0 || istep >= ntot_steps) {
291 ATH_MSG_WARNING( "bounds for Element named "<< " with tech. " << getTechnologyType()
292 << " DEid = " << idHelperSvc()->toStringDetEl(identify()) << " called with: tubeL, tube " << tubeLayer << " " << tube
293 << "; step " << istep << " out of range 0-" << m_nsteps - 1 << " m_ntubesinastep " << m_ntubesinastep );
294 ATH_MSG_WARNING( "Please run in DEBUG mode to get extra diagnostic; setting istep = 0" );
295 }
296 }
297 if ((unsigned int)istep >= m_tubeBounds.size()) {
298 THROW_EXCEPTION(__func__<<"("<<tubeLayer<<","<<tube<<") but m_tubeBounds.size()="<<m_tubeBounds.size()<<" for "<<
299 idHelperSvc()->toStringDetEl(identify()));
300 }
301
302 return istep;
303 }
304
305 Amg::Vector3D MdtReadoutElement::tubeFrame_localROPos(const int tubeLayer, const int tube) const {
306 return signedRODistanceFromTubeCentre(tubeLayer, tube) * Amg::Vector3D::UnitZ();
307 }
308 Amg::Vector3D MdtReadoutElement::localROPos(const int tubeLayer, const int tube) const {
309 return tubeToMultilayerTransf(tubeLayer, tube) * tubeFrame_localROPos(tubeLayer, tube);
310 }
311 Amg::Vector3D MdtReadoutElement::ROPos(const int tubeLayer, const int tube) const {
312 return transform(tubeLayer, tube) * tubeFrame_localROPos(tubeLayer, tube);
313 }
314 Amg::Vector3D MdtReadoutElement::localTubePos(const int tubeLayer, const int tube) const {
315 return fromIdealToDeformed(tubeLayer, tube) * nodeform_localTubePos(tubeLayer, tube);
316 }
317
318 Amg::Vector3D MdtReadoutElement::nodeform_localTubePos(const int tubeLayer, const int tube) const {
319 ATH_MSG_VERBOSE( " Computing LocalTubePos for "<< idHelperSvc()->toStringDetEl(identify())
320 << "/" << tubeLayer << "/" << tube );
321 double xtube{0.}, ytube{0.}, ztube{0.};
322 if (barrel()) {
323 xtube = -m_Rsize / 2. + m_firstwire_y[tubeLayer - 1];
324 ztube = -m_Zsize / 2. + m_firstwire_x[tubeLayer - 1] + (tube - 1) * m_tubepitch;
325 } else {
326 xtube = -m_Zsize / 2. + m_firstwire_y[tubeLayer - 1];
327 ztube = -m_Rsize / 2. + m_firstwire_x[tubeLayer - 1] + (tube - 1) * m_tubepitch;
328 }
329 Amg::Vector3D tubePos{xtube, ytube, ztube};
330 if (hasCutouts()) {
331 if (manager()->MinimalGeoFlag() == 0) {
332 ATH_MSG_DEBUG( " MdtReadoutElement " << idHelperSvc()->toStringDetEl(identify()) << " has cutouts, check for real position of tubes " );
333 PVConstLink cv = getMaterialGeom(); // it is "Multilayer"
334 int nGrandchildren = cv->getNChildVols();
335 // child vol 0 is foam; 1 to (nGrandchildren-1) should be tubes
336 int ii = (tubeLayer - 1) * m_ntubesperlayer + tube;
337
338 // BIS78 only (the BIS7 of Run1/2 has no cutouts, thus, this block won't be reached)
339 if ((getStationIndex() == m_stIdx_BIS && std::abs(getStationEta()) == 7)) --ii;
340 if (m_idHelper.isBMG(identify())) {
341 // usually the tube number corresponds to the child number, however for
342 // BMG chambers full tubes are skipped during the building process
343 // therefore the matching needs to be done via the volume ID
344 int packed_id = tube + maxNTubesPerLayer * tubeLayer;
345 int kk = 0;
346 bool found = false;
347 geoGetIds(
348 [&](int id) {
349 if (!found && id == packed_id) {
350 ii = kk;
351 found = true;
352 }
353 ++kk;
354 },
355 &*cv);
356 if (found) {
357 ATH_MSG_DEBUG( " MdtReadoutElement tube match found for BMG - input : tube(" << tube << "), layer("
358 << tubeLayer << ") - output match : tube(" << ii % maxNTubesPerLayer << "), layer(" << ii / maxNTubesPerLayer
359 << ")" );
360 }
361 }
362 GeoTrf::Transform3D tubeTrans = cv->getXToChildVol(ii);
363 PVConstLink tv = cv->getChildVol(ii);
364 constexpr double maxtol = 0.0000001;
365
366 if (std::abs(xtube - tubeTrans(0, 3)) > maxtol || std::abs(ztube - tubeTrans(2, 3)) > maxtol) {
367 THROW_EXCEPTION(__func__<<"("<<tubeLayer<<","<<tube<<")"<<" - mismatch between local from tube-id/pitch/cutout position"<<
368 Amg::toString(tubePos)<<" and GeoModel "<< Amg::toString(tubeTrans.linear().col(3))<<" for detector element "<<
369 idHelperSvc()->toStringDetEl(identify()) <<"There are "<<nGrandchildren<<" child volumes and "<<
370 (m_ntubesperlayer * m_nlayers)<<" are expected. There should be "<<m_nlayers<<" and "<<
371 m_ntubesperlayer<<" tubes per layer");
372 }
373 if (tubeTrans(1, 3) > maxtol) {
374
375 ATH_MSG_DEBUG( "This a tube with cutout stName/Eta/Phi/ml/tubeLayer/t = " << idHelperSvc()->toStringDetEl(identify())
376 << "/" << tubeLayer << "/" << tube);
377 // check only for tubes actually shifted
378 if (std::abs(m_cutoutShift - tubeTrans(1, 3)) > maxtol) {
379 THROW_EXCEPTION(__func__<<"("<<tubeLayer<<","<<tube<<")"<<" - mismatch between local from tube-id/pitch/cutout position"<<
380 Amg::toString(tubePos)<<" and GeoModel "<< Amg::toString(tubeTrans.linear().col(3))<<" for detector element "<<
381 idHelperSvc()->toStringDetEl(identify()) <<"There are "<<nGrandchildren<<" child volumes and "<<
382 (m_ntubesperlayer * m_nlayers)<<" are expected. There should be "<<m_nlayers<<" and "<<
383 m_ntubesperlayer<<" tubes per layer");
384 }
385 }
386
387 Amg::Vector3D x = tubeTrans.translation();
388 if (tube > m_ntubesperlayer || tubeLayer > m_nlayers) { x = tubePos; }
389 return x;
390 }
391 }
392 return tubePos;
393 }
394
395 Amg::Vector3D MdtReadoutElement::nodeform_tubePos(int tubeLayer, int tube) const {
396 return transform() * nodeform_localTubePos(tubeLayer, tube);
397 }
398 Amg::Vector3D MdtReadoutElement::tubePos(int tubeLayer, int tube) const {
399 return transform() * localTubePos(tubeLayer, tube);
400 }
401 Amg::Transform3D MdtReadoutElement::tubeToMultilayerTransf(const int tubeLayer, const int tube) const {
402 return tubeToMultilayerTransf(nodeform_localTubePos(tubeLayer, tube),
403 fromIdealToDeformed(tubeLayer, tube));
404 }
405#if defined(FLATTEN)
406 // We compile this package with optimization, even in debug builds; otherwise,
407 // the heavy use of Eigen makes it too slow. However, from here we may call
408 // to out-of-line Eigen code that is linked from other DSOs; in that case,
409 // it would not be optimized. Avoid this by forcing all Eigen code
410 // to be inlined here if possible.
412#endif
413
420 Amg::Transform3D MdtReadoutElement::nodeform_localToGlobalTransf(const int tubeLayer, const int tube) const {
421 return globalTransform(nodeform_localTubePos(tubeLayer, tube), Amg::Transform3D::Identity());
422 }
423 Amg::Transform3D MdtReadoutElement::globalToLocalTransf(const int tubeLayer, const int tube) const {
424 return transform(tubeLayer, tube).inverse();
425 }
426
427 Amg::Transform3D MdtReadoutElement::nodeform_globalToLocalTransf(const int tubeLayer, const int tube) const {
428 return nodeform_localToGlobalTransf(tubeLayer, tube).inverse();
429 }
430 double MdtReadoutElement::getNominalTubeLengthWoCutouts(const int tubeLayer, const int tube) const {
431 if (barrel())
432 return m_Ssize;
433 else {
434 int istep = int((tube - 1) / m_ntubesinastep);
435 if (istep < 0 || istep >= m_nsteps) {
436 ATH_MSG_WARNING( "getNominalTubeLengthWoCutouts for Element named " << idHelperSvc()->toStringDetEl(identify())
437 << " called with: tubeL, tube " << tubeLayer
438 << " " << tube << "; step " << istep << " out of range 0-" << m_nsteps - 1 << " m_ntubesinastep " << m_ntubesinastep);
439 istep = 0;
440 }
441 return m_tubelength[istep];
442 }
443 }
444 Amg::Vector3D MdtReadoutElement::localNominalTubePosWoCutouts(const int tubeLayer, const int tube) const {
445 double xtube{0.}, ztube{0.};
446 if (barrel()) {
447 xtube = -m_Rsize / 2. + m_firstwire_y[tubeLayer - 1];
448 ztube = -m_Zsize / 2. + m_firstwire_x[tubeLayer - 1] + (tube - 1) * m_tubepitch;
449 } else {
450 xtube = -m_Zsize / 2. + m_firstwire_y[tubeLayer - 1];
451 ztube = -m_Rsize / 2. + m_firstwire_x[tubeLayer - 1] + (tube - 1) * m_tubepitch;
452 }
453 return Amg::Vector3D{xtube, 0., ztube};
454 }
455
456 const Amg::Transform3D& MdtReadoutElement::fromIdealToDeformed(const int tubeLayer, const int tube) const {
457 size_t itube = (tubeLayer - 1) * m_ntubesperlayer + tube - 1;
458 if (itube >= m_tubeGeo.size()) {
459 ATH_MSG_WARNING(__func__<<"() :"<<__LINE__<< " called with tubeLayer or tube out of range in chamber "
460 << idHelperSvc()->toStringDetEl(identify()) << " : layer " << tubeLayer << " max " << m_nlayers << " tube " << tube
461 << " max " << m_ntubesperlayer << " will compute deformation for first tube in this chamber" );
462 ATH_MSG_WARNING( "Please run in DEBUG mode to get extra diagnostic" );
463 itube = 0;
464 }
465 static const Amg::Transform3D ident{Amg::Transform3D::Identity()};
466 const GeoInfo& geo = m_tubeGeo.at(itube);
467 return geo.deformedTrf ? *geo.deformedTrf : ident;
468 }
469
470#if defined(FLATTEN)
471 // We compile this package with optimization, even in debug builds; otherwise,
472 // the heavy use of Eigen makes it too slow. However, from here we may call
473 // to out-of-line Eigen code that is linked from other DSOs; in that case,
474 // it would not be optimized. Avoid this by forcing all Eigen code
475 // to be inlined here if possible.
477#endif
479 MdtReadoutElement::deformedTransform(int tubeLayer, int tube) const {
480
481 const MuonStation* ms = parentMuonStation();
482 if (!ms->hasBLines() && !ms->hasMdtAsBuiltParams()) {
483 return Amg::Transform3D::Identity();
484 }
485 const Amg::Vector3D fixedPoint = ms->getBlineFixedPointInAmdbLRS();
486
487 // Chamber parameters
488 double moduleWidthS = m_Ssize;
489 double moduleWidthL = m_LongSsize;
490 double height = barrel() ? ms->ZsizeMdtStation() : ms->RsizeMdtStation();
491 double thickness = barrel() ? ms->RsizeMdtStation() : ms->ZsizeMdtStation();
492
493 ATH_MSG_VERBOSE("Calculate deformed transform "<<idHelperSvc()->toStringDetEl(identify())
494 <<", layer: "<<tubeLayer<<", tube: "<<tube<<", fixedPoint: "<<Amg::toString(fixedPoint)<<" / "
495 <<Amg::toString(ms->getGeoTransform()->getDefTransform() *ms->getNativeToAmdbLRS().inverse()* fixedPoint)
496 <<", height: "<<height<<", thickness: "<<thickness
497 <<", ideal tube: "<<Amg::toString(localNominalTubePosWoCutouts(tubeLayer,tube)));
498
499#ifndef NDEBUG
500 double heightML = barrel() ? m_Zsize : m_Rsize;
501 double thicknessML = barrel() ? m_Rsize : m_Zsize;
502 if (std::abs(height - heightML) > 10.) {
503 ATH_MSG_DEBUG( "RE " << idHelperSvc()->toStringDetEl(identify())
504 << "Different ML and MDTStation length in the precision coord.direction --- MultiLayerHeight, MDTstationHeigh "
505 << heightML << " " << height << " MultiLayerThickness, MDTstationThickness " << thicknessML << " " << thickness);
506 }
507#endif
508 // Chamber dimension in Z is defined with extraneous glue width. Correct for it
509 double glue = (tubePitch() - 2. * outerTubeRadius());
510 height -= glue;
511
512 // Calculate transformation from native to AMDB.
513 const Amg::Transform3D toAMDB = ms->getNativeToAmdbLRS() * toParentStation();
514 const Amg::Transform3D fromAMDB = toAMDB.inverse();
515
516 // Get positions of the wire center and end without deformations
517 Amg::Vector3D pt_center = localNominalTubePosWoCutouts(tubeLayer, tube);
518 double halftubelen = 0.5 * getNominalTubeLengthWoCutouts(tubeLayer, tube);
519
520 // Compute tube ends in AMDB coordinates
521 Amg::Vector3D pt_end1 = toAMDB * pt_center + halftubelen * Amg::Vector3D::UnitX(); // s>0 side
522 Amg::Vector3D pt_end2 = toAMDB * pt_center - halftubelen * Amg::Vector3D::UnitX(); // s>0 side
523
524 Amg::Vector3D pt_end1_new = pt_end1;
525 Amg::Vector3D pt_end2_new = pt_end2;
526
527 // if there are as built parameters ... apply them here
528 if (ms->hasMdtAsBuiltParams()) {
529 wireEndpointsAsBuilt(pt_end1_new, pt_end2_new, tubeLayer, tube);
530 }
531
532 // if there are deformation parameters ... apply them here
533 if (ms->hasBLines()) {
534
535 // Get positions after the deformations applied
536 // first wire end point
537 pt_end1_new = posOnDefChamWire(pt_end1_new, moduleWidthS, moduleWidthL, height, thickness, fixedPoint);
538
539 // second wire end point
540 pt_end2_new = posOnDefChamWire(pt_end2_new, moduleWidthS, moduleWidthL, height, thickness, fixedPoint);
541 }
542
543 // Switch tube ends back to MGM coordinates
544 pt_end1 = fromAMDB * pt_end1;
545 pt_end2 = fromAMDB * pt_end2;
546 pt_end1_new = fromAMDB * pt_end1_new;
547 pt_end2_new = fromAMDB * pt_end2_new;
548
549 // Calculate deformation. Make sure that the wire length stays the same.
550 // Code in positionOnDeformedChamber does not provide this by default.
551 // Break transformation into translation of the wire center and the rotation of the wire
552 // Move to the coordinate system originated at the wire center, then rotate the wire, then
553 // move wire center to the new position
554 const Amg::Vector3D pt_center_new = 0.5 * (pt_end1_new + pt_end2_new);
555 const Amg::Transform3D to_center{Amg::getTranslate3D(-pt_center)};
556 const Amg::Transform3D from_center{Amg::getTranslate3D(pt_center_new)};
557 const Amg::Vector3D old_direction = (pt_end2 - pt_end1).unit();
558 const Amg::Vector3D new_direction = (pt_end2_new - pt_end1_new).unit();
559 const Amg::Vector3D rotation_vector = old_direction.cross(new_direction);
560
561
562 Amg::Transform3D deformedTransform{Amg::Transform3D::Identity()};
563 if (rotation_vector.mag() > 10. * std::numeric_limits<double>::epsilon()) {
564 const Amg::AngleAxis3D wire_rotation(std::asin(rotation_vector.mag()), rotation_vector.unit());
565 deformedTransform = from_center * wire_rotation * to_center;
566 } else {
567 deformedTransform = from_center * to_center;
568 }
569 ATH_MSG_VERBOSE("To center "<<GeoTrf::toString(to_center)<<" from: "<<GeoTrf::toString(from_center)<<
570 " -- direction: "<<GeoTrf::toString(old_direction)<<" vs. "<<GeoTrf::toString(new_direction)
571 <<" --> rot: "<<GeoTrf::toString(rotation_vector)<<" ==> "<<GeoTrf::toString(deformedTransform,true));
572 return deformedTransform;
573 }
574
575 // //Correspondence to AMDB parameters -TBM
576 // //cpl_x is tr "trapezoidal effect"
577 // //cpl_y is sy "Longbeam vertical sagitta"
578 // //cpl_z is sz "Longbeam horizontal sagitta"
579 // //sag_x is ?? "shearing deformation"
580 // //sag_y is so,sv "RO crossplate sag, HV crossplate sag"
581 // //sag_z is ?? "different long-beam bow for short/long side"
582 // //the_g is tw "common twist angle for HV and RO side"
583 // //the_c is tw "torsion along tube axis"
584 // //the_m is tw "torsion along tube axis"
585 // //tem_g is T, "temperature"
586 // //tem_c is ev "HV elongation"
587 // //tem_m is eo "RO elongation"
588
589 // /*
590 // CPM: mask-side cross plate (=readout side in endcap)
591 // CPC: CCD-side cross plate (=HV side in endcap)
592 // CPL: lens cross plate (=central cross plate)
593
594 // note that nearly all deformation parameter names are meaningless
595 // */
597 const double moduleWidthS,
598 const double moduleWidthL,
599 const double height,
600 const double thickness,
601 const Amg::Vector3D& fixedPoint) const {
602
603 using Parameter = BLinePar::Parameter;
604 const double sp = m_BLinePar->getParameter(Parameter::sp);
605 const double sn = m_BLinePar->getParameter(Parameter::sn);
606 const double tw = m_BLinePar->getParameter(Parameter::tw);
607 const double eg = m_BLinePar->getParameter(Parameter::eg);
608 double ep = m_BLinePar->getParameter(Parameter::ep);
609 double en = m_BLinePar->getParameter(Parameter::en);
610 // S.Spagnolo Feb.6, 2011, modified by P.F Giraud, 2015-01-17
611 // This version does not implement deformations modifying only the second
612 // coordinate, or leaving the end-plug positions unchanged.
613 // This version should be called only with the coordinates of the end-plugs
614 // as argument, as is done in fromIdealToDeformed
615
616 // MDT deformations like tube bow: bz,bp,bn bend the tube while the wire endpoints are not affected
617 // => the wire keeps it's nominal straight line trajectory but it is not concentric to the tube
618 // ==> in this function bz, bp and bn are ignored or set to 0
619 // MDT deformations that extend/contract the wire longitudinally (while keeping it straight):
620 // delta_s from eg and tr are irrelevant for the tube geometry
621 // and for the wire trajectory => set to 0 here
622 // (should be applied as a correction to the
623 // tube lenght => tube surface bounds
624 // =++>>>> effect in tracking just through the gravitational sagging TOTALLY NEGLIGIBLE=> ignore)
625 // pg is irrelevant for tracking purposes and (at least for the endcaps) is applies to the internal bars only, not to the tubes !!!
626 // =++>>>> IGNORE IT
627 // ep,en: bend the tube by moving (differently) the endplugs ===> the wire straight trajectory is moved w.r.t. the nominal one
628 // in addition the tubes keep their nominal position at the center => the wire is not concentric to
629 // the tube delta_s from ep,en must also be considered for the implementation of the realistic tube
630 // trajectory induced by ep,en
631 // tw,sp,sn,pg (for deltaT and deltaZ) are geometrical effects, that impact on tracking and keep the wire straight.
632
633
634
635 Amg::Vector3D deformPos(locAMDBPos);
636
637 // NOTE s0,z0,t0 are the coord. in the amdb frame of this point: the origin of the frame can be different than the fixed point for
638 // deformations s0mdt,z0mdt,t0mdt
639 // (always equal to the point at lowest t,z and s=0 of the MDT stack)
640 ATH_MSG_VERBOSE( "** In "<<__func__<<" - moduleWidthS " << moduleWidthS<<", moduleWidthL: "
641 <<moduleWidthL <<", height: "<<height<<", thickness: " <<thickness << "." );
642 ATH_MSG_VERBOSE( "** In "<<__func__<<" - going to correct for B-line the position of Point at " <<Amg::toString(locAMDBPos)
643 << " in the amdb-szt frame" );
644
645 double s0mdt = locAMDBPos.x(); // always I think !
646 if (std::abs(fixedPoint.x()) > 0.01) {
647 s0mdt = locAMDBPos.x() - fixedPoint.x();
648 }
649 double z0mdt = locAMDBPos.y();
650 // unless in the D section of this station there's a dy diff. from 0 for the innermost MDT multilayer (sometimes in the barrel)
651 if (std::abs(fixedPoint.y()) > 0.01) {
652 z0mdt = locAMDBPos.y() - fixedPoint.y();
653 }
654 double t0mdt = locAMDBPos.z();
655 // unless in the D section of this station there's a dz diff. from 0 for the innermost MDT multilayer (often in barrel)
656 if (std::abs(fixedPoint.z()) > 0.01) t0mdt = locAMDBPos.z() - fixedPoint.z();
657 if (z0mdt < 0 || t0mdt < 0) {
658 ATH_MSG_WARNING(""<<__func__<<": correcting the local position of a point outside the mdt station (2 multilayers) volume -- RE "
659 << idHelperSvc()->toStringDetEl(identify()) << " local point: szt=" << Amg::toString(locAMDBPos)
660 << " fixedPoint " <<Amg::toString(fixedPoint) );
661 }
662 ATH_MSG_VERBOSE( "** In "<<__func__<<" - correct for offset of B-line fixed point " << s0mdt << " " << z0mdt << " " << t0mdt);
663
664 double ds{0.},dz{0.},dt{0.};
665 double width_actual = moduleWidthS + (moduleWidthL - moduleWidthS) * (z0mdt / height);
666 double s_rel = s0mdt / (width_actual / 2.);
667 double z_rel = (z0mdt - height / 2.) / (height / 2.);
668 double t_rel = (t0mdt - thickness / 2.) / (thickness / 2.);
669
670 ATH_MSG_VERBOSE( "** In "<<__func__<<" - width_actual: "<<width_actual<<", s_rel: "<<s_rel<<", z_rel: "
671 <<z_rel<<", t_rel: "<<t_rel);
672
673 // sp, sn - cross plate sag out of plane
674 if ((sp != 0) || (sn != 0)) {
675 double ztmp = z_rel * z_rel - 1;
676 dt += 0.5 * (sp + sn) * ztmp + 0.5 * (sp - sn) * ztmp * s_rel;
677 }
678
679 // tw - twist
680 if (tw != 0) {
681 dt -= tw * s_rel * z_rel;
682 dz += tw * s_rel * t_rel * thickness / height;
683 ATH_MSG_VERBOSE( "** In "<<__func__<<": tw=" << tw << " dt, dz " << dt << " " << dz );
684 }
685
686 // eg - global expansion
687 if (eg != 0) {
688 double egppm = eg / 1000.;
689 ds += 0.;
690 dz += z0mdt * egppm;
691 dt += t0mdt * egppm;
692 }
693
694 // ep, en - local expansion
695 //
696 // Imporant note: the chamber height and length, as they denoted in Christoph's talk,
697 // correspond to thickness and height parameters of this function;
698 //
699
700 if ((ep != 0) || (en != 0)) {
701 ep = ep / 1000.;
702 en = en / 1000.;
703 double phi = 0.5 * (ep + en) * s_rel * s_rel + 0.5 * (ep - en) * s_rel;
704 double localDt = phi * (t0mdt - thickness / 2.);
705 double localDz = phi * (z0mdt - height / 2.);
706 dt += localDt;
707 dz += localDz;
708 }
709
710 ATH_MSG_VERBOSE( "posOnDefChamStraighWire: ds,z,t = " << ds << " " << dz << " " << dt );
711 deformPos[0] = locAMDBPos[0] + ds;
712 deformPos[1] = locAMDBPos[1] + dz;
713 deformPos[2] = locAMDBPos[2] + dt;
714
715 return deformPos;
716 }
717
718// Function to apply AsBuilt parameter correction to wire center and end position
719// For definitions of AsBuilt parameters see Florian Bauer's talk:
720// http://atlas-muon-align.web.cern.ch/atlas-muon-align/endplug/asbuilt.pdf
721#if defined(FLATTEN)
722 // We compile this package with optimization, even in debug builds; otherwise,
723 // the heavy use of Eigen makes it too slow. However, from here we may call
724 // to out-of-line Eigen code that is linked from other DSOs; in that case,
725 // it would not be optimized. Avoid this by forcing all Eigen code
726 // to be inlined here if possible.
728#endif
729 void
731 const int tubeLayer, const int tube) const {
733 if (!params) {
734 ATH_MSG_WARNING( "Cannot find Mdt AsBuilt parameters for chamber " << idHelperSvc()->toStringDetEl(identify()) );
735 return;
736 }
737
738 ATH_MSG_VERBOSE( "Applying as-built parameters for chamber " << idHelperSvc()->toStringDetEl(identify())
739 << " tubeLayer=" << tubeLayer << " tube=" << tube);
740
741 constexpr int nsid = 2;
742 using tubeSide_t = MdtAsBuiltPar::tubeSide_t;
743 using multilayer_t = MdtAsBuiltPar::multilayer_t;
744 std::array<MdtAsBuiltPar::tubeSide_t, nsid> tubeSide{tubeSide_t::POS, tubeSide_t::NEG};
745 std::array<Amg::Vector3D, nsid> wireEnd{locAMDBWireEndP, locAMDBWireEndN};
746 multilayer_t ml = (getMultilayer() == 1) ? multilayer_t::ML1 : multilayer_t::ML2;
747
748 const double xmin = *std::min_element(m_firstwire_x.begin(), m_firstwire_x.begin() + m_nlayers) - outerTubeRadius();
749 const int ref_layer = (ml == multilayer_t::ML1) ? m_nlayers : 1;
750 const double y_offset = (ml == multilayer_t::ML1) ? outerTubeRadius() : -outerTubeRadius();
751
752 for (int isid = 0; isid < nsid; ++isid) { // first s>0 then s<0
753 // Compute the reference for the as-built parameters
754 double xref{0.}, yref{0.}, zref{0.};
755 if (barrel()) {
756 xref = -m_Rsize / 2. + m_firstwire_y[ref_layer - 1] + y_offset;
757 zref = -m_Zsize / 2. + xmin;
758 } else {
759 xref = -m_Zsize / 2. + m_firstwire_y[ref_layer - 1] + y_offset;
760 zref = -m_Rsize / 2. + xmin;
761 }
763 Amg::Vector3D reference_point{xref, yref, zref};
764
765 reference_point = toAMDB * reference_point;
766
767 if (isid == 0)
768 reference_point = reference_point + 0.5 * getNominalTubeLengthWoCutouts(ref_layer, 1) * Amg::Vector3D::UnitX();
769 else
770 reference_point = reference_point -0.5 * getNominalTubeLengthWoCutouts(ref_layer, 1) * Amg::Vector3D::UnitX();
771
772 ATH_MSG_VERBOSE("AMDB transform "<<idHelperSvc()->toStringDetEl(identify())<<
773 " "<<GeoTrf::toString(toAMDB, true)<<", reference point: "<<Amg::toString(reference_point));
774
775 int layer_delta = tubeLayer;
776 if (ml == multilayer_t::ML1) layer_delta = m_nlayers + 1 - tubeLayer;
777
778 // Get the As-Built parameters for this ML and side of the chamber
779 double zpitch = params->zpitch(ml, tubeSide[isid]);
780 double ypitch = params->ypitch(ml, tubeSide[isid]);
781 double stagg = (double)params->stagg(ml, tubeSide[isid]);
782 double alpha = params->alpha(ml, tubeSide[isid]);
783 double y0 = params->y0(ml, tubeSide[isid]);
784 double z0 = params->z0(ml, tubeSide[isid]);
785
786 // Find the vector from the reference_point to the endplug
787 int do_stagg = (layer_delta - 1) % 2; // 0 for layer 1 and 3, 1 for layer 2 and 4
788 double offset_stagg = ((double)do_stagg) * 0.5 * zpitch * stagg;
789 Amg::Vector3D end_plug(0., (tube - 1.0) * zpitch + offset_stagg, (layer_delta - 1) * ypitch);
790
791 const Amg::Transform3D amgTransf{Amg::getRotateX3D(-alpha)};
792 end_plug = amgTransf * end_plug;
793
794 // Calculate x position, which varies for endcap chambers
795 double xshift = 0.;
796 if (isid == 0)
797 xshift = 0.5 * getNominalTubeLengthWoCutouts(tubeLayer, tube) - 0.5 * getNominalTubeLengthWoCutouts(ref_layer, 1);
798 else
799 xshift = -0.5 * getNominalTubeLengthWoCutouts(tubeLayer, tube) + 0.5 * getNominalTubeLengthWoCutouts(ref_layer, 1);
800
801 Amg::Vector3D ret(reference_point.x() + xshift, reference_point.y() + z0 + end_plug.y(),
802 reference_point.z() + y0 + end_plug.z());
803
804 // Warn if result of calculation is too far off
805 // BIL1A13 has as-built parameters up to 3mm off, giving the size of the cut
806 if ((ret - wireEnd[isid]).mag() > 3. * CLHEP::mm) {
807 ATH_MSG_WARNING( "Large as-built correction for chamber " << idHelperSvc()->toStringDetEl(identify()) << ", side "
808 << isid << ", Delta " << Amg::toString(ret - wireEnd[isid]) );
809 }
810 ATH_MSG_VERBOSE(( tubeSide[isid] == tubeSide_t::POS ? "positive" : "negative")<<" wire end has moved from "
811 <<Amg::toString(wireEnd[isid])<<" to "<<Amg::toString(ret));
812
813 // Save the result
814 if (tubeSide[isid] == tubeSide_t::POS)
815 locAMDBWireEndP = ret;
816 else
817 locAMDBWireEndN = ret;
818 }
819 }
820 MdtReadoutElement::GeoInfo MdtReadoutElement::makeGeoInfo(const int tubeLayer, const int tube) const {
821 Amg::Transform3D deformedTrf = deformedTransform(tubeLayer, tube);
822 GeoInfo info{globalTransform(nodeform_localTubePos(tubeLayer, tube), deformedTrf)};
823 info.deformedTrf = std::make_unique<Amg::Transform3D>(std::move(deformedTrf));
824 return info;
825 }
826
827 const MdtReadoutElement::GeoInfo& MdtReadoutElement::geoInfo(const int tubeLayer, const int tube) const {
828 size_t itube = (tubeLayer - 1) * m_ntubesperlayer + tube - 1;
829 if (itube >= m_tubeGeo.size()) {
830 ATH_MSG_WARNING(__func__<<"() :"<<__LINE__<<" called with tubeLayer or tube out of range in chamber "
831 << idHelperSvc()->toStringDetEl(identify()) << " : layer " << tubeLayer << " max " << m_nlayers << " tube " << tube
832 << " max " << m_ntubesperlayer << " will compute transform for first tube in this chamber" );
833 ATH_MSG_WARNING( "Please run in DEBUG mode to get extra diagnostic" );
834 itube = 0;
835 }
836 return m_tubeGeo.at(itube);
837 }
838
839 const Amg::Transform3D& MdtReadoutElement::transform(const int tubeLayer, const int tube) const {
840 const GeoInfo& info{geoInfo(tubeLayer, tube)};
841 if (!info.isValid) {
842 THROW_EXCEPTION("There is no transform cached for tubeLayer: "<<tubeLayer
843 <<", tube: "<<tube<<" in "<<idHelperSvc()->toStringDetEl(identify()));
844 }
845 return info.m_transform;
846 }
847
848 const Trk::StraightLineSurface& MdtReadoutElement::surface(const int tubeLayer, const int tube) const {
849 int ntot_tubes = m_nlayers * m_ntubesperlayer;
850 int itube = (tubeLayer - 1) * m_ntubesperlayer + tube - 1;
851 // consistency checks
852 if (itube >= ntot_tubes) {
853 ATH_MSG_WARNING( "surface called with tubeLayer or tube out of range in chamber "
854 << idHelperSvc()->toStringDetEl(identify()) << " : layer " << tubeLayer << " max " << m_nlayers << " tube " << tube
855 << " max " << m_ntubesperlayer << " will compute surface for first tube in this chamber" );
856 ATH_MSG_WARNING( "Please run in DEBUG mode to get extra diagnostic" );
857 itube = 0;
858 }
859 assert(m_tubeSurfaces.at(itube) != nullptr);
860 return *m_tubeSurfaces.at(itube);
861 }
862 const Trk::CylinderBounds& MdtReadoutElement::bounds(const int tubeLayer, const int tube) const {
863 const auto& bounds = m_tubeBounds.at(boundHash(tubeLayer, tube));
864 assert(bounds!= nullptr);
865 return *bounds;
866 }
867 const Amg::Vector3D& MdtReadoutElement::center(const int tubeLayer, const int tube) const { return geoInfo(tubeLayer, tube).m_center; }
869 if (!m_elemNormal.isValid()) { m_elemNormal.set(transform().linear() * Amg::Vector3D::UnitX()); }
870 return *m_elemNormal.ptr();
871 }
872
874 assert(m_associatedSurface != nullptr);
875 return *m_associatedSurface;
876 }
877
879
882 ATH_MSG_DEBUG( "Clearing cache for ReadoutElement " << idHelperSvc()->toStringDetEl(identify()) );
883 m_elemNormal.reset();
884 }
885
887 ATH_MSG_DEBUG( "Setting B-line for " << idHelperSvc()->toStringDetEl(identify()) );
888 if (m_BLinePar == bLine) {
889 return;
890 }
891 m_BLinePar = bLine;
892 refreshCache();
893 }
894
896 ATH_MSG_DEBUG( "Filling cache for ReadoutElement " << idHelperSvc()->toStringDetEl(identify())
897 <<", nlayers: "<<getNLayers()<<", tubes per lay: "<<getNtubesperlayer());
898
899 if (!m_associatedBounds) {
900 if (barrel()) {
901 m_associatedBounds = std::make_unique<Trk::RectangleBounds>(getSsize() / 2., getZsize() / 2.);
902 } else {
903 m_associatedBounds = std::make_unique<Trk::TrapezoidBounds>(getSsize() / 2.,
904 getLongSsize() / 2.,
905 getRsize() / 2.);
906 }
907 }
908 ATH_MSG_VERBOSE( "global Normal " << Amg::toString(normal()) );
909
910 for (int tubeLayer = 1; tubeLayer <= getNLayers(); ++tubeLayer) {
911 for (int tube = 1; tube <= getNtubesperlayer(); ++tube) {
912 // in case of BMG chambers, do not check the 'dead' tubes
913 // (the tubes are numbered from 1-54 for each however there are cutouts for the
914 // alignment system where no tubes are built-in, meaning, those tubes do not exist/are 'dead')
915 bool addTrf{false};
916
917 if (!m_builtFromCnv && manager()->mdtIdHelper()->isBMG(identify())) {
918 // usually the tube number corresponds to the child number, however for
919 // BMG chambers full tubes are skipped during the building process
920 // therefore the matching needs to be done via the volume ID
921 int packed_id = tube + maxNTubesPerLayer * tubeLayer;
922 geoGetIds(
923 [&](int id) {
924 if (id == packed_id) {
925 addTrf = true;
926 }
927
928 }, getMaterialGeom());
929 } else {
930 addTrf = true;
931 }
932 if (!addTrf) {
933 continue;
934 }
935 size_t itube = (tubeLayer - 1) * m_ntubesperlayer + tube - 1;
936 m_tubeGeo.at(itube) = makeGeoInfo(tubeLayer, tube);
937 auto& surface = m_tubeSurfaces.at(itube);
938 if (!surface) {
939 Identifier id = m_idHelper.channelID(identify(), getMultilayer(), tubeLayer, tube);
940 surface = std::make_unique<Trk::StraightLineSurface>(*this, id);
941 }
942 std::unique_ptr<Trk::CylinderBounds>& ptr = m_tubeBounds.at(boundHash(tubeLayer, tube));
943 if (!ptr) {
944 double tubelength = getTubeLengthForCaching(tubeLayer, tube);
945 ptr = std::make_unique<Trk::CylinderBounds>(innerTubeRadius(), 0.5 * tubelength - m_deadlength);
946 }
947 }
948 }
950 Amg::RotationMatrix3D muonTRotation(transform().rotation());
951 Amg::RotationMatrix3D surfaceTRotation;
952 surfaceTRotation.col(0) = muonTRotation.col(1);
953 surfaceTRotation.col(1) = muonTRotation.col(2);
954 surfaceTRotation.col(2) = muonTRotation.col(0);
955
956 Amg::Transform3D trans3D(surfaceTRotation);
957 trans3D.pretranslate(transform().translation());
958
959 m_associatedSurface = std::make_unique<Trk::PlaneSurface>(Amg::Transform3D(trans3D), m_associatedBounds);
960 }
961
963 if (idHelperSvc()->detElId(id) != identify()) return false;
964 int layer = m_idHelper.tubeLayer(id);
965 if (layer < 1 || layer > getNLayers()) return false;
966 int tube = m_idHelper.tube(id);
967 return tube >= 1 && tube <= getNtubesperlayer();
968 }
969
970 // **************************** interfaces related to Tracking *****************************************************)
971
972} // namespace MuonGM
Scalar phi() const
phi method
Scalar mag() const
mag method
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Visitor to collect all IDs under a GeoModel node.
void geoGetIds(FUNCTION f, const GeoGraphNode *node, int depthLimit=1)
Template helper for running the visitor.
Definition GeoGetIds.h:82
double coord
Type of coordination system.
static Double_t sp
int sign(int a)
#define x
Container classifier the MDT as-built parameters See parameter description in http://atlas-muon-align...
multilayer_t
MDT multi-layer index.
tubeSide_t
MDT tube side.
static constexpr int maxNTubesPerLayer
The maxNTubesPerLayer represents the absolute maximum of tubes which are built into a single multilay...
Definition MdtIdHelper.h:68
Amg::Transform3D tubeToMultilayerTransf(const Identifier &id) const
double getTubeLengthForCaching(const int tubeLayer, const int tube) const
virtual const Amg::Vector3D & center() const override final
Return the center of the element.
int isAtReadoutSide(const Amg::Vector3D &GlobalHitPosition, const Identifier &id) const
bool endcap() const
Returns whether the chamber is in the endcap.
void setMultilayer(const int ml)
Sets the multilayer number.
Amg::Vector3D localTubePos(const Identifier &id) const
void wireEndpointsAsBuilt(Amg::Vector3D &locAMDBWireEndP, Amg::Vector3D &locAMDBWireEndN, const int tubelayer, const int tube) const
double signedRODistanceFromTubeCentre(const Identifier &id) const
Amg::Vector3D tubePos(const Identifier &id) const
Returns the global position of the given tube.
Amg::Vector3D ROPos(const int tubelayer, const int tube) const
Amg::Transform3D nodeform_globalToLocalTransf(const Identifier &id) const
double getNominalTubeLengthWoCutouts(const int tubeLayer, const int tube) const
Amg::Vector3D localROPos(const Identifier &id) const
Amg::Transform3D globalTransform(const Amg::Vector3D &tubePos, const Amg::Transform3D &toDeform) const
Amg::Vector3D localNominalTubePosWoCutouts(const int tubelayer, const int tube) const
Amg::Vector3D nodeform_localTubePos(const Identifier &id) const
Amg::Transform3D nodeform_localToGlobalTransf(const Identifier &id) const
unsigned boundHash(const int tubeLayer, const int tube) const
Return the hash for the bounds.
Amg::Vector3D tubeFrame_localROPos(const int tubelayer, const int tube) const
bool m_builtFromCnv
Flag indicating whether the RE is built by the ReadoutGeomCnvAlg.
std::vector< std::unique_ptr< Trk::StraightLineSurface > > m_tubeSurfaces
int getNLayers() const
Returns the number of tube layers inside the multilayer.
int getMultilayer() const
Returns the multilayer represented by the readout element.
Amg::Vector3D posOnDefChamWire(const Amg::Vector3D &locAMDBPos, const double width_narrow, const double width_wide, const double height, const double thickness, const Amg::Vector3D &fixedPoint) const
const Amg::Transform3D & fromIdealToDeformed(const int tubelayer, const int tube) const
virtual const Amg::Transform3D & transform() const override final
Return local to global transform.
virtual const Trk::SurfaceBounds & bounds() const override final
Return the boundaries of the element.
virtual const Amg::Vector3D & normal() const override final
Return the normal of the element.
double distanceFromRO(const Amg::Vector3D &GlobalHitPosition, const Identifier &id) const
double RODistanceFromTubeCentre(const Identifier &id) const
double outerTubeRadius() const
Returns the tube radius taking the thickness of the tubes into account.
const GeoInfo & geoInfo(const int tubeLayer, const int tube) const
int getNtubesperlayer() const
Returns the number of tubes in each tube layer.
GeoInfo makeGeoInfo(const int tubelayer, const int tube) const
double tubePitch() const
Returns the distance between 2 tubes in a tube layer.
bool getWireFirstLocalCoordAlongR(int tubeLayer, double &coord) const
Amg::Vector3D nodeform_tubePos(const Identifier &id) const
Returns the global position of the tube excluding the B-line & As-built corrections.
bool barrel() const
Returns whether the chamber is in the barrel (Assement on first later in stationName).
virtual const Trk::Surface & surface() const override final
Return surface associated with this detector element.
double innerTubeRadius() const
Returns the inner tube radius excluding the aluminium walls.
std::vector< std::unique_ptr< Trk::CylinderBounds > > m_tubeBounds
Amg::Transform3D deformedTransform(const int tubelayer, const int tube) const
std::vector< const Trk::Surface * > surfaces() const
returns all the surfaces contained in this detector element
bool getWireFirstLocalCoordAlongZ(int tubeLayer, double &coord) const
double getWireLength(const int tubeLayer, const int tube) const
void setNLayers(const int nl)
Sets the number of layers.
Amg::Transform3D globalToLocalTransf(const int tubeLayer, const int tube) const
MdtReadoutElement(GeoVFullPhysVol *pv, const std::string &stName, MuonDetectorManager *mgr)
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
MuonReadoutElement(GeoVFullPhysVol *pv, MuonDetectorManager *mgr, Trk::DetectorElemType detType)
Identifier identify() const override final
Returns the ATLAS Identifier of the MuonReadOutElement.
const Amg::Transform3D & getNativeToAmdbLRS() const
const MdtAsBuiltPar * getMdtAsBuiltParams() const
Bounds for a cylindrical Surface.
Class for a StraightLineSurface in the ATLAS detector to describe dirft tube and straw like detectors...
Abstract base class for surface bounds to be specified.
Abstract Base Class for tracking surfaces.
Definition Surface.h:79
const Amg::Vector3D & center() const
Returns the center position of the Surface.
#define ATH_FLATTEN
double xmin
Definition listroot.cxx:60
Amg::Transform3D getRotateX3D(double angle)
get a rotation transformation around X-axis
Amg::Transform3D getTranslate3D(const double X, const double Y, const double Z)
: Returns a shift transformation along an arbitrary axis
Eigen::AngleAxisd AngleAxis3D
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 3, 3 > RotationMatrix3D
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
Eigen::Translation< double, 3 > Translation3D
Ensure that the Athena extensions are properly loaded.
Definition GeoMuonHits.h:27
Ensure that the ATLAS eigen extensions are properly loaded.
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10