19 m_dopingConcentration(0.),
26 m_eLatticeMobility(1.35e-6),
27 m_hLatticeMobility(0.45e-6),
32 m_eBetaCanaliInv(1. / 1.109),
33 m_hBetaCanaliInv(1. / 1.213),
40 m_eTrapDensity(1.e13),
41 m_hTrapDensity(1.e13),
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),
63 m_useNonParabolicity(true),
64 m_useFullBandDos(true),
65 m_useAnisotropy(true),
67 m_eStepXL(m_eFinalXL / nEnergyStepsXL),
69 m_eStepG(m_eFinalG / nEnergyStepsG),
71 m_eStepV(m_eFinalV / nEnergyStepsV),
82 m_opticalDataFile(
"OpticalData_Si.txt") {
100 m_cfTotElectronsX.clear();
101 m_cfElectronsX.clear();
102 m_energyLossElectronsX.clear();
103 m_scatTypeElectronsX.clear();
105 m_cfTotElectronsL.clear();
106 m_cfElectronsL.clear();
107 m_energyLossElectronsL.clear();
108 m_scatTypeElectronsL.clear();
110 m_cfTotElectronsG.clear();
111 m_cfElectronsG.clear();
112 m_energyLossElectronsG.clear();
113 m_scatTypeElectronsG.clear();
115 m_ieMinL = int(m_eMinL / m_eStepXL) + 1;
116 m_ieMinG = int(m_eMinG / m_eStepG) + 1;
118 m_cfTotHoles.clear();
120 m_energyLossHoles.clear();
121 m_scatTypeHoles.clear();
124 InitialiseDensityOfStates();
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();
134 m_ionProducts.clear();
139 if (toupper(type) ==
'N') {
142 m_dopingConcentration = c;
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;
150 }
else if (toupper(type) ==
'P') {
153 m_dopingConcentration = c;
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;
161 }
else if (toupper(type) ==
'I') {
163 m_dopingConcentration = 0.;
166 <<
" Unknown dopant type (" << type <<
").\n"
167 <<
" Available types are n, p and i (intrinsic).\n";
177 c = m_dopingConcentration;
183 std::cerr <<
m_className <<
"::SetTrapCrossSection:\n"
184 <<
" Capture cross-section [cm2] must non-negative.\n";
190 std::cerr <<
m_className <<
"::SetTrapCrossSection:\n"
191 <<
" Capture cross-section [cm2] must be non-negative.n";
204 <<
" Trap density [cm-3] must be non-negative.\n";
218 <<
" Trapping time [ns-1] must be positive.\n";
225 <<
" Trapping time [ns-1] must be positive.\n";
235 const double ez,
const double bx,
236 const double by,
const double bz,
237 double& vx,
double& vy,
double& vz) {
241 if (!UpdateTransportParameters()) {
242 std::cerr <<
m_className <<
"::ElectronVelocity:\n"
243 <<
" Error calculating the transport parameters.\n";
254 const double e = sqrt(ex * ex + ey * ey + ez * ez);
258 switch (m_highFieldMobilityModel) {
259 case HighFieldMobilityModelMinimos:
260 ElectronMobilityMinimos(e, mu);
262 case HighFieldMobilityModelCanali:
263 ElectronMobilityCanali(e, mu);
265 case HighFieldMobilityModelReggiani:
266 ElectronMobilityReggiani(e, mu);
274 const double b = sqrt(bx * bx + by * by + bz * bz);
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);
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;
293 const double ez,
const double bx,
294 const double by,
const double bz,
299 if (!UpdateTransportParameters()) {
300 std::cerr <<
m_className <<
"::ElectronTownsend:\n"
301 <<
" Error calculating the transport parameters.\n";
312 const double e = sqrt(ex * ex + ey * ey + ez * ez);
314 switch (m_impactIonisationModel) {
315 case ImpactIonisationModelVanOverstraeten:
316 return ElectronImpactIonisationVanOverstraetenDeMan(e, alpha);
318 case ImpactIonisationModelGrant:
319 return ElectronImpactIonisationGrant(e, alpha);
322 std::cerr <<
m_className <<
"::ElectronTownsend:\n"
323 <<
" Unknown model. Program bug!\n";
330 const double ez,
const double bx,
331 const double by,
const double bz,
336 if (!UpdateTransportParameters()) {
337 std::cerr <<
m_className <<
"::ElectronAttachment:\n"
338 <<
" Error calculating the transport parameters.\n";
349 switch (m_trappingModel) {
351 eta = m_eTrapCs * m_eTrapDensity;
356 eta = m_eTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
357 if (eta > 0.) eta = 1. / eta;
360 std::cerr <<
m_className <<
"::ElectronAttachment:\n"
361 <<
" Unknown model. Program bug!\n";
370 const double ez,
const double bx,
371 const double by,
const double bz,
double& vx,
372 double& vy,
double& vz) {
376 if (!UpdateTransportParameters()) {
378 <<
" Error calculating the transport parameters.\n";
389 const double e = sqrt(ex * ex + ey * ey + ez * ez);
393 switch (m_highFieldMobilityModel) {
394 case HighFieldMobilityModelMinimos:
395 HoleMobilityMinimos(e, mu);
397 case HighFieldMobilityModelCanali:
398 HoleMobilityCanali(e, mu);
400 case HighFieldMobilityModelReggiani:
401 HoleMobilityReggiani(e, mu);
407 const double b = sqrt(bx * bx + by * by + bz * bz);
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);
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;
426 const double ez,
const double bx,
427 const double by,
const double bz,
432 if (!UpdateTransportParameters()) {
434 <<
" Error calculating the transport parameters.\n";
445 const double e = sqrt(ex * ex + ey * ey + ez * ez);
447 switch (m_impactIonisationModel) {
448 case ImpactIonisationModelVanOverstraeten:
449 return HoleImpactIonisationVanOverstraetenDeMan(e, alpha);
451 case ImpactIonisationModelGrant:
452 return HoleImpactIonisationGrant(e, alpha);
456 <<
" Unknown model. Program bug!\n";
463 const double ez,
const double bx,
464 const double by,
const double bz,
469 if (!UpdateTransportParameters()) {
471 <<
" Error calculating the transport parameters.\n";
482 switch (m_trappingModel) {
484 eta = m_hTrapCs * m_hTrapDensity;
489 eta = m_hTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
490 if (eta > 0.) eta = 1. / eta;
494 <<
" Unknown model. Program bug!\n";
504 if (mue <= 0. || muh <= 0.) {
505 std::cerr <<
m_className <<
"::SetLowFieldMobility:\n"
506 <<
" Mobility must be greater than zero.\n";
512 m_hasUserMobility =
true;
518 m_latticeMobilityModel = LatticeMobilityModelMinimos;
519 m_hasUserMobility =
false;
525 m_latticeMobilityModel = LatticeMobilityModelSentaurus;
526 m_hasUserMobility =
false;
532 m_latticeMobilityModel = LatticeMobilityModelReggiani;
533 m_hasUserMobility =
false;
539 m_dopingMobilityModel = DopingMobilityModelMinimos;
540 m_hasUserMobility =
false;
546 m_dopingMobilityModel = DopingMobilityModelMasetti;
547 m_hasUserMobility =
false;
552 const double vsath) {
554 if (vsate <= 0. || vsath <= 0.) {
555 std::cout <<
m_className <<
"::SetSaturationVelocity:\n"
556 <<
" Restoring default values.\n";
557 m_hasUserSaturationVelocity =
false;
561 m_hasUserSaturationVelocity =
true;
569 m_saturationVelocityModel = SaturationVelocityModelMinimos;
570 m_hasUserSaturationVelocity =
false;
576 m_saturationVelocityModel = SaturationVelocityModelCanali;
577 m_hasUserSaturationVelocity =
false;
583 m_saturationVelocityModel = SaturationVelocityModelReggiani;
584 m_hasUserSaturationVelocity =
false;
590 m_highFieldMobilityModel = HighFieldMobilityModelMinimos;
596 m_highFieldMobilityModel = HighFieldMobilityModelCanali;
602 m_highFieldMobilityModel = HighFieldMobilityModelReggiani;
608 m_highFieldMobilityModel = HighFieldMobilityModelConstant;
613 m_impactIonisationModel = ImpactIonisationModelVanOverstraeten;
619 m_impactIonisationModel = ImpactIonisationModelGrant;
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";
634 m_eStepG = m_eFinalG / nEnergyStepsG;
642 const double pz,
double& vx,
double& vy,
643 double& vz,
const int band) {
646 double mx = ElectronMass, my = ElectronMass, mz = ElectronMass;
649 if (band >= 0 && band < m_nValleysX) {
651 if (m_useAnisotropy) {
675 std::cerr <<
m_className <<
"::GetElectronEnergy:\n"
676 <<
" Unexpected band index " << band <<
"!\n";
681 const double mc = 3. / (1. / m_mLongX + 2. / m_mTransX);
686 }
else if (band < m_nValleysX + m_nValleysL) {
690 const double mc = 3. / (1. / m_mLongL + 2. / m_mTransL);
694 }
else if (band == m_nValleysX + m_nValleysL) {
698 if (m_useNonParabolicity) {
701 if (band < m_nValleysX) {
704 }
else if (band < m_nValleysX + m_nValleysL) {
709 const double p2 = 0.5 * (px * px / mx + py * py / my + pz * pz / mz);
711 const double e = 0.5 * (sqrt(1. + 4 * alpha * p2) - 1.) / alpha;
712 const double a = SpeedOfLight / (1. + 2 * alpha * e);
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;
728 double& pz,
int& band) {
730 int nBands = m_nValleysX;
731 if (e > m_eMinL) nBands += m_nValleysL;
732 if (e > m_eMinG) ++nBands;
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)) {
740 if (band >= m_nValleysX) band = m_nValleysX - 1;
746 const double dosSum = m_nValleysX * dosX + m_nValleysL * dosL + dosG;
747 if (dosSum < Small) {
748 band = m_nValleysX + m_nValleysL;
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;
758 band = m_nValleysX + m_nValleysL;
763 std::cout <<
m_className <<
"::GetElectronMomentum:\n"
764 <<
" Randomised band index: " << band <<
"\n";
767 if (band < m_nValleysX) {
769 double pstar = sqrt(2. * ElectronMass * e);
770 if (m_useNonParabolicity) {
771 const double alpha = m_alphaX;
772 pstar *= sqrt(1. + alpha * e);
776 const double stheta = sqrt(1. - ctheta * ctheta);
779 if (m_useAnisotropy) {
780 const double pl = pstar * sqrt(m_mLongX);
781 const double pt = pstar * sqrt(m_mTransX);
787 py = pt * cos(phi) * stheta;
788 pz = pt * sin(phi) * stheta;
793 px = pt * sin(phi) * stheta;
795 pz = pt * cos(phi) * stheta;
800 px = pt * cos(phi) * stheta;
801 py = pt * sin(phi) * stheta;
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);
814 pstar *= sqrt(3. / (1. / m_mLongX + 2. / m_mTransX));
815 px = pstar * cos(phi) * stheta;
816 py = pstar * sin(phi) * stheta;
819 }
else if (band < m_nValleysX + m_nValleysL) {
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));
826 pstar *= sqrt(3. / (1. / m_mLongL + 2. / m_mTransL));
828 }
else if (band == m_nValleysX + m_nValleysL) {
830 const double pstar = sqrt(2. * ElectronMass * e);
838 if (!UpdateTransportParameters()) {
839 std::cerr <<
m_className <<
"::GetElectronNullCollisionRate:\n"
840 <<
" Error calculating the collision rates table.\n";
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;
853 std::cerr <<
m_className <<
"::GetElectronNullCollisionRate:\n"
854 <<
" Band index (" << band <<
") out of range.\n";
861 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
862 <<
" Electron energy must be positive.\n";
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";
875 if (!UpdateTransportParameters()) {
876 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
877 <<
" Error calculating the collision rates table.\n";
883 if (band >= 0 && band < m_nValleysX) {
884 int iE = int(e / m_eStepXL);
885 if (iE >= nEnergyStepsXL)
886 iE = nEnergyStepsXL - 1;
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)
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)
903 return m_cfTotElectronsG[iE];
906 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
907 <<
" Band index (" << band <<
") out of range.\n";
912 double& e1,
double& px,
double& py,
913 double& pz,
int& nion,
int& ndxc,
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";
922 }
else if (e <= 0.) {
923 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
924 std::cerr <<
" Electron energy must be greater than zero.\n";
929 if (!UpdateTransportParameters()) {
930 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
931 std::cerr <<
" Error calculating the collision rates table.\n";
940 if (band >= 0 && band < m_nValleysX) {
943 int iE = int(e / m_eStepXL);
944 if (iE >= nEnergyStepsXL) iE = nEnergyStepsXL - 1;
949 int iUp = m_nLevelsX - 1;
950 if (r <= m_cfElectronsX[iE][iLow]) {
952 }
else if (r >= m_cfElectronsX[iE][m_nLevelsX - 1]) {
956 while (iUp - iLow > 1) {
957 iMid = (iLow + iUp) >> 1;
958 if (r < m_cfElectronsX[iE][iMid]) {
968 type = m_scatTypeElectronsX[level];
970 ++m_nCollElectronDetailed[level];
971 ++m_nCollElectronBand[band];
972 if (type == ElectronCollisionTypeAcousticPhonon) {
973 ++m_nCollElectronAcoustic;
974 }
else if (type == ElectronCollisionTypeIntervalleyG) {
976 ++m_nCollElectronIntervalley;
1000 }
else if (type == ElectronCollisionTypeIntervalleyF) {
1002 ++m_nCollElectronIntervalley;
1012 if (band > 1) band += 2;
1019 }
else if (type == ElectronCollisionTypeInterbandXL) {
1021 ++m_nCollElectronIntervalley;
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;
1033 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
1034 std::cerr <<
" Unexpected collision type (" << type <<
").\n";
1038 loss = m_energyLossElectronsX[level];
1040 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
1043 int iE = int(e / m_eStepXL);
1044 if (iE >= nEnergyStepsXL) iE = nEnergyStepsXL - 1;
1045 if (iE < m_ieMinL) iE = m_ieMinL;
1049 int iUp = m_nLevelsL - 1;
1050 if (r <= m_cfElectronsL[iE][iLow]) {
1052 }
else if (r >= m_cfElectronsL[iE][m_nLevelsL - 1]) {
1056 while (iUp - iLow > 1) {
1057 iMid = (iLow + iUp) >> 1;
1058 if (r < m_cfElectronsL[iE][iMid]) {
1068 type = m_scatTypeElectronsL[level];
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) {
1079 ++m_nCollElectronIntervalley;
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) {
1085 ++m_nCollElectronIntervalley;
1088 if (band >= m_nValleysX) band = m_nValleysX - 1;
1089 }
else if (type == ElectronCollisionTypeInterbandLG) {
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;
1098 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
1099 std::cerr <<
" Unexpected collision type (" << type <<
").\n";
1103 loss = m_energyLossElectronsL[level];
1104 }
else if (band == m_nValleysX + m_nValleysL) {
1107 int iE = int(e / m_eStepG);
1108 if (iE >= nEnergyStepsG) iE = nEnergyStepsG - 1;
1109 if (iE < m_ieMinG) iE = m_ieMinG;
1113 int iUp = m_nLevelsG - 1;
1114 if (r <= m_cfElectronsG[iE][iLow]) {
1116 }
else if (r >= m_cfElectronsG[iE][m_nLevelsG - 1]) {
1120 while (iUp - iLow > 1) {
1121 iMid = (iLow + iUp) >> 1;
1122 if (r < m_cfElectronsG[iE][iMid]) {
1132 type = m_scatTypeElectronsG[level];
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) {
1143 ++m_nCollElectronIntervalley;
1144 }
else if (type == ElectronCollisionTypeInterbandXG) {
1146 ++m_nCollElectronIntervalley;
1149 if (band >= m_nValleysX) band = m_nValleysX - 1;
1150 }
else if (type == ElectronCollisionTypeInterbandLG) {
1152 ++m_nCollElectronIntervalley;
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;
1159 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
1160 std::cerr <<
" Unexpected collision type (" << type <<
").\n";
1164 loss = m_energyLossElectronsG[level];
1166 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
1167 std::cerr <<
" Band index (" << band <<
") out of range.\n";
1174 if (type == ElectronCollisionTypeIonisation) {
1175 double ee = 0., eh = 0.;
1177 loss = ee + eh + m_bandGap;
1178 m_ionProducts.clear();
1181 newIonProd.type = IonProdTypeElectron;
1182 newIonProd.energy = ee;
1183 m_ionProducts.push_back(newIonProd);
1185 newIonProd.type = IonProdTypeHole;
1186 newIonProd.energy = eh;
1187 m_ionProducts.push_back(newIonProd);
1191 if (e < loss) loss = e - 0.00001;
1194 if (e1 < Small) e1 = Small;
1197 if (band >= 0 && band < m_nValleysX) {
1199 double pstar = sqrt(2. * ElectronMass * e1);
1200 if (m_useNonParabolicity) {
1201 const double alpha = m_alphaX;
1202 pstar *= sqrt(1. + alpha * e1);
1206 const double stheta = sqrt(1. - ctheta * ctheta);
1209 if (m_useAnisotropy) {
1210 const double pl = pstar * sqrt(m_mLongX);
1211 const double pt = pstar * sqrt(m_mTransX);
1217 py = pt * cos(phi) * stheta;
1218 pz = pt * sin(phi) * stheta;
1223 px = pt * sin(phi) * stheta;
1225 pz = pt * cos(phi) * stheta;
1230 px = pt * cos(phi) * stheta;
1231 py = pt * sin(phi) * stheta;
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;
1246 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
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));
1253 pstar *= sqrt(3. / (1. / m_mLongL + 2. / m_mTransL));
1257 const double pstar = sqrt(2. * ElectronMass * e1);
1262 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
1263 std::cerr <<
" Band index (" << band <<
") out of range.\n";
1270 double& energy)
const {
1272 if (i >= m_ionProducts.size()) {
1273 std::cerr <<
m_className <<
"::GetIonisationProduct:\n"
1274 <<
" Index (" << i <<
") out of range.\n";
1278 type = m_ionProducts[i].type;
1279 energy = m_ionProducts[i].energy;
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;
1299 return m_nCollElectronAcoustic + m_nCollElectronOptical +
1300 m_nCollElectronIntervalley + m_nCollElectronImpurity +
1301 m_nCollElectronIonisation;
1306 return m_nLevelsX + m_nLevelsL + m_nLevelsG;
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";
1318 return m_nCollElectronDetailed[level];
1323 return m_nValleysX + m_nValleysL + 1;
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";
1334 return m_nCollElectronBand[band];
1338 const unsigned int i) {
1341 std::cerr <<
m_className <<
"::GetOpticalDataRange:\n";
1342 std::cerr <<
" Medium has only one component.\n";
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";
1354 emin = m_opticalDataTable[0].energy;
1355 emax = m_opticalDataTable.back().energy;
1357 std::cout <<
m_className <<
"::GetOpticalDataRange:\n"
1358 <<
" " << emin <<
" < E [eV] < " << emax <<
"\n";
1364 double& eps2,
const unsigned int i) {
1367 std::cerr <<
m_className <<
"::GetDielectricFunction:\n";
1368 std::cerr <<
" Medium has only one component.\n";
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";
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";
1395 int iUp = m_opticalDataTable.size() - 1;
1397 while (iUp - iLow > 1) {
1398 iM = (iUp + iLow) >> 1;
1399 if (e >= m_opticalDataTable[iM].energy) {
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);
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);
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);
1438 std::cerr <<
m_className <<
"::Initialise:\n Nothing changed.\n";
1442 if (!UpdateTransportParameters()) {
1443 std::cerr <<
m_className <<
"::Initialise: Error preparing "
1444 <<
"transport parameters/calculating collision rates.\n";
1450bool MediumSilicon::UpdateTransportParameters() {
1453 switch (m_impactIonisationModel) {
1454 case ImpactIonisationModelVanOverstraeten:
1455 UpdateImpactIonisationVanOverstraetenDeMan();
1457 case ImpactIonisationModelGrant:
1458 UpdateImpactIonisationGrant();
1461 std::cerr <<
m_className <<
"::UpdateTransportParameters\n "
1462 <<
"Unknown impact ionisation model. Program bug!\n";
1466 if (!m_hasUserMobility) {
1468 switch (m_latticeMobilityModel) {
1469 case LatticeMobilityModelMinimos:
1470 UpdateLatticeMobilityMinimos();
1472 case LatticeMobilityModelSentaurus:
1473 UpdateLatticeMobilitySentaurus();
1475 case LatticeMobilityModelReggiani:
1476 UpdateLatticeMobilityReggiani();
1479 std::cerr <<
m_className <<
"::UpdateTransportParameters:\n "
1480 <<
"Unknown lattice mobility model. Program bug!\n";
1485 switch (m_dopingMobilityModel) {
1486 case DopingMobilityModelMinimos:
1487 UpdateDopingMobilityMinimos();
1489 case DopingMobilityModelMasetti:
1490 UpdateDopingMobilityMasetti();
1493 std::cerr <<
m_className <<
"::UpdateTransportParameters:\n "
1494 <<
"Unknown doping mobility model. Program bug!\n";
1500 if (!m_hasUserSaturationVelocity) {
1501 switch (m_saturationVelocityModel) {
1502 case SaturationVelocityModelMinimos:
1503 UpdateSaturationVelocityMinimos();
1505 case SaturationVelocityModelCanali:
1506 UpdateSaturationVelocityCanali();
1508 case SaturationVelocityModelReggiani:
1509 UpdateSaturationVelocityReggiani();
1515 switch (m_highFieldMobilityModel) {
1516 case HighFieldMobilityModelCanali:
1517 UpdateHighFieldMobilityCanali();
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";
1529 std::cout <<
" Saturation velocity [cm / ns]\n"
1530 <<
" Electrons: " << m_eSatVel <<
"\n"
1531 <<
" Holes: " << m_hSatVel <<
"\n";
1535 if (!ElectronScatteringRates())
return false;
1536 if (!HoleScatteringRates())
return false;
1544void MediumSilicon::UpdateLatticeMobilityMinimos() {
1552 const double eMu0 = 1.43e-6;
1553 const double hMu0 = 0.46e-6;
1557 m_eLatticeMobility = eMu0 *
pow(t, -2.);
1558 m_hLatticeMobility = hMu0 *
pow(t, -2.18);
1561void MediumSilicon::UpdateLatticeMobilitySentaurus() {
1569 const double eMu0 = 1.417e-6;
1570 const double hMu0 = 0.4705e-6;
1574 m_eLatticeMobility = eMu0 *
pow(t, -2.5);
1575 m_hLatticeMobility = hMu0 *
pow(t, -2.2);
1579void MediumSilicon::UpdateLatticeMobilityReggiani() {
1586 const double eMu0 = 1.320e-6;
1587 const double hMu0 = 0.460e-6;
1591 m_eLatticeMobility = eMu0 *
pow(t, -2.);
1592 m_hLatticeMobility = hMu0 *
pow(t, -2.2);
1595void MediumSilicon::UpdateDopingMobilityMinimos() {
1604 double eMuMin = 0.080e-6;
1605 double hMuMin = 0.045e-6;
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));
1623void MediumSilicon::UpdateDopingMobilityMasetti() {
1631 if (m_dopingConcentration < 1.e13) {
1632 m_eMobility = m_eLatticeMobility;
1633 m_hMobility = m_hLatticeMobility;
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.;
1654 m_eMobility = eMuMin1 + (m_eLatticeMobility - eMuMin2) /
1655 (1. +
pow(m_dopingConcentration / eCr, eAlpha)) -
1656 eMu1 / (1. +
pow(eCs / m_dopingConcentration, eBeta));
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));
1664void MediumSilicon::UpdateSaturationVelocityMinimos() {
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.));
1676void MediumSilicon::UpdateSaturationVelocityCanali() {
1687void MediumSilicon::UpdateSaturationVelocityReggiani() {
1697void MediumSilicon::UpdateHighFieldMobilityCanali() {
1707 m_eBetaCanaliInv = 1. / m_eBetaCanali;
1708 m_hBetaCanaliInv = 1. / m_hBetaCanali;
1741void MediumSilicon::UpdateImpactIonisationVanOverstraetenDeMan() {
1746 const double hbarOmega = 0.063;
1748 const double gamma = tanh(hbarOmega / (2. * BoltzmannConstant * 300.)) /
1752 m_eImpactA0 = gamma * 7.03e5;
1753 m_eImpactB0 = gamma * 1.231e6;
1754 m_eImpactA1 = gamma * 7.03e5;
1755 m_eImpactB1 = gamma * 1.231e6;
1757 m_hImpactA0 = gamma * 1.582e6;
1758 m_hImpactB0 = gamma * 2.036e6;
1759 m_hImpactA1 = gamma * 6.71e5;
1760 m_hImpactB1 = gamma * 1.693e6;
1763void MediumSilicon::UpdateImpactIonisationGrant() {
1772 const double hbarOmega = 0.063;
1774 const double gamma = tanh(hbarOmega / (2. * BoltzmannConstant * 300.)) /
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;
1784 m_hImpactA0 = 2.00e6 * gamma;
1785 m_hImpactB0 = 1.97e6 * gamma;
1786 m_hImpactA1 = 5.60e5 * gamma;
1787 m_hImpactB1 = 1.32e6 * gamma;
1790bool MediumSilicon::ElectronMobilityMinimos(
const double e,
double& mu)
const {
1798 mu = 2. * m_eMobility /
1799 (1. +
sqrt(1. +
pow(2. * m_eMobility * e / m_eSatVel, 2.)));
1804bool MediumSilicon::ElectronMobilityCanali(
const double e,
double& mu)
const {
1813 pow(1. +
pow(m_eMobility * e / m_eSatVel, m_eBetaCanali),
1819bool MediumSilicon::ElectronMobilityReggiani(
const double e,
double& mu)
const {
1828 mu = m_eMobility /
pow(1 +
pow(m_eMobility * e / m_eSatVel, 1.5), 1. / 1.5);
1854bool MediumSilicon::ElectronImpactIonisationVanOverstraetenDeMan(
1855 const double e,
double& alpha)
const {
1865 }
else if (e < 4e5) {
1866 alpha = m_eImpactA0 *
exp(-m_eImpactB0 / e);
1868 alpha = m_eImpactA1 *
exp(-m_eImpactB1 / e);
1873bool MediumSilicon::ElectronImpactIonisationGrant(
const double e,
1874 double& alpha)
const {
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);
1886 alpha = m_eImpactA2 *
exp(-m_eImpactB2 / e);
1891bool MediumSilicon::HoleMobilityMinimos(
const double e,
double& mu)
const {
1899 mu = m_hMobility / (1. + m_hMobility * e / m_eSatVel);
1904bool MediumSilicon::HoleMobilityCanali(
const double e,
double& mu)
const {
1913 pow(1. +
pow(m_hMobility * e / m_hSatVel, m_hBetaCanali), m_hBetaCanaliInv);
1918bool MediumSilicon::HoleMobilityReggiani(
const double e,
double& mu)
const {
1927 mu = m_hMobility /
pow(1. +
pow(m_hMobility * e / m_hSatVel, 2.), 0.5);
1949bool MediumSilicon::HoleImpactIonisationVanOverstraetenDeMan(
1950 const double e,
double& alpha)
const {
1958 }
else if (e < 4e5) {
1959 alpha = m_hImpactA0 *
exp(-m_hImpactB0 / e);
1961 alpha = m_hImpactA1 *
exp(-m_hImpactB1 / e);
1967bool MediumSilicon::HoleImpactIonisationGrant(
const double e,
1968 double& alpha)
const {
1975 }
else if (e < 5.3e5) {
1976 alpha = m_hImpactA0 *
exp(-m_hImpactB0 / e);
1978 alpha = m_hImpactA1 *
exp(-m_hImpactB1 / e);
1983bool MediumSilicon::LoadOpticalData(
const std::string& filename) {
1986 m_opticalDataTable.clear();
1989 char* pPath = getenv(
"GARFIELD_HOME");
1991 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
1992 <<
" Environment variable GARFIELD_HOME is not set.\n";
1995 const std::string filepath = std::string(pPath) +
"/Data/" + filename;
1998 std::ifstream infile;
1999 infile.open(filepath.c_str(), std::ios::in);
2002 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
2003 <<
" Error opening file " << filename <<
".\n";
2007 double lastEnergy = -1.;
2008 double energy, eps1, eps2, loss;
2012 std::istringstream dataStream;
2014 while (!infile.eof()) {
2017 std::getline(infile, line);
2019 line.erase(line.begin(),
2020 std::find_if(line.begin(), line.end(),
2021 not1(std::ptr_fun<int, int>(isspace))));
2023 if (line[0] ==
'#' || line[0] ==
'*' || (line[0] ==
'/' && line[1] ==
'/'))
2026 dataStream.str(line);
2027 dataStream >> energy >> eps1 >> eps2 >> loss;
2028 if (dataStream.eof())
break;
2030 if (infile.fail()) {
2031 std::cerr <<
m_className <<
"::LoadOpticalData:\n Error reading file "
2032 << filename <<
" (line " << i <<
").\n";
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";
2050 std::cerr <<
m_className <<
"::LoadOpticalData:\n Negative value "
2051 <<
"of the loss function (line " << i <<
").\n";
2055 if (energy <= 0.)
continue;
2057 data.energy = energy;
2060 m_opticalDataTable.push_back(data);
2061 lastEnergy = energy;
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";
2073 std::cout <<
m_className <<
"::LoadOpticalData: Read \n"
2074 << nEntries <<
" values from file " << filepath <<
"\n";
2079bool MediumSilicon::ElectronScatteringRates() {
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();
2094 for (
int i = nEnergyStepsG; i--;) {
2095 m_cfTotElectronsG[i] = 0.;
2096 m_cfElectronsG[i].clear();
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.;
2112 ElectronAcousticScatteringRates();
2113 ElectronOpticalScatteringRates();
2114 ElectronImpurityScatteringRates();
2115 ElectronIntervalleyScatteringRatesXX();
2116 ElectronIntervalleyScatteringRatesXL();
2117 ElectronIntervalleyScatteringRatesLL();
2118 ElectronIntervalleyScatteringRatesXGLG();
2119 ElectronIonisationRatesXL();
2120 ElectronIonisationRatesG();
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";
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);
2136 m_ieMinL = int(m_eMinL / m_eStepXL) + 1;
2137 for (
int i = 0; i < nEnergyStepsXL; ++i) {
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];
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] <<
" ";
2148 outfileL << i * m_eStepXL <<
" " << m_cfTotElectronsL[i] <<
" ";
2149 for (
int j = 0; j < m_nLevelsL; ++j) {
2150 outfileL << m_cfElectronsL[i][j] <<
" ";
2155 if (m_cfTotElectronsX[i] > m_cfNullElectronsX) {
2156 m_cfNullElectronsX = m_cfTotElectronsX[i];
2158 if (m_cfTotElectronsL[i] > m_cfNullElectronsL) {
2159 m_cfNullElectronsL = m_cfTotElectronsL[i];
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";
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];
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";
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];
2188 if (m_useCfOutput) {
2193 std::ofstream outfileG;
2194 if (m_useCfOutput) {
2195 outfileG.open(
"ratesG.txt", std::ios::out);
2197 m_ieMinG = int(m_eMinG / m_eStepG) + 1;
2198 for (
int i = 0; i < nEnergyStepsG; ++i) {
2200 for (
int j = m_nLevelsG; j--;) m_cfTotElectronsG[i] += m_cfElectronsG[i][j];
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] <<
" ";
2210 if (m_cfTotElectronsG[i] > m_cfNullElectronsG) {
2211 m_cfNullElectronsG = m_cfTotElectronsG[i];
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";
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];
2227 if (m_useCfOutput) {
2234bool MediumSilicon::ElectronAcousticScatteringRates() {
2241 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2247 const double defpot = 9.;
2249 const double u = 9.04e-4;
2251 const double cIntra = TwoPi * SpeedOfLight * SpeedOfLight * kbt * defpot *
2252 defpot / (Hbar * u * u * rho);
2256 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2260 m_cfElectronsX[i].push_back(cIntra * dosX);
2261 m_cfElectronsL[i].push_back(cIntra * dosL);
2266 for (
int i = 0; i < nEnergyStepsG; ++i) {
2269 m_cfElectronsG[i].push_back(cIntra * dosG);
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);
2287bool MediumSilicon::ElectronOpticalScatteringRates() {
2299 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2304 const double dtk = 2.2e8;
2306 const double eph = 63.0e-3;
2308 const double nocc = 1. / (
exp(eph / kbt) - 1);
2310 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2311 double c = c0 * dtk * dtk / eph;
2337 for (
int i = 0; i < nEnergyStepsG; ++i) {
2341 m_nValleysX + m_nValleysL);
2342 m_cfElectronsG[i].push_back(c * nocc * dos);
2344 m_cfElectronsG[i].push_back(0.);
2347 if (en > m_eMinG + eph) {
2349 m_nValleysX + m_nValleysL);
2350 m_cfElectronsG[i].push_back(c * (nocc + 1) * dos);
2352 m_cfElectronsG[i].push_back(0.);
2359 m_energyLossElectronsG.push_back(-eph);
2362 m_energyLossElectronsG.push_back(eph);
2365 m_scatTypeElectronsG.push_back(ElectronCollisionTypeOpticalPhonon);
2366 m_scatTypeElectronsG.push_back(ElectronCollisionTypeOpticalPhonon);
2374bool MediumSilicon::ElectronIntervalleyScatteringRatesXX() {
2381 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2385 const unsigned int nPhonons = 6;
2391 const double dtk[nPhonons] = {0.5e8, 0.8e8, 1.1e9, 0.3e8, 2.0e8, 2.0e8};
2393 const double eph[nPhonons] = {12.06e-3, 18.53e-3, 62.04e-3,
2394 18.86e-3, 47.39e-3, 59.03e-3};
2396 double nocc[nPhonons];
2398 const double c0 = HbarC * SpeedOfLight * Pi / rho;
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;
2408 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2409 for (
unsigned int j = 0; j < nPhonons; ++j) {
2412 m_cfElectronsX[i].push_back(c[j] * nocc[j] * dos);
2416 m_cfElectronsX[i].push_back(c[j] * (nocc[j] + 1) * dos);
2418 m_cfElectronsX[i].push_back(0.);
2424 for (
unsigned int j = 0; j < nPhonons; ++j) {
2426 m_energyLossElectronsX.push_back(-eph[j]);
2428 m_energyLossElectronsX.push_back(eph[j]);
2430 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyG);
2431 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyG);
2433 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyF);
2434 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyF);
2438 m_nLevelsX += 2 * nPhonons;
2443bool MediumSilicon::ElectronIntervalleyScatteringRatesXL() {
2451 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2455 const unsigned int nPhonons = 4;
2458 const double dtk[nPhonons] = {2.e8, 2.e8, 2.e8, 2.e8};
2460 const double eph[nPhonons] = {58.e-3, 55.e-3, 41.e-3, 17.e-3};
2462 const unsigned int zX = 6;
2463 const unsigned int zL = 8;
2466 double nocc[nPhonons] = {0.};
2468 const double c0 = HbarC * SpeedOfLight * Pi / rho;
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];
2477 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2478 for (
unsigned int j = 0; j < nPhonons; ++j) {
2481 if (en + eph[j] > m_eMinL) {
2483 m_cfElectronsX[i].push_back(zL * c[j] * nocc[j] * dos);
2485 m_cfElectronsX[i].push_back(0.);
2488 if (en - eph[j] > m_eMinL) {
2490 m_cfElectronsX[i].push_back(zL * c[j] * (nocc[j] + 1) * dos);
2492 m_cfElectronsX[i].push_back(0.);
2498 m_cfElectronsL[i].push_back(zX * c[j] * nocc[j] * dos);
2501 m_cfElectronsL[i].push_back(zX * c[j] * (nocc[j] + 1) * dos);
2503 m_cfElectronsL[i].push_back(0.);
2504 m_cfElectronsL[i].push_back(0.);
2510 for (
unsigned int j = 0; j < nPhonons; ++j) {
2512 m_energyLossElectronsX.push_back(-eph[j]);
2513 m_energyLossElectronsL.push_back(-eph[j]);
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);
2523 m_nLevelsX += 2 * nPhonons;
2524 m_nLevelsL += 2 * nPhonons;
2529bool MediumSilicon::ElectronIntervalleyScatteringRatesLL() {
2539 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2543 const int nPhonons = 1;
2545 const double dtk[nPhonons] = {2.63e8};
2547 const double eph[nPhonons] = {38.87e-3};
2549 double nocc[nPhonons];
2551 const double c0 = HbarC * SpeedOfLight * Pi / rho;
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];
2562 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2563 for (
int j = 0; j < nPhonons; ++j) {
2566 m_cfElectronsL[i].push_back(c[j] * nocc[j] * dos);
2568 if (en > m_eMinL + eph[j]) {
2570 m_cfElectronsL[i].push_back(c[j] * (nocc[j] + 1) * dos);
2572 m_cfElectronsL[i].push_back(0.);
2578 for (
int j = 0; j < nPhonons; ++j) {
2580 m_energyLossElectronsL.push_back(-eph[j]);
2582 m_energyLossElectronsL.push_back(eph[j]);
2583 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIntervalleyF);
2584 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIntervalleyF);
2587 m_nLevelsL += 2 * nPhonons;
2592bool MediumSilicon::ElectronIntervalleyScatteringRatesXGLG() {
2600 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2604 const int nPhonons = 1;
2608 const double dtk[nPhonons] = {2.43e8};
2610 const double eph[nPhonons] = {37.65e-3};
2617 double nocc[nPhonons] = {0.};
2619 const double c0 = HbarC * SpeedOfLight * Pi / rho;
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];
2630 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2631 for (
int j = 0; j < nPhonons; ++j) {
2633 if (en + eph[j] > m_eMinG) {
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);
2639 m_cfElectronsX[i].push_back(0.);
2640 m_cfElectronsL[i].push_back(0.);
2643 if (en - eph[j] > m_eMinG) {
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);
2649 m_cfElectronsX[i].push_back(0.);
2650 m_cfElectronsL[i].push_back(0.);
2658 double dosX = 0., dosL = 0.;
2659 for (
int i = 0; i < nEnergyStepsG; ++i) {
2660 for (
int j = 0; j < nPhonons; ++j) {
2664 m_cfElectronsG[i].push_back(zX * c[j] * nocc[j] * dosX);
2666 m_cfElectronsG[i].push_back(zL * c[j] * nocc[j] * dosL);
2668 m_cfElectronsG[i].push_back(0.);
2674 m_cfElectronsG[i].push_back(zX * c[j] * (nocc[j] + 1) * dosX);
2676 m_cfElectronsG[i].push_back(0.);
2678 if (en - eph[j] > m_eMinL) {
2679 m_cfElectronsG[i].push_back(zL * c[j] * (nocc[j] + 1) * dosL);
2681 m_cfElectronsG[i].push_back(0.);
2687 for (
int j = 0; j < nPhonons; ++j) {
2689 m_energyLossElectronsX.push_back(-eph[j]);
2690 m_energyLossElectronsL.push_back(-eph[j]);
2692 m_energyLossElectronsX.push_back(eph[j]);
2693 m_energyLossElectronsL.push_back(eph[j]);
2695 m_energyLossElectronsG.push_back(-eph[j]);
2696 m_energyLossElectronsG.push_back(-eph[j]);
2698 m_energyLossElectronsG.push_back(eph[j]);
2699 m_energyLossElectronsG.push_back(eph[j]);
2701 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXG);
2702 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXG);
2703 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandLG);
2704 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandLG);
2706 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandXG);
2707 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandLG);
2708 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandXG);
2709 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandLG);
2712 m_nLevelsX += 2 * nPhonons;
2713 m_nLevelsL += 2 * nPhonons;
2714 m_nLevelsG += 4 * nPhonons;
2719bool MediumSilicon::ElectronIonisationRatesXL() {
2727 const double p[3] = {6.25e1, 3.e3, 6.8e5};
2729 const double eth[3] = {1.2, 1.8, 3.45};
2732 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2735 fIon += p[0] * (en - eth[0]) * (en - eth[0]);
2738 fIon += p[1] * (en - eth[1]) * (en - eth[1]);
2741 fIon += p[2] * (en - eth[2]) * (en - eth[2]);
2743 m_cfElectronsX[i].push_back(fIon);
2744 m_cfElectronsL[i].push_back(fIon);
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);
2758bool MediumSilicon::ElectronIonisationRatesG() {
2767 const double p[3] = {6.25e1, 3.e3, 6.8e5};
2769 const double eth[3] = {1.2, 1.8, 3.45};
2772 for (
int i = 0; i < nEnergyStepsG; ++i) {
2775 fIon += p[0] * (en - eth[0]) * (en - eth[0]);
2778 fIon += p[1] * (en - eth[1]) * (en - eth[1]);
2781 fIon += p[2] * (en - eth[2]) * (en - eth[2]);
2783 if (en >= m_eMinG) {
2784 m_cfElectronsG[i].push_back(fIon);
2786 m_cfElectronsG[i].push_back(0.);
2791 m_energyLossElectronsG.push_back(eth[0]);
2792 m_scatTypeElectronsG.push_back(ElectronCollisionTypeIonisation);
2798bool MediumSilicon::ElectronImpurityScatteringRates() {
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.);
2811 const double impurityConcentration = m_dopingConcentration;
2812 if (impurityConcentration < Small)
return true;
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);
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);
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));
2839 m_cfElectronsX[i].push_back(0.);
2841 const double b = 4 * gammaX / ebX;
2843 .push_back((cX /
pow(gammaX, 1.5)) * (log(1. + b) - b / (1. + b)));
2845 if (en <= m_eMinL || gammaL <= 0.) {
2846 m_cfElectronsL[i].push_back(0.);
2848 const double b = 4 * gammaL / ebL;
2850 .push_back((cL /
pow(gammaL, 1.5)) * (log(1. + b) - b / (1. + b)));
2855 m_energyLossElectronsX.push_back(0.);
2856 m_energyLossElectronsL.push_back(0.);
2857 m_scatTypeElectronsX.push_back(ElectronCollisionTypeImpurity);
2858 m_scatTypeElectronsL.push_back(ElectronCollisionTypeImpurity);
2865bool MediumSilicon::HoleScatteringRates() {
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();
2874 m_energyLossHoles.clear();
2875 m_scatTypeHoles.clear();
2880 HoleAcousticScatteringRates();
2881 HoleOpticalScatteringRates();
2883 HoleIonisationRates();
2885 std::ofstream outfile;
2886 if (m_useCfOutput) {
2887 outfile.open(
"ratesV.txt", std::ios::out);
2890 for (
int i = 0; i < nEnergyStepsV; ++i) {
2892 for (
int j = m_nLevelsV; j--;) m_cfTotHoles[i] += m_cfHoles[i][j];
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] <<
" ";
2902 if (m_cfTotHoles[i] > m_cfNullHoles) {
2903 m_cfNullHoles = m_cfTotHoles[i];
2907 if (m_cfTotHoles[i] <= 0.) {
2908 std::cerr <<
m_className <<
"::HoleScatteringRates:\n"
2909 <<
" Scattering rate at " << i * m_eStepV <<
" eV <= 0.\n";
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];
2919 if (m_useCfOutput) {
2926bool MediumSilicon::HoleAcousticScatteringRates() {
2935 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2942 const double defpot = 4.6;
2944 const double u = 9.04e-4;
2946 const double cIntra = TwoPi * SpeedOfLight * SpeedOfLight * kbt * defpot *
2947 defpot / (Hbar * u * u * rho);
2951 for (
int i = 0; i < nEnergyStepsV; ++i) {
2953 m_cfHoles[i].push_back(cIntra * dos);
2958 m_energyLossHoles.push_back(0.);
2959 m_scatTypeHoles.push_back(ElectronCollisionTypeAcousticPhonon);
2965bool MediumSilicon::HoleOpticalScatteringRates() {
2974 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2980 const double dtk = 6.6e8;
2982 const double eph = 63.0e-3;
2984 const double nocc = 1. / (
exp(eph / kbt) - 1);
2986 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2987 double c = c0 * dtk * dtk / eph;
2990 for (
int i = 0; i < nEnergyStepsV; ++i) {
2993 m_cfHoles[i].push_back(c * nocc * dos);
2997 m_cfHoles[i].push_back(c * (nocc + 1) * dos);
2999 m_cfHoles[i].push_back(0.);
3005 m_energyLossHoles.push_back(-eph);
3007 m_energyLossHoles.push_back(eph);
3008 m_scatTypeHoles.push_back(ElectronCollisionTypeOpticalPhonon);
3009 m_scatTypeHoles.push_back(ElectronCollisionTypeOpticalPhonon);
3016bool MediumSilicon::HoleIonisationRates() {
3022 const double p[2] = {2., 1.e3};
3024 const double eth[2] = {1.1, 1.45};
3026 const double b[2] = {6., 4.};
3029 for (
int i = 0; i < nEnergyStepsV; ++i) {
3032 fIon += p[0] *
pow(en - eth[0], b[0]);
3035 fIon += p[1] *
pow(en - eth[1], b[1]);
3037 m_cfHoles[i].push_back(fIon);
3041 m_energyLossHoles.push_back(eth[0]);
3042 m_scatTypeHoles.push_back(ElectronCollisionTypeIonisation);
3051 int iE = int(e / m_eStepDos);
3052 const int nPoints = m_fbDosConduction.size();
3053 if (iE >= nPoints || iE < 0) {
3055 }
else if (iE == nPoints - 1) {
3056 return m_fbDosConduction[nPoints - 1];
3060 m_fbDosConduction[iE] +
3061 (m_fbDosConduction[iE + 1] - m_fbDosConduction[iE]) * (e / m_eStepDos - iE);
3064 }
else if (band < m_nValleysX) {
3066 if (e <= 0.)
return 0.;
3068 const double md3 = pow(ElectronMass, 3) * m_mLongX * m_mTransX * m_mTransX;
3070 if (m_useFullBandDos) {
3073 }
else if (e < m_eMinG) {
3079 return dosX / m_nValleysX;
3087 if (dosX <= 0.)
return 0.;
3088 return dosX / m_nValleysX;
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.));
3095 return sqrt(md3 * e / 2.) / (Pi2 * pow(HbarC, 3.));
3097 }
else if (band < m_nValleysX + m_nValleysL) {
3099 if (e <= m_eMinL)
return 0.;
3102 const double md3 = pow(ElectronMass, 3) * m_mLongL * m_mTransL * m_mTransL;
3104 const double alpha = m_alphaL;
3106 if (m_useFullBandDos) {
3108 const double ej = m_eMinL + 0.5;
3110 return sqrt(md3 * (e - m_eMinL) * (1. + alpha * (e - m_eMinL))) *
3111 (1. + 2 * alpha * (e - m_eMinL)) / (Sqrt2 * Pi2 * pow(HbarC, 3.));
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.));
3123 if (dosXL <= 0.)
return 0.;
3124 return fL * dosXL / 8.;
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.));
3130 return sqrt(md3 * (e - m_eMinL) / 2.) / (Pi2 * pow(HbarC, 3.));
3132 }
else if (band == m_nValleysX + m_nValleysL) {
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";
3143 }
else if (e < ej) {
3147 return dj * (e - m_eMinG) / (ej - m_eMinG);
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.));
3163 const int nPoints = m_fbDosValence.size();
3164 int iE = int(e / m_eStepDos);
3165 if (iE >= nPoints || iE < 0) {
3167 }
else if (iE == nPoints - 1) {
3168 return m_fbDosValence[nPoints - 1];
3172 m_fbDosValence[iE] +
3173 (m_fbDosValence[iE + 1] - m_fbDosValence[iE]) * (e / m_eStepDos - iE);
3177 std::cerr <<
m_className <<
"::GetConductionBandDensityOfStates:\n"
3178 <<
" Band index (" << band <<
") out of range.\n";
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;
3194 int ih = std::min(
int(eh / m_eStepDos), nPointsValence - 1);
3195 while (
RndmUniform() > m_fbDosValence[ih] / m_fbDosMaxV) {
3197 ih = std::min(
int(eh / m_eStepDos), nPointsValence - 1);
3201 int ie = std::min(
int(ee / m_eStepDos), nPointsConduction - 1);
3202 while (
RndmUniform() > m_fbDosConduction[ie] / m_fbDosMaxC) {
3204 ie = std::min(
int(ee / m_eStepDos), nPointsConduction - 1);
3207 const double ep = e0 - m_bandGap - eh - ee;
3208 if (ep < Small)
continue;
3209 if (ep > 5.)
return;
3211 int ip = std::min(
int(ep / m_eStepDos), nPointsConduction - 1);
3212 if (
RndmUniform() > m_fbDosConduction[ip] / m_fbDosMaxC)
continue;
3217void MediumSilicon::InitialiseDensityOfStates() {
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};
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};
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];
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];
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 SetLatticeMobilityModelReggiani()
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 SetDopingMobilityModelMasetti()
void SetTrapDensity(const double n)
double GetElectronNullCollisionRate(const int band)
bool GetDielectricFunction(const double e, double &eps1, double &eps2, const unsigned int i=0)
void SetHighFieldMobilityModelMinimos()
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)
void ResetCollisionCounters()
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()
void SetLatticeMobilityModelSentaurus()
void SetSaturationVelocityModelCanali()
void SetHighFieldMobilityModelCanali()
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 SetLatticeMobilityModelMinimos()
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)
void SetImpactIonisationModelGrant()
bool GetElectronCollision(const double e, int &type, int &level, double &e1, double &dx, double &dy, double &dz, int &nion, int &ndxc, int &band)
void SetDopingMobilityModelMinimos()
unsigned int GetNumberOfElectronBands() const
Abstract base class for media.
void SetTemperature(const double t)
virtual bool HoleTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
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)
double GetDielectricConstant() const
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)
virtual void SetAtomicNumber(const double z)
void SetDielectricConstant(const double eps)
virtual void EnableDrift()
virtual bool ElectronTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
virtual void SetMassDensity(const double rho)
virtual bool ElectronAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
virtual void EnablePrimaryIonisation()
virtual void SetAtomicWeight(const double a)
bool m_hasElectronVelocityE
std::vector< std::vector< std::vector< double > > > tabElectronTownsend
bool m_hasElectronAttachment
virtual bool HoleAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
double RndmUniform()
Draw a random number uniformly distributed in the range [0, 1).
void RndmDirection(double &dx, double &dy, double &dz, const double length=1.)
Draw a random (isotropic) direction vector.
double RndmUniformPos()
Draw a random number uniformly distributed in the range (0, 1).
DoubleAc pow(const DoubleAc &f, double p)
DoubleAc exp(const DoubleAc &f)
DoubleAc sqrt(const DoubleAc &f)