Garfield++ v2r0
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 // m_bandGap(1.44),
18 m_eMobility(1.1e-6),
19 m_hMobility(0.1e-6),
20 m_eSatVel(1.02e-2),
21 m_hSatVel(0.72e-2),
22 m_eHallFactor(1.15),
23 m_hHallFactor(0.7),
24 m_eTrapCs(1.e-15),
25 m_hTrapCs(1.e-15),
26 m_eTrapDensity(1.e13),
27 m_hTrapDensity(1.e13),
28 m_eTrapTime(0.),
29 m_hTrapTime(0.),
30 m_trappingModel(0),
31 m_hasUserMobility(false),
32 m_hasUserSaturationVelocity(false),
33 m_opticalDataFile("OpticalData_CdTe.txt") {
34
35 m_className = "MediumCdTe";
36 m_name = "CdTe";
37
38 SetTemperature(300.);
40 SetAtomicNumber(48.52);
41 SetAtomicWeight(240.01);
42 SetMassDensity(5.85);
43
46 m_microscopic = false;
47
48 m_w = 4.43;
49 m_fano = 0.1;
50}
51
52void MediumCdTe::GetComponent(const unsigned int i,
53 std::string& label, double& f) {
54
55 if (i == 0) {
56 label = "Cd";
57 f = 0.5;
58 } else if (i == 1) {
59 label = "Te";
60 f = 0.5;
61 } else {
62 std::cerr << m_className << "::GetComponent:\n Index out of range.\n";
63 }
64}
65
66void MediumCdTe::SetTrapCrossSection(const double ecs, const double hcs) {
67
68 if (ecs < 0.) {
69 std::cerr << m_className << "::SetTrapCrossSection:\n"
70 << " Capture cross-section [cm2] must positive.\n";
71 } else {
72 m_eTrapCs = ecs;
73 }
74
75 if (hcs < 0.) {
76 std::cerr << m_className << "::SetTrapCrossSection:\n"
77 << " Capture cross-section [cm2] must be positive.n";
78 } else {
79 m_hTrapCs = hcs;
80 }
81
82 m_trappingModel = 0;
83 m_isChanged = true;
84}
85
86void MediumCdTe::SetTrapDensity(const double n) {
87
88 if (n < 0.) {
89 std::cerr << m_className << "::SetTrapDensity:\n"
90 << " Trap density [cm-3] must be greater than zero.\n";
91 } else {
92 m_eTrapDensity = n;
93 m_hTrapDensity = n;
94 }
95
96 m_trappingModel = 0;
97 m_isChanged = true;
98}
99
100void MediumCdTe::SetTrappingTime(const double etau, const double htau) {
101
102 if (etau <= 0.) {
103 std::cerr << m_className << "::SetTrappingTime:\n"
104 << " Trapping time [ns-1] must be greater than zero.\n";
105 } else {
106 m_eTrapTime = etau;
107 }
108
109 if (htau <= 0.) {
110 std::cerr << m_className << "::SetTrappingTime:\n"
111 << " Trapping time [ns-1] must be greater than zero.\n";
112 } else {
113 m_hTrapTime = htau;
114 }
115
116 m_trappingModel = 1;
117 m_isChanged = true;
118}
119
120bool MediumCdTe::ElectronVelocity(const double ex, const double ey,
121 const double ez, const double bx,
122 const double by, const double bz, double& vx,
123 double& vy, double& vz) {
124
125 vx = vy = vz = 0.;
127 // Interpolation in user table.
128 return Medium::ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
129 }
130 // Calculate the mobility
131 const double mu = -m_eMobility;
132 const double b2 = bx * bx + by * by + bz * bz;
133 if (b2 < Small) {
134 vx = mu * ex;
135 vy = mu * ey;
136 vz = mu * ez;
137 } else {
138 // Hall mobility
139 const double muH = m_eHallFactor * mu;
140 const double muH2 = muH * muH;
141 const double eb = bx * ex + by * ey + bz * ez;
142 const double nom = 1. + muH2 * b2;
143 // Compute the drift velocity using the Langevin equation.
144 vx = mu * (ex + muH * (ey * bz - ez * by) + muH2 * bx * eb) / nom;
145 vy = mu * (ey + muH * (ez * bx - ex * bz) + muH2 * by * eb) / nom;
146 vz = mu * (ez + muH * (ex * by - ey * bx) + muH2 * bz * eb) / nom;
147 }
148 return true;
149}
150
151bool MediumCdTe::ElectronTownsend(const double ex, const double ey,
152 const double ez, const double bx,
153 const double by, const double bz,
154 double& alpha) {
155
156 alpha = 0.;
157 if (!tabElectronTownsend.empty()) {
158 // Interpolation in user table.
159 return Medium::ElectronTownsend(ex, ey, ez, bx, by, bz, alpha);
160 }
161 return false;
162}
163
164bool MediumCdTe::ElectronAttachment(const double ex, const double ey,
165 const double ez, const double bx,
166 const double by, const double bz,
167 double& eta) {
168
169 eta = 0.;
171 // Interpolation in user table.
172 return Medium::ElectronAttachment(ex, ey, ez, bx, by, bz, eta);
173 }
174
175 switch (m_trappingModel) {
176 case 0:
177 eta = m_eTrapCs * m_eTrapDensity;
178 break;
179 case 1:
180 double vx, vy, vz;
181 ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
182 eta = m_eTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
183 if (eta > 0.) eta = 1. / eta;
184 break;
185 default:
186 std::cerr << m_className << "::ElectronAttachment:\n"
187 << " Unknown model activated. Program bug!\n";
188 return false;
189 break;
190 }
191
192 return true;
193}
194
195bool MediumCdTe::HoleVelocity(const double ex, const double ey, const double ez,
196 const double bx, const double by, const double bz,
197 double& vx, double& vy, double& vz) {
198
199 vx = vy = vz = 0.;
200 if (m_hasHoleVelocityE) {
201 // Interpolation in user table.
202 return Medium::HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
203 }
204 // Calculate the mobility
205 const double mu = m_hMobility;
206 const double b2 = bx * bx + by * by + bz * bz;
207 if (b2 < Small) {
208 vx = mu * ex;
209 vy = mu * ey;
210 vz = mu * ez;
211 } else {
212 // Hall mobility
213 const double muH = m_hHallFactor * mu;
214 const double muH2 = muH * muH;
215 const double eb = bx * ex + by * ey + bz * ez;
216 const double nom = 1. + muH2 * b2;
217 // Compute the drift velocity using the Langevin equation.
218 vx = mu * (ex + muH * (ey * bz - ez * by) + muH2 * bx * eb) / nom;
219 vy = mu * (ey + muH * (ez * bx - ex * bz) + muH2 * by * eb) / nom;
220 vz = mu * (ez + muH * (ex * by - ey * bx) + muH2 * bz * eb) / nom;
221 }
222 return true;
223}
224
225bool MediumCdTe::HoleTownsend(const double ex, const double ey, const double ez,
226 const double bx, const double by, const double bz,
227 double& alpha) {
228
229 alpha = 0.;
230 if (m_hasHoleTownsend) {
231 // Interpolation in user table.
232 return Medium::HoleTownsend(ex, ey, ez, bx, by, bz, alpha);
233 }
234 return false;
235}
236
237bool MediumCdTe::HoleAttachment(const double ex, const double ey,
238 const double ez, const double bx,
239 const double by, const double bz, double& eta) {
240
241 eta = 0.;
243 // Interpolation in user table.
244 return Medium::HoleAttachment(ex, ey, ez, bx, by, bz, eta);
245 }
246 switch (m_trappingModel) {
247 case 0:
248 eta = m_hTrapCs * m_hTrapDensity;
249 break;
250 case 1:
251 double vx, vy, vz;
252 HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
253 eta = m_hTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
254 if (eta > 0.) eta = 1. / eta;
255 break;
256 default:
257 std::cerr << m_className << "::HoleAttachment:\n"
258 << " Unknown model activated. Program bug!\n";
259 return false;
260 break;
261 }
262 return true;
263}
264
265void MediumCdTe::SetLowFieldMobility(const double mue, const double muh) {
266
267 if (mue <= 0. || muh <= 0.) {
268 std::cerr << m_className << "::SetLowFieldMobility:\n"
269 << " Mobility must be greater than zero.\n";
270 return;
271 }
272
273 m_eMobility = mue;
274 m_hMobility = muh;
275 m_hasUserMobility = true;
276 m_isChanged = true;
277}
278
279void MediumCdTe::SetSaturationVelocity(const double vsate, const double vsath) {
280
281 if (vsate <= 0. || vsath <= 0.) {
282 std::cout << m_className << "::SetSaturationVelocity:\n"
283 << " Restoring default values.\n";
284 m_hasUserSaturationVelocity = false;
285 } else {
286 m_eSatVel = vsate;
287 m_hSatVel = vsath;
288 m_hasUserSaturationVelocity = true;
289 }
290 m_isChanged = true;
291}
292
293bool MediumCdTe::GetOpticalDataRange(double& emin, double& emax,
294 const unsigned int i) {
295
296 if (i != 0) {
297 std::cerr << m_className << "::GetOpticalDataRange:\n"
298 << " Medium has only one component.\n";
299 }
300
301 // Make sure the optical data table has been loaded.
302 if (m_opticalDataTable.empty()) {
303 if (!LoadOpticalData(m_opticalDataFile)) {
304 std::cerr << m_className << "::GetOpticalDataRange:\n"
305 << " Optical data table could not be loaded.\n";
306 return false;
307 }
308 }
309
310 emin = m_opticalDataTable[0].energy;
311 emax = m_opticalDataTable.back().energy;
312 if (m_debug) {
313 std::cout << m_className << "::GetOpticalDataRange:\n "
314 << emin << " < E [eV] < " << emax << "\n";
315 }
316 return true;
317}
318
319bool MediumCdTe::GetDielectricFunction(const double e, double& eps1,
320 double& eps2, const unsigned int i) {
321
322 if (i != 0) {
323 std::cerr << m_className << "::GetDielectricFunction:\n"
324 << " Medium has only one component.\n";
325 return false;
326 }
327
328 // Make sure the optical data table has been loaded.
329 if (m_opticalDataTable.empty()) {
330 if (!LoadOpticalData(m_opticalDataFile)) {
331 std::cerr << m_className << "::GetDielectricFunction:\n"
332 << " Optical data table could not be loaded.\n";
333 return false;
334 }
335 }
336
337 // Make sure the requested energy is within the range of the table.
338 const double emin = m_opticalDataTable[0].energy;
339 const double emax = m_opticalDataTable.back().energy;
340 if (e < emin || e > emax) {
341 std::cerr << m_className << "::GetDielectricFunction:\n"
342 << " Requested energy (" << e << " eV)"
343 << " is outside the range of the optical data table.\n"
344 << " " << emin << " < E [eV] < " << emax << "\n";
345 eps1 = eps2 = 0.;
346 return false;
347 }
348
349 // Locate the requested energy in the table.
350 int iLo = 0;
351 int iUp = m_opticalDataTable.size() - 1;
352 int iM;
353 while (iUp - iLo > 1) {
354 iM = (iUp + iLo) >> 1;
355 if (e >= m_opticalDataTable[iM].energy) {
356 iLo = 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(m_opticalDataTable[iLo].energy);
366 const double logX1 = log(m_opticalDataTable[iUp].energy);
367 const double logX = log(e);
368 if (m_opticalDataTable[iLo].eps1 <= 0. ||
369 m_opticalDataTable[iUp].eps1 <= 0.) {
370 eps1 = m_opticalDataTable[iLo].eps1 +
371 (e - m_opticalDataTable[iLo].energy) *
372 (m_opticalDataTable[iUp].eps1 - m_opticalDataTable[iLo].eps1) /
373 (m_opticalDataTable[iUp].energy - m_opticalDataTable[iLo].energy);
374 } else {
375 const double logY0 = log(m_opticalDataTable[iLo].eps1);
376 const double logY1 = log(m_opticalDataTable[iUp].eps1);
377 eps1 = logY0 + (logX - logX0) * (logY1 - logY0) / (logX1 - logX0);
378 eps1 = exp(eps1);
379 }
380
381 // Interpolate the imaginary part of dielectric function,
382 // using log-log interpolation.
383 const double logY0 = log(m_opticalDataTable[iLo].eps2);
384 const double logY1 = log(m_opticalDataTable[iUp].eps2);
385 eps2 = logY0 + (log(e) - logX0) * (logY1 - logY0) / (logX1 - logX0);
386 eps2 = exp(eps2);
387 return true;
388}
389
390bool MediumCdTe::LoadOpticalData(const std::string& filename) {
391
392 // Get the path to the data directory.
393 char* pPath = getenv("GARFIELD_HOME");
394 if (pPath == 0) {
395 std::cerr << m_className << "::LoadOpticalData:\n"
396 << " Environment variable GARFIELD_HOME is not set.\n";
397 return false;
398 }
399 const std::string filepath = std::string(pPath) + "/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 << " Error opening file " << filename << ".\n";
408 return false;
409 }
410
411 // Clear the optical data table.
412 m_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 Error reading file "
439 << filename << " (line " << i << ").\n";
440 return false;
441 }
442 // Reset the stringstream.
443 dataStream.str("");
444 dataStream.clear();
445 // Make sure the values make sense.
446 // The table has to be in ascending order
447 // with respect to the photon energy.
448 if (energy <= lastEnergy) {
449 std::cerr << m_className << "::LoadOpticalData:\n Table is not in "
450 << "monotonically increasing order (line " << i << ").\n "
451 << lastEnergy << " " << energy << " "
452 << eps1 << " " << eps2 << "\n";
453 return false;
454 }
455 // The imaginary part of the dielectric function has to be positive.
456 if (eps2 < 0.) {
457 std::cerr << m_className << "::LoadOpticalData:\n Negative value "
458 << "of the loss function (line " << i << ").\n";
459 return false;
460 }
461 // Ignore negative photon energies.
462 if (energy <= 0.) continue;
463 // Add the values to the list.
464 data.energy = energy;
465 data.eps1 = eps1;
466 data.eps2 = eps2;
467 m_opticalDataTable.push_back(data);
468 lastEnergy = energy;
469 }
470
471 const int nEntries = m_opticalDataTable.size();
472 if (nEntries <= 0) {
473 std::cerr << m_className << "::LoadOpticalData:\n Importing data from "
474 << filepath << "failed.\n No valid data found.\n";
475 return false;
476 }
477
478 if (m_debug) {
479 std::cout << m_className << "::LoadOpticalData:\n Read " << nEntries
480 << " values from file " << filepath << "\n";
481 }
482 return true;
483}
484}
void SetTrapDensity(const double n)
Definition: MediumCdTe.cc:86
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:195
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:164
bool GetOpticalDataRange(double &emin, double &emax, const unsigned int i=0)
Definition: MediumCdTe.cc:293
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:151
void SetSaturationVelocity(const double vsate, const double vsath)
Definition: MediumCdTe.cc:279
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:120
void GetComponent(const unsigned int i, std::string &label, double &f)
Definition: MediumCdTe.cc:52
void SetTrapCrossSection(const double ecs, const double hcs)
Definition: MediumCdTe.cc:66
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:225
bool GetDielectricFunction(const double e, double &eps1, double &eps2, const unsigned int i=0)
Definition: MediumCdTe.cc:319
MediumCdTe()
Constructor.
Definition: MediumCdTe.cc:15
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:237
void SetLowFieldMobility(const double mue, const double muh)
Definition: MediumCdTe.cc:265
void SetTrappingTime(const double etau, const double htau)
Definition: MediumCdTe.cc:100
Abstract base class for media.
Definition: Medium.hh:11
void SetTemperature(const double t)
Definition: Medium.cc:104
bool m_microscopic
Definition: Medium.hh:319
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:971
double m_fano
Definition: Medium.hh:323
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:704
std::string m_name
Definition: Medium.hh:301
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:204
bool m_hasHoleTownsend
Definition: Medium.hh:358
virtual void SetAtomicNumber(const double z)
Definition: Medium.cc:154
void SetDielectricConstant(const double eps)
Definition: Medium.cc:126
virtual void EnableDrift()
Definition: Medium.hh:52
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:490
virtual void SetMassDensity(const double rho)
Definition: Medium.cc:187
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:544
virtual void EnablePrimaryIonisation()
Definition: Medium.hh:54
virtual void SetAtomicWeight(const double a)
Definition: Medium.cc:165
std::string m_className
Definition: Medium.hh:294
bool m_hasHoleAttachment
Definition: Medium.hh:358
bool m_isChanged
Definition: Medium.hh:326
bool m_hasElectronVelocityE
Definition: Medium.hh:339
std::vector< std::vector< std::vector< double > > > tabElectronTownsend
Definition: Medium.hh:348
bool m_hasHoleVelocityE
Definition: Medium.hh:356
bool m_hasElectronAttachment
Definition: Medium.hh:341
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:1023