ATLAS Offline Software
Loading...
Searching...
No Matches
StripSurfaceChargesGenerator.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#include "GaudiKernel/ConcurrencyFlags.h"
28
29// C++ Standard Library
30#include <cmath>
31
35
36namespace ITk
37{
38
39// constructor
41 const std::string& name,
42 const IInterface* parent)
43 : base_class(type, name, parent) {
44}
45
46// ----------------------------------------------------------------------
47// Initialize
48// ----------------------------------------------------------------------
50 ATH_MSG_DEBUG("StripSurfaceChargesGenerator::initialize()");
51
52 // Get ISiPropertiesTool
53 ATH_CHECK(m_siPropertiesTool.retrieve());
54
55 // Get ISiliconConditionsSvc
56 ATH_CHECK(m_siConditionsTool.retrieve());
57
59
60 if (m_doTrapping) {
61 // -- Get Radiation Damage Tool
62 ATH_CHECK(m_radDamageTool.retrieve());
63 } else {
64 m_radDamageTool.disable();
65 }
66
67 if (m_doHistoTrap) {
68 if (Gaudi::Concurrency::ConcurrencyFlags::numThreads() > 1) {
69 ATH_MSG_FATAL("Filling histograms not supported in MT jobs.");
70 return StatusCode::FAILURE;
71 }
72
73 // -- Get Histogram Service
74 ATH_CHECK(m_thistSvc.retrieve());
75 m_h = std::make_unique<Hists>();
76 ATH_CHECK(m_h->book(*m_thistSvc));
77 }
79
80 // Induced Charge Module.
82 const SCT_ID* sct_id{nullptr};
83 ATH_CHECK(detStore()->retrieve(sct_id, "SCT_ID"));
84 m_InducedChargeModel = std::make_unique<InducedChargeModel>(sct_id->wafer_hash_max());
85 }
86
87 // Surface drift time calculation Stuff
90 if ((m_tSurfaceDrift > m_tHalfwayDrift) and (m_tHalfwayDrift >= 0.0) and
92 m_SurfaceDriftFlag = true;
93 } else {
94 ATH_MSG_INFO("\tsurface drift still not on, wrong params");
95 }
96
97 // Make sure these two flags are not set simultaneously
98 if (m_tfix>-998. and m_tsubtract>-998.) {
99 ATH_MSG_FATAL("\tCannot set both FixedTime and SubtractTime options!");
100 ATH_MSG_INFO("\tMake sure the two flags are not set simultaneously in jo");
101 return StatusCode::FAILURE;
102 }
103
104 ATH_CHECK(m_lorentzAngleTool.retrieve());
105
106 return StatusCode::SUCCESS;
107}
108
109StatusCode StripSurfaceChargesGenerator::Hists::book (ITHistSvc& histSvc)
110{
111 m_h_efieldz = new TProfile("efieldz", "", 50, 0., 0.4);
112 ATH_CHECK(histSvc.regHist("/file1/efieldz", m_h_efieldz));
113
114 m_h_efield = new TH1F("efield", "", 100, 200., 800.);
115 ATH_CHECK(histSvc.regHist("/file1/efield", m_h_efield));
116
117 m_h_spess = new TH1F("spess", "", 50, 0., 0.4);
118 ATH_CHECK(histSvc.regHist("/file1/spess", m_h_spess));
119
120 m_h_depD = new TH1F("depD", "", 50, -0.3, 0.3);
121 ATH_CHECK(histSvc.regHist("/file1/depD", m_h_depD));
122
123 m_h_drift_electrode = new TH2F("drift_electrode", "", 50, 0., 20., 50, 0., 20.);
124 ATH_CHECK(histSvc.regHist("/file1/drift_electrode", m_h_drift_electrode));
125
126 m_h_drift_time = new TH1F("drift_time", "", 100, 0., 20.);
127 ATH_CHECK(histSvc.regHist("/file1/drift_time", m_h_drift_time));
128
129 m_h_t_electrode = new TH1F("t_electrode", "", 100, 0., 20.);
130 ATH_CHECK(histSvc.regHist("/file1/t_electrode", m_h_t_electrode));
131
132 m_h_ztrap = new TH1F("ztrap", "", 100, 0., 0.3);
133 ATH_CHECK(histSvc.regHist("/file1/ztrap", m_h_ztrap));
134
135 // More histograms to check what's going on
136 m_h_zhit = new TH1F("zhit", "", 50, -0.2, 0.2);
137 ATH_CHECK(histSvc.regHist("/file1/zhit", m_h_zhit));
138
139 m_h_ztrap_tot = new TH1F("ztrap_tot", "", 100, 0., 0.5);
140 ATH_CHECK(histSvc.regHist("/file1/ztrap_tot", m_h_ztrap_tot));
141
142 m_h_no_ztrap = new TH1F("no_ztrap", "", 100, 0., 0.5);
143 ATH_CHECK(histSvc.regHist("/file1/no_ztrap", m_h_no_ztrap));
144
145 m_h_trap_drift_t = new TH1F("trap_drift_t", "", 100, 0., 20.);
146 ATH_CHECK(histSvc.regHist("/file1/trap_drift_t", m_h_trap_drift_t));
147
148 m_h_notrap_drift_t = new TH1F("notrap_drift_t", "", 100, 0., 20.);
149 ATH_CHECK(histSvc.regHist("/file1/notrap_drift_t", m_h_notrap_drift_t));
150
151 m_h_mob_Char = new TProfile("mob_Char", "", 200, 100., 1000.);
152 ATH_CHECK(histSvc.regHist("/file1/mob_Char", m_h_mob_Char));
153
154 m_h_vel = new TProfile("vel", "", 100, 100., 1000.);
155 ATH_CHECK(histSvc.regHist("/file1/vel", m_h_vel));
156
157 m_h_drift1 = new TProfile("drift1", "", 50, 0., 0.3);
158 ATH_CHECK(histSvc.regHist("/file1/drift1", m_h_drift1));
159
160 m_h_gen = new TProfile("gen", "", 50, 0., 0.3);
161 ATH_CHECK(histSvc.regHist("/file1/gen", m_h_gen));
162
163 m_h_gen1 = new TProfile("gen1", "", 50, 0., 0.3);
164 ATH_CHECK(histSvc.regHist("/file1/gen1", m_h_gen1));
165
166 m_h_gen2 = new TProfile("gen2", "", 50, 0., 0.3);
167 ATH_CHECK(histSvc.regHist("/file1/gen2", m_h_gen2));
168
169 m_h_velocity_trap = new TProfile("velocity_trap", "", 50, 0., 1000.);
170 ATH_CHECK(histSvc.regHist("/file1/velocity_trap", m_h_velocity_trap));
171
172 m_h_mobility_trap = new TProfile("mobility_trap", "", 50, 100., 1000.);
173 ATH_CHECK(histSvc.regHist("/file1/mobility_trap", m_h_mobility_trap));
174
175 m_h_trap_pos = new TH1F("trap_pos", "", 100, 0., 0.3);
176 ATH_CHECK(histSvc.regHist("/file1/trap_pos", m_h_trap_pos));
177
178 return StatusCode::SUCCESS;
179}
180
181
182// ----------------------------------------------------------------------
183// finalize
184// ----------------------------------------------------------------------
186 ATH_MSG_DEBUG("StripSurfaceChargesGenerator::finalize()");
187 return StatusCode::SUCCESS;
188}
189
190// ----------------------------------------------------------------------
191// perpandicular Drift time calculation
192// ----------------------------------------------------------------------
193float StripSurfaceChargesGenerator::driftTime(float zhit, const SiDetectorElement* element, const EventContext& ctx) const {
194 if (element==nullptr) {
195 ATH_MSG_ERROR("StripSurfaceChargesGenerator::process element is nullptr");
196 return -2.0;
197 }
198 const SCT_ModuleSideDesign* design{dynamic_cast<const SCT_ModuleSideDesign*>(&(element->design()))};
199 if (design==nullptr) {
200 ATH_MSG_ERROR("StripSurfaceChargesGenerator::process can not get " << design);
201 return -2.0;
202 }
203 const double thickness{design->thickness()};
204 const IdentifierHash hashId{element->identifyHash()};
205
206 if ((zhit < 0.0) or (zhit > thickness)) {
207 ATH_MSG_DEBUG("driftTime: hit coordinate zhit=" << zhit / CLHEP::micrometer << " out of range");
208 return -2.0;
209 }
210
211 float depletionVoltage{0.};
212 float biasVoltage{0.};
213 if (m_useSiCondDB) {
214 depletionVoltage = m_siConditionsTool->depletionVoltage(hashId, ctx) * CLHEP::volt;
215 biasVoltage = m_siConditionsTool->biasVoltage(hashId, ctx) * CLHEP::volt;
216 } else {
217 depletionVoltage = m_vdepl * CLHEP::volt;
218 biasVoltage = m_vbias * CLHEP::volt;
219 }
220
221 const float denominator{static_cast<float>(depletionVoltage + biasVoltage - (2.0 * zhit * depletionVoltage / thickness))};
222 if (denominator <= 0.0) {
223 if (biasVoltage >= depletionVoltage) { // Should not happen
224 if(not m_isOverlay) {
225 ATH_MSG_ERROR("driftTime: negative argument X for log(X) " << zhit);
226 }
227 return -1.0;
228 } else {
229 // (m_biasVoltage<m_depletionVoltage) can happen with underdepleted sensors, lose charges in that volume
230 return -10.0;
231 }
232 }
233
234 float t_drift{std::log((depletionVoltage + biasVoltage) / denominator)};
235 t_drift *= thickness * thickness / (2.0 * m_siPropertiesTool->getSiProperties(hashId, ctx).holeDriftMobility() * depletionVoltage);
236 return t_drift;
237}
238
239// ----------------------------------------------------------------------
240// Sigma diffusion calculation
241// ----------------------------------------------------------------------
242float StripSurfaceChargesGenerator::diffusionSigma(float zhit, const SiDetectorElement* element, const EventContext& ctx) const {
243 if (element==nullptr) {
244 ATH_MSG_ERROR("StripSurfaceChargesGenerator::diffusionSigma element is nullptr");
245 return 0.0;
246 }
247 const IdentifierHash hashId{element->identifyHash()};
248 const float t{driftTime(zhit, element, ctx)}; // in ns
249
250 if (t > 0.0) {
251 const float sigma{static_cast<float>(std::sqrt(2. * m_siPropertiesTool->getSiProperties(hashId, ctx).holeDiffusionConstant() * t))}; // in mm
252 return sigma;
253 } else {
254 return 0.0;
255 }
256}
257
258// ----------------------------------------------------------------------
259// Maximum drift time
260// ----------------------------------------------------------------------
261float StripSurfaceChargesGenerator::maxDriftTime(const SiDetectorElement* element, const EventContext& ctx) const {
262 if (element) {
263 const float sensorThickness{static_cast<float>(element->thickness())};
264 return driftTime(sensorThickness, element, ctx);
265 } else {
266 ATH_MSG_INFO("Error: SiDetectorElement not set!");
267 return 0.;
268 }
269}
270
271// ----------------------------------------------------------------------
272// Maximum Sigma difusion
273// ----------------------------------------------------------------------
274float StripSurfaceChargesGenerator::maxDiffusionSigma(const SiDetectorElement* element, const EventContext& ctx) const {
275 if (element) {
276 const float sensorThickness{static_cast<float>(element->thickness())};
277 return diffusionSigma(sensorThickness, element, ctx);
278 } else {
279 ATH_MSG_INFO("Error: SiDetectorElement not set!");
280 return 0.;
281 }
282}
283
284// ----------------------------------------------------------------------
285// Calculating the surface drift time but I should confess that
286// I haven't found out yet where the calculation come from
287// ----------------------------------------------------------------------
289 if (m_SurfaceDriftFlag) {
290 if ((ysurf >= 0.0) and (ysurf <= m_distInterStrip)) {
291 float t_surfaceDrift{0.};
292 if (ysurf < m_distHalfInterStrip) {
293 const float y{ysurf / m_distHalfInterStrip};
294 t_surfaceDrift= m_tHalfwayDrift * y * y;
295 } else {
296 const float y{(m_distInterStrip - ysurf) / (m_distInterStrip - m_distHalfInterStrip)};
297 t_surfaceDrift = m_tSurfaceDrift + (m_tHalfwayDrift - m_tSurfaceDrift) * y * y;
298 }
299 return t_surfaceDrift;
300 } else {
301 ATH_MSG_INFO(" ysurf out of range " << ysurf);
302 return -1.0;
303 }
304 } else {
305 return 0.0;
306 }
307}
308
309// -------------------------------------------------------------------------------------------
310// create a list of surface charges from a hit - called from StripDigitization
311// AthAlgorithm
312// -------------------------------------------------------------------------------------------
314 const TimedHitPtr<SiHit>& phit,
316 CLHEP::HepRandomEngine * rndmEngine,
317 const EventContext& ctx) {
318 ATH_MSG_VERBOSE("StripSurfaceChargesGenerator::process starts");
319 processSiHit(element, *phit, inserter, phit.eventTime(), phit.eventId(), rndmEngine, ctx);
320}
321
322// -------------------------------------------------------------------------------------------
323// create a list of surface charges from a hit - called from both AthAlgorithm
324// and PileUpTool
325// -------------------------------------------------------------------------------------------
327 const SiHit& phit,
329 float p_eventTime,
330 unsigned short p_eventId,
331 CLHEP::HepRandomEngine* rndmEngine,
332 const EventContext& ctx) const {
333 const SCT_ModuleSideDesign* design;
334 const SCT_ModuleSideDesign* initialDesign{dynamic_cast<const SCT_ModuleSideDesign*>(&(element->design()))};
335 if (initialDesign==nullptr) {
336 ATH_MSG_ERROR("StripSurfaceChargesGenerator::process can not get " << initialDesign);
337 return;
338 }
339
340 //If this proves costly, we can pass a (potentially null) motherDesign
341 //in the interface instead, but this will require a new interface class
342 //(see comment in SiDigitization/ISurfaceChargesGenerator.h)
343
344 const SCT_ModuleSideDesign* motherDesign = initialDesign->getMother();
345
346 if(motherDesign!=nullptr){
347 ATH_MSG_DEBUG("Found a Mother Design - Using it!");
348 design = motherDesign;
349 }
350 else {
351 ATH_MSG_DEBUG("No Mother Design - Using Design from DetElement directly!");
352 design = initialDesign;
353 }
354
355 const double thickness{design->thickness()};
356 const IdentifierHash hashId{element->identifyHash()};
357 const double tanLorentz{m_lorentzAngleTool->getTanLorentzAngle(hashId, ctx)};
358
359 // ---**************************************
360 // Time of Flight Calculation - separate method?
361 // ---**************************************
362 // --- Original calculation of Time of Flight of the particle Time needed by the particle to reach the sensor
363 float timeOfFlight{p_eventTime + hitTime(phit)};
364
365 // Kondo 19/09/2007: Use the coordinate of the center of the module to calculate the time of flight
366 timeOfFlight -= (element->center().mag()) / CLHEP::c_light;
367 // !< extract the distance to the origin of the module to Time of flight
368
369 // !< timing set from jo to adjust (subtract) the timing
370 if (m_tsubtract > -998.) {
371 timeOfFlight -= m_tsubtract;
372 }
373 // ---**************************************
374
375 const CLHEP::Hep3Vector pos{phit.localStartPosition()};
376 const float xEta{static_cast<float>(pos[SiHit::xEta])};
377 const float xPhi{static_cast<float>(pos[SiHit::xPhi])};
378 const float xDep{static_cast<float>(pos[SiHit::xDep])};
379
380 const CLHEP::Hep3Vector endPos{phit.localEndPosition()};
381 const float cEta{static_cast<float>(endPos[SiHit::xEta]) - xEta};
382 const float cPhi{static_cast<float>(endPos[SiHit::xPhi]) - xPhi};
383 const float cDep{static_cast<float>(endPos[SiHit::xDep]) - xDep};
384
385
386
387 const float largeStep{std::sqrt(cEta*cEta + cPhi*cPhi + cDep*cDep)};
388 const int numberOfSteps{static_cast<int>(largeStep / m_smallStepLength) + 1};
389 const float steps{static_cast<float>(m_numberOfCharges * numberOfSteps)};
390 const float e1{static_cast<float>(phit.energyLoss() / steps)};
391 const float q1{static_cast<float>(e1 * m_siPropertiesTool->getSiProperties(hashId, ctx).electronHolePairsPerEnergy())};
392
393 // NB this is different to the SCT, where this would be
394 //float xhit{xEta};
395 //float yhit{xPhi};
396 //float zhit{xDep};
397 //float cX{cEta};
398 //float cY{cPhi};
399 //float cZ{cDep};
400
401 float xhit{xDep};
402 float yhit{xPhi};
403 float zhit{xEta};
404 float cX{cDep};
405 float cY{cPhi};
406 float cZ{cEta};
407
409 if (m_doInducedChargeModel) { // Setting magnetic field for the ICM.
411 const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
412 float vdepl{m_vdepl};
413 float vbias{m_vbias};
414 if (m_useSiCondDB) {
415 vdepl = m_siConditionsTool->depletionVoltage(hashId, ctx);
416 vbias = m_siConditionsTool->biasVoltage(hashId, ctx);
417 }
418 data = m_InducedChargeModel->setWaferData(vdepl,
419 vbias,
420 element,
421 fieldCondObj,
423 rndmEngine,
424 ctx);
425 }
426
427 const float stepX{cX / numberOfSteps};
428 const float stepY{cY / numberOfSteps};
429 const float stepZ{cZ / numberOfSteps};
430
431 // check the status of truth information for this SiHit
432 // some Truth information is cut for pile up events
433 const HepMcParticleLink trklink = HepMcParticleLink::getRedirectedLink(phit.particleLink(), p_eventId, ctx); // This link should now correctly resolve to the TruthEvent McEventCollection in the main StoreGateSvc.
435 if (phit.truthID() != 0 || phit.truthBarcode() != 0) { // if the hit was not caused by a delta-ray then one of these must be true
436 if (not trklink.isValid()) {
437 // TODO consider extending this check to reject links to
438 // GenEvents other than the first one in the McEventCollection,
439 // so that the digitization output doesn't change if pile-up
440 // truth is saved.
441 hitproc = SiCharge::cut_track;
442 }
443 }
444
445 float dstep{-0.5};
446 for (int istep{0}; istep < numberOfSteps; ++istep) {
447 dstep += 1.0;
448 float z1{zhit + stepZ * dstep};
449
450 // Distance between charge and readout side.
451 // design->readoutSide() is +1 if readout side is in +ve depth axis direction and visa-versa.
452 float zReadout{static_cast<float>(0.5 * thickness - design->readoutSide() * z1)};
453 const double spess{zReadout};
454
455 if (m_doHistoTrap) {
456 Hists& h = getHists();
457 h.m_h_depD->Fill(z1);
458 h.m_h_spess->Fill(spess);
459 }
460
461 float t_drift{driftTime(zReadout, element, ctx)}; // !< t_drift: perpandicular drift time
462 if (t_drift>-2.0000002 and t_drift<-1.9999998) {
463 ATH_MSG_DEBUG("Checking for rounding errors in compression");
464 if ((std::abs(z1) - 0.5 * thickness) < 0.000010) {
465 ATH_MSG_DEBUG("Rounding error found attempting to correct it. z1 = " << std::fixed << std::setprecision(8) << z1);
466 if (z1 < 0.0) {
467 z1 = 0.0000005 - 0.5 * thickness;
468 // set new coordinate to be 0.5nm inside wafer volume.
469 } else {
470 z1 = 0.5 * thickness - 0.0000005;
471 // set new coordinate to be 0.5nm inside wafer volume.
472 }
473 zReadout = 0.5 * thickness - design->readoutSide() * z1;
474 t_drift = driftTime(zReadout, element, ctx);
475 if (t_drift>-2.0000002 and t_drift<-1.9999998) {
476 ATH_MSG_WARNING("Attempt failed. Making no correction.");
477 } else {
478 ATH_MSG_DEBUG("Correction Successful! z1 = " << std::fixed << std::setprecision(8) << z1 << ", zReadout = " << zReadout << ", t_drift = " << t_drift);
479 }
480 } else {
481 ATH_MSG_DEBUG("No rounding error found. Making no correction.");
482 }
483 }
484 if (t_drift > 0.0) {
485 const float x1{xhit + stepX * dstep};
486 float y1{yhit + stepY * dstep};
487
488 float sigma{0.};
489 if (not m_doInducedChargeModel) {
490 sigma = diffusionSigma(zReadout, element, ctx);
491 y1 += tanLorentz * zReadout; // !< Taking into account the magnetic field
492 } // These are treated in Induced Charge Model.
493
494 for (int i{0}; i < m_numberOfCharges; ++i) {
495 const float rx{CLHEP::RandGaussZiggurat::shoot(rndmEngine)};
496 const float xd{x1 + sigma * rx};
497 const float ry{CLHEP::RandGaussZiggurat::shoot(rndmEngine)};
498 const float yd{y1 + sigma * ry};
499
500 // For charge trapping with Ramo potential
501 const double stripPitch{0.080}; // mm
502 double dstrip{y1 / stripPitch}; // mm
503 if (dstrip > 0.) {
504 dstrip = dstrip - std::trunc(dstrip);
505 } else {
506 dstrip = dstrip - std::trunc(dstrip) + 1;
507 }
508
509 // now y will be x and z will be y ....just to make sure to confuse everebody
510 double y0{dstrip * stripPitch}; // mm
511 double z0{thickness - zReadout}; // mm
512
513 // -- Charge Trapping
514 if (m_doTrapping) {
515 if (m_doHistoTrap) {
516 Hists& h = getHists();
517 h.m_h_zhit->Fill(zhit);
518 }
519 double trap_pos{-999999.}, drift_time{-999999.}; // FIXME need better default values
520 if (chargeIsTrapped(spess, element, trap_pos, drift_time)) {
521 if (not m_doRamo) {
522 break;
523 } else { // if we want to take into account also Ramo Potential
524 double Q_m2{0.}, Q_m1{0.}, Q_00{0.}, Q_p1{0.}, Q_p2{0.}; // Charges
525
526 dstrip = y1 / stripPitch; // mm
527 // need the distance from the nearest strips
528 // edge not centre, xtaka = 1/2*stripPitch
529 // centre of detector, y1=0, is in the middle of
530 // an interstrip gap
531 if (dstrip > 0.) {
532 dstrip -= static_cast<double>(static_cast<int>(dstrip));
533 } else {
534 dstrip -= static_cast<double>(static_cast<int>(dstrip)) + 1;
535 }
536
537 // now y will be x and z will be y ....just to make sure to confuse everebody
538 double yfin{dstrip * stripPitch}; // mm
539 double zfin{thickness - trap_pos}; // mm
540
541 m_radDamageTool->holeTransport(y0, z0, yfin, zfin, Q_m2, Q_m1, Q_00, Q_p1, Q_p2);
542 for (int strip{-2}; strip<=2; strip++) {
543 const double ystrip{yd + strip * stripPitch}; // mm
544 const SiLocalPosition position(element->hitLocalToLocal(xd, ystrip));
545 if (design->inActiveArea(position)) {
546 double charge{0.};
547 if (strip == -2) charge = Q_m2;
548 else if (strip == -1) charge = Q_m1;
549 else if (strip == 0) charge = Q_00;
550 else if (strip == 1) charge = Q_p1;
551 else if (strip == 2) charge = Q_p2;
552 const double time{drift_time};
553 if (charge != 0.) {
554 inserter(SiSurfaceCharge(position, SiCharge(q1*charge, time, hitproc, trklink)));
555 continue;
556 }
557 }
558 }
559 ATH_MSG_INFO("strip zero charge = " << Q_00); // debug
560 } // m_doRamo==true
561 } // chargeIsTrapped()
562 } // m_doTrapping==true
563
564 if (not m_doRamo) {
565 if (m_doInducedChargeModel) { // Induced Charge Model
566 // Charges storages for 50 ns. 0.5 ns steps.
572
573 const double mm2cm = 0.1; // For mm -> cm conversion
574 // Unit for y and z : mm -> cm in InducedChargeModel
575 m_InducedChargeModel->holeTransport(*data,
576 y0*mm2cm, z0*mm2cm,
577 Q_m2, Q_m1, Q_00, Q_p1, Q_p2,
578 hashId, m_siPropertiesTool,
579 ctx);
580 m_InducedChargeModel->electronTransport(*data,
581 y0*mm2cm, z0*mm2cm,
582 Q_m2, Q_m1, Q_00, Q_p1, Q_p2,
583 hashId, m_siPropertiesTool,
584 ctx);
585
586 for (int it{0}; it<InducedChargeModel::NTransportSteps; it++) {
587 if (Q_00[it] == 0.0) continue;
588 double ICM_time{(it+0.5)*0.5 + timeOfFlight};
589 double Q_new[InducedChargeModel::NStrips]{
590 Q_m2[it], Q_m1[it], Q_00[it], Q_p1[it], Q_p2[it]
591 };
593 double ystrip{y1 + strip * stripPitch};
594 SiLocalPosition position{element->hitLocalToLocal(x1, ystrip)};
595 if (design->inActiveArea(position)) {
596 inserter(SiSurfaceCharge(position,
598 ICM_time, hitproc, trklink)));
599 }
600 }
601 }
602 } else { // not m_doInducedChargeModel
603 const SiLocalPosition position{element->hitLocalToLocal(xd, yd)};
604 if (design->inActiveArea(position)) {
605 const float sdist{static_cast<float>(design->scaledDistanceToNearestDiode(position))};
606 // !< dist on the surface from the hit point to the nearest strip (diode)
607 const float t_surf{surfaceDriftTime(2.0 * sdist)}; // !< Surface drift time
608 const float totaltime{(m_tfix > -998.) ? m_tfix.value() : t_drift + timeOfFlight + t_surf}; // !< Total drift time
609 inserter(SiSurfaceCharge(position, SiCharge(q1, totaltime, hitproc, trklink)));
610 } else {
611 ATH_MSG_VERBOSE(std::fixed << std::setprecision(8) << "Local position (phi, eta, depth): ("
612 << position.xPhi() << ", " << position.xEta() << ", " << position.xDepth()
613 << ") of the element is out of active area, charge = " << q1);
614 }
615 }
616 }
617 } // end of loop on charges
618 }
619 }
620 }
621
623 const SiDetectorElement* element,
624 double& trap_pos,
625 double& drift_time) const {
626 if (element==nullptr) {
627 ATH_MSG_ERROR("StripSurfaceChargesGenerator::chargeIsTrapped element is nullptr");
628 return false;
629 }
630 bool isTrapped{false};
631 const IdentifierHash hashId{element->identifyHash()};
632 const SCT_ChargeTrappingCondData condData{m_radDamageTool->getCondData(hashId, spess)};
633 const double electric_field{condData.getElectricField()};
634
635 if (m_doHistoTrap) {
636 Hists& h = getHists();
637 const double mobChar{condData.getHoleDriftMobility()};
638 h.m_h_efieldz->Fill(spess, electric_field);
639 h.m_h_efield->Fill(electric_field);
640 h.m_h_mob_Char->Fill(electric_field, mobChar);
641 h.m_h_vel->Fill(electric_field, electric_field * mobChar);
642 }
643 const double t_electrode{condData.getTimeToElectrode()};
644 drift_time = condData.getTrappingTime();
645 const double z_trap{condData.getTrappingPositionZ()};
646 trap_pos = spess - z_trap;
647 if (m_doHistoTrap) {
648 Hists& h = getHists();
649 h.m_h_drift_time->Fill(drift_time);
650 h.m_h_t_electrode->Fill(t_electrode);
651 h.m_h_drift_electrode->Fill(drift_time, t_electrode);
652 h.m_h_ztrap_tot->Fill(z_trap);
653 }
654 // -- Calculate if the charge is trapped, and at which distance
655 // -- Charge gets trapped before arriving to the electrode
656 if (drift_time < t_electrode) {
657 isTrapped = true;
658 ATH_MSG_INFO("drift_time: " << drift_time << " t_electrode: " << t_electrode << " spess " << spess);
659 ATH_MSG_INFO("z_trap: " << z_trap);
660 if (m_doHistoTrap) {
661 Hists& h = getHists();
662 h.m_h_ztrap->Fill(z_trap);
663 h.m_h_trap_drift_t->Fill(drift_time);
664 h.m_h_drift1->Fill(spess, drift_time / t_electrode);
665 h.m_h_gen->Fill(spess, drift_time);
666 h.m_h_gen1->Fill(spess, z_trap);
667 h.m_h_gen2->Fill(spess, z_trap / drift_time * t_electrode);
668 h.m_h_velocity_trap->Fill(electric_field, z_trap / drift_time);
669 h.m_h_mobility_trap->Fill(electric_field, z_trap / drift_time / electric_field);
670 h.m_h_trap_pos->Fill(trap_pos);
671 }
672 } else {
673 isTrapped = false;
674 if (m_doHistoTrap) {
675 const double z_trap{condData.getTrappingPositionZ()};
676 Hists& h = getHists();
677 h.m_h_no_ztrap->Fill(z_trap);
678 h.m_h_notrap_drift_t->Fill(drift_time);
679 }
680 }
681 return isTrapped;
682}
683
684
687{
688 // We earlier checked that no more than one thread is being used.
689 Hists* h ATLAS_THREAD_SAFE = m_h.get();
690 return *h;
691}
692
693
694} // namespace ITk
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
#define ATLAS_THREAD_SAFE
Header file for AthHistogramAlgorithm.
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
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
float maxDriftTime(const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
max drift charge equivalent to the detector thickness
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCacheCondObjInputKey
bool chargeIsTrapped(double spess, const InDetDD::SiDetectorElement *element, double &trap_pos, double &drift_time) const
virtual StatusCode initialize() override
AlgTool initialize.
float surfaceDriftTime(float ysurf) const
Calculate of the surface drift time.
float diffusionSigma(float zhit, const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
calculate diffusion sigma from a gaussian dist scattered charge
void processSiHit(const InDetDD::SiDetectorElement *element, const SiHit &phit, ISiSurfaceChargesInserter &inserter, float eventTime, unsigned short eventID, CLHEP::HepRandomEngine *rndmEngine, const EventContext &ctx) const
ToolHandle< ISiPropertiesTool > m_siPropertiesTool
virtual StatusCode finalize() override
AlgTool finalize.
FloatProperty m_tSurfaceDrift
related to the surface drift
ToolHandle< ISiLorentzAngleTool > m_lorentzAngleTool
ToolHandle< ISiliconConditionsTool > m_siConditionsTool
float m_distInterStrip
Inter strip distance normalized to 1.
float maxDiffusionSigma(const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
max sigma diffusion
std::unique_ptr< InducedChargeModel > m_InducedChargeModel
StripSurfaceChargesGenerator(const std::string &type, const std::string &name, const IInterface *parent)
constructor
float m_distHalfInterStrip
Half way distance inter strip.
ToolHandle< ISCT_RadDamageSummaryTool > m_radDamageTool
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 ...
const SCT_ModuleSideDesign * getMother() const
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
@ 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