ATLAS Offline Software
Loading...
Searching...
No Matches
SiDetectorElement.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
11
13
16#include "GeoModelKernel/GeoVFullPhysVol.h"
24
25#include "CLHEP/Geometry/Vector3D.h"
26#include "CLHEP/Units/SystemOfUnits.h"
27#include "CLHEP/Vector/ThreeVector.h"
28
29#include <cassert>
30#include <cmath>
31
32namespace InDetDD {
33 using Trk::distPhi;
34 using Trk::distEta;
35 using Trk::distDepth;
36
37 // Constructor with parameters:
40 const GeoVFullPhysVol* geophysvol,
41 const SiCommonItems* commonItems,
42 const GeoAlignmentStore* geoAlignStore) :
43 SolidStateDetectorElementBase(id,design,geophysvol,commonItems,geoAlignStore),
45 {
47 }
48
49 // Destructor:
51
52 bool
54 {
55 if (const auto *const pIdHelper= getIdHelper();isPixel() and isBarrel() and
57 const PixelID* p_pixelId = static_cast<const PixelID*>(pIdHelper);
58 return (0==p_pixelId->layer_disk(m_id));
59 } else {
60 return false;
61 }
62 }
63
64 bool
66 {
67 if (const auto *const pIdHelper= getIdHelper(); isPixel() and isBarrel()
68 and pIdHelper->helper() == AtlasDetectorID::HelperType::Pixel) {
69 const PixelID* p_pixelId = static_cast<const PixelID*>(pIdHelper);
70 return ( 0==p_pixelId->layer_disk(m_id));
71 } else {
72 return false;
73 }
74 }
75
76 bool
78 {
79 if (const auto *const pIdHelper = getIdHelper(); isPixel() and isBarrel() and
81 const PixelID* p_pixelId = static_cast<const PixelID*>(pIdHelper);
82 return ( 1==p_pixelId->layer_disk(m_id));
83 } else {
84 return false;
85 }
86 }
87
90 {
91 Identifier id; // Will be initialized in an invalid state.
92
93 // If something fails it returns the id in an invalid state.
94
95 if (cellId.isValid()) {
96 const auto *const pAtlasHelper = getIdHelper();
97 if (isPixel()) {
98 if (pAtlasHelper->helper() == AtlasDetectorID::HelperType::Pixel) {
99 const PixelID* pixelIdHelper = static_cast<const PixelID*>(pAtlasHelper);
100 id = pixelIdHelper->pixel_id(m_id, cellId.phiIndex(), cellId.etaIndex());
101 }
102 } else if (isSCT()) {
103
104 if (pAtlasHelper->helper() == AtlasDetectorID::HelperType::SCT) {
105 const SCT_ID* sctIdHelper = static_cast<const SCT_ID*>(pAtlasHelper);
106 id = sctIdHelper->strip_id(m_id, cellId.strip());
107 }
108 } else if (isPLR()) {
109 if (pAtlasHelper->helper() == AtlasDetectorID::HelperType::PLR) {
110 const PLR_ID* plrIdHelper = static_cast<const PLR_ID*>(pAtlasHelper);
111 id = plrIdHelper->pixel_id(m_id, cellId.phiIndex(), cellId.etaIndex());
112 }
113 }
114 }
115
116 return id;
117 }
118
121 {
122 SiCellId cellId; // Initialized in invalid state.
123
124 // If something fails it returns the cellId in an invalid state.
125
126 if (identifier.is_valid()) {
127 const auto *const pAtlasHelper = getIdHelper();
128 if (isPixel() and pAtlasHelper->helper() == AtlasDetectorID::HelperType::Pixel) {
129 const auto *const pixelIdHelper = static_cast<const PixelID*>(pAtlasHelper);
130 cellId = SiCellId(pixelIdHelper->phi_index(identifier), pixelIdHelper->eta_index(identifier));
131 } else if (isSCT() and pAtlasHelper->helper() == AtlasDetectorID::HelperType::SCT) {
132 const SCT_ID* sctIdHelper = static_cast<const SCT_ID*>(pAtlasHelper);
133 //This adds some extra code for supporting rows,
134 //but this method is only used in validation-type code
135 //So should not add an overhead in normal running
136 //(although we perhaps still try to avoid this...)
137 int strip = sctIdHelper->strip(identifier);
138 int row = sctIdHelper->row(identifier);
139 if(row>0){
140 const auto &sctDesign = *static_cast<const SiDetectorDesign *>(m_siDesign);
141 int strip1D = sctDesign.strip1Dim(strip, row);
142 cellId = SiCellId(strip1D);
143 }else {
144 cellId = SiCellId(strip);
145 }
146
147 } else if (isPLR() and pAtlasHelper->helper() == AtlasDetectorID::HelperType::PLR) {
148 const PLR_ID* plrIdHelper = static_cast<const PLR_ID*>(pAtlasHelper);
149 cellId = SiCellId(plrIdHelper->phi_index(identifier), plrIdHelper->eta_index(identifier));
150 }
151 }
152
153 return cellId;
154 }
155
156 const std::vector<const Trk::Surface*>&
158 {
159 if (!m_surfaces.isValid()) {
160 std::vector<const Trk::Surface*> s;
161 s.push_back(&surface());
162 if (otherSide()) {
163 s.push_back(&(otherSide()->surface()));
164 }
165 m_surfaces.set (std::move (s));
166 }
167
168 // return the surfaces
169 return *m_surfaces.ptr();
170 }
171
172 const Amg::Transform3D&
174 {
175 return (isModuleFrame()) ? transform() : m_otherSide->transform();
176 }
177
180 {
181 return (isModuleFrame()) ? defTransform() : m_otherSide->defTransform();
182 }
183
184 // Take a transform in the local reconstruction and return it in the module frame
185 // For a given transform l in frame A. The equivalent transform in frame B is
186 // B.inverse() * A * l * A.inverse() * B
187 // Here A is the local to global transform of the element and B is the local to global
188 // transform of the module.
189 // If we are already in the module frame then there is nothing to do, we just return the
190 // transform that is input. Otherwise we use the above formula.
193 {
194 if (isModuleFrame()) {
195 return localTransform;
196 } else {
197 return m_otherSide->transform().inverse() * transform() * localTransform * transform().inverse() * m_otherSide->transform();
198 }
199 }
200
203 {
204 if (isModuleFrame()) {
205 return {}; // Identity
206 } else {
207 return m_otherSide->transform().inverse() * transform();
208 }
209 }
210
211 bool
213 {
214 // The module frame is the axial side.
215 // NB isStereo returns false for the pixel and so
216 // isModuleFrame is always true for the pixel.
217
218 return !isStereo();
219 }
220
221 // compute sin(tilt angle) at center:
222 double
224 {
225 // Tilt is defined as the angle between a refVector and the sensor normal.
226 // In barrel refVector = unit vector radial.
227 // in endcap it is assumed there is no tilt.
228 // sinTilt = (refVector cross normal) . z
229
230 // tilt angle is not defined for the endcap
231 if (isEndcap()) return 0.;
232
233 // Angle between normal and radial vector.
234 // HepGeom::Vector3D<double> refVector(m_center.x(), m_center.y(), 0);
235 // return (refVector.cross(m_normal)).z()/refVector.mag();
236 // or the equivalent
237 const Amg::Vector3D& normal = this->normal();
238 const Amg::Vector3D& center = this->center();
239 return (center.x() * normal.y() - center.y() * normal.x()) / center.perp();
240 }
241
242 double
244 {
245 // tilt angle is not defined for the endcap
246 if (isEndcap()) return 0.;
247
248 Amg::Vector3D point = globalPosition(localPos);
249 return sinTilt(point);
250 }
251
252 double
254 {
255 // It is assumed that the global position is already in the plane of the element.
256
257 // tilt angle is not defined for the endcap
258 if (isEndcap()) return 0.;
259
260 // Angle between normal and radial vector.
261 //HepGeom::Vector3D<double> refVector(globalPos.x(), globalPos.y(), 0);
262 //return (refVector.cross(m_normal)).z()/refVector.mag();
263 // or the equivalent
264 const Amg::Vector3D& normal = this->normal();
265 return (globalPos.x() * normal.y() - globalPos.y() * normal.x()) / globalPos.perp();
266 }
267
268 double
270 {
271 return sinStereoImpl();
272 }
273
274 double
276 {
277 Amg::Vector3D point=globalPosition(localPos);
278 return sinStereoImpl(point);
279 }
280
281 double
283 {
284 return sinStereoImpl(globalPos);
285 }
286
287 double
289 {
290 return static_cast<const SiDetectorDesign *>(m_design)->sinStripAngleReco(localPos[0], localPos[1]);
291 }
292
293 double
295 {
296 return sinStereoLocal(localPosition(globalPos));
297 }
298
299 bool
301 {
302 if (!m_isStereo.isValid()) {
304 }
305
306 return *m_isStereo.ptr();
307 }
308
310 {
311 // Calculate rz = r (barrel) or z (endcap)
312 // Use center of sensor ((0,0,0) in local coordinates) for determining this.
313 // HepGeom::Point3D<double> globalCenter = globalPosition(HepGeom::Point3D<double>(0,0,0));
314 if (isBarrel()) {
315 return center().perp(); // r
316 } else {
317 return center().z(); // z
318 }
319 }
320
321
322 bool
324 {
325 //again, can we avoid casting here?
326 return static_cast<const SiDetectorDesign *>(m_siDesign)->nearBondGap(localPosition, etaTol);
327 }
328
329 bool
331 {
332 return static_cast<const SiDetectorDesign *>(m_siDesign)->nearBondGap(localPosition(globalPosition), etaTol);
333 }
334
335
336
337 // Special method for SCT to retrieve the two ends of a "strip"
338 std::pair<Amg::Vector3D,Amg::Vector3D>
340 {
341 //again with the casting...
342 const std::pair<Amg::Vector2D,Amg::Vector2D> localEnds=
343 static_cast<const SiDetectorDesign *>(m_siDesign)->endsOfStrip(position);
344 return std::pair<Amg::Vector3D,Amg::Vector3D >(globalPosition(localEnds.first),
345 globalPosition(localEnds.second));
346 }
347
348 void
350 {
351 if (!m_id.is_valid()) throw std::runtime_error("SiDetectorElement: Invalid identifier");
352
353 // Set booleans for wether we are pixel/sct barrel/endcap
356 // we use is_lumi here instead of is_plr because is_plr is currently only setup
357 // for ExpandedIdentifiers and not Identifiers, which is what is needed here.
359 if (!m_isPixel && !m_isSCT && !m_isPLR) {
360 ATH_MSG_WARNING("Element id is not for pixel, SCT, or PLR");
361 }
362
363 // Set m_idHash. Also set m_isBarrel.
364 if (isPixel() and getIdHelper()->helper() == AtlasDetectorID::HelperType::Pixel) {
365 const PixelID* pixelId = static_cast<const PixelID*>(getIdHelper());
366 if (pixelId) {
367 m_isBarrel = pixelId->is_barrel(m_id);
368 m_idHash = pixelId->wafer_hash(m_id);
369
370 if (pixelId->is_dbm(m_id)) {
371 m_isBarrel = false;
372 m_isDBM = true;
373 }
374 }
375 } else if (isSCT() and getIdHelper()->helper() == AtlasDetectorID::HelperType::SCT) {
376 const SCT_ID* sctId = static_cast<const SCT_ID*>(getIdHelper());
377 if (sctId) {
378 m_isBarrel = sctId->is_barrel(m_id);
379 m_idHash = sctId->wafer_hash(m_id);
380 }
381 } else if (isPLR() and getIdHelper()->helper() == AtlasDetectorID::HelperType::PLR) {
382 const PLR_ID* plrId = static_cast<const PLR_ID*>(getIdHelper());
383 if (plrId) {
384 m_isBarrel = plrId->is_barrel(m_id);
385 m_idHash = plrId->wafer_hash(m_id);
386 }
387 }
388
389 if (!m_idHash.is_valid()) throw std::runtime_error("SiDetectorElement: Unable to set IdentifierHash");
390
391 // Set surface
392 m_surface = std::make_unique<Trk::PlaneSurface>(*this);
393
394 }
395
396 bool
398 {
399 if (isSCT() and m_otherSide and getIdHelper()->helper() == AtlasDetectorID::HelperType::SCT) {
400 double sinStereoThis = std::abs(sinStereoImpl()); // Call the private impl method
401 double sinStereoOther = std::abs(m_otherSide->sinStereo());
402 if (std::abs(sinStereoThis - sinStereoOther) < 1e-5) {
403 // If they happen to be equal then set side0 as axial and side1 as stereo.
404 const SCT_ID* sctId = static_cast<const SCT_ID*>(getIdHelper());
405 if (sctId) {
406 int side = sctId->side(m_id);
407 return (side == 1);
408 }
409 } else {
410 // set the stereo side as the one with largest absolute sinStereo.
411 return (sinStereoThis > sinStereoOther);
412 }
413 }
414
415 return false;
416 }
417
418 double
420 {
421 // Stereo is the angle between a refVector and a vector along the strip/pixel in eta direction.
422 // I'm not sure how the sign should be defined. I've defined it here
423 // with rotation sense respect to normal,
424 // where normal is away from IP in barrel and in -ve z direction in endcap
425
426 // In Barrel refVector = unit vector along z axis,
427 // in endcap refVector = unit vector radial.
428 //
429 // sinStereo = (refVector cross stripAxis) . normal
430 // = (refVector cross etaAxis) . normal
431 // = refVector . (etaAxis cross normal)
432 // = refVector . phiAxis
433 //
434 // in Barrel we use
435 // sinStereo = refVector . phiAxis
436 // = phiAxis.z()
437 //
438 // in endcap we use
439 // sinStereo = (refVector cross etaAxis) . normal
440 // = -(center cross etaAxis) . zAxis
441 // = (etaAxis cross center). z()
442
443 //Since these are barrel, endcap, sensor-type, specific, might be better for these to be calculated in the design()
444 //However, not clear how one could do that for the annulus calculation which uses global frame
445 double sinStereo = 0.;
446 auto designShape = m_siDesign->shape();
447 if (isBarrel()) {
448 sinStereo = this->phiAxis().z();
449 } else { // endcap
450 if (designShape == InDetDD::Annulus) { //built-in Stereo angle for Annulus shape sensor
451 Amg::Vector3D sensorCenter = m_siDesign->sensorCenter();
452 //Below retrieved method will return -sin(m_Stereo), thus sinStereolocal = sin(m_Stereo)
453 double sinStereoReco = - (m_siDesign->sinStripAngleReco(sensorCenter[1], sensorCenter[0]));
454 double cosStereoReco = sqrt(1-sinStereoReco*sinStereoReco);
455 double radialShift = sensorCenter[0];
456 //The focus of all strips in the local reco frame
457 Amg::Vector2D localfocus(-radialShift*sinStereoReco, radialShift - radialShift*cosStereoReco);
458 //The focus of all strips in the global frame
459 Amg::Vector3D globalfocus(globalPosition(localfocus));
460 //The direction of x-axis of the Strip frame in the global frame
461 const Amg::Vector3D& center = this->center();
462 Amg::Vector3D globalSFxAxis =(center - globalfocus)/radialShift;
463 //Stereo angle is the angle between global radial direction and the x-axis of the Strip frame in the global frame
464 sinStereo = (center.y() * globalSFxAxis.x() - center.x() * globalSFxAxis.y()) / center.perp();
465 }
466 // else if (designShape == InDetDD::PolarAnnulus) {} // Polar specialisation in future
467 else { // barrel
468 const Amg::Vector3D& etaAxis = this->etaAxis();
469 const Amg::Vector3D& center = this->center();
470 sinStereo = (center.y() * etaAxis.x() - center.x() * etaAxis.y()) / center.perp();
471 }
472 }
473 return sinStereo;
474 }
475
476 double
478 {
479 //
480 // sinStereo = (refVector cross stripAxis) . normal
481 //
482 double sinStereo = 0.;
483 if (isBarrel()) {
484 if (m_siDesign->shape() != InDetDD::Trapezoid) {
485 sinStereo = this->phiAxis().z();
486 } else { // trapezoid
487 assert (minWidth() != maxWidth());
488 double radius = width() * length() / (maxWidth() - minWidth());
489 const Amg::Vector3D& etaAxis = this->etaAxis();
490 const Amg::Vector3D& center = this->center();
491 const Amg::Vector3D& normal = this->normal();
492 Amg::Vector3D stripAxis = radius * etaAxis + globalPos - center;
493 sinStereo = (stripAxis.x() * normal.y() - stripAxis.y() * normal.x()) / stripAxis.mag();
494 }
495 } else { // endcap
496 if (m_siDesign->shape() != InDetDD::Trapezoid) {
497 const Amg::Vector3D& etaAxis = this->etaAxis();
498 sinStereo = (globalPos.y() * etaAxis.x() - globalPos.x() * etaAxis.y()) / globalPos.perp();
499 } else { // trapezoid
500 assert (minWidth() != maxWidth());
501 const Amg::Vector3D& etaAxis = this->etaAxis();
502 const Amg::Vector3D& center = this->center();
503 double radius = width() * length() / (maxWidth() - minWidth());
504 // Only need projection in xy plane.
505 double stripAxisX = globalPos.x() - center.x() + etaAxis.x()*radius;
506 double stripAxisY = globalPos.y() - center.y() + etaAxis.y()*radius;
507 double norm = 1./(radius*sqrt(stripAxisX*stripAxisX + stripAxisY*stripAxisY));
508 sinStereo = norm * (stripAxisX * globalPos.y() - stripAxisY * globalPos.x());
509 }
510 }
511 return sinStereo;
512 }
513
514
515
516} // namespace InDetDD
#define ATH_MSG_WARNING(x)
This class provides an interface to generate or decode an identifier for the upper levels of the dete...
This is an Identifier helper class for the Pixel subdetector.
This is an Identifier helper class for the SCT subdetector.
bool is_sct(Identifier id) const
bool is_pixel(Identifier id) const
bool is_lumi(Identifier id) const
virtual HelperType helper() const
Type of helper, defaulted to 'Unimplemented'.
Ensure that the extensions for the Vector3D are properly loaded.
Identifier for the strip or pixel cell.
Definition SiCellId.h:29
int strip() const
Get strip number. Equivalent to phiIndex().
Definition SiCellId.h:131
int phiIndex() const
Get phi index. Equivalent to strip().
Definition SiCellId.h:122
bool isValid() const
Test if its in a valid state.
Definition SiCellId.h:136
int etaIndex() const
Get eta index.
Definition SiCellId.h:114
Helper class to concentrate common items, such as the pointer to the IdHelper, the lorentzAngle tool ...
Base class for the detector design classes for Pixel and SCT.
virtual int strip1Dim(int strip, int row) const
only relevant for SCT.
virtual SiCellId cellIdFromIdentifier(const Identifier &identifier) const override final
SiCellId from Identifier.
virtual const SiDetectorDesign & design() const override final
access to the local description (inline):
bool nearBondGap(const Amg::Vector2D &localPosition, double etaTol) const
Test if near bond gap within tolerances.
virtual double get_rz() const override final
bool isStereo() const
Check if it is the stereo side (useful for SCT)
std::pair< Amg::Vector3D, Amg::Vector3D > endsOfStrip(const Amg::Vector2D &position) const
Special method for SCT to retrieve the two ends of a "strip" Returned coordinates are in global frame...
Amg::Transform3D localToModuleFrame(const Amg::Transform3D &localTransform) const
Take a transform of the local element frame and return its equivalent in the module frame.
double sinStereoImpl() const
Private implementation method with no lock at center.
CxxUtils::CachedValue< bool > m_isStereo
double sinStereo() const
Compute sin(stereo angle) at a given position: at center.
void commonConstructor()
Common code for constructors.
Amg::Transform3D defModuleTransform() const
Default module to global frame transform, ie with no misalignment.
const SiDetectorElement * otherSide() const
Useful for SCT only.
double sinStereoLocal(const Amg::Vector2D &localPos) const
Angle of strip in local frame with respect to the etaAxis.
const SiDetectorElement * m_otherSide
double sinTilt() const
Compute sin(tilt angle) at a given position: at center.
virtual ~SiDetectorElement()
Destructor.
virtual Identifier identifierFromCellId(const SiCellId &cellId) const override final
Identifier <-> SiCellId (ie strip number or pixel eta_index,phi_index) Identifier from SiCellId (ie s...
const SiDetectorDesign * m_siDesign
Amg::Transform3D localToModuleTransform() const
Transformation from local element to module frame.
const Amg::Transform3D & moduleTransform() const
Module to global frame transform.
const std::vector< const Trk::Surface * > & surfaces() const
Returns the full list of surfaces associated to this detector element.
bool isModuleFrame() const
Check if the element and module frame are the same.
SiDetectorElement()=delete
Don't allow no-argument constructor.
CxxUtils::CachedValue< std::vector< const Trk::Surface * > > m_surfaces
bool determineStereo() const
Find isStereo.
double length() const
Length in eta direction (z - barrel, r - endcap)
Amg::Vector2D localPosition(const HepGeom::Point3D< double > &globalPosition) const
transform a global position into a 2D local position (reconstruction frame) (inline)
const DetectorDesign * m_design
local description of this detector element
double width() const
Methods from design (inline)
virtual const Amg::Vector3D & normal() const override final
Get reconstruction local normal axes in global frame.
virtual const Amg::Transform3D & transform() const override final
Return local to global transform.
double maxWidth() const
Max width.
HepGeom::Point3D< double > globalPosition(const HepGeom::Point3D< double > &localPos) const
transform a reconstruction local position into a global position (inline):
virtual const Amg::Vector3D & center() const override final
Center in global coordinates.
SolidStateDetectorElementBase(const Identifier &id, const DetectorDesign *design, const GeoVFullPhysVol *geophysvol, const SiCommonItems *commonItems, const GeoAlignmentStore *geoAlignStore=nullptr)
Constructor with parameters.
double minWidth() const
Min width.
IdentifierHash m_idHash
hash id of this detector element
const AtlasDetectorID * getIdHelper() const
Returns the id helper (inline)
Trk::Surface & surface()
Element Surface.
Identifier m_id
identifier of this detector element
This is a Identifier helper class for the PLR subdetector.
Definition PLR_ID.h:22
This is an Identifier helper class for the Pixel subdetector.
Definition PixelID.h:67
bool is_dbm(const Identifier &id) const
Test for dbm - WARNING: id MUST be pixel id, otherwise answer is not accurate. Use SiliconID for gene...
Definition PixelID.h:593
int eta_index(const Identifier &id) const
Definition PixelID.h:645
int layer_disk(const Identifier &id) const
Definition PixelID.h:607
Identifier pixel_id(int barrel_ec, int layer_disk, int phi_module, int eta_module, int phi_index, int eta_index) const
For an individual pixel.
Definition PixelID.h:428
IdentifierHash wafer_hash(Identifier wafer_id) const
wafer hash from id
Definition PixelID.h:383
int phi_index(const Identifier &id) const
Definition PixelID.h:639
bool is_barrel(const Identifier &id) const
Test for barrel - WARNING: id MUST be pixel id, otherwise answer is not accurate. Use SiliconID for g...
Definition PixelID.h:586
This is an Identifier helper class for the SCT subdetector.
Definition SCT_ID.h:68
int side(const Identifier &id) const
Definition SCT_ID.h:705
IdentifierHash wafer_hash(const Identifier &wafer_id) const
wafer hash from id - optimized
Definition SCT_ID.h:487
int row(const Identifier &id) const
Definition SCT_ID.h:711
int strip(const Identifier &id) const
Definition SCT_ID.h:717
Identifier strip_id(int barrel_ec, int layer_disk, int phi_module, int eta_module, int side, int strip) const
For an individual strip.
Definition SCT_ID.h:530
bool is_barrel(const Identifier &id) const
Test for barrel - WARNING: id MUST be sct id, otherwise answer is not accurate. Use SiliconID for gen...
Definition SCT_ID.h:674
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Message Stream Member.
@ distEta
readout for silicon
Definition ParamDefs.h:51
@ distPhi
Definition ParamDefs.h:50