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