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
97
98 int ntot_steps = m_nsteps;
99 if (hasCutouts() && manager()->MinimalGeoFlag() == 0) { ntot_steps = m_nlayers * m_ntubesperlayer; }
100 m_tubeBounds.resize(ntot_steps);
101 }
102
103 double MdtReadoutElement::getTubeLengthForCaching(const int tubeLayer, const int tube) const {
104 double nominalTubeLength = 0.;
105 if (barrel())
106 nominalTubeLength = m_Ssize;
107 else {
108 int istep = int((tube - 1) / m_ntubesinastep);
109 if (istep < 0 || istep >= m_nsteps) {
110 ATH_MSG_WARNING( "getTubeLenght for Element with tech. " << getTechnologyType()
111 << " DEid = " << idHelperSvc()->toStringDetEl(identify()) << " called with: tubeL, tube " << tubeLayer << " " << tube
112 << "; step " << istep << " out of range 0-" << m_nsteps - 1 << " m_ntubesinastep " << m_ntubesinastep );
113 istep = 0;
114 }
115 nominalTubeLength = m_tubelength[istep];
116 }
117
118 double tlength = nominalTubeLength;
119
120 if (hasCutouts()) {
121 if (manager()->MinimalGeoFlag() == 0) {
122 ATH_MSG_VERBOSE( " MdtReadoutElement " <<idHelperSvc()->toStringDetEl(identify())
123 << " has cutouts, check for real tube length for tubeLayer, tube " << tubeLayer << " " << tube );
124 PVConstLink cv = getMaterialGeom(); // it is "Multilayer"
125 int nGrandchildren = cv->getNChildVols();
126 if (nGrandchildren <= 0) return tlength;
127 // child vol 0 is foam; 1 to (nGrandchildren-1) should be tubes
128 int ii = (tubeLayer - 1) * m_ntubesperlayer + tube;
129 // BIS78 only (the BIS7 of Run1/2 has no cutouts, thus, this block won't be reached)
130 if ((getStationIndex() == m_stIdx_BIS && std::abs(getStationEta()) == 7)) --ii;
131 if (m_idHelper.isBMG(identify())) {
132 // usually the tube number corresponds to the child number, however for
133 // BMG chambers full tubes are skipped during the building process
134 // therefore the matching needs to be done via the volume ID
135 int packed_id = tube + maxNTubesPerLayer * tubeLayer;
136 int kk = 0;
137 bool found = false;
138 geoGetIds(
139 [&](int id) {
140 if (!found && id == packed_id) {
141 ii = kk;
142 found = true;
143 }
144 ++kk;
145 }, cv);
146 if (found) {
147 ATH_MSG_DEBUG( " MdtReadoutElement tube match found for BMG - input : tube(" << tube << "), layer("
148 << tubeLayer << ") - output match : tube(" << ii % maxNTubesPerLayer << "), layer(" << ii / maxNTubesPerLayer
149 << ")" );
150 }
151 }
152 if (ii >= nGrandchildren) {
153 ATH_MSG_WARNING( " MdtReadoutElement " << idHelperSvc()->toStringDetEl(identify()) << " has cutouts, nChild = " << nGrandchildren
154 << " --- getTubeLength is looking for child with index ii=" << ii << " for tubeL and tube = " << tubeLayer << " "
155 << tube );
156 ATH_MSG_WARNING( "returning nominalTubeLength " );
157 return tlength;
158 }
159 if (ii < 0) {
160 ATH_MSG_WARNING( " MdtReadoutElement " << idHelperSvc()->toStringDetEl(identify()) << " has cutouts, nChild = " << nGrandchildren
161 << " --- getTubeLength is looking for child with index ii=" << ii << " for tubeL and tube = " << tubeLayer << " "
162 << tube );
163 ATH_MSG_WARNING( "returning nominalTubeLength " );
164 return tlength;
165 }
166 PVConstLink physChild = cv->getChildVol(ii);
167 const GeoShape* shape = physChild->getLogVol()->getShape();
168 if (shape == nullptr) return tlength;
169 const GeoTube* theTube = dynamic_cast<const GeoTube*>(shape);
170 if (theTube != nullptr)
171 tlength = 2. * theTube->getZHalfLength();
172 else
173 ATH_MSG_WARNING( "PhysChild with index " << ii
174 << " out of (tubeLayer-1)*m_ntubesperlayer+tube with tl=" << tubeLayer << " tubes/lay=" << m_ntubesperlayer
175 << " t=" << tube << " for MdtReadoutElement " << idHelperSvc()->toStringDetEl(identify()) );
176 }
177 if (std::abs(tlength - nominalTubeLength) > 0.1) {
178 ATH_MSG_VERBOSE( "Tube " << tube << " in tubeLayer = " << tubeLayer
179 << " is affected by a cutout: eff. length = " << tlength << " while nominal = " << nominalTubeLength
180 << " in station " << idHelperSvc()->toStringDetEl(identify()));
181 } else {
182 ATH_MSG_VERBOSE( "Tube " << tube << " in tubeLayer = " << tubeLayer
183 << " is NOT affected by the cutout: eff. length = " << tlength << " while nominal = " << nominalTubeLength);
184 }
185 }
186 return tlength;
187 }
188
189 double MdtReadoutElement::distanceFromRO(const Amg::Vector3D& x, int tubeLayer, int tube) const {
190 // x is given in the global reference frame
191 const Amg::Vector3D cPos = center(tubeLayer, tube);
192 const Amg::Vector3D roPos = ROPos(tubeLayer, tube);
193 const Amg::Vector3D c_ro = cPos - roPos;
194 const Amg::Vector3D x_ro = x - roPos;
195
196 double scalprod = c_ro.dot(x_ro);
197 double wlen = getWireLength(tubeLayer, tube);
198 if (wlen > 10. * CLHEP::mm)
199 scalprod = std::abs(2. * scalprod / getWireLength(tubeLayer, tube));
200 else {
201 ATH_MSG_WARNING( " Distance of Point " <<Amg::toString(x) << " from RO side cannot be calculated (=0) since wirelength = " << wlen );
202 scalprod = 0.;
203 }
204 return scalprod;
205 }
206
207 int MdtReadoutElement::isAtReadoutSide(const Amg::Vector3D& GlobalHitPosition, int tubeLayer, int tube) const {
208 double distance = distanceFromRO(GlobalHitPosition, tubeLayer, tube);
209 if (distance < 0) {
210 ATH_MSG_WARNING( "isAtReadoutSide() - GlobalHitPosition appears to be outside the tube volume " << distance );
211 return 1;
212 } else if (distance <= getWireLength(tubeLayer, tube) / 2.)
213 return 1;
214 else if (distance < getWireLength(tubeLayer, tube))
215 return -1;
216 else {
217 ATH_MSG_WARNING( "isAtReadoutSide() - GlobalHitPosition appears to be outside the tube volume " << distance );
218 return -1;
219 }
220 }
221 double MdtReadoutElement::RODistanceFromTubeCentre(const int tubeLayer, const int tube) const {
222 return getWireLength(tubeLayer, tube) / 2.;
223 }
224 double MdtReadoutElement::signedRODistanceFromTubeCentre(const int tubeLayer, const int tube) const {
225 // it is a signed quantity:
226 // the sign corresponds to the sign of the z coordinate of the RO endplug in the tube
227 // reference frame
228 int amdb_plus_minus1 = 1;
229 if (!m_zsignRO_tubeFrame.isValid()) {
230 const MuonStation* ms = parentMuonStation();
231 if (std::abs(ms->xAmdbCRO()) > 10.) {
232 Amg::Vector3D tem = ms->xAmdbCRO()* Amg::Vector3D::UnitX();
233 Amg::Transform3D amdbToGlobal{ms->getAmdbLRSToGlobal()};
234 Amg::Vector3D temGlo = amdbToGlobal * tem;
235 Amg::Vector3D ROtubeFrame = nodeform_globalToLocalTransf(tubeLayer, tube) * temGlo;
236 if (ROtubeFrame.z() < 0)
237 m_zsignRO_tubeFrame.set(-1);
238 else
239 m_zsignRO_tubeFrame.set(1);
240 }
241 }
242 // if no CRO in a chamber in AMDB (BIS in layout R), use the standard convention for RO-HV side
243 if (!m_zsignRO_tubeFrame.isValid()) {
244 int sign = 0;
245 if (barrel()) {
246 if (sideA()) {
247 if (largeSector())
248 sign = -1;
249 else
250 sign = 1;
251 } else {
252 if (largeSector())
253 sign = 1;
254 else
255 sign = -1;
256 }
257 // a special case is BIS in sector 12
258 if (getStationName().substr(0, 3) == "BIS" && getStationPhi() == 6) sign = -sign;
259 } else {
260 if (sideA()) {
261 if (largeSector())
262 sign = 1;
263 else
264 sign = -1;
265 } else {
266 if (largeSector())
267 sign = -1;
268 else
269 sign = 1;
270 }
271 }
273 }
274 amdb_plus_minus1 = *m_zsignRO_tubeFrame.ptr();
275 if (amdb_plus_minus1 == 0) {
276 ATH_MSG_WARNING( "Unable to get the sign of RO side; signedRODistancefromTubeCenter returns 0" );
277 }
278
279 return amdb_plus_minus1 * getWireLength(tubeLayer, tube) / 2.;
280 }
281
282 Amg::Vector3D MdtReadoutElement::tubeFrame_localROPos(const int tubeLayer, const int tube) const {
283 return signedRODistanceFromTubeCentre(tubeLayer, tube) * Amg::Vector3D::UnitZ();
284 }
285 Amg::Vector3D MdtReadoutElement::localROPos(const int tubeLayer, const int tube) const {
286 return tubeToMultilayerTransf(tubeLayer, tube) * tubeFrame_localROPos(tubeLayer, tube);
287 }
288 Amg::Vector3D MdtReadoutElement::ROPos(const int tubeLayer, const int tube) const {
289 return transform(tubeLayer, tube) * tubeFrame_localROPos(tubeLayer, tube);
290 }
291 Amg::Vector3D MdtReadoutElement::localTubePos(const int tubeLayer, const int tube) const {
292 return fromIdealToDeformed(tubeLayer, tube) * nodeform_localTubePos(tubeLayer, tube);
293 }
294
295 Amg::Vector3D MdtReadoutElement::nodeform_localTubePos(const int tubeLayer, const int tube) const {
296 ATH_MSG_VERBOSE( " Computing LocalTubePos for "<< idHelperSvc()->toStringDetEl(identify())
297 << "/" << tubeLayer << "/" << tube );
298 double xtube{0.}, ytube{0.}, ztube{0.};
299 if (barrel()) {
300 xtube = -m_Rsize / 2. + m_firstwire_y[tubeLayer - 1];
301 ztube = -m_Zsize / 2. + m_firstwire_x[tubeLayer - 1] + (tube - 1) * m_tubepitch;
302 } else {
303 xtube = -m_Zsize / 2. + m_firstwire_y[tubeLayer - 1];
304 ztube = -m_Rsize / 2. + m_firstwire_x[tubeLayer - 1] + (tube - 1) * m_tubepitch;
305 }
306 Amg::Vector3D tubePos{xtube, ytube, ztube};
307 if (hasCutouts()) {
308 if (manager()->MinimalGeoFlag() == 0) {
309 ATH_MSG_DEBUG( " MdtReadoutElement " << idHelperSvc()->toStringDetEl(identify()) << " has cutouts, check for real position of tubes " );
310 PVConstLink cv = getMaterialGeom(); // it is "Multilayer"
311 int nGrandchildren = cv->getNChildVols();
312 // child vol 0 is foam; 1 to (nGrandchildren-1) should be tubes
313 int ii = (tubeLayer - 1) * m_ntubesperlayer + tube;
314
315 // BIS78 only (the BIS7 of Run1/2 has no cutouts, thus, this block won't be reached)
316 if ((getStationIndex() == m_stIdx_BIS && std::abs(getStationEta()) == 7)) --ii;
317 if (m_idHelper.isBMG(identify())) {
318 // usually the tube number corresponds to the child number, however for
319 // BMG chambers full tubes are skipped during the building process
320 // therefore the matching needs to be done via the volume ID
321 int packed_id = tube + maxNTubesPerLayer * tubeLayer;
322 int kk = 0;
323 bool found = false;
324 geoGetIds(
325 [&](int id) {
326 if (!found && id == packed_id) {
327 ii = kk;
328 found = true;
329 }
330 ++kk;
331 },
332 &*cv);
333 if (found) {
334 ATH_MSG_DEBUG( " MdtReadoutElement tube match found for BMG - input : tube(" << tube << "), layer("
335 << tubeLayer << ") - output match : tube(" << ii % maxNTubesPerLayer << "), layer(" << ii / maxNTubesPerLayer
336 << ")" );
337 }
338 }
339 GeoTrf::Transform3D tubeTrans = cv->getXToChildVol(ii);
340 PVConstLink tv = cv->getChildVol(ii);
341 constexpr double maxtol = 0.0000001;
342
343 if (std::abs(xtube - tubeTrans(0, 3)) > maxtol || std::abs(ztube - tubeTrans(2, 3)) > maxtol) {
344 THROW_EXCEPTION(__func__<<"("<<tubeLayer<<","<<tube<<")"<<" - mismatch between local from tube-id/pitch/cutout position"<<
345 Amg::toString(tubePos)<<" and GeoModel "<< Amg::toString(tubeTrans.linear().col(3))<<" for detector element "<<
346 idHelperSvc()->toStringDetEl(identify()) <<"There are "<<nGrandchildren<<" child volumes and "<<
347 (m_ntubesperlayer * m_nlayers)<<" are expected. There should be "<<m_nlayers<<" and "<<
348 m_ntubesperlayer<<" tubes per layer");
349 }
350 if (tubeTrans(1, 3) > maxtol) {
351
352 ATH_MSG_DEBUG( "This a tube with cutout stName/Eta/Phi/ml/tl/t = " << idHelperSvc()->toStringDetEl(identify())
353 << "/" << tubeLayer << "/" << tube);
354 // check only for tubes actually shifted
355 if (std::abs(m_cutoutShift - tubeTrans(1, 3)) > maxtol) {
356 THROW_EXCEPTION(__func__<<"("<<tubeLayer<<","<<tube<<")"<<" - mismatch between local from tube-id/pitch/cutout position"<<
357 Amg::toString(tubePos)<<" and GeoModel "<< Amg::toString(tubeTrans.linear().col(3))<<" for detector element "<<
358 idHelperSvc()->toStringDetEl(identify()) <<"There are "<<nGrandchildren<<" child volumes and "<<
359 (m_ntubesperlayer * m_nlayers)<<" are expected. There should be "<<m_nlayers<<" and "<<
360 m_ntubesperlayer<<" tubes per layer");
361 }
362 }
363
364 Amg::Vector3D x = tubeTrans.translation();
365 if (tube > m_ntubesperlayer || tubeLayer > m_nlayers) { x = tubePos; }
366 return x;
367 }
368 }
369 return tubePos;
370 }
371
372 Amg::Vector3D MdtReadoutElement::nodeform_tubePos(int tubeLayer, int tube) const {
373 return transform() * nodeform_localTubePos(tubeLayer, tube);
374 }
375 Amg::Vector3D MdtReadoutElement::tubePos(int tubeLayer, int tube) const {
376 return transform() * localTubePos(tubeLayer, tube);
377 }
378 Amg::Transform3D MdtReadoutElement::tubeToMultilayerTransf(const int tubeLayer, const int tube) const {
379 return tubeToMultilayerTransf(nodeform_localTubePos(tubeLayer, tube),
380 fromIdealToDeformed(tubeLayer, tube));
381 }
382#if defined(FLATTEN)
383 // We compile this package with optimization, even in debug builds; otherwise,
384 // the heavy use of Eigen makes it too slow. However, from here we may call
385 // to out-of-line Eigen code that is linked from other DSOs; in that case,
386 // it would not be optimized. Avoid this by forcing all Eigen code
387 // to be inlined here if possible.
389#endif
390
397 Amg::Transform3D MdtReadoutElement::nodeform_localToGlobalTransf(const int tubeLayer, const int tube) const {
398 return globalTransform(nodeform_localTubePos(tubeLayer, tube), Amg::Transform3D::Identity());
399 }
400 Amg::Transform3D MdtReadoutElement::globalToLocalTransf(const int tubeLayer, const int tube) const {
401 return transform(tubeLayer, tube).inverse();
402 }
403
404 Amg::Transform3D MdtReadoutElement::nodeform_globalToLocalTransf(const int tubeLayer, const int tube) const {
405 return nodeform_localToGlobalTransf(tubeLayer, tube).inverse();
406 }
407 double MdtReadoutElement::getNominalTubeLengthWoCutouts(const int tubeLayer, const int tube) const {
408 if (barrel())
409 return m_Ssize;
410 else {
411 int istep = int((tube - 1) / m_ntubesinastep);
412 if (istep < 0 || istep >= m_nsteps) {
413 ATH_MSG_WARNING( "getNominalTubeLengthWoCutouts for Element named " << idHelperSvc()->toStringDetEl(identify())
414 << " called with: tubeL, tube " << tubeLayer
415 << " " << tube << "; step " << istep << " out of range 0-" << m_nsteps - 1 << " m_ntubesinastep " << m_ntubesinastep);
416 istep = 0;
417 }
418 return m_tubelength[istep];
419 }
420 }
421 Amg::Vector3D MdtReadoutElement::localNominalTubePosWoCutouts(const int tubeLayer, const int tube) const {
422 double xtube{0.}, ztube{0.};
423 if (barrel()) {
424 xtube = -m_Rsize / 2. + m_firstwire_y[tubeLayer - 1];
425 ztube = -m_Zsize / 2. + m_firstwire_x[tubeLayer - 1] + (tube - 1) * m_tubepitch;
426 } else {
427 xtube = -m_Zsize / 2. + m_firstwire_y[tubeLayer - 1];
428 ztube = -m_Rsize / 2. + m_firstwire_x[tubeLayer - 1] + (tube - 1) * m_tubepitch;
429 }
430 return Amg::Vector3D{xtube, 0., ztube};
431 }
432
433 const Amg::Transform3D& MdtReadoutElement::fromIdealToDeformed(const int tubeLayer, const int tube) const {
434 size_t itube = (tubeLayer - 1) * m_ntubesperlayer + tube - 1;
435 if (itube >= m_deformTransf.size()) {
436 ATH_MSG_WARNING(__func__<<"() :"<<__LINE__<< " called with tubeLayer or tube out of range in chamber "
437 << idHelperSvc()->toStringDetEl(identify()) << " : layer " << tubeLayer << " max " << m_nlayers << " tube " << tube
438 << " max " << m_ntubesperlayer << " will compute deformation for first tube in this chamber" );
439 ATH_MSG_WARNING( "Please run in DEBUG mode to get extra diagnostic" );
440 itube = 0;
441 }
442
444 if (!ptr) {
445 Amg::Transform3D trans = deformedTransform(tubeLayer, tube);
446 ptr.set(std::make_unique<Amg::Transform3D>(std::move(trans)));
448 }
449 return *ptr;
450 }
451
452#if defined(FLATTEN)
453 // We compile this package with optimization, even in debug builds; otherwise,
454 // the heavy use of Eigen makes it too slow. However, from here we may call
455 // to out-of-line Eigen code that is linked from other DSOs; in that case,
456 // it would not be optimized. Avoid this by forcing all Eigen code
457 // to be inlined here if possible.
459#endif
461 MdtReadoutElement::deformedTransform(int tubeLayer, int tube) const {
462
463 const MuonStation* ms = parentMuonStation();
464 if (!ms->hasBLines() && !ms->hasMdtAsBuiltParams()) {
465 return Amg::Transform3D::Identity();
466 }
467 const Amg::Vector3D fixedPoint = ms->getBlineFixedPointInAmdbLRS();
468
469 // Chamber parameters
470 double moduleWidthS = m_Ssize;
471 double moduleWidthL = m_LongSsize;
472 double height = barrel() ? ms->ZsizeMdtStation() : ms->RsizeMdtStation();
473 double thickness = barrel() ? ms->RsizeMdtStation() : ms->ZsizeMdtStation();
474
475 ATH_MSG_VERBOSE("Calculate deformed transform "<<idHelperSvc()->toStringDetEl(identify())
476 <<", layer: "<<tubeLayer<<", tube: "<<tube<<", fixedPoint: "<<Amg::toString(fixedPoint)<<" / "
477 <<Amg::toString(ms->getGeoTransform()->getDefTransform() *ms->getNativeToAmdbLRS().inverse()* fixedPoint)
478 <<", height: "<<height<<", thickness: "<<thickness
479 <<", ideal tube: "<<Amg::toString(localNominalTubePosWoCutouts(tubeLayer,tube)));
480
481#ifndef NDEBUG
482 double heightML = barrel() ? m_Zsize : m_Rsize;
483 double thicknessML = barrel() ? m_Rsize : m_Zsize;
484 if (std::abs(height - heightML) > 10.) {
485 ATH_MSG_DEBUG( "RE " << idHelperSvc()->toStringDetEl(identify())
486 << "Different ML and MDTStation length in the precision coord.direction --- MultiLayerHeight, MDTstationHeigh "
487 << heightML << " " << height << " MultiLayerThickness, MDTstationThickness " << thicknessML << " " << thickness);
488 }
489#endif
490 // Chamber dimension in Z is defined with extraneous glue width. Correct for it
491 double glue = (tubePitch() - 2. * outerTubeRadius());
492 height -= glue;
493
494 // Calculate transformation from native to AMDB.
495 const Amg::Transform3D toAMDB = ms->getNativeToAmdbLRS() * toParentStation();
496 const Amg::Transform3D fromAMDB = toAMDB.inverse();
497
498 // Get positions of the wire center and end without deformations
499 Amg::Vector3D pt_center = localNominalTubePosWoCutouts(tubeLayer, tube);
500 double halftubelen = 0.5 * getNominalTubeLengthWoCutouts(tubeLayer, tube);
501
502 // Compute tube ends in AMDB coordinates
503 Amg::Vector3D pt_end1 = toAMDB * pt_center + halftubelen * Amg::Vector3D::UnitX(); // s>0 side
504 Amg::Vector3D pt_end2 = toAMDB * pt_center - halftubelen * Amg::Vector3D::UnitX(); // s>0 side
505
506 Amg::Vector3D pt_end1_new = pt_end1;
507 Amg::Vector3D pt_end2_new = pt_end2;
508
509 // if there are as built parameters ... apply them here
510 if (ms->hasMdtAsBuiltParams()) {
511 wireEndpointsAsBuilt(pt_end1_new, pt_end2_new, tubeLayer, tube);
512 }
513
514 // if there are deformation parameters ... apply them here
515 if (ms->hasBLines()) {
516
517 // Get positions after the deformations applied
518 // first wire end point
519 pt_end1_new = posOnDefChamWire(pt_end1_new, moduleWidthS, moduleWidthL, height, thickness, fixedPoint);
520
521 // second wire end point
522 pt_end2_new = posOnDefChamWire(pt_end2_new, moduleWidthS, moduleWidthL, height, thickness, fixedPoint);
523 }
524
525 // Switch tube ends back to MGM coordinates
526 pt_end1 = fromAMDB * pt_end1;
527 pt_end2 = fromAMDB * pt_end2;
528 pt_end1_new = fromAMDB * pt_end1_new;
529 pt_end2_new = fromAMDB * pt_end2_new;
530
531 // Calculate deformation. Make sure that the wire length stays the same.
532 // Code in positionOnDeformedChamber does not provide this by default.
533 // Break transformation into translation of the wire center and the rotation of the wire
534 // Move to the coordinate system originated at the wire center, then rotate the wire, then
535 // move wire center to the new position
536 const Amg::Vector3D pt_center_new = 0.5 * (pt_end1_new + pt_end2_new);
537 const Amg::Transform3D to_center{Amg::getTranslate3D(-pt_center)};
538 const Amg::Transform3D from_center{Amg::getTranslate3D(pt_center_new)};
539 const Amg::Vector3D old_direction = (pt_end2 - pt_end1).unit();
540 const Amg::Vector3D new_direction = (pt_end2_new - pt_end1_new).unit();
541 const Amg::Vector3D rotation_vector = old_direction.cross(new_direction);
542
543
544 Amg::Transform3D deformedTransform{Amg::Transform3D::Identity()};
545 if (rotation_vector.mag() > 10. * std::numeric_limits<double>::epsilon()) {
546 const Amg::AngleAxis3D wire_rotation(std::asin(rotation_vector.mag()), rotation_vector.unit());
547 deformedTransform = from_center * wire_rotation * to_center;
548 } else {
549 deformedTransform = from_center * to_center;
550 }
551 ATH_MSG_VERBOSE("To center "<<GeoTrf::toString(to_center)<<" from: "<<GeoTrf::toString(from_center)<<
552 " -- direction: "<<GeoTrf::toString(old_direction)<<" vs. "<<GeoTrf::toString(new_direction)
553 <<" --> rot: "<<GeoTrf::toString(rotation_vector)<<" ==> "<<GeoTrf::toString(deformedTransform,true));
554 return deformedTransform;
555 }
556
557 // //Correspondence to AMDB parameters -TBM
558 // //cpl_x is tr "trapezoidal effect"
559 // //cpl_y is sy "Longbeam vertical sagitta"
560 // //cpl_z is sz "Longbeam horizontal sagitta"
561 // //sag_x is ?? "shearing deformation"
562 // //sag_y is so,sv "RO crossplate sag, HV crossplate sag"
563 // //sag_z is ?? "different long-beam bow for short/long side"
564 // //the_g is tw "common twist angle for HV and RO side"
565 // //the_c is tw "torsion along tube axis"
566 // //the_m is tw "torsion along tube axis"
567 // //tem_g is T, "temperature"
568 // //tem_c is ev "HV elongation"
569 // //tem_m is eo "RO elongation"
570
571 // /*
572 // CPM: mask-side cross plate (=readout side in endcap)
573 // CPC: CCD-side cross plate (=HV side in endcap)
574 // CPL: lens cross plate (=central cross plate)
575
576 // note that nearly all deformation parameter names are meaningless
577 // */
579 const double moduleWidthS,
580 const double moduleWidthL,
581 const double height,
582 const double thickness,
583 const Amg::Vector3D& fixedPoint) const {
584
585 using Parameter = BLinePar::Parameter;
586 const double sp = m_BLinePar->getParameter(Parameter::sp);
587 const double sn = m_BLinePar->getParameter(Parameter::sn);
588 const double tw = m_BLinePar->getParameter(Parameter::tw);
589 const double eg = m_BLinePar->getParameter(Parameter::eg);
590 double ep = m_BLinePar->getParameter(Parameter::ep);
591 double en = m_BLinePar->getParameter(Parameter::en);
592 // S.Spagnolo Feb.6, 2011, modified by P.F Giraud, 2015-01-17
593 // This version does not implement deformations modifying only the second
594 // coordinate, or leaving the end-plug positions unchanged.
595 // This version should be called only with the coordinates of the end-plugs
596 // as argument, as is done in fromIdealToDeformed
597
598 // MDT deformations like tube bow: bz,bp,bn bend the tube while the wire endpoints are not affected
599 // => the wire keeps it's nominal straight line trajectory but it is not concentric to the tube
600 // ==> in this function bz, bp and bn are ignored or set to 0
601 // MDT deformations that extend/contract the wire longitudinally (while keeping it straight):
602 // delta_s from eg and tr are irrelevant for the tube geometry
603 // and for the wire trajectory => set to 0 here
604 // (should be applied as a correction to the
605 // tube lenght => tube surface bounds
606 // =++>>>> effect in tracking just through the gravitational sagging TOTALLY NEGLIGIBLE=> ignore)
607 // pg is irrelevant for tracking purposes and (at least for the endcaps) is applies to the internal bars only, not to the tubes !!!
608 // =++>>>> IGNORE IT
609 // ep,en: bend the tube by moving (differently) the endplugs ===> the wire straight trajectory is moved w.r.t. the nominal one
610 // in addition the tubes keep their nominal position at the center => the wire is not concentric to
611 // the tube delta_s from ep,en must also be considered for the implementation of the realistic tube
612 // trajectory induced by ep,en
613 // tw,sp,sn,pg (for deltaT and deltaZ) are geometrical effects, that impact on tracking and keep the wire straight.
614
615
616
617 Amg::Vector3D deformPos(locAMDBPos);
618
619 // 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
620 // deformations s0mdt,z0mdt,t0mdt
621 // (always equal to the point at lowest t,z and s=0 of the MDT stack)
622 ATH_MSG_VERBOSE( "** In "<<__func__<<" - moduleWidthS " << moduleWidthS<<", moduleWidthL: "
623 <<moduleWidthL <<", height: "<<height<<", thickness: " <<thickness << "." );
624 ATH_MSG_VERBOSE( "** In "<<__func__<<" - going to correct for B-line the position of Point at " <<Amg::toString(locAMDBPos)
625 << " in the amdb-szt frame" );
626
627 double s0mdt = locAMDBPos.x(); // always I think !
628 if (std::abs(fixedPoint.x()) > 0.01) {
629 s0mdt = locAMDBPos.x() - fixedPoint.x();
630 }
631 double z0mdt = locAMDBPos.y();
632 // unless in the D section of this station there's a dy diff. from 0 for the innermost MDT multilayer (sometimes in the barrel)
633 if (std::abs(fixedPoint.y()) > 0.01) {
634 z0mdt = locAMDBPos.y() - fixedPoint.y();
635 }
636 double t0mdt = locAMDBPos.z();
637 // unless in the D section of this station there's a dz diff. from 0 for the innermost MDT multilayer (often in barrel)
638 if (std::abs(fixedPoint.z()) > 0.01) t0mdt = locAMDBPos.z() - fixedPoint.z();
639 if (z0mdt < 0 || t0mdt < 0) {
640 ATH_MSG_WARNING(""<<__func__<<": correcting the local position of a point outside the mdt station (2 multilayers) volume -- RE "
641 << idHelperSvc()->toStringDetEl(identify()) << " local point: szt=" << Amg::toString(locAMDBPos)
642 << " fixedPoint " <<Amg::toString(fixedPoint) );
643 }
644 ATH_MSG_VERBOSE( "** In "<<__func__<<" - correct for offset of B-line fixed point " << s0mdt << " " << z0mdt << " " << t0mdt);
645
646 double ds{0.},dz{0.},dt{0.};
647 double width_actual = moduleWidthS + (moduleWidthL - moduleWidthS) * (z0mdt / height);
648 double s_rel = s0mdt / (width_actual / 2.);
649 double z_rel = (z0mdt - height / 2.) / (height / 2.);
650 double t_rel = (t0mdt - thickness / 2.) / (thickness / 2.);
651
652 ATH_MSG_VERBOSE( "** In "<<__func__<<" - width_actual: "<<width_actual<<", s_rel: "<<s_rel<<", z_rel: "
653 <<z_rel<<", t_rel: "<<t_rel);
654
655 // sp, sn - cross plate sag out of plane
656 if ((sp != 0) || (sn != 0)) {
657 double ztmp = z_rel * z_rel - 1;
658 dt += 0.5 * (sp + sn) * ztmp + 0.5 * (sp - sn) * ztmp * s_rel;
659 }
660
661 // tw - twist
662 if (tw != 0) {
663 dt -= tw * s_rel * z_rel;
664 dz += tw * s_rel * t_rel * thickness / height;
665 ATH_MSG_VERBOSE( "** In "<<__func__<<": tw=" << tw << " dt, dz " << dt << " " << dz );
666 }
667
668 // eg - global expansion
669 if (eg != 0) {
670 double egppm = eg / 1000.;
671 ds += 0.;
672 dz += z0mdt * egppm;
673 dt += t0mdt * egppm;
674 }
675
676 // ep, en - local expansion
677 //
678 // Imporant note: the chamber height and length, as they denoted in Christoph's talk,
679 // correspond to thickness and height parameters of this function;
680 //
681
682 if ((ep != 0) || (en != 0)) {
683 ep = ep / 1000.;
684 en = en / 1000.;
685 double phi = 0.5 * (ep + en) * s_rel * s_rel + 0.5 * (ep - en) * s_rel;
686 double localDt = phi * (t0mdt - thickness / 2.);
687 double localDz = phi * (z0mdt - height / 2.);
688 dt += localDt;
689 dz += localDz;
690 }
691
692 ATH_MSG_VERBOSE( "posOnDefChamStraighWire: ds,z,t = " << ds << " " << dz << " " << dt );
693 deformPos[0] = locAMDBPos[0] + ds;
694 deformPos[1] = locAMDBPos[1] + dz;
695 deformPos[2] = locAMDBPos[2] + dt;
696
697 return deformPos;
698 }
699
700// Function to apply AsBuilt parameter correction to wire center and end position
701// For definitions of AsBuilt parameters see Florian Bauer's talk:
702// http://atlas-muon-align.web.cern.ch/atlas-muon-align/endplug/asbuilt.pdf
703#if defined(FLATTEN)
704 // We compile this package with optimization, even in debug builds; otherwise,
705 // the heavy use of Eigen makes it too slow. However, from here we may call
706 // to out-of-line Eigen code that is linked from other DSOs; in that case,
707 // it would not be optimized. Avoid this by forcing all Eigen code
708 // to be inlined here if possible.
710#endif
711 void
713 const int tubeLayer, const int tube) const {
715 if (!params) {
716 ATH_MSG_WARNING( "Cannot find Mdt AsBuilt parameters for chamber " << idHelperSvc()->toStringDetEl(identify()) );
717 return;
718 }
719
720 ATH_MSG_VERBOSE( "Applying as-built parameters for chamber " << idHelperSvc()->toStringDetEl(identify())
721 << " tubeLayer=" << tubeLayer << " tube=" << tube);
722
723 constexpr int nsid = 2;
724 using tubeSide_t = MdtAsBuiltPar::tubeSide_t;
725 using multilayer_t = MdtAsBuiltPar::multilayer_t;
726 std::array<MdtAsBuiltPar::tubeSide_t, nsid> tubeSide{tubeSide_t::POS, tubeSide_t::NEG};
727 std::array<Amg::Vector3D, nsid> wireEnd{locAMDBWireEndP, locAMDBWireEndN};
728 multilayer_t ml = (getMultilayer() == 1) ? multilayer_t::ML1 : multilayer_t::ML2;
729
730 const double xmin = *std::min_element(m_firstwire_x.begin(), m_firstwire_x.begin() + m_nlayers) - outerTubeRadius();
731 const int ref_layer = (ml == multilayer_t::ML1) ? m_nlayers : 1;
732 const double y_offset = (ml == multilayer_t::ML1) ? outerTubeRadius() : -outerTubeRadius();
733
734 for (int isid = 0; isid < nsid; ++isid) { // first s>0 then s<0
735 // Compute the reference for the as-built parameters
736 double xref{0.}, yref{0.}, zref{0.};
737 if (barrel()) {
738 xref = -m_Rsize / 2. + m_firstwire_y[ref_layer - 1] + y_offset;
739 zref = -m_Zsize / 2. + xmin;
740 } else {
741 xref = -m_Zsize / 2. + m_firstwire_y[ref_layer - 1] + y_offset;
742 zref = -m_Rsize / 2. + xmin;
743 }
745 Amg::Vector3D reference_point{xref, yref, zref};
746
747 reference_point = toAMDB * reference_point;
748
749 if (isid == 0)
750 reference_point = reference_point + 0.5 * getNominalTubeLengthWoCutouts(ref_layer, 1) * Amg::Vector3D::UnitX();
751 else
752 reference_point = reference_point -0.5 * getNominalTubeLengthWoCutouts(ref_layer, 1) * Amg::Vector3D::UnitX();
753
754 ATH_MSG_VERBOSE("AMDB transform "<<idHelperSvc()->toStringDetEl(identify())<<
755 " "<<GeoTrf::toString(toAMDB, true)<<", reference point: "<<Amg::toString(reference_point));
756
757 int layer_delta = tubeLayer;
758 if (ml == multilayer_t::ML1) layer_delta = m_nlayers + 1 - tubeLayer;
759
760 // Get the As-Built parameters for this ML and side of the chamber
761 double zpitch = params->zpitch(ml, tubeSide[isid]);
762 double ypitch = params->ypitch(ml, tubeSide[isid]);
763 double stagg = (double)params->stagg(ml, tubeSide[isid]);
764 double alpha = params->alpha(ml, tubeSide[isid]);
765 double y0 = params->y0(ml, tubeSide[isid]);
766 double z0 = params->z0(ml, tubeSide[isid]);
767
768 // Find the vector from the reference_point to the endplug
769 int do_stagg = (layer_delta - 1) % 2; // 0 for layer 1 and 3, 1 for layer 2 and 4
770 double offset_stagg = ((double)do_stagg) * 0.5 * zpitch * stagg;
771 Amg::Vector3D end_plug(0., (tube - 1.0) * zpitch + offset_stagg, (layer_delta - 1) * ypitch);
772
773 const Amg::Transform3D amgTransf{Amg::getRotateX3D(-alpha)};
774 end_plug = amgTransf * end_plug;
775
776 // Calculate x position, which varies for endcap chambers
777 double xshift = 0.;
778 if (isid == 0)
779 xshift = 0.5 * getNominalTubeLengthWoCutouts(tubeLayer, tube) - 0.5 * getNominalTubeLengthWoCutouts(ref_layer, 1);
780 else
781 xshift = -0.5 * getNominalTubeLengthWoCutouts(tubeLayer, tube) + 0.5 * getNominalTubeLengthWoCutouts(ref_layer, 1);
782
783 Amg::Vector3D ret(reference_point.x() + xshift, reference_point.y() + z0 + end_plug.y(),
784 reference_point.z() + y0 + end_plug.z());
785
786 // Warn if result of calculation is too far off
787 // BIL1A13 has as-built parameters up to 3mm off, giving the size of the cut
788 if ((ret - wireEnd[isid]).mag() > 3. * CLHEP::mm) {
789 ATH_MSG_WARNING( "Large as-built correction for chamber " << idHelperSvc()->toStringDetEl(identify()) << ", side "
790 << isid << ", Delta " << Amg::toString(ret - wireEnd[isid]) );
791 }
792 ATH_MSG_VERBOSE(( tubeSide[isid] == tubeSide_t::POS ? "positive" : "negative")<<" wire end has moved from "
793 <<Amg::toString(wireEnd[isid])<<" to "<<Amg::toString(ret));
794
795 // Save the result
796 if (tubeSide[isid] == tubeSide_t::POS)
797 locAMDBWireEndP = ret;
798 else
799 locAMDBWireEndN = ret;
800 }
801 }
802 std::unique_ptr<MdtReadoutElement::GeoInfo> MdtReadoutElement::makeGeoInfo(const int tubeLayer, const int tube) const {
804 return std::make_unique<GeoInfo>(std::move(transform));
805 }
806
807 const MdtReadoutElement::GeoInfo& MdtReadoutElement::geoInfo(const int tubeLayer, const int tube) const {
808 size_t itube = (tubeLayer - 1) * m_ntubesperlayer + tube - 1;
809 if (itube >= m_tubeGeo.size()) {
810 ATH_MSG_WARNING(__func__<<"() :"<<__LINE__<<" called with tubeLayer or tube out of range in chamber "
811 << idHelperSvc()->toStringDetEl(identify()) << " : layer " << tubeLayer << " max " << m_nlayers << " tube " << tube
812 << " max " << m_ntubesperlayer << " will compute transform for first tube in this chamber" );
813 ATH_MSG_WARNING( "Please run in DEBUG mode to get extra diagnostic" );
814 itube = 0;
815 }
816
817 const CxxUtils::CachedUniquePtr<GeoInfo>& ptr = m_tubeGeo.at(itube);
818 if (!ptr) {
819 ptr.set(makeGeoInfo(tubeLayer, tube));
820 if (!m_haveTubeGeo) m_haveTubeGeo = true;
821 }
822 return *ptr;
823 }
824
825 const Amg::Transform3D& MdtReadoutElement::transform(const int tubeLayer, const int tube) const {
826 return geoInfo(tubeLayer, tube).m_transform;
827 }
828
829 const Trk::StraightLineSurface& MdtReadoutElement::surface(const int tubeLayer, const int tube) const {
830
831 int ntot_tubes = m_nlayers * m_ntubesperlayer;
832 int itube = (tubeLayer - 1) * m_ntubesperlayer + tube - 1;
833 // consistency checks
834 if (itube >= ntot_tubes) {
835 ATH_MSG_WARNING( "surface called with tubeLayer or tube out of range in chamber "
836 << idHelperSvc()->toStringDetEl(identify()) << " : layer " << tubeLayer << " max " << m_nlayers << " tube " << tube
837 << " max " << m_ntubesperlayer << " will compute surface for first tube in this chamber" );
838 ATH_MSG_WARNING( "Please run in DEBUG mode to get extra diagnostic" );
839 itube = 0;
840 }
841
843 if (!ptr) {
844 Identifier id = m_idHelper.channelID(identify(), getMultilayer(), tubeLayer, tube);
845 ptr.set(std::make_unique<Trk::StraightLineSurface>(*this, id));
847 }
848 return *ptr;
849 }
850 const Trk::CylinderBounds& MdtReadoutElement::bounds(const int tubeLayer, const int tube) const {
851 int istep = 0;
852 int ntot_steps = m_nsteps;
853
854 if (hasCutouts() && manager()->MinimalGeoFlag() == 0) {
855 ntot_steps = m_nlayers * m_ntubesperlayer;
856 istep = (tubeLayer - 1) * m_ntubesperlayer + tube - 1;
857 } else {
858 if (endcap()) istep = int((tube - 1) / m_ntubesinastep);
859
860 if (istep < 0 || istep >= ntot_steps) {
861 ATH_MSG_WARNING( "bounds for Element named "<< " with tech. " << getTechnologyType()
862 << " DEid = " << idHelperSvc()->toStringDetEl(identify()) << " called with: tubeL, tube " << tubeLayer << " " << tube
863 << "; step " << istep << " out of range 0-" << m_nsteps - 1 << " m_ntubesinastep " << m_ntubesinastep );
864 ATH_MSG_WARNING( "Please run in DEBUG mode to get extra diagnostic; setting istep = 0" );
865 }
866 }
867 if ((unsigned int)istep >= m_tubeBounds.size()) {
868 THROW_EXCEPTION(__func__<<"("<<tubeLayer<<","<<tube<<") but m_tubeBounds.size()="<<m_tubeBounds.size()<<" for "<<
869 idHelperSvc()->toStringDetEl(identify()));
870 }
872 if (!ptr) {
873 double tubelength = getTubeLengthForCaching(tubeLayer, tube);
874 ptr.set(std::make_unique<Trk::CylinderBounds>(innerTubeRadius(), 0.5 * tubelength - m_deadlength));
876 }
877 return *ptr;
878 }
879 const Amg::Vector3D& MdtReadoutElement::center(const int tubeLayer, const int tube) const { return geoInfo(tubeLayer, tube).m_center; }
881 if (!m_elemNormal.isValid()) { m_elemNormal.set(transform().linear() * Amg::Vector3D::UnitX()); }
882 return *m_elemNormal.ptr();
883 }
884
886 if (!m_associatedSurface) {
887 Amg::RotationMatrix3D muonTRotation(transform().rotation());
888 Amg::RotationMatrix3D surfaceTRotation;
889 surfaceTRotation.col(0) = muonTRotation.col(1);
890 surfaceTRotation.col(1) = muonTRotation.col(2);
891 surfaceTRotation.col(2) = muonTRotation.col(0);
892
893 Amg::Transform3D trans3D(surfaceTRotation);
894 trans3D.pretranslate(transform().translation());
895
896 if (barrel()) {
897 m_associatedSurface.set(std::make_unique<Trk::PlaneSurface>(Amg::Transform3D(trans3D), getSsize() * 0.5,
898 getZsize() * 0.5));
899 } else {
900 m_associatedSurface.set(std::make_unique<Trk::PlaneSurface>(Amg::Transform3D(trans3D), getSsize() * 0.5,
901 getLongSsize() * 0.5,
902 getRsize() * 0.5));
903 }
904 }
905 return *m_associatedSurface;
906 }
907
909
911 if (!m_associatedBounds) {
912 if (barrel()) {
914 std::make_unique<Trk::RectangleBounds>(getSsize() / 2., getZsize() / 2.));
915 } else {
916 m_associatedBounds.set(std::make_unique<Trk::TrapezoidBounds>(
917 getSsize() / 2., getLongSsize() / 2., getRsize() / 2.));
918 }
919 }
920 return *m_associatedBounds;
921 }
923 ATH_MSG_DEBUG( "Clearing cache for ReadoutElement " << idHelperSvc()->toStringDetEl(identify()) );
925 m_associatedSurface.release();
926 }
927 else ATH_MSG_VERBOSE( "no associated surface to be deleted" );
928
929 if (m_associatedBounds) {
930 m_associatedBounds.release();
931 } ATH_MSG_VERBOSE( "no associated bounds to be deleted" );
932 m_elemNormal.reset();
933 if (m_haveTubeSurfaces) {
934 m_haveTubeSurfaces = false;
935 for (auto& s : m_tubeSurfaces) { s.release(); }
936 }
937 if (m_haveTubeGeo) {
938 m_haveTubeGeo = false;
939 for (auto& g : m_tubeGeo) { g.release(); }
940 }
941 if (m_haveTubeBounds) {
942 m_haveTubeBounds = false;
943 for (auto& b : m_tubeBounds) { b.release(); }
944 }
945 // reset here the deform-related transforms
946 if (m_haveDeformTransf) {
947 m_haveDeformTransf = false;
948 for (auto& d : m_deformTransf) { d.release(); }
949 }
950 }
951
953 ATH_MSG_DEBUG( "Setting B-line for " << idHelperSvc()->toStringDetEl(identify()) );
954 if (m_BLinePar == bLine) {
955 return;
956 }
957 m_BLinePar = bLine;
958 refreshCache();
959 }
960
962 ATH_MSG_DEBUG( "Filling cache for ReadoutElement " << idHelperSvc()->toStringDetEl(identify()));
963
964 const Trk::PlaneSurface* tmpSurface = dynamic_cast<const Trk::PlaneSurface*>(&surface()); //<! filling m_associatedSurface
965 const Trk::SurfaceBounds* tmpBounds = nullptr; //<! filling m_associatedBounds
966 if (barrel())
967 tmpBounds = dynamic_cast<const Trk::RectangleBounds*>(&bounds());
968 else
969 tmpBounds = dynamic_cast<const Trk::TrapezoidBounds*>(&bounds());
970 ATH_MSG_VERBOSE( "global Surface / Bounds pointers " << tmpSurface << " " << tmpBounds );
971 ATH_MSG_VERBOSE( "global Normal " << normal() );
972
973 const Trk::CylinderBounds* tmpCil = nullptr;
974 const Trk::StraightLineSurface* tmpSaggL = nullptr;
975 Amg::Vector3D myPoint{Amg::Vector3D::Zero()};
976 Amg::Transform3D myTransform{Amg::Transform3D::Identity()};
977 for (int tl = 1; tl <= getNLayers(); ++tl) {
978 for (int tube = 1; tube <= getNtubesperlayer(); ++tube) {
979 // in case of BMG chambers, do not check the 'dead' tubes
980 // (the tubes are numbered from 1-54 for each however there are cutouts for the
981 // alignment system where no tubes are built-in, meaning, those tubes do not exist/are 'dead')
982 if (manager()->mdtIdHelper()->isBMG(identify())) {
983 PVConstLink cv = getMaterialGeom();
984 // usually the tube number corresponds to the child number, however for
985 // BMG chambers full tubes are skipped during the building process
986 // therefore the matching needs to be done via the volume ID
987 int packed_id = tube + maxNTubesPerLayer * tl;
988 bool found = false;
989 geoGetIds(
990 [&](int id) {
991 if (!found && id == packed_id) {
992 myTransform = transform(tl, tube); //<! filling m_tubeTransf
993 myPoint = center(tl, tube); //<! filling m_tubeCenter
994 tmpCil = dynamic_cast<const Trk::CylinderBounds*>(&bounds(tl, tube)); //<! filling m_tubeBounds
995 tmpSaggL = dynamic_cast<const Trk::StraightLineSurface*>(&surface(tl, tube)); //<! filling m_tubeSurfaces
996 found = true;
997 }
998 },
999 &*cv);
1000 if (found) {
1001 ATH_MSG_VERBOSE( "tubeLayer/tube " << tl << " " << tube << " transform at origin "
1002 << Amg::toString(myTransform.linear()) );
1003 ATH_MSG_VERBOSE( "tubeLayer/tube " << tl << " " << tube << " tube center " << myPoint );
1004 ATH_MSG_VERBOSE( "tubeLayer/tube " << tl << " " << tube << " tube bounds pointer " << tmpCil );
1005 ATH_MSG_VERBOSE( "tubeLayer/tube " << tl << " " << tube << " tube surface pointer " << tmpSaggL );
1006 }
1007 } else {
1008 // print in order to compute !!!
1009 myTransform = transform(tl, tube); //<! filling m_tubeTransf
1010 myPoint = center(tl, tube); //<! filling m_tubeCenter
1011 tmpCil = dynamic_cast<const Trk::CylinderBounds*>(&bounds(tl, tube)); //<! filling m_tubeBounds
1012 tmpSaggL = dynamic_cast<const Trk::StraightLineSurface*>(&surface(tl, tube)); //<! filling m_tubeSurfaces
1013 ATH_MSG_VERBOSE( "tubeLayer/tube " << tl << " " << tube << " transform at origin "
1014 << Amg::toString(myTransform.translation()) );
1015 ATH_MSG_VERBOSE( "tubeLayer/tube " << tl << " " << tube << " tube center " << myPoint );
1016 ATH_MSG_VERBOSE( "tubeLayer/tube " << tl << " " << tube << " tube bounds pointer " << tmpCil );
1017 ATH_MSG_VERBOSE( "tubeLayer/tube " << tl << " " << tube << " tube surface pointer " << tmpSaggL );
1018 }
1019 }
1020 }
1021 }
1022
1024 if (idHelperSvc()->detElId(id) != identify()) return false;
1025 int layer = m_idHelper.tubeLayer(id);
1026 if (layer < 1 || layer > getNLayers()) return false;
1027 int tube = m_idHelper.tube(id);
1028 return tube >= 1 && tube <= getNtubesperlayer();
1029 }
1030
1031 // **************************** interfaces related to Tracking *****************************************************)
1032
1033} // 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.
std::vector< CxxUtils::CachedUniquePtr< Trk::StraightLineSurface > > m_tubeSurfaces
Amg::Vector3D localTubePos(const Identifier &id) const
std::atomic< bool > m_haveTubeSurfaces
Flag whether any elements have been inserted into the corresponding vectors.
std::unique_ptr< GeoInfo > makeGeoInfo(const int tubelayer, const int tube) 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.
std::vector< CxxUtils::CachedUniquePtr< Amg::Transform3D > > m_deformTransf
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
Amg::Vector3D tubeFrame_localROPos(const int tubelayer, const int tube) const
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.
virtual const Amg::Transform3D & transform(const Identifier &id) const override final
Return local to global transform associated with this identifier.
double distanceFromRO(const Amg::Vector3D &GlobalHitPosition, const Identifier &id) const
double RODistanceFromTubeCentre(const Identifier &id) const
std::vector< CxxUtils::CachedUniquePtr< Trk::CylinderBounds > > m_tubeBounds
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.
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.
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 planaer rectangular or trapezoidal surface in the ATLAS detector.
Bounds for a rectangular, planar 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.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
Bounds for a trapezoidal, planar 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
CachedUniquePtrT< const T > CachedUniquePtr
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