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