17 m_eStepXL(m_eFinalXL / nEnergyStepsXL),
18 m_eStepG(m_eFinalG / nEnergyStepsG),
19 m_eStepV(m_eFinalV / nEnergyStepsV) {
36 m_ieMinL = int(m_eMinL / m_eStepXL) + 1;
37 m_ieMinG = int(m_eMinG / m_eStepG) + 1;
40 InitialiseDensityOfStates();
44 if (toupper(type) ==
'N') {
47 m_dopingConcentration = c;
50 <<
" Doping concentration must be greater than zero.\n"
51 <<
" Using default value for n-type silicon "
52 <<
"(10^12 cm-3) instead.\n";
53 m_dopingConcentration = 1.e12;
55 }
else if (toupper(type) ==
'P') {
58 m_dopingConcentration = c;
61 <<
" Doping concentration must be greater than zero.\n"
62 <<
" Using default value for p-type silicon "
63 <<
"(10^18 cm-3) instead.\n";
64 m_dopingConcentration = 1.e18;
66 }
else if (toupper(type) ==
'I') {
68 m_dopingConcentration = 0.;
71 <<
" Unknown dopant type (" << type <<
").\n"
72 <<
" Available types are n, p and i (intrinsic).\n";
81 c = m_dopingConcentration;
86 std::cerr <<
m_className <<
"::SetTrapCrossSection:\n"
87 <<
" Capture cross-section [cm2] must non-negative.\n";
93 std::cerr <<
m_className <<
"::SetTrapCrossSection:\n"
94 <<
" Capture cross-section [cm2] must be non-negative.n";
106 <<
" Trap density [cm-3] must be non-negative.\n";
119 <<
" Trapping time [ns-1] must be positive.\n";
126 <<
" Trapping time [ns-1] must be positive.\n";
136 const double ez,
const double bx,
137 const double by,
const double bz,
138 double& vx,
double& vy,
double& vz) {
141 if (!UpdateTransportParameters()) {
142 std::cerr <<
m_className <<
"::ElectronVelocity:\n"
143 <<
" Error calculating the transport parameters.\n";
154 const double e = sqrt(ex * ex + ey * ey + ez * ez);
158 switch (m_highFieldMobilityModel) {
159 case HighFieldMobility::Minimos:
160 ElectronMobilityMinimos(e, mu);
162 case HighFieldMobility::Canali:
163 ElectronMobilityCanali(e, mu);
165 case HighFieldMobility::Reggiani:
166 ElectronMobilityReggiani(e, mu);
174 const double b = sqrt(bx * bx + by * by + bz * bz);
181 const double muH = m_eHallFactor * mu;
182 const double eb = bx * ex + by * ey + bz * ez;
183 const double mub = muH * b;
184 const double f = mu / (1. + mub * mub);
185 const double muH2 = muH * muH;
187 vx = f * (ex + muH * (ey * bz - ez * by) + muH2 * bx * eb);
188 vy = f * (ey + muH * (ez * bx - ex * bz) + muH2 * by * eb);
189 vz = f * (ez + muH * (ex * by - ey * bx) + muH2 * bz * eb);
195 const double ez,
const double bx,
196 const double by,
const double bz,
200 if (!UpdateTransportParameters()) {
201 std::cerr <<
m_className <<
"::ElectronTownsend:\n"
202 <<
" Error calculating the transport parameters.\n";
213 const double e = sqrt(ex * ex + ey * ey + ez * ez);
215 switch (m_impactIonisationModel) {
216 case ImpactIonisation::VanOverstraeten:
217 return ElectronImpactIonisationVanOverstraetenDeMan(e, alpha);
219 case ImpactIonisation::Grant:
220 return ElectronImpactIonisationGrant(e, alpha);
222 case ImpactIonisation::Massey:
223 return ElectronImpactIonisationMassey(e, alpha);
226 std::cerr <<
m_className <<
"::ElectronTownsend: Unknown model. Bug!\n";
233 const double ez,
const double bx,
234 const double by,
const double bz,
238 if (!UpdateTransportParameters()) {
239 std::cerr <<
m_className <<
"::ElectronAttachment:\n"
240 <<
" Error calculating the transport parameters.\n";
251 switch (m_trappingModel) {
253 eta = m_eTrapCs * m_eTrapDensity;
258 eta = m_eTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
259 if (eta > 0.) eta = 1. / eta;
262 std::cerr <<
m_className <<
"::ElectronAttachment: Unknown model. Bug!\n";
271 const double ez,
const double bx,
272 const double by,
const double bz,
double& vx,
273 double& vy,
double& vz) {
276 if (!UpdateTransportParameters()) {
278 <<
" Error calculating the transport parameters.\n";
289 const double e = sqrt(ex * ex + ey * ey + ez * ez);
293 switch (m_highFieldMobilityModel) {
294 case HighFieldMobility::Minimos:
295 HoleMobilityMinimos(e, mu);
297 case HighFieldMobility::Canali:
298 HoleMobilityCanali(e, mu);
300 case HighFieldMobility::Reggiani:
301 HoleMobilityReggiani(e, mu);
307 const double b = sqrt(bx * bx + by * by + bz * bz);
314 const double muH = m_hHallFactor * mu;
315 const double eb = bx * ex + by * ey + bz * ez;
316 const double mub = muH * b;
317 const double f = mu / (1. + mub * mub);
318 const double muH2 = muH * muH;
320 vx = f * (ex + muH * (ey * bz - ez * by) + muH2 * bx * eb);
321 vy = f * (ey + muH * (ez * bx - ex * bz) + muH2 * by * eb);
322 vz = f * (ez + muH * (ex * by - ey * bx) + muH2 * bz * eb);
328 const double ez,
const double bx,
329 const double by,
const double bz,
333 if (!UpdateTransportParameters()) {
335 <<
" Error calculating the transport parameters.\n";
346 const double e = sqrt(ex * ex + ey * ey + ez * ez);
348 switch (m_impactIonisationModel) {
349 case ImpactIonisation::VanOverstraeten:
350 return HoleImpactIonisationVanOverstraetenDeMan(e, alpha);
352 case ImpactIonisation::Grant:
353 return HoleImpactIonisationGrant(e, alpha);
355 case ImpactIonisation::Massey:
356 return HoleImpactIonisationMassey(e, alpha);
359 std::cerr <<
m_className <<
"::HoleTownsend: Unknown model. Bug!\n";
366 const double ez,
const double bx,
367 const double by,
const double bz,
371 if (!UpdateTransportParameters()) {
373 <<
" Error calculating the transport parameters.\n";
384 switch (m_trappingModel) {
386 eta = m_hTrapCs * m_hTrapDensity;
391 eta = m_hTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
392 if (eta > 0.) eta = 1. / eta;
395 std::cerr <<
m_className <<
"::HoleAttachment: Unknown model. Bug!\n";
404 if (mue <= 0. || muh <= 0.) {
405 std::cerr <<
m_className <<
"::SetLowFieldMobility:\n"
406 <<
" Mobility must be greater than zero.\n";
412 m_hasUserMobility =
true;
417 m_latticeMobilityModel = LatticeMobility::Minimos;
418 m_hasUserMobility =
false;
423 m_latticeMobilityModel = LatticeMobility::Sentaurus;
424 m_hasUserMobility =
false;
429 m_latticeMobilityModel = LatticeMobility::Reggiani;
430 m_hasUserMobility =
false;
435 m_dopingMobilityModel = DopingMobility::Minimos;
436 m_hasUserMobility =
false;
441 m_dopingMobilityModel = DopingMobility::Masetti;
442 m_hasUserMobility =
false;
447 const double vsath) {
448 if (vsate <= 0. || vsath <= 0.) {
449 std::cout <<
m_className <<
"::SetSaturationVelocity:\n"
450 <<
" Restoring default values.\n";
451 m_hasUserSaturationVelocity =
false;
455 m_hasUserSaturationVelocity =
true;
462 m_saturationVelocityModel = SaturationVelocity::Minimos;
463 m_hasUserSaturationVelocity =
false;
468 m_saturationVelocityModel = SaturationVelocity::Canali;
469 m_hasUserSaturationVelocity =
false;
474 m_saturationVelocityModel = SaturationVelocity::Reggiani;
475 m_hasUserSaturationVelocity =
false;
480 m_highFieldMobilityModel = HighFieldMobility::Minimos;
485 m_highFieldMobilityModel = HighFieldMobility::Canali;
490 m_highFieldMobilityModel = HighFieldMobility::Reggiani;
495 m_highFieldMobilityModel = HighFieldMobility::Constant;
499 m_impactIonisationModel = ImpactIonisation::VanOverstraeten;
504 m_impactIonisationModel = ImpactIonisation::Grant;
509 m_impactIonisationModel = ImpactIonisation::Massey;
514 if (e <= m_eMinG + Small) {
515 std::cerr <<
m_className <<
"::SetMaxElectronEnergy:\n"
516 <<
" Requested upper electron energy limit (" << e
517 <<
" eV) is too small.\n";
523 m_eStepG = m_eFinalG / nEnergyStepsG;
531 const double pz,
double& vx,
double& vy,
532 double& vz,
const int band) {
534 double mx = ElectronMass, my = ElectronMass, mz = ElectronMass;
537 if (band >= 0 && band < m_nValleysX) {
563 std::cerr <<
m_className <<
"::GetElectronEnergy:\n"
564 <<
" Unexpected band index " << band <<
"!\n";
569 const double mc = 3. / (1. / m_mLongX + 2. / m_mTransX);
574 }
else if (band < m_nValleysX + m_nValleysL) {
578 const double mc = 3. / (1. / m_mLongL + 2. / m_mTransL);
582 }
else if (band == m_nValleysX + m_nValleysL) {
586 if (m_nonParabolic) {
589 if (band < m_nValleysX) {
592 }
else if (band < m_nValleysX + m_nValleysL) {
597 const double p2 = 0.5 * (px * px / mx + py * py / my + pz * pz / mz);
599 const double e = 0.5 * (sqrt(1. + 4 * alpha * p2) - 1.) / alpha;
600 const double a = SpeedOfLight / (1. + 2 * alpha * e);
608 const double e = 0.5 * (px * px / mx + py * py / my + pz * pz / mz);
609 vx = SpeedOfLight * px / mx;
610 vy = SpeedOfLight * py / my;
611 vz = SpeedOfLight * pz / mz;
616 double& pz,
int& band) {
617 int nBands = m_nValleysX;
618 if (e > m_eMinL) nBands += m_nValleysL;
619 if (e > m_eMinG) ++nBands;
622 if (band < 0 || band > m_nValleysX + m_nValleysL ||
623 (e < m_eMinL || band >= m_nValleysX) ||
624 (e < m_eMinG || band == m_nValleysX + m_nValleysL)) {
627 if (band >= m_nValleysX) band = m_nValleysX - 1;
633 const double dosSum = m_nValleysX * dosX + m_nValleysL * dosL + dosG;
634 if (dosSum < Small) {
635 band = m_nValleysX + m_nValleysL;
640 if (band >= m_nValleysX) band = m_nValleysX - 1;
641 }
else if (r < dosX + dosL) {
642 band = m_nValleysX + int(m_nValleysL *
RndmUniform());
643 if (band >= m_nValleysX + m_nValleysL) band = m_nValleysL - 1;
645 band = m_nValleysX + m_nValleysL;
650 std::cout <<
m_className <<
"::GetElectronMomentum:\n"
651 <<
" Randomised band index: " << band <<
"\n";
654 if (band < m_nValleysX) {
656 double pstar = sqrt(2. * ElectronMass * e);
657 if (m_nonParabolic) {
658 const double alpha = m_alphaX;
659 pstar *= sqrt(1. + alpha * e);
663 const double stheta = sqrt(1. - ctheta * ctheta);
667 const double pl = pstar * sqrt(m_mLongX);
668 const double pt = pstar * sqrt(m_mTransX);
674 py = pt * cos(phi) * stheta;
675 pz = pt * sin(phi) * stheta;
680 px = pt * sin(phi) * stheta;
682 pz = pt * cos(phi) * stheta;
687 px = pt * cos(phi) * stheta;
688 py = pt * sin(phi) * stheta;
693 std::cerr <<
m_className <<
"::GetElectronMomentum:\n"
694 <<
" Unexpected band index (" << band <<
").\n";
695 px = pstar * stheta * cos(phi);
696 py = pstar * stheta * sin(phi);
701 pstar *= sqrt(3. / (1. / m_mLongX + 2. / m_mTransX));
702 px = pstar * cos(phi) * stheta;
703 py = pstar * sin(phi) * stheta;
706 }
else if (band < m_nValleysX + m_nValleysL) {
708 double pstar = sqrt(2. * ElectronMass * (e - m_eMinL));
709 if (m_nonParabolic) {
710 const double alpha = m_alphaL;
711 pstar *= sqrt(1. + alpha * (e - m_eMinL));
713 pstar *= sqrt(3. / (1. / m_mLongL + 2. / m_mTransL));
715 }
else if (band == m_nValleysX + m_nValleysL) {
717 const double pstar = sqrt(2. * ElectronMass * e);
724 if (!UpdateTransportParameters()) {
725 std::cerr <<
m_className <<
"::GetElectronNullCollisionRate:\n"
726 <<
" Error calculating the collision rates table.\n";
732 if (band >= 0 && band < m_nValleysX) {
733 return m_cfNullElectronsX;
734 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
735 return m_cfNullElectronsL;
736 }
else if (band == m_nValleysX + m_nValleysL) {
737 return m_cfNullElectronsG;
739 std::cerr <<
m_className <<
"::GetElectronNullCollisionRate:\n"
740 <<
" Band index (" << band <<
") out of range.\n";
746 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
747 <<
" Electron energy must be positive.\n";
752 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
753 <<
" Collision rate at " << e <<
" eV (band " << band
754 <<
") is not included in the current table.\n"
755 <<
" Increasing energy range to " << 1.05 * e <<
" eV.\n";
760 if (!UpdateTransportParameters()) {
761 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
762 <<
" Error calculating the collision rates table.\n";
768 if (band >= 0 && band < m_nValleysX) {
769 int iE = int(e / m_eStepXL);
770 if (iE >= nEnergyStepsXL)
771 iE = nEnergyStepsXL - 1;
774 return m_cfTotElectronsX[iE];
775 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
776 int iE = int(e / m_eStepXL);
777 if (iE >= nEnergyStepsXL)
778 iE = nEnergyStepsXL - 1;
779 else if (iE < m_ieMinL)
781 return m_cfTotElectronsL[iE];
782 }
else if (band == m_nValleysX + m_nValleysL) {
783 int iE = int(e / m_eStepG);
784 if (iE >= nEnergyStepsG)
785 iE = nEnergyStepsG - 1;
786 else if (iE < m_ieMinG)
788 return m_cfTotElectronsG[iE];
791 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
792 <<
" Band index (" << band <<
") out of range.\n";
797 const double e,
int& type,
int& level,
double& e1,
double& px,
double& py,
798 double& pz, std::vector<std::pair<int, double> >& secondaries,
int& ndxc,
801 std::cerr <<
m_className <<
"::GetElectronCollision:\n"
802 <<
" Requested electron energy (" << e <<
" eV) exceeds the "
803 <<
"current energy range (" << m_eFinalG <<
" eV).\n"
804 <<
" Increasing energy range to " << 1.05 * e <<
" eV.\n";
806 }
else if (e <= 0.) {
807 std::cerr <<
m_className <<
"::GetElectronCollision:\n"
808 <<
" Electron energy must be greater than zero.\n";
813 if (!UpdateTransportParameters()) {
814 std::cerr <<
m_className <<
"::GetElectronCollision:\n"
815 <<
" Error calculating the collision rates table.\n";
824 if (band >= 0 && band < m_nValleysX) {
827 int iE = int(e / m_eStepXL);
828 if (iE >= nEnergyStepsXL) iE = nEnergyStepsXL - 1;
832 if (r <= m_cfElectronsX[iE][0]) {
834 }
else if (r >= m_cfElectronsX[iE][m_nLevelsX - 1]) {
835 level = m_nLevelsX - 1;
837 const auto begin = m_cfElectronsX[iE].cbegin();
838 level = std::lower_bound(begin, begin + m_nLevelsX, r) - begin;
842 type = m_scatTypeElectronsX[level];
844 ++m_nCollElectronDetailed[level];
845 ++m_nCollElectronBand[band];
846 if (type == ElectronCollisionTypeAcousticPhonon) {
847 ++m_nCollElectronAcoustic;
848 }
else if (type == ElectronCollisionTypeIntervalleyG) {
850 ++m_nCollElectronIntervalley;
874 }
else if (type == ElectronCollisionTypeIntervalleyF) {
876 ++m_nCollElectronIntervalley;
886 if (band > 1) band += 2;
893 }
else if (type == ElectronCollisionTypeInterbandXL) {
895 ++m_nCollElectronIntervalley;
897 band = m_nValleysX + int(
RndmUniform() * m_nValleysL);
898 if (band >= m_nValleysX + m_nValleysL)
899 band = m_nValleysX + m_nValleysL - 1;
900 }
else if (type == ElectronCollisionTypeInterbandXG) {
901 ++m_nCollElectronIntervalley;
902 band = m_nValleysX + m_nValleysL;
903 }
else if (type == ElectronCollisionTypeImpurity) {
904 ++m_nCollElectronImpurity;
905 }
else if (type == ElectronCollisionTypeIonisation) {
906 ++m_nCollElectronIonisation;
908 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
909 std::cerr <<
" Unexpected collision type (" << type <<
").\n";
913 loss = m_energyLossElectronsX[level];
915 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
918 int iE = int(e / m_eStepXL);
919 if (iE >= nEnergyStepsXL) iE = nEnergyStepsXL - 1;
920 if (iE < m_ieMinL) iE = m_ieMinL;
923 if (r <= m_cfElectronsL[iE][0]) {
925 }
else if (r >= m_cfElectronsL[iE][m_nLevelsL - 1]) {
926 level = m_nLevelsL - 1;
928 const auto begin = m_cfElectronsL[iE].cbegin();
929 level = std::lower_bound(begin, begin + m_nLevelsL, r) - begin;
933 type = m_scatTypeElectronsL[level];
935 ++m_nCollElectronDetailed[m_nLevelsX + level];
936 ++m_nCollElectronBand[band];
937 if (type == ElectronCollisionTypeAcousticPhonon) {
938 ++m_nCollElectronAcoustic;
939 }
else if (type == ElectronCollisionTypeOpticalPhonon) {
940 ++m_nCollElectronOptical;
941 }
else if (type == ElectronCollisionTypeIntervalleyG ||
942 type == ElectronCollisionTypeIntervalleyF) {
944 ++m_nCollElectronIntervalley;
946 band = m_nValleysX + int(
RndmUniform() * m_nValleysL);
947 if (band >= m_nValleysX + m_nValleysL) band = m_nValleysX + m_nValleysL;
948 }
else if (type == ElectronCollisionTypeInterbandXL) {
950 ++m_nCollElectronIntervalley;
953 if (band >= m_nValleysX) band = m_nValleysX - 1;
954 }
else if (type == ElectronCollisionTypeInterbandLG) {
956 ++m_nCollElectronIntervalley;
957 band = m_nValleysX + m_nValleysL;
958 }
else if (type == ElectronCollisionTypeImpurity) {
959 ++m_nCollElectronImpurity;
960 }
else if (type == ElectronCollisionTypeIonisation) {
961 ++m_nCollElectronIonisation;
963 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
964 std::cerr <<
" Unexpected collision type (" << type <<
").\n";
968 loss = m_energyLossElectronsL[level];
969 }
else if (band == m_nValleysX + m_nValleysL) {
972 int iE = int(e / m_eStepG);
973 if (iE >= nEnergyStepsG) iE = nEnergyStepsG - 1;
974 if (iE < m_ieMinG) iE = m_ieMinG;
977 if (r <= m_cfElectronsG[iE][0]) {
979 }
else if (r >= m_cfElectronsG[iE][m_nLevelsG - 1]) {
980 level = m_nLevelsG - 1;
982 const auto begin = m_cfElectronsG[iE].cbegin();
983 level = std::lower_bound(begin, begin + m_nLevelsG, r) - begin;
987 type = m_scatTypeElectronsG[level];
989 ++m_nCollElectronDetailed[m_nLevelsX + m_nLevelsL + level];
990 ++m_nCollElectronBand[band];
991 if (type == ElectronCollisionTypeAcousticPhonon) {
992 ++m_nCollElectronAcoustic;
993 }
else if (type == ElectronCollisionTypeOpticalPhonon) {
994 ++m_nCollElectronOptical;
995 }
else if (type == ElectronCollisionTypeIntervalleyG ||
996 type == ElectronCollisionTypeIntervalleyF) {
998 ++m_nCollElectronIntervalley;
999 }
else if (type == ElectronCollisionTypeInterbandXG) {
1001 ++m_nCollElectronIntervalley;
1004 if (band >= m_nValleysX) band = m_nValleysX - 1;
1005 }
else if (type == ElectronCollisionTypeInterbandLG) {
1007 ++m_nCollElectronIntervalley;
1009 band = m_nValleysX + int(
RndmUniform() * m_nValleysL);
1010 if (band >= m_nValleysX + m_nValleysL)
1011 band = m_nValleysX + m_nValleysL - 1;
1012 }
else if (type == ElectronCollisionTypeIonisation) {
1013 ++m_nCollElectronIonisation;
1015 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
1016 std::cerr <<
" Unexpected collision type (" << type <<
").\n";
1020 loss = m_energyLossElectronsG[level];
1022 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
1023 std::cerr <<
" Band index (" << band <<
") out of range.\n";
1030 if (type == ElectronCollisionTypeIonisation) {
1031 double ee = 0., eh = 0.;
1033 loss = ee + eh + m_bandGap;
1035 secondaries.emplace_back(std::make_pair(IonProdTypeElectron, ee));
1037 secondaries.emplace_back(std::make_pair(IonProdTypeHole, eh));
1040 if (e < loss) loss = e - 0.00001;
1043 if (e1 < Small) e1 = Small;
1046 if (band >= 0 && band < m_nValleysX) {
1048 double pstar = sqrt(2. * ElectronMass * e1);
1049 if (m_nonParabolic) {
1050 const double alpha = m_alphaX;
1051 pstar *= sqrt(1. + alpha * e1);
1055 const double stheta = sqrt(1. - ctheta * ctheta);
1058 if (m_anisotropic) {
1059 const double pl = pstar * sqrt(m_mLongX);
1060 const double pt = pstar * sqrt(m_mTransX);
1066 py = pt * cos(phi) * stheta;
1067 pz = pt * sin(phi) * stheta;
1072 px = pt * sin(phi) * stheta;
1074 pz = pt * cos(phi) * stheta;
1079 px = pt * cos(phi) * stheta;
1080 py = pt * sin(phi) * stheta;
1088 pstar *= sqrt(3. / (1. / m_mLongX + 2. / m_mTransX));
1089 px = pstar * cos(phi) * stheta;
1090 py = pstar * sin(phi) * stheta;
1091 pz = pstar * ctheta;
1095 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
1097 double pstar = sqrt(2. * ElectronMass * (e1 - m_eMinL));
1098 if (m_nonParabolic) {
1099 const double alpha = m_alphaL;
1100 pstar *= sqrt(1. + alpha * (e1 - m_eMinL));
1102 pstar *= sqrt(3. / (1. / m_mLongL + 2. / m_mTransL));
1106 const double pstar = sqrt(2. * ElectronMass * e1);
1111 std::cerr <<
m_className <<
"::GetElectronCollision:"
1112 <<
" Band index (" << band <<
") out of range.\n";
1119 m_nCollElectronAcoustic = m_nCollElectronOptical = 0;
1120 m_nCollElectronIntervalley = 0;
1121 m_nCollElectronImpurity = 0;
1122 m_nCollElectronIonisation = 0;
1123 const auto nLevels = m_nLevelsX + m_nLevelsL + m_nLevelsG;
1124 m_nCollElectronDetailed.assign(nLevels, 0);
1125 const auto nBands = m_nValleysX + m_nValleysL + 1;
1126 m_nCollElectronBand.assign(nBands, 0);
1130 return m_nCollElectronAcoustic + m_nCollElectronOptical +
1131 m_nCollElectronIntervalley + m_nCollElectronImpurity +
1132 m_nCollElectronIonisation;
1136 return m_nLevelsX + m_nLevelsL + m_nLevelsG;
1140 const unsigned int level)
const {
1141 const unsigned int nLevels = m_nLevelsX + m_nLevelsL + m_nLevelsG;
1142 if (level >= nLevels) {
1143 std::cerr <<
m_className <<
"::GetNumberOfElectronCollisions:\n"
1144 <<
" Scattering rate term (" << level <<
") does not exist.\n";
1147 return m_nCollElectronDetailed[level];
1151 return m_nValleysX + m_nValleysL + 1;
1155 const int nBands = m_nValleysX + m_nValleysL + 1;
1156 if (band < 0 || band >= nBands) {
1157 std::cerr <<
m_className <<
"::GetElectronBandPopulation:\n";
1158 std::cerr <<
" Band index (" << band <<
") out of range.\n";
1161 return m_nCollElectronBand[band];
1165 const unsigned int i) {
1167 std::cerr <<
m_className <<
"::GetOpticalDataRange: Index out of range.\n";
1171 if (m_opticalDataEnergies.empty()) {
1172 if (!LoadOpticalData(m_opticalDataFile)) {
1173 std::cerr <<
m_className <<
"::GetOpticalDataRange:\n"
1174 <<
" Optical data table could not be loaded.\n";
1179 emin = m_opticalDataEnergies.front();
1180 emax = m_opticalDataEnergies.back();
1182 std::cout <<
m_className <<
"::GetOpticalDataRange:\n"
1183 <<
" " << emin <<
" < E [eV] < " << emax <<
"\n";
1189 double& eps2,
const unsigned int i) {
1191 std::cerr <<
m_className +
"::GetDielectricFunction: Index out of range.\n";
1196 if (m_opticalDataEnergies.empty()) {
1197 if (!LoadOpticalData(m_opticalDataFile)) {
1198 std::cerr <<
m_className <<
"::GetDielectricFunction:\n";
1199 std::cerr <<
" Optical data table could not be loaded.\n";
1205 const double emin = m_opticalDataEnergies.front();
1206 const double emax = m_opticalDataEnergies.back();
1207 if (e < emin || e > emax) {
1208 std::cerr <<
m_className <<
"::GetDielectricFunction:\n"
1209 <<
" Requested energy (" << e <<
" eV) "
1210 <<
" is outside the range of the optical data table.\n"
1211 <<
" " << emin <<
" < E [eV] < " << emax <<
"\n";
1217 const auto begin = m_opticalDataEnergies.cbegin();
1218 const auto it1 = std::upper_bound(begin, m_opticalDataEnergies.cend(), e);
1220 eps1 = m_opticalDataEpsilon.front().first;
1221 eps2 = m_opticalDataEpsilon.front().second;
1224 const auto it0 = std::prev(it1);
1227 const double x0 = *it0;
1228 const double x1 = *it1;
1229 const double lnx0 = log(*it0);
1230 const double lnx1 = log(*it1);
1231 const double lnx = log(e);
1232 const double y0 = m_opticalDataEpsilon[it0 - begin].first;
1233 const double y1 = m_opticalDataEpsilon[it1 - begin].first;
1234 if (y0 <= 0. || y1 <= 0.) {
1236 eps1 = y0 + (e - x0) * (y1 - y0) / (x1 - x0);
1239 const double lny0 = log(y0);
1240 const double lny1 = log(y1);
1241 eps1 = lny0 + (lnx - lnx0) * (lny1 - lny0) / (lnx1 - lnx0);
1247 const double lnz0 = log(m_opticalDataEpsilon[it0 - begin].second);
1248 const double lnz1 = log(m_opticalDataEpsilon[it1 - begin].second);
1249 eps2 = lnz0 + (lnx - lnx0) * (lnz1 - lnz0) / (lnx1 - lnx0);
1257 std::cerr <<
m_className <<
"::Initialise: Nothing changed.\n";
1261 if (!UpdateTransportParameters()) {
1262 std::cerr <<
m_className <<
"::Initialise:\n Error preparing "
1263 <<
"transport parameters/calculating collision rates.\n";
1269bool MediumSilicon::UpdateTransportParameters() {
1271 switch (m_impactIonisationModel) {
1272 case ImpactIonisation::VanOverstraeten:
1273 UpdateImpactIonisationVanOverstraetenDeMan();
1275 case ImpactIonisation::Grant:
1276 UpdateImpactIonisationGrant();
1278 case ImpactIonisation::Massey:
1281 std::cerr <<
m_className <<
"::UpdateTransportParameters:\n "
1282 <<
"Unknown impact ionisation model. Program bug!\n";
1286 if (!m_hasUserMobility) {
1288 switch (m_latticeMobilityModel) {
1289 case LatticeMobility::Minimos:
1290 UpdateLatticeMobilityMinimos();
1292 case LatticeMobility::Sentaurus:
1293 UpdateLatticeMobilitySentaurus();
1295 case LatticeMobility::Reggiani:
1296 UpdateLatticeMobilityReggiani();
1299 std::cerr <<
m_className <<
"::UpdateTransportParameters:\n "
1300 <<
"Unknown lattice mobility model. Program bug!\n";
1305 switch (m_dopingMobilityModel) {
1306 case DopingMobility::Minimos:
1307 UpdateDopingMobilityMinimos();
1309 case DopingMobility::Masetti:
1310 UpdateDopingMobilityMasetti();
1313 std::cerr <<
m_className <<
"::UpdateTransportParameters:\n "
1314 <<
"Unknown doping mobility model. Program bug!\n";
1320 if (!m_hasUserSaturationVelocity) {
1321 switch (m_saturationVelocityModel) {
1322 case SaturationVelocity::Minimos:
1323 UpdateSaturationVelocityMinimos();
1325 case SaturationVelocity::Canali:
1326 UpdateSaturationVelocityCanali();
1328 case SaturationVelocity::Reggiani:
1329 UpdateSaturationVelocityReggiani();
1335 if (m_highFieldMobilityModel == HighFieldMobility::Canali) {
1336 UpdateHighFieldMobilityCanali();
1340 std::cout <<
m_className <<
"::UpdateTransportParameters:\n"
1341 <<
" Low-field mobility [cm2 V-1 ns-1]\n"
1342 <<
" Electrons: " << m_eMobility <<
"\n"
1343 <<
" Holes: " << m_hMobility <<
"\n";
1344 if (m_highFieldMobilityModel == HighFieldMobility::Constant) {
1345 std::cout <<
" Mobility is not field-dependent.\n";
1347 std::cout <<
" Saturation velocity [cm / ns]\n"
1348 <<
" Electrons: " << m_eSatVel <<
"\n"
1349 <<
" Holes: " << m_hSatVel <<
"\n";
1353 if (!ElectronScatteringRates())
return false;
1354 if (!HoleScatteringRates())
return false;
1362void MediumSilicon::UpdateLatticeMobilityMinimos() {
1369 constexpr double eMu0 = 1.43e-6;
1370 constexpr double hMu0 = 0.46e-6;
1374 m_eLatticeMobility = eMu0 *
pow(t, -2.);
1375 m_hLatticeMobility = hMu0 *
pow(t, -2.18);
1378void MediumSilicon::UpdateLatticeMobilitySentaurus() {
1385 constexpr double eMu0 = 1.417e-6;
1386 constexpr double hMu0 = 0.4705e-6;
1390 m_eLatticeMobility = eMu0 *
pow(t, -2.5);
1391 m_hLatticeMobility = hMu0 *
pow(t, -2.2);
1394void MediumSilicon::UpdateLatticeMobilityReggiani() {
1400 constexpr double eMu0 = 1.320e-6;
1401 constexpr double hMu0 = 0.460e-6;
1405 m_eLatticeMobility = eMu0 *
pow(t, -2.);
1406 m_hLatticeMobility = hMu0 *
pow(t, -2.2);
1409void MediumSilicon::UpdateDopingMobilityMinimos() {
1417 double eMuMin = 0.080e-6;
1418 double hMuMin = 0.045e-6;
1429 const double eRefC = 1.12e17 * c1;
1430 const double hRefC = 2.23e17 * c1;
1433 m_eMobility = eMuMin +
1434 (m_eLatticeMobility - eMuMin) /
1435 (1. +
pow(m_dopingConcentration / eRefC, alpha));
1436 m_hMobility = hMuMin +
1437 (m_hLatticeMobility - hMuMin) /
1438 (1. +
pow(m_dopingConcentration / hRefC, alpha));
1441void MediumSilicon::UpdateDopingMobilityMasetti() {
1448 if (m_dopingConcentration < 1.e13) {
1449 m_eMobility = m_eLatticeMobility;
1450 m_hMobility = m_hLatticeMobility;
1455 constexpr double eMuMin1 = 0.0522e-6;
1456 constexpr double eMuMin2 = 0.0522e-6;
1457 constexpr double eMu1 = 0.0434e-6;
1458 constexpr double hMuMin1 = 0.0449e-6;
1459 constexpr double hMuMin2 = 0.;
1460 constexpr double hMu1 = 0.029e-6;
1461 constexpr double eCr = 9.68e16;
1462 constexpr double eCs = 3.42e20;
1463 constexpr double hCr = 2.23e17;
1464 constexpr double hCs = 6.10e20;
1465 constexpr double hPc = 9.23e16;
1466 constexpr double eAlpha = 0.68;
1467 constexpr double eBeta = 2.;
1468 constexpr double hAlpha = 0.719;
1469 constexpr double hBeta = 2.;
1471 m_eMobility = eMuMin1 +
1472 (m_eLatticeMobility - eMuMin2) /
1473 (1. +
pow(m_dopingConcentration / eCr, eAlpha)) -
1474 eMu1 / (1. +
pow(eCs / m_dopingConcentration, eBeta));
1476 m_hMobility = hMuMin1 *
exp(-hPc / m_dopingConcentration) +
1477 (m_hLatticeMobility - hMuMin2) /
1478 (1. +
pow(m_dopingConcentration / hCr, hAlpha)) -
1479 hMu1 / (1. +
pow(hCs / m_dopingConcentration, hBeta));
1482void MediumSilicon::UpdateSaturationVelocityMinimos() {
1489 m_eSatVel = 1.e-2 / (1. + 0.74 * (
m_temperature / 300. - 1.));
1490 m_hSatVel = 0.704e-2 / (1. + 0.37 * (
m_temperature / 300. - 1.));
1493void MediumSilicon::UpdateSaturationVelocityCanali() {
1503void MediumSilicon::UpdateSaturationVelocityReggiani() {
1512void MediumSilicon::UpdateHighFieldMobilityCanali() {
1521 m_eBetaCanaliInv = 1. / m_eBetaCanali;
1522 m_hBetaCanaliInv = 1. / m_hBetaCanali;
1525void MediumSilicon::UpdateImpactIonisationVanOverstraetenDeMan() {
1536 constexpr double hbarOmega = 0.063;
1538 const double gamma =
1539 tanh(hbarOmega / (2. * BoltzmannConstant * 300.)) /
1545 m_eImpactA0 = gamma * 7.03e5;
1546 m_eImpactB0 = gamma * 1.231e6;
1547 m_eImpactA1 = gamma * 7.03e5;
1548 m_eImpactB1 = gamma * 1.231e6;
1550 m_hImpactA0 = gamma * 1.582e6;
1551 m_hImpactB0 = gamma * 2.036e6;
1552 m_hImpactA1 = gamma * 6.71e5;
1553 m_hImpactB1 = gamma * 1.693e6;
1556void MediumSilicon::UpdateImpactIonisationGrant() {
1564 constexpr double hbarOmega = 0.063;
1566 const double gamma =
1567 tanh(hbarOmega / (2. * BoltzmannConstant * 300.)) /
1570 m_eImpactA0 = 2.60e6 * gamma;
1571 m_eImpactB0 = 1.43e6 * gamma;
1572 m_eImpactA1 = 6.20e5 * gamma;
1573 m_eImpactB1 = 1.08e6 * gamma;
1574 m_eImpactA2 = 5.05e5 * gamma;
1575 m_eImpactB2 = 9.90e5 * gamma;
1577 m_hImpactA0 = 2.00e6 * gamma;
1578 m_hImpactB0 = 1.97e6 * gamma;
1579 m_hImpactA1 = 5.60e5 * gamma;
1580 m_hImpactB1 = 1.32e6 * gamma;
1583bool MediumSilicon::ElectronMobilityMinimos(
const double e,
double& mu)
const {
1590 const double r = 2 * m_eMobility * e / m_eSatVel;
1591 mu = 2. * m_eMobility / (1. +
sqrt(1. + r * r));
1596bool MediumSilicon::ElectronMobilityCanali(
const double e,
double& mu)
const {
1603 const double r = m_eMobility * e / m_eSatVel;
1604 mu = m_eMobility /
pow(1. +
pow(r, m_eBetaCanali), m_eBetaCanaliInv);
1609bool MediumSilicon::ElectronMobilityReggiani(
const double e,
double& mu)
const {
1617 const double r = m_eMobility * e / m_eSatVel;
1618 constexpr double k = 1. / 1.5;
1619 mu = m_eMobility /
pow(1. +
pow(r, 1.5), k);
1624bool MediumSilicon::ElectronImpactIonisationVanOverstraetenDeMan(
1625 const double e,
double& alpha)
const {
1635 }
else if (e < 4e5) {
1636 alpha = m_eImpactA0 *
exp(-m_eImpactB0 / e);
1638 alpha = m_eImpactA1 *
exp(-m_eImpactB1 / e);
1643bool MediumSilicon::ElectronImpactIonisationGrant(
const double e,
1644 double& alpha)
const {
1650 }
else if (e < 2.4e5) {
1651 alpha = m_eImpactA0 *
exp(-m_eImpactB0 / e);
1652 }
else if (e < 5.3e5) {
1653 alpha = m_eImpactA1 *
exp(-m_eImpactB1 / e);
1655 alpha = m_eImpactA2 *
exp(-m_eImpactB2 / e);
1660bool MediumSilicon::ElectronImpactIonisationMassey(
const double e,
1661 double& alpha)
const {
1666 constexpr double a = 4.43e5;
1667 constexpr double c = 9.66e5;
1668 constexpr double d = 4.99e2;
1678bool MediumSilicon::HoleMobilityMinimos(
const double e,
double& mu)
const {
1685 mu = m_hMobility / (1. + m_hMobility * e / m_eSatVel);
1690bool MediumSilicon::HoleMobilityCanali(
const double e,
double& mu)
const {
1697 const double r = m_hMobility * e / m_hSatVel;
1698 mu = m_hMobility /
pow(1. +
pow(r, m_hBetaCanali), m_hBetaCanaliInv);
1703bool MediumSilicon::HoleMobilityReggiani(
const double e,
double& mu)
const {
1711 const double r = m_hMobility * e / m_hSatVel;
1712 mu = m_hMobility /
sqrt(1. + r * r);
1717bool MediumSilicon::HoleImpactIonisationVanOverstraetenDeMan(
1718 const double e,
double& alpha)
const {
1726 }
else if (e < 4e5) {
1727 alpha = m_hImpactA0 *
exp(-m_hImpactB0 / e);
1729 alpha = m_hImpactA1 *
exp(-m_hImpactB1 / e);
1734bool MediumSilicon::HoleImpactIonisationGrant(
const double e,
1735 double& alpha)
const {
1741 }
else if (e < 5.3e5) {
1742 alpha = m_hImpactA0 *
exp(-m_hImpactB0 / e);
1744 alpha = m_hImpactA1 *
exp(-m_hImpactB1 / e);
1749bool MediumSilicon::HoleImpactIonisationMassey(
const double e,
1750 double& alpha)
const {
1755 constexpr double a = 1.13e6;
1756 constexpr double c = 1.17e6;
1757 constexpr double d = 1.09e3;
1767bool MediumSilicon::LoadOpticalData(
const std::string& filename) {
1769 m_opticalDataEnergies.clear();
1770 m_opticalDataEpsilon.clear();
1773 char* pPath = getenv(
"GARFIELD_HOME");
1775 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
1776 <<
" Environment variable GARFIELD_HOME is not set.\n";
1779 const std::string filepath = std::string(pPath) +
"/Data/" + filename;
1782 std::ifstream infile;
1783 infile.open(filepath.c_str(), std::ios::in);
1786 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
1787 <<
" Error opening file " << filename <<
".\n";
1791 double lastEnergy = -1.;
1792 double energy, eps1, eps2, loss;
1795 std::istringstream dataStream;
1797 while (!infile.eof()) {
1800 std::getline(infile, line);
1803 if (line.empty())
continue;
1805 if (line[0] ==
'#' || line[0] ==
'*' || (line[0] ==
'/' && line[1] ==
'/'))
1808 dataStream.str(line);
1809 dataStream >> energy >> eps1 >> eps2 >> loss;
1810 if (dataStream.eof())
break;
1812 if (infile.fail()) {
1813 std::cerr <<
m_className <<
"::LoadOpticalData:\n Error reading file "
1814 << filename <<
" (line " << i <<
").\n";
1823 if (energy <= lastEnergy) {
1824 std::cerr <<
m_className <<
"::LoadOpticalData:\n Table is not in "
1825 <<
"monotonically increasing order (line " << i <<
").\n"
1826 <<
" " << lastEnergy <<
" " << energy <<
" " << eps1
1827 <<
" " << eps2 <<
"\n";
1832 std::cerr <<
m_className <<
"::LoadOpticalData:\n Negative value "
1833 <<
"of the loss function (line " << i <<
").\n";
1837 if (energy <= 0.)
continue;
1839 m_opticalDataEnergies.emplace_back(energy);
1840 m_opticalDataEpsilon.emplace_back(std::make_pair(eps1, eps2));
1841 lastEnergy = energy;
1844 if (m_opticalDataEnergies.empty()) {
1845 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
1846 <<
" Import of data from file " << filepath <<
"failed.\n"
1847 <<
" No valid data found.\n";
1852 std::cout <<
m_className <<
"::LoadOpticalData:\n Read "
1853 << m_opticalDataEnergies.size() <<
" values from file "
1854 << filepath <<
"\n";
1859bool MediumSilicon::ElectronScatteringRates() {
1861 m_cfTotElectronsX.assign(nEnergyStepsXL, 0.);
1862 m_cfTotElectronsL.assign(nEnergyStepsXL, 0.);
1863 m_cfTotElectronsG.assign(nEnergyStepsG, 0.);
1864 m_cfElectronsX.assign(nEnergyStepsXL, std::vector<double>());
1865 m_cfElectronsL.assign(nEnergyStepsXL, std::vector<double>());
1866 m_cfElectronsG.assign(nEnergyStepsG, std::vector<double>());
1867 m_energyLossElectronsX.clear();
1868 m_energyLossElectronsL.clear();
1869 m_energyLossElectronsG.clear();
1870 m_scatTypeElectronsX.clear();
1871 m_scatTypeElectronsL.clear();
1872 m_scatTypeElectronsG.clear();
1873 m_cfNullElectronsX = 0.;
1874 m_cfNullElectronsL = 0.;
1875 m_cfNullElectronsG = 0.;
1881 ElectronAcousticScatteringRates();
1882 ElectronOpticalScatteringRates();
1883 ElectronImpurityScatteringRates();
1884 ElectronIntervalleyScatteringRatesXX();
1885 ElectronIntervalleyScatteringRatesXL();
1886 ElectronIntervalleyScatteringRatesLL();
1887 ElectronIntervalleyScatteringRatesXGLG();
1888 ElectronIonisationRatesXL();
1889 ElectronIonisationRatesG();
1892 std::cout <<
m_className <<
"::ElectronScatteringRates:\n"
1893 <<
" " << m_nLevelsX <<
" X-valley scattering terms\n"
1894 <<
" " << m_nLevelsL <<
" L-valley scattering terms\n"
1895 <<
" " << m_nLevelsG <<
" higher band scattering terms\n";
1898 std::ofstream outfileX;
1899 std::ofstream outfileL;
1901 outfileX.open(
"ratesX.txt", std::ios::out);
1902 outfileL.open(
"ratesL.txt", std::ios::out);
1905 m_ieMinL = int(m_eMinL / m_eStepXL) + 1;
1906 for (
int i = 0; i < nEnergyStepsXL; ++i) {
1908 for (
int j = m_nLevelsX; j--;) m_cfTotElectronsX[i] += m_cfElectronsX[i][j];
1909 for (
int j = m_nLevelsL; j--;) m_cfTotElectronsL[i] += m_cfElectronsL[i][j];
1912 outfileX << i * m_eStepXL <<
" " << m_cfTotElectronsX[i] <<
" ";
1913 for (
int j = 0; j < m_nLevelsX; ++j) {
1914 outfileX << m_cfElectronsX[i][j] <<
" ";
1917 outfileL << i * m_eStepXL <<
" " << m_cfTotElectronsL[i] <<
" ";
1918 for (
int j = 0; j < m_nLevelsL; ++j) {
1919 outfileL << m_cfElectronsL[i][j] <<
" ";
1924 if (m_cfTotElectronsX[i] > m_cfNullElectronsX) {
1925 m_cfNullElectronsX = m_cfTotElectronsX[i];
1927 if (m_cfTotElectronsL[i] > m_cfNullElectronsL) {
1928 m_cfNullElectronsL = m_cfTotElectronsL[i];
1932 if (m_cfTotElectronsX[i] <= 0.) {
1933 std::cerr <<
m_className <<
"::ElectronScatteringRates:\n X-valley "
1934 <<
"scattering rate at " << i * m_eStepXL <<
" eV <= 0.\n";
1938 for (
int j = 0; j < m_nLevelsX; ++j) {
1939 m_cfElectronsX[i][j] /= m_cfTotElectronsX[i];
1940 if (j > 0) m_cfElectronsX[i][j] += m_cfElectronsX[i][j - 1];
1944 if (m_cfTotElectronsL[i] <= 0.) {
1945 if (i < m_ieMinL)
continue;
1946 std::cerr <<
m_className <<
"::ElectronScatteringRates:\n L-valley "
1947 <<
"scattering rate at " << i * m_eStepXL <<
" eV <= 0.\n";
1951 for (
int j = 0; j < m_nLevelsL; ++j) {
1952 m_cfElectronsL[i][j] /= m_cfTotElectronsL[i];
1953 if (j > 0) m_cfElectronsL[i][j] += m_cfElectronsL[i][j - 1];
1962 std::ofstream outfileG;
1964 outfileG.open(
"ratesG.txt", std::ios::out);
1966 m_ieMinG = int(m_eMinG / m_eStepG) + 1;
1967 for (
int i = 0; i < nEnergyStepsG; ++i) {
1969 for (
int j = m_nLevelsG; j--;) m_cfTotElectronsG[i] += m_cfElectronsG[i][j];
1972 outfileG << i * m_eStepG <<
" " << m_cfTotElectronsG[i] <<
" ";
1973 for (
int j = 0; j < m_nLevelsG; ++j) {
1974 outfileG << m_cfElectronsG[i][j] <<
" ";
1979 if (m_cfTotElectronsG[i] > m_cfNullElectronsG) {
1980 m_cfNullElectronsG = m_cfTotElectronsG[i];
1984 if (m_cfTotElectronsG[i] <= 0.) {
1985 if (i < m_ieMinG)
continue;
1986 std::cerr <<
m_className <<
"::ElectronScatteringRates:\n Higher "
1987 <<
"band scattering rate at " << i * m_eStepG <<
" eV <= 0.\n";
1990 for (
int j = 0; j < m_nLevelsG; ++j) {
1991 m_cfElectronsG[i][j] /= m_cfTotElectronsG[i];
1992 if (j > 0) m_cfElectronsG[i][j] += m_cfElectronsG[i][j - 1];
2003bool MediumSilicon::ElectronAcousticScatteringRates() {
2009 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2015 constexpr double defpot2 = 9. * 9.;
2017 constexpr double u = 9.04e-4;
2019 const double cIntra = TwoPi * SpeedOfLight * SpeedOfLight * kbt * defpot2 /
2020 (Hbar * u * u * rho);
2024 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2028 m_cfElectronsX[i].push_back(cIntra * dosX);
2029 m_cfElectronsL[i].push_back(cIntra * dosL);
2034 for (
int i = 0; i < nEnergyStepsG; ++i) {
2037 m_cfElectronsG[i].push_back(cIntra * dosG);
2042 m_energyLossElectronsX.push_back(0.);
2043 m_energyLossElectronsL.push_back(0.);
2044 m_energyLossElectronsG.push_back(0.);
2045 m_scatTypeElectronsX.push_back(ElectronCollisionTypeAcousticPhonon);
2046 m_scatTypeElectronsL.push_back(ElectronCollisionTypeAcousticPhonon);
2047 m_scatTypeElectronsG.push_back(ElectronCollisionTypeAcousticPhonon);
2055bool MediumSilicon::ElectronOpticalScatteringRates() {
2066 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2071 constexpr double dtk = 2.2e8;
2073 constexpr double eph = 63.0e-3;
2075 const double nocc = 1. / (
exp(eph / kbt) - 1);
2077 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2078 double c = c0 * dtk * dtk / eph;
2104 for (
int i = 0; i < nEnergyStepsG; ++i) {
2109 m_cfElectronsG[i].push_back(c * nocc * dos);
2111 m_cfElectronsG[i].push_back(0.);
2114 if (en > m_eMinG + eph) {
2117 m_cfElectronsG[i].push_back(c * (nocc + 1) * dos);
2119 m_cfElectronsG[i].push_back(0.);
2126 m_energyLossElectronsG.push_back(-eph);
2129 m_energyLossElectronsG.push_back(eph);
2132 m_scatTypeElectronsG.push_back(ElectronCollisionTypeOpticalPhonon);
2133 m_scatTypeElectronsG.push_back(ElectronCollisionTypeOpticalPhonon);
2141bool MediumSilicon::ElectronIntervalleyScatteringRatesXX() {
2147 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2151 constexpr unsigned int nPhonons = 6;
2157 constexpr double dtk[nPhonons] = {0.5e8, 0.8e8, 1.1e9, 0.3e8, 2.0e8, 2.0e8};
2159 constexpr double eph[nPhonons] = {12.06e-3, 18.53e-3, 62.04e-3,
2160 18.86e-3, 47.39e-3, 59.03e-3};
2162 double nocc[nPhonons];
2164 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2167 for (
unsigned int j = 0; j < nPhonons; ++j) {
2168 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2169 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2170 if (j > 2) c[j] *= 4;
2174 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2175 for (
unsigned int j = 0; j < nPhonons; ++j) {
2178 m_cfElectronsX[i].push_back(c[j] * nocc[j] * dos);
2182 m_cfElectronsX[i].push_back(c[j] * (nocc[j] + 1) * dos);
2184 m_cfElectronsX[i].push_back(0.);
2190 for (
unsigned int j = 0; j < nPhonons; ++j) {
2192 m_energyLossElectronsX.push_back(-eph[j]);
2194 m_energyLossElectronsX.push_back(eph[j]);
2196 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyG);
2197 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyG);
2199 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyF);
2200 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyF);
2204 m_nLevelsX += 2 * nPhonons;
2209bool MediumSilicon::ElectronIntervalleyScatteringRatesXL() {
2216 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2220 constexpr unsigned int nPhonons = 4;
2223 constexpr double dtk[nPhonons] = {2.e8, 2.e8, 2.e8, 2.e8};
2225 constexpr double eph[nPhonons] = {58.e-3, 55.e-3, 41.e-3, 17.e-3};
2227 constexpr unsigned int zX = 6;
2228 constexpr unsigned int zL = 8;
2231 double nocc[nPhonons] = {0.};
2233 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2236 for (
unsigned int j = 0; j < nPhonons; ++j) {
2237 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2238 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2242 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2243 for (
unsigned int j = 0; j < nPhonons; ++j) {
2246 if (en + eph[j] > m_eMinL) {
2248 m_cfElectronsX[i].push_back(zL * c[j] * nocc[j] * dos);
2250 m_cfElectronsX[i].push_back(0.);
2253 if (en - eph[j] > m_eMinL) {
2255 m_cfElectronsX[i].push_back(zL * c[j] * (nocc[j] + 1) * dos);
2257 m_cfElectronsX[i].push_back(0.);
2263 m_cfElectronsL[i].push_back(zX * c[j] * nocc[j] * dos);
2266 m_cfElectronsL[i].push_back(zX * c[j] * (nocc[j] + 1) * dos);
2268 m_cfElectronsL[i].push_back(0.);
2269 m_cfElectronsL[i].push_back(0.);
2275 for (
unsigned int j = 0; j < nPhonons; ++j) {
2277 m_energyLossElectronsX.push_back(-eph[j]);
2278 m_energyLossElectronsL.push_back(-eph[j]);
2280 m_energyLossElectronsX.push_back(eph[j]);
2281 m_energyLossElectronsL.push_back(eph[j]);
2282 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXL);
2283 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXL);
2284 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandXL);
2285 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandXL);
2288 m_nLevelsX += 2 * nPhonons;
2289 m_nLevelsL += 2 * nPhonons;
2294bool MediumSilicon::ElectronIntervalleyScatteringRatesLL() {
2303 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2307 const int nPhonons = 1;
2309 const double dtk[nPhonons] = {2.63e8};
2311 const double eph[nPhonons] = {38.87e-3};
2313 double nocc[nPhonons];
2315 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2318 for (
int j = 0; j < nPhonons; ++j) {
2319 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2320 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2326 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2327 for (
int j = 0; j < nPhonons; ++j) {
2330 m_cfElectronsL[i].push_back(c[j] * nocc[j] * dos);
2332 if (en > m_eMinL + eph[j]) {
2334 m_cfElectronsL[i].push_back(c[j] * (nocc[j] + 1) * dos);
2336 m_cfElectronsL[i].push_back(0.);
2342 for (
int j = 0; j < nPhonons; ++j) {
2344 m_energyLossElectronsL.push_back(-eph[j]);
2346 m_energyLossElectronsL.push_back(eph[j]);
2347 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIntervalleyF);
2348 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIntervalleyF);
2351 m_nLevelsL += 2 * nPhonons;
2356bool MediumSilicon::ElectronIntervalleyScatteringRatesXGLG() {
2363 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2367 const int nPhonons = 1;
2371 const double dtk[nPhonons] = {2.43e8};
2373 const double eph[nPhonons] = {37.65e-3};
2380 double nocc[nPhonons] = {0.};
2382 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2385 for (
int j = 0; j < nPhonons; ++j) {
2386 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2387 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2393 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2394 for (
int j = 0; j < nPhonons; ++j) {
2396 if (en + eph[j] > m_eMinG) {
2398 m_nValleysX + m_nValleysL);
2399 m_cfElectronsX[i].push_back(zG * c[j] * nocc[j] * dos);
2400 m_cfElectronsL[i].push_back(zG * c[j] * nocc[j] * dos);
2402 m_cfElectronsX[i].push_back(0.);
2403 m_cfElectronsL[i].push_back(0.);
2406 if (en - eph[j] > m_eMinG) {
2408 m_nValleysX + m_nValleysL);
2409 m_cfElectronsX[i].push_back(zG * c[j] * (nocc[j] + 1) * dos);
2410 m_cfElectronsL[i].push_back(zG * c[j] * (nocc[j] + 1) * dos);
2412 m_cfElectronsX[i].push_back(0.);
2413 m_cfElectronsL[i].push_back(0.);
2421 double dosX = 0., dosL = 0.;
2422 for (
int i = 0; i < nEnergyStepsG; ++i) {
2423 for (
int j = 0; j < nPhonons; ++j) {
2427 m_cfElectronsG[i].push_back(zX * c[j] * nocc[j] * dosX);
2429 m_cfElectronsG[i].push_back(zL * c[j] * nocc[j] * dosL);
2431 m_cfElectronsG[i].push_back(0.);
2437 m_cfElectronsG[i].push_back(zX * c[j] * (nocc[j] + 1) * dosX);
2439 m_cfElectronsG[i].push_back(0.);
2441 if (en - eph[j] > m_eMinL) {
2442 m_cfElectronsG[i].push_back(zL * c[j] * (nocc[j] + 1) * dosL);
2444 m_cfElectronsG[i].push_back(0.);
2450 for (
int j = 0; j < nPhonons; ++j) {
2452 m_energyLossElectronsX.push_back(-eph[j]);
2453 m_energyLossElectronsL.push_back(-eph[j]);
2455 m_energyLossElectronsX.push_back(eph[j]);
2456 m_energyLossElectronsL.push_back(eph[j]);
2458 m_energyLossElectronsG.push_back(-eph[j]);
2459 m_energyLossElectronsG.push_back(-eph[j]);
2461 m_energyLossElectronsG.push_back(eph[j]);
2462 m_energyLossElectronsG.push_back(eph[j]);
2464 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXG);
2465 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXG);
2466 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandLG);
2467 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandLG);
2469 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandXG);
2470 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandLG);
2471 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandXG);
2472 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandLG);
2475 m_nLevelsX += 2 * nPhonons;
2476 m_nLevelsL += 2 * nPhonons;
2477 m_nLevelsG += 4 * nPhonons;
2482bool MediumSilicon::ElectronIonisationRatesXL() {
2489 constexpr double p[3] = {6.25e1, 3.e3, 6.8e5};
2491 constexpr double eth[3] = {1.2, 1.8, 3.45};
2494 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2497 fIon += p[0] * (en - eth[0]) * (en - eth[0]);
2500 fIon += p[1] * (en - eth[1]) * (en - eth[1]);
2503 fIon += p[2] * (en - eth[2]) * (en - eth[2]);
2505 m_cfElectronsX[i].push_back(fIon);
2506 m_cfElectronsL[i].push_back(fIon);
2510 m_energyLossElectronsX.push_back(eth[0]);
2511 m_energyLossElectronsL.push_back(eth[0]);
2512 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIonisation);
2513 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIonisation);
2520bool MediumSilicon::ElectronIonisationRatesG() {
2528 constexpr double p[3] = {6.25e1, 3.e3, 6.8e5};
2530 constexpr double eth[3] = {1.2, 1.8, 3.45};
2533 for (
int i = 0; i < nEnergyStepsG; ++i) {
2536 fIon += p[0] * (en - eth[0]) * (en - eth[0]);
2539 fIon += p[1] * (en - eth[1]) * (en - eth[1]);
2542 fIon += p[2] * (en - eth[2]) * (en - eth[2]);
2544 if (en >= m_eMinG) {
2545 m_cfElectronsG[i].push_back(fIon);
2547 m_cfElectronsG[i].push_back(0.);
2552 m_energyLossElectronsG.push_back(eth[0]);
2553 m_scatTypeElectronsG.push_back(ElectronCollisionTypeIonisation);
2559bool MediumSilicon::ElectronImpurityScatteringRates() {
2566 ElectronMass *
pow(m_mLongX * m_mTransX * m_mTransX, 1. / 3.);
2568 ElectronMass *
pow(m_mLongL * m_mTransL * m_mTransL, 1. / 3.);
2573 const double impurityConcentration = m_dopingConcentration;
2574 if (impurityConcentration < Small)
return true;
2577 const double ls =
sqrt(eps * kbt / (4 * Pi * FineStructureConstant * HbarC *
2578 impurityConcentration));
2579 const double ebX = 0.5 * HbarC * HbarC / (mdX * ls * ls);
2580 const double ebL = 0.5 * HbarC * HbarC / (mdL * ls * ls);
2587 const double cX = impurityConcentration * Pi *
2588 pow(FineStructureConstant * HbarC, 2) * SpeedOfLight /
2589 (
sqrt(2 * mdX) * eps * eps);
2590 const double cL = impurityConcentration * Pi *
2591 pow(FineStructureConstant * HbarC, 2) * SpeedOfLight /
2592 (
sqrt(2 * mdL) * eps * eps);
2595 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2596 const double gammaX = en * (1. + m_alphaX * en);
2597 const double gammaL = (en - m_eMinL) * (1. + m_alphaL * (en - m_eMinL));
2601 m_cfElectronsX[i].push_back(0.);
2603 const double b = 4 * gammaX / ebX;
2604 m_cfElectronsX[i].push_back((cX /
pow(gammaX, 1.5)) *
2605 (log(1. + b) - b / (1. + b)));
2607 if (en <= m_eMinL || gammaL <= 0.) {
2608 m_cfElectronsL[i].push_back(0.);
2610 const double b = 4 * gammaL / ebL;
2611 m_cfElectronsL[i].push_back((cL /
pow(gammaL, 1.5)) *
2612 (log(1. + b) - b / (1. + b)));
2617 m_energyLossElectronsX.push_back(0.);
2618 m_energyLossElectronsL.push_back(0.);
2619 m_scatTypeElectronsX.push_back(ElectronCollisionTypeImpurity);
2620 m_scatTypeElectronsL.push_back(ElectronCollisionTypeImpurity);
2627bool MediumSilicon::HoleScatteringRates() {
2629 m_cfTotHoles.assign(nEnergyStepsV, 0.);
2630 m_cfHoles.assign(nEnergyStepsV, std::vector<double>());
2631 m_energyLossHoles.clear();
2632 m_scatTypeHoles.clear();
2637 HoleAcousticScatteringRates();
2638 HoleOpticalScatteringRates();
2640 HoleIonisationRates();
2642 std::ofstream outfile;
2644 outfile.open(
"ratesV.txt", std::ios::out);
2647 for (
int i = 0; i < nEnergyStepsV; ++i) {
2649 for (
int j = m_nLevelsV; j--;) m_cfTotHoles[i] += m_cfHoles[i][j];
2652 outfile << i * m_eStepV <<
" " << m_cfTotHoles[i] <<
" ";
2653 for (
int j = 0; j < m_nLevelsV; ++j) {
2654 outfile << m_cfHoles[i][j] <<
" ";
2659 if (m_cfTotHoles[i] > m_cfNullHoles) {
2660 m_cfNullHoles = m_cfTotHoles[i];
2664 if (m_cfTotHoles[i] <= 0.) {
2665 std::cerr <<
m_className <<
"::HoleScatteringRates:\n"
2666 <<
" Scattering rate at " << i * m_eStepV <<
" eV <= 0.\n";
2670 for (
int j = 0; j < m_nLevelsV; ++j) {
2671 m_cfHoles[i][j] /= m_cfTotHoles[i];
2672 if (j > 0) m_cfHoles[i][j] += m_cfHoles[i][j - 1];
2683bool MediumSilicon::HoleAcousticScatteringRates() {
2691 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2698 constexpr double defpot2 = 4.6 * 4.6;
2700 constexpr double u = 9.04e-4;
2702 const double cIntra = TwoPi * SpeedOfLight * SpeedOfLight * kbt * defpot2 /
2703 (Hbar * u * u * rho);
2707 for (
int i = 0; i < nEnergyStepsV; ++i) {
2709 m_cfHoles[i].push_back(cIntra * dos);
2714 m_energyLossHoles.push_back(0.);
2715 m_scatTypeHoles.push_back(ElectronCollisionTypeAcousticPhonon);
2721bool MediumSilicon::HoleOpticalScatteringRates() {
2729 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2735 constexpr double dtk = 6.6e8;
2737 constexpr double eph = 63.0e-3;
2739 const double nocc = 1. / (
exp(eph / kbt) - 1);
2741 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2742 double c = c0 * dtk * dtk / eph;
2745 for (
int i = 0; i < nEnergyStepsV; ++i) {
2748 m_cfHoles[i].push_back(c * nocc * dos);
2752 m_cfHoles[i].push_back(c * (nocc + 1) * dos);
2754 m_cfHoles[i].push_back(0.);
2760 m_energyLossHoles.push_back(-eph);
2762 m_energyLossHoles.push_back(eph);
2763 m_scatTypeHoles.push_back(ElectronCollisionTypeOpticalPhonon);
2764 m_scatTypeHoles.push_back(ElectronCollisionTypeOpticalPhonon);
2771bool MediumSilicon::HoleIonisationRates() {
2776 constexpr double p[2] = {2., 1.e3};
2778 constexpr double eth[2] = {1.1, 1.45};
2780 constexpr double b[2] = {6., 4.};
2783 for (
int i = 0; i < nEnergyStepsV; ++i) {
2786 fIon += p[0] *
pow(en - eth[0], b[0]);
2789 fIon += p[1] *
pow(en - eth[1], b[1]);
2791 m_cfHoles[i].push_back(fIon);
2795 m_energyLossHoles.push_back(eth[0]);
2796 m_scatTypeHoles.push_back(ElectronCollisionTypeIonisation);
2805 int iE = int(e / m_eStepDos);
2806 const int nPoints = m_fbDosConduction.size();
2807 if (iE >= nPoints || iE < 0) {
2809 }
else if (iE == nPoints - 1) {
2810 return m_fbDosConduction[nPoints - 1];
2813 const double dos = m_fbDosConduction[iE] +
2814 (m_fbDosConduction[iE + 1] - m_fbDosConduction[iE]) *
2815 (e / m_eStepDos - iE);
2818 }
else if (band < m_nValleysX) {
2820 if (e <= 0.)
return 0.;
2822 const double md3 = pow(ElectronMass, 3) * m_mLongX * m_mTransX * m_mTransX;
2824 if (m_fullBandDos) {
2827 }
else if (e < m_eMinG) {
2833 return dosX / m_nValleysX;
2841 if (dosX <= 0.)
return 0.;
2842 return dosX / m_nValleysX;
2844 }
else if (m_nonParabolic) {
2845 const double alpha = m_alphaX;
2846 return sqrt(md3 * e * (1. + alpha * e) / 2.) * (1. + 2 * alpha * e) /
2847 (Pi2 * pow(HbarC, 3.));
2849 return sqrt(md3 * e / 2.) / (Pi2 * pow(HbarC, 3.));
2851 }
else if (band < m_nValleysX + m_nValleysL) {
2853 if (e <= m_eMinL)
return 0.;
2856 const double md3 = pow(ElectronMass, 3) * m_mLongL * m_mTransL * m_mTransL;
2858 const double alpha = m_alphaL;
2860 if (m_fullBandDos) {
2862 const double ej = m_eMinL + 0.5;
2864 return sqrt(md3 * (e - m_eMinL) * (1. + alpha * (e - m_eMinL))) *
2865 (1. + 2 * alpha * (e - m_eMinL)) /
2866 (Sqrt2 * Pi2 * pow(HbarC, 3.));
2869 double fL = sqrt(md3 * (ej - m_eMinL) * (1. + alpha * (ej - m_eMinL))) *
2870 (1. + 2 * alpha * (ej - m_eMinL)) /
2871 (Sqrt2 * Pi2 * pow(HbarC, 3.));
2879 if (dosXL <= 0.)
return 0.;
2880 return fL * dosXL / 8.;
2882 }
else if (m_nonParabolic) {
2883 return sqrt(md3 * (e - m_eMinL) * (1. + alpha * (e - m_eMinL))) *
2884 (1. + 2 * alpha * (e - m_eMinL)) / (Sqrt2 * Pi2 * pow(HbarC, 3.));
2886 return sqrt(md3 * (e - m_eMinL) / 2.) / (Pi2 * pow(HbarC, 3.));
2888 }
else if (band == m_nValleysX + m_nValleysL) {
2890 const double ej = 2.7;
2891 if (m_eMinG >= ej) {
2892 std::cerr <<
m_className <<
"::GetConductionBandDensityOfStates:\n"
2893 <<
" Cannot determine higher band density-of-states.\n"
2894 <<
" Program bug. Check offset energy!\n";
2899 }
else if (e < ej) {
2903 return dj * (e - m_eMinG) / (ej - m_eMinG);
2909 std::cerr <<
m_className <<
"::GetConductionBandDensityOfStates:\n"
2910 <<
" Band index (" << band <<
") out of range.\n";
2911 return ElectronMass * sqrt(ElectronMass * e / 2.) / (Pi2 * pow(HbarC, 3.));
2918 const int nPoints = m_fbDosValence.size();
2919 int iE = int(e / m_eStepDos);
2920 if (iE >= nPoints || iE < 0) {
2922 }
else if (iE == nPoints - 1) {
2923 return m_fbDosValence[nPoints - 1];
2927 m_fbDosValence[iE] +
2928 (m_fbDosValence[iE + 1] - m_fbDosValence[iE]) * (e / m_eStepDos - iE);
2932 std::cerr <<
m_className <<
"::GetConductionBandDensityOfStates:\n"
2933 <<
" Band index (" << band <<
") out of range.\n";
2939 const int nPointsValence = m_fbDosValence.size();
2940 const int nPointsConduction = m_fbDosConduction.size();
2941 const double widthValenceBand = m_eStepDos * nPointsValence;
2942 const double widthConductionBand = m_eStepDos * nPointsConduction;
2948 int ih = std::min(
int(eh / m_eStepDos), nPointsValence - 1);
2949 while (
RndmUniform() > m_fbDosValence[ih] / m_fbDosMaxV) {
2951 ih = std::min(
int(eh / m_eStepDos), nPointsValence - 1);
2955 int ie = std::min(
int(ee / m_eStepDos), nPointsConduction - 1);
2956 while (
RndmUniform() > m_fbDosConduction[ie] / m_fbDosMaxC) {
2958 ie = std::min(
int(ee / m_eStepDos), nPointsConduction - 1);
2961 const double ep = e0 - m_bandGap - eh - ee;
2962 if (ep < Small)
continue;
2963 if (ep > 5.)
return;
2965 int ip = std::min(
int(ep / m_eStepDos), nPointsConduction - 1);
2966 if (
RndmUniform() > m_fbDosConduction[ip] / m_fbDosMaxC)
continue;
2971void MediumSilicon::InitialiseDensityOfStates() {
2975 {0., 1.28083, 2.08928, 2.70763, 3.28095, 3.89162, 4.50547, 5.15043,
2976 5.89314, 6.72667, 7.67768, 8.82725, 10.6468, 12.7003, 13.7457, 14.0263,
2977 14.2731, 14.5527, 14.8808, 15.1487, 15.4486, 15.7675, 16.0519, 16.4259,
2978 16.7538, 17.0589, 17.3639, 17.6664, 18.0376, 18.4174, 18.2334, 16.7552,
2979 15.1757, 14.2853, 13.6516, 13.2525, 12.9036, 12.7203, 12.6104, 12.6881,
2980 13.2862, 14.0222, 14.9366, 13.5084, 9.77808, 6.15266, 3.47839, 2.60183,
2981 2.76747, 3.13985, 3.22524, 3.29119, 3.40868, 3.6118, 3.8464, 4.05776,
2982 4.3046, 4.56219, 4.81553, 5.09909, 5.37616, 5.67297, 6.04611, 6.47252,
2983 6.9256, 7.51254, 8.17923, 8.92351, 10.0309, 11.726, 16.2853, 18.2457,
2984 12.8879, 7.86019, 6.02275, 5.21777, 4.79054, 3.976, 3.11855, 2.46854,
2985 1.65381, 0.830278, 0.217735}};
2987 m_fbDosConduction = {
2988 {0., 1.5114, 2.71026, 3.67114, 4.40173, 5.05025, 5.6849, 6.28358,
2989 6.84628, 7.43859, 8.00204, 8.80658, 9.84885, 10.9579, 12.0302, 13.2051,
2990 14.6948, 16.9879, 18.4492, 18.1933, 17.6747, 16.8135, 15.736, 14.4965,
2991 13.1193, 12.1817, 12.6109, 15.3148, 19.4936, 23.0093, 24.4106, 22.2834,
2992 19.521, 18.9894, 18.8015, 17.9363, 17.0252, 15.9871, 14.8486, 14.3797,
2993 14.2426, 14.3571, 14.7271, 14.681, 14.3827, 14.2789, 14.144, 14.1684,
2994 14.1418, 13.9237, 13.7558, 13.5691, 13.4567, 13.2693, 12.844, 12.4006,
2995 12.045, 11.7729, 11.3607, 11.14, 11.0586, 10.5475, 9.73786, 9.34423,
2996 9.4694, 9.58071, 9.6967, 9.84854, 10.0204, 9.82705, 9.09102, 8.30665,
2997 7.67306, 7.18925, 6.79675, 6.40713, 6.21687, 6.33267, 6.5223, 6.17877,
2998 5.48659, 4.92208, 4.44239, 4.02941, 3.5692, 3.05953, 2.6428, 2.36979,
2999 2.16273, 2.00627, 1.85206, 1.71265, 1.59497, 1.46681, 1.34913, 1.23951,
3000 1.13439, 1.03789, 0.924155, 0.834962, 0.751017}};
3002 auto it = std::max_element(m_fbDosValence.begin(), m_fbDosValence.end());
3004 it = std::max_element(m_fbDosConduction.begin(), m_fbDosConduction.end());
bool GetDielectricFunction(const double e, double &eps1, double &eps2, const unsigned int i=0) override
Get the complex dielectric function at a given energy.
void SetLatticeMobilityModelReggiani()
Calculate the lattice mobility using the Reggiani model.
void SetDoping(const char type, const double c)
Set doping concentration [cm-3] and type ('i', 'n', 'p').
void GetDoping(char &type, double &c) const
Retrieve doping concentration.
bool ElectronTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha) override
Ionisation coefficient [cm-1].
void SetHighFieldMobilityModelReggiani()
Parameterize the high-field mobility using the Reggiani model.
double GetElectronCollisionRate(const double e, const int band) override
Collision rate [ns-1] for given electron energy.
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) override
Drift velocity [cm / ns].
unsigned int GetNumberOfLevels() const
void SetSaturationVelocityModelReggiani()
Calculate the saturation velocities using the Reggiani model.
bool ElectronAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta) override
Attachment coefficient [cm-1].
double GetValenceBandDensityOfStates(const double e, const int band=-1)
bool GetElectronCollision(const double e, int &type, int &level, double &e1, double &dx, double &dy, double &dz, std::vector< std::pair< int, double > > &secondaries, int &ndxc, int &band) override
Sample the collision type. Update energy and direction vector.
void SetDopingMobilityModelMasetti()
Use the Masetti model for the doping-dependence of the mobility (default).
void SetTrapDensity(const double n)
Trap density [cm-3], by default set to zero.
void SetHighFieldMobilityModelMinimos()
Parameterize the high-field mobility using the Minimos model.
MediumSilicon()
Constructor.
void SetSaturationVelocity(const double vsate, const double vsath)
Specify the saturation velocities of electrons and holes.
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) override
Drift velocity [cm / ns].
void ComputeSecondaries(const double e0, double &ee, double &eh)
void ResetCollisionCounters()
double GetConductionBandDensityOfStates(const double e, const int band=0)
bool SetMaxElectronEnergy(const double e)
bool HoleTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha) override
Ionisation coefficient [cm-1].
void SetHighFieldMobilityModelConstant()
Make the velocity proportional to the electric field (no saturation).
void SetLatticeMobilityModelSentaurus()
Calculate the lattice mobility using the Sentaurus model (default).
void SetSaturationVelocityModelCanali()
Calculate the saturation velocities using the Canali model (default).
void SetHighFieldMobilityModelCanali()
Parameterize the high-field mobility using the Canali model (default).
void GetElectronMomentum(const double e, double &px, double &py, double &pz, int &band) override
void SetImpactIonisationModelVanOverstraetenDeMan()
Calculate α using the van Overstraeten-de Man model (default).
void SetTrappingTime(const double etau, const double htau)
Set time constant for trapping of electrons and holes [ns].
void SetSaturationVelocityModelMinimos()
Calculate the saturation velocities using the Minimos model.
void SetLowFieldMobility(const double mue, const double muh)
Specify the low field values of the electron and hole mobilities.
bool HoleAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta) override
Attachment coefficient [cm-1].
double GetElectronEnergy(const double px, const double py, const double pz, double &vx, double &vy, double &vz, const int band=0) override
Dispersion relation (energy vs. wave vector)
bool GetOpticalDataRange(double &emin, double &emax, const unsigned int i=0) override
Get the energy range [eV] of the available optical data.
double GetElectronNullCollisionRate(const int band) override
Null-collision rate [ns-1].
unsigned int GetNumberOfElectronCollisions() const
void SetLatticeMobilityModelMinimos()
Calculate the lattice mobility using the Minimos model.
void SetTrapCrossSection(const double ecs, const double hcs)
Trapping cross-sections for electrons and holes.
int GetElectronBandPopulation(const int band)
void SetImpactIonisationModelGrant()
Calculate α using the Grant model.
void SetDopingMobilityModelMinimos()
Use the Minimos model for the doping-dependence of the mobility.
void SetImpactIonisationModelMassey()
Calculate α using the Massey model.
unsigned int GetNumberOfElectronBands() const
Abstract base class for media.
void SetTemperature(const double t)
Set the temperature [K].
virtual bool HoleTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
Ionisation coefficient [cm-1].
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)
Drift velocity [cm / ns].
std::vector< std::vector< std::vector< double > > > m_eAlp
std::vector< std::vector< std::vector< double > > > m_hAlp
virtual void EnableDrift(const bool on=true)
Switch electron/ion/hole on/off.
double GetDielectricConstant() const
Get the relative static dielectric constant.
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)
Drift velocity [cm / ns].
virtual void EnablePrimaryIonisation(const bool on=true)
Make the medium ionisable or non-ionisable.
virtual void SetAtomicNumber(const double z)
Set the effective atomic number.
std::vector< std::vector< std::vector< double > > > m_eVelE
void SetDielectricConstant(const double eps)
Set the relative static dielectric constant.
virtual bool ElectronTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
Ionisation coefficient [cm-1].
std::vector< std::vector< std::vector< double > > > m_eAtt
virtual void SetMassDensity(const double rho)
Set the mass density [g/cm3].
std::vector< std::vector< std::vector< double > > > m_hVelE
virtual bool ElectronAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
Attachment coefficient [cm-1].
std::vector< std::vector< std::vector< double > > > m_hAtt
virtual void SetAtomicWeight(const double a)
Set the effective atomic weight.
virtual bool HoleAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
Attachment coefficient [cm-1].
double RndmUniform()
Draw a random number uniformly distributed in the range [0, 1).
void ltrim(std::string &line)
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)