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 emag = sqrt(ex * ex + ey * ey + ez * ez);
158 switch (m_highFieldMobilityModel) {
159 case HighFieldMobility::Minimos:
160 ElectronMobilityMinimos(emag, mu);
162 case HighFieldMobility::Canali:
163 ElectronMobilityCanali(emag, mu);
165 case HighFieldMobility::Reggiani:
166 ElectronMobilityReggiani(emag, mu);
174 const double b2 = bx * bx + by * by + bz * bz;
181 const double muH = m_eHallFactor * mu;
182 const double mu2 = muH * muH;
183 const double f = mu / (1. + mu2 * b2);
184 const double eb = bx * ex + by * ey + bz * ez;
186 vx = f * (ex + muH * (ey * bz - ez * by) + mu2 * bx * eb);
187 vy = f * (ey + muH * (ez * bx - ex * bz) + mu2 * by * eb);
188 vz = f * (ez + muH * (ex * by - ey * bx) + mu2 * bz * eb);
194 const double ez,
const double bx,
195 const double by,
const double bz,
199 if (!UpdateTransportParameters()) {
200 std::cerr <<
m_className <<
"::ElectronTownsend:\n"
201 <<
" Error calculating the transport parameters.\n";
212 const double emag = sqrt(ex * ex + ey * ey + ez * ez);
214 switch (m_impactIonisationModel) {
215 case ImpactIonisation::VanOverstraeten:
216 return ElectronImpactIonisationVanOverstraetenDeMan(emag, alpha);
217 case ImpactIonisation::Grant:
218 return ElectronImpactIonisationGrant(emag, alpha);
219 case ImpactIonisation::Massey:
220 return ElectronImpactIonisationMassey(emag, alpha);
222 std::cerr <<
m_className <<
"::ElectronTownsend: Unknown model. Bug!\n";
229 const double ez,
const double bx,
230 const double by,
const double bz,
234 if (!UpdateTransportParameters()) {
235 std::cerr <<
m_className <<
"::ElectronAttachment:\n"
236 <<
" Error calculating the transport parameters.\n";
247 switch (m_trappingModel) {
249 eta = m_eTrapCs * m_eTrapDensity;
254 eta = m_eTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
255 if (eta > 0.) eta = -1. / eta;
258 std::cerr <<
m_className <<
"::ElectronAttachment: Unknown model. Bug!\n";
266 const double ez,
const double bx,
267 const double by,
const double bz,
double& vx,
268 double& vy,
double& vz) {
271 if (!UpdateTransportParameters()) {
273 <<
" Error calculating the transport parameters.\n";
284 const double emag = sqrt(ex * ex + ey * ey + ez * ez);
288 switch (m_highFieldMobilityModel) {
289 case HighFieldMobility::Minimos:
290 HoleMobilityMinimos(emag, mu);
292 case HighFieldMobility::Canali:
293 HoleMobilityCanali(emag, mu);
295 case HighFieldMobility::Reggiani:
296 HoleMobilityReggiani(emag, mu);
302 const double b2 = bx * bx + by * by + bz * bz;
309 const double muH = m_hHallFactor * mu;
310 const double mu2 = muH * muH;
311 const double f = mu / (1. + mu2 * b2);
312 const double eb = bx * ex + by * ey + bz * ez;
314 vx = f * (ex + muH * (ey * bz - ez * by) + mu2 * bx * eb);
315 vy = f * (ey + muH * (ez * bx - ex * bz) + mu2 * by * eb);
316 vz = f * (ez + muH * (ex * by - ey * bx) + mu2 * bz * eb);
322 const double ez,
const double bx,
323 const double by,
const double bz,
327 if (!UpdateTransportParameters()) {
329 <<
" Error calculating the transport parameters.\n";
340 const double emag = sqrt(ex * ex + ey * ey + ez * ez);
342 switch (m_impactIonisationModel) {
343 case ImpactIonisation::VanOverstraeten:
344 return HoleImpactIonisationVanOverstraetenDeMan(emag, alpha);
345 case ImpactIonisation::Grant:
346 return HoleImpactIonisationGrant(emag, alpha);
347 case ImpactIonisation::Massey:
348 return HoleImpactIonisationMassey(emag, alpha);
350 std::cerr <<
m_className <<
"::HoleTownsend: Unknown model. Bug!\n";
357 const double ez,
const double bx,
358 const double by,
const double bz,
362 if (!UpdateTransportParameters()) {
364 <<
" Error calculating the transport parameters.\n";
375 switch (m_trappingModel) {
377 eta = m_hTrapCs * m_hTrapDensity;
382 eta = m_hTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
383 if (eta > 0.) eta = -1. / eta;
386 std::cerr <<
m_className <<
"::HoleAttachment: Unknown model. Bug!\n";
394 if (mue <= 0. || muh <= 0.) {
395 std::cerr <<
m_className <<
"::SetLowFieldMobility:\n"
396 <<
" Mobility must be greater than zero.\n";
402 m_hasUserMobility =
true;
407 m_latticeMobilityModel = LatticeMobility::Minimos;
408 m_hasUserMobility =
false;
413 m_latticeMobilityModel = LatticeMobility::Sentaurus;
414 m_hasUserMobility =
false;
419 m_latticeMobilityModel = LatticeMobility::Reggiani;
420 m_hasUserMobility =
false;
425 m_dopingMobilityModel = DopingMobility::Minimos;
426 m_hasUserMobility =
false;
431 m_dopingMobilityModel = DopingMobility::Masetti;
432 m_hasUserMobility =
false;
437 const double vsath) {
438 if (vsate <= 0. || vsath <= 0.) {
439 std::cout <<
m_className <<
"::SetSaturationVelocity:\n"
440 <<
" Restoring default values.\n";
441 m_hasUserSaturationVelocity =
false;
445 m_hasUserSaturationVelocity =
true;
452 m_saturationVelocityModel = SaturationVelocity::Minimos;
453 m_hasUserSaturationVelocity =
false;
458 m_saturationVelocityModel = SaturationVelocity::Canali;
459 m_hasUserSaturationVelocity =
false;
464 m_saturationVelocityModel = SaturationVelocity::Reggiani;
465 m_hasUserSaturationVelocity =
false;
470 m_highFieldMobilityModel = HighFieldMobility::Minimos;
475 m_highFieldMobilityModel = HighFieldMobility::Canali;
480 m_highFieldMobilityModel = HighFieldMobility::Reggiani;
485 m_highFieldMobilityModel = HighFieldMobility::Constant;
489 m_impactIonisationModel = ImpactIonisation::VanOverstraeten;
494 m_impactIonisationModel = ImpactIonisation::Grant;
499 m_impactIonisationModel = ImpactIonisation::Massey;
504 if (e <= m_eMinG + Small) {
505 std::cerr <<
m_className <<
"::SetMaxElectronEnergy:\n"
506 <<
" Requested upper electron energy limit (" << e
507 <<
" eV) is too small.\n";
513 m_eStepG = m_eFinalG / nEnergyStepsG;
521 const double pz,
double& vx,
double& vy,
522 double& vz,
const int band) {
524 double mx = ElectronMass, my = ElectronMass, mz = ElectronMass;
527 if (band >= 0 && band < m_nValleysX) {
553 std::cerr <<
m_className <<
"::GetElectronEnergy:\n"
554 <<
" Unexpected band index " << band <<
"!\n";
559 const double mc = 3. / (1. / m_mLongX + 2. / m_mTransX);
564 }
else if (band < m_nValleysX + m_nValleysL) {
568 const double mc = 3. / (1. / m_mLongL + 2. / m_mTransL);
572 }
else if (band == m_nValleysX + m_nValleysL) {
576 if (m_nonParabolic) {
579 if (band < m_nValleysX) {
582 }
else if (band < m_nValleysX + m_nValleysL) {
587 const double p2 = 0.5 * (px * px / mx + py * py / my + pz * pz / mz);
589 const double e = 0.5 * (sqrt(1. + 4 * alpha * p2) - 1.) / alpha;
590 const double a = SpeedOfLight / (1. + 2 * alpha * e);
598 const double e = 0.5 * (px * px / mx + py * py / my + pz * pz / mz);
599 vx = SpeedOfLight * px / mx;
600 vy = SpeedOfLight * py / my;
601 vz = SpeedOfLight * pz / mz;
606 double& pz,
int& band) {
607 int nBands = m_nValleysX;
608 if (e > m_eMinL) nBands += m_nValleysL;
609 if (e > m_eMinG) ++nBands;
612 if (band < 0 || band > m_nValleysX + m_nValleysL ||
613 (e < m_eMinL || band >= m_nValleysX) ||
614 (e < m_eMinG || band == m_nValleysX + m_nValleysL)) {
617 if (band >= m_nValleysX) band = m_nValleysX - 1;
623 const double dosSum = m_nValleysX * dosX + m_nValleysL * dosL + dosG;
624 if (dosSum < Small) {
625 band = m_nValleysX + m_nValleysL;
630 if (band >= m_nValleysX) band = m_nValleysX - 1;
631 }
else if (r < dosX + dosL) {
632 band = m_nValleysX + int(m_nValleysL *
RndmUniform());
633 if (band >= m_nValleysX + m_nValleysL) band = m_nValleysL - 1;
635 band = m_nValleysX + m_nValleysL;
640 std::cout <<
m_className <<
"::GetElectronMomentum:\n"
641 <<
" Randomised band index: " << band <<
"\n";
644 if (band < m_nValleysX) {
646 double pstar = sqrt(2. * ElectronMass * e);
647 if (m_nonParabolic) {
648 const double alpha = m_alphaX;
649 pstar *= sqrt(1. + alpha * e);
653 const double stheta = sqrt(1. - ctheta * ctheta);
657 const double pl = pstar * sqrt(m_mLongX);
658 const double pt = pstar * sqrt(m_mTransX);
664 py = pt * cos(phi) * stheta;
665 pz = pt * sin(phi) * stheta;
670 px = pt * sin(phi) * stheta;
672 pz = pt * cos(phi) * stheta;
677 px = pt * cos(phi) * stheta;
678 py = pt * sin(phi) * stheta;
683 std::cerr <<
m_className <<
"::GetElectronMomentum:\n"
684 <<
" Unexpected band index (" << band <<
").\n";
685 px = pstar * stheta * cos(phi);
686 py = pstar * stheta * sin(phi);
691 pstar *= sqrt(3. / (1. / m_mLongX + 2. / m_mTransX));
692 px = pstar * cos(phi) * stheta;
693 py = pstar * sin(phi) * stheta;
696 }
else if (band < m_nValleysX + m_nValleysL) {
698 double pstar = sqrt(2. * ElectronMass * (e - m_eMinL));
699 if (m_nonParabolic) {
700 const double alpha = m_alphaL;
701 pstar *= sqrt(1. + alpha * (e - m_eMinL));
703 pstar *= sqrt(3. / (1. / m_mLongL + 2. / m_mTransL));
705 }
else if (band == m_nValleysX + m_nValleysL) {
707 const double pstar = sqrt(2. * ElectronMass * e);
714 if (!UpdateTransportParameters()) {
715 std::cerr <<
m_className <<
"::GetElectronNullCollisionRate:\n"
716 <<
" Error calculating the collision rates table.\n";
722 if (band >= 0 && band < m_nValleysX) {
723 return m_cfNullElectronsX;
724 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
725 return m_cfNullElectronsL;
726 }
else if (band == m_nValleysX + m_nValleysL) {
727 return m_cfNullElectronsG;
729 std::cerr <<
m_className <<
"::GetElectronNullCollisionRate:\n"
730 <<
" Band index (" << band <<
") out of range.\n";
736 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
737 <<
" Electron energy must be positive.\n";
742 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
743 <<
" Collision rate at " << e <<
" eV (band " << band
744 <<
") is not included in the current table.\n"
745 <<
" Increasing energy range to " << 1.05 * e <<
" eV.\n";
750 if (!UpdateTransportParameters()) {
751 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
752 <<
" Error calculating the collision rates table.\n";
758 if (band >= 0 && band < m_nValleysX) {
759 int iE = int(e / m_eStepXL);
760 if (iE >= nEnergyStepsXL)
761 iE = nEnergyStepsXL - 1;
764 return m_cfTotElectronsX[iE];
765 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
766 int iE = int(e / m_eStepXL);
767 if (iE >= nEnergyStepsXL)
768 iE = nEnergyStepsXL - 1;
769 else if (iE < m_ieMinL)
771 return m_cfTotElectronsL[iE];
772 }
else if (band == m_nValleysX + m_nValleysL) {
773 int iE = int(e / m_eStepG);
774 if (iE >= nEnergyStepsG)
775 iE = nEnergyStepsG - 1;
776 else if (iE < m_ieMinG)
778 return m_cfTotElectronsG[iE];
781 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
782 <<
" Band index (" << band <<
") out of range.\n";
787 const double e,
int& type,
int& level,
double& e1,
double& px,
double& py,
788 double& pz, std::vector<std::pair<int, double> >& secondaries,
int& ndxc,
791 std::cerr <<
m_className <<
"::GetElectronCollision:\n"
792 <<
" Requested electron energy (" << e <<
" eV) exceeds the "
793 <<
"current energy range (" << m_eFinalG <<
" eV).\n"
794 <<
" Increasing energy range to " << 1.05 * e <<
" eV.\n";
796 }
else if (e <= 0.) {
797 std::cerr <<
m_className <<
"::GetElectronCollision:\n"
798 <<
" Electron energy must be greater than zero.\n";
803 if (!UpdateTransportParameters()) {
804 std::cerr <<
m_className <<
"::GetElectronCollision:\n"
805 <<
" Error calculating the collision rates table.\n";
814 if (band >= 0 && band < m_nValleysX) {
817 int iE = int(e / m_eStepXL);
818 if (iE >= nEnergyStepsXL) iE = nEnergyStepsXL - 1;
822 if (r <= m_cfElectronsX[iE][0]) {
824 }
else if (r >= m_cfElectronsX[iE][m_nLevelsX - 1]) {
825 level = m_nLevelsX - 1;
827 const auto begin = m_cfElectronsX[iE].cbegin();
828 level = std::lower_bound(begin, begin + m_nLevelsX, r) - begin;
832 type = m_scatTypeElectronsX[level];
834 ++m_nCollElectronDetailed[level];
835 ++m_nCollElectronBand[band];
836 if (type == ElectronCollisionTypeAcousticPhonon) {
837 ++m_nCollElectronAcoustic;
838 }
else if (type == ElectronCollisionTypeIntervalleyG) {
840 ++m_nCollElectronIntervalley;
864 }
else if (type == ElectronCollisionTypeIntervalleyF) {
866 ++m_nCollElectronIntervalley;
876 if (band > 1) band += 2;
883 }
else if (type == ElectronCollisionTypeInterbandXL) {
885 ++m_nCollElectronIntervalley;
887 band = m_nValleysX + int(
RndmUniform() * m_nValleysL);
888 if (band >= m_nValleysX + m_nValleysL)
889 band = m_nValleysX + m_nValleysL - 1;
890 }
else if (type == ElectronCollisionTypeInterbandXG) {
891 ++m_nCollElectronIntervalley;
892 band = m_nValleysX + m_nValleysL;
893 }
else if (type == ElectronCollisionTypeImpurity) {
894 ++m_nCollElectronImpurity;
895 }
else if (type == ElectronCollisionTypeIonisation) {
896 ++m_nCollElectronIonisation;
898 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
899 std::cerr <<
" Unexpected collision type (" << type <<
").\n";
903 loss = m_energyLossElectronsX[level];
905 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
908 int iE = int(e / m_eStepXL);
909 if (iE >= nEnergyStepsXL) iE = nEnergyStepsXL - 1;
910 if (iE < m_ieMinL) iE = m_ieMinL;
913 if (r <= m_cfElectronsL[iE][0]) {
915 }
else if (r >= m_cfElectronsL[iE][m_nLevelsL - 1]) {
916 level = m_nLevelsL - 1;
918 const auto begin = m_cfElectronsL[iE].cbegin();
919 level = std::lower_bound(begin, begin + m_nLevelsL, r) - begin;
923 type = m_scatTypeElectronsL[level];
925 ++m_nCollElectronDetailed[m_nLevelsX + level];
926 ++m_nCollElectronBand[band];
927 if (type == ElectronCollisionTypeAcousticPhonon) {
928 ++m_nCollElectronAcoustic;
929 }
else if (type == ElectronCollisionTypeOpticalPhonon) {
930 ++m_nCollElectronOptical;
931 }
else if (type == ElectronCollisionTypeIntervalleyG ||
932 type == ElectronCollisionTypeIntervalleyF) {
934 ++m_nCollElectronIntervalley;
936 band = m_nValleysX + int(
RndmUniform() * m_nValleysL);
937 if (band >= m_nValleysX + m_nValleysL) band = m_nValleysX + m_nValleysL;
938 }
else if (type == ElectronCollisionTypeInterbandXL) {
940 ++m_nCollElectronIntervalley;
943 if (band >= m_nValleysX) band = m_nValleysX - 1;
944 }
else if (type == ElectronCollisionTypeInterbandLG) {
946 ++m_nCollElectronIntervalley;
947 band = m_nValleysX + m_nValleysL;
948 }
else if (type == ElectronCollisionTypeImpurity) {
949 ++m_nCollElectronImpurity;
950 }
else if (type == ElectronCollisionTypeIonisation) {
951 ++m_nCollElectronIonisation;
953 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
954 std::cerr <<
" Unexpected collision type (" << type <<
").\n";
958 loss = m_energyLossElectronsL[level];
959 }
else if (band == m_nValleysX + m_nValleysL) {
962 int iE = int(e / m_eStepG);
963 if (iE >= nEnergyStepsG) iE = nEnergyStepsG - 1;
964 if (iE < m_ieMinG) iE = m_ieMinG;
967 if (r <= m_cfElectronsG[iE][0]) {
969 }
else if (r >= m_cfElectronsG[iE][m_nLevelsG - 1]) {
970 level = m_nLevelsG - 1;
972 const auto begin = m_cfElectronsG[iE].cbegin();
973 level = std::lower_bound(begin, begin + m_nLevelsG, r) - begin;
977 type = m_scatTypeElectronsG[level];
979 ++m_nCollElectronDetailed[m_nLevelsX + m_nLevelsL + level];
980 ++m_nCollElectronBand[band];
981 if (type == ElectronCollisionTypeAcousticPhonon) {
982 ++m_nCollElectronAcoustic;
983 }
else if (type == ElectronCollisionTypeOpticalPhonon) {
984 ++m_nCollElectronOptical;
985 }
else if (type == ElectronCollisionTypeIntervalleyG ||
986 type == ElectronCollisionTypeIntervalleyF) {
988 ++m_nCollElectronIntervalley;
989 }
else if (type == ElectronCollisionTypeInterbandXG) {
991 ++m_nCollElectronIntervalley;
994 if (band >= m_nValleysX) band = m_nValleysX - 1;
995 }
else if (type == ElectronCollisionTypeInterbandLG) {
997 ++m_nCollElectronIntervalley;
999 band = m_nValleysX + int(
RndmUniform() * m_nValleysL);
1000 if (band >= m_nValleysX + m_nValleysL)
1001 band = m_nValleysX + m_nValleysL - 1;
1002 }
else if (type == ElectronCollisionTypeIonisation) {
1003 ++m_nCollElectronIonisation;
1005 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
1006 std::cerr <<
" Unexpected collision type (" << type <<
").\n";
1010 loss = m_energyLossElectronsG[level];
1012 std::cerr <<
m_className <<
"::GetElectronCollision:\n";
1013 std::cerr <<
" Band index (" << band <<
") out of range.\n";
1020 if (type == ElectronCollisionTypeIonisation) {
1021 double ee = 0., eh = 0.;
1023 loss = ee + eh + m_bandGap;
1025 secondaries.emplace_back(std::make_pair(IonProdTypeElectron, ee));
1027 secondaries.emplace_back(std::make_pair(IonProdTypeHole, eh));
1030 if (e < loss) loss = e - 0.00001;
1033 if (e1 < Small) e1 = Small;
1036 if (band >= 0 && band < m_nValleysX) {
1038 double pstar = sqrt(2. * ElectronMass * e1);
1039 if (m_nonParabolic) {
1040 const double alpha = m_alphaX;
1041 pstar *= sqrt(1. + alpha * e1);
1045 const double stheta = sqrt(1. - ctheta * ctheta);
1048 if (m_anisotropic) {
1049 const double pl = pstar * sqrt(m_mLongX);
1050 const double pt = pstar * sqrt(m_mTransX);
1056 py = pt * cos(phi) * stheta;
1057 pz = pt * sin(phi) * stheta;
1062 px = pt * sin(phi) * stheta;
1064 pz = pt * cos(phi) * stheta;
1069 px = pt * cos(phi) * stheta;
1070 py = pt * sin(phi) * stheta;
1077 pstar *= sqrt(3. / (1. / m_mLongX + 2. / m_mTransX));
1078 px = pstar * cos(phi) * stheta;
1079 py = pstar * sin(phi) * stheta;
1080 pz = pstar * ctheta;
1084 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
1086 double pstar = sqrt(2. * ElectronMass * (e1 - m_eMinL));
1087 if (m_nonParabolic) {
1088 const double alpha = m_alphaL;
1089 pstar *= sqrt(1. + alpha * (e1 - m_eMinL));
1091 pstar *= sqrt(3. / (1. / m_mLongL + 2. / m_mTransL));
1095 const double pstar = sqrt(2. * ElectronMass * e1);
1101 m_nCollElectronAcoustic = m_nCollElectronOptical = 0;
1102 m_nCollElectronIntervalley = 0;
1103 m_nCollElectronImpurity = 0;
1104 m_nCollElectronIonisation = 0;
1105 const auto nLevels = m_nLevelsX + m_nLevelsL + m_nLevelsG;
1106 m_nCollElectronDetailed.assign(nLevels, 0);
1107 const auto nBands = m_nValleysX + m_nValleysL + 1;
1108 m_nCollElectronBand.assign(nBands, 0);
1112 return m_nCollElectronAcoustic + m_nCollElectronOptical +
1113 m_nCollElectronIntervalley + m_nCollElectronImpurity +
1114 m_nCollElectronIonisation;
1118 return m_nLevelsX + m_nLevelsL + m_nLevelsG;
1122 const unsigned int level)
const {
1123 const unsigned int nLevels = m_nLevelsX + m_nLevelsL + m_nLevelsG;
1124 if (level >= nLevels) {
1125 std::cerr <<
m_className <<
"::GetNumberOfElectronCollisions:\n"
1126 <<
" Scattering rate term (" << level <<
") does not exist.\n";
1129 return m_nCollElectronDetailed[level];
1133 return m_nValleysX + m_nValleysL + 1;
1137 const int nBands = m_nValleysX + m_nValleysL + 1;
1138 if (band < 0 || band >= nBands) {
1139 std::cerr <<
m_className <<
"::GetElectronBandPopulation:\n";
1140 std::cerr <<
" Band index (" << band <<
") out of range.\n";
1143 return m_nCollElectronBand[band];
1147 const unsigned int i) {
1149 std::cerr <<
m_className <<
"::GetOpticalDataRange: Index out of range.\n";
1153 if (m_opticalDataEnergies.empty()) {
1154 if (!LoadOpticalData(m_opticalDataFile)) {
1155 std::cerr <<
m_className <<
"::GetOpticalDataRange:\n"
1156 <<
" Optical data table could not be loaded.\n";
1161 emin = m_opticalDataEnergies.front();
1162 emax = m_opticalDataEnergies.back();
1164 std::cout <<
m_className <<
"::GetOpticalDataRange:\n"
1165 <<
" " << emin <<
" < E [eV] < " << emax <<
"\n";
1171 double& eps2,
const unsigned int i) {
1173 std::cerr <<
m_className +
"::GetDielectricFunction: Index out of range.\n";
1178 if (m_opticalDataEnergies.empty()) {
1179 if (!LoadOpticalData(m_opticalDataFile)) {
1180 std::cerr <<
m_className <<
"::GetDielectricFunction:\n";
1181 std::cerr <<
" Optical data table could not be loaded.\n";
1187 const double emin = m_opticalDataEnergies.front();
1188 const double emax = m_opticalDataEnergies.back();
1189 if (e < emin || e > emax) {
1190 std::cerr <<
m_className <<
"::GetDielectricFunction:\n"
1191 <<
" Requested energy (" << e <<
" eV) "
1192 <<
" is outside the range of the optical data table.\n"
1193 <<
" " << emin <<
" < E [eV] < " << emax <<
"\n";
1199 const auto begin = m_opticalDataEnergies.cbegin();
1200 const auto it1 = std::upper_bound(begin, m_opticalDataEnergies.cend(), e);
1202 eps1 = m_opticalDataEpsilon.front().first;
1203 eps2 = m_opticalDataEpsilon.front().second;
1206 const auto it0 = std::prev(it1);
1209 const double x0 = *it0;
1210 const double x1 = *it1;
1211 const double lnx0 = log(*it0);
1212 const double lnx1 = log(*it1);
1213 const double lnx = log(e);
1214 const double y0 = m_opticalDataEpsilon[it0 - begin].first;
1215 const double y1 = m_opticalDataEpsilon[it1 - begin].first;
1216 if (y0 <= 0. || y1 <= 0.) {
1218 eps1 = y0 + (e - x0) * (y1 - y0) / (x1 - x0);
1221 const double lny0 = log(y0);
1222 const double lny1 = log(y1);
1223 eps1 = lny0 + (lnx - lnx0) * (lny1 - lny0) / (lnx1 - lnx0);
1229 const double lnz0 = log(m_opticalDataEpsilon[it0 - begin].second);
1230 const double lnz1 = log(m_opticalDataEpsilon[it1 - begin].second);
1231 eps2 = lnz0 + (lnx - lnx0) * (lnz1 - lnz0) / (lnx1 - lnx0);
1239 std::cerr <<
m_className <<
"::Initialise: Nothing changed.\n";
1243 if (!UpdateTransportParameters()) {
1244 std::cerr <<
m_className <<
"::Initialise:\n Error preparing "
1245 <<
"transport parameters/calculating collision rates.\n";
1251bool MediumSilicon::UpdateTransportParameters() {
1252 std::lock_guard<std::mutex> guard(m_mutex);
1255 switch (m_impactIonisationModel) {
1256 case ImpactIonisation::VanOverstraeten:
1257 UpdateImpactIonisationVanOverstraetenDeMan();
1259 case ImpactIonisation::Grant:
1260 UpdateImpactIonisationGrant();
1262 case ImpactIonisation::Massey:
1265 std::cerr <<
m_className <<
"::UpdateTransportParameters:\n "
1266 <<
"Unknown impact ionisation model. Program bug!\n";
1270 if (!m_hasUserMobility) {
1272 switch (m_latticeMobilityModel) {
1273 case LatticeMobility::Minimos:
1274 UpdateLatticeMobilityMinimos();
1276 case LatticeMobility::Sentaurus:
1277 UpdateLatticeMobilitySentaurus();
1279 case LatticeMobility::Reggiani:
1280 UpdateLatticeMobilityReggiani();
1283 std::cerr <<
m_className <<
"::UpdateTransportParameters:\n "
1284 <<
"Unknown lattice mobility model. Program bug!\n";
1289 switch (m_dopingMobilityModel) {
1290 case DopingMobility::Minimos:
1291 UpdateDopingMobilityMinimos();
1293 case DopingMobility::Masetti:
1294 UpdateDopingMobilityMasetti();
1297 std::cerr <<
m_className <<
"::UpdateTransportParameters:\n "
1298 <<
"Unknown doping mobility model. Program bug!\n";
1304 if (!m_hasUserSaturationVelocity) {
1305 switch (m_saturationVelocityModel) {
1306 case SaturationVelocity::Minimos:
1307 UpdateSaturationVelocityMinimos();
1309 case SaturationVelocity::Canali:
1310 UpdateSaturationVelocityCanali();
1312 case SaturationVelocity::Reggiani:
1313 UpdateSaturationVelocityReggiani();
1319 if (m_highFieldMobilityModel == HighFieldMobility::Canali) {
1320 UpdateHighFieldMobilityCanali();
1324 std::cout <<
m_className <<
"::UpdateTransportParameters:\n"
1325 <<
" Low-field mobility [cm2 V-1 ns-1]\n"
1326 <<
" Electrons: " << m_eMobility <<
"\n"
1327 <<
" Holes: " << m_hMobility <<
"\n";
1328 if (m_highFieldMobilityModel == HighFieldMobility::Constant) {
1329 std::cout <<
" Mobility is not field-dependent.\n";
1331 std::cout <<
" Saturation velocity [cm / ns]\n"
1332 <<
" Electrons: " << m_eSatVel <<
"\n"
1333 <<
" Holes: " << m_hSatVel <<
"\n";
1337 if (!ElectronScatteringRates())
return false;
1338 if (!HoleScatteringRates())
return false;
1346void MediumSilicon::UpdateLatticeMobilityMinimos() {
1353 constexpr double eMu0 = 1.43e-6;
1354 constexpr double hMu0 = 0.46e-6;
1358 m_eLatticeMobility = eMu0 *
pow(t, -2.);
1359 m_hLatticeMobility = hMu0 *
pow(t, -2.18);
1362void MediumSilicon::UpdateLatticeMobilitySentaurus() {
1369 constexpr double eMu0 = 1.417e-6;
1370 constexpr double hMu0 = 0.4705e-6;
1374 m_eLatticeMobility = eMu0 *
pow(t, -2.5);
1375 m_hLatticeMobility = hMu0 *
pow(t, -2.2);
1378void MediumSilicon::UpdateLatticeMobilityReggiani() {
1384 constexpr double eMu0 = 1.320e-6;
1385 constexpr double hMu0 = 0.460e-6;
1389 m_eLatticeMobility = eMu0 *
pow(t, -2.);
1390 m_hLatticeMobility = hMu0 *
pow(t, -2.2);
1393void MediumSilicon::UpdateDopingMobilityMinimos() {
1401 double eMuMin = 0.080e-6;
1402 double hMuMin = 0.045e-6;
1413 const double eRefC = 1.12e17 * c1;
1414 const double hRefC = 2.23e17 * c1;
1417 m_eMobility = eMuMin +
1418 (m_eLatticeMobility - eMuMin) /
1419 (1. +
pow(m_dopingConcentration / eRefC, alpha));
1420 m_hMobility = hMuMin +
1421 (m_hLatticeMobility - hMuMin) /
1422 (1. +
pow(m_dopingConcentration / hRefC, alpha));
1425void MediumSilicon::UpdateDopingMobilityMasetti() {
1432 if (m_dopingConcentration < 1.e13) {
1433 m_eMobility = m_eLatticeMobility;
1434 m_hMobility = m_hLatticeMobility;
1439 constexpr double eMuMin1 = 0.0522e-6;
1440 constexpr double eMuMin2 = 0.0522e-6;
1441 constexpr double eMu1 = 0.0434e-6;
1442 constexpr double hMuMin1 = 0.0449e-6;
1443 constexpr double hMuMin2 = 0.;
1444 constexpr double hMu1 = 0.029e-6;
1445 constexpr double eCr = 9.68e16;
1446 constexpr double eCs = 3.42e20;
1447 constexpr double hCr = 2.23e17;
1448 constexpr double hCs = 6.10e20;
1449 constexpr double hPc = 9.23e16;
1450 constexpr double eAlpha = 0.68;
1451 constexpr double eBeta = 2.;
1452 constexpr double hAlpha = 0.719;
1453 constexpr double hBeta = 2.;
1455 m_eMobility = eMuMin1 +
1456 (m_eLatticeMobility - eMuMin2) /
1457 (1. +
pow(m_dopingConcentration / eCr, eAlpha)) -
1458 eMu1 / (1. +
pow(eCs / m_dopingConcentration, eBeta));
1460 m_hMobility = hMuMin1 *
exp(-hPc / m_dopingConcentration) +
1461 (m_hLatticeMobility - hMuMin2) /
1462 (1. +
pow(m_dopingConcentration / hCr, hAlpha)) -
1463 hMu1 / (1. +
pow(hCs / m_dopingConcentration, hBeta));
1466void MediumSilicon::UpdateSaturationVelocityMinimos() {
1473 m_eSatVel = 1.e-2 / (1. + 0.74 * (
m_temperature / 300. - 1.));
1474 m_hSatVel = 0.704e-2 / (1. + 0.37 * (
m_temperature / 300. - 1.));
1477void MediumSilicon::UpdateSaturationVelocityCanali() {
1487void MediumSilicon::UpdateSaturationVelocityReggiani() {
1496void MediumSilicon::UpdateHighFieldMobilityCanali() {
1505 m_eBetaCanaliInv = 1. / m_eBetaCanali;
1506 m_hBetaCanaliInv = 1. / m_hBetaCanali;
1509void MediumSilicon::UpdateImpactIonisationVanOverstraetenDeMan() {
1520 constexpr double hbarOmega = 0.063;
1522 const double gamma =
1523 tanh(hbarOmega / (2. * BoltzmannConstant * 300.)) /
1529 m_eImpactA0 = gamma * 7.03e5;
1530 m_eImpactB0 = gamma * 1.231e6;
1531 m_eImpactA1 = gamma * 7.03e5;
1532 m_eImpactB1 = gamma * 1.231e6;
1534 m_hImpactA0 = gamma * 1.582e6;
1535 m_hImpactB0 = gamma * 2.036e6;
1536 m_hImpactA1 = gamma * 6.71e5;
1537 m_hImpactB1 = gamma * 1.693e6;
1540void MediumSilicon::UpdateImpactIonisationGrant() {
1548 constexpr double hbarOmega = 0.063;
1550 const double gamma =
1551 tanh(hbarOmega / (2. * BoltzmannConstant * 300.)) /
1554 m_eImpactA0 = 2.60e6 * gamma;
1555 m_eImpactB0 = 1.43e6 * gamma;
1556 m_eImpactA1 = 6.20e5 * gamma;
1557 m_eImpactB1 = 1.08e6 * gamma;
1558 m_eImpactA2 = 5.05e5 * gamma;
1559 m_eImpactB2 = 9.90e5 * gamma;
1561 m_hImpactA0 = 2.00e6 * gamma;
1562 m_hImpactB0 = 1.97e6 * gamma;
1563 m_hImpactA1 = 5.60e5 * gamma;
1564 m_hImpactB1 = 1.32e6 * gamma;
1567bool MediumSilicon::ElectronMobilityMinimos(
const double e,
double& mu)
const {
1574 const double r = 2 * m_eMobility * e / m_eSatVel;
1575 mu = 2. * m_eMobility / (1. +
sqrt(1. + r * r));
1580bool MediumSilicon::ElectronMobilityCanali(
const double e,
double& mu)
const {
1587 const double r = m_eMobility * e / m_eSatVel;
1588 mu = m_eMobility /
pow(1. +
pow(r, m_eBetaCanali), m_eBetaCanaliInv);
1593bool MediumSilicon::ElectronMobilityReggiani(
const double e,
double& mu)
const {
1601 const double r = m_eMobility * e / m_eSatVel;
1602 constexpr double k = 1. / 1.5;
1603 mu = m_eMobility /
pow(1. +
pow(r, 1.5), k);
1608bool MediumSilicon::ElectronImpactIonisationVanOverstraetenDeMan(
1609 const double e,
double& alpha)
const {
1619 }
else if (e < 4e5) {
1620 alpha = m_eImpactA0 *
exp(-m_eImpactB0 / e);
1622 alpha = m_eImpactA1 *
exp(-m_eImpactB1 / e);
1627bool MediumSilicon::ElectronImpactIonisationGrant(
const double e,
1628 double& alpha)
const {
1634 }
else if (e < 2.4e5) {
1635 alpha = m_eImpactA0 *
exp(-m_eImpactB0 / e);
1636 }
else if (e < 5.3e5) {
1637 alpha = m_eImpactA1 *
exp(-m_eImpactB1 / e);
1639 alpha = m_eImpactA2 *
exp(-m_eImpactB2 / e);
1644bool MediumSilicon::ElectronImpactIonisationMassey(
const double e,
1645 double& alpha)
const {
1650 constexpr double a = 4.43e5;
1651 constexpr double c = 9.66e5;
1652 constexpr double d = 4.99e2;
1662bool MediumSilicon::HoleMobilityMinimos(
const double e,
double& mu)
const {
1669 mu = m_hMobility / (1. + m_hMobility * e / m_eSatVel);
1674bool MediumSilicon::HoleMobilityCanali(
const double e,
double& mu)
const {
1681 const double r = m_hMobility * e / m_hSatVel;
1682 mu = m_hMobility /
pow(1. +
pow(r, m_hBetaCanali), m_hBetaCanaliInv);
1687bool MediumSilicon::HoleMobilityReggiani(
const double e,
double& mu)
const {
1695 const double r = m_hMobility * e / m_hSatVel;
1696 mu = m_hMobility /
sqrt(1. + r * r);
1701bool MediumSilicon::HoleImpactIonisationVanOverstraetenDeMan(
1702 const double e,
double& alpha)
const {
1710 }
else if (e < 4e5) {
1711 alpha = m_hImpactA0 *
exp(-m_hImpactB0 / e);
1713 alpha = m_hImpactA1 *
exp(-m_hImpactB1 / e);
1718bool MediumSilicon::HoleImpactIonisationGrant(
const double e,
1719 double& alpha)
const {
1725 }
else if (e < 5.3e5) {
1726 alpha = m_hImpactA0 *
exp(-m_hImpactB0 / e);
1728 alpha = m_hImpactA1 *
exp(-m_hImpactB1 / e);
1733bool MediumSilicon::HoleImpactIonisationMassey(
const double e,
1734 double& alpha)
const {
1739 constexpr double a = 1.13e6;
1740 constexpr double c = 1.71e6;
1741 constexpr double d = 1.09e3;
1751bool MediumSilicon::LoadOpticalData(
const std::string& filename) {
1753 m_opticalDataEnergies.clear();
1754 m_opticalDataEpsilon.clear();
1757 char* pPath = getenv(
"GARFIELD_HOME");
1759 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
1760 <<
" Environment variable GARFIELD_HOME is not set.\n";
1763 const std::string filepath = std::string(pPath) +
"/Data/" + filename;
1766 std::ifstream infile;
1767 infile.open(filepath.c_str(), std::ios::in);
1770 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
1771 <<
" Error opening file " << filename <<
".\n";
1775 double lastEnergy = -1.;
1776 double energy, eps1, eps2, loss;
1779 std::istringstream dataStream;
1781 while (!infile.eof()) {
1784 std::getline(infile, line);
1787 if (line.empty())
continue;
1789 if (line[0] ==
'#' || line[0] ==
'*' || (line[0] ==
'/' && line[1] ==
'/'))
1792 dataStream.str(line);
1793 dataStream >> energy >> eps1 >> eps2 >> loss;
1794 if (dataStream.eof())
break;
1796 if (infile.fail()) {
1797 std::cerr <<
m_className <<
"::LoadOpticalData:\n Error reading file "
1798 << filename <<
" (line " << i <<
").\n";
1807 if (energy <= lastEnergy) {
1808 std::cerr <<
m_className <<
"::LoadOpticalData:\n Table is not in "
1809 <<
"monotonically increasing order (line " << i <<
").\n"
1810 <<
" " << lastEnergy <<
" " << energy <<
" " << eps1
1811 <<
" " << eps2 <<
"\n";
1816 std::cerr <<
m_className <<
"::LoadOpticalData:\n Negative value "
1817 <<
"of the loss function (line " << i <<
").\n";
1821 if (energy <= 0.)
continue;
1823 m_opticalDataEnergies.emplace_back(energy);
1824 m_opticalDataEpsilon.emplace_back(std::make_pair(eps1, eps2));
1825 lastEnergy = energy;
1828 if (m_opticalDataEnergies.empty()) {
1829 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
1830 <<
" Import of data from file " << filepath <<
"failed.\n"
1831 <<
" No valid data found.\n";
1836 std::cout <<
m_className <<
"::LoadOpticalData:\n Read "
1837 << m_opticalDataEnergies.size() <<
" values from file "
1838 << filepath <<
"\n";
1843bool MediumSilicon::ElectronScatteringRates() {
1845 m_cfTotElectronsX.assign(nEnergyStepsXL, 0.);
1846 m_cfTotElectronsL.assign(nEnergyStepsXL, 0.);
1847 m_cfTotElectronsG.assign(nEnergyStepsG, 0.);
1848 m_cfElectronsX.assign(nEnergyStepsXL, std::vector<double>());
1849 m_cfElectronsL.assign(nEnergyStepsXL, std::vector<double>());
1850 m_cfElectronsG.assign(nEnergyStepsG, std::vector<double>());
1851 m_energyLossElectronsX.clear();
1852 m_energyLossElectronsL.clear();
1853 m_energyLossElectronsG.clear();
1854 m_scatTypeElectronsX.clear();
1855 m_scatTypeElectronsL.clear();
1856 m_scatTypeElectronsG.clear();
1857 m_cfNullElectronsX = 0.;
1858 m_cfNullElectronsL = 0.;
1859 m_cfNullElectronsG = 0.;
1865 ElectronAcousticScatteringRates();
1866 ElectronOpticalScatteringRates();
1867 ElectronImpurityScatteringRates();
1868 ElectronIntervalleyScatteringRatesXX();
1869 ElectronIntervalleyScatteringRatesXL();
1870 ElectronIntervalleyScatteringRatesLL();
1871 ElectronIntervalleyScatteringRatesXGLG();
1872 ElectronIonisationRatesXL();
1873 ElectronIonisationRatesG();
1876 std::cout <<
m_className <<
"::ElectronScatteringRates:\n"
1877 <<
" " << m_nLevelsX <<
" X-valley scattering terms\n"
1878 <<
" " << m_nLevelsL <<
" L-valley scattering terms\n"
1879 <<
" " << m_nLevelsG <<
" higher band scattering terms\n";
1882 std::ofstream outfileX;
1883 std::ofstream outfileL;
1885 outfileX.open(
"ratesX.txt", std::ios::out);
1886 outfileL.open(
"ratesL.txt", std::ios::out);
1889 m_ieMinL = int(m_eMinL / m_eStepXL) + 1;
1890 for (
int i = 0; i < nEnergyStepsXL; ++i) {
1892 for (
int j = m_nLevelsX; j--;) m_cfTotElectronsX[i] += m_cfElectronsX[i][j];
1893 for (
int j = m_nLevelsL; j--;) m_cfTotElectronsL[i] += m_cfElectronsL[i][j];
1896 outfileX << i * m_eStepXL <<
" " << m_cfTotElectronsX[i] <<
" ";
1897 for (
int j = 0; j < m_nLevelsX; ++j) {
1898 outfileX << m_cfElectronsX[i][j] <<
" ";
1901 outfileL << i * m_eStepXL <<
" " << m_cfTotElectronsL[i] <<
" ";
1902 for (
int j = 0; j < m_nLevelsL; ++j) {
1903 outfileL << m_cfElectronsL[i][j] <<
" ";
1908 if (m_cfTotElectronsX[i] > m_cfNullElectronsX) {
1909 m_cfNullElectronsX = m_cfTotElectronsX[i];
1911 if (m_cfTotElectronsL[i] > m_cfNullElectronsL) {
1912 m_cfNullElectronsL = m_cfTotElectronsL[i];
1916 if (m_cfTotElectronsX[i] <= 0.) {
1917 std::cerr <<
m_className <<
"::ElectronScatteringRates:\n X-valley "
1918 <<
"scattering rate at " << i * m_eStepXL <<
" eV <= 0.\n";
1922 for (
int j = 0; j < m_nLevelsX; ++j) {
1923 m_cfElectronsX[i][j] /= m_cfTotElectronsX[i];
1924 if (j > 0) m_cfElectronsX[i][j] += m_cfElectronsX[i][j - 1];
1928 if (m_cfTotElectronsL[i] <= 0.) {
1929 if (i < m_ieMinL)
continue;
1930 std::cerr <<
m_className <<
"::ElectronScatteringRates:\n L-valley "
1931 <<
"scattering rate at " << i * m_eStepXL <<
" eV <= 0.\n";
1935 for (
int j = 0; j < m_nLevelsL; ++j) {
1936 m_cfElectronsL[i][j] /= m_cfTotElectronsL[i];
1937 if (j > 0) m_cfElectronsL[i][j] += m_cfElectronsL[i][j - 1];
1946 std::ofstream outfileG;
1948 outfileG.open(
"ratesG.txt", std::ios::out);
1950 m_ieMinG = int(m_eMinG / m_eStepG) + 1;
1951 for (
int i = 0; i < nEnergyStepsG; ++i) {
1953 for (
int j = m_nLevelsG; j--;) m_cfTotElectronsG[i] += m_cfElectronsG[i][j];
1956 outfileG << i * m_eStepG <<
" " << m_cfTotElectronsG[i] <<
" ";
1957 for (
int j = 0; j < m_nLevelsG; ++j) {
1958 outfileG << m_cfElectronsG[i][j] <<
" ";
1963 if (m_cfTotElectronsG[i] > m_cfNullElectronsG) {
1964 m_cfNullElectronsG = m_cfTotElectronsG[i];
1968 if (m_cfTotElectronsG[i] <= 0.) {
1969 if (i < m_ieMinG)
continue;
1970 std::cerr <<
m_className <<
"::ElectronScatteringRates:\n Higher "
1971 <<
"band scattering rate at " << i * m_eStepG <<
" eV <= 0.\n";
1974 for (
int j = 0; j < m_nLevelsG; ++j) {
1975 m_cfElectronsG[i][j] /= m_cfTotElectronsG[i];
1976 if (j > 0) m_cfElectronsG[i][j] += m_cfElectronsG[i][j - 1];
1987bool MediumSilicon::ElectronAcousticScatteringRates() {
1993 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
1999 constexpr double defpot2 = 9. * 9.;
2001 constexpr double u = 9.04e-4;
2003 const double cIntra = TwoPi * SpeedOfLight * SpeedOfLight * kbt * defpot2 /
2004 (Hbar * u * u * rho);
2008 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2012 m_cfElectronsX[i].push_back(cIntra * dosX);
2013 m_cfElectronsL[i].push_back(cIntra * dosL);
2018 for (
int i = 0; i < nEnergyStepsG; ++i) {
2021 m_cfElectronsG[i].push_back(cIntra * dosG);
2026 m_energyLossElectronsX.push_back(0.);
2027 m_energyLossElectronsL.push_back(0.);
2028 m_energyLossElectronsG.push_back(0.);
2029 m_scatTypeElectronsX.push_back(ElectronCollisionTypeAcousticPhonon);
2030 m_scatTypeElectronsL.push_back(ElectronCollisionTypeAcousticPhonon);
2031 m_scatTypeElectronsG.push_back(ElectronCollisionTypeAcousticPhonon);
2039bool MediumSilicon::ElectronOpticalScatteringRates() {
2050 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2055 constexpr double dtk = 2.2e8;
2057 constexpr double eph = 63.0e-3;
2059 const double nocc = 1. / (
exp(eph / kbt) - 1);
2061 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2062 double c = c0 * dtk * dtk / eph;
2088 for (
int i = 0; i < nEnergyStepsG; ++i) {
2093 m_cfElectronsG[i].push_back(c * nocc * dos);
2095 m_cfElectronsG[i].push_back(0.);
2098 if (en > m_eMinG + eph) {
2101 m_cfElectronsG[i].push_back(c * (nocc + 1) * dos);
2103 m_cfElectronsG[i].push_back(0.);
2110 m_energyLossElectronsG.push_back(-eph);
2113 m_energyLossElectronsG.push_back(eph);
2116 m_scatTypeElectronsG.push_back(ElectronCollisionTypeOpticalPhonon);
2117 m_scatTypeElectronsG.push_back(ElectronCollisionTypeOpticalPhonon);
2125bool MediumSilicon::ElectronIntervalleyScatteringRatesXX() {
2131 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2135 constexpr unsigned int nPhonons = 6;
2141 constexpr double dtk[nPhonons] = {0.5e8, 0.8e8, 1.1e9, 0.3e8, 2.0e8, 2.0e8};
2143 constexpr double eph[nPhonons] = {12.06e-3, 18.53e-3, 62.04e-3,
2144 18.86e-3, 47.39e-3, 59.03e-3};
2146 double nocc[nPhonons];
2148 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2151 for (
unsigned int j = 0; j < nPhonons; ++j) {
2152 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2153 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2154 if (j > 2) c[j] *= 4;
2158 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2159 for (
unsigned int j = 0; j < nPhonons; ++j) {
2162 m_cfElectronsX[i].push_back(c[j] * nocc[j] * dos);
2166 m_cfElectronsX[i].push_back(c[j] * (nocc[j] + 1) * dos);
2168 m_cfElectronsX[i].push_back(0.);
2174 for (
unsigned int j = 0; j < nPhonons; ++j) {
2176 m_energyLossElectronsX.push_back(-eph[j]);
2178 m_energyLossElectronsX.push_back(eph[j]);
2180 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyG);
2181 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyG);
2183 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyF);
2184 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyF);
2188 m_nLevelsX += 2 * nPhonons;
2193bool MediumSilicon::ElectronIntervalleyScatteringRatesXL() {
2200 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2204 constexpr unsigned int nPhonons = 4;
2207 constexpr double dtk[nPhonons] = {2.e8, 2.e8, 2.e8, 2.e8};
2209 constexpr double eph[nPhonons] = {58.e-3, 55.e-3, 41.e-3, 17.e-3};
2211 constexpr unsigned int zX = 6;
2212 constexpr unsigned int zL = 8;
2215 double nocc[nPhonons] = {0.};
2217 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2220 for (
unsigned int j = 0; j < nPhonons; ++j) {
2221 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2222 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2226 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2227 for (
unsigned int j = 0; j < nPhonons; ++j) {
2230 if (en + eph[j] > m_eMinL) {
2232 m_cfElectronsX[i].push_back(zL * c[j] * nocc[j] * dos);
2234 m_cfElectronsX[i].push_back(0.);
2237 if (en - eph[j] > m_eMinL) {
2239 m_cfElectronsX[i].push_back(zL * c[j] * (nocc[j] + 1) * dos);
2241 m_cfElectronsX[i].push_back(0.);
2247 m_cfElectronsL[i].push_back(zX * c[j] * nocc[j] * dos);
2250 m_cfElectronsL[i].push_back(zX * c[j] * (nocc[j] + 1) * dos);
2252 m_cfElectronsL[i].push_back(0.);
2253 m_cfElectronsL[i].push_back(0.);
2259 for (
unsigned int j = 0; j < nPhonons; ++j) {
2261 m_energyLossElectronsX.push_back(-eph[j]);
2262 m_energyLossElectronsL.push_back(-eph[j]);
2264 m_energyLossElectronsX.push_back(eph[j]);
2265 m_energyLossElectronsL.push_back(eph[j]);
2266 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXL);
2267 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXL);
2268 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandXL);
2269 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandXL);
2272 m_nLevelsX += 2 * nPhonons;
2273 m_nLevelsL += 2 * nPhonons;
2278bool MediumSilicon::ElectronIntervalleyScatteringRatesLL() {
2287 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2291 const int nPhonons = 1;
2293 const double dtk[nPhonons] = {2.63e8};
2295 const double eph[nPhonons] = {38.87e-3};
2297 double nocc[nPhonons];
2299 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2302 for (
int j = 0; j < nPhonons; ++j) {
2303 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2304 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2310 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2311 for (
int j = 0; j < nPhonons; ++j) {
2314 m_cfElectronsL[i].push_back(c[j] * nocc[j] * dos);
2316 if (en > m_eMinL + eph[j]) {
2318 m_cfElectronsL[i].push_back(c[j] * (nocc[j] + 1) * dos);
2320 m_cfElectronsL[i].push_back(0.);
2326 for (
int j = 0; j < nPhonons; ++j) {
2328 m_energyLossElectronsL.push_back(-eph[j]);
2330 m_energyLossElectronsL.push_back(eph[j]);
2331 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIntervalleyF);
2332 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIntervalleyF);
2335 m_nLevelsL += 2 * nPhonons;
2340bool MediumSilicon::ElectronIntervalleyScatteringRatesXGLG() {
2347 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2351 const int nPhonons = 1;
2355 const double dtk[nPhonons] = {2.43e8};
2357 const double eph[nPhonons] = {37.65e-3};
2364 double nocc[nPhonons] = {0.};
2366 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2369 for (
int j = 0; j < nPhonons; ++j) {
2370 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2371 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2377 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2378 for (
int j = 0; j < nPhonons; ++j) {
2380 if (en + eph[j] > m_eMinG) {
2382 m_nValleysX + m_nValleysL);
2383 m_cfElectronsX[i].push_back(zG * c[j] * nocc[j] * dos);
2384 m_cfElectronsL[i].push_back(zG * c[j] * nocc[j] * dos);
2386 m_cfElectronsX[i].push_back(0.);
2387 m_cfElectronsL[i].push_back(0.);
2390 if (en - eph[j] > m_eMinG) {
2392 m_nValleysX + m_nValleysL);
2393 m_cfElectronsX[i].push_back(zG * c[j] * (nocc[j] + 1) * dos);
2394 m_cfElectronsL[i].push_back(zG * c[j] * (nocc[j] + 1) * dos);
2396 m_cfElectronsX[i].push_back(0.);
2397 m_cfElectronsL[i].push_back(0.);
2405 double dosX = 0., dosL = 0.;
2406 for (
int i = 0; i < nEnergyStepsG; ++i) {
2407 for (
int j = 0; j < nPhonons; ++j) {
2411 m_cfElectronsG[i].push_back(zX * c[j] * nocc[j] * dosX);
2413 m_cfElectronsG[i].push_back(zL * c[j] * nocc[j] * dosL);
2415 m_cfElectronsG[i].push_back(0.);
2421 m_cfElectronsG[i].push_back(zX * c[j] * (nocc[j] + 1) * dosX);
2423 m_cfElectronsG[i].push_back(0.);
2425 if (en - eph[j] > m_eMinL) {
2426 m_cfElectronsG[i].push_back(zL * c[j] * (nocc[j] + 1) * dosL);
2428 m_cfElectronsG[i].push_back(0.);
2434 for (
int j = 0; j < nPhonons; ++j) {
2436 m_energyLossElectronsX.push_back(-eph[j]);
2437 m_energyLossElectronsL.push_back(-eph[j]);
2439 m_energyLossElectronsX.push_back(eph[j]);
2440 m_energyLossElectronsL.push_back(eph[j]);
2442 m_energyLossElectronsG.push_back(-eph[j]);
2443 m_energyLossElectronsG.push_back(-eph[j]);
2445 m_energyLossElectronsG.push_back(eph[j]);
2446 m_energyLossElectronsG.push_back(eph[j]);
2448 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXG);
2449 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXG);
2450 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandLG);
2451 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandLG);
2453 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandXG);
2454 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandLG);
2455 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandXG);
2456 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandLG);
2459 m_nLevelsX += 2 * nPhonons;
2460 m_nLevelsL += 2 * nPhonons;
2461 m_nLevelsG += 4 * nPhonons;
2466bool MediumSilicon::ElectronIonisationRatesXL() {
2473 constexpr double p[3] = {6.25e1, 3.e3, 6.8e5};
2475 constexpr double eth[3] = {1.2, 1.8, 3.45};
2478 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2481 fIon += p[0] * (en - eth[0]) * (en - eth[0]);
2484 fIon += p[1] * (en - eth[1]) * (en - eth[1]);
2487 fIon += p[2] * (en - eth[2]) * (en - eth[2]);
2489 m_cfElectronsX[i].push_back(fIon);
2490 m_cfElectronsL[i].push_back(fIon);
2494 m_energyLossElectronsX.push_back(eth[0]);
2495 m_energyLossElectronsL.push_back(eth[0]);
2496 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIonisation);
2497 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIonisation);
2504bool MediumSilicon::ElectronIonisationRatesG() {
2512 constexpr double p[3] = {6.25e1, 3.e3, 6.8e5};
2514 constexpr double eth[3] = {1.2, 1.8, 3.45};
2517 for (
int i = 0; i < nEnergyStepsG; ++i) {
2520 fIon += p[0] * (en - eth[0]) * (en - eth[0]);
2523 fIon += p[1] * (en - eth[1]) * (en - eth[1]);
2526 fIon += p[2] * (en - eth[2]) * (en - eth[2]);
2528 if (en >= m_eMinG) {
2529 m_cfElectronsG[i].push_back(fIon);
2531 m_cfElectronsG[i].push_back(0.);
2536 m_energyLossElectronsG.push_back(eth[0]);
2537 m_scatTypeElectronsG.push_back(ElectronCollisionTypeIonisation);
2543bool MediumSilicon::ElectronImpurityScatteringRates() {
2550 ElectronMass *
pow(m_mLongX * m_mTransX * m_mTransX, 1. / 3.);
2552 ElectronMass *
pow(m_mLongL * m_mTransL * m_mTransL, 1. / 3.);
2557 const double impurityConcentration = m_dopingConcentration;
2558 if (impurityConcentration < Small)
return true;
2561 const double ls =
sqrt(eps * kbt / (4 * Pi * FineStructureConstant * HbarC *
2562 impurityConcentration));
2563 const double ebX = 0.5 * HbarC * HbarC / (mdX * ls * ls);
2564 const double ebL = 0.5 * HbarC * HbarC / (mdL * ls * ls);
2571 const double cX = impurityConcentration * Pi *
2572 pow(FineStructureConstant * HbarC, 2) * SpeedOfLight /
2573 (
sqrt(2 * mdX) * eps * eps);
2574 const double cL = impurityConcentration * Pi *
2575 pow(FineStructureConstant * HbarC, 2) * SpeedOfLight /
2576 (
sqrt(2 * mdL) * eps * eps);
2579 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2580 const double gammaX = en * (1. + m_alphaX * en);
2581 const double gammaL = (en - m_eMinL) * (1. + m_alphaL * (en - m_eMinL));
2585 m_cfElectronsX[i].push_back(0.);
2587 const double b = 4 * gammaX / ebX;
2588 m_cfElectronsX[i].push_back((cX /
pow(gammaX, 1.5)) *
2589 (log(1. + b) - b / (1. + b)));
2591 if (en <= m_eMinL || gammaL <= 0.) {
2592 m_cfElectronsL[i].push_back(0.);
2594 const double b = 4 * gammaL / ebL;
2595 m_cfElectronsL[i].push_back((cL /
pow(gammaL, 1.5)) *
2596 (log(1. + b) - b / (1. + b)));
2601 m_energyLossElectronsX.push_back(0.);
2602 m_energyLossElectronsL.push_back(0.);
2603 m_scatTypeElectronsX.push_back(ElectronCollisionTypeImpurity);
2604 m_scatTypeElectronsL.push_back(ElectronCollisionTypeImpurity);
2611bool MediumSilicon::HoleScatteringRates() {
2613 m_cfTotHoles.assign(nEnergyStepsV, 0.);
2614 m_cfHoles.assign(nEnergyStepsV, std::vector<double>());
2615 m_energyLossHoles.clear();
2616 m_scatTypeHoles.clear();
2621 HoleAcousticScatteringRates();
2622 HoleOpticalScatteringRates();
2624 HoleIonisationRates();
2626 std::ofstream outfile;
2628 outfile.open(
"ratesV.txt", std::ios::out);
2631 for (
int i = 0; i < nEnergyStepsV; ++i) {
2633 for (
int j = m_nLevelsV; j--;) m_cfTotHoles[i] += m_cfHoles[i][j];
2636 outfile << i * m_eStepV <<
" " << m_cfTotHoles[i] <<
" ";
2637 for (
int j = 0; j < m_nLevelsV; ++j) {
2638 outfile << m_cfHoles[i][j] <<
" ";
2643 if (m_cfTotHoles[i] > m_cfNullHoles) {
2644 m_cfNullHoles = m_cfTotHoles[i];
2648 if (m_cfTotHoles[i] <= 0.) {
2649 std::cerr <<
m_className <<
"::HoleScatteringRates:\n"
2650 <<
" Scattering rate at " << i * m_eStepV <<
" eV <= 0.\n";
2654 for (
int j = 0; j < m_nLevelsV; ++j) {
2655 m_cfHoles[i][j] /= m_cfTotHoles[i];
2656 if (j > 0) m_cfHoles[i][j] += m_cfHoles[i][j - 1];
2667bool MediumSilicon::HoleAcousticScatteringRates() {
2675 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2682 constexpr double defpot2 = 4.6 * 4.6;
2684 constexpr double u = 9.04e-4;
2686 const double cIntra = TwoPi * SpeedOfLight * SpeedOfLight * kbt * defpot2 /
2687 (Hbar * u * u * rho);
2691 for (
int i = 0; i < nEnergyStepsV; ++i) {
2693 m_cfHoles[i].push_back(cIntra * dos);
2698 m_energyLossHoles.push_back(0.);
2699 m_scatTypeHoles.push_back(ElectronCollisionTypeAcousticPhonon);
2705bool MediumSilicon::HoleOpticalScatteringRates() {
2713 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2719 constexpr double dtk = 6.6e8;
2721 constexpr double eph = 63.0e-3;
2723 const double nocc = 1. / (
exp(eph / kbt) - 1);
2725 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2726 double c = c0 * dtk * dtk / eph;
2729 for (
int i = 0; i < nEnergyStepsV; ++i) {
2732 m_cfHoles[i].push_back(c * nocc * dos);
2736 m_cfHoles[i].push_back(c * (nocc + 1) * dos);
2738 m_cfHoles[i].push_back(0.);
2744 m_energyLossHoles.push_back(-eph);
2746 m_energyLossHoles.push_back(eph);
2747 m_scatTypeHoles.push_back(ElectronCollisionTypeOpticalPhonon);
2748 m_scatTypeHoles.push_back(ElectronCollisionTypeOpticalPhonon);
2755bool MediumSilicon::HoleIonisationRates() {
2760 constexpr double p[2] = {2., 1.e3};
2762 constexpr double eth[2] = {1.1, 1.45};
2764 constexpr double b[2] = {6., 4.};
2767 for (
int i = 0; i < nEnergyStepsV; ++i) {
2770 fIon += p[0] *
pow(en - eth[0], b[0]);
2773 fIon += p[1] *
pow(en - eth[1], b[1]);
2775 m_cfHoles[i].push_back(fIon);
2779 m_energyLossHoles.push_back(eth[0]);
2780 m_scatTypeHoles.push_back(ElectronCollisionTypeIonisation);
2789 int iE = int(e / m_eStepDos);
2790 const int nPoints = m_fbDosConduction.size();
2791 if (iE >= nPoints || iE < 0) {
2793 }
else if (iE == nPoints - 1) {
2794 return m_fbDosConduction[nPoints - 1];
2797 const double dos = m_fbDosConduction[iE] +
2798 (m_fbDosConduction[iE + 1] - m_fbDosConduction[iE]) *
2799 (e / m_eStepDos - iE);
2802 }
else if (band < m_nValleysX) {
2804 if (e <= 0.)
return 0.;
2806 const double md3 = pow(ElectronMass, 3) * m_mLongX * m_mTransX * m_mTransX;
2808 if (m_fullBandDos) {
2811 }
else if (e < m_eMinG) {
2817 return dosX / m_nValleysX;
2825 if (dosX <= 0.)
return 0.;
2826 return dosX / m_nValleysX;
2828 }
else if (m_nonParabolic) {
2829 const double alpha = m_alphaX;
2830 return sqrt(md3 * e * (1. + alpha * e) / 2.) * (1. + 2 * alpha * e) /
2831 (Pi2 * pow(HbarC, 3.));
2833 return sqrt(md3 * e / 2.) / (Pi2 * pow(HbarC, 3.));
2835 }
else if (band < m_nValleysX + m_nValleysL) {
2837 if (e <= m_eMinL)
return 0.;
2840 const double md3 = pow(ElectronMass, 3) * m_mLongL * m_mTransL * m_mTransL;
2842 const double alpha = m_alphaL;
2844 if (m_fullBandDos) {
2846 const double ej = m_eMinL + 0.5;
2848 return sqrt(md3 * (e - m_eMinL) * (1. + alpha * (e - m_eMinL))) *
2849 (1. + 2 * alpha * (e - m_eMinL)) /
2850 (Sqrt2 * Pi2 * pow(HbarC, 3.));
2853 double fL = sqrt(md3 * (ej - m_eMinL) * (1. + alpha * (ej - m_eMinL))) *
2854 (1. + 2 * alpha * (ej - m_eMinL)) /
2855 (Sqrt2 * Pi2 * pow(HbarC, 3.));
2863 if (dosXL <= 0.)
return 0.;
2864 return fL * dosXL / 8.;
2866 }
else if (m_nonParabolic) {
2867 return sqrt(md3 * (e - m_eMinL) * (1. + alpha * (e - m_eMinL))) *
2868 (1. + 2 * alpha * (e - m_eMinL)) / (Sqrt2 * Pi2 * pow(HbarC, 3.));
2870 return sqrt(md3 * (e - m_eMinL) / 2.) / (Pi2 * pow(HbarC, 3.));
2872 }
else if (band == m_nValleysX + m_nValleysL) {
2874 const double ej = 2.7;
2875 if (m_eMinG >= ej) {
2876 std::cerr <<
m_className <<
"::GetConductionBandDensityOfStates:\n"
2877 <<
" Cannot determine higher band density-of-states.\n"
2878 <<
" Program bug. Check offset energy!\n";
2883 }
else if (e < ej) {
2887 return dj * (e - m_eMinG) / (ej - m_eMinG);
2893 std::cerr <<
m_className <<
"::GetConductionBandDensityOfStates:\n"
2894 <<
" Band index (" << band <<
") out of range.\n";
2895 return ElectronMass * sqrt(ElectronMass * e / 2.) / (Pi2 * pow(HbarC, 3.));
2902 const int nPoints = m_fbDosValence.size();
2903 int iE = int(e / m_eStepDos);
2904 if (iE >= nPoints || iE < 0) {
2906 }
else if (iE == nPoints - 1) {
2907 return m_fbDosValence[nPoints - 1];
2911 m_fbDosValence[iE] +
2912 (m_fbDosValence[iE + 1] - m_fbDosValence[iE]) * (e / m_eStepDos - iE);
2916 std::cerr <<
m_className <<
"::GetConductionBandDensityOfStates:\n"
2917 <<
" Band index (" << band <<
") out of range.\n";
2923 const int nPointsValence = m_fbDosValence.size();
2924 const int nPointsConduction = m_fbDosConduction.size();
2925 const double widthValenceBand = m_eStepDos * nPointsValence;
2926 const double widthConductionBand = m_eStepDos * nPointsConduction;
2932 int ih = std::min(
int(eh / m_eStepDos), nPointsValence - 1);
2933 while (
RndmUniform() > m_fbDosValence[ih] / m_fbDosMaxV) {
2935 ih = std::min(
int(eh / m_eStepDos), nPointsValence - 1);
2939 int ie = std::min(
int(ee / m_eStepDos), nPointsConduction - 1);
2940 while (
RndmUniform() > m_fbDosConduction[ie] / m_fbDosMaxC) {
2942 ie = std::min(
int(ee / m_eStepDos), nPointsConduction - 1);
2945 const double ep = e0 - m_bandGap - eh - ee;
2946 if (ep < Small)
continue;
2947 if (ep > 5.)
return;
2949 int ip = std::min(
int(ep / m_eStepDos), nPointsConduction - 1);
2950 if (
RndmUniform() > m_fbDosConduction[ip] / m_fbDosMaxC)
continue;
2955void MediumSilicon::InitialiseDensityOfStates() {
2959 {0., 1.28083, 2.08928, 2.70763, 3.28095, 3.89162, 4.50547, 5.15043,
2960 5.89314, 6.72667, 7.67768, 8.82725, 10.6468, 12.7003, 13.7457, 14.0263,
2961 14.2731, 14.5527, 14.8808, 15.1487, 15.4486, 15.7675, 16.0519, 16.4259,
2962 16.7538, 17.0589, 17.3639, 17.6664, 18.0376, 18.4174, 18.2334, 16.7552,
2963 15.1757, 14.2853, 13.6516, 13.2525, 12.9036, 12.7203, 12.6104, 12.6881,
2964 13.2862, 14.0222, 14.9366, 13.5084, 9.77808, 6.15266, 3.47839, 2.60183,
2965 2.76747, 3.13985, 3.22524, 3.29119, 3.40868, 3.6118, 3.8464, 4.05776,
2966 4.3046, 4.56219, 4.81553, 5.09909, 5.37616, 5.67297, 6.04611, 6.47252,
2967 6.9256, 7.51254, 8.17923, 8.92351, 10.0309, 11.726, 16.2853, 18.2457,
2968 12.8879, 7.86019, 6.02275, 5.21777, 4.79054, 3.976, 3.11855, 2.46854,
2969 1.65381, 0.830278, 0.217735}};
2971 m_fbDosConduction = {
2972 {0., 1.5114, 2.71026, 3.67114, 4.40173, 5.05025, 5.6849, 6.28358,
2973 6.84628, 7.43859, 8.00204, 8.80658, 9.84885, 10.9579, 12.0302, 13.2051,
2974 14.6948, 16.9879, 18.4492, 18.1933, 17.6747, 16.8135, 15.736, 14.4965,
2975 13.1193, 12.1817, 12.6109, 15.3148, 19.4936, 23.0093, 24.4106, 22.2834,
2976 19.521, 18.9894, 18.8015, 17.9363, 17.0252, 15.9871, 14.8486, 14.3797,
2977 14.2426, 14.3571, 14.7271, 14.681, 14.3827, 14.2789, 14.144, 14.1684,
2978 14.1418, 13.9237, 13.7558, 13.5691, 13.4567, 13.2693, 12.844, 12.4006,
2979 12.045, 11.7729, 11.3607, 11.14, 11.0586, 10.5475, 9.73786, 9.34423,
2980 9.4694, 9.58071, 9.6967, 9.84854, 10.0204, 9.82705, 9.09102, 8.30665,
2981 7.67306, 7.18925, 6.79675, 6.40713, 6.21687, 6.33267, 6.5223, 6.17877,
2982 5.48659, 4.92208, 4.44239, 4.02941, 3.5692, 3.05953, 2.6428, 2.36979,
2983 2.16273, 2.00627, 1.85206, 1.71265, 1.59497, 1.46681, 1.34913, 1.23951,
2984 1.13439, 1.03789, 0.924155, 0.834962, 0.751017}};
2986 auto it = std::max_element(m_fbDosValence.begin(), m_fbDosValence.end());
2988 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)