ATLAS Offline Software
Loading...
Searching...
No Matches
SCTSiLorentzAngleCondAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
9
10// Local include
12
13// Athena includes
17
18// Gaudi include
19#include "GaudiKernel/PhysicalConstants.h"
20
21// STL include
22
23SCTSiLorentzAngleCondAlg::SCTSiLorentzAngleCondAlg(const std::string& name, ISvcLocator* pSvcLocator):
24 ::AthCondAlgorithm(name, pSvcLocator),
25 m_maxHash{0}
26{
27}
28
30{
31 if (m_siConditionsTool.empty()) m_sctDefaults.setValue(true);
32
33 if (not m_sctDefaults.value()) {
34 // SCTSiliconConditionsTool
35 ATH_CHECK(m_siConditionsTool.retrieve());
36 } else {
37 m_siConditionsTool.disable();
38 }
39 // Read Cond handle
40 ATH_CHECK(m_readKeyTemp.initialize((not m_sctDefaults.value()) and (not m_useGeoModel.value())));
41 ATH_CHECK(m_readKeyHV.initialize((not m_sctDefaults.value()) and (not m_useGeoModel.value())));
42
44
45 ATH_CHECK(m_SCTDetEleCollKey.initialize());
46
47 // Write Cond Handle
48 ATH_CHECK(m_writeKey.initialize());
49
50 // Get maximum hash for vector sizes. We need the idhelper for this.
51 const SCT_ID* idHelper{nullptr};
52 ATH_CHECK(detStore()->retrieve(idHelper, "SCT_ID"));
53 m_maxHash = idHelper->wafer_hash_max();
54
55 return StatusCode::SUCCESS;
56}
57
58StatusCode SCTSiLorentzAngleCondAlg::execute(const EventContext& ctx) const
59{
60 // Write Cond Handle
62 // Do we have a valid Write Cond Handle for current time?
63 if (writeHandle.isValid()) {
64 ATH_MSG_DEBUG("CondHandle " << writeHandle.fullKey() << " is already valid."
65 << " In theory this should not be called, but may happen"
66 << " if multiple concurrent events are being processed out of order.");
67 return StatusCode::SUCCESS;
68 }
69
70 // Get SCT_DetectorElementCollection
72 const InDetDD::SiDetectorElementCollection* elements(sctDetEle.retrieve());
73 if (elements==nullptr) {
74 ATH_MSG_FATAL(m_SCTDetEleCollKey.fullKey() << " could not be retrieved");
75 return StatusCode::FAILURE;
76 }
77 writeHandle.addDependency(sctDetEle); // Run-LB IOV
78
79 if ((not m_sctDefaults.value()) and (not m_useGeoModel.value())) {
80 // Read Cond Handle (temperature)
82 const SCT_DCSFloatCondData* readCdoTemp{*readHandleTemp};
83 if (readCdoTemp==nullptr) {
84 ATH_MSG_FATAL("Null pointer to the read conditions object");
85 return StatusCode::FAILURE;
86 }
87 writeHandle.addDependency(readHandleTemp);
88 ATH_MSG_INFO("Input is " << readHandleTemp.fullKey() << " with the range of " << readHandleTemp.getRange());
89
90 // Read Cond Handle (HV)
92 const SCT_DCSFloatCondData* readCdoHV{*readHandleHV};
93 if (readCdoHV==nullptr) {
94 ATH_MSG_FATAL("Null pointer to the read conditions object");
95 return StatusCode::FAILURE;
96 }
97 writeHandle.addDependency(readHandleHV);
98 ATH_MSG_INFO("Input is " << readHandleHV.fullKey() << " with the range of " << readHandleHV.getRange());
99 }
100
101 MagField::AtlasFieldCache fieldCache;
102 if (m_useMagFieldCache.value()) {
103 // Get field cache object
105 const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
106
107 if (fieldCondObj==nullptr) {
108 ATH_MSG_FATAL("Failed to retrieve AtlasFieldCacheCondObj with key " << m_fieldCondObjInputKey.key());
109 return StatusCode::FAILURE;
110 }
111 writeHandle.addDependency(readHandle);
112 fieldCondObj->getInitializedCache(fieldCache);
113 }
114
115 // Construct the output Cond Object and fill it in
116 std::unique_ptr<SiLorentzAngleCondData> writeCdo{std::make_unique<SiLorentzAngleCondData>()};
117 writeCdo->resize(m_maxHash);
118 // SiLorentzAngleCondData myData;
119
120 for (unsigned int hash{0}; hash<m_maxHash; hash++) {
121 const IdentifierHash elementHash{hash};
122
123 double temperatureC{0.0};
124 double deplVoltage{0.0};
125 double biasVoltage{0.0};
126
127 if (m_sctDefaults.value()) {
128 temperatureC = m_temperature.value();
129 deplVoltage = m_deplVoltage.value() * CLHEP::volt;
130 biasVoltage = m_biasVoltage.value() * CLHEP::volt;
131 } else {
132 temperatureC = m_siConditionsTool->temperature(elementHash, ctx);
133 deplVoltage = m_siConditionsTool->depletionVoltage(elementHash, ctx) * CLHEP::volt;
134 biasVoltage = m_siConditionsTool->biasVoltage(elementHash, ctx) * CLHEP::volt;
135 ATH_MSG_DEBUG("SCT Hash = " << elementHash << " Temperature = " << temperatureC << " [deg C], BiasV = " << biasVoltage << " DeplV = " << deplVoltage);
136 }
137
138 // Protect against invalid temperature
139 if (not ((temperatureC>m_temperatureMin) and (temperatureC<m_temperatureMax))) {
140 temperatureC = m_temperature.value();
141 ATH_MSG_DEBUG("Invalid temperature: " << temperatureC << " C. " << "Setting to " << m_temperature.value() << " C. " << "Detector element hash: " << elementHash);
142 }
143 double temperature{temperatureC + Gaudi::Units::STP_Temperature}; // C -> K
144
145 // Calculate depletion depth. If biasVoltage is less than depletionVoltage
146 // the detector is not fully depleted and we need to take this into account.
147 // We take absolute values just in case voltages are signed.
148 const InDetDD::SiDetectorElement* element{elements->getDetectorElement(elementHash)};
149 double depletionDepth{element->thickness()};
150 if (deplVoltage==0.0) {
151 ATH_MSG_WARNING("Depletion voltage in "<<__FILE__<<" is zero, which might be a bug.");
152 }
153 if (std::abs(biasVoltage) < std::abs(deplVoltage)) {
154 depletionDepth *= std::sqrt(std::abs(biasVoltage / deplVoltage));
155 }
156
157 double meanElectricField{0.};
158 if (depletionDepth>0.) {
159 meanElectricField = biasVoltage / depletionDepth;
160 }
161 InDet::SiliconProperties siProperties;
162 siProperties.setConditions(temperature, meanElectricField);
163 double mobility{siProperties.signedHallMobility(element->carrierType())};
164
165 // Get magnetic field. This first checks that field cache is valid.
166 Amg::Vector3D magneticField{getMagneticField(fieldCache, element)};
167
168 // The angles are in the hit frame. This is because that is what is needed by the digization and also
169 // gives a more physical sign of the angle (ie dosen't flip sign when the detector is flipped).
170 // The hit depth axis is pointing from the readout side to the backside if m_design->readoutSide() < 0
171 // The hit depth axis is pointing from the backside to the readout side if m_design->readoutSide() > 0
172 double tanLorentzAnglePhi{element->design().readoutSide() * mobility * element->hitDepthDirection()
173 * element->hitPhiDirection() * (element->normal().cross(magneticField)).dot(element->phiAxis())};
174 writeCdo->setTanLorentzAngle(elementHash, tanLorentzAnglePhi);
175
176 // This gives the effective correction in the reconstruction frame hence the extra hitPhiDirection()
177 // as the angle above is in the hit frame.
178 double lorentzCorrectionPhi{-0.5 * element->hitPhiDirection() * tanLorentzAnglePhi * depletionDepth};
179 writeCdo->setLorentzShift(elementHash, lorentzCorrectionPhi);
180
181 // The Lorentz eta shift very small and so can be ignored, but we include it for completeness.
182 // In the SCT its largest in the stereo side of the barrel modules where it is about 0.3 micron along the strip.
183 double tanLorentzAngleEta{element->design().readoutSide() * mobility * element->hitDepthDirection()
184 * element->hitEtaDirection() * (element->normal().cross(magneticField)).dot(element->etaAxis())};
185 writeCdo->setTanLorentzAngleEta(elementHash, tanLorentzAngleEta);
186 double lorentzCorrectionEta{-0.5 * element->hitPhiDirection() * tanLorentzAngleEta * depletionDepth};
187 writeCdo->setLorentzShiftEta(elementHash, lorentzCorrectionEta);
188
189 // Monitoring value
190 writeCdo->setBiasVoltage(elementHash, biasVoltage/CLHEP::volt);
191 writeCdo->setTemperature(elementHash, temperatureC);
192 writeCdo->setDepletionVoltage(elementHash, deplVoltage/CLHEP::volt);
193
194 ATH_MSG_DEBUG("Hash = " << elementHash << " tanPhi = " << lorentzCorrectionPhi << " shiftPhi = " << writeCdo->getLorentzShift(elementHash) << "Depletion depth = " << depletionDepth);
195 ATH_MSG_VERBOSE("Temperature (C), bias voltage, depletion voltage: " << temperatureC << ", " << biasVoltage/CLHEP::volt << ", " << deplVoltage/CLHEP::volt);
196 ATH_MSG_VERBOSE("Depletion depth: " << depletionDepth/CLHEP::mm);
197 ATH_MSG_VERBOSE("Mobility (cm2/V/s): " << mobility/(CLHEP::cm2/CLHEP::volt/CLHEP::s));
198 ATH_MSG_VERBOSE("Magnetic Field (tesla): " << "(" << magneticField.x()/CLHEP::tesla << "," << magneticField.y()/CLHEP::tesla << "," << magneticField.z()/CLHEP::tesla << ")");
199 ATH_MSG_VERBOSE("LorentzShift, tanLorentzAngle = " << writeCdo->getLorentzShift(elementHash) << ", " << writeCdo->getTanLorentzAngle(elementHash));
200 ATH_MSG_VERBOSE("LorentzShiftEta, tanLorentzAngleEta = " << writeCdo->getLorentzShiftEta(elementHash) << ", " << writeCdo->getTanLorentzAngleEta(elementHash));
201 }
202
203 // Record the output cond object
204 if (writeHandle.record(std::move(writeCdo)).isFailure()) {
205 ATH_MSG_FATAL("Could not record SiLorentzAngleCondData " << writeHandle.key()
206 << " with EventRange " << writeHandle.getRange() << " into Conditions Store");
207 return StatusCode::FAILURE;
208 }
209 ATH_MSG_INFO("recorded new CDO " << writeHandle.key() << " with range " << writeHandle.getRange() << " into Conditions Store");
210
211 return StatusCode::SUCCESS;
212}
213
215{
216 return StatusCode::SUCCESS;
217}
218
220
221 if (m_useMagFieldCache.value()) {
222 Amg::Vector3D pointvec{element->center()};
223
224 ATH_MSG_VERBOSE("Getting magnetic field from MT magnetic field service.");
225
226 double point[3];
227 point[0] = pointvec[0];
228 point[1] = pointvec[1];
229 point[2] = pointvec[2];
230 double field[3];
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}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
This is an Identifier helper class for the SCT subdetector.
const ServiceHandle< StoreGateSvc > & detStore() const
Base class for conditions algorithms.
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.
virtual const Amg::Vector3D & center() const override final
Center in global coordinates.
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,...
Amg::Vector3D getMagneticField(MagField::AtlasFieldCache &fieldCache, const InDetDD::SiDetectorElement *element) const
SG::ReadCondHandleKey< InDetDD::SiDetectorElementCollection > m_SCTDetEleCollKey
virtual StatusCode finalize() override final
SG::WriteCondHandleKey< SiLorentzAngleCondData > m_writeKey
SG::ReadCondHandleKey< SCT_DCSFloatCondData > m_readKeyHV
virtual StatusCode execute(const EventContext &ctx) const override final
SCTSiLorentzAngleCondAlg(const std::string &name, ISvcLocator *pSvcLocator)
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCondObjInputKey
ToolHandle< ISiliconConditionsTool > m_siConditionsTool
SG::ReadCondHandleKey< SCT_DCSFloatCondData > m_readKeyTemp
virtual StatusCode initialize() override final
Class for data object used in SCT_DCSConditions{HV,Temp}CondAlg, SCT_DCSConditionsTool,...
This is an Identifier helper class for the SCT subdetector.
Definition SCT_ID.h:68
size_type wafer_hash_max() const
Definition SCT_ID.cxx:621
const_pointer_type retrieve()
const DataObjID & fullKey() const
const EventIDRange & getRange()
const std::string & key() const
void addDependency(const EventIDRange &range)
const EventIDRange & getRange() const
StatusCode record(const EventIDRange &range, T *t)
record handle, with explicit range DEPRECATED
const DataObjID & fullKey() const
Eigen::Matrix< double, 3, 1 > Vector3D