ATLAS Offline Software
Loading...
Searching...
No Matches
SiLorentzAngleTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <algorithm>
8#include <limits>
9
10#include "GaudiKernel/SystemOfUnits.h"
11
17
18SiLorentzAngleTool::SiLorentzAngleTool(const std::string& type, const std::string& name, const IInterface* parent):
19 base_class(type, name, parent),
20 m_condData{"SCTSiLorentzAngleCondData"}
21{
22 declareProperty("IgnoreLocalPos", m_ignoreLocalPos = false,
23 "Treat methods that take a local position as if one called the methods without a local position");
24 // YOU NEED TO USE THE SAME PROPERTIES AS USED IN Pixel/SCTSiLorentzAngleCondAlg!!!
25 declareProperty("DetectorName", m_detectorName="Pixel", "Detector name (Pixel, SCT or PLR)");
26 declareProperty("NominalField", m_nominalField = 2.0834*Gaudi::Units::tesla);
27 declareProperty("UseMagFieldCache", m_useMagFieldCache = true);
28 declareProperty("SiLorentzAngleCondData", m_condData, "Key of input SiLorentzAngleCondData");
29}
30
32
33 ATH_MSG_DEBUG("SiLorentzAngleTool Initialized");
34
35 if ((m_detectorName not_eq "Pixel") and (m_detectorName not_eq "SCT") and (m_detectorName not_eq "PLR")) {
36 ATH_MSG_FATAL("Invalid detector name: " << m_detectorName << ". Must be Pixel, SCT or PLR.");
37 return StatusCode::FAILURE;
38 }
39
40 // Read Cond Handle
41 ATH_CHECK(m_condData.initialize());
42 ATH_CHECK(m_detEleCollKey.initialize());
43
44 // MagneticFieldCache
45 if (not m_useMagFieldCache) {
46 ATH_MSG_DEBUG("Not using Magnetic Field cache - Will be using Nominal Field!");
47 }
49
50 return StatusCode::SUCCESS;
51}
52
54 return StatusCode::SUCCESS;
55}
56
57double SiLorentzAngleTool::getLorentzShift(const IdentifierHash& elementHash, const EventContext& ctx) const {
58 const SiLorentzAngleCondData* condData{getCondData(ctx)};
59 if (condData) {
60 return condData->getLorentzShift(elementHash);
61 }
62 return s_invalidValue;
63}
64
65double SiLorentzAngleTool::getLorentzShift(const IdentifierHash& elementHash, const Amg::Vector2D& locPos) const {
66 if (m_ignoreLocalPos) return getLorentzShift(elementHash, Gaudi::Hive::currentContext());
67 // The cache is used to store the results. The cache is therefore invalidated if we specify a position.
68 return getValue(elementHash, locPos, LorentzShift);
69}
70
72 const SiLorentzAngleCondData* condData{getCondData(Gaudi::Hive::currentContext())};
73 if (condData) {
74 return condData->getLorentzShiftEta(elementHash);
75 }
76 return s_invalidValue;
77}
78
79double SiLorentzAngleTool::getLorentzShiftEta(const IdentifierHash& elementHash, const Amg::Vector2D& locPos) const {
80 if (m_ignoreLocalPos) return getLorentzShiftEta(elementHash);
81 // The cache is used to store the results. The cache is therefore invalidated if we specify a position.
82 return getValue(elementHash, locPos, LorentzShiftEta);
83}
84
85double SiLorentzAngleTool::getTanLorentzAngle(const IdentifierHash& elementHash, const EventContext& ctx) const {
86 const SiLorentzAngleCondData* condData{getCondData(ctx)};
87 if (condData) {
88 return condData->getTanLorentzAngle(elementHash);
89 }
90 return s_invalidValue;
91}
92
93double SiLorentzAngleTool::getTanLorentzAngle(const IdentifierHash& elementHash, const Amg::Vector2D& locPos) const {
94 if (m_ignoreLocalPos) return getTanLorentzAngle(elementHash, Gaudi::Hive::currentContext());
95 // The cache is used to store the results. The cache is therefore invalidated if we specify a position.
96 return getValue(elementHash, locPos, TanLorentzAngle);
97}
98
100 const SiLorentzAngleCondData* condData{getCondData(Gaudi::Hive::currentContext())};
101 if (condData) {
102 return condData->getTanLorentzAngleEta(elementHash);
103 }
104 return s_invalidValue;
105}
106
107double SiLorentzAngleTool::getTanLorentzAngleEta(const IdentifierHash& elementHash, const Amg::Vector2D& locPos) const {
108 if (m_ignoreLocalPos) return getTanLorentzAngleEta(elementHash);
109 // The cache is used to store the results. The cache is therefore invalidated if we specify a position.
110 return getValue(elementHash, locPos, TanLorentzAngleEta);
111}
112
113double SiLorentzAngleTool::getBiasVoltage(const IdentifierHash& elementHash) const {
114 const SiLorentzAngleCondData* condData{getCondData(Gaudi::Hive::currentContext())};
115 if (condData) {
116 return condData->getBiasVoltage(elementHash);
117 }
118 return s_invalidValue;
119}
120
121double SiLorentzAngleTool::getTemperature(const IdentifierHash& elementHash) const {
122 const SiLorentzAngleCondData* condData{getCondData(Gaudi::Hive::currentContext())};
123 if (condData) {
124 return condData->getTemperature(elementHash);
125 }
126 return s_invalidValue;
127}
128
130 const SiLorentzAngleCondData* condData{getCondData(Gaudi::Hive::currentContext())};
131 if (condData) {
132 return condData->getDepletionVoltage(elementHash);
133 }
134 return s_invalidValue;
135}
136
137double SiLorentzAngleTool::getValue(const IdentifierHash& elementHash, const Amg::Vector2D& locPos, Variable variable) const {
138 if (not (variable==TanLorentzAngle or variable==LorentzShift or variable==TanLorentzAngleEta or variable==LorentzShiftEta)) {
139 ATH_MSG_WARNING("getValue with Variable=" << variable << " is not available");
140 return s_invalidValue;
141 }
142
143 double temperature{getTemperature(elementHash)};
144 double deplVoltage{getDepletionVoltage(elementHash)};
145 double biasVoltage{getBiasVoltage(elementHash)};
146
147 // Calculate depletion depth. If biasVoltage is less than depletionVoltage
148 // the detector is not fully depleted and we need to take this into account.
149 // We take absolute values just in case voltages are signed.
150 const InDetDD::SiDetectorElement* element{getDetectorElement(elementHash)};
151 double depletionDepth{element->thickness()};
152 if (deplVoltage==0.0) ATH_MSG_WARNING("Depletion voltage in "<<__FILE__<<" is zero, which might be a bug.");
153 if (std::abs(biasVoltage) < std::abs(deplVoltage)) {
154 depletionDepth *= std::sqrt(std::abs(biasVoltage / deplVoltage));
155 }
156 double meanElectricField{0.};
157 if (depletionDepth) {
158 meanElectricField = biasVoltage / depletionDepth;
159 }
160 double mobility{0.};
161 InDet::SiliconProperties siProperties;
162 siProperties.setConditions(temperature, meanElectricField);
163 mobility = siProperties.signedHallMobility(element->carrierType());
164 // Get magnetic field.
165 Amg::Vector3D pointvec{element->globalPosition(locPos)};
166 Amg::Vector3D magneticField{getMagneticField(pointvec)};
167
168 double correctionFactor{getCorrectionFactor()};
169
170 // The angles are in the hit frame. This is because that is what is needed by the digization and also
171 // gives a more physical sign of the angle (ie dosen't flip sign when the detector is flipped).
172 // The hit depth axis is pointing from the readout side to the backside if m_design->readoutSide() < 0
173 // The hit depth axis is pointing from the backside to the readout side if m_design->readoutSide() > 0
174 if (variable==TanLorentzAngle or variable==LorentzShift) {
175 double tanLorentzAnglePhi{element->design().readoutSide()*mobility*element->hitDepthDirection()*element->hitPhiDirection()*(element->normal().cross(magneticField)).dot(element->phiAxis())};
176 if (variable==TanLorentzAngle) {
177 return correctionFactor*tanLorentzAnglePhi;
178 }
179 // This gives the effective correction in the reconstruction frame hence the extra hitPhiDirection()
180 // as the angle above is in the hit frame.
181 double lorentzCorrectionPhi{-0.5*element->hitPhiDirection()*tanLorentzAnglePhi*depletionDepth};
182 return correctionFactor*lorentzCorrectionPhi;
183 }
184
185 // The Lorentz eta shift very small and so can be ignored, but we include it for completeness.
186 // It is < ~0.1 um in the pixel.
187 // In the SCT its largest in the stereo side of the barrel modules where it is about 0.3 micron along the strip.
188 if (variable==TanLorentzAngleEta or variable==LorentzShiftEta) {
189 double tanLorentzAngleEta{element->design().readoutSide()*mobility*element->hitDepthDirection()*element->hitEtaDirection()*(element->normal().cross(magneticField)).dot(element->etaAxis())};
190 if (variable==TanLorentzAngleEta) {
191 return correctionFactor*tanLorentzAngleEta;
192 }
193 double lorentzCorrectionEta{-0.5*element->hitPhiDirection()*tanLorentzAngleEta*depletionDepth};
194 return correctionFactor*lorentzCorrectionEta;
195 }
196
197 ATH_MSG_WARNING("You should not see this message. Something is wrong in getValue");
198 return s_invalidValue;
199}
200
202{
203 const SiLorentzAngleCondData* condData{getCondData(Gaudi::Hive::currentContext())};
204 if (condData) {
205 return condData->getCorrectionFactor();
206 }
207 return s_invalidValue;
208}
209
211 // Get the magnetic field.
212 bool useMagFieldCache{m_useMagFieldCache};
213 MagField::AtlasFieldCache fieldCache;
214 if (useMagFieldCache) {
215 SG::ReadCondHandle<AtlasFieldCacheCondObj> readHandle{m_fieldCondObjInputKey, Gaudi::Hive::currentContext()};
216 const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
217 if (fieldCondObj == nullptr) {
218 ATH_MSG_ERROR("SCTSiLorentzAngleCondAlg : Failed to retrieve AtlasFieldCacheCondObj with key " << m_fieldCondObjInputKey.key());
219 useMagFieldCache = false;
220 } else {
221 fieldCondObj->getInitializedCache(fieldCache);
222 }
223 }
224 if (useMagFieldCache) {
225 ATH_MSG_VERBOSE("Getting magnetic field from magnetic field service.");
226 double field[3];
227 double point[3];
228 point[0] = pointvec[0];
229 point[1] = pointvec[1];
230 point[2] = pointvec[2];
231 fieldCache.getField(point, field);
232 return Amg::Vector3D(field[0], field[1], field[2]);
233 } else {
234 ATH_MSG_VERBOSE("Using Nominal Field");
235 return Amg::Vector3D(0., 0., m_nominalField);
236 }
237}
238
239const SiLorentzAngleCondData* SiLorentzAngleTool::getCondData(const EventContext& ctx) const {
241 if (handle.isValid()) {
242 const SiLorentzAngleCondData* data{*handle};
243 return data;
244 }
245 ATH_MSG_WARNING(m_condData.key() << " cannot be retrieved.");
246 return nullptr;
247}
248
251 const InDetDD::SiDetectorElementCollection* elements{nullptr};
252 if (handle.isValid()) elements = *handle;
253 if (elements!=nullptr) return elements->getDetectorElement(waferHash);
254
255 ATH_MSG_WARNING(m_detEleCollKey.key() << " cannot be retrieved.");
256 return nullptr;
257}
258
259const double SiLorentzAngleTool::s_invalidValue{std::numeric_limits<double>::quiet_NaN()};
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
void getInitializedCache(MagField::AtlasFieldCache &cache) const
get B field cache for evaluation as a function of 2-d or 3-d position.
This is a "hash" representation of an Identifier.
int readoutSide() const
ReadoutSide.
Class to hold the SiDetectorElement objects to be put in the detector store.
const SiDetectorElement * getDetectorElement(const IdentifierHash &hash) const
Class to hold geometrical description of a silicon detector element.
virtual const SiDetectorDesign & design() const override final
access to the local description (inline):
InDetDD::CarrierType carrierType() const
carrier type for readout.
double hitPhiDirection() const
See previous method.
virtual const Amg::Vector3D & normal() const override final
Get reconstruction local normal axes in global frame.
HepGeom::Point3D< double > globalPosition(const HepGeom::Point3D< double > &localPos) const
transform a reconstruction local position into a global position (inline):
double hitDepthDirection() const
Directions of hit depth,phi,eta axes relative to reconstruction local position axes (LocalPosition).
double hitEtaDirection() const
See previous method.
void setConditions(double temperature, double electricField)
double signedHallMobility(InDetDD::CarrierType carrier) const
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
void getField(const double *ATH_RESTRICT xyz, double *ATH_RESTRICT bxyz, double *ATH_RESTRICT deriv=nullptr)
get B field value at given position xyz[3] is in mm, bxyz[3] is in kT if deriv[9] is given,...
Concrete class for Lorentz angle conditions data for each detector element.
double getLorentzShift(const IdentifierHash &elementHash) const
Get the Lorentz shift correction in the local x (phiDist) direction Assumes the center of the detecto...
double getTemperature(const IdentifierHash &elementHash) const
Get temperature.
double getTanLorentzAngleEta(const IdentifierHash &elementHash) const
Get tan af the Lorentz angle in the local y (etaDist) direction Assumes the center of the detector an...
double getDepletionVoltage(const IdentifierHash &elementHash) const
Get depletion voltage.
double getBiasVoltage(const IdentifierHash &elementHash) const
Get bias voltage.
double getCorrectionFactor() const
Get correction factor.
double getTanLorentzAngle(const IdentifierHash &elementHash) const
Get tan af the Lorentz angle in the local x (phiDist) direction Assumes the center of the detector an...
double getLorentzShiftEta(const IdentifierHash &elementHash) const
Get the Lorentz shift correction in the local y (etaDist) direction Assumes the center of the detecto...
const SiLorentzAngleCondData * getCondData(const EventContext &ctx) const
virtual double getDepletionVoltage(const IdentifierHash &elementHash) const override
Get depletion voltage.
virtual double getBiasVoltage(const IdentifierHash &elementHash) const override
Get bias voltage.
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCondObjInputKey
SG::ReadCondHandleKey< SiLorentzAngleCondData > m_condData
static const double s_invalidValue
Amg::Vector3D getMagneticField(const Amg::Vector3D &pointvec) const
virtual StatusCode initialize() override
Service init.
virtual double getTemperature(const IdentifierHash &elementHash) const override
Get temperature.
virtual double getLorentzShift(const IdentifierHash &elementHash, const EventContext &ctx) const override
Get the Lorentz shift correction in the local x (phiDist) direction Assumes the center of the detecto...
double getValue(const IdentifierHash &elementHash, const Amg::Vector2D &locPos, Variable variable) const
virtual double getTanLorentzAngleEta(const IdentifierHash &elementHash) const override
Get tan af the Lorentz angle in the local y (etaDist) direction Assumes the center of the detector an...
virtual double getLorentzShiftEta(const IdentifierHash &elementHash) const override
Get the Lorentz shift correction in the local y (etaDist) direction Assumes the center of the detecto...
const InDetDD::SiDetectorElement * getDetectorElement(const IdentifierHash &waferHash) const
SG::ReadCondHandleKey< InDetDD::SiDetectorElementCollection > m_detEleCollKey
SiLorentzAngleTool(const std::string &type, const std::string &name, const IInterface *parent)
double getCorrectionFactor() const
virtual double getTanLorentzAngle(const IdentifierHash &elementHash, const EventContext &ctx) const override
Get tan af the Lorentz angle in the local x (phiDist) direction Assumes the center of the detector an...
virtual StatusCode finalize() override
Service finalize.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D