ATLAS Offline Software
Loading...
Searching...
No Matches
SCT_ChargeTrappingTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
10
13
17
18#include "GaudiKernel/PhysicalConstants.h"
19#include "GaudiKernel/SystemOfUnits.h"
20
21#include "CLHEP/Random/RandFlat.h"
22
23#include <stdexcept>
24#include <algorithm>
25#include <cmath>
26
27SCT_ChargeTrappingTool::SCT_ChargeTrappingTool(const std::string& type, const std::string& name, const IInterface* parent) :
28 base_class(type, name, parent)
29{
30}
31
32StatusCode
34{
35 if (m_detectorName!="SCT") {
36 ATH_MSG_FATAL("Invalid detector name: " << m_detectorName << ". Must be SCT.");
37 return StatusCode::FAILURE;
38 }
39
40 m_isSCT = (m_detectorName=="SCT");
41
42 // Get conditions summary tool
44 if (not m_siConditionsTool.empty()) {
45 ATH_CHECK(m_siConditionsTool.retrieve());
47 } else {
48 m_siConditionsTool.disable();
50 }
51
52 // Read CondHandle Key
53 ATH_CHECK(m_SCTDetEleCollKey.initialize());
54
55 // initialize PotentialValue
56 for (int ix{0}; ix<81; ix++) {
57 for (int iy{0}; iy<115; iy++) {
58 m_PotentialValue[ix][iy] = getPotentialValue(ix, iy);
59 }
60 }
61
62 return StatusCode::SUCCESS;
63}
64
66{
67 return StatusCode::SUCCESS;
68}
69
70SCT_ChargeTrappingCondData SCT_ChargeTrappingTool::getCondData(const IdentifierHash& elementHash, double pos, const EventContext& ctx) const
71{
72 return calculate(elementHash, pos, ctx);
73}
74
75void SCT_ChargeTrappingTool::getHoleTransport(double& x0, double& y0, double& xfin, double& yfin, double& Q_m2, double& Q_m1, double& Q_00, double& Q_p1, double& Q_p2, const EventContext& /*ctx*/) const
76{
77 holeTransport(x0, y0, xfin, yfin, Q_m2, Q_m1, Q_00, Q_p1, Q_p2);
78}
79
80SCT_ChargeTrappingCondData SCT_ChargeTrappingTool::calculate(const IdentifierHash& elementHash, double pos, const EventContext& ctx) const
81{
82 ATH_MSG_VERBOSE("Updating cache for elementHash = " << elementHash);
83
85 // Only print the warning once.
87 ATH_MSG_WARNING("Conditions Summary Tool is not used. Will use temperature and voltages from job options. "
88 << "Effects of radiation damage may be wrong!");
89 }
90
92
93 const InDetDD::SiDetectorElement* element{getDetectorElement(elementHash, ctx)};
94
95 double temperature{0.};
96 double deplVoltage{0.};
97 double biasVoltage{0.};
98 if (not m_conditionsToolValid) {
99 temperature = m_temperature + Gaudi::Units::STP_Temperature;
100 deplVoltage = m_deplVoltage * Gaudi::Units::volt;
101 biasVoltage = m_biasVoltage * Gaudi::Units::volt;
102 } else {
103 temperature = m_siConditionsTool->temperature(elementHash, ctx) + Gaudi::Units::STP_Temperature;
104 deplVoltage = m_siConditionsTool->depletionVoltage(elementHash, ctx) * Gaudi::Units::volt;
105 biasVoltage = m_siConditionsTool->biasVoltage(elementHash, ctx) * Gaudi::Units::volt;
106 }
107
108 // Protect against invalid temperature
109 double temperatureC{temperature - Gaudi::Units::STP_Temperature};
110 if (not (temperatureC > m_temperatureMin and temperatureC < m_temperatureMax)) {
111 ATH_MSG_WARNING("Invalid temperature: " << temperatureC << " C. "
112 << "Setting to " << m_temperature << " C.");
113 temperature = m_temperature + Gaudi::Units::STP_Temperature;
114 }
115
116 // Calculate depletion depth. If biasVoltage is less than depletionVoltage
117 // the detector is not fully depleted and we need to take this into account.
118 // We take absolute values just in case voltages are signed .
119 double depletionDepth{element->thickness()};
120 if (std::abs(biasVoltage) < std::abs(deplVoltage)) {
121 depletionDepth *= std::sqrt(std::abs(biasVoltage / deplVoltage));
122 // -- if this was the case would need to re-calculate the Ramo Potential and other parameters.
123 }
124
125 double electricField{m_electricFieldTool->getElectricField(pos,//posZ
126 m_fluence,
127 deplVoltage,
128 element->thickness(),
129 std::abs(biasVoltage))};
130 //electric field will be a function of bias voltage and fluence...
131
132 condData.setElectricField(electricField);
133
134 InDet::SiliconProperties siProperties;
135 siProperties.setConditions(temperature, electricField);
136
137 // -- Calculate electron and holes drift mobility and velocity for these conditions (temperature, electricField)
138 // using parametrizations in SiliconProperties (SiPropertiesTool). These will be used later for the trapping model.
139 // In the SCT we collect holes.
140 double electronDriftMobility{0.};
141 double holeDriftMobility{0.};
142 double electronDriftVelocity{0.};
143 double holeDriftVelocity{0.};
144 if(element->carrierType()==InDetDD::electrons) {
145 // electronDriftMobility = siProperties.calcElectronDriftMobility(temperature,electricField);
146 // electronDriftVelocity = electronDriftMobility*electricField;
147 } else {
148 if (m_calcHoles){
149 holeDriftMobility = siProperties.calcHoleDriftMobility(temperature,electricField*Gaudi::Units::volt)*Gaudi::Units::volt;
150 //in this way you could put the electric field in V/mm and the mobility will be in [V mm^2 ns^-1]
151 condData.setHoleDriftMobility(holeDriftMobility);
152 holeDriftVelocity = holeDriftMobility*electricField;
153 }
154 }
155
156 // -- Calculate Trapping Times
157 const double trappingElectrons{1./(m_fluence*m_betaElectrons)};
158 condData.setTrappingElectrons(trappingElectrons);
159
160 double trappingHoles{0.};
161 if (m_calcHoles) {
162 trappingHoles = 1./(m_fluence*m_betaHoles);
163 condData.setTrappingHoles(trappingHoles);
164 }
165
166 // -- Calculate Mean Free Path
167 const double meanFreePathElectrons{electronDriftVelocity*trappingElectrons};
168 if (meanFreePathElectrons == 0.)[[unlikely]]{
169 throw std::runtime_error("SCT_ChargeTrappingTool::calculate: meanFreePathElectrons is zero.");
170 }
171 condData.setMeanFreePathElectrons(meanFreePathElectrons);
172
173 double meanFreePathHoles{0.};
174 if (m_calcHoles) {
175 meanFreePathHoles = holeDriftVelocity*trappingHoles;
176 condData.setMeanFreePathHoles(meanFreePathHoles);
177 if (meanFreePathHoles == 0.)[[unlikely]]{
178 throw std::runtime_error("SCT_ChargeTrappingTool::calculate: meanFreePathHoles is zero.");
179 }
180 }
181
182 // -- Trapping probability
183 double trappingProbability_electron{0.0};
184 double trappingProbability_hole{0.0};
185 double trappingProbability{0.0};
186 if (element->carrierType()==InDetDD::electrons) {
187 trappingProbability = 1.0 - std::exp(-std::abs(pos/meanFreePathElectrons));
188 trappingProbability_electron = trappingProbability;
189 } else {
190 if (m_calcHoles) {
191 trappingProbability = 1.0 - std::exp(-std::abs(pos/meanFreePathHoles));
192 trappingProbability_hole = trappingProbability;
193 } else {
194 trappingProbability = 0.0;
195 }
196 }
197 condData.setTrappingProbability(trappingProbability);
198
199 // -- Drift time without being trapped
200 const double u{CLHEP::RandFlat::shoot(0., 1.)};
201 const double drift_time{-std::log(u)*trappingHoles};
202 condData.setTrappingTime(drift_time);
203
204 if (holeDriftVelocity == 0.)[[unlikely]]{
205 throw std::runtime_error("SCT_ChargeTrappingTool::calculate: holeDriftVelocity is zero.");
206 }
207 // -- Time to arrive to the electrode
208 const double t_electrode_hole{pos/holeDriftVelocity};
209 condData.setTimeToElectrode(t_electrode_hole);
210
211 // -- Position at which the trapping happened
212 const double trappingPosition_hole{holeDriftVelocity*drift_time};
213 condData.setTrappingPositionZ(trappingPosition_hole);
214
215 //-------------------
216
217 ATH_MSG_VERBOSE("Temperature (C), bias voltage, depletion voltage: "
218 << temperature - Gaudi::Units::STP_Temperature << ", "
219 << biasVoltage/Gaudi::Units::volt << ", "
220 << deplVoltage/Gaudi::Units::volt);
221 ATH_MSG_VERBOSE("Depletion depth: " << depletionDepth/Gaudi::Units::mm);
222 ATH_MSG_VERBOSE("Electric Field: " << electricField/(Gaudi::Units::volt/Gaudi::Units::mm));
223 ATH_MSG_VERBOSE("Electron drift mobility (cm2/V/s): " << electronDriftMobility/(Gaudi::Units::cm2/Gaudi::Units::volt/Gaudi::Units::s));
224 ATH_MSG_VERBOSE("Electron drift velocity (cm/s): " << electronDriftVelocity);
225 ATH_MSG_VERBOSE("Electron mean free path (cm): " << condData.getMeanFreePathElectrons());
226 ATH_MSG_VERBOSE("Electron trapping probability: " << trappingProbability_electron);
227
228 if (m_calcHoles) {
229 ATH_MSG_VERBOSE("Hole drift mobility (cm2/V/s): " << holeDriftMobility/(Gaudi::Units::cm2/Gaudi::Units::volt/Gaudi::Units::s));
230 ATH_MSG_VERBOSE("Hole drift velocity (cm/s): " << holeDriftVelocity);
231 ATH_MSG_VERBOSE("Hole mean free path (cm): " << condData.getMeanFreePathHoles());
232 ATH_MSG_VERBOSE("Hole trapping probability: " << trappingProbability_hole);
233 }
234
235 return condData;
236}
237
238
239
240//-------------------------------------------------------------------------------------------------------------------
241// RAMO POTENTIAL
242//-------------------------------------------------------------------------------------------------------------------
243
244//-------------------------------------------------------------------
245// calculation of induced charge using Weighting (Ramo) function
246//-------------------------------------------------------------------
247double SCT_ChargeTrappingTool::induced(int istrip, double x, double y) const {
248 // x and y are the coorlocation of charge (e or hole)
249 // induced chardege on the strip "istrip" situated at the height y = d
250 // the center of the strip (istrip=0) is x = 0.004 [cm]
251 static const double deltax{0.0005};
252 static const double deltay{0.00025};
253
254 static const double bulk_depth{0.0285}; // in [cm]
255 static const double strip_pitch{0.0080}; // in [cm]
256 // x is width, y is depth
257
258 if ((y < 0.) or (y > bulk_depth)) return 0.;
259 const double xc{strip_pitch * (istrip + 0.5)};
260 const double dx{std::abs(x-xc)};
261 const int ix{static_cast<int>(dx/deltax)};
262 if (ix > 79) return 0.;
263 const int iy{static_cast<int>(y/deltay)};
264 const double fx{(dx - ix*deltax) / deltax};
265 const double fy{(y - iy*deltay) / deltay};
266 const int ix1{ix + 1};
267 const int iy1{iy + 1};
268 const double P{m_PotentialValue[ix ][iy ] * (1.-fx) * (1.-fy)
269 + m_PotentialValue[ix1][iy ] * fx * (1.-fy)
270 + m_PotentialValue[ix ][iy1] * (1.-fx) * fy
271 + m_PotentialValue[ix1][iy1] * fx * fy};
272 ATH_MSG_DEBUG("induced: x,y,iy="<<x<<" "<<y<<" "<<iy<<" istrip,xc,dx,ix="
273 <<istrip<<" "<<xc<<" " <<dx<<" "<<ix<<" fx,fy="<<fx <<" " <<fy<< ", P="<<P);
274
275 return P;
276}
277
278
279//---------------------------------------------------------------------
280// holeTransport
281//---------------------------------------------------------------------
282void SCT_ChargeTrappingTool::holeTransport(double& x0, double& y0, double& xfin, double& yfin, double& Q_m2, double& Q_m1, double& Q_00, double& Q_p1, double& Q_p2) const {
283 // transport holes in the bulk
284 // T. Kondo, 2010.9.9
285 // External parameters to be specified
286 // m_transportTimeMax [nsec]
287 // m_transportTimeStep [nsec]
288 // bulk_depth [cm]
289 // Induced currents are added to
290 // Q_m2,Q_m1,Q_00,Q_p1,Q_p2
291 //
292 // initPotentialValue(); // <-this has to go into the main
293
294 // x is width, y is depth
295
296 double x{x0/10.}; // original hole position [cm]
297 double y{y0/10.}; // original hole position [cm]
298 double qstrip[5];
299
300 for (int istrip{-2}; istrip < 3 ; istrip++) {
301 qstrip[istrip+2] = induced(istrip, x, y);
302 }
303 ATH_MSG_DEBUG("h:qstrip=" << qstrip[0] << " " << qstrip[1] << " " << qstrip[2] << " " << qstrip[3] << " " << qstrip[4]);
304
305 // Get induced current by subtracting induced charges
306 for (int istrip{-2}; istrip < 3 ; istrip++) {
307 x = xfin/10.;
308 y = yfin/10.;
309 const double qnew{induced(istrip, x, y)};
310 int jj{istrip + 2};
311 const double dq{qnew - qstrip[jj]};
312 qstrip[jj] = qnew;
313 ATH_MSG_DEBUG("dq= " << dq);
314 switch(istrip) {
315 case -2: Q_m2 += dq ; break;
316 case -1: Q_m1 += dq ; break;
317 case 0: Q_00 += dq ; break;
318 case +1: Q_p1 += dq ; break;
319 case +2: Q_p2 += dq ; break;
320 // default: break; // Coverity complains the default is deadcode.
321 }
322 }
323 ATH_MSG_DEBUG("h:qstrip=" << qstrip[0] << " " << qstrip[1] << " " << qstrip[2] << " " << qstrip[3] << " " << qstrip[4]);
324}
325
326double
328 return ::getPotentialValue(ix, iy);
329}
330
331const InDetDD::SiDetectorElement* SCT_ChargeTrappingTool::getDetectorElement(const IdentifierHash& waferHash, const EventContext& ctx) const {
333 if (not condData.isValid()) return nullptr;
334 return condData->getDetectorElement(waferHash);
335}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static Double_t P(Double_t *tt, Double_t *par)
#define y
#define x
This is a "hash" representation of an Identifier.
Class to hold geometrical description of a silicon detector element.
InDetDD::CarrierType carrierType() const
carrier type for readout.
void setConditions(double temperature, double electricField)
double calcHoleDriftMobility(double temperature, double electricField) const
Data object for SCT_ChargeTrappingTool, SCT_RadDamageSummaryTool, SCT_SurfaceChargesGenerator.
void setTrappingTime(const double trappingTime)
void setHoleDriftMobility(const double holeDriftMobility)
void setTrappingHoles(const double trappingHoles)
void setTrappingProbability(const double trappingProbability)
void setTimeToElectrode(const double electrodeTime)
void setTrappingPositionZ(const double trappingPosition)
void setMeanFreePathHoles(const double meanFreePathHoles)
void setTrappingElectrons(const double trappingElectrons)
void setMeanFreePathElectrons(const double meanFreePathElectrons)
void setElectricField(const double electricField)
ToolHandle< ISiliconConditionsTool > m_siConditionsTool
virtual StatusCode initialize() override
SCT_ChargeTrappingCondData calculate(const IdentifierHash &elementHash, double pos, const EventContext &ctx) const
void holeTransport(double &x0, double &y0, double &xfin, double &yfin, double &Q_m2, double &Q_m1, double &Q_00, double &Q_p1, double &Q_p2) const
ToolHandle< ISCT_ElectricFieldTool > m_electricFieldTool
virtual void getHoleTransport(double &x0, double &y0, double &xfin, double &yfin, double &Q_m2, double &Q_m1, double &Q_00, double &Q_p1, double &Q_p2, const EventContext &ctx) const override
SG::ReadCondHandleKey< InDetDD::SiDetectorElementCollection > m_SCTDetEleCollKey
std::atomic_bool m_conditionsToolWarning
virtual SCT_ChargeTrappingCondData getCondData(const IdentifierHash &elementHash, double pos, const EventContext &ctx) const override
double induced(int istrip, double x, double y) const
static double getPotentialValue(int &ix, int &iy)
SCT_ChargeTrappingTool(const std::string &type, const std::string &name, const IInterface *parent)
virtual StatusCode finalize() override
const InDetDD::SiDetectorElement * getDetectorElement(const IdentifierHash &waferHash, const EventContext &ctx) const
#define unlikely(x)