262 {
263
264 bool isITk(false);
266 isITk = true;
268 return StatusCode::SUCCESS;
269 }
270 } else {
271
273 if (!Module.
isDBM()) {
274 return StatusCode::SUCCESS;
275 }
276 }
277 }
278
279 const PixelID* p_pixelId =
static_cast<const PixelID*
>(Module.
getIdHelper());
281
282
283 double eta_0 = initialConditions[0];
284 double phi_0 = initialConditions[1];
285 double depth_0 = initialConditions[2];
286 double dEta = initialConditions[3];
287 double dPhi = initialConditions[4];
288 double dDepth = initialConditions[5];
289 double ncharges = initialConditions[6];
290 double iTotalLength = initialConditions[7];
291
292 const double oneOverNchargesTimes1e6 = 1./(1.E+6 * ncharges);
293
294
298
299 int etaCells = p_design.
columns();
300 int phiCells = p_design.
rows();
301
302 double eleholePairEnergy = 0;
303 double smearRand = 0;
304
305 double diffusionConstant;
306 if (Module.
isDBM()) {
307 eleholePairEnergy = 1. / (13. * CLHEP::eV);
308 diffusionConstant = .00265;
309 smearRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine);
310 } else {
312 diffusionConstant = .007;
313 }
314
315 double collectionDist = 0.2 * CLHEP::mm;
316 double smearScale = 1. + 0.35 * smearRand;
317 double tanLorentz(0);
318 double coLorentz(0);
321 coLorentz = std::sqrt(1.0 + (tanLorentz*tanLorentz));
322 }
323
324
325
326
327
329 const double pHitTime =
hitTime(phit);
330
331 const double halfEtaPitch = 0.5*Module.
etaPitch();
332 const double halfPhiPitch = 0.5*Module.
phiPitch();
333
335 SG::ReadCondHandle<PixelRadiationDamageFluenceMapData> fluenceDataHandle(
m_fluenceDataKey,ctx);
336 const PixelRadiationDamageFluenceMapData *fluenceData = *fluenceDataHandle;
337
338 std::pair<double, double> trappingTimes;
341 }
342 else {
344 }
345
351
352 std::map<unsigned, std::pair<SiLocalPosition, double>> cachedChargeMap;
353 std::map<unsigned, SiCellId> diodeCellMap;
354 for (const auto& iHitRecord : trfHitRecord) {
355
356 double eta_i = eta_0;
357 double phi_i = phi_0;
358 double depth_i = depth_0;
359 if (iTotalLength) {
360 eta_i += 1.0 * iHitRecord.first / iTotalLength *
dEta;
361 phi_i += 1.0 * iHitRecord.first / iTotalLength *
dPhi;
362 depth_i += 1.0 * iHitRecord.first / iTotalLength * dDepth;
363 }
364
365
368 if (!pixel_i.
isValid())
continue;
369
370
371
372 double dist_electrode = 0.5 * sensorThickness - Module.
design().
readoutSide() * depth_i;
373 if (dist_electrode < 0) {
374 dist_electrode = 0;
375 }
376
378
379
380 const int nnLoop_pixelEtaMax = std::min(1, pixel_i.
etaIndex());
381 const int nnLoop_pixelEtaMin = std::max(-1, pixel_i.
etaIndex() + 1 - etaCells);
382 const int nnLoop_pixelPhiMax = std::min(1, pixel_i.
phiIndex());
383 const int nnLoop_pixelPhiMin = std::max(-1, pixel_i.
phiIndex() + 1 - phiCells);
384
385 std::array<double, 3> sensorScales{};
386
387 const std::size_t distance_f_e_bin_x = distanceMap_e.
getBinX(dist_electrode);
388 const std::size_t distance_f_h_bin_x = distanceMap_h.
getBinX(dist_electrode);
389 const std::size_t tanLorentz_e_bin_x = lorentzMap_e.
getBinX(dist_electrode);
390 const std::size_t tanLorentz_h_bin_x = lorentzMap_h.
getBinX(dist_electrode);
391
392 const std::size_t sizePhi = std::abs(nnLoop_pixelPhiMax - nnLoop_pixelPhiMin) + 1;
393
394 const auto pixel_eta = pixel_i.
etaIndex();
395 const auto pixel_phi = pixel_i.
phiIndex();
396
397
398 std::array<std::pair<double,double>,9 > centrePixelNNEtaPhi;
399 for (
int p = nnLoop_pixelEtaMin;
p <= nnLoop_pixelEtaMax;
p++) {
400 const std::size_t ieta =
p - nnLoop_pixelEtaMin;
401
402 double scale_f = 1.;
404 if (std::abs(columnWidth - 0.6) < 1e-9) {
405 scale_f = 4. / 6.;
406 } else if (std::abs(columnWidth - 0.45) < 1e-9) {
407 scale_f = 25. / 45.;
408 } else if (std::abs(columnWidth - 0.5) < 1e-9) {
409 scale_f = 25. / 50.;
410 }
411 sensorScales[ieta] = scale_f;
412
413 for (
int q = nnLoop_pixelPhiMin;
q <= nnLoop_pixelPhiMax;
q++) {
415 pixel_phi - q);
416 const std::size_t iphi =
q - nnLoop_pixelPhiMin;
417 const std::size_t
index = iphi + ieta*sizePhi;
418 centrePixelNNEtaPhi.at(index).first = centreOfPixel_nn.
xEta();
419 centrePixelNNEtaPhi[
index].second = centreOfPixel_nn.
xPhi();
420 }
421 }
422
423
424 for (int j = 0; j < ncharges; j++) {
425
426 double energy_per_step = oneOverNchargesTimes1e6 * iHitRecord.second;
427 double u = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0);
428
429 const double drifttime_e = (-1.) * (trappingTimes.first) * logf(u);
430 u = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0);
431 const double drifttime_h = (-1.) * (trappingTimes.second) * logf(u);
432
433
434
435
436
437
438
439 const double depth_f_e = distanceMap_e.
getContent(distance_f_e_bin_x, distanceMap_e.
getBinY(drifttime_e));
440 const double depth_f_h = distanceMap_h.
getContent(distance_f_h_bin_x, distanceMap_h.
getBinY(drifttime_h));
441 const double tanLorentz_e = lorentzMap_e.
getContent(tanLorentz_e_bin_x, lorentzMap_e.
getBinY(depth_f_e));
442 const double tanLorentz_h = lorentzMap_h.
getContent(tanLorentz_h_bin_x, lorentzMap_h.
getBinY(depth_f_h));
443 const double dz_e = std::abs(dist_electrode - depth_f_e);
444 const double dz_h = std::abs(depth_f_h - dist_electrode);
445 const double coLorentz_e = std::sqrt(1.0 + (tanLorentz_e*tanLorentz_e));
446
447
448 double phiRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine);
449
450
451 const double rdif_e = diffusionConstant * std::sqrt(dz_e * coLorentz_e / 0.3);
452 const double phi_f_e = phi_i + dz_e * tanLorentz_e + rdif_e * phiRand;
453 double etaRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine);
454 double eta_f_e = eta_i + rdif_e * etaRand;
455
456 phiRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine);
457 const double coLorentz_h = std::sqrt(1.0 + (tanLorentz_h*tanLorentz_h));
458 const double rdif_h = diffusionConstant * std::sqrt(dz_h * coLorentz_h / 0.3);
459 const double phi_f_h = phi_i + dz_h * tanLorentz_h + rdif_h * phiRand;
460 etaRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine);
461 double eta_f_h = eta_i + rdif_h * etaRand;
462
463
464
468 }
469
470 const std::size_t ramo_f_e_bin_z = ramoPotentialMap.
getBinZ(1e3*depth_f_e);
471 const std::size_t ramo_f_h_bin_z = ramoPotentialMap.
getBinZ(1e3*depth_f_h);
472
473 const bool isFirstZ_e = ramoPotentialMap.
isFirstZ(1e3*depth_f_e);
474 const bool isOverflowZ_h = ramoPotentialMap.
isOverflowZ(1e3*depth_f_h);
475
476 const double pixelEta_f_e = eta_f_e - centreOfPixel_i.
xEta();
477 const double pixelPhi_f_e = phi_f_e - centreOfPixel_i.
xPhi();
478
479 const double pixelEta_f_h = eta_f_h - centreOfPixel_i.
xEta();
480 const double pixelPhi_f_h = phi_f_h - centreOfPixel_i.
xPhi();
481
482
483
484 for (
int p = nnLoop_pixelEtaMin;
p <= nnLoop_pixelEtaMax;
p++) {
485 const std::size_t ieta =
p - nnLoop_pixelEtaMin;
486
487 for (
int q = nnLoop_pixelPhiMin;
q <= nnLoop_pixelPhiMax;
q++) {
488
489
490
491 const std::size_t iphi =
q - nnLoop_pixelPhiMin;
492 const std::size_t
index = iphi + ieta*sizePhi;
493
494
495 const std::pair<double,double>& centrePixelNN = centrePixelNNEtaPhi.at(index);
496 const double dPhi_nn_centre = centrePixelNN.second - centreOfPixel_i.
xPhi();
497 const double dEta_nn_centre = centrePixelNN.first - centreOfPixel_i.
xEta();
498
499
500
501
502
503
504
505 const double dEta_f_e = std::abs(pixelEta_f_e - dEta_nn_centre)*sensorScales[ieta];
506 const double dPhi_f_e = std::abs(pixelPhi_f_e - dPhi_nn_centre);
507 const double dEta_f_h = 1
e3*std::abs(pixelEta_f_h - dEta_nn_centre)*sensorScales[ieta];
508 const double dPhi_f_h = 1
e3*std::abs(pixelPhi_f_h - dPhi_nn_centre);
509
510
511 double ramo_f_e = 0.0;
512 double ramo_f_h = 0.0;
513
514 if (isFirstZ_e) {
515 if (dEta_f_e >= halfEtaPitch || dPhi_f_e >= halfPhiPitch) {
516 ramo_f_e = 0.0;
517 } else {
518 ramo_f_e = 1.0;
519 }
520 } else {
521 ramo_f_e = ramoPotentialMap.
getContent(ramoPotentialMap.
getBinX(1e3*dPhi_f_e), ramoPotentialMap.
getBinY(1e3*dEta_f_e), ramo_f_e_bin_z);
522 }
523
524
525 if (isOverflowZ_h) {
526 ramo_f_h = 0;
527 } else {
528 ramo_f_h = ramoPotentialMap.
getContent(ramoPotentialMap.
getBinX(dPhi_f_h), ramoPotentialMap.
getBinY(dEta_f_h), ramo_f_h_bin_z);
529 }
530
531
532
533
534 const double potentialDiff = ramo_f_e - ramo_f_h;
535
536 const double induced_charge = potentialDiff * energy_per_step * eleholePairEnergy;
537
538 unsigned key = (
static_cast<unsigned>(pixel_eta-
p) << 16) |
static_cast<unsigned>(pixel_phi-q);
539 auto cacheIterator = cachedChargeMap.find(key);
540 if(cacheIterator == cachedChargeMap.end()) {
541 cachedChargeMap.insert(std::make_pair(key, std::make_pair(Module.
hitLocalToLocal(centrePixelNN.first, centrePixelNN.second), induced_charge)));
542 } else {
543 cacheIterator->second.second += induced_charge;
544 }
545 }
546 }
547 }
548 }
549
550 std::for_each(cachedChargeMap.begin(), cachedChargeMap.end(), [&diodeCellMap, &Module, &chargedDiodes, &pHitTime, &particleLink](auto& pos_charge_pair){
551 auto& key = pos_charge_pair.first;
552 auto& chargePos = pos_charge_pair.second.first;
553 auto& charge_value = pos_charge_pair.second.second;
554
555 const SiSurfaceCharge scharge(chargePos, SiCharge(charge_value, pHitTime, SiCharge::track, particleLink));
556 auto diodeIterator = diodeCellMap.find(key);
557 if(diodeIterator == diodeCellMap.end()) diodeIterator = diodeCellMap.insert(std::make_pair(key, Module.cellIdOfPosition(scharge.position()))).first;
558 const SiCellId& thisDiode = diodeIterator->second;
559 if (thisDiode.isValid()) {
560 const SiCharge& charge = scharge.charge();
561 chargedDiodes.add(thisDiode, charge);
562 }
563 });
564
565 }
567
568
569
570
571
573
574
575 if (layerToRead > 3) {
576 layerToRead = 3;
577 }
578
582
583 for (const auto & iHitRecord : trfHitRecord) {
584 double eta_i = eta_0;
585 double phi_i = phi_0;
586 double depth_i = depth_0;
587 if (iTotalLength) {
588 eta_i += 1.0 * iHitRecord.first / iTotalLength *
dEta;
589 phi_i += 1.0 * iHitRecord.first / iTotalLength *
dPhi;
590 depth_i += 1.0 * iHitRecord.first / iTotalLength * dDepth;
591 }
592
593 const double depthZ = (depth_i + 0.5*sensorThickness)/Gaudi::Units::micrometer;
594
595 const double dist_electrode = distanceCorrectionHist.
getContent(depthZ)*Gaudi::Units::micrometer;
596
597
598 tanLorentz = lorentzCorrectionHist.
getContent(depthZ);
599 coLorentz = std::sqrt(1.0 + (tanLorentz*tanLorentz));
600
601
602 const double chargeCorrection = chargeCorrectionHist.
getContent(depthZ);
603
604
605 double nontrappingProbability = 1.0;
606 if (Module.
isDBM()) {
607 nontrappingProbability =
exp(-dist_electrode / collectionDist);
608 }
609
610 for (int j = 0; j < ncharges; j++) {
611
612 double energy_per_step = oneOverNchargesTimes1e6 * iHitRecord.second;
613
614 double rdif = diffusionConstant * std::sqrt(dist_electrode * coLorentz / 0.3);
615
616
617 double phiRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine);
618 double phi_drifted = phi_i + dist_electrode * tanLorentz + rdif * phiRand;
619 double etaRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine);
620 double eta_drifted = eta_i + rdif * etaRand;
621
622
625 }
626
627
628 const SiLocalPosition& chargePos = Module.
hitLocalToLocal(eta_drifted, phi_drifted);
629
630
631 double ed = 0;
632 if (Module.
isDBM()) {
633 ed = energy_per_step * eleholePairEnergy * nontrappingProbability * smearScale;
634 } else {
635 ed = energy_per_step * eleholePairEnergy;
636 }
637
638 ed *= chargeCorrection;
639
640
641 const SiSurfaceCharge scharge(chargePos, SiCharge(ed, pHitTime,
SiCharge::track, particleLink));
642
644
646 const SiCharge&
charge = scharge.charge();
648 }
649 }
650 }
651 } else {
652 for (const auto & iHitRecord : trfHitRecord) {
653 double eta_i = eta_0;
654 double phi_i = phi_0;
655 double depth_i = depth_0;
656 if (iTotalLength) {
657 eta_i += 1.0 * iHitRecord.first / iTotalLength *
dEta;
658 phi_i += 1.0 * iHitRecord.first / iTotalLength *
dPhi;
659 depth_i += 1.0 * iHitRecord.first / iTotalLength * dDepth;
660 }
661
662
663
664 double dist_electrode = 0.5 * sensorThickness - Module.
design().
readoutSide() * depth_i;
665 if (dist_electrode < 0) {
666 dist_electrode = 0;
667 }
668
669
670 double nontrappingProbability = 1.0;
671 if (Module.
isDBM()) {
672 nontrappingProbability =
exp(-dist_electrode / collectionDist);
673 }
674
675 for (int j = 0; j < ncharges; j++) {
676
677 double energy_per_step = oneOverNchargesTimes1e6 * iHitRecord.second;
678
679 double rdif = diffusionConstant * std::sqrt(dist_electrode * coLorentz / 0.3);
680
681
682 double phiRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine);
683 double phi_drifted = phi_i + dist_electrode * tanLorentz + rdif * phiRand;
684 double etaRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine);
685 double eta_drifted = eta_i + rdif * etaRand;
686
687
690 }
691
692
693 const SiLocalPosition& chargePos = Module.
hitLocalToLocal(eta_drifted, phi_drifted);
694
695
696 double ed = 0;
697 if (Module.
isDBM()) {
698 ed = energy_per_step * eleholePairEnergy * nontrappingProbability * smearScale;
699 } else {
700 ed = energy_per_step * eleholePairEnergy;
701 }
702
703
704 const SiSurfaceCharge scharge(chargePos, SiCharge(ed, pHitTime,
SiCharge::track, particleLink));
705
707
709 const SiCharge&
charge = scharge.charge();
711 }
712 }
713 }
714 }
715
716 return StatusCode::SUCCESS;
717}
float hitTime(const AFP_SIDSimHit &hit)
double charge(const T &p)
static HepMcParticleLink getRedirectedLink(const HepMcParticleLink &particleLink, uint32_t eventIndex, const EventContext &ctx)
Return a HepMcParticleLink pointing at the same particle, but in a different GenEvent.
double thickness() const
Method which returns thickness of the silicon wafer.
int readoutSide() const
ReadoutSide.
PixelReadoutTechnology getReadoutTechnology() const
int columns() const
Number of cell columns per module:
int rows() const
Number of cell rows per module:
SiLocalPosition positionFromColumnRow(const int column, const int row) const
Given row and column index of a diode, return position of diode center ALTERNATIVE/PREFERED way is to...
virtual bool is3D() const
double widthFromColumnRange(const int colMin, const int colMax) const
Method to calculate eta width from a column range.
int numberOfCircuits() const
Total number of circuits:
int phiIndex() const
Get phi index. Equivalent to strip().
bool isValid() const
Test if its in a valid state.
int etaIndex() const
Get eta index.
virtual const SiDetectorDesign & design() const override final
access to the local description (inline):
double phiPitch() const
Pitch (inline methods)
double xPhi() const
position along phi direction:
double xEta() const
position along eta direction:
SiCellId cellIdOfPosition(const Amg::Vector2D &localPos) const
As in previous method but returns SiCellId.
virtual IdentifierHash identifyHash() const override final
identifier hash (inline)
virtual Identifier identify() const override final
identifier of this detector element (inline)
const AtlasDetectorID * getIdHelper() const
Returns the id helper (inline)
Amg::Vector2D hitLocalToLocal(double xEta, double xPhi) const
Simulation/Hit local frame to reconstruction local frame.
double etaPitch() const
Pitch (inline methods)
double electronHolePairsPerEnergy() const
float getContent(std::size_t x) const
bool isFirstZ(const float value) const
std::size_t getBinY(Args &&...args) const
std::size_t getBinZ(Args &&...args) const
bool isOverflowZ(const float value) const
std::size_t getBinX(Args &&...args) const
int layer_disk(const Identifier &id) const
const PixelHistoConverter & getLorentzMap_e(int layer) const
double getFluenceLayer(int layer) const
const PixelHistoConverter & getRamoPotentialMap(int layer) const
const PixelHistoConverter & getDistanceMap_e(int layer) const
const PixelHistoConverter & getDistanceMap_h(int layer) const
const PixelHistoConverter & getLorentzMap_h(int layer) const
void add(const InDetDD::SiCellId &diode, const T &charge)
const HepMcParticleLink & particleLink() const
unsigned short eventId() const
the index of the component event in PileUpEventInfo.
bool dPhi(const xAOD::TauJet &tau, const xAOD::CaloVertexedTopoCluster &cluster, float &out)
bool dEta(const xAOD::TauJet &tau, const xAOD::CaloVertexedTopoCluster &cluster, float &out)
@ u
Enums for curvilinear frames.