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