Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
MediumSilicon.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 "MediumSilicon.hh"
9#include "Random.hh"
10#include "GarfieldConstants.hh"
12
13namespace Garfield {
14
16 : Medium(),
17 m_bandGap(1.12),
18 m_dopingType('i'),
19 m_dopingConcentration(0.),
20 mLongX(0.916),
21 mTransX(0.191),
22 mLongL(1.59),
23 mTransL(0.12),
24 alphaX(0.5),
25 alphaL(0.5),
26 eLatticeMobility(1.35e-6),
27 hLatticeMobility(0.45e-6),
28 eMobility(1.35e-6),
29 hMobility(0.45e-6),
30 eBetaCanali(1.109),
31 hBetaCanali(1.213),
32 eBetaCanaliInv(1. / 1.109),
33 hBetaCanaliInv(1. / 1.213),
34 eSatVel(1.02e-2),
35 hSatVel(0.72e-2),
36 eHallFactor(1.15),
37 hHallFactor(0.7),
38 eTrapCs(1.e-15),
39 hTrapCs(1.e-15),
40 eTrapDensity(1.e13),
41 hTrapDensity(1.e13),
42 eTrapTime(0.),
43 hTrapTime(0.),
44 trappingModel(0),
45 eImpactA0(3.318e5),
46 eImpactA1(0.703e6),
47 eImpactA2(0.),
48 eImpactB0(1.135e6),
49 eImpactB1(1.231e6),
50 eImpactB2(0.),
51 hImpactA0(1.582e6),
52 hImpactA1(0.671e6),
53 hImpactB0(2.036e6),
54 hImpactB1(1.693e6),
55 m_hasUserMobility(false),
56 m_hasUserSaturationVelocity(false),
57 latticeMobilityModel(LatticeMobilityModelSentaurus),
58 dopingMobilityModel(DopingMobilityModelMasetti),
59 saturationVelocityModel(SaturationVelocityModelCanali),
60 highFieldMobilityModel(HighFieldMobilityModelCanali),
61 impactIonisationModel(ImpactIonisationModelVanOverstraeten),
62 useCfOutput(false),
63 useNonParabolicity(true),
64 useFullBandDos(true),
65 useAnisotropy(true),
66 eFinalXL(4.),
67 eStepXL(eFinalXL / nEnergyStepsXL),
68 eFinalG(10.),
69 eStepG(eFinalG / nEnergyStepsG),
70 eFinalV(8.5),
71 eStepV(eFinalV / nEnergyStepsV),
72 nLevelsX(0),
73 nLevelsL(0),
74 nLevelsG(0),
75 nLevelsV(0),
76 nValleysX(6),
77 nValleysL(8),
78 eMinL(1.05),
79 eMinG(2.24),
80 ieMinL(0),
81 ieMinG(0),
82 m_hasOpticalData(false),
83 opticalDataFile("OpticalData_Si.txt") {
84
85 m_className = "MediumSilicon";
86 m_name = "Si";
87
88 SetTemperature(300.);
90 SetAtomicNumber(14.);
91 SetAtomicWeight(28.0855);
92 SetMassDensity(2.329);
93
96 m_microscopic = true;
97
98 m_w = 3.6;
99 m_fano = 0.11;
100
101 cfTotElectronsX.clear();
102 cfElectronsX.clear();
103 energyLossElectronsX.clear();
104 scatTypeElectronsX.clear();
105
106 cfTotElectronsL.clear();
107 cfElectronsL.clear();
108 energyLossElectronsL.clear();
109 scatTypeElectronsL.clear();
110
111 cfTotElectronsG.clear();
112 cfElectronsG.clear();
113 energyLossElectronsG.clear();
114 scatTypeElectronsG.clear();
115
116 ieMinL = int(eMinL / eStepXL) + 1;
117 ieMinG = int(eMinG / eStepG) + 1;
118
119 cfTotHoles.clear();
120 cfHoles.clear();
121 energyLossHoles.clear();
122 scatTypeHoles.clear();
123
124 // Load the density of states table.
125 InitialiseDensityOfStates();
126
127 // Initialize the collision counters.
128 nCollElectronAcoustic = nCollElectronOptical = 0;
129 nCollElectronIntervalley = 0;
130 nCollElectronImpurity = 0;
131 nCollElectronIonisation = 0;
132 nCollElectronDetailed.clear();
133 nCollElectronBand.clear();
134
135 nIonisationProducts = 0;
136 ionProducts.clear();
137}
138
139void MediumSilicon::SetDoping(const char& type, const double& c) {
140
141 if (toupper(type) == 'N') {
142 m_dopingType = 'n';
143 if (c > Small) {
144 m_dopingConcentration = c;
145 } else {
146 std::cerr << m_className << "::SetDoping:\n";
147 std::cerr << " Doping concentration must be greater than zero.\n";
148 std::cerr << " Using default value for n-type silicon "
149 << "(10^12 cm-3) instead.\n";
150 m_dopingConcentration = 1.e12;
151 }
152 } else if (toupper(type) == 'P') {
153 m_dopingType = 'p';
154 if (c > Small) {
155 m_dopingConcentration = c;
156 } else {
157 std::cerr << m_className << "::SetDoping:\n";
158 std::cerr << " Doping concentration must be greater than zero.\n";
159 std::cerr << " Using default value for p-type silicon "
160 << "(10^18 cm-3) instead.\n";
161 m_dopingConcentration = 1.e18;
162 }
163 } else if (toupper(type) == 'I') {
164 m_dopingType = 'i';
165 m_dopingConcentration = 0.;
166 } else {
167 std::cerr << m_className << "::SetDoping:\n";
168 std::cerr << " Unknown dopant type (" << type << ").\n";
169 std::cerr << " Available types are n, p and i (intrinsic).\n";
170 return;
171 }
172
173 m_isChanged = true;
174}
175
176void MediumSilicon::GetDoping(char& type, double& c) const {
177
178 type = m_dopingType;
179 c = m_dopingConcentration;
180}
181
182void MediumSilicon::SetTrapCrossSection(const double& ecs, const double& hcs) {
183
184 if (ecs < 0.) {
185 std::cerr << m_className << "::SetTrapCrossSection:\n";
186 std::cerr << " Capture cross-section [cm2] must positive.\n";
187 } else {
188 eTrapCs = ecs;
189 }
190
191 if (hcs < 0.) {
192 std::cerr << m_className << "::SetTrapCrossSection:\n";
193 std::cerr << " Capture cross-section [cm2] must be positive.n";
194 } else {
195 hTrapCs = hcs;
196 }
197
198 trappingModel = 0;
199 m_isChanged = true;
200}
201
202void MediumSilicon::SetTrapDensity(const double& n) {
203
204 if (n < 0.) {
205 std::cerr << m_className << "::SetTrapDensity:\n";
206 std::cerr << " Trap density [cm-3] must be greater than zero.\n";
207 } else {
208 eTrapDensity = n;
209 hTrapDensity = n;
210 }
211
212 trappingModel = 0;
213 m_isChanged = true;
214}
215
216void MediumSilicon::SetTrappingTime(const double& etau, const double& htau) {
217
218 if (etau <= 0.) {
219 std::cerr << m_className << "::SetTrappingTime:\n";
220 std::cerr << " Trapping time [ns-1] must be positive.\n";
221 } else {
222 eTrapTime = etau;
223 }
224
225 if (htau <= 0.) {
226 std::cerr << m_className << "::SetTrappingTime:\n";
227 std::cerr << " Trapping time [ns-1] must be positive.\n";
228 } else {
229 hTrapTime = htau;
230 }
231
232 trappingModel = 1;
233 m_isChanged = true;
234}
235
236bool MediumSilicon::ElectronVelocity(const double ex, const double ey,
237 const double ez, const double bx,
238 const double by, const double bz,
239 double& vx, double& vy, double& vz) {
240
241 vx = vy = vz = 0.;
242 if (m_isChanged) {
243 if (!UpdateTransportParameters()) {
244 std::cerr << m_className << "::ElectronVelocity:\n";
245 std::cerr << " Error calculating the transport parameters.\n";
246 return false;
247 }
248 m_isChanged = false;
249 }
250
252 // Interpolation in user table.
253 return Medium::ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
254 }
255
256 const double e = sqrt(ex * ex + ey * ey + ez * ez);
257
258 // Calculate the mobility
259 double mu;
260 switch (highFieldMobilityModel) {
261 case HighFieldMobilityModelMinimos:
262 ElectronMobilityMinimos(e, mu);
263 break;
264 case HighFieldMobilityModelCanali:
265 ElectronMobilityCanali(e, mu);
266 break;
267 case HighFieldMobilityModelReggiani:
268 ElectronMobilityReggiani(e, mu);
269 break;
270 default:
271 mu = eMobility;
272 break;
273 }
274 mu = -mu;
275
276 const double b = sqrt(bx * bx + by * by + bz * bz);
277 if (b < Small) {
278 vx = mu * ex;
279 vy = mu * ey;
280 vz = mu * ez;
281 } else {
282 // Hall mobility
283 const double muH = eHallFactor * mu;
284 const double eb = bx * ex + by * ey + bz * ez;
285 const double nom = 1. + pow(muH * b, 2);
286 // Compute the drift velocity using the Langevin equation.
287 vx = mu * (ex + muH * (ey * bz - ez * by) + muH * muH * bx * eb) / nom;
288 vy = mu * (ey + muH * (ez * bx - ex * bz) + muH * muH * by * eb) / nom;
289 vz = mu * (ez + muH * (ex * by - ey * bx) + muH * muH * bz * eb) / nom;
290 }
291 return true;
292}
293
294bool MediumSilicon::ElectronTownsend(const double ex, const double ey,
295 const double ez, const double bx,
296 const double by, const double bz,
297 double& alpha) {
298
299 alpha = 0.;
300 if (m_isChanged) {
301 if (!UpdateTransportParameters()) {
302 std::cerr << m_className << "::ElectronTownsend:\n";
303 std::cerr << " Error calculating the transport parameters.\n";
304 return false;
305 }
306 m_isChanged = false;
307 }
308
310 // Interpolation in user table.
311 return Medium::ElectronTownsend(ex, ey, ez, bx, by, bz, alpha);
312 }
313
314 const double e = sqrt(ex * ex + ey * ey + ez * ez);
315
316 switch (impactIonisationModel) {
317 case ImpactIonisationModelVanOverstraeten:
318 return ElectronImpactIonisationVanOverstraetenDeMan(e, alpha);
319 break;
320 case ImpactIonisationModelGrant:
321 return ElectronImpactIonisationGrant(e, alpha);
322 break;
323 default:
324 std::cerr << m_className << "::ElectronTownsend:\n";
325 std::cerr << " Unknown model activated. Program bug!\n";
326 break;
327 }
328 return false;
329}
330
331bool MediumSilicon::ElectronAttachment(const double ex, const double ey,
332 const double ez, const double bx,
333 const double by, const double bz,
334 double& eta) {
335
336 eta = 0.;
337 if (m_isChanged) {
338 if (!UpdateTransportParameters()) {
339 std::cerr << m_className << "::ElectronAttachment:\n";
340 std::cerr << " Error calculating the transport parameters.\n";
341 return false;
342 }
343 m_isChanged = false;
344 }
345
347 // Interpolation in user table.
348 return Medium::ElectronAttachment(ex, ey, ez, bx, by, bz, eta);
349 }
350
351 switch (trappingModel) {
352 case 0:
353 eta = eTrapCs * eTrapDensity;
354 break;
355 case 1:
356 double vx, vy, vz;
357 ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
358 eta = eTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
359 if (eta > 0.) eta = 1. / eta;
360 break;
361 default:
362 std::cerr << m_className << "::ElectronAttachment:\n";
363 std::cerr << " Unknown model activated. Program bug!\n";
364 return false;
365 break;
366 }
367
368 return true;
369}
370
371bool MediumSilicon::HoleVelocity(const double ex, const double ey,
372 const double ez, const double bx,
373 const double by, const double bz, double& vx,
374 double& vy, double& vz) {
375
376 vx = vy = vz = 0.;
377 if (m_isChanged) {
378 if (!UpdateTransportParameters()) {
379 std::cerr << m_className << "::HoleVelocity:\n";
380 std::cerr << " Error calculating the transport parameters.\n";
381 return false;
382 }
383 m_isChanged = false;
384 }
385
386 if (m_hasHoleVelocityE) {
387 // Interpolation in user table.
388 return Medium::HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
389 }
390
391 const double e = sqrt(ex * ex + ey * ey + ez * ez);
392
393 // Calculate the mobility
394 double mu;
395 switch (highFieldMobilityModel) {
396 case HighFieldMobilityModelMinimos:
397 HoleMobilityMinimos(e, mu);
398 break;
399 case HighFieldMobilityModelCanali:
400 HoleMobilityCanali(e, mu);
401 break;
402 case HighFieldMobilityModelReggiani:
403 HoleMobilityReggiani(e, mu);
404 break;
405 default:
406 mu = hMobility;
407 }
408
409 const double b = sqrt(bx * bx + by * by + bz * bz);
410 if (b < Small) {
411 vx = mu * ex;
412 vy = mu * ey;
413 vz = mu * ez;
414 } else {
415 // Hall mobility
416 const double muH = hHallFactor * mu;
417 const double eb = bx * ex + by * ey + bz * ez;
418 const double nom = 1. + pow(muH * b, 2);
419 // Compute the drift velocity using the Langevin equation.
420 vx = mu * (ex + muH * (ey * bz - ez * by) + muH * muH * bx * eb) / nom;
421 vy = mu * (ey + muH * (ez * bx - ex * bz) + muH * muH * by * eb) / nom;
422 vz = mu * (ez + muH * (ex * by - ey * bx) + muH * muH * bz * eb) / nom;
423 }
424 return true;
425}
426
427bool MediumSilicon::HoleTownsend(const double ex, const double ey,
428 const double ez, const double bx,
429 const double by, const double bz,
430 double& alpha) {
431
432 alpha = 0.;
433 if (m_isChanged) {
434 if (!UpdateTransportParameters()) {
435 std::cerr << m_className << "::HoleTownsend:\n";
436 std::cerr << " Error calculating the transport parameters.\n";
437 return false;
438 }
439 m_isChanged = false;
440 }
441
442 if (m_hasHoleTownsend) {
443 // Interpolation in user table.
444 return Medium::HoleTownsend(ex, ey, ez, bx, by, bz, alpha);
445 }
446
447 const double e = sqrt(ex * ex + ey * ey + ez * ez);
448
449 switch (impactIonisationModel) {
450 case ImpactIonisationModelVanOverstraeten:
451 return HoleImpactIonisationVanOverstraetenDeMan(e, alpha);
452 break;
453 case ImpactIonisationModelGrant:
454 return HoleImpactIonisationGrant(e, alpha);
455 break;
456 default:
457 std::cerr << m_className << "::HoleTownsend:\n";
458 std::cerr << " Unknown model activated. Program bug!\n";
459 break;
460 }
461 return false;
462}
463
464bool MediumSilicon::HoleAttachment(const double ex, const double ey,
465 const double ez, const double bx,
466 const double by, const double bz,
467 double& eta) {
468
469 eta = 0.;
470 if (m_isChanged) {
471 if (!UpdateTransportParameters()) {
472 std::cerr << m_className << "::HoleAttachment:\n";
473 std::cerr << " Error calculating the transport parameters.\n";
474 return false;
475 }
476 m_isChanged = false;
477 }
478
480 // Interpolation in user table.
481 return Medium::HoleAttachment(ex, ey, ez, bx, by, bz, eta);
482 }
483
484 switch (trappingModel) {
485 case 0:
486 eta = hTrapCs * hTrapDensity;
487 break;
488 case 1:
489 double vx, vy, vz;
490 HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
491 eta = hTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
492 if (eta > 0.) eta = 1. / eta;
493 break;
494 default:
495 std::cerr << m_className << "::HoleAttachment:\n";
496 std::cerr << " Unknown model activated. Program bug!\n";
497 return false;
498 break;
499 }
500
501 return true;
502}
503
504void MediumSilicon::SetLowFieldMobility(const double mue, const double muh) {
505
506 if (mue <= 0. || muh <= 0.) {
507 std::cerr << m_className << "::SetLowFieldMobility:\n";
508 std::cerr << " Mobility must be greater than zero.\n";
509 return;
510 }
511
512 eMobility = mue;
513 hMobility = muh;
514 m_hasUserMobility = true;
515 m_isChanged = true;
516}
517
519
520 latticeMobilityModel = LatticeMobilityModelMinimos;
521 m_hasUserMobility = false;
522 m_isChanged = true;
523}
524
526
527 latticeMobilityModel = LatticeMobilityModelSentaurus;
528 m_hasUserMobility = false;
529 m_isChanged = true;
530}
531
533
534 latticeMobilityModel = LatticeMobilityModelReggiani;
535 m_hasUserMobility = false;
536 m_isChanged = true;
537}
538
540
541 dopingMobilityModel = DopingMobilityModelMinimos;
542 m_hasUserMobility = false;
543 m_isChanged = true;
544}
545
547
548 dopingMobilityModel = DopingMobilityModelMasetti;
549 m_hasUserMobility = false;
550 m_isChanged = true;
551}
552
554 const double vsath) {
555
556 if (vsate <= 0. || vsath <= 0.) {
557 std::cout << m_className << "::SetSaturationVelocity:\n";
558 std::cout << " Restoring default values.\n";
559 m_hasUserSaturationVelocity = false;
560 } else {
561 eSatVel = vsate;
562 hSatVel = vsath;
563 m_hasUserSaturationVelocity = true;
564 }
565
566 m_isChanged = true;
567}
568
570
571 saturationVelocityModel = SaturationVelocityModelMinimos;
572 m_hasUserSaturationVelocity = false;
573 m_isChanged = true;
574}
575
577
578 saturationVelocityModel = SaturationVelocityModelCanali;
579 m_hasUserSaturationVelocity = false;
580 m_isChanged = true;
581}
582
584
585 saturationVelocityModel = SaturationVelocityModelReggiani;
586 m_hasUserSaturationVelocity = false;
587 m_isChanged = true;
588}
589
591
592 highFieldMobilityModel = HighFieldMobilityModelMinimos;
593 m_isChanged = true;
594}
595
597
598 highFieldMobilityModel = HighFieldMobilityModelCanali;
599 m_isChanged = true;
600}
601
603
604 highFieldMobilityModel = HighFieldMobilityModelReggiani;
605 m_isChanged = true;
606}
607
609
610 highFieldMobilityModel = HighFieldMobilityModelConstant;
611}
612
614
615 impactIonisationModel = ImpactIonisationModelVanOverstraeten;
616 m_isChanged = true;
617}
618
620
621 impactIonisationModel = ImpactIonisationModelGrant;
622 m_isChanged = true;
623}
624
626
627 if (e <= eMinG + Small) {
628 std::cerr << m_className << "::SetMaxElectronEnergy:\n";
629 std::cerr << " Provided upper electron energy limit (" << e
630 << " eV) is too small.\n";
631 return false;
632 }
633
634 eFinalG = e;
635 // Determine the energy interval size.
636 eStepG = eFinalG / nEnergyStepsG;
637
638 m_isChanged = true;
639
640 return true;
641}
642
643double MediumSilicon::GetElectronEnergy(const double px, const double py,
644 const double pz, double& vx, double& vy,
645 double& vz, const int band) {
646
647 // Effective masses
648 double mx = ElectronMass, my = ElectronMass, mz = ElectronMass;
649 // Energy offset
650 double e0 = 0.;
651 if (band >= 0 && band < nValleysX) {
652 // X valley
653 if (useAnisotropy) {
654 switch (band) {
655 case 0:
656 case 1:
657 // X 100, -100
658 mx *= mLongX;
659 my *= mTransX;
660 mz *= mTransX;
661 break;
662 case 2:
663 case 3:
664 // X 010, 0-10
665 mx *= mTransX;
666 my *= mLongX;
667 mz *= mTransX;
668 break;
669 case 4:
670 case 5:
671 // X 001, 00-1
672 mx *= mTransX;
673 my *= mTransX;
674 mz *= mLongX;
675 break;
676 default:
677 std::cerr << m_className << "::GetElectronEnergy:\n";
678 std::cerr << " Unexpected band index " << band << "!\n";
679 break;
680 }
681 } else {
682 // Conduction effective mass
683 const double mc = 3. / (1. / mLongX + 2. / mTransX);
684 mx *= mc;
685 my *= mc;
686 mz *= mc;
687 }
688 } else if (band < nValleysX + nValleysL) {
689 // L valley, isotropic approximation
690 e0 = eMinL;
691 // Effective mass
692 const double mc = 3. / (1. / mLongL + 2. / mTransL);
693 mx *= mc;
694 my *= mc;
695 mz *= mc;
696 } else if (band == nValleysX + nValleysL) {
697 // Higher band(s)
698 }
699
700 if (useNonParabolicity) {
701 // Non-parabolicity parameter
702 double alpha = 0.;
703 if (band < nValleysX) {
704 // X valley
705 alpha = alphaX;
706 } else if (band < nValleysX + nValleysL) {
707 // L valley
708 alpha = alphaL;
709 }
710
711 const double p2 = 0.5 * (px * px / mx + py * py / my + pz * pz / mz);
712 if (alpha > 0.) {
713 const double e = 0.5 * (sqrt(1. + 4 * alpha * p2) - 1.) / alpha;
714 const double a = SpeedOfLight / (1. + 2 * alpha * e);
715 vx = a * px / mx;
716 vy = a * py / my;
717 vz = a * pz / mz;
718 return e0 + e;
719 }
720 }
721
722 const double e = 0.5 * (px * px / mx + py * py / my + pz * pz / mz);
723 vx = SpeedOfLight * px / mx;
724 vy = SpeedOfLight * py / my;
725 vz = SpeedOfLight * pz / mz;
726 return e0 + e;
727}
728
729void MediumSilicon::GetElectronMomentum(const double e, double& px, double& py,
730 double& pz, int& band) {
731
732 int nBands = nValleysX;
733 if (e > eMinL) nBands += nValleysL;
734 if (e > eMinG) ++nBands;
735
736 // If the band index is out of range, choose one at random.
737 if (band < 0 || band > nValleysX + nValleysL ||
738 (e < eMinL || band >= nValleysX) ||
739 (e < eMinG || band == nValleysX + nValleysL)) {
740 if (e < eMinL) {
741 band = int(nValleysX * RndmUniform());
742 if (band >= nValleysX) band = nValleysX - 1;
743 } else {
744 const double dosX = GetConductionBandDensityOfStates(e, 0);
745 const double dosL = GetConductionBandDensityOfStates(e, nValleysX);
746 const double dosG =
747 GetConductionBandDensityOfStates(e, nValleysX + nValleysL);
748 const double dosSum = nValleysX * dosX + nValleysL * dosL + dosG;
749 if (dosSum < Small) {
750 band = nValleysX + nValleysL;
751 } else {
752 const double r = RndmUniform() * dosSum;
753 if (r < dosX) {
754 band = int(nValleysX * RndmUniform());
755 if (band >= nValleysX) band = nValleysX - 1;
756 } else if (r < dosX + dosL) {
757 band = nValleysX + int(nValleysL * RndmUniform());
758 if (band >= nValleysX + nValleysL) band = nValleysL - 1;
759 } else {
760 band = nValleysX + nValleysL;
761 }
762 }
763 }
764 if (m_debug) {
765 std::cout << m_className << "::GetElectronMomentum:\n";
766 std::cout << " Randomised band index: " << band << "\n";
767 }
768 }
769 if (band < nValleysX) {
770 // X valleys
771 double pstar = sqrt(2. * ElectronMass * e);
772 if (useNonParabolicity) {
773 const double alpha = alphaX;
774 pstar *= sqrt(1. + alpha * e);
775 }
776
777 const double ctheta = 1. - 2. * RndmUniform();
778 const double stheta = sqrt(1. - ctheta * ctheta);
779 const double phi = TwoPi * RndmUniform();
780
781 if (useAnisotropy) {
782 const double pl = pstar * sqrt(mLongX);
783 const double pt = pstar * sqrt(mTransX);
784 switch (band) {
785 case 0:
786 case 1:
787 // 100
788 px = pl * ctheta;
789 py = pt * cos(phi) * stheta;
790 pz = pt * sin(phi) * stheta;
791 break;
792 case 2:
793 case 3:
794 // 010
795 px = pt * sin(phi) * stheta;
796 py = pl * ctheta;
797 pz = pt * cos(phi) * stheta;
798 break;
799 case 4:
800 case 5:
801 // 001
802 px = pt * cos(phi) * stheta;
803 py = pt * sin(phi) * stheta;
804 pz = pl * ctheta;
805 break;
806 default:
807 // Other band; should not occur.
808 std::cerr << m_className << "::GetElectronMomentum:\n";
809 std::cerr << " Unexpected band index (" << band << ").\n";
810 px = pstar * stheta * cos(phi);
811 py = pstar * stheta * sin(phi);
812 pz = pstar * ctheta;
813 break;
814 }
815 } else {
816 pstar *= sqrt(3. / (1. / mLongX + 2. / mTransX));
817 px = pstar * cos(phi) * stheta;
818 py = pstar * sin(phi) * stheta;
819 pz = pstar * ctheta;
820 }
821 } else if (band < nValleysX + nValleysL) {
822 // L valleys
823 double pstar = sqrt(2. * ElectronMass * (e - eMinL));
824 if (useNonParabolicity) {
825 const double alpha = alphaL;
826 pstar *= sqrt(1. + alpha * (e - eMinL));
827 }
828 pstar *= sqrt(3. / (1. / mLongL + 2. / mTransL));
829
830 const double ctheta = 1. - 2. * RndmUniform();
831 const double stheta = sqrt(1. - ctheta * ctheta);
832 const double phi = TwoPi * RndmUniform();
833
834 px = pstar * cos(phi) * stheta;
835 py = pstar * sin(phi) * stheta;
836 pz = pstar * ctheta;
837 } else if (band == nValleysX + nValleysL) {
838 // Higher band
839 double pstar = sqrt(2. * ElectronMass * e);
840
841 const double ctheta = 1. - 2. * RndmUniform();
842 const double stheta = sqrt(1. - ctheta * ctheta);
843 const double phi = TwoPi * RndmUniform();
844
845 px = pstar * cos(phi) * stheta;
846 py = pstar * sin(phi) * stheta;
847 pz = pstar * ctheta;
848 }
849}
850
852
853 if (m_isChanged) {
854 if (!UpdateTransportParameters()) {
855 std::cerr << m_className << "::GetElectronNullCollisionRate:\n";
856 std::cerr << " Error calculating the collision rates table.\n";
857 return 0.;
858 }
859 m_isChanged = false;
860 }
861
862 if (band >= 0 && band < nValleysX) {
863 return cfNullElectronsX;
864 } else if (band >= nValleysX && band < nValleysX + nValleysL) {
865 return cfNullElectronsL;
866 } else if (band == nValleysX + nValleysL) {
867 return cfNullElectronsG;
868 }
869 std::cerr << m_className << "::GetElectronNullCollisionRate:\n";
870 std::cerr << " Band index (" << band << ") out of range.\n";
871 return 0.;
872}
873
874double MediumSilicon::GetElectronCollisionRate(const double e, const int band) {
875
876 if (e <= 0.) {
877 std::cerr << m_className << "::GetElectronCollisionRate:\n";
878 std::cerr << " Electron energy must be positive.\n";
879 return 0.;
880 }
881
882 if (e > eFinalG) {
883 std::cerr << m_className << "::GetElectronCollisionRate:\n";
884 std::cerr << " Collision rate at " << e << " eV (band " << band
885 << ") is not included"
886 << " in the current table.\n";
887 std::cerr << " Increasing energy range to " << 1.05 * e << " eV.\n";
888 SetMaxElectronEnergy(1.05 * e);
889 }
890
891 if (m_isChanged) {
892 if (!UpdateTransportParameters()) {
893 std::cerr << m_className << "::GetElectronCollisionRate:\n";
894 std::cerr << " Error calculating the collision rates table.\n";
895 return 0.;
896 }
897 m_isChanged = false;
898 }
899
900 if (band >= 0 && band < nValleysX) {
901 int iE = int(e / eStepXL);
902 if (iE >= nEnergyStepsXL)
903 iE = nEnergyStepsXL - 1;
904 else if (iE < 0)
905 iE = 0;
906 return cfTotElectronsX[iE];
907 } else if (band >= nValleysX && band < nValleysX + nValleysL) {
908 int iE = int(e / eStepXL);
909 if (iE >= nEnergyStepsXL)
910 iE = nEnergyStepsXL - 1;
911 else if (iE < ieMinL)
912 iE = ieMinL;
913 return cfTotElectronsL[iE];
914 } else if (band == nValleysX + nValleysL) {
915 int iE = int(e / eStepG);
916 if (iE >= nEnergyStepsG)
917 iE = nEnergyStepsG - 1;
918 else if (iE < ieMinG)
919 iE = ieMinG;
920 return cfTotElectronsG[iE];
921 }
922
923 std::cerr << m_className << "::GetElectronCollisionRate:\n";
924 std::cerr << " Band index (" << band << ") out of range.\n";
925 return 0.;
926}
927
928bool MediumSilicon::GetElectronCollision(const double e, int& type, int& level,
929 double& e1, double& px, double& py,
930 double& pz, int& nion, int& ndxc,
931 int& band) {
932
933 if (e > eFinalG) {
934 std::cerr << m_className << "::GetElectronCollision:\n";
935 std::cerr << " Requested electron energy (" << e;
936 std::cerr << " eV) exceeds current energy range (" << eFinalG;
937 std::cerr << " eV).\n";
938 std::cerr << " Increasing energy range to " << 1.05 * e << " eV.\n";
939 SetMaxElectronEnergy(1.05 * e);
940 } else if (e <= 0.) {
941 std::cerr << m_className << "::GetElectronCollision:\n";
942 std::cerr << " Electron energy must be greater than zero.\n";
943 return false;
944 }
945
946 if (m_isChanged) {
947 if (!UpdateTransportParameters()) {
948 std::cerr << m_className << "::GetElectronCollision:\n";
949 std::cerr << " Error calculating the collision rates table.\n";
950 return false;
951 }
952 m_isChanged = false;
953 }
954
955 // Energy loss
956 double loss = 0.;
957 // Sample the scattering process.
958 if (band >= 0 && band < nValleysX) {
959 // X valley
960 // Get the energy interval.
961 int iE = int(e / eStepXL);
962 if (iE >= nEnergyStepsXL) iE = nEnergyStepsXL - 1;
963 if (iE < 0) iE = 0;
964 // Select the scattering process.
965 const double r = RndmUniform();
966 int iLow = 0;
967 int iUp = nLevelsX - 1;
968 if (r <= cfElectronsX[iE][iLow]) {
969 level = iLow;
970 } else if (r >= cfElectronsX[iE][nLevelsX - 1]) {
971 level = iUp;
972 } else {
973 int iMid;
974 while (iUp - iLow > 1) {
975 iMid = (iLow + iUp) >> 1;
976 if (r < cfElectronsX[iE][iMid]) {
977 iUp = iMid;
978 } else {
979 iLow = iMid;
980 }
981 }
982 level = iUp;
983 }
984
985 // Get the collision type.
986 type = scatTypeElectronsX[level];
987 // Fill the collision counters.
988 ++nCollElectronDetailed[level];
989 ++nCollElectronBand[band];
990 if (type == ElectronCollisionTypeAcousticPhonon) {
991 ++nCollElectronAcoustic;
992 } else if (type == ElectronCollisionTypeIntervalleyG) {
993 // Intervalley scattering (g type)
994 ++nCollElectronIntervalley;
995 // Final valley is in opposite direction.
996 switch (band) {
997 case 0:
998 band = 1;
999 break;
1000 case 1:
1001 band = 0;
1002 break;
1003 case 2:
1004 band = 3;
1005 break;
1006 case 3:
1007 band = 2;
1008 break;
1009 case 4:
1010 band = 5;
1011 break;
1012 case 5:
1013 band = 4;
1014 break;
1015 default:
1016 break;
1017 }
1018 } else if (type == ElectronCollisionTypeIntervalleyF) {
1019 // Intervalley scattering (f type)
1020 ++nCollElectronIntervalley;
1021 // Final valley is perpendicular.
1022 switch (band) {
1023 case 0:
1024 case 1:
1025 band = int(RndmUniform() * 4) + 2;
1026 break;
1027 case 2:
1028 case 3:
1029 band = int(RndmUniform() * 4);
1030 if (band > 1) band += 2;
1031 break;
1032 case 4:
1033 case 5:
1034 band = int(RndmUniform() * 4);
1035 break;
1036 }
1037 } else if (type == ElectronCollisionTypeInterbandXL) {
1038 // XL scattering
1039 ++nCollElectronIntervalley;
1040 // Final valley is in L band.
1041 band = nValleysX + int(RndmUniform() * nValleysL);
1042 if (band >= nValleysX + nValleysL) band = nValleysX + nValleysL - 1;
1043 } else if (type == ElectronCollisionTypeInterbandXG) {
1044 ++nCollElectronIntervalley;
1045 band = nValleysX + nValleysL;
1046 } else if (type == ElectronCollisionTypeImpurity) {
1047 ++nCollElectronImpurity;
1048 } else if (type == ElectronCollisionTypeIonisation) {
1049 ++nCollElectronIonisation;
1050 } else {
1051 std::cerr << m_className << "::GetElectronCollision:\n";
1052 std::cerr << " Unexpected collision type (" << type << ").\n";
1053 }
1054
1055 // Get the energy loss.
1056 loss = energyLossElectronsX[level];
1057
1058 } else if (band >= nValleysX && band < nValleysX + nValleysL) {
1059 // L valley
1060 // Get the energy interval.
1061 int iE = int(e / eStepXL);
1062 if (iE >= nEnergyStepsXL) iE = nEnergyStepsXL - 1;
1063 if (iE < ieMinL) iE = ieMinL;
1064 // Select the scattering process.
1065 const double r = RndmUniform();
1066 int iLow = 0;
1067 int iUp = nLevelsL - 1;
1068 if (r <= cfElectronsL[iE][iLow]) {
1069 level = iLow;
1070 } else if (r >= cfElectronsL[iE][nLevelsL - 1]) {
1071 level = iUp;
1072 } else {
1073 int iMid;
1074 while (iUp - iLow > 1) {
1075 iMid = (iLow + iUp) >> 1;
1076 if (r < cfElectronsL[iE][iMid]) {
1077 iUp = iMid;
1078 } else {
1079 iLow = iMid;
1080 }
1081 }
1082 level = iUp;
1083 }
1084
1085 // Get the collision type.
1086 type = scatTypeElectronsL[level];
1087 // Fill the collision counters.
1088 ++nCollElectronDetailed[nLevelsX + level];
1089 ++nCollElectronBand[band];
1090 if (type == ElectronCollisionTypeAcousticPhonon) {
1091 ++nCollElectronAcoustic;
1092 } else if (type == ElectronCollisionTypeOpticalPhonon) {
1093 ++nCollElectronOptical;
1094 } else if (type == ElectronCollisionTypeIntervalleyG ||
1095 type == ElectronCollisionTypeIntervalleyF) {
1096 // Equivalent intervalley scattering
1097 ++nCollElectronIntervalley;
1098 // Randomise the final valley.
1099 band = nValleysX + int(RndmUniform() * nValleysL);
1100 if (band >= nValleysX + nValleysL) band = nValleysX + nValleysL;
1101 } else if (type == ElectronCollisionTypeInterbandXL) {
1102 // LX scattering
1103 ++nCollElectronIntervalley;
1104 // Randomise the final valley.
1105 band = int(RndmUniform() * nValleysX);
1106 if (band >= nValleysX) band = nValleysX - 1;
1107 } else if (type == ElectronCollisionTypeInterbandLG) {
1108 // LG scattering
1109 ++nCollElectronIntervalley;
1110 band = nValleysX + nValleysL;
1111 } else if (type == ElectronCollisionTypeImpurity) {
1112 ++nCollElectronImpurity;
1113 } else if (type == ElectronCollisionTypeIonisation) {
1114 ++nCollElectronIonisation;
1115 } else {
1116 std::cerr << m_className << "::GetElectronCollision:\n";
1117 std::cerr << " Unexpected collision type (" << type << ").\n";
1118 }
1119
1120 // Get the energy loss.
1121 loss = energyLossElectronsL[level];
1122 } else if (band == nValleysX + nValleysL) {
1123 // Higher bands
1124 // Get the energy interval.
1125 int iE = int(e / eStepG);
1126 if (iE >= nEnergyStepsG) iE = nEnergyStepsG - 1;
1127 if (iE < ieMinG) iE = ieMinG;
1128 // Select the scattering process.
1129 const double r = RndmUniform();
1130 int iLow = 0;
1131 int iUp = nLevelsG - 1;
1132 if (r <= cfElectronsG[iE][iLow]) {
1133 level = iLow;
1134 } else if (r >= cfElectronsG[iE][nLevelsG - 1]) {
1135 level = iUp;
1136 } else {
1137 int iMid;
1138 while (iUp - iLow > 1) {
1139 iMid = (iLow + iUp) >> 1;
1140 if (r < cfElectronsG[iE][iMid]) {
1141 iUp = iMid;
1142 } else {
1143 iLow = iMid;
1144 }
1145 }
1146 level = iUp;
1147 }
1148
1149 // Get the collision type.
1150 type = scatTypeElectronsG[level];
1151 // Fill the collision counters.
1152 ++nCollElectronDetailed[nLevelsX + nLevelsL + level];
1153 ++nCollElectronBand[band];
1154 if (type == ElectronCollisionTypeAcousticPhonon) {
1155 ++nCollElectronAcoustic;
1156 } else if (type == ElectronCollisionTypeOpticalPhonon) {
1157 ++nCollElectronOptical;
1158 } else if (type == ElectronCollisionTypeIntervalleyG ||
1159 type == ElectronCollisionTypeIntervalleyF) {
1160 // Equivalent intervalley scattering
1161 ++nCollElectronIntervalley;
1162 } else if (type == ElectronCollisionTypeInterbandXG) {
1163 // GX scattering
1164 ++nCollElectronIntervalley;
1165 // Randomise the final valley.
1166 band = int(RndmUniform() * nValleysX);
1167 if (band >= nValleysX) band = nValleysX - 1;
1168 } else if (type == ElectronCollisionTypeInterbandLG) {
1169 // GL scattering
1170 ++nCollElectronIntervalley;
1171 // Randomise the final valley.
1172 band = nValleysX + int(RndmUniform() * nValleysL);
1173 if (band >= nValleysX + nValleysL) band = nValleysX + nValleysL - 1;
1174 } else if (type == ElectronCollisionTypeIonisation) {
1175 ++nCollElectronIonisation;
1176 } else {
1177 std::cerr << m_className << "::GetElectronCollision:\n";
1178 std::cerr << " Unexpected collision type (" << type << ").\n";
1179 }
1180
1181 // Get the energy loss.
1182 loss = energyLossElectronsG[level];
1183 } else {
1184 std::cerr << m_className << "::GetElectronCollision:\n";
1185 std::cerr << " Band index (" << band << ") out of range.\n";
1186 return false;
1187 }
1188
1189 // Secondaries
1190 nion = ndxc = 0;
1191 // Ionising collision
1192 if (type == ElectronCollisionTypeIonisation) {
1193 double ee = 0., eh = 0.;
1194 ComputeSecondaries(e, ee, eh);
1195 loss = ee + eh + m_bandGap;
1196 ionProducts.clear();
1197 // Add the secondary electron.
1198 ionProd newIonProd;
1199 newIonProd.type = IonProdTypeElectron;
1200 newIonProd.energy = ee;
1201 ionProducts.push_back(newIonProd);
1202 // Add the hole.
1203 newIonProd.type = IonProdTypeHole;
1204 newIonProd.energy = eh;
1205 ionProducts.push_back(newIonProd);
1206 nion = nIonisationProducts = 2;
1207 }
1208
1209 if (e < loss) loss = e - 0.00001;
1210 // Update the energy.
1211 e1 = e - loss;
1212 if (e1 < Small) e1 = Small;
1213
1214 // Update the momentum.
1215 if (band >= 0 && band < nValleysX) {
1216 // X valleys
1217 double pstar = sqrt(2. * ElectronMass * e1);
1218 if (useNonParabolicity) {
1219 const double alpha = alphaX;
1220 pstar *= sqrt(1. + alpha * e1);
1221 }
1222
1223 const double ctheta = 1. - 2. * RndmUniform();
1224 const double stheta = sqrt(1. - ctheta * ctheta);
1225 const double phi = TwoPi * RndmUniform();
1226
1227 if (useAnisotropy) {
1228 const double pl = pstar * sqrt(mLongX);
1229 const double pt = pstar * sqrt(mTransX);
1230 switch (band) {
1231 case 0:
1232 case 1:
1233 // 100
1234 px = pl * ctheta;
1235 py = pt * cos(phi) * stheta;
1236 pz = pt * sin(phi) * stheta;
1237 break;
1238 case 2:
1239 case 3:
1240 // 010
1241 px = pt * sin(phi) * stheta;
1242 py = pl * ctheta;
1243 pz = pt * cos(phi) * stheta;
1244 break;
1245 case 4:
1246 case 5:
1247 // 001
1248 px = pt * cos(phi) * stheta;
1249 py = pt * sin(phi) * stheta;
1250 pz = pl * ctheta;
1251 break;
1252 default:
1253 return false;
1254 break;
1255 }
1256 } else {
1257 pstar *= sqrt(3. / (1. / mLongX + 2. / mTransX));
1258 px = pstar * cos(phi) * stheta;
1259 py = pstar * sin(phi) * stheta;
1260 pz = pstar * ctheta;
1261 }
1262 return true;
1263
1264 } else if (band >= nValleysX && band < nValleysX + nValleysL) {
1265 // L valleys
1266 double pstar = sqrt(2. * ElectronMass * (e1 - eMinL));
1267 if (useNonParabolicity) {
1268 const double alpha = alphaL;
1269 pstar *= sqrt(1. + alpha * (e1 - eMinL));
1270 }
1271
1272 const double ctheta = 1. - 2. * RndmUniform();
1273 const double stheta = sqrt(1. - ctheta * ctheta);
1274 const double phi = TwoPi * RndmUniform();
1275
1276 pstar *= sqrt(3. / (1. / mLongL + 2. / mTransL));
1277 px = pstar * cos(phi) * stheta;
1278 py = pstar * sin(phi) * stheta;
1279 pz = pstar * ctheta;
1280 return true;
1281
1282 } else {
1283 double pstar = sqrt(2. * ElectronMass * e1);
1284
1285 const double ctheta = 1. - 2. * RndmUniform();
1286 const double stheta = sqrt(1. - ctheta * ctheta);
1287 const double phi = TwoPi * RndmUniform();
1288
1289 px = pstar * cos(phi) * stheta;
1290 py = pstar * sin(phi) * stheta;
1291 pz = pstar * ctheta;
1292 return true;
1293 }
1294
1295 std::cerr << m_className << "::GetElectronCollision:\n";
1296 std::cerr << " Band index (" << band << ") out of range.\n";
1297 e1 = e;
1298 type = 0;
1299 return false;
1300}
1301
1302bool MediumSilicon::GetIonisationProduct(const int i, int& type,
1303 double& energy) {
1304
1305 if (i < 0 || i >= nIonisationProducts) {
1306 std::cerr << m_className << "::GetIonisationProduct:\n";
1307 std::cerr << " Index (" << i << ") out of range.\n";
1308 return false;
1309 }
1310
1311 type = ionProducts[i].type;
1312 energy = ionProducts[i].energy;
1313 return true;
1314}
1315
1317
1318 nCollElectronAcoustic = nCollElectronOptical = 0;
1319 nCollElectronIntervalley = 0;
1320 nCollElectronImpurity = 0;
1321 nCollElectronIonisation = 0;
1322 const int nLevels = nLevelsX + nLevelsL + nLevelsG;
1323 nCollElectronDetailed.resize(nLevels);
1324 for (int j = nLevels; j--;) nCollElectronDetailed[j] = 0;
1325 const int nBands = nValleysX + nValleysL + 1;
1326 nCollElectronBand.resize(nBands);
1327 for (int j = nBands; j--;) nCollElectronBand[j] = 0;
1328}
1329
1331
1332 return nCollElectronAcoustic + nCollElectronOptical +
1333 nCollElectronIntervalley + nCollElectronImpurity +
1334 nCollElectronIonisation;
1335}
1336
1338
1339 const int nLevels = nLevelsX + nLevelsL + nLevelsG;
1340 return nLevels;
1341}
1342
1344
1345 const int nLevels = nLevelsX + nLevelsL + nLevelsG;
1346 if (level < 0 || level >= nLevels) {
1347 std::cerr << m_className << "::GetNumberOfElectronCollisions:\n";
1348 std::cerr << " Requested scattering rate term (" << level
1349 << ") does not exist.\n";
1350 return 0;
1351 }
1352 return nCollElectronDetailed[level];
1353}
1354
1356
1357 const int nBands = nValleysX + nValleysL + 1;
1358 return nBands;
1359}
1360
1362
1363 const int nBands = nValleysX + nValleysL + 1;
1364 if (band < 0 || band >= nBands) {
1365 std::cerr << m_className << "::GetElectronBandPopulation:\n";
1366 std::cerr << " Band index (" << band << ") out of range.\n";
1367 return 0;
1368 }
1369 return nCollElectronBand[band];
1370}
1371
1372bool MediumSilicon::GetOpticalDataRange(double& emin, double& emax,
1373 const unsigned int& i) {
1374
1375 if (i != 0) {
1376 std::cerr << m_className << "::GetOpticalDataRange:\n";
1377 std::cerr << " Medium has only one component.\n";
1378 }
1379
1380 // Make sure the optical data table has been loaded.
1381 if (!m_hasOpticalData) {
1382 if (!LoadOpticalData(opticalDataFile)) {
1383 std::cerr << m_className << "::GetOpticalDataRange:\n";
1384 std::cerr << " Optical data table could not be loaded.\n";
1385 return false;
1386 }
1387 m_hasOpticalData = true;
1388 }
1389
1390 emin = opticalDataTable[0].energy;
1391 emax = opticalDataTable.back().energy;
1392 if (m_debug) {
1393 std::cout << m_className << "::GetOpticalDataRange:\n";
1394 std::cout << " " << emin << " < E [eV] < " << emax << "\n";
1395 }
1396 return true;
1397}
1398
1399bool MediumSilicon::GetDielectricFunction(const double& e, double& eps1,
1400 double& eps2, const unsigned int& i) {
1401
1402 if (i != 0) {
1403 std::cerr << m_className << "::GetDielectricFunction:\n";
1404 std::cerr << " Medium has only one component.\n";
1405 return false;
1406 }
1407
1408 // Make sure the optical data table has been loaded.
1409 if (!m_hasOpticalData) {
1410 if (!LoadOpticalData(opticalDataFile)) {
1411 std::cerr << m_className << "::GetDielectricFunction:\n";
1412 std::cerr << " Optical data table could not be loaded.\n";
1413 return false;
1414 }
1415 m_hasOpticalData = true;
1416 }
1417
1418 // Make sure the requested energy is within the range of the table.
1419 const double emin = opticalDataTable[0].energy;
1420 const double emax = opticalDataTable.back().energy;
1421 if (e < emin || e > emax) {
1422 std::cerr << m_className << "::GetDielectricFunction:\n";
1423 std::cerr << " Requested energy (" << e << " eV) "
1424 << " is outside the range of the optical data table.\n";
1425 std::cerr << " " << emin << " < E [eV] < " << emax << "\n";
1426 eps1 = eps2 = 0.;
1427 return false;
1428 }
1429
1430 // Locate the requested energy in the table.
1431 int iLow = 0;
1432 int iUp = opticalDataTable.size() - 1;
1433 int iM;
1434 while (iUp - iLow > 1) {
1435 iM = (iUp + iLow) >> 1;
1436 if (e >= opticalDataTable[iM].energy) {
1437 iLow = iM;
1438 } else {
1439 iUp = iM;
1440 }
1441 }
1442
1443 // Interpolate the real part of dielectric function.
1444 // Use linear interpolation if one of the values is negative,
1445 // Otherwise use log-log interpolation.
1446 const double logX0 = log(opticalDataTable[iLow].energy);
1447 const double logX1 = log(opticalDataTable[iUp].energy);
1448 const double logX = log(e);
1449 if (opticalDataTable[iLow].eps1 <= 0. || opticalDataTable[iUp].eps1 <= 0.) {
1450 eps1 = opticalDataTable[iLow].eps1 +
1451 (e - opticalDataTable[iLow].energy) *
1452 (opticalDataTable[iUp].eps1 - opticalDataTable[iLow].eps1) /
1453 (opticalDataTable[iUp].energy - opticalDataTable[iLow].energy);
1454 } else {
1455 const double logY0 = log(opticalDataTable[iLow].eps1);
1456 const double logY1 = log(opticalDataTable[iUp].eps1);
1457 eps1 = logY0 + (logX - logX0) * (logY1 - logY0) / (logX1 - logX0);
1458 eps1 = exp(eps1);
1459 }
1460
1461 // Interpolate the imaginary part of dielectric function,
1462 // using log-log interpolation.
1463 const double logY0 = log(opticalDataTable[iLow].eps2);
1464 const double logY1 = log(opticalDataTable[iUp].eps2);
1465 eps2 = logY0 + (log(e) - logX0) * (logY1 - logY0) / (logX1 - logX0);
1466 eps2 = exp(eps2);
1467 return true;
1468}
1469
1471
1472 if (!m_isChanged) {
1473 if (m_debug) {
1474 std::cerr << m_className << "::Initialise:\n";
1475 std::cerr << " Nothing changed.\n";
1476 }
1477 return true;
1478 }
1479 if (!UpdateTransportParameters()) {
1480 std::cerr << m_className << "::Initialise:\n";
1481 std::cerr << " Error preparing transport parameters/"
1482 << "calculating collision rates.\n";
1483 return false;
1484 }
1485 return true;
1486}
1487
1488bool MediumSilicon::UpdateTransportParameters() {
1489
1490 // Calculate impact ionisation coefficients
1491 switch (impactIonisationModel) {
1492 case ImpactIonisationModelVanOverstraeten:
1493 UpdateImpactIonisationVanOverstraetenDeMan();
1494 break;
1495 case ImpactIonisationModelGrant:
1496 UpdateImpactIonisationGrant();
1497 break;
1498 default:
1499 std::cerr << m_className << "::UpdateTransportParameters:\n";
1500 std::cerr << " Unknown impact ionisation model. Bug!\n";
1501 break;
1502 }
1503
1504 if (!m_hasUserMobility) {
1505 // Calculate lattice mobility
1506 switch (latticeMobilityModel) {
1507 case LatticeMobilityModelMinimos:
1508 UpdateLatticeMobilityMinimos();
1509 break;
1510 case LatticeMobilityModelSentaurus:
1511 UpdateLatticeMobilitySentaurus();
1512 break;
1513 case LatticeMobilityModelReggiani:
1514 UpdateLatticeMobilityReggiani();
1515 break;
1516 default:
1517 std::cerr << m_className << "::UpdateTransportParameters:\n";
1518 std::cerr << " Unknown lattice mobility model.\n";
1519 std::cerr << " Program bug!\n";
1520 break;
1521 }
1522
1523 // Calculate doping mobility
1524 switch (dopingMobilityModel) {
1525 case DopingMobilityModelMinimos:
1526 UpdateDopingMobilityMinimos();
1527 break;
1528 case DopingMobilityModelMasetti:
1529 UpdateDopingMobilityMasetti();
1530 break;
1531 default:
1532 std::cerr << m_className << "::UpdateTransportParameters:\n";
1533 std::cerr << " Unknown doping mobility model.\n";
1534 std::cerr << " Program bug!\n";
1535 break;
1536 }
1537 }
1538
1539 // Calculate saturation velocity
1540 if (!m_hasUserSaturationVelocity) {
1541 switch (saturationVelocityModel) {
1542 case SaturationVelocityModelMinimos:
1543 UpdateSaturationVelocityMinimos();
1544 break;
1545 case SaturationVelocityModelCanali:
1546 UpdateSaturationVelocityCanali();
1547 break;
1548 case SaturationVelocityModelReggiani:
1549 UpdateSaturationVelocityReggiani();
1550 break;
1551 }
1552 }
1553
1554 // Calculate high field saturation parameters
1555 switch (highFieldMobilityModel) {
1556 case HighFieldMobilityModelCanali:
1557 UpdateHighFieldMobilityCanali();
1558 break;
1559 }
1560
1561 if (m_debug) {
1562 std::cout << m_className << "::UpdateTransportParameters:\n";
1563 std::cout << " Low-field mobility [cm2 V-1 ns-1]\n";
1564 std::cout << " Electrons: " << eMobility << "\n";
1565 std::cout << " Holes: " << hMobility << "\n";
1566 if (highFieldMobilityModel > 2) {
1567 std::cout << " Mobility is not field-dependent.\n";
1568 } else {
1569 std::cout << " Saturation velocity [cm / ns]\n";
1570 std::cout << " Electrons: " << eSatVel << "\n";
1571 std::cout << " Holes: " << hSatVel << "\n";
1572 }
1573 }
1574
1575 if (!ElectronScatteringRates()) return false;
1576 if (!HoleScatteringRates()) return false;
1577
1578 // Reset the collision counters.
1580
1581 return true;
1582}
1583
1584void MediumSilicon::UpdateLatticeMobilityMinimos() {
1585
1586 // References:
1587 // - S. Selberherr, W. Haensch, M. Seavey, J. Slotboom,
1588 // Solid State Electronics 33 (1990), 1425-1436
1589 // - Minimos 6.1 User's Guide (1999)
1590
1591 // Lattice mobilities at 300 K [cm2 / (V ns)]
1592 const double eMu0 = 1.43e-6;
1593 const double hMu0 = 0.46e-6;
1594 // Temperature normalized to 300 K
1595 const double t = m_temperature / 300.;
1596 // Temperature dependence of lattice mobility
1597 eLatticeMobility = eMu0 * pow(t, -2.);
1598 hLatticeMobility = hMu0 * pow(t, -2.18);
1599}
1600
1601void MediumSilicon::UpdateLatticeMobilitySentaurus() {
1602
1603 // References:
1604 // - C. Lombardi et al.,
1605 // IEEE Trans. CAD 7 (1988), 1164-1171
1606 // - Sentaurus Device User Guide (2007)
1607
1608 // Lattice mobilities at 300 K [cm2 / (V ns)]
1609 const double eMu0 = 1.417e-6;
1610 const double hMu0 = 0.4705e-6;
1611 // Temperature normalized to 300 K
1612 const double t = m_temperature / 300.;
1613 // Temperature dependence of lattice mobility
1614 eLatticeMobility = eMu0 * pow(t, -2.5);
1615 hLatticeMobility = hMu0 * pow(t, -2.2);
1616}
1617
1618void MediumSilicon::UpdateLatticeMobilityReggiani() {
1619
1620 // Reference:
1621 // - M. A. Omar, L. Reggiani
1622 // Solid State Electronics 30 (1987), 693-697
1623
1624 // Lattice mobilities at 300 K [cm2 / (V ns)]
1625 const double eMu0 = 1.320e-6;
1626 const double hMu0 = 0.460e-6;
1627 // Temperature normalized to 300 K
1628 const double t = m_temperature / 300.;
1629 // Temperature dependence of lattice mobility
1630 eLatticeMobility = eMu0 * pow(t, -2.);
1631 hLatticeMobility = hMu0 * pow(t, -2.2);
1632}
1633
1634void MediumSilicon::UpdateDopingMobilityMinimos() {
1635
1636 // References:
1637 // - S. Selberherr, W. Haensch, M. Seavey, J. Slotboom,
1638 // Solid State Electronics 33 (1990), 1425-1436
1639 // - Minimos 6.1 User's Guide (1999)
1640
1641 // Mobility reduction due to ionised impurity scattering
1642 // Surface term not taken into account
1643 double eMuMin = 0.080e-6;
1644 double hMuMin = 0.045e-6;
1645 if (m_temperature > 200.) {
1646 eMuMin *= pow(m_temperature / 300., -0.45);
1647 hMuMin *= pow(m_temperature / 300., -0.45);
1648 } else {
1649 eMuMin *= pow(2. / 3., -0.45) * pow(m_temperature / 200., -0.15);
1650 hMuMin *= pow(2. / 3., -0.45) * pow(m_temperature / 200., -0.15);
1651 }
1652 const double eRefC = 1.12e17 * pow(m_temperature / 300., 3.2);
1653 const double hRefC = 2.23e17 * pow(m_temperature / 300., 3.2);
1654 const double alpha = 0.72 * pow(m_temperature / 300., 0.065);
1655 // Assume impurity concentration equal to doping concentration
1656 eMobility = eMuMin + (eLatticeMobility - eMuMin) /
1657 (1. + pow(m_dopingConcentration / eRefC, alpha));
1658 hMobility = hMuMin + (hLatticeMobility - hMuMin) /
1659 (1. + pow(m_dopingConcentration / hRefC, alpha));
1660}
1661
1662void MediumSilicon::UpdateDopingMobilityMasetti() {
1663
1664 // Reference:
1665 // - G. Masetti, M. Severi, S. Solmi,
1666 // IEEE Trans. Electron Devices 30 (1983), 764-769
1667 // - Sentaurus Device User Guide (2007)
1668 // - Minimos NT User Guide (2004)
1669
1670 if (m_dopingConcentration < 1.e13) {
1671 eMobility = eLatticeMobility;
1672 hMobility = hLatticeMobility;
1673 return;
1674 }
1675
1676 // Parameters adopted from Minimos NT User Guide
1677 const double eMuMin1 = 0.0522e-6;
1678 const double eMuMin2 = 0.0522e-6;
1679 const double eMu1 = 0.0434e-6;
1680 const double hMuMin1 = 0.0449e-6;
1681 const double hMuMin2 = 0.;
1682 const double hMu1 = 0.029e-6;
1683 const double eCr = 9.68e16;
1684 const double eCs = 3.42e20;
1685 const double hCr = 2.23e17;
1686 const double hCs = 6.10e20;
1687 const double hPc = 9.23e16;
1688 const double eAlpha = 0.68;
1689 const double eBeta = 2.;
1690 const double hAlpha = 0.719;
1691 const double hBeta = 2.;
1692
1693 eMobility = eMuMin1 + (eLatticeMobility - eMuMin2) /
1694 (1. + pow(m_dopingConcentration / eCr, eAlpha)) -
1695 eMu1 / (1. + pow(eCs / m_dopingConcentration, eBeta));
1696
1697 hMobility = hMuMin1 * exp(-hPc / m_dopingConcentration) +
1698 (hLatticeMobility - hMuMin2) /
1699 (1. + pow(m_dopingConcentration / hCr, hAlpha)) -
1700 hMu1 / (1. + pow(hCs / m_dopingConcentration, hBeta));
1701}
1702
1703void MediumSilicon::UpdateSaturationVelocityMinimos() {
1704
1705 // References:
1706 // - R. Quay, C. Moglestue, V. Palankovski, S. Selberherr,
1707 // Materials Science in Semiconductor Processing 3 (2000), 149-155
1708 // - Minimos NT User Guide (2004)
1709
1710 // Temperature-dependence of saturation velocities [cm / ns]
1711 eSatVel = 1.e-2 / (1. + 0.74 * (m_temperature / 300. - 1.));
1712 hSatVel = 0.704e-2 / (1. + 0.37 * (m_temperature / 300. - 1.));
1713}
1714
1715void MediumSilicon::UpdateSaturationVelocityCanali() {
1716
1717 // References:
1718 // - C. Canali, G. Majni, R. Minder, G. Ottaviani,
1719 // IEEE Transactions on Electron Devices 22 (1975), 1045-1047
1720 // - Sentaurus Device User Guide (2007)
1721
1722 eSatVel = 1.07e-2 * pow(300. / m_temperature, 0.87);
1723 hSatVel = 8.37e-3 * pow(300. / m_temperature, 0.52);
1724}
1725
1726void MediumSilicon::UpdateSaturationVelocityReggiani() {
1727
1728 // Reference:
1729 // - M. A. Omar, L. Reggiani
1730 // Solid State Electronics 30 (1987), 693-697
1731
1732 eSatVel = 1.470e-2 * sqrt(tanh(150. / m_temperature));
1733 hSatVel = 0.916e-2 * sqrt(tanh(300. / m_temperature));
1734}
1735
1736void MediumSilicon::UpdateHighFieldMobilityCanali() {
1737
1738 // References:
1739 // - C. Canali, G. Majni, R. Minder, G. Ottaviani,
1740 // IEEE Transactions on Electron Devices 22 (1975), 1045-1047
1741 // - Sentaurus Device User Guide (2007)
1742
1743 // Temperature dependent exponent in high-field mobility formula
1744 eBetaCanali = 1.109 * pow(m_temperature / 300., 0.66);
1745 hBetaCanali = 1.213 * pow(m_temperature / 300., 0.17);
1746 eBetaCanaliInv = 1. / eBetaCanali;
1747 hBetaCanaliInv = 1. / hBetaCanali;
1748}
1749
1750void MediumSilicon::UpdateImpactIonisationVanOverstraetenDeMan() {
1751
1752 // References:
1753 // - R. van Overstraeten and H. de Man,
1754 // Solid State Electronics 13 (1970), 583-608
1755 // - W. Maes, K. de Meyer and R. van Overstraeten,
1756 // Solid State Electronics 33 (1990), 705-718
1757 // - Sentaurus Device User Guide (2007)
1758
1759 // Temperature dependence as in Sentaurus Device
1760 // Optical phonon energy
1761 const double hbarOmega = 0.063;
1762 // Temperature scaling coefficient
1763 const double gamma = tanh(hbarOmega / (2. * BoltzmannConstant * 300.)) /
1764 tanh(hbarOmega / (2. * BoltzmannConstant * m_temperature));
1765
1766 // Low field coefficients taken from Maes, de Meyer, van Overstraeten
1767 eImpactA0 = gamma * 3.318e5;
1768 eImpactB0 = gamma * 1.135e6;
1769 eImpactA1 = gamma * 7.03e5;
1770 eImpactB1 = gamma * 1.231e6;
1771
1772 hImpactA0 = gamma * 1.582e6;
1773 hImpactB0 = gamma * 2.036e6;
1774 hImpactA1 = gamma * 6.71e5;
1775 hImpactB1 = gamma * 1.693e6;
1776}
1777
1778void MediumSilicon::UpdateImpactIonisationGrant() {
1779
1780 // References:
1781 // - W. N. Grant,
1782 // Solid State Electronics 16 (1973), 1189 - 1203
1783 // - Sentaurus Device User Guide (2007)
1784
1785 // Temperature dependence as in Sentaurus Device
1786 // Optical phonon energy
1787 double hbarOmega = 0.063;
1788 // Temperature scaling coefficient
1789 double gamma = tanh(hbarOmega / (2. * BoltzmannConstant * 300.)) /
1790 tanh(hbarOmega / (2. * BoltzmannConstant * m_temperature));
1791
1792 eImpactA0 = 2.60e6 * gamma;
1793 eImpactB0 = 1.43e6 * gamma;
1794 eImpactA1 = 6.20e5 * gamma;
1795 eImpactB1 = 1.08e6 * gamma;
1796 eImpactA2 = 5.05e5 * gamma;
1797 eImpactB2 = 9.90e5 * gamma;
1798
1799 hImpactA0 = 2.00e6 * gamma;
1800 hImpactB0 = 1.97e6 * gamma;
1801 hImpactA1 = 5.60e5 * gamma;
1802 hImpactB1 = 1.32e6 * gamma;
1803}
1804
1805bool MediumSilicon::ElectronMobilityMinimos(const double e, double& mu) const {
1806
1807 // Reference:
1808 // - Minimos User's Guide (1999)
1809
1810 if (e < Small) {
1811 mu = 0.;
1812 } else {
1813 mu = 2. * eMobility /
1814 (1. + sqrt(1. + pow(2. * eMobility * e / eSatVel, 2.)));
1815 }
1816 return true;
1817}
1818
1819bool MediumSilicon::ElectronMobilityCanali(const double e, double& mu) const {
1820
1821 // Reference:
1822 // - Sentaurus Device User Guide (2007)
1823
1824 if (e < Small) {
1825 mu = 0.;
1826 } else {
1827 mu = eMobility /
1828 pow(1. + pow(eMobility * e / eSatVel, eBetaCanali), eBetaCanaliInv);
1829 }
1830 return true;
1831}
1832
1833bool MediumSilicon::ElectronMobilityReggiani(const double e, double& mu) const {
1834
1835 // Reference:
1836 // - M. A. Omar, L. Reggiani
1837 // Solid State Electronics 30 (1987), 693-697
1838
1839 if (e < Small) {
1840 mu = 0.;
1841 } else {
1842 mu = eMobility / pow(1 + pow(eMobility * e / eSatVel, 1.5), 1. / 1.5);
1843 }
1844 return true;
1845}
1846
1847bool MediumSilicon::ElectronImpactIonisationVanOverstraetenDeMan(
1848 const double e, double& alpha) const {
1849
1850 // References:
1851 // - R. van Overstraeten and H. de Man,
1852 // Solid State Electronics 13 (1970), 583-608
1853 // - W. Maes, K. de Meyer and R. van Overstraeten,
1854 // Solid State Electronics 33 (1990), 705-718
1855
1856 if (e < Small) {
1857 alpha = 0.;
1858 } else if (e < 1.2786e5) {
1859 alpha = eImpactA0 * exp(-eImpactB0 / e);
1860 } else {
1861 alpha = eImpactA1 * exp(-eImpactB1 / e);
1862 }
1863 return true;
1864}
1865
1866bool MediumSilicon::ElectronImpactIonisationGrant(const double e,
1867 double& alpha) const {
1868
1869 // Reference:
1870 // - W. N. Grant, Solid State Electronics 16 (1973), 1189 - 1203
1871
1872 if (e < Small) {
1873 alpha = 0.;
1874 } else if (e < 2.4e5) {
1875 alpha = eImpactA0 * exp(-eImpactB0 / e);
1876 } else if (e < 5.3e5) {
1877 alpha = eImpactA1 * exp(-eImpactB1 / e);
1878 } else {
1879 alpha = eImpactA2 * exp(-eImpactB2 / e);
1880 }
1881 return true;
1882}
1883
1884bool MediumSilicon::HoleMobilityMinimos(const double e, double& mu) const {
1885
1886 // Reference:
1887 // - Minimos User's Guide (1999)
1888
1889 if (e < Small) {
1890 mu = 0.;
1891 } else {
1892 mu = hMobility / (1. + hMobility * e / eSatVel);
1893 }
1894 return true;
1895}
1896
1897bool MediumSilicon::HoleMobilityCanali(const double e, double& mu) const {
1898
1899 // Reference:
1900 // - Sentaurus Device User Guide (2007)
1901
1902 if (e < Small) {
1903 mu = 0.;
1904 } else {
1905 mu = hMobility /
1906 pow(1. + pow(hMobility * e / hSatVel, hBetaCanali), hBetaCanaliInv);
1907 }
1908 return true;
1909}
1910
1911bool MediumSilicon::HoleMobilityReggiani(const double e, double& mu) const {
1912
1913 // Reference:
1914 // - M. A. Omar, L. Reggiani
1915 // Solid State Electronics 30 (1987), 693-697
1916
1917 if (e < Small) {
1918 mu = 0.;
1919 } else {
1920 mu = hMobility / pow(1. + pow(hMobility * e / hSatVel, 2.), 0.5);
1921 }
1922 return true;
1923}
1924
1925bool MediumSilicon::HoleImpactIonisationVanOverstraetenDeMan(
1926 const double e, double& alpha) const {
1927
1928 // Reference:
1929 // - R. van Overstraeten and H. de Man,
1930 // Solid State Electronics 13 (1970), 583-608
1931
1932 if (e < Small) {
1933 alpha = 0.;
1934 } else {
1935 alpha = hImpactA1 * exp(-hImpactB1 / e);
1936 }
1937 return true;
1938}
1939
1940bool MediumSilicon::HoleImpactIonisationGrant(const double e,
1941 double& alpha) const {
1942
1943 // Reference:
1944 // - W. N. Grant, Solid State Electronics 16 (1973), 1189 - 1203
1945
1946 if (e < Small) {
1947 alpha = 0.;
1948 } else if (e < 5.3e5) {
1949 alpha = hImpactA0 * exp(-hImpactB0 / e);
1950 } else {
1951 alpha = hImpactA1 * exp(-hImpactB1 / e);
1952 }
1953 return true;
1954}
1955
1956bool MediumSilicon::LoadOpticalData(const std::string filename) {
1957
1958 // Get the path to the data directory.
1959 char* pPath = getenv("GARFIELD_HOME");
1960 if (pPath == 0) {
1961 std::cerr << m_className << "::LoadOpticalData:\n";
1962 std::cerr << " Environment variable GARFIELD_HOME is not set.\n";
1963 return false;
1964 }
1965 std::string filepath = pPath;
1966 filepath = filepath + "/Data/" + filename;
1967
1968 // Open the file.
1969 std::ifstream infile;
1970 infile.open(filepath.c_str(), std::ios::in);
1971 // Make sure the file could actually be opened.
1972 if (!infile) {
1973 std::cerr << m_className << "::LoadOpticalData:\n";
1974 std::cerr << " Error opening file " << filename << ".\n";
1975 return false;
1976 }
1977
1978 // Clear the optical data table.
1979 opticalDataTable.clear();
1980
1981 double lastEnergy = -1.;
1982 double energy, eps1, eps2, loss;
1983 opticalData data;
1984 // Read the file line by line.
1985 std::string line;
1986 std::istringstream dataStream;
1987 int i = 0;
1988 while (!infile.eof()) {
1989 ++i;
1990 // Read the next line.
1991 std::getline(infile, line);
1992 // Strip white space from the beginning of the line.
1993 line.erase(line.begin(),
1994 std::find_if(line.begin(), line.end(),
1995 not1(std::ptr_fun<int, int>(isspace))));
1996 // Skip comments.
1997 if (line[0] == '#' || line[0] == '*' || (line[0] == '/' && line[1] == '/'))
1998 continue;
1999 // Extract the values.
2000 dataStream.str(line);
2001 dataStream >> energy >> eps1 >> eps2 >> loss;
2002 if (dataStream.eof()) break;
2003 // Check if the data has been read correctly.
2004 if (infile.fail()) {
2005 std::cerr << m_className << "::LoadOpticalData:\n";
2006 std::cerr << " Error reading file " << filename << " (line " << i
2007 << ").\n";
2008 return false;
2009 }
2010 // Reset the stringstream.
2011 dataStream.str("");
2012 dataStream.clear();
2013 // Make sure the values make sense.
2014 // The table has to be in ascending order
2015 // with respect to the photon energy.
2016 if (energy <= lastEnergy) {
2017 std::cerr << m_className << "::LoadOpticalData:\n";
2018 std::cerr << " Table is not in monotonically "
2019 << "increasing order (line " << i << ").\n";
2020 std::cerr << " " << lastEnergy << " " << energy << " " << eps1
2021 << " " << eps2 << "\n";
2022 return false;
2023 }
2024 // The imaginary part of the dielectric function has to be positive.
2025 if (eps2 < 0.) {
2026 std::cerr << m_className << "::LoadOpticalData:\n";
2027 std::cerr << " Negative value of the loss function "
2028 << "(line " << i << ").\n";
2029 return false;
2030 }
2031 // Ignore negative photon energies.
2032 if (energy <= 0.) continue;
2033 // Add the values to the list.
2034 data.energy = energy;
2035 data.eps1 = eps1;
2036 data.eps2 = eps2;
2037 opticalDataTable.push_back(data);
2038 lastEnergy = energy;
2039 }
2040
2041 const int nEntries = opticalDataTable.size();
2042 if (nEntries <= 0) {
2043 std::cerr << m_className << "::LoadOpticalData:\n";
2044 std::cerr << " Import of data from file " << filepath << "failed.\n";
2045 std::cerr << " No valid data found.\n";
2046 return false;
2047 }
2048
2049 if (m_debug) {
2050 std::cout << m_className << "::LoadOpticalData:\n";
2051 std::cout << " Read " << nEntries << " values from file " << filepath
2052 << "\n";
2053 }
2054 return true;
2055}
2056
2057bool MediumSilicon::ElectronScatteringRates() {
2058
2059 // Reset the scattering rates
2060 cfTotElectronsX.resize(nEnergyStepsXL);
2061 cfTotElectronsL.resize(nEnergyStepsXL);
2062 cfTotElectronsG.resize(nEnergyStepsG);
2063 cfElectronsX.resize(nEnergyStepsXL);
2064 cfElectronsL.resize(nEnergyStepsXL);
2065 cfElectronsG.resize(nEnergyStepsG);
2066 for (int i = nEnergyStepsXL; i--;) {
2067 cfTotElectronsX[i] = 0.;
2068 cfTotElectronsL[i] = 0.;
2069 cfElectronsX[i].clear();
2070 cfElectronsL[i].clear();
2071 }
2072 for (int i = nEnergyStepsG; i--;) {
2073 cfTotElectronsG[i] = 0.;
2074 cfElectronsG[i].clear();
2075 }
2076 energyLossElectronsX.clear();
2077 energyLossElectronsL.clear();
2078 energyLossElectronsG.clear();
2079 scatTypeElectronsX.clear();
2080 scatTypeElectronsL.clear();
2081 scatTypeElectronsG.clear();
2082 cfNullElectronsX = 0.;
2083 cfNullElectronsL = 0.;
2084 cfNullElectronsG = 0.;
2085
2086 nLevelsX = 0;
2087 nLevelsL = 0;
2088 nLevelsG = 0;
2089 // Fill the scattering rate tables.
2090 ElectronAcousticScatteringRates();
2091 ElectronOpticalScatteringRates();
2092 ElectronImpurityScatteringRates();
2093 ElectronIntervalleyScatteringRatesXX();
2094 ElectronIntervalleyScatteringRatesXL();
2095 ElectronIntervalleyScatteringRatesLL();
2096 ElectronIntervalleyScatteringRatesXGLG();
2097 ElectronIonisationRatesXL();
2098 ElectronIonisationRatesG();
2099
2100 if (m_debug) {
2101 std::cout << m_className << "::ElectronScatteringRates:\n";
2102 std::cout << " " << nLevelsX << " X-valley scattering terms\n";
2103 std::cout << " " << nLevelsL << " L-valley scattering terms\n";
2104 std::cout << " " << nLevelsG << " higher band scattering terms\n";
2105 }
2106
2107 std::ofstream outfileX;
2108 std::ofstream outfileL;
2109 if (useCfOutput) {
2110 outfileX.open("ratesX.txt", std::ios::out);
2111 outfileL.open("ratesL.txt", std::ios::out);
2112 }
2113
2114 ieMinL = int(eMinL / eStepXL) + 1;
2115 for (int i = 0; i < nEnergyStepsXL; ++i) {
2116 // Sum up the scattering rates of all processes.
2117 for (int j = nLevelsX; j--;) cfTotElectronsX[i] += cfElectronsX[i][j];
2118 for (int j = nLevelsL; j--;) cfTotElectronsL[i] += cfElectronsL[i][j];
2119
2120 if (useCfOutput) {
2121 outfileX << i* eStepXL << " " << cfTotElectronsX[i] << " ";
2122 for (int j = 0; j < nLevelsX; ++j) {
2123 outfileX << cfElectronsX[i][j] << " ";
2124 }
2125 outfileX << "\n";
2126 outfileL << i* eStepXL << " " << cfTotElectronsL[i] << " ";
2127 for (int j = 0; j < nLevelsL; ++j) {
2128 outfileL << cfElectronsL[i][j] << " ";
2129 }
2130 outfileL << "\n";
2131 }
2132
2133 if (cfTotElectronsX[i] > cfNullElectronsX) {
2134 cfNullElectronsX = cfTotElectronsX[i];
2135 }
2136 if (cfTotElectronsL[i] > cfNullElectronsL) {
2137 cfNullElectronsL = cfTotElectronsL[i];
2138 }
2139
2140 // Make sure the total scattering rate is positive.
2141 if (cfTotElectronsX[i] <= 0.) {
2142 std::cerr << m_className << "::ElectronScatteringRates:\n";
2143 std::cerr << " X-valley scattering rate at " << i* eStepXL
2144 << " eV <= 0.\n";
2145 return false;
2146 }
2147 // Normalise the rates.
2148 for (int j = 0; j < nLevelsX; ++j) {
2149 cfElectronsX[i][j] /= cfTotElectronsX[i];
2150 if (j > 0) cfElectronsX[i][j] += cfElectronsX[i][j - 1];
2151 }
2152
2153 // Make sure the total scattering rate is positive.
2154 if (cfTotElectronsL[i] <= 0.) {
2155 if (i < ieMinL) continue;
2156 std::cerr << m_className << "::ElectronScatteringRates:\n";
2157 std::cerr << " L-valley scattering rate at " << i* eStepXL
2158 << " eV <= 0.\n";
2159 return false;
2160 }
2161 // Normalise the rates.
2162 for (int j = 0; j < nLevelsL; ++j) {
2163 cfElectronsL[i][j] /= cfTotElectronsL[i];
2164 if (j > 0) cfElectronsL[i][j] += cfElectronsL[i][j - 1];
2165 }
2166 }
2167
2168 if (useCfOutput) {
2169 outfileX.close();
2170 outfileL.close();
2171 }
2172
2173 std::ofstream outfileG;
2174 if (useCfOutput) {
2175 outfileG.open("ratesG.txt", std::ios::out);
2176 }
2177 ieMinG = int(eMinG / eStepG) + 1;
2178 for (int i = 0; i < nEnergyStepsG; ++i) {
2179 // Sum up the scattering rates of all processes.
2180 for (int j = nLevelsG; j--;) cfTotElectronsG[i] += cfElectronsG[i][j];
2181
2182 if (useCfOutput) {
2183 outfileG << i* eStepG << " " << cfTotElectronsG[i] << " ";
2184 for (int j = 0; j < nLevelsG; ++j) {
2185 outfileG << cfElectronsG[i][j] << " ";
2186 }
2187 outfileG << "\n";
2188 }
2189
2190 if (cfTotElectronsG[i] > cfNullElectronsG) {
2191 cfNullElectronsG = cfTotElectronsG[i];
2192 }
2193
2194 // Make sure the total scattering rate is positive.
2195 if (cfTotElectronsG[i] <= 0.) {
2196 if (i < ieMinG) continue;
2197 std::cerr << m_className << "::ElectronScatteringRates:\n";
2198 std::cerr << " Higher band scattering rate at " << i* eStepG
2199 << " eV <= 0.\n";
2200 }
2201 // Normalise the rates.
2202 for (int j = 0; j < nLevelsG; ++j) {
2203 cfElectronsG[i][j] /= cfTotElectronsG[i];
2204 if (j > 0) cfElectronsG[i][j] += cfElectronsG[i][j - 1];
2205 }
2206 }
2207
2208 if (useCfOutput) {
2209 outfileG.close();
2210 }
2211
2212 return true;
2213}
2214
2215bool MediumSilicon::ElectronAcousticScatteringRates() {
2216
2217 // Reference:
2218 // - C. Jacoboni and L. Reggiani,
2219 // Rev. Mod. Phys. 55, 645-705
2220
2221 // Mass density [(eV/c2)/cm3]
2222 const double rho = m_density * m_a * AtomicMassUnitElectronVolt;
2223 // Lattice temperature [eV]
2224 const double kbt = BoltzmannConstant * m_temperature;
2225
2226 // Acoustic phonon intraband scattering
2227 // Acoustic deformation potential [eV]
2228 const double defpot = 9.;
2229 // Longitudinal velocity of sound [cm/ns]
2230 const double u = 9.04e-4;
2231 // Prefactor for acoustic deformation potential scattering
2232 const double cIntra = TwoPi * SpeedOfLight * SpeedOfLight * kbt * defpot *
2233 defpot / (Hbar * u * u * rho);
2234
2235 // Fill the scattering rate tables.
2236 double en = Small;
2237 for (int i = 0; i < nEnergyStepsXL; ++i) {
2238 const double dosX = GetConductionBandDensityOfStates(en, 0);
2239 const double dosL = GetConductionBandDensityOfStates(en, nValleysX);
2240
2241 cfElectronsX[i].push_back(cIntra * dosX);
2242 cfElectronsL[i].push_back(cIntra * dosL);
2243 en += eStepXL;
2244 }
2245
2246 en = Small;
2247 for (int i = 0; i < nEnergyStepsG; ++i) {
2248 const double dosG =
2249 GetConductionBandDensityOfStates(en, nValleysX + nValleysL);
2250 cfElectronsG[i].push_back(cIntra * dosG);
2251 en += eStepG;
2252 }
2253
2254 // Assume that energy loss is negligible.
2255 energyLossElectronsX.push_back(0.);
2256 energyLossElectronsL.push_back(0.);
2257 energyLossElectronsG.push_back(0.);
2258 scatTypeElectronsX.push_back(ElectronCollisionTypeAcousticPhonon);
2259 scatTypeElectronsL.push_back(ElectronCollisionTypeAcousticPhonon);
2260 scatTypeElectronsG.push_back(ElectronCollisionTypeAcousticPhonon);
2261 ++nLevelsX;
2262 ++nLevelsL;
2263 ++nLevelsG;
2264
2265 return true;
2266}
2267
2268bool MediumSilicon::ElectronOpticalScatteringRates() {
2269
2270 // Reference:
2271 // - K. Hess (editor),
2272 // Monte Carlo device simulation: full band and beyond
2273 // Chapter 5
2274 // - C. Jacoboni and L. Reggiani,
2275 // Rev. Mod. Phys. 55, 645-705
2276 // - M. Lundstrom,
2277 // Fundamentals of carrier transport
2278
2279 // Mass density [(eV/c2)/cm3]
2280 const double rho = m_density * m_a * AtomicMassUnitElectronVolt;
2281 // Lattice temperature [eV]
2282 const double kbt = BoltzmannConstant * m_temperature;
2283
2284 // Coupling constant [eV/cm]
2285 const double dtk = 2.2e8;
2286 // Phonon energy [eV]
2287 const double eph = 63.0e-3;
2288 // Phonon cccupation numbers
2289 const double nocc = 1. / (exp(eph / kbt) - 1);
2290 // Prefactors
2291 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2292 double c = c0 * dtk * dtk / eph;
2293
2294 double en = 0.;
2295 double dos = 0.;
2296 // L valleys
2297 /*
2298 for (int i = 0; i < nEnergyStepsXL; ++i) {
2299 // Absorption
2300 if (en > eMinL) {
2301 dos = GetConductionBandDensityOfStates(en + eph, nValleysX);
2302 cfElectronsL[i].push_back(c * nocc * dos);
2303 } else {
2304 cfElectronsL[i].push_back(0.);
2305 }
2306 // Emission
2307 if (en > eMinL + eph) {
2308 dos = GetConductionBandDensityOfStates(en - eph, nValleysX);
2309 cfElectronsL[i].push_back(c * (nocc + 1) * dos);
2310 } else {
2311 cfElectronsL[i].push_back(0.);
2312 }
2313 en += eStepXL;
2314 }
2315 //*/
2316
2317 en = 0.;
2318 // Higher band(s)
2319 for (int i = 0; i < nEnergyStepsG; ++i) {
2320 // Absorption
2321 if (en > eMinG) {
2322 dos = GetConductionBandDensityOfStates(en + eph, nValleysX + nValleysL);
2323 cfElectronsG[i].push_back(c * nocc * dos);
2324 } else {
2325 cfElectronsG[i].push_back(0.);
2326 }
2327 // Emission
2328 if (en > eMinG + eph) {
2329 dos = GetConductionBandDensityOfStates(en - eph, nValleysX + nValleysL);
2330 cfElectronsG[i].push_back(c * (nocc + 1) * dos);
2331 } else {
2332 cfElectronsG[i].push_back(0.);
2333 }
2334 en += eStepG;
2335 }
2336
2337 // Absorption
2338 // energyLossElectronsL.push_back(-eph);
2339 energyLossElectronsG.push_back(-eph);
2340 // Emission
2341 // energyLossElectronsL.push_back(eph);
2342 energyLossElectronsG.push_back(eph);
2343 // scatTypeElectronsL.push_back(ElectronCollisionTypeOpticalPhonon);
2344 // scatTypeElectronsL.push_back(ElectronCollisionTypeOpticalPhonon);
2345 scatTypeElectronsG.push_back(ElectronCollisionTypeOpticalPhonon);
2346 scatTypeElectronsG.push_back(ElectronCollisionTypeOpticalPhonon);
2347
2348 // nLevelsL += 2;
2349 nLevelsG += 2;
2350
2351 return true;
2352}
2353
2354bool MediumSilicon::ElectronIntervalleyScatteringRatesXX() {
2355
2356 // Reference:
2357 // - C. Jacoboni and L. Reggiani,
2358 // Rev. Mod. Phys. 55, 645-705
2359
2360 // Mass density [(eV/c2)/cm3]
2361 const double rho = m_density * m_a * AtomicMassUnitElectronVolt;
2362 // Lattice temperature [eV]
2363 const double kbt = BoltzmannConstant * m_temperature;
2364
2365 const int nPhonons = 6;
2366 // f-type scattering: transition between orthogonal axes (multiplicity 4)
2367 // g-type scattering: transition between opposite axes (multiplicity 1)
2368 // Sequence of transitions in the table:
2369 // TA (g) - LA (g) - LO (g) - TA (f) - LA (f) - TO (f)
2370 // Coupling constants [eV/cm]
2371 const double dtk[nPhonons] = {0.5e8, 0.8e8, 1.1e9, 0.3e8, 2.0e8, 2.0e8};
2372 // Phonon energies [eV]
2373 const double eph[nPhonons] = {12.06e-3, 18.53e-3, 62.04e-3,
2374 18.86e-3, 47.39e-3, 59.03e-3};
2375 // Phonon cccupation numbers
2376 double nocc[nPhonons];
2377 // Prefactors
2378 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2379 double c[nPhonons];
2380
2381 for (int j = 0; j < nPhonons; ++j) {
2382 nocc[j] = 1. / (exp(eph[j] / kbt) - 1);
2383 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2384 if (j > 2) c[j] *= 4;
2385 }
2386
2387 double en = 0.;
2388 double dos = 0.;
2389 for (int i = 0; i < nEnergyStepsXL; ++i) {
2390 for (int j = 0; j < nPhonons; ++j) {
2391 // Absorption
2392 dos = GetConductionBandDensityOfStates(en + eph[j], 0);
2393 cfElectronsX[i].push_back(c[j] * nocc[j] * dos);
2394 // Emission
2395 if (en > eph[j]) {
2396 dos = GetConductionBandDensityOfStates(en - eph[j], 0);
2397 cfElectronsX[i].push_back(c[j] * (nocc[j] + 1) * dos);
2398 } else {
2399 cfElectronsX[i].push_back(0.);
2400 }
2401 }
2402 en += eStepXL;
2403 }
2404
2405 for (int j = 0; j < nPhonons; ++j) {
2406 // Absorption
2407 energyLossElectronsX.push_back(-eph[j]);
2408 // Emission
2409 energyLossElectronsX.push_back(eph[j]);
2410 if (j <= 2) {
2411 scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyG);
2412 scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyG);
2413 } else {
2414 scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyF);
2415 scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyF);
2416 }
2417 }
2418
2419 nLevelsX += 2 * nPhonons;
2420
2421 return true;
2422}
2423
2424bool MediumSilicon::ElectronIntervalleyScatteringRatesXL() {
2425
2426 // Reference:
2427 // - M. Lundstrom, Fundamentals of carrier transport
2428 // - M. Martin et al.,
2429 // Semicond. Sci. Technol. 8, 1291-1297
2430
2431 // Mass density [(eV/c2)/cm3]
2432 const double rho = m_density * m_a * AtomicMassUnitElectronVolt;
2433 // Lattice temperature [eV]
2434 const double kbt = BoltzmannConstant * m_temperature;
2435
2436 const int nPhonons = 4;
2437
2438 // Coupling constants [eV/cm]
2439 const double dtk[nPhonons] = {2.e8, 2.e8, 2.e8, 2.e8};
2440 // Phonon energies [eV]
2441 const double eph[nPhonons] = {58.e-3, 55.e-3, 41.e-3, 17.e-3};
2442 // Number of equivalent valleys
2443 const int zX = 6;
2444 const int zL = 8;
2445
2446 // Phonon cccupation numbers
2447 double nocc[nPhonons] = {0.};
2448 // Prefactors
2449 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2450 double c[nPhonons];
2451
2452 for (int j = 0; j < nPhonons; ++j) {
2453 nocc[j] = 1. / (exp(eph[j] / kbt) - 1);
2454 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2455 }
2456
2457 double en = 0.;
2458 double dos = 0.;
2459 for (int i = 0; i < nEnergyStepsXL; ++i) {
2460 for (int j = 0; j < nPhonons; ++j) {
2461 // XL
2462 // Absorption
2463 if (en + eph[j] > eMinL) {
2464 dos = GetConductionBandDensityOfStates(en + eph[j], nValleysX);
2465 cfElectronsX[i].push_back(zL * c[j] * nocc[j] * dos);
2466 } else {
2467 cfElectronsX[i].push_back(0.);
2468 }
2469 // Emission
2470 if (en - eph[j] > eMinL) {
2471 dos = GetConductionBandDensityOfStates(en - eph[j], nValleysX);
2472 cfElectronsX[i].push_back(zL * c[j] * (nocc[j] + 1) * dos);
2473 } else {
2474 cfElectronsX[i].push_back(0.);
2475 }
2476 // LX
2477 if (en > eMinL) {
2478 // Absorption
2479 dos = GetConductionBandDensityOfStates(en + eph[j], 0);
2480 cfElectronsL[i].push_back(zX * c[j] * nocc[j] * dos);
2481 // Emission
2482 dos = GetConductionBandDensityOfStates(en - eph[j], 0);
2483 cfElectronsL[i].push_back(zX * c[j] * (nocc[j] + 1) * dos);
2484 } else {
2485 cfElectronsL[i].push_back(0.);
2486 cfElectronsL[i].push_back(0.);
2487 }
2488 }
2489 en += eStepXL;
2490 }
2491
2492 for (int j = 0; j < nPhonons; ++j) {
2493 // Absorption
2494 energyLossElectronsX.push_back(-eph[j]);
2495 energyLossElectronsL.push_back(-eph[j]);
2496 // Emission
2497 energyLossElectronsX.push_back(eph[j]);
2498 energyLossElectronsL.push_back(eph[j]);
2499 scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXL);
2500 scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXL);
2501 scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandXL);
2502 scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandXL);
2503 }
2504
2505 nLevelsX += 2 * nPhonons;
2506 nLevelsL += 2 * nPhonons;
2507
2508 return true;
2509}
2510
2511bool MediumSilicon::ElectronIntervalleyScatteringRatesLL() {
2512
2513 // Reference:
2514 // - K. Hess (editor),
2515 // Monte Carlo device simulation: full band and beyond
2516 // Chapter 5
2517 // - M. J. Martin et al.,
2518 // Semicond. Sci. Technol. 8, 1291-1297
2519
2520 // Mass density [(eV/c2)/cm3]
2521 const double rho = m_density * m_a * AtomicMassUnitElectronVolt;
2522 // Lattice temperature [eV]
2523 const double kbt = BoltzmannConstant * m_temperature;
2524
2525 const int nPhonons = 1;
2526 // Coupling constant [eV/cm]
2527 const double dtk[nPhonons] = {2.63e8};
2528 // Phonon energy [eV]
2529 const double eph[nPhonons] = {38.87e-3};
2530 // Phonon cccupation numbers
2531 double nocc[nPhonons];
2532 // Prefactors
2533 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2534 double c[nPhonons];
2535
2536 for (int j = 0; j < nPhonons; ++j) {
2537 nocc[j] = 1. / (exp(eph[j] / kbt) - 1);
2538 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2539 c[j] *= 7;
2540 }
2541
2542 double en = 0.;
2543 double dos = 0.;
2544 for (int i = 0; i < nEnergyStepsXL; ++i) {
2545 for (int j = 0; j < nPhonons; ++j) {
2546 // Absorption
2547 dos = GetConductionBandDensityOfStates(en + eph[j], nValleysX);
2548 cfElectronsL[i].push_back(c[j] * nocc[j] * dos);
2549 // Emission
2550 if (en > eMinL + eph[j]) {
2551 dos = GetConductionBandDensityOfStates(en - eph[j], nValleysX);
2552 cfElectronsL[i].push_back(c[j] * (nocc[j] + 1) * dos);
2553 } else {
2554 cfElectronsL[i].push_back(0.);
2555 }
2556 }
2557 en += eStepXL;
2558 }
2559
2560 for (int j = 0; j < nPhonons; ++j) {
2561 // Absorption
2562 energyLossElectronsL.push_back(-eph[j]);
2563 // Emission
2564 energyLossElectronsL.push_back(eph[j]);
2565 scatTypeElectronsL.push_back(ElectronCollisionTypeIntervalleyF);
2566 scatTypeElectronsL.push_back(ElectronCollisionTypeIntervalleyF);
2567 }
2568
2569 nLevelsL += 2 * nPhonons;
2570
2571 return true;
2572}
2573
2574bool MediumSilicon::ElectronIntervalleyScatteringRatesXGLG() {
2575
2576 // Reference:
2577 // - K. Hess (editor),
2578 // Monte Carlo device simulation: full band and beyond
2579 // Chapter 5
2580
2581 // Mass density [(eV/c2)/cm3]
2582 const double rho = m_density * m_a * AtomicMassUnitElectronVolt;
2583 // Lattice temperature [eV]
2584 const double kbt = BoltzmannConstant * m_temperature;
2585
2586 const int nPhonons = 1;
2587
2588 // Coupling constants [eV/cm]
2589 // Average of XG and LG
2590 const double dtk[nPhonons] = {2.43e8};
2591 // Phonon energies [eV]
2592 const double eph[nPhonons] = {37.65e-3};
2593 // Number of equivalent valleys
2594 const int zX = 6;
2595 const int zL = 8;
2596 const int zG = 1;
2597
2598 // Phonon cccupation numbers
2599 double nocc[nPhonons] = {0.};
2600 // Prefactors
2601 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2602 double c[nPhonons];
2603
2604 for (int j = 0; j < nPhonons; ++j) {
2605 nocc[j] = 1. / (exp(eph[j] / kbt) - 1);
2606 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2607 }
2608
2609 double en = 0.;
2610 double dos = 0.;
2611 // XG, LG
2612 for (int i = 0; i < nEnergyStepsXL; ++i) {
2613 for (int j = 0; j < nPhonons; ++j) {
2614 // Absorption
2615 if (en + eph[j] > eMinG) {
2616 dos = GetConductionBandDensityOfStates(en + eph[j],
2617 nValleysX + nValleysL);
2618 cfElectronsX[i].push_back(zG * c[j] * nocc[j] * dos);
2619 cfElectronsL[i].push_back(zG * c[j] * nocc[j] * dos);
2620 } else {
2621 cfElectronsX[i].push_back(0.);
2622 cfElectronsL[i].push_back(0.);
2623 }
2624 // Emission
2625 if (en - eph[j] > eMinG) {
2626 dos = GetConductionBandDensityOfStates(en - eph[j],
2627 nValleysX + nValleysL);
2628 cfElectronsX[i].push_back(zG * c[j] * (nocc[j] + 1) * dos);
2629 cfElectronsL[i].push_back(zG * c[j] * (nocc[j] + 1) * dos);
2630 } else {
2631 cfElectronsX[i].push_back(0.);
2632 cfElectronsL[i].push_back(0.);
2633 }
2634 }
2635 en += eStepXL;
2636 }
2637
2638 // GX, GL
2639 en = 0.;
2640 double dosX = 0., dosL = 0.;
2641 for (int i = 0; i < nEnergyStepsG; ++i) {
2642 for (int j = 0; j < nPhonons; ++j) {
2643 // Absorption
2644 dosX = GetConductionBandDensityOfStates(en + eph[j], 0);
2645 dosL = GetConductionBandDensityOfStates(en + eph[j], nValleysX);
2646 cfElectronsG[i].push_back(zX * c[j] * nocc[j] * dosX);
2647 if (en > eMinL) {
2648 cfElectronsG[i].push_back(zL * c[j] * nocc[j] * dosL);
2649 } else {
2650 cfElectronsG[i].push_back(0.);
2651 }
2652 // Emission
2653 dosX = GetConductionBandDensityOfStates(en - eph[j], 0);
2654 dosL = GetConductionBandDensityOfStates(en - eph[j], nValleysX);
2655 if (en > eph[j]) {
2656 cfElectronsG[i].push_back(zX * c[j] * (nocc[j] + 1) * dosX);
2657 } else {
2658 cfElectronsG[i].push_back(0.);
2659 }
2660 if (en - eph[j] > eMinL) {
2661 cfElectronsG[i].push_back(zL * c[j] * (nocc[j] + 1) * dosL);
2662 } else {
2663 cfElectronsG[i].push_back(0.);
2664 }
2665 }
2666 en += eStepG;
2667 }
2668
2669 for (int j = 0; j < nPhonons; ++j) {
2670 // Absorption (XL)
2671 energyLossElectronsX.push_back(-eph[j]);
2672 energyLossElectronsL.push_back(-eph[j]);
2673 // Emission (XL)
2674 energyLossElectronsX.push_back(eph[j]);
2675 energyLossElectronsL.push_back(eph[j]);
2676 // Absorption (G)
2677 energyLossElectronsG.push_back(-eph[j]);
2678 energyLossElectronsG.push_back(-eph[j]);
2679 // Emission (G)
2680 energyLossElectronsG.push_back(eph[j]);
2681 energyLossElectronsG.push_back(eph[j]);
2682
2683 scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXG);
2684 scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXG);
2685 scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandLG);
2686 scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandLG);
2687
2688 scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandXG);
2689 scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandLG);
2690 scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandXG);
2691 scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandLG);
2692 }
2693
2694 nLevelsX += 2 * nPhonons;
2695 nLevelsL += 2 * nPhonons;
2696 nLevelsG += 4 * nPhonons;
2697
2698 return true;
2699}
2700
2701bool MediumSilicon::ElectronIonisationRatesXL() {
2702
2703 // References:
2704 // - E. Cartier, M. V. Fischetti, E. A. Eklund and F. R. McFeely,
2705 // Appl. Phys. Lett 62, 3339-3341
2706 // - DAMOCLES web page: www.research.ibm.com/DAMOCLES
2707
2708 // Coefficients [ns-1]
2709 const double p[3] = {6.25e1, 3.e3, 6.8e5};
2710 // Threshold energies [eV]
2711 const double eth[3] = {1.2, 1.8, 3.45};
2712
2713 double en = 0.;
2714 for (int i = 0; i < nEnergyStepsXL; ++i) {
2715 double fIon = 0.;
2716 if (en > eth[0]) {
2717 fIon += p[0] * (en - eth[0]) * (en - eth[0]);
2718 }
2719 if (en > eth[1]) {
2720 fIon += p[1] * (en - eth[1]) * (en - eth[1]);
2721 }
2722 if (en > eth[2]) {
2723 fIon += p[2] * (en - eth[2]) * (en - eth[2]);
2724 }
2725 cfElectronsX[i].push_back(fIon);
2726 cfElectronsL[i].push_back(fIon);
2727 en += eStepXL;
2728 }
2729
2730 energyLossElectronsX.push_back(eth[0]);
2731 energyLossElectronsL.push_back(eth[0]);
2732 scatTypeElectronsX.push_back(ElectronCollisionTypeIonisation);
2733 scatTypeElectronsL.push_back(ElectronCollisionTypeIonisation);
2734 ++nLevelsX;
2735 ++nLevelsL;
2736
2737 return true;
2738}
2739
2740bool MediumSilicon::ElectronIonisationRatesG() {
2741
2742 // References:
2743 // - E. Cartier, M. V. Fischetti, E. A. Eklund and F. R. McFeely,
2744 // Appl. Phys. Lett 62, 3339-3341
2745 // - S. Tanuma, C. J. Powell and D. R. Penn
2746 // Surf. Interface Anal. (2010)
2747
2748 // Coefficients [ns-1]
2749 const double p[3] = {6.25e1, 3.e3, 6.8e5};
2750 // Threshold energies [eV]
2751 const double eth[3] = {1.2, 1.8, 3.45};
2752
2753 double en = 0.;
2754 for (int i = 0; i < nEnergyStepsG; ++i) {
2755 double fIon = 0.;
2756 if (en > eth[0]) {
2757 fIon += p[0] * (en - eth[0]) * (en - eth[0]);
2758 }
2759 if (en > eth[1]) {
2760 fIon += p[1] * (en - eth[1]) * (en - eth[1]);
2761 }
2762 if (en > eth[2]) {
2763 fIon += p[2] * (en - eth[2]) * (en - eth[2]);
2764 }
2765 if (en >= eMinG) {
2766 cfElectronsG[i].push_back(fIon);
2767 } else {
2768 cfElectronsG[i].push_back(0.);
2769 }
2770 en += eStepG;
2771 }
2772
2773 energyLossElectronsG.push_back(eth[0]);
2774 scatTypeElectronsG.push_back(ElectronCollisionTypeIonisation);
2775 ++nLevelsG;
2776
2777 return true;
2778}
2779
2780bool MediumSilicon::ElectronImpurityScatteringRates() {
2781
2782 // Lattice temperature [eV]
2783 const double kbt = BoltzmannConstant * m_temperature;
2784
2785 // Band parameters
2786 // Density of states effective masses
2787 const double mdX = ElectronMass * pow(mLongX * mTransX * mTransX, 1. / 3.);
2788 const double mdL = ElectronMass * pow(mLongL * mTransL * mTransL, 1. / 3.);
2789
2790 // Dielectric constant
2791 const double eps = GetDielectricConstant();
2792 // Impurity concentration
2793 const double impurityConcentration = m_dopingConcentration;
2794 if (impurityConcentration < Small) return true;
2795
2796 // Screening length
2797 const double ls = sqrt(eps * kbt / (4 * Pi * FineStructureConstant * HbarC *
2798 impurityConcentration));
2799 const double ebX = 0.5 * HbarC * HbarC / (mdX * ls * ls);
2800 const double ebL = 0.5 * HbarC * HbarC / (mdL * ls * ls);
2801
2802 // Prefactor
2803 // const double c = pow(2., 2.5) * Pi * impurityConcentration *
2804 // pow(FineStructureConstant * HbarC, 2) *
2805 // SpeedOfLight / (eps * eps * sqrt(md) * eb * eb);
2806 // Use momentum-transfer cross-section
2807 const double cX = impurityConcentration * Pi *
2808 pow(FineStructureConstant * HbarC, 2) * SpeedOfLight /
2809 (sqrt(2 * mdX) * eps * eps);
2810 const double cL = impurityConcentration * Pi *
2811 pow(FineStructureConstant * HbarC, 2) * SpeedOfLight /
2812 (sqrt(2 * mdL) * eps * eps);
2813
2814 double en = 0.;
2815 for (int i = 0; i < nEnergyStepsXL; ++i) {
2816 const double gammaX = en * (1. + alphaX * en);
2817 const double gammaL = (en - eMinL) * (1. + alphaL * (en - eMinL));
2818 // cfElectrons[i][iLevel] = c * sqrt(gamma) * (1. + 2 * alpha * en) /
2819 // (1. + 4. * gamma / eb);
2820 if (gammaX <= 0.) {
2821 cfElectronsX[i].push_back(0.);
2822 } else {
2823 const double b = 4 * gammaX / ebX;
2824 cfElectronsX[i]
2825 .push_back((cX / pow(gammaX, 1.5)) * (log(1. + b) - b / (1. + b)));
2826 }
2827 if (en <= eMinL || gammaL <= 0.) {
2828 cfElectronsL[i].push_back(0.);
2829 } else {
2830 const double b = 4 * gammaL / ebL;
2831 cfElectronsL[i]
2832 .push_back((cL / pow(gammaL, 1.5)) * (log(1. + b) - b / (1. + b)));
2833 }
2834 en += eStepXL;
2835 }
2836
2837 energyLossElectronsX.push_back(0.);
2838 energyLossElectronsL.push_back(0.);
2839 scatTypeElectronsX.push_back(ElectronCollisionTypeImpurity);
2840 scatTypeElectronsL.push_back(ElectronCollisionTypeImpurity);
2841 ++nLevelsX;
2842 ++nLevelsL;
2843
2844 return true;
2845}
2846
2847bool MediumSilicon::HoleScatteringRates() {
2848
2849 // Reset the scattering rates
2850 cfTotHoles.resize(nEnergyStepsV);
2851 cfHoles.resize(nEnergyStepsV);
2852 for (int i = nEnergyStepsV; i--;) {
2853 cfTotHoles[i] = 0.;
2854 cfHoles[i].clear();
2855 }
2856 energyLossHoles.clear();
2857 scatTypeHoles.clear();
2858 cfNullHoles = 0.;
2859
2860 nLevelsV = 0;
2861 // Fill the scattering rates table
2862 HoleAcousticScatteringRates();
2863 HoleOpticalScatteringRates();
2864 // HoleImpurityScatteringRates();
2865 HoleIonisationRates();
2866
2867 std::ofstream outfile;
2868 if (useCfOutput) {
2869 outfile.open("ratesV.txt", std::ios::out);
2870 }
2871
2872 for (int i = 0; i < nEnergyStepsV; ++i) {
2873 // Sum up the scattering rates of all processes.
2874 for (int j = nLevelsV; j--;) cfTotHoles[i] += cfHoles[i][j];
2875
2876 if (useCfOutput) {
2877 outfile << i* eStepV << " " << cfTotHoles[i] << " ";
2878 for (int j = 0; j < nLevelsV; ++j) {
2879 outfile << cfHoles[i][j] << " ";
2880 }
2881 outfile << "\n";
2882 }
2883
2884 if (cfTotHoles[i] > cfNullHoles) {
2885 cfNullHoles = cfTotHoles[i];
2886 }
2887
2888 // Make sure the total scattering rate is positive.
2889 if (cfTotHoles[i] <= 0.) {
2890 std::cerr << m_className << "::HoleScatteringRates:\n";
2891 std::cerr << " Scattering rate at " << i* eStepV << " eV <= 0.\n";
2892 return false;
2893 }
2894 // Normalise the rates.
2895 for (int j = 0; j < nLevelsV; ++j) {
2896 cfHoles[i][j] /= cfTotHoles[i];
2897 if (j > 0) cfHoles[i][j] += cfHoles[i][j - 1];
2898 }
2899 }
2900
2901 if (useCfOutput) {
2902 outfile.close();
2903 }
2904
2905 return true;
2906}
2907
2908bool MediumSilicon::HoleAcousticScatteringRates() {
2909
2910 // Reference:
2911 // - C. Jacoboni and L. Reggiani,
2912 // Rev. Mod. Phys. 55, 645-705
2913 // - DAMOCLES web page: www.research.ibm.com/DAMOCLES
2914 // - M. Lundstrom, Fundamentals of carrier transport
2915
2916 // Mass density [(eV/c2)/cm3]
2917 const double rho = m_density * m_a * AtomicMassUnitElectronVolt;
2918 // Lattice temperature [eV]
2919 const double kbt = BoltzmannConstant * m_temperature;
2920
2921 // Acoustic phonon intraband scattering
2922 // Acoustic deformation potential [eV]
2923 // DAMOCLES: 4.6 eV; Lundstrom: 5 eV
2924 const double defpot = 4.6;
2925 // Longitudinal velocity of sound [cm/ns]
2926 const double u = 9.04e-4;
2927 // Prefactor for acoustic deformation potential scattering
2928 const double cIntra = TwoPi * SpeedOfLight * SpeedOfLight * kbt * defpot *
2929 defpot / (Hbar * u * u * rho);
2930
2931 // Fill the scattering rate tables.
2932 double en = Small;
2933 for (int i = 0; i < nEnergyStepsV; ++i) {
2934 const double dos = GetValenceBandDensityOfStates(en, 0);
2935 cfHoles[i].push_back(cIntra * dos);
2936 en += eStepV;
2937 }
2938
2939 // Assume that energy loss is negligible.
2940 energyLossHoles.push_back(0.);
2941 scatTypeHoles.push_back(ElectronCollisionTypeAcousticPhonon);
2942 ++nLevelsV;
2943
2944 return true;
2945}
2946
2947bool MediumSilicon::HoleOpticalScatteringRates() {
2948
2949 // Reference:
2950 // - C. Jacoboni and L. Reggiani,
2951 // Rev. Mod. Phys. 55, 645-705
2952 // - DAMOCLES web page: www.research.ibm.com/DAMOCLES
2953 // - M. Lundstrom, Fundamentals of carrier transport
2954
2955 // Mass density [(eV/c2)/cm3]
2956 const double rho = m_density * m_a * AtomicMassUnitElectronVolt;
2957 // Lattice temperature [eV]
2958 const double kbt = BoltzmannConstant * m_temperature;
2959
2960 // Coupling constant [eV/cm]
2961 // DAMOCLES: 6.6, Lundstrom: 6.0
2962 const double dtk = 6.6e8;
2963 // Phonon energy [eV]
2964 const double eph = 63.0e-3;
2965 // Phonon cccupation numbers
2966 const double nocc = 1. / (exp(eph / kbt) - 1);
2967 // Prefactors
2968 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2969 double c = c0 * dtk * dtk / eph;
2970
2971 double en = 0.;
2972 double dos = 0.;
2973 for (int i = 0; i < nEnergyStepsV; ++i) {
2974 // Absorption
2975 dos = GetValenceBandDensityOfStates(en + eph, 0);
2976 cfHoles[i].push_back(c * nocc * dos);
2977 // Emission
2978 if (en > eph) {
2979 dos = GetValenceBandDensityOfStates(en - eph, 0);
2980 cfHoles[i].push_back(c * (nocc + 1) * dos);
2981 } else {
2982 cfHoles[i].push_back(0.);
2983 }
2984 en += eStepV;
2985 }
2986
2987 // Absorption
2988 energyLossHoles.push_back(-eph);
2989 // Emission
2990 energyLossHoles.push_back(eph);
2991 scatTypeHoles.push_back(ElectronCollisionTypeOpticalPhonon);
2992 scatTypeHoles.push_back(ElectronCollisionTypeOpticalPhonon);
2993
2994 nLevelsV += 2;
2995
2996 return true;
2997}
2998
2999bool MediumSilicon::HoleIonisationRates() {
3000
3001 // References:
3002 // - DAMOCLES web page: www.research.ibm.com/DAMOCLES
3003
3004 // Coefficients [ns-1]
3005 const double p[2] = {2., 1.e3};
3006 // Threshold energies [eV]
3007 const double eth[2] = {1.1, 1.45};
3008 // Exponents
3009 const double b[2] = {6., 4.};
3010
3011 double en = 0.;
3012 for (int i = 0; i < nEnergyStepsV; ++i) {
3013 double fIon = 0.;
3014 if (en > eth[0]) {
3015 fIon += p[0] * pow(en - eth[0], b[0]);
3016 }
3017 if (en > eth[1]) {
3018 fIon += p[1] * pow(en - eth[1], b[1]);
3019 }
3020 cfHoles[i].push_back(fIon);
3021 en += eStepV;
3022 }
3023
3024 energyLossHoles.push_back(eth[0]);
3025 scatTypeHoles.push_back(ElectronCollisionTypeIonisation);
3026 ++nLevelsV;
3027
3028 return true;
3029}
3030
3032 const int band) {
3033 if (band < 0) {
3034 int iE = int(e / eStepDos);
3035 if (iE >= nFbDosEntriesConduction || iE < 0) {
3036 return 0.;
3037 } else if (iE == nFbDosEntriesConduction - 1) {
3038 return fbDosConduction[nFbDosEntriesConduction - 1];
3039 }
3040
3041 const double dos =
3042 fbDosConduction[iE] +
3043 (fbDosConduction[iE + 1] - fbDosConduction[iE]) * (e / eStepDos - iE);
3044 return dos * 1.e21;
3045
3046 } else if (band < nValleysX) {
3047 // X valleys
3048 if (e <= 0.) return 0.;
3049 // Density-of-states effective mass (cube)
3050 const double md3 = pow(ElectronMass, 3) * mLongX * mTransX * mTransX;
3051
3052 if (useFullBandDos) {
3053 if (e < eMinL) {
3054 return GetConductionBandDensityOfStates(e, -1) / nValleysX;
3055 } else if (e < eMinG) {
3056 // Subtract the fraction of the full-band density of states
3057 // attributed to the L valleys.
3058 const double dosX =
3060 GetConductionBandDensityOfStates(e, nValleysX) * nValleysL;
3061 return dosX / nValleysX;
3062 } else {
3063 // Subtract the fraction of the full-band density of states
3064 // attributed to the L valleys and the higher bands.
3065 const double dosX =
3067 GetConductionBandDensityOfStates(e, nValleysX) * nValleysL -
3068 GetConductionBandDensityOfStates(e, nValleysX + nValleysL);
3069 if (dosX <= 0.) return 0.;
3070 return dosX / nValleysX;
3071 }
3072 } else if (useNonParabolicity) {
3073 const double alpha = alphaX;
3074 return sqrt(md3 * e * (1. + alpha * e) / 2.) * (1. + 2 * alpha * e) /
3075 (Pi2 * pow(HbarC, 3.));
3076 } else {
3077 return sqrt(md3 * e / 2.) / (Pi2 * pow(HbarC, 3.));
3078 }
3079 } else if (band < nValleysX + nValleysL) {
3080 // L valleys
3081 if (e <= eMinL) return 0.;
3082
3083 // Density-of-states effective mass (cube)
3084 const double md3 = pow(ElectronMass, 3) * mLongL * mTransL * mTransL;
3085 // Non-parabolicity parameter
3086 const double alpha = alphaL;
3087
3088 if (useFullBandDos) {
3089 // Energy up to which the non-parabolic approximation is used.
3090 const double ej = eMinL + 0.5;
3091 if (e <= ej) {
3092 return sqrt(md3 * (e - eMinL) * (1. + alpha * (e - eMinL))) *
3093 (1. + 2 * alpha * (e - eMinL)) / (Sqrt2 * Pi2 * pow(HbarC, 3.));
3094 } else {
3095 // Fraction of full-band density of states attributed to L valleys
3096 double fL = sqrt(md3 * (ej - eMinL) * (1. + alpha * (ej - eMinL))) *
3097 (1. + 2 * alpha * (ej - eMinL)) /
3098 (Sqrt2 * Pi2 * pow(HbarC, 3.));
3099 fL = nValleysL * fL / GetConductionBandDensityOfStates(ej, -1);
3100
3101 double dosXL = GetConductionBandDensityOfStates(e, -1);
3102 if (e > eMinG) {
3103 dosXL -= GetConductionBandDensityOfStates(e, nValleysX + nValleysL);
3104 }
3105 if (dosXL <= 0.) return 0.;
3106 return fL * dosXL / 8.;
3107 }
3108 } else if (useNonParabolicity) {
3109 return sqrt(md3 * (e - eMinL) * (1. + alpha * (e - eMinL))) *
3110 (1. + 2 * alpha * (e - eMinL)) / (Sqrt2 * Pi2 * pow(HbarC, 3.));
3111 } else {
3112 return sqrt(md3 * (e - eMinL) / 2.) / (Pi2 * pow(HbarC, 3.));
3113 }
3114 } else if (band == nValleysX + nValleysL) {
3115 // Higher bands
3116 const double ej = 2.7;
3117 if (eMinG >= ej) {
3118 std::cerr << m_className << "::GetConductionBandDensityOfStates:\n";
3119 std::cerr << " Cannot determine higher band density-of-states.\n";
3120 std::cerr << " Program bug. Check offset energy!\n";
3121 return 0.;
3122 }
3123 if (e < eMinG) {
3124 return 0.;
3125 } else if (e < ej) {
3126 // Coexistence of XL and higher bands.
3127 const double dj = GetConductionBandDensityOfStates(ej, -1);
3128 // Assume linear increase of density-of-states.
3129 return dj * (e - eMinG) / (ej - eMinG);
3130 } else {
3132 }
3133 }
3134
3135 std::cerr << m_className << "::GetConductionBandDensityOfStates:\n";
3136 std::cerr << " Band index (" << band << ") out of range.\n";
3137 return ElectronMass * sqrt(ElectronMass * e / 2.) / (Pi2 * pow(HbarC, 3.));
3138}
3139
3141 const int band) {
3142
3143 if (band <= 0) {
3144 // Total (full-band) density of states.
3145
3146 int iE = int(e / eStepDos);
3147 if (iE >= nFbDosEntriesValence || iE < 0) {
3148 return 0.;
3149 } else if (iE == nFbDosEntriesValence - 1) {
3150 return fbDosValence[nFbDosEntriesValence - 1];
3151 }
3152
3153 const double dos =
3154 fbDosValence[iE] +
3155 (fbDosValence[iE + 1] - fbDosValence[iE]) * (e / eStepDos - iE);
3156 return dos * 1.e21;
3157 }
3158
3159 std::cerr << m_className << "::GetConductionBandDensityOfStates:\n";
3160 std::cerr << " Band index (" << band << ") out of range.\n";
3161 return 0.;
3162}
3163
3164void MediumSilicon::ComputeSecondaries(const double e0, double& ee,
3165 double& eh) {
3166
3167 const double widthValenceBand = eStepDos * nFbDosEntriesValence;
3168 const double widthConductionBand = eStepDos * nFbDosEntriesConduction;
3169
3170 bool ok = false;
3171 while (!ok) {
3172 // Sample a hole energy according to the valence band DOS.
3173 eh = RndmUniformPos() * std::min(widthValenceBand, e0);
3174 int ih = std::min(int(eh / eStepDos), nFbDosEntriesValence - 1);
3175 while (RndmUniform() > fbDosValence[ih] / fbDosMaxV) {
3176 eh = RndmUniformPos() * std::min(widthValenceBand, e0);
3177 ih = std::min(int(eh / eStepDos), nFbDosEntriesValence - 1);
3178 }
3179 // Sample an electron energy according to the conduction band DOS.
3180 ee = RndmUniformPos() * std::min(widthConductionBand, e0);
3181 int ie = std::min(int(ee / eStepDos), nFbDosEntriesConduction - 1);
3182 while (RndmUniform() > fbDosConduction[ie] / fbDosMaxC) {
3183 ee = RndmUniformPos() * std::min(widthConductionBand, e0);
3184 ie = std::min(int(ee / eStepDos), nFbDosEntriesConduction - 1);
3185 }
3186 // Calculate the energy of the primary electron.
3187 const double ep = e0 - m_bandGap - eh - ee;
3188 if (ep < Small) continue;
3189 if (ep > 5.) return;
3190 // Check if the primary electron energy is consistent with the DOS.
3191 int ip = std::min(int(ep / eStepDos), nFbDosEntriesConduction - 1);
3192 if (RndmUniform() > fbDosConduction[ip] / fbDosMaxC) continue;
3193 ok = true;
3194 }
3195}
3196
3197void MediumSilicon::InitialiseDensityOfStates() {
3198
3199 eStepDos = 0.1;
3200
3201 const int nFbDosEntriesV = 83;
3202 const double fbDosV[nFbDosEntriesV] = {
3203 0., 1.28083, 2.08928, 2.70763, 3.28095, 3.89162, 4.50547, 5.15043,
3204 5.89314, 6.72667, 7.67768, 8.82725, 10.6468, 12.7003, 13.7457, 14.0263,
3205 14.2731, 14.5527, 14.8808, 15.1487, 15.4486, 15.7675, 16.0519, 16.4259,
3206 16.7538, 17.0589, 17.3639, 17.6664, 18.0376, 18.4174, 18.2334, 16.7552,
3207 15.1757, 14.2853, 13.6516, 13.2525, 12.9036, 12.7203, 12.6104, 12.6881,
3208 13.2862, 14.0222, 14.9366, 13.5084, 9.77808, 6.15266, 3.47839, 2.60183,
3209 2.76747, 3.13985, 3.22524, 3.29119, 3.40868, 3.6118, 3.8464, 4.05776,
3210 4.3046, 4.56219, 4.81553, 5.09909, 5.37616, 5.67297, 6.04611, 6.47252,
3211 6.9256, 7.51254, 8.17923, 8.92351, 10.0309, 11.726, 16.2853, 18.2457,
3212 12.8879, 7.86019, 6.02275, 5.21777, 4.79054, 3.976, 3.11855, 2.46854,
3213 1.65381, 0.830278, 0.217735};
3214
3215 // Total (full-band) density of states.
3216 const int nFbDosEntriesC = 101;
3217 const double fbDosC[nFbDosEntriesC] = {
3218 0., 1.5114, 2.71026, 3.67114, 4.40173, 5.05025, 5.6849, 6.28358,
3219 6.84628, 7.43859, 8.00204, 8.80658, 9.84885, 10.9579, 12.0302, 13.2051,
3220 14.6948, 16.9879, 18.4492, 18.1933, 17.6747, 16.8135, 15.736, 14.4965,
3221 13.1193, 12.1817, 12.6109, 15.3148, 19.4936, 23.0093, 24.4106, 22.2834,
3222 19.521, 18.9894, 18.8015, 17.9363, 17.0252, 15.9871, 14.8486, 14.3797,
3223 14.2426, 14.3571, 14.7271, 14.681, 14.3827, 14.2789, 14.144, 14.1684,
3224 14.1418, 13.9237, 13.7558, 13.5691, 13.4567, 13.2693, 12.844, 12.4006,
3225 12.045, 11.7729, 11.3607, 11.14, 11.0586, 10.5475, 9.73786, 9.34423,
3226 9.4694, 9.58071, 9.6967, 9.84854, 10.0204, 9.82705, 9.09102, 8.30665,
3227 7.67306, 7.18925, 6.79675, 6.40713, 6.21687, 6.33267, 6.5223, 6.17877,
3228 5.48659, 4.92208, 4.44239, 4.02941, 3.5692, 3.05953, 2.6428, 2.36979,
3229 2.16273, 2.00627, 1.85206, 1.71265, 1.59497, 1.46681, 1.34913, 1.23951,
3230 1.13439, 1.03789, 0.924155, 0.834962, 0.751017};
3231
3232 nFbDosEntriesValence = nFbDosEntriesV;
3233 nFbDosEntriesConduction = nFbDosEntriesC;
3234 fbDosValence.resize(nFbDosEntriesValence);
3235 fbDosConduction.resize(nFbDosEntriesConduction);
3236 fbDosMaxV = fbDosV[nFbDosEntriesV - 1];
3237 fbDosMaxC = fbDosC[nFbDosEntriesC - 1];
3238 for (int i = nFbDosEntriesV; i--;) {
3239 fbDosValence[i] = fbDosV[i];
3240 if (fbDosV[i] > fbDosMaxV) fbDosMaxV = fbDosV[i];
3241 }
3242 for (int i = nFbDosEntriesC; i--;) {
3243 fbDosConduction[i] = fbDosC[i];
3244 if (fbDosC[i] > fbDosMaxC) fbDosMaxC = fbDosC[i];
3245 }
3246}
3247}
DoubleAc cos(const DoubleAc &f)
Definition: DoubleAc.cpp:431
DoubleAc pow(const DoubleAc &f, double p)
Definition: DoubleAc.cpp:336
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:313
DoubleAc sin(const DoubleAc &f)
Definition: DoubleAc.cpp:383
DoubleAc exp(const DoubleAc &f)
Definition: DoubleAc.cpp:376
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)
void SetTrappingTime(const double &etau, const double &htau)
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)
void GetDoping(char &type, double &c) const
void SetHighFieldMobilityModelReggiani()
bool HoleAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
void SetSaturationVelocityModelReggiani()
double GetValenceBandDensityOfStates(const double e, const int band=-1)
double GetElectronNullCollisionRate(const int band)
bool GetDielectricFunction(const double &e, double &eps1, double &eps2, const unsigned int &i=0)
void SetSaturationVelocity(const double vsate, const double vsath)
bool ElectronAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
void ComputeSecondaries(const double e0, double &ee, double &eh)
bool HoleTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
double GetElectronEnergy(const double px, const double py, const double pz, double &vx, double &vy, double &vz, const int band=0)
void SetDoping(const char &type, const double &c)
void SetTrapDensity(const double &n)
double GetConductionBandDensityOfStates(const double e, const int band=0)
bool SetMaxElectronEnergy(const double e)
void SetHighFieldMobilityModelConstant()
bool GetIonisationProduct(const int i, int &type, double &energy)
void SetImpactIonisationModelVanOverstraetenDeMan()
bool GetOpticalDataRange(double &emin, double &emax, const unsigned int &i=0)
void SetTrapCrossSection(const double &ecs, const double &hcs)
void SetSaturationVelocityModelMinimos()
void SetLowFieldMobility(const double mue, const double muh)
double GetElectronCollisionRate(const double e, const int band)
bool ElectronTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
void GetElectronMomentum(const double e, double &px, double &py, double &pz, int &band)
int GetNumberOfElectronCollisions() const
int GetElectronBandPopulation(const int band)
bool GetElectronCollision(const double e, int &type, int &level, double &e1, double &dx, double &dy, double &dz, int &nion, int &ndxc, int &band)
double m_density
Definition: Medium.hh:305
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
double GetDielectricConstant() const
Definition: Medium.hh:34
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
double m_temperature
Definition: Medium.hh:293
double RndmUniform()
Definition: Random.hh:16
double RndmUniformPos()
Definition: Random.hh:19