ATLAS Offline Software
Loading...
Searching...
No Matches
SCT_SurfaceChargesGenerator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 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 float vdepl{m_vdepl};
368 float vbias{m_vbias};
369 if (m_useSiCondDB) {
370 vdepl = m_siConditionsTool->depletionVoltage(hashId, ctx);
371 vbias = m_siConditionsTool->biasVoltage(hashId, ctx);
372 }
373 data = m_InducedChargeModel->setWaferData(vdepl,
374 vbias,
375 element,
376 fieldCondObj,
378 rndmEngine,
379 ctx);
380 }
381
382 const float StepX{cEta / numberOfSteps};
383 const float StepY{cPhi / numberOfSteps};
384 const float StepZ{cDep / numberOfSteps};
385
386 // check the status of truth information for this SiHit
387 // some Truth information is cut for pile up events
388 const HepMcParticleLink trklink = HepMcParticleLink::getRedirectedLink(phit.particleLink(), p_eventId, ctx); // This link should now correctly resolve to the TruthEvent McEventCollection in the main StoreGateSvc.
390 if (phit.truthID() != 0 || phit.truthBarcode() != 0) { // if the hit was not caused by a delta-ray then one of these must be true
391 if (not trklink.isValid()) {
392 // TODO consider extending this check to reject links to
393 // GenEvents other than the first one in the McEventCollection,
394 // so that the digitization output doesn't change if pile-up
395 // truth is saved.
396 hitproc = SiCharge::cut_track;
397 }
398 }
399
400 float dstep{-0.5};
401 for (int istep{0}; istep < numberOfSteps; ++istep) {
402 dstep += 1.0;
403 float z1{zhit + StepZ * dstep};
404
405 // Distance between charge and readout side.
406 // design->readoutSide() is +1 if readout side is in +ve depth axis direction and visa-versa.
407 float zReadout{static_cast<float>(0.5 * thickness - design->readoutSide() * z1)};
408 const double spess{zReadout};
409
410 if (m_doHistoTrap) {
411 m_h_depD->Fill(z1);
412 m_h_spess->Fill(spess);
413 }
414
415 float t_drift{driftTime(zReadout, element, ctx)}; // !< t_drift: perpandicular drift time
416 if (t_drift>-2.0000002 and t_drift<-1.9999998) {
417 ATH_MSG_DEBUG("Checking for rounding errors in compression");
418 if ((std::abs(z1) - 0.5 * thickness) < 0.000010) {
419 ATH_MSG_DEBUG("Rounding error found attempting to correct it. z1 = " << std::fixed << std::setprecision(8) << z1);
420 if (z1 < 0.0) {
421 z1 = 0.0000005 - 0.5 * thickness;
422 // set new coordinate to be 0.5nm inside wafer volume.
423 } else {
424 z1 = 0.5 * thickness - 0.0000005;
425 // set new coordinate to be 0.5nm inside wafer volume.
426 }
427 zReadout = 0.5 * thickness - design->readoutSide() * z1;
428 t_drift = driftTime(zReadout, element, ctx);
429 if (t_drift>-2.0000002 and t_drift<-1.9999998) {
430 ATH_MSG_WARNING("Attempt failed. Making no correction.");
431 } else {
432 ATH_MSG_DEBUG("Correction Successful! z1 = " << std::fixed << std::setprecision(8) << z1 << ", zReadout = " << zReadout << ", t_drift = " << t_drift);
433 }
434 } else {
435 ATH_MSG_DEBUG("No rounding error found. Making no correction.");
436 }
437 }
438 if (t_drift > 0.0) {
439 const float x1{xhit + StepX * dstep};
440 float y1{yhit + StepY * dstep};
441
442 float sigma{0.};
443 if (not m_doInducedChargeModel) {
444 sigma = diffusionSigma(zReadout, element, ctx);
445 y1 += tanLorentz * zReadout; // !< Taking into account the magnetic field
446 } // These are treated in Induced Charge Model.
447
448 for (int i{0}; i < m_numberOfCharges; ++i) {
449 const float rx{CLHEP::RandGaussZiggurat::shoot(rndmEngine)};
450 const float xd{x1 + sigma * rx};
451 const float ry{CLHEP::RandGaussZiggurat::shoot(rndmEngine)};
452 const float yd{y1 + sigma * ry};
453
454 // For charge trapping with Ramo potential
455 const double stripPitch{0.080}; // mm
456 double dstrip{y1 / stripPitch}; // mm
457 if (dstrip > 0.) {
458 dstrip = dstrip - std::trunc(dstrip);
459 } else {
460 dstrip = dstrip - std::trunc(dstrip) + 1;
461 }
462
463 // now y will be x and z will be y ....just to make sure to confuse everebody
464 double y0{dstrip * stripPitch}; // mm
465 double z0{thickness - zReadout}; // mm
466
467 // -- Charge Trapping
468 if (m_doTrapping) {
469 if (m_doHistoTrap) {
470 m_h_zhit->Fill(zhit);
471 }
472 double trap_pos{-999999.}, drift_time{-999999.}; // FIXME need better default values
473 if (chargeIsTrapped(spess, element, trap_pos, drift_time)) {
474 if (not m_doRamo) {
475 break;
476 } else { // if we want to take into account also Ramo Potential
477 double Q_all[5]={0.0,0.0,0.0,0.0,0.0};
478
479 dstrip = y1 / stripPitch; // mm
480 // need the distance from the nearest strips
481 // edge not centre, xtaka = 1/2*stripPitch
482 // centre of detector, y1=0, is in the middle of
483 // an interstrip gap
484 if (dstrip > 0.) {
485 dstrip -= static_cast<double>(static_cast<int>(dstrip));
486 } else {
487 dstrip -= static_cast<double>(static_cast<int>(dstrip)) + 1;
488 }
489
490 // now y will be x and z will be y ....just to make sure to confuse everebody
491 double yfin{dstrip * stripPitch}; // mm
492 double zfin{thickness - trap_pos}; // mm
493
494 m_radDamageTool->holeTransport(y0, z0, yfin, zfin, Q_all[0], Q_all[1], Q_all[2], Q_all[3], Q_all[4]);
495 for (int strip{-2}; strip<=2; strip++) {
496 const double ystrip{yd + strip * stripPitch}; // mm
497 const SiLocalPosition position(element->hitLocalToLocal(xd, ystrip));
498 if (design->inActiveArea(position)) {
499 const double charge = Q_all[strip+2];
500 const double time{drift_time};
501 if (charge != 0.) {
502 inserter(SiSurfaceCharge(position, SiCharge(q1*charge, time, hitproc, trklink)));
503 continue;
504 }
505 }
506 }
507 ATH_MSG_INFO("strip zero charge = " << Q_all[2]); // debug
508 } // m_doRamo==true
509 } // chargeIsTrapped()
510 } // m_doTrapping==true
511
512 if (not m_doRamo) {
513 if (m_doInducedChargeModel) { // Induced Charge Model
514 // Charges storages for 50 ns. 0.5 ns steps.
520
521 const double mm2cm = 0.1; // For mm -> cm conversion
522 // Unit for y and z : mm -> cm in InducedChargeModel
523 m_InducedChargeModel->holeTransport(*data,
524 y0*mm2cm, z0*mm2cm,
525 Q_m2, Q_m1, Q_00, Q_p1, Q_p2,
526 hashId, m_siPropertiesTool,
527 ctx);
528 m_InducedChargeModel->electronTransport(*data,
529 y0*mm2cm, z0*mm2cm,
530 Q_m2, Q_m1, Q_00, Q_p1, Q_p2,
531 hashId, m_siPropertiesTool,
532 ctx);
533
534 for (int it{0}; it<InducedChargeModel::NTransportSteps; it++) {
535 if (Q_00[it] == 0.0) continue;
536 double ICM_time{(it+0.5)*0.5 + timeOfFlight};
537 double Q_new[InducedChargeModel::NStrips]{
538 Q_m2[it], Q_m1[it], Q_00[it], Q_p1[it], Q_p2[it]
539 };
541 double ystrip{y1 + strip * stripPitch};
542 SiLocalPosition position{element->hitLocalToLocal(x1, ystrip)};
543 if (design->inActiveArea(position)) {
544 inserter(SiSurfaceCharge(position,
546 ICM_time, hitproc, trklink)));
547 }
548 }
549 }
550 } else { // not m_doInducedChargeModel
551 const SiLocalPosition position{element->hitLocalToLocal(xd, yd)};
552 if (design->inActiveArea(position)) {
553 const float sdist{static_cast<float>(design->scaledDistanceToNearestDiode(position))};
554 // !< dist on the surface from the hit point to the nearest strip (diode)
555 const float t_surf{surfaceDriftTime(2.0 * sdist)}; // !< Surface drift time
556 const float totaltime{(m_tfix > -998.) ? m_tfix.value() : t_drift + timeOfFlight + t_surf}; // !< Total drift time
557 inserter(SiSurfaceCharge(position, SiCharge(q1, totaltime, hitproc, trklink)));
558 } else {
559 ATH_MSG_VERBOSE(std::fixed << std::setprecision(8) << "Local position (phi, eta, depth): ("
560 << position.xPhi() << ", " << position.xEta() << ", " << position.xDepth()
561 << ") of the element is out of active area, charge = " << q1);
562 }
563 }
564 }
565 } // end of loop on charges
566 }
567 }
568 }
569
571 const SiDetectorElement* element,
572 double& trap_pos,
573 double& drift_time) {
574 if (element==nullptr) {
575 ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::chargeIsTrapped element is nullptr");
576 return false;
577 }
578 bool isTrapped{false};
579 const IdentifierHash hashId{element->identifyHash()};
580 const SCT_ChargeTrappingCondData condData{m_radDamageTool->getCondData(hashId, spess)};
581 const double electric_field{condData.getElectricField()};
582
583 if (m_doHistoTrap) {
584 const double mobChar{condData.getHoleDriftMobility()};
585 m_h_efieldz->Fill(spess, electric_field);
586 m_h_efield->Fill(electric_field);
587 m_h_mob_Char->Fill(electric_field, mobChar);
588 m_h_vel->Fill(electric_field, electric_field * mobChar);
589 }
590 const double t_electrode{condData.getTimeToElectrode()};
591 drift_time = condData.getTrappingTime();
592 const double z_trap{condData.getTrappingPositionZ()};
593 trap_pos = spess - z_trap;
594 if (m_doHistoTrap) {
595 m_h_drift_time->Fill(drift_time);
596 m_h_t_electrode->Fill(t_electrode);
597 m_h_drift_electrode->Fill(drift_time, t_electrode);
598 m_h_ztrap_tot->Fill(z_trap);
599 }
600 // -- Calculate if the charge is trapped, and at which distance
601 // -- Charge gets trapped before arriving to the electrode
602 if (drift_time < t_electrode) {
603 isTrapped = true;
604 ATH_MSG_INFO("drift_time: " << drift_time << " t_electrode: " << t_electrode << " spess " << spess);
605 ATH_MSG_INFO("z_trap: " << z_trap);
606 if (m_doHistoTrap) {
607 m_h_ztrap->Fill(z_trap);
608 m_h_trap_drift_t->Fill(drift_time);
609 m_h_drift1->Fill(spess, drift_time / t_electrode);
610 m_h_gen->Fill(spess, drift_time);
611 m_h_gen1->Fill(spess, z_trap);
612 m_h_gen2->Fill(spess, z_trap / drift_time * t_electrode);
613 m_h_velocity_trap->Fill(electric_field, z_trap / drift_time);
614 m_h_mobility_trap->Fill(electric_field, z_trap / drift_time / electric_field);
615 m_h_trap_pos->Fill(trap_pos);
616 }
617 } else {
618 isTrapped = false;
619 if (m_doHistoTrap) {
620 const double z_trap{condData.getTrappingPositionZ()};
621 m_h_no_ztrap->Fill(z_trap);
622 m_h_notrap_drift_t->Fill(drift_time);
623 }
624 }
625 return isTrapped;
626}
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
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
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: ...
double xDepth() const
position along depth direction:
double xPhi() const
position along phi direction:
double xEta() const
position along eta direction:
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 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.
bool chargeIsTrapped(double spess, const InDetDD::SiDetectorElement *element, double &trap_pos, double &drift_time)
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