ATLAS Offline Software
SensorSim3DTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "SensorSim3DTool.h"
8 #include "InDetSimEvent/SiHit.h"
14 
15 #include "GaudiKernel/SystemOfUnits.h"
16 
17 #include "CLHEP/Random/RandFlat.h"
18 #include "CLHEP/Random/RandGaussZiggurat.h"
19 
20 #include "CLHEP/Units/PhysicalConstants.h"
22 
23 #include "TFile.h"
24 
25 #include <cmath>
26 #include <memory>
27 
28 using namespace InDetDD;
29 
30 //===============================================
31 // C O N S T R U C T O R
32 //===============================================
33 SensorSim3DTool::SensorSim3DTool(const std::string& type, const std::string& name, const IInterface* parent) :
35 }
36 
38 
39 //===============================================
40 // I N I T I A L I Z E
41 //===============================================
43  ATH_MSG_DEBUG("SensorSim3DTool::initialize()");
44 
46  ATH_CHECK(m_radDamageUtil.retrieve());
47 
50 
51  // read the template correction maps if template correction is used
52  if (m_radiationDamageSimulationType == RadiationDamageSimulationType::TEMPLATE_CORRECTION) {
53  ATH_MSG_INFO("Opening file: " << m_templateCorrectionRootFile << " for radiation damage correction");
54  std::unique_ptr<TFile> file(TFile::Open(PathResolverFindCalibFile(m_templateCorrectionRootFile).c_str(), "READ"));
55  if (!file) {
56  ATH_MSG_ERROR("Unable to read the ROOT file needed for radiation damage correction at: " << m_templateCorrectionRootFile);
57  return StatusCode::FAILURE;
58  }
59 
60  // we need separate corrections for the barrel and for the rings
61  constexpr std::size_t numberOfLayers = 2;
62  if (m_chargeCorrectionHistos.size() != numberOfLayers) {
63  ATH_MSG_ERROR("The size of the vector of charge correction histogram paths is " << m_chargeCorrectionHistos.size() << " instead of " << numberOfLayers);
64  return StatusCode::FAILURE;
65  }
66 
67  for (const std::string& i : m_chargeCorrectionHistos) {
68  ATH_MSG_INFO("Reading histogram: " << i << " for charge correction needed for Pixel radiation damage simulation");
69  std::unique_ptr<TH1> h(file->Get<TH1>(i.c_str()));
70  if (!h) {
71  ATH_MSG_ERROR("Cannot read histogram " << i << " needed for charge correction");
72  return StatusCode::FAILURE;
73  }
74 
75  h->SetDirectory(nullptr);
76 
77  m_chargeCorrection.emplace_back();
78  ATH_CHECK(m_chargeCorrection.back().setHisto1D(h.get()));
79  }
80 
81  file->Close();
82  }
83 
84  return StatusCode::SUCCESS;
85 }
86 
87 //===============================================
88 // F I N A L I Z E
89 //===============================================
91  ATH_MSG_DEBUG("SensorSim3DTool::finalize()");
92  return StatusCode::SUCCESS;
93 }
94 
95 //===============================================
96 // I N D U C E C H A R G E
97 //===============================================
99  SiChargedDiodeCollection& chargedDiodes,
100  const InDetDD::SiDetectorElement& Module,
101  const InDetDD::PixelModuleDesign& p_design,
102  std::vector< std::pair<double, double> >& trfHitRecord,
103  std::vector<double>& initialConditions,
104  CLHEP::HepRandomEngine* rndmEngine,
105  const EventContext &ctx) {
106 
108  if (m_digitizeITk3Das3D) {
109  if (!p_design.is3D()) {
110  return StatusCode::SUCCESS;
111  }
112 
113  // for now skip pixel luminosity rings
114  if (Module.isPLR()) {
115  return StatusCode::SUCCESS;
116  }
117  } else {
118  return StatusCode::SUCCESS;
119  }
120  } else {
121  if (!Module.isBarrel()) {
122  return StatusCode::SUCCESS;
123  }
125  return StatusCode::SUCCESS;
126  }
127  if (p_design.numberOfCircuits() > 1) {
128  return StatusCode::SUCCESS;
129  }
130  }
131 
132  ATH_MSG_DEBUG("Applying SensorSim3D charge processor");
133  if (initialConditions.size() != 8) {
134  ATH_MSG_ERROR("Starting coordinates were not filled correctly in EnergyDepositionSvc.");
135  return StatusCode::FAILURE;
136  }
137 
138  double eta_0 = initialConditions[0];
139  double phi_0 = initialConditions[1];
140  double depth_0 = initialConditions[2];
141  double dEta = initialConditions[3];
142  double dPhi = initialConditions[4];
143  double dDepth = initialConditions[5];
144  double ncharges = initialConditions[6];
145  double iTotalLength = initialConditions[7];
146  ncharges = 50;
147 
148  ATH_MSG_VERBOSE("Applying 3D sensor simulation.");
149  double sensorThickness = Module.design().thickness();
150  const InDet::SiliconProperties& siProperties = m_siPropertiesTool->getSiProperties(Module.identifyHash(), ctx);
151  double eleholePairEnergy = siProperties.electronHolePairsPerEnergy();
152 
153 
154  // Charge Collection Probability Map bin size
155  const double x_bin_size = 0.001;
156  const double y_bin_size = 0.001;
157 
158  // determine which readout is used
159  // FEI4 : 50 X 250 microns
160  double pixel_size_x = Module.width() / p_design.rows();
161  double pixel_size_y = Module.length() / p_design.columns();
162  double module_size_x = Module.width();
163  double module_size_y = Module.length();
164 
165  const HepMcParticleLink particleLink = HepMcParticleLink::getRedirectedLink(phit->particleLink(), phit.eventId(), ctx); // This link should now correctly resolve to the TruthEvent McEventCollection in the main StoreGateSvc.
166  const double pHitTime = hitTime(phit);
167 
168  const int layerIndex = Module.isBarrel() ? 0 : 1;
169 
170  if (m_radiationDamageSimulationType == RadiationDamageSimulationType::RAMO_POTENTIAL) {
171  const bool doChunkCorrection = m_doChunkCorrection.value();
172  //**************************************//
173  //*** Now diffuse charges to surface *** //
174  //**************************************//
175  //Calculate trapping times based on fluence (already includes check for fluence=0)
177  const PixelRadiationDamageFluenceMapData *fluenceData = *fluenceDataHandle;
178 
179  std::pair < double, double > trappingTimes = m_radDamageUtil->getTrappingTimes(fluenceData->getFluenceLayer3D(0)); //0 = IBL
180  m_trappingTimeElectrons = trappingTimes.first;
181  m_trappingTimeHoles = trappingTimes.second;
182 
183  const PixelHistoConverter& ramoPotentialMap = fluenceData->getRamoPotentialMap3D(0);
184  const PixelHistoConverter& eFieldMap = fluenceData->getEFieldMap3D(0);
185  const PixelHistoConverter& xPositionMap_e = fluenceData->getXPositionMap3D_e(0);
186  const PixelHistoConverter& xPositionMap_h = fluenceData->getXPositionMap3D_h(0);
187  const PixelHistoConverter& yPositionMap_e = fluenceData->getYPositionMap3D_e(0);
188  const PixelHistoConverter& yPositionMap_h = fluenceData->getYPositionMap3D_h(0);
189  const PixelHistoConverter& timeMap_e = fluenceData->getTimeMap3D_e(0);
190  const PixelHistoConverter& timeMap_h = fluenceData->getTimeMap3D_h(0);
191  const PixelHistoConverter& avgChargeMap_e = fluenceData->getAvgChargeMap3D_e();
192  const PixelHistoConverter& avgChargeMap_h = fluenceData->getAvgChargeMap3D_h();
193 
194  //Parameters which will be smeared by a random value for each charge propagated,
195  //recomputed for every trfHitRecord but initialized only once
196  std::vector<double> DtElectron (ncharges, 0.);
197  std::vector<double> DtHole (ncharges, 0.);
198  std::vector<double> rdifElectron (ncharges, 0.);
199  std::vector<double> rdifHole (ncharges, 0.);
200 
201  for (const auto & iHitRecord : trfHitRecord) {
202  double eta_i = eta_0;
203  double phi_i = phi_0;
204  double depth_i = depth_0;
205 
206  if (iTotalLength) {
207  eta_i += 1.0 * iHitRecord.first / iTotalLength * dEta;
208  phi_i += 1.0 * iHitRecord.first / iTotalLength * dPhi;
209  depth_i += 1.0 * iHitRecord.first / iTotalLength * dDepth;
210  }
211 
212  const double energy_per_step = 1.0 * iHitRecord.second / 1.E+6 / ncharges; //in MeV
213  ATH_MSG_DEBUG("es_current: " << energy_per_step << " split between " << ncharges << " charges");
214 
215  double dist_electrode = 0.5 * sensorThickness - Module.design().readoutSide() * depth_i;
216  if (dist_electrode < 0) dist_electrode = 0;
217 
218  CLHEP::Hep3Vector chargepos;
219  chargepos.setX(phi_i);
220  chargepos.setY(eta_i);
221  chargepos.setZ(dist_electrode);
222 
223  bool coord = Module.isModuleFrame();
224 
226  "ismoduleframe " << coord << " -- startPosition (x,y,z) = " << chargepos.x() << ", " << chargepos.y() << ", " <<
227  chargepos.z());
228 
229  // -- change origin of coordinates to the left bottom of module
230  double x_new = chargepos.x() + 0.5*module_size_x;
231  double y_new = chargepos.y() + 0.5*module_size_y;
232 
233  // -- change from module frame to pixel frame
234  int nPixX = int(x_new / pixel_size_x);
235  int nPixY = int(y_new / pixel_size_y);
236  ATH_MSG_DEBUG(" -- nPixX = " << nPixX << " nPixY = " << nPixY);
237 
238  //position relative to the bottom left corner of the pixel
239  double x_pix = x_new - pixel_size_x * (nPixX);
240  double y_pix = y_new - pixel_size_y * (nPixY);
241  // -- change origin of coordinates to the center of the pixel
242  double x_pix_center = x_pix - pixel_size_x / 2;
243  double y_pix_center = y_pix - pixel_size_y / 2;
244  ATH_MSG_DEBUG(" -- current hit position w.r.t. pixel corner = " << x_pix << " " << y_pix);
245  ATH_MSG_DEBUG(" -- current hit position w.r.t. pixel center = " << x_pix_center << " " << y_pix_center);
246 
247  //only process hits which are not on the electrodes (E-field zero)
248  //all the maps have 250 as the x value, so need to invert x and y whenever reading maps
249  double efield = eFieldMap.getContent(eFieldMap.getBinX(1e3*y_pix),eFieldMap.getBinY(1e3*x_pix))*1.0E-7; //return efield in MV/mm (for mobility calculation)
250 
251  if (efield == 0) {
252  ATH_MSG_DEBUG("Skipping since efield = 0 for x_pix = " << x_pix << " y_pix = " << y_pix);
253  continue;
254  }
255 
256  const double mobilityElectron = getMobility(efield, false);
257  const double mobilityHole = getMobility(efield, true);
258  auto driftTimeElectron = getDriftTime(false, ncharges, rndmEngine);
259  auto driftTimeHole = getDriftTime(true, ncharges, rndmEngine);
260  //Need to determine how many elementary charges this charge chunk represents.
261  double chunk_size = energy_per_step * eleholePairEnergy; //number of electrons/holes
262  //set minimum limit to prevent dividing into smaller subcharges than one fundamental charge
263  if (chunk_size < 1) chunk_size = 1;
264  const double kappa = 1. / std::sqrt(chunk_size);
265 
266  const double timeToElectrodeElectron = timeMap_e.getContent(timeMap_e.getBinX(1e3*y_pix), timeMap_e.getBinY(1e3*x_pix));
267  const double timeToElectrodeHole = timeMap_h.getContent(timeMap_h.getBinX(1e3*y_pix), timeMap_h.getBinY(1e3*x_pix));
268 
269  /* Diffusion via the Einstein relation
270  D = mu * kB * T / q
271  D = (mu / mm^2/MV*ns) * (T/273 K) * 0.024 microns^2 / ns */
272  const auto prefactor_e = mobilityElectron*0.024*m_temperature / 273.;
273  const auto prefactor_h = mobilityHole*0.024*m_temperature / 273.;
274  //Apply diffusion. rdif is the max. diffusion
275  for(size_t i = 0; i < ncharges; ++i) {
276  DtElectron[i] = prefactor_e * std::min(driftTimeElectron[i], timeToElectrodeElectron);
277  DtHole[i] = prefactor_h * std::min(driftTimeHole[i], timeToElectrodeHole);
278  rdifElectron[i] = 1e-3*std::sqrt(DtElectron[i]); //in mm
279  rdifHole[i] = 1e-3*std::sqrt(DtHole[i]); //in mm
280  }
281 
282  const float average_chargeElectron = avgChargeMap_e.getContent(avgChargeMap_e.getBinY(1e3*y_pix), avgChargeMap_e.getBinX(1e3*x_pix));
283  const float average_chargeHole = avgChargeMap_h.getContent(avgChargeMap_h.getBinY(1e3*y_pix), avgChargeMap_h.getBinX(1e3*x_pix));
284 
285  //We're sticking to the "old" convention here where there was a loop over -1/0/1 for both directions
286  //(x/y) to the neighbouring pixels. We call them (p)lus, (z)ero, (m)inus in either i- or j- direction
287  //hence giving us plus-in-i or pi or zero-in-j or zj etc.
288  //i is in direction of x, whereas j is into the y direction, this code is ugly, but given that we don't have very few branching conditions
289  //it's pretty fast
290 
291  //This was: ramoPotentialMap.getBinY(1000*(x_pix + pixel_size_x * 3 - i * pixel_size_x)
292  const std::size_t ramo_init_bin_y_pi = ramoPotentialMap.getBinY(1000*(x_pix + pixel_size_x * 2));
293  const std::size_t ramo_init_bin_y_zi = ramoPotentialMap.getBinY(1000*(x_pix + pixel_size_x * 3));
294  const std::size_t ramo_init_bin_y_mi = ramoPotentialMap.getBinY(1000*(x_pix + pixel_size_x * 4));
295 
296  //This was: ramoPotentialMap.getBinX(1000*(y_pix + 0.5*pixel_size_y - j * pixel_size_y)
297  const std::size_t ramo_init_bin_x_pj = ramoPotentialMap.getBinX(1000*(y_pix - 0.5*pixel_size_y));
298  const std::size_t ramo_init_bin_x_zj = ramoPotentialMap.getBinX(1000*(y_pix + 0.5*pixel_size_y));
299  const std::size_t ramo_init_bin_x_mj = ramoPotentialMap.getBinX(1000*(y_pix + 1.5*pixel_size_y));
300 
301  //For some reason the x- and y-indices for some values are swapped, this is extremely confusing
302  float ramoInit_pipj = ramoPotentialMap.getContent(ramo_init_bin_x_pj, ramo_init_bin_y_pi);
303  float ramoInit_pizj = ramoPotentialMap.getContent(ramo_init_bin_x_zj, ramo_init_bin_y_pi);
304  float ramoInit_pimj = ramoPotentialMap.getContent(ramo_init_bin_x_mj, ramo_init_bin_y_pi);
305  float ramoInit_zipj = ramoPotentialMap.getContent(ramo_init_bin_x_pj, ramo_init_bin_y_zi);
306  float ramoInit_zizj = ramoPotentialMap.getContent(ramo_init_bin_x_zj, ramo_init_bin_y_zi);
307  float ramoInit_zimj = ramoPotentialMap.getContent(ramo_init_bin_x_mj, ramo_init_bin_y_zi);
308  float ramoInit_mipj = ramoPotentialMap.getContent(ramo_init_bin_x_pj, ramo_init_bin_y_mi);
309  float ramoInit_mizj = ramoPotentialMap.getContent(ramo_init_bin_x_zj, ramo_init_bin_y_mi);
310  float ramoInit_mimj = ramoPotentialMap.getContent(ramo_init_bin_x_mj, ramo_init_bin_y_mi);
311 
312  const auto hit_time = hitTime(phit);
313 
314  //Loop over charge-carrier pairs, we're looping over electrons and holes at the same time
315  for (int j = 0; j < ncharges; j++) {
316  // In case the charge moves into a neighboring pixel
317  int extraNPixXElectron = nPixX;
318  int extraNPixYElectron = nPixY;
319  int extraNPixXHole = nPixX;
320  int extraNPixYHole = nPixY;
321 
322  //Apply drift due to diffusion
323  std::array<double, 4> randomNumbers{};
324  CLHEP::RandGaussZiggurat::shootArray(rndmEngine, 4, randomNumbers.data());
325 
326  double xposDiffElectron = x_pix + rdifElectron[j] * randomNumbers[0];
327  double yposDiffElectron = y_pix + rdifElectron[j] * randomNumbers[1];
328  double xposDiffHole = x_pix + rdifHole[j] * randomNumbers[2];
329  double yposDiffHole = y_pix + rdifHole[j] * randomNumbers[3];
330 
331  // Account for drifting into another pixel
332  while (xposDiffElectron > pixel_size_x) {
333  extraNPixXElectron++; // increments or decrements pixel count in x
334  xposDiffElectron -= pixel_size_x; // moves xpos coordinate 1 pixel over in x
335  }
336  while (xposDiffElectron < 0) {
337  extraNPixXElectron--;
338  xposDiffElectron += pixel_size_x;
339  }
340  while (yposDiffElectron > pixel_size_y) {
341  extraNPixYElectron++; // increments or decrements pixel count in y
342  yposDiffElectron -= pixel_size_y; // moves xpos coordinate 1 pixel over in y
343  }
344  while (yposDiffElectron < 0) {
345  extraNPixYElectron--;
346  yposDiffElectron += pixel_size_y;
347  }
348 
349  //And drifting for for holes
350  while (xposDiffHole > pixel_size_x) {
351  extraNPixXHole++;
352  xposDiffHole -= pixel_size_x;
353  }
354  while (xposDiffHole < 0) {
355  extraNPixXHole--;
356  xposDiffHole += pixel_size_x;
357  }
358  while (yposDiffHole > pixel_size_y) {
359  extraNPixYHole++;
360  yposDiffHole -= pixel_size_y;
361  }
362  while (yposDiffHole < 0) {
363  extraNPixYHole--;
364  yposDiffHole += pixel_size_y;
365  }
366  auto xposFinalElectron = yPositionMap_e.getContent(
367  yPositionMap_e.getBinX(1e3*yposDiffElectron),
368  yPositionMap_e.getBinY(1e3*xposDiffElectron),
369  yPositionMap_e.getBinZ(std::min(driftTimeElectron[j],timeToElectrodeElectron))
370  ) * 1e-3; //[mm]
371  auto yposFinalElectron = xPositionMap_e.getContent(
372  xPositionMap_e.getBinX(1e3*yposDiffElectron),
373  xPositionMap_e.getBinY(1e3*xposDiffElectron),
374  xPositionMap_e.getBinZ(std::min(driftTimeElectron[j],timeToElectrodeElectron))
375  ) * 1e-3; //[mm]
376 
377  auto xposFinalHole = yPositionMap_h.getContent(
378  yPositionMap_h.getBinX(1e3*yposDiffHole),
379  yPositionMap_h.getBinY(1e3*xposDiffHole),
380  yPositionMap_h.getBinZ(std::min(driftTimeHole[j],timeToElectrodeHole))
381  ) * 1e-3; //[mm]
382  auto yposFinalHole = xPositionMap_h.getContent(
383  xPositionMap_h.getBinX(1e3*yposDiffHole),
384  xPositionMap_h.getBinY(1e3*xposDiffHole),
385  xPositionMap_h.getBinZ(std::min(driftTimeHole[j],timeToElectrodeHole))
386  ) * 1e-3; //[mm]
387 
388  // -- Calculate signal in current pixel and in the neighboring ones
389  //This was: ramoPotentialMap.getBinY(1000*(xposFinal + pixel_size_x * 3 - i * pixel_size_x)
390  const std::size_t ramo_final_bin_y_pi_electrons = ramoPotentialMap.getBinY(1000*(xposFinalElectron + pixel_size_x * 2));
391  const std::size_t ramo_final_bin_y_pi_holes = ramoPotentialMap.getBinY(1000*(xposFinalHole + pixel_size_x * 2));
392  const std::size_t ramo_final_bin_y_zi_electrons = ramoPotentialMap.getBinY(1000*(xposFinalElectron + pixel_size_x * 3));
393  const std::size_t ramo_final_bin_y_zi_holes = ramoPotentialMap.getBinY(1000*(xposFinalHole + pixel_size_x * 3));
394  const std::size_t ramo_final_bin_y_mi_electrons = ramoPotentialMap.getBinY(1000*(xposFinalElectron + pixel_size_x * 4));
395  const std::size_t ramo_final_bin_y_mi_holes = ramoPotentialMap.getBinY(1000*(xposFinalHole + pixel_size_x * 4));
396  //This was: ramoPotentialMap.getBinX(1000*(yposFinal + 0.5*pixel_size_y - j * pixel_size_y)
397  const std::size_t ramo_final_bin_x_pj_electrons = ramoPotentialMap.getBinX(1000*(yposFinalElectron - 0.5*pixel_size_y));
398  const std::size_t ramo_final_bin_x_pj_holes = ramoPotentialMap.getBinX(1000*(yposFinalHole - 0.5*pixel_size_y));
399  const std::size_t ramo_final_bin_x_zj_electrons = ramoPotentialMap.getBinX(1000*(yposFinalElectron + 0.5*pixel_size_y));
400  const std::size_t ramo_final_bin_x_zj_holes = ramoPotentialMap.getBinX(1000*(yposFinalHole + 0.5*pixel_size_y));
401  const std::size_t ramo_final_bin_x_mj_electrons = ramoPotentialMap.getBinX(1000*(yposFinalElectron + 1.5*pixel_size_y));
402  const std::size_t ramo_final_bin_x_mj_holes = ramoPotentialMap.getBinX(1000*(yposFinalHole + 1.5*pixel_size_y));
403 
404  float ramoFinal_pipj_electrons = ramoPotentialMap.getContent(ramo_final_bin_x_pj_electrons, ramo_final_bin_y_pi_electrons);
405  float ramoFinal_pizj_electrons = ramoPotentialMap.getContent(ramo_final_bin_x_zj_electrons, ramo_final_bin_y_pi_electrons);
406  float ramoFinal_pimj_electrons = ramoPotentialMap.getContent(ramo_final_bin_x_mj_electrons, ramo_final_bin_y_pi_electrons);
407  float ramoFinal_zipj_electrons = ramoPotentialMap.getContent(ramo_final_bin_x_pj_electrons, ramo_final_bin_y_zi_electrons);
408  float ramoFinal_zizj_electrons = ramoPotentialMap.getContent(ramo_final_bin_x_zj_electrons, ramo_final_bin_y_zi_electrons);
409  float ramoFinal_zimj_electrons = ramoPotentialMap.getContent(ramo_final_bin_x_mj_electrons, ramo_final_bin_y_zi_electrons);
410  float ramoFinal_mipj_electrons = ramoPotentialMap.getContent(ramo_final_bin_x_pj_electrons, ramo_final_bin_y_mi_electrons);
411  float ramoFinal_mizj_electrons = ramoPotentialMap.getContent(ramo_final_bin_x_zj_electrons, ramo_final_bin_y_mi_electrons);
412  float ramoFinal_mimj_electrons = ramoPotentialMap.getContent(ramo_final_bin_x_mj_electrons, ramo_final_bin_y_mi_electrons);
413 
414  float ramoFinal_pipj_holes = ramoPotentialMap.getContent(ramo_final_bin_x_pj_holes, ramo_final_bin_y_pi_holes);
415  float ramoFinal_pizj_holes = ramoPotentialMap.getContent(ramo_final_bin_x_zj_holes, ramo_final_bin_y_pi_holes);
416  float ramoFinal_pimj_holes = ramoPotentialMap.getContent(ramo_final_bin_x_mj_holes, ramo_final_bin_y_pi_holes);
417  float ramoFinal_zipj_holes = ramoPotentialMap.getContent(ramo_final_bin_x_pj_holes, ramo_final_bin_y_zi_holes);
418  float ramoFinal_zizj_holes = ramoPotentialMap.getContent(ramo_final_bin_x_zj_holes, ramo_final_bin_y_zi_holes);
419  float ramoFinal_zimj_holes = ramoPotentialMap.getContent(ramo_final_bin_x_mj_holes, ramo_final_bin_y_zi_holes);
420  float ramoFinal_mipj_holes = ramoPotentialMap.getContent(ramo_final_bin_x_pj_holes, ramo_final_bin_y_mi_holes);
421  float ramoFinal_mizj_holes = ramoPotentialMap.getContent(ramo_final_bin_x_zj_holes, ramo_final_bin_y_mi_holes);
422  float ramoFinal_mimj_holes = ramoPotentialMap.getContent(ramo_final_bin_x_mj_holes, ramo_final_bin_y_mi_holes);
423 
424  // Record deposit
425  double eHitRamo_pipj_electrons = energy_per_step * (ramoFinal_pipj_electrons - ramoInit_pipj);
426  double eHitRamo_pipj_holes = -1. * energy_per_step * (ramoFinal_pipj_holes - ramoInit_pipj);
427  double eHitRamo_pizj_electrons = energy_per_step * (ramoFinal_pizj_electrons - ramoInit_pizj);
428  double eHitRamo_pizj_holes = -1. * energy_per_step * (ramoFinal_pizj_holes - ramoInit_pizj);
429  double eHitRamo_pimj_electrons = energy_per_step * (ramoFinal_pimj_electrons - ramoInit_pimj);
430  double eHitRamo_pimj_holes = -1. * energy_per_step * (ramoFinal_pimj_holes - ramoInit_pimj);
431  double eHitRamo_zipj_electrons = energy_per_step * (ramoFinal_zipj_electrons - ramoInit_zipj);
432  double eHitRamo_zipj_holes = -1. * energy_per_step * (ramoFinal_zipj_holes - ramoInit_zipj);
433  double eHitRamo_zizj_electrons = energy_per_step * (ramoFinal_zizj_electrons - ramoInit_zizj);
434  double eHitRamo_zizj_holes = -1. * energy_per_step * (ramoFinal_zizj_holes - ramoInit_zizj);
435  double eHitRamo_zimj_electrons = energy_per_step * (ramoFinal_zimj_electrons - ramoInit_zimj);
436  double eHitRamo_zimj_holes = -1. * energy_per_step * (ramoFinal_zimj_holes - ramoInit_zimj);
437  double eHitRamo_mipj_electrons = energy_per_step * (ramoFinal_mipj_electrons - ramoInit_mipj);
438  double eHitRamo_mipj_holes = -1. * energy_per_step * (ramoFinal_mipj_holes - ramoInit_mipj);
439  double eHitRamo_mizj_electrons = energy_per_step * (ramoFinal_mizj_electrons - ramoInit_mizj);
440  double eHitRamo_mizj_holes = -1. * energy_per_step * (ramoFinal_mizj_holes - ramoInit_mizj);
441  double eHitRamo_mimj_electrons = energy_per_step * (ramoFinal_mimj_electrons - ramoInit_mimj);
442  double eHitRamo_mimj_holes = -1. * energy_per_step * (ramoFinal_mimj_holes - ramoInit_mimj);
443 
444  if(doChunkCorrection) {
445  eHitRamo_pipj_electrons = energy_per_step * average_chargeElectron + kappa * (eHitRamo_pipj_electrons - energy_per_step * average_chargeElectron);
446  eHitRamo_pipj_holes = energy_per_step * average_chargeHole + kappa * (eHitRamo_pipj_holes - energy_per_step * average_chargeHole);
447  eHitRamo_pizj_electrons = energy_per_step * average_chargeElectron + kappa * (eHitRamo_pizj_electrons - energy_per_step * average_chargeElectron);
448  eHitRamo_pizj_holes = energy_per_step * average_chargeHole + kappa * (eHitRamo_pizj_holes - energy_per_step * average_chargeHole);
449  eHitRamo_pimj_electrons = energy_per_step * average_chargeElectron + kappa * (eHitRamo_pimj_electrons - energy_per_step * average_chargeElectron);
450  eHitRamo_pimj_holes = energy_per_step * average_chargeHole + kappa * (eHitRamo_pimj_holes - energy_per_step * average_chargeHole);
451  eHitRamo_zipj_electrons = energy_per_step * average_chargeElectron + kappa * (eHitRamo_zipj_electrons - energy_per_step * average_chargeElectron);
452  eHitRamo_zipj_holes = energy_per_step * average_chargeHole + kappa * (eHitRamo_zipj_holes - energy_per_step * average_chargeHole);
453  eHitRamo_zizj_electrons = energy_per_step * average_chargeElectron + kappa * (eHitRamo_zizj_electrons - energy_per_step * average_chargeElectron);
454  eHitRamo_zizj_holes = energy_per_step * average_chargeHole + kappa * (eHitRamo_zizj_holes - energy_per_step * average_chargeHole);
455  eHitRamo_zimj_electrons = energy_per_step * average_chargeElectron + kappa * (eHitRamo_zimj_electrons - energy_per_step * average_chargeElectron);
456  eHitRamo_pimj_holes = energy_per_step * average_chargeHole + kappa * (eHitRamo_pimj_holes - energy_per_step * average_chargeHole);
457  eHitRamo_mipj_electrons = energy_per_step * average_chargeElectron + kappa * (eHitRamo_mipj_electrons - energy_per_step * average_chargeElectron);
458  eHitRamo_mipj_holes = energy_per_step * average_chargeHole + kappa * (eHitRamo_mipj_holes - energy_per_step * average_chargeHole);
459  eHitRamo_mizj_electrons = energy_per_step * average_chargeElectron + kappa * (eHitRamo_mizj_electrons - energy_per_step * average_chargeElectron);
460  eHitRamo_mizj_holes = energy_per_step * average_chargeHole + kappa * (eHitRamo_mizj_holes - energy_per_step * average_chargeHole);
461  eHitRamo_mimj_electrons = energy_per_step * average_chargeElectron + kappa * (eHitRamo_mimj_electrons - energy_per_step * average_chargeElectron);
462  eHitRamo_mimj_holes = energy_per_step * average_chargeHole + kappa * (eHitRamo_mimj_holes - energy_per_step * average_chargeHole);
463  }
464 
465  // -- pixel coordinates --> module coordinates
466  //This was: double x_mod = x_pix + pixel_size_x * extraNPixX - 0.5*module_size_x + i*pixel_size_x;
467  //This was: double y_mod = y_pix + pixel_size_y * extraNPixY - 0.5*module_size_y + j*pixel_size_y;
468  double x_mod_pi_electrons = x_pix + pixel_size_x * extraNPixXElectron - 0.5*module_size_x + pixel_size_x;
469  double y_mod_pj_electrons = y_pix + pixel_size_y * extraNPixYElectron - 0.5*module_size_y + pixel_size_y;
470  double x_mod_pi_holes = x_pix + pixel_size_x * extraNPixXHole - 0.5*module_size_x + pixel_size_x;
471  double y_mod_pj_holes = y_pix + pixel_size_y * extraNPixYHole - 0.5*module_size_y + pixel_size_y;
472  double x_mod_zi_electrons = x_pix + pixel_size_x * extraNPixXElectron - 0.5*module_size_x;
473  double y_mod_zj_electrons = y_pix + pixel_size_y * extraNPixYElectron - 0.5*module_size_y;
474  double x_mod_zi_holes = x_pix + pixel_size_x * extraNPixXHole - 0.5*module_size_x;
475  double y_mod_zj_holes = y_pix + pixel_size_y * extraNPixYHole - 0.5*module_size_y;
476  double x_mod_mi_electrons = x_pix + pixel_size_x * extraNPixXElectron - 0.5*module_size_x - pixel_size_x;
477  double y_mod_mj_electrons = y_pix + pixel_size_y * extraNPixYElectron - 0.5*module_size_y - pixel_size_y;
478  double x_mod_mi_holes = x_pix + pixel_size_x * extraNPixXHole - 0.5*module_size_x - pixel_size_x;
479  double y_mod_mj_holes = y_pix + pixel_size_y * extraNPixYHole - 0.5*module_size_y - pixel_size_y;
480 
481  //This was: const SiLocalPosition& chargePos = Module.hitLocalToLocal(y_mod, x_mod) (for whatever reason half the maps x/y are inverted...)
482  const SiLocalPosition& chargePos_pipj_electrons = Module.hitLocalToLocal(y_mod_pj_electrons, x_mod_pi_electrons);
483  const SiLocalPosition& chargePos_pizj_electrons = Module.hitLocalToLocal(y_mod_zj_electrons, x_mod_pi_electrons);
484  const SiLocalPosition& chargePos_pimj_electrons = Module.hitLocalToLocal(y_mod_mj_electrons, x_mod_pi_electrons);
485  const SiLocalPosition& chargePos_zipj_electrons = Module.hitLocalToLocal(y_mod_pj_electrons, x_mod_zi_electrons);
486  const SiLocalPosition& chargePos_zizj_electrons = Module.hitLocalToLocal(y_mod_zj_electrons, x_mod_zi_electrons);
487  const SiLocalPosition& chargePos_zimj_electrons = Module.hitLocalToLocal(y_mod_mj_electrons, x_mod_zi_electrons);
488  const SiLocalPosition& chargePos_mipj_electrons = Module.hitLocalToLocal(y_mod_pj_electrons, x_mod_mi_electrons);
489  const SiLocalPosition& chargePos_mizj_electrons = Module.hitLocalToLocal(y_mod_zj_electrons, x_mod_mi_electrons);
490  const SiLocalPosition& chargePos_mimj_electrons = Module.hitLocalToLocal(y_mod_mj_electrons, x_mod_mi_electrons);
491 
492  const SiLocalPosition& chargePos_pipj_holes = Module.hitLocalToLocal(y_mod_pj_holes, x_mod_pi_holes);
493  const SiLocalPosition& chargePos_pizj_holes = Module.hitLocalToLocal(y_mod_zj_holes, x_mod_pi_holes);
494  const SiLocalPosition& chargePos_pimj_holes = Module.hitLocalToLocal(y_mod_mj_holes, x_mod_pi_holes);
495  const SiLocalPosition& chargePos_zipj_holes = Module.hitLocalToLocal(y_mod_pj_holes, x_mod_zi_holes);
496  const SiLocalPosition& chargePos_zizj_holes = Module.hitLocalToLocal(y_mod_zj_holes, x_mod_zi_holes);
497  const SiLocalPosition& chargePos_zimj_holes = Module.hitLocalToLocal(y_mod_mj_holes, x_mod_zi_holes);
498  const SiLocalPosition& chargePos_mipj_holes = Module.hitLocalToLocal(y_mod_pj_holes, x_mod_mi_holes);
499  const SiLocalPosition& chargePos_mizj_holes = Module.hitLocalToLocal(y_mod_zj_holes, x_mod_mi_holes);
500  const SiLocalPosition& chargePos_mimj_holes = Module.hitLocalToLocal(y_mod_mj_holes, x_mod_mi_holes);
501 
502  //This was: const SiSurfaceCharge scharge(chargePos, SiCharge(eHitRamo*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
503  const SiSurfaceCharge scharge_pipj_electrons(chargePos_pipj_electrons, SiCharge(eHitRamo_pipj_electrons*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
504  const SiSurfaceCharge scharge_pizj_electrons(chargePos_pizj_electrons, SiCharge(eHitRamo_pizj_electrons*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
505  const SiSurfaceCharge scharge_pimj_electrons(chargePos_pimj_electrons, SiCharge(eHitRamo_pimj_electrons*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
506  const SiSurfaceCharge scharge_zipj_electrons(chargePos_zipj_electrons, SiCharge(eHitRamo_zipj_electrons*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
507  const SiSurfaceCharge scharge_zizj_electrons(chargePos_zizj_electrons, SiCharge(eHitRamo_zizj_electrons*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
508  const SiSurfaceCharge scharge_zimj_electrons(chargePos_zimj_electrons, SiCharge(eHitRamo_zimj_electrons*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
509  const SiSurfaceCharge scharge_mipj_electrons(chargePos_mipj_electrons, SiCharge(eHitRamo_mipj_electrons*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
510  const SiSurfaceCharge scharge_mizj_electrons(chargePos_mizj_electrons, SiCharge(eHitRamo_mizj_electrons*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
511  const SiSurfaceCharge scharge_mimj_electrons(chargePos_mimj_electrons, SiCharge(eHitRamo_mimj_electrons*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
512 
513  const SiSurfaceCharge scharge_pipj_holes(chargePos_pipj_holes, SiCharge(eHitRamo_pipj_holes*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
514  const SiSurfaceCharge scharge_pizj_holes(chargePos_pizj_holes, SiCharge(eHitRamo_pizj_holes*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
515  const SiSurfaceCharge scharge_pimj_holes(chargePos_pimj_holes, SiCharge(eHitRamo_pimj_holes*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
516  const SiSurfaceCharge scharge_zipj_holes(chargePos_zipj_holes, SiCharge(eHitRamo_zipj_holes*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
517  const SiSurfaceCharge scharge_zizj_holes(chargePos_zizj_holes, SiCharge(eHitRamo_zizj_holes*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
518  const SiSurfaceCharge scharge_zimj_holes(chargePos_zimj_holes, SiCharge(eHitRamo_zimj_holes*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
519  const SiSurfaceCharge scharge_mipj_holes(chargePos_mipj_holes, SiCharge(eHitRamo_mipj_holes*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
520  const SiSurfaceCharge scharge_mizj_holes(chargePos_mizj_holes, SiCharge(eHitRamo_mizj_holes*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
521  const SiSurfaceCharge scharge_mimj_holes(chargePos_mimj_holes, SiCharge(eHitRamo_mimj_holes*eleholePairEnergy, hit_time, SiCharge::track, particleLink));
522 
523  auto addCharge = [&Module, &chargedDiodes](SiSurfaceCharge const & scharge) {
524  const SiCellId& diode = Module.cellIdOfPosition(scharge.position());
525  if (diode.isValid()) {
526  const SiCharge& charge = scharge.charge();
527  chargedDiodes.add(diode, charge);
528  }
529  };
530 
531  addCharge(scharge_pipj_electrons);
532  addCharge(scharge_pizj_electrons);
533  addCharge(scharge_pimj_electrons);
534  addCharge(scharge_zipj_electrons);
535  addCharge(scharge_zizj_electrons);
536  addCharge(scharge_zimj_electrons);
537  addCharge(scharge_mipj_electrons);
538  addCharge(scharge_mizj_electrons);
539  addCharge(scharge_mimj_electrons);
540  addCharge(scharge_pipj_holes);
541  addCharge(scharge_pizj_holes);
542  addCharge(scharge_pimj_holes);
543  addCharge(scharge_zipj_holes);
544  addCharge(scharge_zizj_holes);
545  addCharge(scharge_zimj_holes);
546  addCharge(scharge_mipj_holes);
547  addCharge(scharge_mizj_holes);
548  addCharge(scharge_mimj_holes);
549  }
550  }
551  } else if (m_radiationDamageSimulationType == RadiationDamageSimulationType::TEMPLATE_CORRECTION) {
552  const PixelHistoConverter& chargeCorrectionHist = m_chargeCorrection[layerIndex];
553 
554  for (const auto& iHitRecord : trfHitRecord) {
555  double eta_i = eta_0;
556  double phi_i = phi_0;
557  double depth_i = depth_0;
558 
559  if (iTotalLength) {
560  eta_i += 1.0 * iHitRecord.first / iTotalLength * dEta;
561  phi_i += 1.0 * iHitRecord.first / iTotalLength * dPhi;
562  depth_i += 1.0 * iHitRecord.first / iTotalLength * dDepth;
563  }
564 
565  double es_current = 1.0 * iHitRecord.second / 1.E+6;
566 
567  double dist_electrode = 0.5 * sensorThickness - Module.design().readoutSide() * depth_i;
568  if (dist_electrode < 0) dist_electrode = 0;
569 
570  CLHEP::Hep3Vector chargepos;
571  chargepos.setX(phi_i);
572  chargepos.setY(eta_i);
573  chargepos.setZ(dist_electrode);
574 
575  bool coord = Module.isModuleFrame();
576 
578  "ismoduleframe " << coord << " -- startPosition (x,y,z) = " << chargepos.x() << ", " << chargepos.y() << ", " <<
579  chargepos.z());
580 
581  // -- change origin of coordinates to the left bottom of module
582  const double x_new = chargepos.x() + 0.5*module_size_x;
583  const double y_new = chargepos.y() + 0.5*module_size_y;
584 
585  // -- change from module frame to pixel frame
586  const int nPixX = int(x_new / pixel_size_x);
587  const int nPixY = int(y_new / pixel_size_y);
588  ATH_MSG_DEBUG(" -- nPixX = " << nPixX << " nPixY = " << nPixY);
589  const double x_pix = x_new - pixel_size_x * (nPixX);
590  const double y_pix = y_new - pixel_size_y * (nPixY);
591  // -- change origin of coordinates to the center of the pixel
592  const double x_pix_center = x_pix - pixel_size_x / 2;
593  const double y_pix_center = y_pix - pixel_size_y / 2;
594  ATH_MSG_DEBUG(" -- current hit position w.r.t. pixel center = " << x_pix_center << " " << y_pix_center);
595 
596  // radiation damage correction
597  const double distance = std::hypot(x_pix_center, y_pix_center) / Gaudi::Units::micrometer; // to get it in micrometers
598  const double chargeCorrection = chargeCorrectionHist.getContent(distance);
599 
600  // calculate the charge at the incident sensor
601  // no neighbours are considered as that is allready included in the template correction
602  const double ed = es_current * eleholePairEnergy * chargeCorrection;
603 
604  // -- pixel coordinates --> module coordinates
605  const double x_mod = x_pix_center + 0.5*pixel_size_x + pixel_size_x * nPixX - 0.5*module_size_x;
606  const double y_mod = y_pix_center + 0.5*pixel_size_y + pixel_size_y * nPixY - 0.5*module_size_y;
607  const SiLocalPosition& chargePos = Module.hitLocalToLocal(y_mod, x_mod);
608 
609  const SiSurfaceCharge scharge(chargePos,
610  SiCharge(ed, pHitTime, SiCharge::track, particleLink));
611  const SiCellId& diode = Module.cellIdOfPosition(scharge.position());
612  if (diode.isValid()) {
613  const SiCharge& charge = scharge.charge();
614  chargedDiodes.add(diode, charge);
615  }
616  }
617  } else {
618  //**************************************//
619  //*** Now diffuse charges to surface *** //
620  //**************************************//
621  for (const auto& iHitRecord : trfHitRecord) {
622  double eta_i = eta_0;
623  double phi_i = phi_0;
624  double depth_i = depth_0;
625 
626  if (iTotalLength) {
627  eta_i += 1.0 * iHitRecord.first / iTotalLength * dEta;
628  phi_i += 1.0 * iHitRecord.first / iTotalLength * dPhi;
629  depth_i += 1.0 * iHitRecord.first / iTotalLength * dDepth;
630  }
631 
632  double es_current = 1.0 * iHitRecord.second / 1.E+6;
633 
634  double dist_electrode = 0.5 * sensorThickness - Module.design().readoutSide() * depth_i;
635  if (dist_electrode < 0) dist_electrode = 0;
636 
637  CLHEP::Hep3Vector chargepos;
638  chargepos.setX(phi_i);
639  chargepos.setY(eta_i);
640  chargepos.setZ(dist_electrode);
641 
642  bool coord = Module.isModuleFrame();
643 
645  "ismoduleframe " << coord << " -- startPosition (x,y,z) = " << chargepos.x() << ", " << chargepos.y() << ", " <<
646  chargepos.z());
647 
648  // -- change origin of coordinates to the left bottom of module
649  double x_new = chargepos.x() + 0.5*module_size_x;
650  double y_new = chargepos.y() + 0.5*module_size_y;
651 
652  // -- change from module frame to pixel frame
653  int nPixX = int(x_new / pixel_size_x);
654  int nPixY = int(y_new / pixel_size_y);
655  ATH_MSG_DEBUG(" -- nPixX = " << nPixX << " nPixY = " << nPixY);
656  double x_pix = x_new - pixel_size_x * (nPixX);
657  double y_pix = y_new - pixel_size_y * (nPixY);
658  // -- change origin of coordinates to the center of the pixel
659  double x_pix_center = x_pix - pixel_size_x / 2;
660  double y_pix_center = y_pix - pixel_size_y / 2;
661  ATH_MSG_DEBUG(" -- current hit position w.r.t. pixel center = " << x_pix_center << " " << y_pix_center);
662 
663  double x_neighbor;
664  double y_neighbor;
665  CLHEP::Hep3Vector pos_neighbor;
666  // -- Calculate signal in current pixel and in the neighboring ones
667  // -- loop in the x-coordinate
668  for (int i = -1; i <= 1; i++) {
669  x_neighbor = x_pix_center - i * pixel_size_x;
670  // -- loop in the y-coordinate
671  for (int j = -1; j <= 1; j++) {
672  y_neighbor = y_pix_center - j * pixel_size_y;
673 
674  // -- check if the neighbor falls inside the charge collection prob map window
675  if ((std::abs(x_neighbor) < pixel_size_x) && (std::abs(y_neighbor) < pixel_size_y)) {
676  // -- change origin of coordinates to the bottom left of the charge
677  // collection prob map "window", i.e. shift of 1-pixel twd bottom left
678  double x_neighbor_map = x_neighbor + pixel_size_x;
679  double y_neighbor_map = y_neighbor + pixel_size_y;
680 
681  int x_bin_cc_map = x_neighbor_map / x_bin_size;
682  int y_bin_cc_map = y_neighbor_map / y_bin_size;
683 
684  // -- retrieve the charge collection probability from Svc
685  // -- swap x and y bins to match Map coord convention
686  double ccprob_neighbor = getProbMapEntry(InDetDD::PixelReadoutTechnology::FEI4, y_bin_cc_map, x_bin_cc_map);
687  if (ccprob_neighbor == -1.) return StatusCode::FAILURE;
688 
689  double ed = es_current * eleholePairEnergy * ccprob_neighbor;
690 
691  // -- pixel coordinates --> module coordinates
692  double x_mod = x_neighbor + 0.5*pixel_size_x + pixel_size_x * nPixX - 0.5*module_size_x;
693  double y_mod = y_neighbor + 0.5*pixel_size_y + pixel_size_y * nPixY - 0.5*module_size_y;
694  const SiLocalPosition& chargePos = Module.hitLocalToLocal(y_mod, x_mod);
695 
696  const SiSurfaceCharge scharge(chargePos,
697  SiCharge(ed, pHitTime, SiCharge::track, particleLink));
698  const SiCellId& diode = Module.cellIdOfPosition(scharge.position());
699  if (diode.isValid()) {
700  const SiCharge& charge = scharge.charge();
701  chargedDiodes.add(diode, charge);
702  }
703  }
704  }
705  }
706  }
707  }
708 
709  return StatusCode::SUCCESS;
710 }
711 
712 // read the Charge Collection Prob Map from text file
713 StatusCode SensorSim3DTool::readProbMap(const std::string& fileE) {
714  std::string line;
715  const std::string& fileName = fileE;
717  if (inputFile.empty()) {
718  ATH_MSG_ERROR("Could not open input file!!!!!");
719  return StatusCode::FAILURE;
720  }
721  ATH_MSG_DEBUG("opening file " << inputFile);
722  std::ifstream myfile(inputFile.c_str());
723  if (myfile.is_open()) {
724  ATH_MSG_DEBUG(" opened file!");
725  while (myfile.good()) {
726  while (std::getline(myfile, line)) {
727  std::istringstream sline(line);
728  int xpos, ypos;
729  double prob;
730  sline >> xpos >> ypos >> prob;
731  if (fileName.find("FEI4") != std::string::npos) {
732  m_probMapFEI4.insert(std::make_pair(std::make_pair(xpos, ypos), prob));
733  ATH_MSG_DEBUG("FEI4 inside xpos " << xpos << " ypos " << ypos << " prob " << prob);
734  } else if (fileName.find("FEI3") != std::string::npos) {
735  m_probMapFEI3.insert(std::make_pair(std::make_pair(xpos, ypos), prob));
736  ATH_MSG_DEBUG("FEI3 inside xpos " << xpos << " ypos " << ypos << " prob " << prob);
737  } else {
738  ATH_MSG_ERROR("Please check name of Charge Coll Prob Maps! (should contain FEI3 or FEI4) ");
739  return StatusCode::FAILURE;
740  }
741  }
742  }
743  myfile.close();
744  }
745  return StatusCode::SUCCESS;
746 }
747 
748 // -- Print out the Charge Collection Probability map (full map)
749 StatusCode SensorSim3DTool::printProbMap(const std::string& readout) const {
750  if (readout == "FEI4") {
751  for (const auto& it : m_probMapFEI4) {
753  "read full probMap FEI4 --- bin x " << it.first.first << " bin y " << it.first.second << " prob " <<
754  it.second);
755  }
756  } else if (readout == "FEI3") {
757  for (const auto& it : m_probMapFEI3) {
759  "read full probMap FEI3 --- bin x " << it.first.first << " bin y " << it.first.second << " prob " <<
760  it.second);
761  }
762  } else {
763  ATH_MSG_ERROR("Error in printout Charge Coll Prob Maps! (readout should contain FEI3 or FEI4 strings) ");
764  return StatusCode::FAILURE;
765  }
766  return StatusCode::SUCCESS;
767 }
768 
769 // -- Returns the Charge Collection Probability at a given point (bin_x,bin_y)
770 double SensorSim3DTool::getProbMapEntry(const InDetDD::PixelReadoutTechnology &readout, int binx, int biny) const {
771  std::pair<int, int> doublekey(binx, biny);
772  double echarge;
773  if (readout == InDetDD::PixelReadoutTechnology::FEI4) {
774  std::multimap<std::pair<int, int>, double>::const_iterator iter = m_probMapFEI4.find(doublekey);
775  echarge = iter->second;
776  } else if (readout == InDetDD::PixelReadoutTechnology::FEI3) {
777  std::multimap<std::pair<int, int>, double>::const_iterator iter = m_probMapFEI3.find(doublekey);
778  echarge = iter->second;
779  } else {
780  ATH_MSG_ERROR("No Map Entry available for the requested readout");
781  echarge = -1.;
782  }
783  return echarge;
784 }
785 
786 double SensorSim3DTool::getMobility(double electricField, bool isHoleBit) {
787  //Not exactly the same as the getMobility function in RadDamageUtil, since we don't have a Hall effect for 3D sensors
788  // (B and E are parallel)
789  //Maybe good to do something about this in the future
790 
791  double vsat = 0;
792  double ecrit = 0;
793  double beta = 0;
794 
795  //These parameterizations come from C. Jacoboni et al., Solid-State Electronics 20 (1977) 77-89. (see also
796  // https://cds.cern.ch/record/684187/files/indet-2001-004.pdf).
797 
798  if (isHoleBit) {
799  vsat = 1.62 * std::pow(m_temperature, -0.52); // mm/ns
800  ecrit = 1.24E-7 * std::pow(m_temperature, 1.68); // MV/mm
801  beta = 0.46 * std::pow(m_temperature, 0.17);
802  } else {
803  vsat = 15.3 * std::pow(m_temperature, -0.87); // mm/ns
804  ecrit = 1.01E-7 * std::pow(m_temperature, 1.55); // MV/mm
805  beta = 2.57E-2 * std::pow(m_temperature, 0.66);
806  }
807 
808  double mobility = (vsat / ecrit) / std::pow(1 + std::pow((electricField / ecrit), beta), (1 / beta));
809  return mobility; // mm^2/(MV*ns)
810 }
811 
812 std::vector<double> SensorSim3DTool::getDriftTime(bool isHoleBit, size_t n,
813  CLHEP::HepRandomEngine* rndmEngine)
814 {
815  std::vector<double> rand (n, 0.);
816  std::vector<double> result (n, 0.);
817  CLHEP::RandFlat::shootArray(rndmEngine, n, rand.data(), 0., 1.);
818  for(size_t i = 0; i < n; i++) {
819  if (isHoleBit) {
820  result[i]= (-1.) * m_trappingTimeHoles * logf(rand[i]); // ns
821  } else {
822  result[i] = (-1.) * m_trappingTimeElectrons * logf(rand[i]); // ns
823  }
824  }
825  return result;
826 }
PixelID.h
This is an Identifier helper class for the Pixel subdetector. This class is a factory for creating co...
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
SensorSim3DTool::induceCharge
virtual StatusCode induceCharge(const TimedHitPtr< SiHit > &phit, SiChargedDiodeCollection &chargedDiodes, const InDetDD::SiDetectorElement &Module, const InDetDD::PixelModuleDesign &p_design, std::vector< std::pair< double, double > > &trfHitRecord, std::vector< double > &initialConditions, CLHEP::HepRandomEngine *rndmEngine, const EventContext &ctx) override
Definition: SensorSim3DTool.cxx:98
checkFileSG.line
line
Definition: checkFileSG.py:75
SiSurfaceCharge
Definition: SiSurfaceCharge.h:23
InDetDD::SolidStateDetectorElementBase::cellIdOfPosition
SiCellId cellIdOfPosition(const Amg::Vector2D &localPos) const
As in previous method but returns SiCellId.
Definition: SolidStateDetectorElementBase.cxx:224
InDetDD::PixelReadoutTechnology
PixelReadoutTechnology
Definition: PixelReadoutDefinitions.h:34
get_generator_info.result
result
Definition: get_generator_info.py:21
SensorSim3DTool::getDriftTime
std::vector< double > getDriftTime(bool isHoleBit, size_t number, CLHEP::HepRandomEngine *rndmEngine)
Definition: SensorSim3DTool.cxx:812
InDetDD::DetectorDesign::thickness
double thickness() const
Method which returns thickness of the silicon wafer.
Definition: DetectorDesign.h:271
SG::ReadCondHandle
Definition: ReadCondHandle.h:44
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
PixelHistoConverter::getBinY
std::size_t getBinY(Args &&...args) const
Definition: PixelHistoConverter.h:79
InDetDD::PixelModuleDesign
Definition: PixelModuleDesign.h:48
SensorSim3DTool::m_temperature
Gaudi::Property< double > m_temperature
Definition: SensorSim3DTool.h:105
InDetDD::PixelModuleDesign::columns
int columns() const
Number of cell columns per module:
Definition: PixelModuleDesign.h:322
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
SensorSim3DTool::m_probMapFEI3
std::multimap< std::pair< int, int >, double > m_probMapFEI3
Definition: SensorSim3DTool.h:68
SensorSimTool::m_radiationDamageSimulationType
Gaudi::Property< int > m_radiationDamageSimulationType
Definition: SensorSimTool.h:87
SiHit.h
SensorSim3DTool::finalize
virtual StatusCode finalize() override
Definition: SensorSim3DTool.cxx:90
SensorSim3DTool::readProbMap
StatusCode readProbMap(const std::string &)
Definition: SensorSim3DTool.cxx:713
SensorSim3DTool::initialize
virtual StatusCode initialize() override
Definition: SensorSim3DTool.cxx:42
conifer::pow
constexpr int pow(int x)
Definition: conifer.h:20
InDetDD::PixelModuleDesign::rows
int rows() const
Number of cell rows per module:
Definition: PixelModuleDesign.h:327
SiCharge::track
@ track
Definition: SiCharge.h:28
InDetDD::SiCellId::isValid
bool isValid() const
Test if its in a valid state.
Definition: SiCellId.h:136
skel.it
it
Definition: skel.GENtoEVGEN.py:396
SensorSim3DTool::m_cc_prob_file_fei3
Gaudi::Property< std::string > m_cc_prob_file_fei3
Definition: SensorSim3DTool.h:73
InDetDD::DetectorDesign::readoutSide
int readoutSide() const
ReadoutSide.
Definition: DetectorDesign.h:291
InDetDD::PixelReadoutTechnology::FEI3
@ FEI3
SiCharge
Definition: SiCharge.h:25
PixelRadiationDamageFluenceMapData::getTimeMap3D_e
const PixelHistoConverter & getTimeMap3D_e(int layer) const
Definition: PixelRadiationDamageFluenceMapData.cxx:65
TimedHitPtr< SiHit >
SensorSimTool::m_fluenceDataKey
SG::ReadCondHandleKey< PixelRadiationDamageFluenceMapData > m_fluenceDataKey
Definition: SensorSimTool.h:116
PixelRadiationDamageFluenceMapData::getEFieldMap3D
const PixelHistoConverter & getEFieldMap3D(int layer) const
Definition: PixelRadiationDamageFluenceMapData.cxx:60
SensorSimTool::m_chargeCorrectionHistos
Gaudi::Property< std::vector< std::string > > m_chargeCorrectionHistos
Definition: SensorSimTool.h:104
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
SensorSim3DTool::~SensorSim3DTool
virtual ~SensorSim3DTool()
covarianceTool.prob
prob
Definition: covarianceTool.py:678
SensorSim3DTool::m_probMapFEI4
std::multimap< std::pair< int, int >, double > m_probMapFEI4
Definition: SensorSim3DTool.h:67
SensorSimTool::m_siPropertiesTool
ToolHandle< ISiPropertiesTool > m_siPropertiesTool
Definition: SensorSimTool.h:77
InDetDD::SolidStateDetectorElementBase::identifyHash
virtual IdentifierHash identifyHash() const override final
identifier hash (inline)
SiSurfaceCharge::position
const InDetDD::SiLocalPosition & position() const
Definition: SiSurfaceCharge.h:75
InDetDD::PixelReadoutTechnology::RD53
@ RD53
SensorSim3DTool::m_trappingTimeElectrons
Gaudi::Property< double > m_trappingTimeElectrons
Definition: SensorSim3DTool.h:95
InDetDD::SiLocalPosition
Definition: SiLocalPosition.h:31
PixelHistoConverter::getBinZ
std::size_t getBinZ(Args &&...args) const
Definition: PixelHistoConverter.h:84
SensorSimTool::initialize
virtual StatusCode initialize()
Definition: SensorSimTool.h:54
PixelRadiationDamageFluenceMapData::getYPositionMap3D_e
const PixelHistoConverter & getYPositionMap3D_e(int layer) const
Definition: PixelRadiationDamageFluenceMapData.cxx:63
SiSurfaceCharge::charge
const SiCharge & charge() const
Definition: SiSurfaceCharge.h:80
FortranAlgorithmOptions.fileName
fileName
Definition: FortranAlgorithmOptions.py:13
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
CheckAppliedSFs.e3
e3
Definition: CheckAppliedSFs.py:264
LArG4FSStartPointFilter.rand
rand
Definition: LArG4FSStartPointFilter.py:80
SiChargedDiodeCollection
Definition: SiChargedDiodeCollection.h:109
PixelHistoConverter
Definition: PixelHistoConverter.h:25
InDetDD::SiDetectorElement::isModuleFrame
bool isModuleFrame() const
Check if the element and module frame are the same.
Definition: SiDetectorElement.cxx:212
CaloCondBlobAlgs_fillNoiseFromASCII.inputFile
string inputFile
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:17
PixelRadiationDamageFluenceMapData
Definition: PixelRadiationDamageFluenceMapData.h:25
lumiFormat.i
int i
Definition: lumiFormat.py:85
h
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
extractSporadic.h
list h
Definition: extractSporadic.py:97
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
TauGNNUtils::Variables::Track::dPhi
bool dPhi(const xAOD::TauJet &tau, const xAOD::TauTrack &track, double &out)
Definition: TauGNNUtils.cxx:538
InDetDD::PixelModuleDesign::numberOfCircuits
int numberOfCircuits() const
Total number of circuits:
Definition: PixelModuleDesign.h:297
file
TFile * file
Definition: tile_monitor.h:29
InDetDD::SolidStateDetectorElementBase::width
double width() const
Methods from design (inline)
SensorSim3DTool::SensorSim3DTool
SensorSim3DTool()
test_pyathena.parent
parent
Definition: test_pyathena.py:15
SensorSim3DTool::m_trappingTimeHoles
Gaudi::Property< double > m_trappingTimeHoles
Definition: SensorSim3DTool.h:100
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
python.SystemOfUnits.micrometer
int micrometer
Definition: SystemOfUnits.py:71
SensorSim3DTool::printProbMap
StatusCode printProbMap(const std::string &) const
Definition: SensorSim3DTool.cxx:749
InDetDD::SolidStateDetectorElementBase::hitLocalToLocal
Amg::Vector2D hitLocalToLocal(double xEta, double xPhi) const
Simulation/Hit local frame to reconstruction local frame.
Definition: SolidStateDetectorElementBase.cxx:95
min
#define min(a, b)
Definition: cfImp.cxx:40
SensorSim3DTool::m_radDamageUtil
ToolHandle< RadDamageUtil > m_radDamageUtil
Definition: SensorSim3DTool.h:110
PixelRadiationDamageFluenceMapData::getFluenceLayer3D
double getFluenceLayer3D(int layer) const
Definition: PixelRadiationDamageFluenceMapData.cxx:46
PixelRadiationDamageFluenceMapData::getXPositionMap3D_h
const PixelHistoConverter & getXPositionMap3D_h(int layer) const
Definition: PixelRadiationDamageFluenceMapData.cxx:62
SensorSim3DTool::m_chargeCorrection
std::vector< PixelHistoConverter > m_chargeCorrection
Definition: SensorSim3DTool.h:70
PathResolver.h
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
charge
double charge(const T &p)
Definition: AtlasPID.h:538
InDetDD::SiDetectorElement
Definition: SiDetectorElement.h:109
InDetDD::PixelReadoutTechnology::FEI4
@ FEI4
InDetDD::SiDetectorElement::isBarrel
bool isBarrel() const
InDet::SiliconProperties
Definition: SiliconProperties.h:24
PixelRadiationDamageFluenceMapData::getTimeMap3D_h
const PixelHistoConverter & getTimeMap3D_h(int layer) const
Definition: PixelRadiationDamageFluenceMapData.cxx:66
PixelRadiationDamageFluenceMapData::getYPositionMap3D_h
const PixelHistoConverter & getYPositionMap3D_h(int layer) const
Definition: PixelRadiationDamageFluenceMapData.cxx:64
InDetDD::PixelModuleDesign::getReadoutTechnology
PixelReadoutTechnology getReadoutTechnology() const
Definition: PixelModuleDesign.h:368
SiDetectorElement.h
JetVoronoiDiagramHelpers::coord
double coord
Definition: JetVoronoiDiagramHelpers.h:45
SiChargedDiodeCollection::add
void add(const InDetDD::SiCellId &diode, const T &charge)
Definition: SiChargedDiodeCollection.h:299
PathResolverFindCalibFile
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
Definition: PathResolver.cxx:431
InDetDD::SiCellId
Definition: SiCellId.h:29
SensorSimTool::m_digitizeITk3Das3D
Gaudi::Property< bool > m_digitizeITk3Das3D
Definition: SensorSimTool.h:122
PixelRadiationDamageFluenceMapData::getAvgChargeMap3D_h
const PixelHistoConverter & getAvgChargeMap3D_h() const
Definition: PixelRadiationDamageFluenceMapData.cxx:68
InDetDD::PixelModuleDesign::is3D
virtual bool is3D() const
Definition: PixelModuleDesign.h:363
TimedHitPtr::eventId
unsigned short eventId() const
the index of the component event in PileUpEventInfo.
Definition: TimedHitPtr.h:45
InDetDD
Message Stream Member.
Definition: FakeTrackBuilder.h:8
PixelModuleDesign.h
PixelRadiationDamageFluenceMapData::getAvgChargeMap3D_e
const PixelHistoConverter & getAvgChargeMap3D_e() const
Definition: PixelRadiationDamageFluenceMapData.cxx:67
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
SensorSim3DTool.h
InDet::SiliconProperties::electronHolePairsPerEnergy
double electronHolePairsPerEnergy() const
Definition: SiliconProperties.cxx:238
SensorSim3DTool::getMobility
double getMobility(double electricField, bool isHoleBit)
Definition: SensorSim3DTool.cxx:786
SensorSim3DTool::m_cc_prob_file_fei4
Gaudi::Property< std::string > m_cc_prob_file_fei4
Definition: SensorSim3DTool.h:79
SensorSimTool
Definition: SensorSimTool.h:38
SensorSim3DTool::m_doChunkCorrection
Gaudi::Property< bool > m_doChunkCorrection
Definition: SensorSim3DTool.h:90
hitTime
float hitTime(const AFP_SIDSimHit &hit)
Definition: AFP_SIDSimHit.h:39
InDetDD::SolidStateDetectorElementBase::length
double length() const
Length in eta direction (z - barrel, r - endcap)
SensorSimTool::m_templateCorrectionRootFile
Gaudi::Property< std::string > m_templateCorrectionRootFile
Definition: SensorSimTool.h:92
MuonParameters::beta
@ beta
Definition: MuonParamDefs.h:144
PixelHistoConverter::getBinX
std::size_t getBinX(Args &&...args) const
Definition: PixelHistoConverter.h:74
InDetDD::SiDetectorElement::design
virtual const SiDetectorDesign & design() const override final
access to the local description (inline):
TauGNNUtils::Variables::Track::dEta
bool dEta(const xAOD::TauJet &tau, const xAOD::TauTrack &track, double &out)
Definition: TauGNNUtils.cxx:527
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
PixelRadiationDamageFluenceMapData::getRamoPotentialMap3D
const PixelHistoConverter & getRamoPotentialMap3D(int layer) const
Definition: PixelRadiationDamageFluenceMapData.cxx:59
SensorSim3DTool::getProbMapEntry
double getProbMapEntry(const InDetDD::PixelReadoutTechnology &, int, int) const
Definition: SensorSim3DTool.cxx:770
InDetDD::SiDetectorElement::isPLR
bool isPLR() const
SiSurfaceCharge.h
PixelRadiationDamageFluenceMapData::getXPositionMap3D_e
const PixelHistoConverter & getXPositionMap3D_e(int layer) const
Definition: PixelRadiationDamageFluenceMapData.cxx:61
SiliconProperties.h
SiChargedDiodeCollection.h
PixelHistoConverter::getContent
float getContent(std::size_t x) const
Definition: PixelHistoConverter.h:34