ATLAS Offline Software
Loading...
Searching...
No Matches
SCT_SurfaceChargesGenerator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7// DD
10
11// Athena
14#include "InDetSimEvent/SiHit.h" // for SiHit, SiHit::::xDep, etc
15#include "HitManagement/TimedHitPtr.h" // for TimedHitPtr
16
17// ROOT
18#include "TH1.h" // for TH1F
19#include "TH2.h" // for TH2F
20#include "TProfile.h" // for TProfile
21
22// CLHEP
23#include "CLHEP/Geometry/Point3D.h"
24#include "CLHEP/Random/RandomEngine.h"
25#include "CLHEP/Random/RandGaussZiggurat.h"
26
27// C++ Standard Library
28#include <cmath>
29
33
34// constructor
36 const std::string& name,
37 const IInterface* parent)
38 : base_class(type, name, parent) {
39}
40
41// ----------------------------------------------------------------------
42// Initialize
43// ----------------------------------------------------------------------
45 ATH_MSG_DEBUG("SCT_SurfaceChargesGenerator::initialize()");
46
47 // Get ISiPropertiesTool
48 ATH_CHECK(m_siPropertiesTool.retrieve());
49
50 // Get ISiliconConditionsSvc
51 ATH_CHECK(m_siConditionsTool.retrieve());
52
54
55 if (m_doTrapping) {
56 // -- Get Radiation Damage Tool
57 ATH_CHECK(m_radDamageTool.retrieve());
58 } else {
59 m_radDamageTool.disable();
60 }
61
62 if (m_doHistoTrap) {
63 // -- Get Histogram Service
64 ATH_CHECK(m_thistSvc.retrieve());
65
66 m_h_efieldz = new TProfile("efieldz", "", 50, 0., 0.4);
67 ATH_CHECK(m_thistSvc->regHist("/file1/efieldz", m_h_efieldz));
68
69 m_h_efield = new TH1F("efield", "", 100, 200., 800.);
70 ATH_CHECK(m_thistSvc->regHist("/file1/efield", m_h_efield));
71
72 m_h_spess = new TH1F("spess", "", 50, 0., 0.4);
73 ATH_CHECK(m_thistSvc->regHist("/file1/spess", m_h_spess));
74
75 m_h_depD = new TH1F("depD", "", 50, -0.3, 0.3);
76 ATH_CHECK(m_thistSvc->regHist("/file1/depD", m_h_depD));
77
78 m_h_drift_electrode = new TH2F("drift_electrode", "", 50, 0., 20., 50, 0., 20.);
79 ATH_CHECK(m_thistSvc->regHist("/file1/drift_electrode", m_h_drift_electrode));
80
81 m_h_drift_time = new TH1F("drift_time", "", 100, 0., 20.);
82 ATH_CHECK(m_thistSvc->regHist("/file1/drift_time", m_h_drift_time));
83
84 m_h_t_electrode = new TH1F("t_electrode", "", 100, 0., 20.);
85 ATH_CHECK(m_thistSvc->regHist("/file1/t_electrode", m_h_t_electrode));
86
87 m_h_ztrap = new TH1F("ztrap", "", 100, 0., 0.3);
88 ATH_CHECK(m_thistSvc->regHist("/file1/ztrap", m_h_ztrap));
89
90 // More histograms to check what's going on
91 m_h_zhit = new TH1F("zhit", "", 50, -0.2, 0.2);
92 ATH_CHECK(m_thistSvc->regHist("/file1/zhit", m_h_zhit));
93
94 m_h_ztrap_tot = new TH1F("ztrap_tot", "", 100, 0., 0.5);
95 ATH_CHECK(m_thistSvc->regHist("/file1/ztrap_tot", m_h_ztrap_tot));
96
97 m_h_no_ztrap = new TH1F("no_ztrap", "", 100, 0., 0.5);
98 ATH_CHECK(m_thistSvc->regHist("/file1/no_ztrap", m_h_no_ztrap));
99
100 m_h_trap_drift_t = new TH1F("trap_drift_t", "", 100, 0., 20.);
101 ATH_CHECK(m_thistSvc->regHist("/file1/trap_drift_t", m_h_trap_drift_t));
102
103 m_h_notrap_drift_t = new TH1F("notrap_drift_t", "", 100, 0., 20.);
104 ATH_CHECK(m_thistSvc->regHist("/file1/notrap_drift_t", m_h_notrap_drift_t));
105
106 m_h_mob_Char = new TProfile("mob_Char", "", 200, 100., 1000.);
107 ATH_CHECK(m_thistSvc->regHist("/file1/mob_Char", m_h_mob_Char));
108
109 m_h_vel = new TProfile("vel", "", 100, 100., 1000.);
110 ATH_CHECK(m_thistSvc->regHist("/file1/vel", m_h_vel));
111
112 m_h_drift1 = new TProfile("drift1", "", 50, 0., 0.3);
113 ATH_CHECK(m_thistSvc->regHist("/file1/drift1", m_h_drift1));
114
115 m_h_gen = new TProfile("gen", "", 50, 0., 0.3);
116 ATH_CHECK(m_thistSvc->regHist("/file1/gen", m_h_gen));
117
118 m_h_gen1 = new TProfile("gen1", "", 50, 0., 0.3);
119 ATH_CHECK(m_thistSvc->regHist("/file1/gen1", m_h_gen1));
120
121 m_h_gen2 = new TProfile("gen2", "", 50, 0., 0.3);
122 ATH_CHECK(m_thistSvc->regHist("/file1/gen2", m_h_gen2));
123
124 m_h_velocity_trap = new TProfile("velocity_trap", "", 50, 0., 1000.);
125 ATH_CHECK(m_thistSvc->regHist("/file1/velocity_trap", m_h_velocity_trap));
126
127 m_h_mobility_trap = new TProfile("mobility_trap", "", 50, 100., 1000.);
128 ATH_CHECK(m_thistSvc->regHist("/file1/mobility_trap", m_h_mobility_trap));
129
130 m_h_trap_pos = new TH1F("trap_pos", "", 100, 0., 0.3);
131 ATH_CHECK(m_thistSvc->regHist("/file1/trap_pos", m_h_trap_pos));
132 }
134
135 // Induced Charge Module.
137 const SCT_ID* sct_id{nullptr};
138 ATH_CHECK(detStore()->retrieve(sct_id, "SCT_ID"));
139 m_InducedChargeModel = std::make_unique<InducedChargeModel>(sct_id->wafer_hash_max());
140 }
141
142 // Surface drift time calculation Stuff
145 if ((m_tSurfaceDrift > m_tHalfwayDrift) and (m_tHalfwayDrift >= 0.0) and
147 m_SurfaceDriftFlag = true;
148 } else {
149 ATH_MSG_INFO("\tsurface drift still not on, wrong params");
150 }
151
152 // Make sure these two flags are not set simultaneously
153 if (m_tfix>-998. and m_tsubtract>-998.) {
154 ATH_MSG_FATAL("\tCannot set both FixedTime and SubtractTime options!");
155 ATH_MSG_INFO("\tMake sure the two flags are not set simultaneously in jo");
156 return StatusCode::FAILURE;
157 }
158
159 ATH_CHECK(m_lorentzAngleTool.retrieve());
160
161 return StatusCode::SUCCESS;
162}
163
164// ----------------------------------------------------------------------
165// finalize
166// ----------------------------------------------------------------------
168 ATH_MSG_DEBUG("SCT_SurfaceChargesGenerator::finalize()");
169 return StatusCode::SUCCESS;
170}
171
172// ----------------------------------------------------------------------
173// perpandicular Drift time calculation
174// ----------------------------------------------------------------------
175float SCT_SurfaceChargesGenerator::driftTime(float zhit, const SiDetectorElement* element, const EventContext& ctx) const {
176 if (element==nullptr) {
177 ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::process element is nullptr");
178 return -2.0;
179 }
180 const SCT_ModuleSideDesign* design{dynamic_cast<const SCT_ModuleSideDesign*>(&(element->design()))};
181 if (design==nullptr) {
182 ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::process can not get " << design);
183 return -2.0;
184 }
185 const double thickness{design->thickness()};
186 const IdentifierHash hashId{element->identifyHash()};
187
188 if ((zhit < 0.0) or (zhit > thickness)) {
189 ATH_MSG_DEBUG("driftTime: hit coordinate zhit=" << zhit / CLHEP::micrometer << " out of range");
190 return -2.0;
191 }
192
193 float depletionVoltage{0.};
194 float biasVoltage{0.};
195 if (m_useSiCondDB) {
196 depletionVoltage = m_siConditionsTool->depletionVoltage(hashId, ctx) * CLHEP::volt;
197 biasVoltage = m_siConditionsTool->biasVoltage(hashId, ctx) * CLHEP::volt;
198 } else {
199 depletionVoltage = m_vdepl * CLHEP::volt;
200 biasVoltage = m_vbias * CLHEP::volt;
201 }
202
203 const float denominator{static_cast<float>(depletionVoltage + biasVoltage - (2.0 * zhit * depletionVoltage / thickness))};
204 if (denominator <= 0.0) {
205 if (biasVoltage >= depletionVoltage) { // Should not happen
206 if(not m_isOverlay) {
207 ATH_MSG_ERROR("driftTime: negative argument X for log(X) " << zhit);
208 }
209 return -1.0;
210 } else {
211 // (m_biasVoltage<m_depletionVoltage) can happen with underdepleted sensors, lose charges in that volume
212 return -10.0;
213 }
214 }
215
216 float t_drift{std::log((depletionVoltage + biasVoltage) / denominator)};
217 t_drift *= thickness * thickness / (2.0 * m_siPropertiesTool->getSiProperties(hashId, ctx).holeDriftMobility() * depletionVoltage);
218 return t_drift;
219}
220
221// ----------------------------------------------------------------------
222// Sigma diffusion calculation
223// ----------------------------------------------------------------------
224float SCT_SurfaceChargesGenerator::diffusionSigma(float zhit, const SiDetectorElement* element, const EventContext& ctx) const {
225 if (element==nullptr) {
226 ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::diffusionSigma element is nullptr");
227 return 0.0;
228 }
229 const IdentifierHash hashId{element->identifyHash()};
230 const float t{driftTime(zhit, element, ctx)}; // in ns
231
232 if (t > 0.0) {
233 const float sigma{static_cast<float>(std::sqrt(2. * m_siPropertiesTool->getSiProperties(hashId, ctx).holeDiffusionConstant() * t))}; // in mm
234 return sigma;
235 } else {
236 return 0.0;
237 }
238}
239
240// ----------------------------------------------------------------------
241// Maximum drift time
242// ----------------------------------------------------------------------
243float SCT_SurfaceChargesGenerator::maxDriftTime(const SiDetectorElement* element, const EventContext& ctx) const {
244 if (element) {
245 const float sensorThickness{static_cast<float>(element->thickness())};
246 return driftTime(sensorThickness, element, ctx);
247 } else {
248 ATH_MSG_INFO("Error: SiDetectorElement not set!");
249 return 0.;
250 }
251}
252
253// ----------------------------------------------------------------------
254// Maximum Sigma difusion
255// ----------------------------------------------------------------------
256float SCT_SurfaceChargesGenerator::maxDiffusionSigma(const SiDetectorElement* element, const EventContext& ctx) const {
257 if (element) {
258 const float sensorThickness{static_cast<float>(element->thickness())};
259 return diffusionSigma(sensorThickness, element, ctx);
260 } else {
261 ATH_MSG_INFO("Error: SiDetectorElement not set!");
262 return 0.;
263 }
264}
265
266// ----------------------------------------------------------------------
267// Calculating the surface drift time but I should confess that
268// I haven't found out yet where the calculation come from
269// ----------------------------------------------------------------------
271 if (m_SurfaceDriftFlag) {
272 if ((ysurf >= 0.0) and (ysurf <= m_distInterStrip)) {
273 float t_surfaceDrift{0.};
274 if (ysurf < m_distHalfInterStrip) {
275 const float y{ysurf / m_distHalfInterStrip};
276 t_surfaceDrift= m_tHalfwayDrift * y * y;
277 } else {
278 const float y{(m_distInterStrip - ysurf) / (m_distInterStrip - m_distHalfInterStrip)};
279 t_surfaceDrift = m_tSurfaceDrift + (m_tHalfwayDrift - m_tSurfaceDrift) * y * y;
280 }
281 return t_surfaceDrift;
282 } else {
283 ATH_MSG_INFO(" ysurf out of range " << ysurf);
284 return -1.0;
285 }
286 } else {
287 return 0.0;
288 }
289}
290
291// -------------------------------------------------------------------------------------------
292// create a list of surface charges from a hit - called from SCT_Digitization
293// AthAlgorithm
294// -------------------------------------------------------------------------------------------
296 const TimedHitPtr<SiHit>& phit,
298 CLHEP::HepRandomEngine * rndmEngine,
299 const EventContext& ctx) {
300 ATH_MSG_VERBOSE("SCT_SurfaceChargesGenerator::process starts");
301 processSiHit(element, *phit, inserter, phit.eventTime(), phit.eventId(), rndmEngine, ctx);
302}
303
304// -------------------------------------------------------------------------------------------
305// create a list of surface charges from a hit - called from both AthAlgorithm
306// and PileUpTool
307// -------------------------------------------------------------------------------------------
309 const SiHit& phit,
311 float p_eventTime,
312 unsigned short p_eventId,
313 CLHEP::HepRandomEngine* rndmEngine,
314 const EventContext& ctx) {
315 const SCT_ModuleSideDesign* design{dynamic_cast<const SCT_ModuleSideDesign*>(&(element->design()))};
316 if (design==nullptr) {
317 ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::process can not get " << design);
318 return;
319 }
320
321 const double thickness{design->thickness()};
322 const IdentifierHash hashId{element->identifyHash()};
323 const double tanLorentz{m_lorentzAngleTool->getTanLorentzAngle(hashId, ctx)};
324
325 // ---**************************************
326 // Time of Flight Calculation - separate method?
327 // ---**************************************
328 // --- Original calculation of Time of Flight of the particle Time needed by the particle to reach the sensor
329 float timeOfFlight{p_eventTime + hitTime(phit)};
330
331 // Kondo 19/09/2007: Use the coordinate of the center of the module to calculate the time of flight
332 timeOfFlight -= (element->center().mag()) / CLHEP::c_light;
333 // !< extract the distance to the origin of the module to Time of flight
334
335 // !< timing set from jo to adjust (subtract) the timing
336 if (m_tsubtract > -998.) {
337 timeOfFlight -= m_tsubtract;
338 }
339 // ---**************************************
340
341 const CLHEP::Hep3Vector pos{phit.localStartPosition()};
342 const float xEta{static_cast<float>(pos[SiHit::xEta])};
343 const float xPhi{static_cast<float>(pos[SiHit::xPhi])};
344 const float xDep{static_cast<float>(pos[SiHit::xDep])};
345
346 const CLHEP::Hep3Vector endPos{phit.localEndPosition()};
347 const float cEta{static_cast<float>(endPos[SiHit::xEta]) - xEta};
348 const float cPhi{static_cast<float>(endPos[SiHit::xPhi]) - xPhi};
349 const float cDep{static_cast<float>(endPos[SiHit::xDep]) - xDep};
350
351 const float LargeStep{std::sqrt(cEta*cEta + cPhi*cPhi + cDep*cDep)};
352 const int numberOfSteps{static_cast<int>(LargeStep / m_smallStepLength) + 1};
353 const float steps{static_cast<float>(m_numberOfCharges * numberOfSteps)};
354 const float e1{static_cast<float>(phit.energyLoss() / steps)};
355 const float q1{static_cast<float>(e1 * m_siPropertiesTool->getSiProperties(hashId, ctx).electronHolePairsPerEnergy())};
356
357 // in the following, to test the code, we will use the original coordinate
358 // system of the SCTtest3SurfaceChargesGenerator x is eta y is phi z is depth
359 float xhit{xEta};
360 float yhit{xPhi};
361 float zhit{xDep};
362
364 if (m_doInducedChargeModel) { // Setting magnetic field for the ICM.
366 const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
367 if (!fieldCondObj)[[unlikely]]{
368 ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::process has fieldCondObj=nullptr");
369 return;
370 }
371 float vdepl{m_vdepl};
372 float vbias{m_vbias};
373 if (m_useSiCondDB) {
374 vdepl = m_siConditionsTool->depletionVoltage(hashId, ctx);
375 vbias = m_siConditionsTool->biasVoltage(hashId, ctx);
376 }
377 data = m_InducedChargeModel->setWaferData(vdepl,
378 vbias,
379 element,
380 fieldCondObj,
382 rndmEngine,
383 ctx);
384 }
385
386 const float StepX{cEta / numberOfSteps};
387 const float StepY{cPhi / numberOfSteps};
388 const float StepZ{cDep / numberOfSteps};
389
390 // check the status of truth information for this SiHit
391 // some Truth information is cut for pile up events
392 const HepMcParticleLink trklink = HepMcParticleLink::getRedirectedLink(phit.particleLink(), p_eventId, ctx); // This link should now correctly resolve to the TruthEvent McEventCollection in the main StoreGateSvc.
394 if (phit.truthID() != 0 || phit.truthBarcode() != 0) { // if the hit was not caused by a delta-ray then one of these must be true
395 if (not trklink.isValid()) {
396 // TODO consider extending this check to reject links to
397 // GenEvents other than the first one in the McEventCollection,
398 // so that the digitization output doesn't change if pile-up
399 // truth is saved.
400 hitproc = SiCharge::cut_track;
401 }
402 }
403
404 float dstep{-0.5};
405 for (int istep{0}; istep < numberOfSteps; ++istep) {
406 dstep += 1.0;
407 float z1{zhit + StepZ * dstep};
408
409 // Distance between charge and readout side.
410 // design->readoutSide() is +1 if readout side is in +ve depth axis direction and visa-versa.
411 float zReadout{static_cast<float>(0.5 * thickness - design->readoutSide() * z1)};
412 const double spess{zReadout};
413
414 if (m_doHistoTrap) {
415 m_h_depD->Fill(z1);
416 m_h_spess->Fill(spess);
417 }
418
419 float t_drift{driftTime(zReadout, element, ctx)}; // !< t_drift: perpandicular drift time
420 if (t_drift>-2.0000002 and t_drift<-1.9999998) {
421 ATH_MSG_DEBUG("Checking for rounding errors in compression");
422 if ((std::abs(z1) - 0.5 * thickness) < 0.000010) {
423 ATH_MSG_DEBUG("Rounding error found attempting to correct it. z1 = " << std::fixed << std::setprecision(8) << z1);
424 if (z1 < 0.0) {
425 z1 = 0.0000005 - 0.5 * thickness;
426 // set new coordinate to be 0.5nm inside wafer volume.
427 } else {
428 z1 = 0.5 * thickness - 0.0000005;
429 // set new coordinate to be 0.5nm inside wafer volume.
430 }
431 zReadout = 0.5 * thickness - design->readoutSide() * z1;
432 t_drift = driftTime(zReadout, element, ctx);
433 if (t_drift>-2.0000002 and t_drift<-1.9999998) {
434 ATH_MSG_WARNING("Attempt failed. Making no correction.");
435 } else {
436 ATH_MSG_DEBUG("Correction Successful! z1 = " << std::fixed << std::setprecision(8) << z1 << ", zReadout = " << zReadout << ", t_drift = " << t_drift);
437 }
438 } else {
439 ATH_MSG_DEBUG("No rounding error found. Making no correction.");
440 }
441 }
442 if (t_drift > 0.0) {
443 const float x1{xhit + StepX * dstep};
444 float y1{yhit + StepY * dstep};
445
446 float sigma{0.};
447 if (not m_doInducedChargeModel) {
448 sigma = diffusionSigma(zReadout, element, ctx);
449 y1 += tanLorentz * zReadout; // !< Taking into account the magnetic field
450 } // These are treated in Induced Charge Model.
451
452 for (int i{0}; i < m_numberOfCharges; ++i) {
453 const float rx{CLHEP::RandGaussZiggurat::shoot(rndmEngine)};
454 const float xd{x1 + sigma * rx};
455 const float ry{CLHEP::RandGaussZiggurat::shoot(rndmEngine)};
456 const float yd{y1 + sigma * ry};
457
458 // For charge trapping with Ramo potential
459 const double stripPitch{0.080}; // mm
460 double dstrip{y1 / stripPitch}; // mm
461 if (dstrip > 0.) {
462 dstrip = dstrip - std::trunc(dstrip);
463 } else {
464 dstrip = dstrip - std::trunc(dstrip) + 1;
465 }
466
467 // now y will be x and z will be y ....just to make sure to confuse everebody
468 double y0{dstrip * stripPitch}; // mm
469 double z0{thickness - zReadout}; // mm
470
471 // -- Charge Trapping
472 if (m_doTrapping) {
473 if (m_doHistoTrap) {
474 m_h_zhit->Fill(zhit);
475 }
476 double trap_pos{-999999.}, drift_time{-999999.}; // FIXME need better default values
477 if (chargeIsTrapped(spess, element, trap_pos, drift_time, ctx)) {
478 if (not m_doRamo) {
479 break;
480 } else { // if we want to take into account also Ramo Potential
481 double Q_all[5]={0.0,0.0,0.0,0.0,0.0};
482
483 dstrip = y1 / stripPitch; // mm
484 // need the distance from the nearest strips
485 // edge not centre, xtaka = 1/2*stripPitch
486 // centre of detector, y1=0, is in the middle of
487 // an interstrip gap
488 if (dstrip > 0.) {
489 dstrip -= static_cast<double>(static_cast<int>(dstrip));
490 } else {
491 dstrip -= static_cast<double>(static_cast<int>(dstrip)) + 1;
492 }
493
494 // now y will be x and z will be y ....just to make sure to confuse everebody
495 double yfin{dstrip * stripPitch}; // mm
496 double zfin{thickness - trap_pos}; // mm
497
498 m_radDamageTool->holeTransport(y0, z0, yfin, zfin, Q_all[0], Q_all[1], Q_all[2], Q_all[3], Q_all[4], ctx);
499 for (int strip{-2}; strip<=2; strip++) {
500 const double ystrip{yd + strip * stripPitch}; // mm
501 const SiLocalPosition position(element->hitLocalToLocal(xd, ystrip));
502 if (design->inActiveArea(position)) {
503 const double charge = Q_all[strip+2];
504 const double time{drift_time};
505 if (charge != 0.) {
506 inserter(SiSurfaceCharge(position, SiCharge(q1*charge, time, hitproc, trklink)));
507 continue;
508 }
509 }
510 }
511 ATH_MSG_INFO("strip zero charge = " << Q_all[2]); // debug
512 } // m_doRamo==true
513 } // chargeIsTrapped()
514 } // m_doTrapping==true
515
516 if (not m_doRamo) {
517 if (m_doInducedChargeModel) { // Induced Charge Model
518 // Charges storages for 50 ns. 0.5 ns steps.
524
525 const double mm2cm = 0.1; // For mm -> cm conversion
526 // Unit for y and z : mm -> cm in InducedChargeModel
527 m_InducedChargeModel->holeTransport(*data,
528 y0*mm2cm, z0*mm2cm,
529 Q_m2, Q_m1, Q_00, Q_p1, Q_p2,
530 hashId, m_siPropertiesTool,
531 ctx);
532 m_InducedChargeModel->electronTransport(*data,
533 y0*mm2cm, z0*mm2cm,
534 Q_m2, Q_m1, Q_00, Q_p1, Q_p2,
535 hashId, m_siPropertiesTool,
536 ctx);
537
538 for (int it{0}; it<InducedChargeModel::NTransportSteps; it++) {
539 if (Q_00[it] == 0.0) continue;
540 double ICM_time{(it+0.5)*0.5 + timeOfFlight};
541 double Q_new[InducedChargeModel::NStrips]{
542 Q_m2[it], Q_m1[it], Q_00[it], Q_p1[it], Q_p2[it]
543 };
545 double ystrip{y1 + strip * stripPitch};
546 SiLocalPosition position{element->hitLocalToLocal(x1, ystrip)};
547 if (design->inActiveArea(position)) {
548 inserter(SiSurfaceCharge(position,
550 ICM_time, hitproc, trklink)));
551 }
552 }
553 }
554 } else { // not m_doInducedChargeModel
555 const SiLocalPosition position{element->hitLocalToLocal(xd, yd)};
556 if (design->inActiveArea(position)) {
557 const float sdist{static_cast<float>(design->scaledDistanceToNearestDiode(position))};
558 // !< dist on the surface from the hit point to the nearest strip (diode)
559 const float t_surf{surfaceDriftTime(2.0 * sdist)}; // !< Surface drift time
560 const float totaltime{(m_tfix > -998.) ? m_tfix.value() : t_drift + timeOfFlight + t_surf}; // !< Total drift time
561 inserter(SiSurfaceCharge(position, SiCharge(q1, totaltime, hitproc, trklink)));
562 } else {
563 ATH_MSG_VERBOSE(std::fixed << std::setprecision(8) << "Local position (phi, eta, depth): ("
564 << position.xPhi() << ", " << position.xEta() << ", " << position.xDepth()
565 << ") of the element is out of active area, charge = " << q1);
566 }
567 }
568 }
569 } // end of loop on charges
570 }
571 }
572 }
573
575 const SiDetectorElement* element,
576 double& trap_pos,
577 double& drift_time,
578 const EventContext& ctx) {
579 if (element==nullptr) {
580 ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::chargeIsTrapped element is nullptr");
581 return false;
582 }
583 bool isTrapped{false};
584 const IdentifierHash hashId{element->identifyHash()};
585 const SCT_ChargeTrappingCondData condData{m_radDamageTool->getCondData(hashId, spess, ctx)};
586 const double electric_field{condData.getElectricField()};
587
588 if (m_doHistoTrap) {
589 const double mobChar{condData.getHoleDriftMobility()};
590 m_h_efieldz->Fill(spess, electric_field);
591 m_h_efield->Fill(electric_field);
592 m_h_mob_Char->Fill(electric_field, mobChar);
593 m_h_vel->Fill(electric_field, electric_field * mobChar);
594 }
595 const double t_electrode{condData.getTimeToElectrode()};
596 drift_time = condData.getTrappingTime();
597 const double z_trap{condData.getTrappingPositionZ()};
598 trap_pos = spess - z_trap;
599 if (m_doHistoTrap) {
600 m_h_drift_time->Fill(drift_time);
601 m_h_t_electrode->Fill(t_electrode);
602 m_h_drift_electrode->Fill(drift_time, t_electrode);
603 m_h_ztrap_tot->Fill(z_trap);
604 }
605 // -- Calculate if the charge is trapped, and at which distance
606 // -- Charge gets trapped before arriving to the electrode
607 if (drift_time < t_electrode) {
608 isTrapped = true;
609 ATH_MSG_INFO("drift_time: " << drift_time << " t_electrode: " << t_electrode << " spess " << spess);
610 ATH_MSG_INFO("z_trap: " << z_trap);
611 if (m_doHistoTrap) {
612 m_h_ztrap->Fill(z_trap);
613 m_h_trap_drift_t->Fill(drift_time);
614 m_h_drift1->Fill(spess, drift_time / t_electrode);
615 m_h_gen->Fill(spess, drift_time);
616 m_h_gen1->Fill(spess, z_trap);
617 m_h_gen2->Fill(spess, z_trap / drift_time * t_electrode);
618 m_h_velocity_trap->Fill(electric_field, z_trap / drift_time);
619 m_h_mobility_trap->Fill(electric_field, z_trap / drift_time / electric_field);
620 m_h_trap_pos->Fill(trap_pos);
621 }
622 } else {
623 isTrapped = false;
624 if (m_doHistoTrap) {
625 const double z_trap{condData.getTrappingPositionZ()};
626 m_h_no_ztrap->Fill(z_trap);
627 m_h_notrap_drift_t->Fill(drift_time);
628 }
629 }
630 return isTrapped;
631}
float hitTime(const AFP_SIDSimHit &hit)
Scalar mag() const
mag method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#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)
double charge(const T &p)
Definition AtlasPID.h:997
This is an Identifier helper class for the SCT subdetector.
#define y
This is a "hash" representation of an Identifier.
double thickness() const
Method which returns thickness of the silicon wafer.
int readoutSide() const
ReadoutSide.
Base class for the SCT module side design, extended by the Forward and Barrel module design.
virtual double scaledDistanceToNearestDiode(const SiLocalPosition &chargePos) const =0
give distance to the nearest diode in units of pitch, from 0.0 to 0.5, this method should be fast as ...
virtual bool inActiveArea(const SiLocalPosition &chargePos, bool checkBondGap=true) const =0
check if the position is in active area
Class to hold geometrical description of a silicon detector element.
virtual const SiDetectorDesign & design() const override final
access to the local description (inline):
Class to represent a position in the natural frame of a silicon sensor, for Pixel and SCT For Pixel: ...
virtual IdentifierHash identifyHash() const override final
identifier hash (inline)
virtual const Amg::Vector3D & center() const override final
Center in global coordinates.
Amg::Vector2D hitLocalToLocal(double xEta, double xPhi) const
Simulation/Hit local frame to reconstruction local frame.
Data object for SCT_ChargeTrappingTool, SCT_RadDamageSummaryTool, SCT_SurfaceChargesGenerator.
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
float diffusionSigma(float zhit, const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
calculate diffusion sigma from a gaussian dist scattered charge
ToolHandle< ISCT_RadDamageSummaryTool > m_radDamageTool
float maxDiffusionSigma(const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
max sigma diffusion
SCT_SurfaceChargesGenerator(const std::string &type, const std::string &name, const IInterface *parent)
constructor
std::unique_ptr< InducedChargeModel > m_InducedChargeModel
virtual void process(const InDetDD::SiDetectorElement *element, const TimedHitPtr< SiHit > &phit, ISiSurfaceChargesInserter &inserter, CLHEP::HepRandomEngine *rndmEngine, const EventContext &ctx) override
create a list of surface charges from a hit
bool chargeIsTrapped(double spess, const InDetDD::SiDetectorElement *element, double &trap_pos, double &drift_time, const EventContext &ctx)
bool m_SurfaceDriftFlag
surface drift ON/OFF
float m_distHalfInterStrip
Half way distance inter strip.
float maxDriftTime(const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
max drift charge equivalent to the detector thickness
ToolHandle< ISiliconConditionsTool > m_siConditionsTool
void processSiHit(const InDetDD::SiDetectorElement *element, const SiHit &phit, ISiSurfaceChargesInserter &inserter, float eventTime, unsigned short eventID, CLHEP::HepRandomEngine *rndmEngine, const EventContext &ctx)
ToolHandle< ISiLorentzAngleTool > m_lorentzAngleTool
ServiceHandle< ITHistSvc > m_thistSvc
virtual StatusCode initialize() override
AlgTool initialize.
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCacheCondObjInputKey
virtual StatusCode finalize() override
AlgTool finalize.
FloatProperty m_tSurfaceDrift
related to the surface drift
float m_distInterStrip
Inter strip distance normalized to 1.
float surfaceDriftTime(float ysurf) const
Calculate of the surface drift time.
ToolHandle< ISiPropertiesTool > m_siPropertiesTool
float driftTime(float zhit, const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
calculate drift time perpandicular to the surface for a charge at distance zhit from mid gap
@ cut_track
Definition SiCharge.h:28
Definition SiHit.h:19
double energyLoss() const
Definition SiHit.h:175
int truthID() const
Definition SiHit.cxx:208
HepGeom::Point3D< double > localStartPosition() const
Definition SiHit.cxx:146
@ xPhi
Definition SiHit.h:162
@ xEta
Definition SiHit.h:162
@ xDep
Definition SiHit.h:162
int truthBarcode() const
Definition SiHit.cxx:202
const HepMcParticleLink & particleLink() const
Definition SiHit.h:190
HepGeom::Point3D< double > localEndPosition() const
Definition SiHit.cxx:153
a smart pointer to a hit that also provides access to the extended timing info of the host event.
Definition TimedHitPtr.h:18
unsigned short eventId() const
the index of the component event in PileUpEventInfo.
Definition TimedHitPtr.h:47
float eventTime() const
t0 offset of the bunch xing containing the hit in ns.
Definition TimedHitPtr.h:55
#define unlikely(x)