Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
MediumCdTe.cc
Go to the documentation of this file.
1#include <iostream>
2#include <fstream>
3#include <sstream>
4#include <cmath>
5#include <algorithm>
6#include <vector>
7
8#include "MediumCdTe.hh"
9#include "Random.hh"
10#include "GarfieldConstants.hh"
12
13namespace Garfield {
14
16 : Medium(),
17 // bandGap(1.44),
18 eMobility(1.1e-6),
19 hMobility(0.1e-6),
20 eSatVel(1.02e-2),
21 hSatVel(0.72e-2),
22 eHallFactor(1.15),
23 hHallFactor(0.7),
24 eTrapCs(1.e-15),
25 hTrapCs(1.e-15),
26 eTrapDensity(1.e13),
27 hTrapDensity(1.e13),
28 eTrapTime(0.),
29 hTrapTime(0.),
30 trappingModel(0),
31 m_hasUserMobility(false),
32 m_hasUserSaturationVelocity(false),
33 m_hasOpticalData(false),
34 opticalDataFile("OpticalData_Si.txt") {
35
36 m_className = "MediumCdTe";
37 m_name = "CdTe";
38
39 SetTemperature(300.);
41 SetAtomicNumber(48.52);
42 SetAtomicWeight(240.01);
43 SetMassDensity(5.85);
44
47 m_microscopic = false;
48
49 m_w = 4.43;
50 m_fano = 0.1;
51}
52
53void MediumCdTe::GetComponent(const unsigned int& i,
54 std::string& label, double& f) {
55
56 if (i == 0) {
57 label = "Cd";
58 f = 0.5;
59 } else if (i == 1) {
60 label = "Te";
61 f = 0.5;
62 }
63}
64
65void MediumCdTe::SetTrapCrossSection(const double ecs, const double hcs) {
66
67 if (ecs < 0.) {
68 std::cerr << m_className << "::SetTrapCrossSection:\n";
69 std::cerr << " Capture cross-section [cm2] must positive.\n";
70 } else {
71 eTrapCs = ecs;
72 }
73
74 if (hcs < 0.) {
75 std::cerr << m_className << "::SetTrapCrossSection:\n";
76 std::cerr << " Capture cross-section [cm2] must be positive.n";
77 } else {
78 hTrapCs = hcs;
79 }
80
81 trappingModel = 0;
82 m_isChanged = true;
83}
84
85void MediumCdTe::SetTrapDensity(const double n) {
86
87 if (n < 0.) {
88 std::cerr << m_className << "::SetTrapDensity:\n";
89 std::cerr << " Trap density [cm-3] must be greater than zero.\n";
90 } else {
91 eTrapDensity = n;
92 hTrapDensity = n;
93 }
94
95 trappingModel = 0;
96 m_isChanged = true;
97}
98
99void MediumCdTe::SetTrappingTime(const double etau, const double htau) {
100
101 if (etau <= 0.) {
102 std::cerr << m_className << "::SetTrappingTime:\n";
103 std::cerr << " Trapping time [ns-1] must be positive.\n";
104 } else {
105 eTrapTime = etau;
106 }
107
108 if (htau <= 0.) {
109 std::cerr << m_className << "::SetTrappingTime:\n";
110 std::cerr << " Trapping time [ns-1] must be positive.\n";
111 } else {
112 hTrapTime = htau;
113 }
114
115 trappingModel = 1;
116 m_isChanged = true;
117}
118
119bool MediumCdTe::ElectronVelocity(const double ex, const double ey,
120 const double ez, const double bx,
121 const double by, const double bz, double& vx,
122 double& vy, double& vz) {
123
124 vx = vy = vz = 0.;
126 // Interpolation in user table.
127 return Medium::ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
128 }
129 // Calculate the mobility
130 double mu = eMobility;
131 mu = -mu;
132 const double b = sqrt(bx * bx + by * by + bz * bz);
133 if (b < Small) {
134 vx = mu * ex;
135 vy = mu * ey;
136 vz = mu * ez;
137 } else {
138 // Hall mobility
139 const double muH = eHallFactor * mu;
140 const double eb = bx * ex + by * ey + bz * ez;
141 const double nom = 1. + pow(muH * b, 2);
142 // Compute the drift velocity using the Langevin equation.
143 vx = mu * (ex + muH * (ey * bz - ez * by) + muH * muH * bx * eb) / nom;
144 vy = mu * (ey + muH * (ez * bx - ex * bz) + muH * muH * by * eb) / nom;
145 vz = mu * (ez + muH * (ex * by - ey * bx) + muH * muH * bz * eb) / nom;
146 }
147 return true;
148}
149
150bool MediumCdTe::ElectronTownsend(const double ex, const double ey,
151 const double ez, const double bx,
152 const double by, const double bz,
153 double& alpha) {
154
155 alpha = 0.;
157 // Interpolation in user table.
158 return Medium::ElectronTownsend(ex, ey, ez, bx, by, bz, alpha);
159 }
160 return false;
161}
162
163bool MediumCdTe::ElectronAttachment(const double ex, const double ey,
164 const double ez, const double bx,
165 const double by, const double bz,
166 double& eta) {
167
168 eta = 0.;
170 // Interpolation in user table.
171 return Medium::ElectronAttachment(ex, ey, ez, bx, by, bz, eta);
172 }
173
174 switch (trappingModel) {
175 case 0:
176 eta = eTrapCs * eTrapDensity;
177 break;
178 case 1:
179 double vx, vy, vz;
180 ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
181 eta = eTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
182 if (eta > 0.) eta = 1. / eta;
183 break;
184 default:
185 std::cerr << m_className << "::ElectronAttachment:\n";
186 std::cerr << " Unknown model activated. Program bug!\n";
187 return false;
188 break;
189 }
190
191 return true;
192}
193
194bool MediumCdTe::HoleVelocity(const double ex, const double ey, const double ez,
195 const double bx, const double by, const double bz,
196 double& vx, double& vy, double& vz) {
197
198 vx = vy = vz = 0.;
199 if (m_hasHoleVelocityE) {
200 // Interpolation in user table.
201 return Medium::HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
202 }
203 // Calculate the mobility
204 double mu = hMobility;
205 const double b = sqrt(bx * bx + by * by + bz * bz);
206 if (b < Small) {
207 vx = mu * ex;
208 vy = mu * ey;
209 vz = mu * ez;
210 } else {
211 // Hall mobility
212 const double muH = hHallFactor * mu;
213 const double eb = bx * ex + by * ey + bz * ez;
214 const double nom = 1. + pow(muH * b, 2);
215 // Compute the drift velocity using the Langevin equation.
216 vx = mu * (ex + muH * (ey * bz - ez * by) + muH * muH * bx * eb) / nom;
217 vy = mu * (ey + muH * (ez * bx - ex * bz) + muH * muH * by * eb) / nom;
218 vz = mu * (ez + muH * (ex * by - ey * bx) + muH * muH * bz * eb) / nom;
219 }
220 return true;
221}
222
223bool MediumCdTe::HoleTownsend(const double ex, const double ey, const double ez,
224 const double bx, const double by, const double bz,
225 double& alpha) {
226
227 alpha = 0.;
228 if (m_hasHoleTownsend) {
229 // Interpolation in user table.
230 return Medium::HoleTownsend(ex, ey, ez, bx, by, bz, alpha);
231 }
232 return false;
233}
234
235bool MediumCdTe::HoleAttachment(const double ex, const double ey,
236 const double ez, const double bx,
237 const double by, const double bz, double& eta) {
238
239 eta = 0.;
241 // Interpolation in user table.
242 return Medium::HoleAttachment(ex, ey, ez, bx, by, bz, eta);
243 }
244 switch (trappingModel) {
245 case 0:
246 eta = hTrapCs * hTrapDensity;
247 break;
248 case 1:
249 double vx, vy, vz;
250 HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
251 eta = hTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
252 if (eta > 0.) eta = 1. / eta;
253 break;
254 default:
255 std::cerr << m_className << "::HoleAttachment:\n";
256 std::cerr << " Unknown model activated. Program bug!\n";
257 return false;
258 break;
259 }
260 return true;
261}
262
263void MediumCdTe::SetLowFieldMobility(const double mue, const double muh) {
264
265 if (mue <= 0. || muh <= 0.) {
266 std::cerr << m_className << "::SetLowFieldMobility:\n";
267 std::cerr << " Mobility must be greater than zero.\n";
268 return;
269 }
270
271 eMobility = mue;
272 hMobility = muh;
273 m_hasUserMobility = true;
274 m_isChanged = true;
275}
276
277void MediumCdTe::SetSaturationVelocity(const double vsate, const double vsath) {
278
279 if (vsate <= 0. || vsath <= 0.) {
280 std::cout << m_className << "::SetSaturationVelocity:\n";
281 std::cout << " Restoring default values.\n";
282 m_hasUserSaturationVelocity = false;
283 } else {
284 eSatVel = vsate;
285 hSatVel = vsath;
286 m_hasUserSaturationVelocity = true;
287 }
288 m_isChanged = true;
289}
290
291bool MediumCdTe::GetOpticalDataRange(double& emin, double& emax,
292 const unsigned int& i) {
293
294 if (i != 0) {
295 std::cerr << m_className << "::GetOpticalDataRange:\n";
296 std::cerr << " Medium has only one component.\n";
297 }
298
299 // Make sure the optical data table has been loaded.
300 if (!m_hasOpticalData) {
301 if (!LoadOpticalData(opticalDataFile)) {
302 std::cerr << m_className << "::GetOpticalDataRange:\n";
303 std::cerr << " Optical data table could not be loaded.\n";
304 return false;
305 }
306 m_hasOpticalData = true;
307 }
308
309 emin = opticalDataTable[0].energy;
310 emax = opticalDataTable.back().energy;
311 if (m_debug) {
312 std::cout << m_className << "::GetOpticalDataRange:\n";
313 std::cout << " " << emin << " < E [eV] < " << emax << "\n";
314 }
315 return true;
316}
317
318bool MediumCdTe::GetDielectricFunction(const double& e, double& eps1,
319 double& eps2, const unsigned int& i) {
320
321 if (i != 0) {
322 std::cerr << m_className << "::GetDielectricFunction:\n";
323 std::cerr << " Medium has only one component.\n";
324 return false;
325 }
326
327 // Make sure the optical data table has been loaded.
328 if (!m_hasOpticalData) {
329 if (!LoadOpticalData(opticalDataFile)) {
330 std::cerr << m_className << "::GetDielectricFunction:\n";
331 std::cerr << " Optical data table could not be loaded.\n";
332 return false;
333 }
334 m_hasOpticalData = true;
335 }
336
337 // Make sure the requested energy is within the range of the table.
338 const double emin = opticalDataTable[0].energy;
339 const double emax = opticalDataTable.back().energy;
340 if (e < emin || e > emax) {
341 std::cerr << m_className << "::GetDielectricFunction:\n";
342 std::cerr << " Requested energy (" << e << " eV) "
343 << " is outside the range of the optical data table.\n";
344 std::cerr << " " << emin << " < E [eV] < " << emax << "\n";
345 eps1 = eps2 = 0.;
346 return false;
347 }
348
349 // Locate the requested energy in the table.
350 int iLow = 0;
351 int iUp = opticalDataTable.size() - 1;
352 int iM;
353 while (iUp - iLow > 1) {
354 iM = (iUp + iLow) >> 1;
355 if (e >= opticalDataTable[iM].energy) {
356 iLow = iM;
357 } else {
358 iUp = iM;
359 }
360 }
361
362 // Interpolate the real part of dielectric function.
363 // Use linear interpolation if one of the values is negative,
364 // Otherwise use log-log interpolation.
365 const double logX0 = log(opticalDataTable[iLow].energy);
366 const double logX1 = log(opticalDataTable[iUp].energy);
367 const double logX = log(e);
368 if (opticalDataTable[iLow].eps1 <= 0. || opticalDataTable[iUp].eps1 <= 0.) {
369 eps1 = opticalDataTable[iLow].eps1 +
370 (e - opticalDataTable[iLow].energy) *
371 (opticalDataTable[iUp].eps1 - opticalDataTable[iLow].eps1) /
372 (opticalDataTable[iUp].energy - opticalDataTable[iLow].energy);
373 } else {
374 const double logY0 = log(opticalDataTable[iLow].eps1);
375 const double logY1 = log(opticalDataTable[iUp].eps1);
376 eps1 = logY0 + (logX - logX0) * (logY1 - logY0) / (logX1 - logX0);
377 eps1 = exp(eps1);
378 }
379
380 // Interpolate the imaginary part of dielectric function,
381 // using log-log interpolation.
382 const double logY0 = log(opticalDataTable[iLow].eps2);
383 const double logY1 = log(opticalDataTable[iUp].eps2);
384 eps2 = logY0 + (log(e) - logX0) * (logY1 - logY0) / (logX1 - logX0);
385 eps2 = exp(eps2);
386 return true;
387}
388
389bool MediumCdTe::LoadOpticalData(const std::string filename) {
390
391 // Get the path to the data directory.
392 char* pPath = getenv("GARFIELD_HOME");
393 if (pPath == 0) {
394 std::cerr << m_className << "::LoadOpticalData:\n";
395 std::cerr << " Environment variable GARFIELD_HOME is not set.\n";
396 return false;
397 }
398 std::string filepath = pPath;
399 filepath = filepath + "/Data/" + filename;
400
401 // Open the file.
402 std::ifstream infile;
403 infile.open(filepath.c_str(), std::ios::in);
404 // Make sure the file could actually be opened.
405 if (!infile) {
406 std::cerr << m_className << "::LoadOpticalData:\n";
407 std::cerr << " Error opening file " << filename << ".\n";
408 return false;
409 }
410
411 // Clear the optical data table.
412 opticalDataTable.clear();
413
414 double lastEnergy = -1.;
415 double energy, eps1, eps2, loss;
416 opticalData data;
417 // Read the file line by line.
418 std::string line;
419 std::istringstream dataStream;
420 int i = 0;
421 while (!infile.eof()) {
422 ++i;
423 // Read the next line.
424 std::getline(infile, line);
425 // Strip white space from the beginning of the line.
426 line.erase(line.begin(),
427 std::find_if(line.begin(), line.end(),
428 not1(std::ptr_fun<int, int>(isspace))));
429 // Skip comments.
430 if (line[0] == '#' || line[0] == '*' || (line[0] == '/' && line[1] == '/'))
431 continue;
432 // Extract the values.
433 dataStream.str(line);
434 dataStream >> energy >> eps1 >> eps2 >> loss;
435 if (dataStream.eof()) break;
436 // Check if the data has been read correctly.
437 if (infile.fail()) {
438 std::cerr << m_className << "::LoadOpticalData:\n";
439 std::cerr << " Error reading file " << filename << " (line " << i
440 << ").\n";
441 return false;
442 }
443 // Reset the stringstream.
444 dataStream.str("");
445 dataStream.clear();
446 // Make sure the values make sense.
447 // The table has to be in ascending order
448 // with respect to the photon energy.
449 if (energy <= lastEnergy) {
450 std::cerr << m_className << "::LoadOpticalData:\n";
451 std::cerr << " Table is not in monotonically "
452 << "increasing order (line " << i << ").\n";
453 std::cerr << " " << lastEnergy << " " << energy << " " << eps1
454 << " " << eps2 << "\n";
455 return false;
456 }
457 // The imaginary part of the dielectric function has to be positive.
458 if (eps2 < 0.) {
459 std::cerr << m_className << "::LoadOpticalData:\n";
460 std::cerr << " Negative value of the loss function "
461 << "(line " << i << ").\n";
462 return false;
463 }
464 // Ignore negative photon energies.
465 if (energy <= 0.) continue;
466 // Add the values to the list.
467 data.energy = energy;
468 data.eps1 = eps1;
469 data.eps2 = eps2;
470 opticalDataTable.push_back(data);
471 lastEnergy = energy;
472 }
473
474 const int nEntries = opticalDataTable.size();
475 if (nEntries <= 0) {
476 std::cerr << m_className << "::LoadOpticalData:\n";
477 std::cerr << " Import of data from file " << filepath << "failed.\n";
478 std::cerr << " No valid data found.\n";
479 return false;
480 }
481
482 if (m_debug) {
483 std::cout << m_className << "::LoadOpticalData:\n";
484 std::cout << " Read " << nEntries << " values from file " << filepath
485 << "\n";
486 }
487 return true;
488}
489}
DoubleAc pow(const DoubleAc &f, double p)
Definition: DoubleAc.cpp:336
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:313
DoubleAc exp(const DoubleAc &f)
Definition: DoubleAc.cpp:376
void SetTrapDensity(const double n)
Definition: MediumCdTe.cc:85
bool HoleVelocity(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
Definition: MediumCdTe.cc:194
bool GetDielectricFunction(const double &e, double &eps1, double &eps2, const unsigned int &i=0)
Definition: MediumCdTe.cc:318
bool ElectronAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
Definition: MediumCdTe.cc:163
void GetComponent(const unsigned int &i, std::string &label, double &f)
Definition: MediumCdTe.cc:53
bool ElectronTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
Definition: MediumCdTe.cc:150
void SetSaturationVelocity(const double vsate, const double vsath)
Definition: MediumCdTe.cc:277
bool ElectronVelocity(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
Definition: MediumCdTe.cc:119
bool GetOpticalDataRange(double &emin, double &emax, const unsigned int &i=0)
Definition: MediumCdTe.cc:291
void SetTrapCrossSection(const double ecs, const double hcs)
Definition: MediumCdTe.cc:65
bool HoleTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
Definition: MediumCdTe.cc:223
bool HoleAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
Definition: MediumCdTe.cc:235
void SetLowFieldMobility(const double mue, const double muh)
Definition: MediumCdTe.cc:263
void SetTrappingTime(const double etau, const double htau)
Definition: MediumCdTe.cc:99
bool m_microscopic
Definition: Medium.hh:309
virtual void SetAtomicWeight(const double &a)
Definition: Medium.cc:178
virtual void SetMassDensity(const double &rho)
Definition: Medium.cc:200
virtual bool HoleTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
Definition: Medium.cc:1079
double m_fano
Definition: Medium.hh:313
bool m_hasElectronTownsend
Definition: Medium.hh:335
virtual bool HoleVelocity(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
Definition: Medium.cc:773
std::string m_name
Definition: Medium.hh:291
virtual void SetAtomicNumber(const double &z)
Definition: Medium.cc:167
virtual bool ElectronVelocity(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
Definition: Medium.cc:217
bool m_hasHoleTownsend
Definition: Medium.hh:350
virtual void EnableDrift()
Definition: Medium.hh:52
void SetTemperature(const double &t)
Definition: Medium.cc:117
void SetDielectricConstant(const double &eps)
Definition: Medium.cc:139
virtual bool ElectronTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
Definition: Medium.cc:542
virtual bool ElectronAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
Definition: Medium.cc:609
virtual void EnablePrimaryIonisation()
Definition: Medium.hh:54
std::string m_className
Definition: Medium.hh:284
bool m_hasHoleAttachment
Definition: Medium.hh:350
bool m_isChanged
Definition: Medium.hh:316
bool m_hasElectronVelocityE
Definition: Medium.hh:333
bool m_hasHoleVelocityE
Definition: Medium.hh:348
bool m_hasElectronAttachment
Definition: Medium.hh:335
virtual bool HoleAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
Definition: Medium.cc:1144