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";
155 const double emag = sqrt(ex * ex + ey * ey + ez * ez);
158 if (fabs(bx) < Small && fabs(by) < Small && fabs(bz) < Small) {
163 Langevin(ex, ey, ez, bx, by, bz, mu, m_eHallFactor * mu, vx, vy, vz);
169 const double ez,
const double bx,
170 const double by,
const double bz,
174 if (!UpdateTransportParameters()) {
175 std::cerr <<
m_className <<
"::ElectronTownsend:\n"
176 <<
" Error calculating the transport parameters.\n";
187 const double emag = sqrt(ex * ex + ey * ey + ez * ez);
188 alpha = ElectronAlpha(emag);
193 const double ez,
const double bx,
194 const double by,
const double bz,
198 if (!UpdateTransportParameters()) {
199 std::cerr <<
m_className <<
"::ElectronAttachment:\n"
200 <<
" Error calculating the transport parameters.\n";
211 switch (m_trappingModel) {
213 eta = m_eTrapCs * m_eTrapDensity;
218 eta = m_eTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
219 if (eta > 0.) eta = -1. / eta;
222 std::cerr <<
m_className <<
"::ElectronAttachment: Unknown model. Bug!\n";
230 const double ez,
const double bx,
231 const double by,
const double bz,
double& vx,
232 double& vy,
double& vz) {
235 if (!UpdateTransportParameters()) {
237 <<
" Error calculating the transport parameters.\n";
249 const double emag = sqrt(ex * ex + ey * ey + ez * ez);
252 if (fabs(bx) < Small && fabs(by) < Small && fabs(bz) < Small) {
257 Langevin(ex, ey, ez, bx, by, bz, mu, m_hHallFactor * mu, vx, vy, vz);
263 const double ez,
const double bx,
264 const double by,
const double bz,
268 if (!UpdateTransportParameters()) {
270 <<
" Error calculating the transport parameters.\n";
281 const double emag = sqrt(ex * ex + ey * ey + ez * ez);
282 alpha = HoleAlpha(emag);
287 const double ez,
const double bx,
288 const double by,
const double bz,
292 if (!UpdateTransportParameters()) {
294 <<
" Error calculating the transport parameters.\n";
305 switch (m_trappingModel) {
307 eta = m_hTrapCs * m_hTrapDensity;
312 eta = m_hTrapTime * sqrt(vx * vx + vy * vy + vz * vz);
313 if (eta > 0.) eta = -1. / eta;
316 std::cerr <<
m_className <<
"::HoleAttachment: Unknown model. Bug!\n";
324 if (mue <= 0. || muh <= 0.) {
325 std::cerr <<
m_className <<
"::SetLowFieldMobility:\n"
326 <<
" Mobility must be greater than zero.\n";
332 m_hasUserMobility =
true;
337 m_latticeMobilityModel = LatticeMobility::Minimos;
338 m_hasUserMobility =
false;
343 m_latticeMobilityModel = LatticeMobility::Sentaurus;
344 m_hasUserMobility =
false;
349 m_latticeMobilityModel = LatticeMobility::Reggiani;
350 m_hasUserMobility =
false;
355 m_dopingMobilityModel = DopingMobility::Minimos;
356 m_hasUserMobility =
false;
361 m_dopingMobilityModel = DopingMobility::Masetti;
362 m_hasUserMobility =
false;
367 const double vsath) {
368 if (vsate <= 0. || vsath <= 0.) {
369 std::cout <<
m_className <<
"::SetSaturationVelocity:\n"
370 <<
" Restoring default values.\n";
371 m_hasUserSaturationVelocity =
false;
375 m_hasUserSaturationVelocity =
true;
382 m_saturationVelocityModel = SaturationVelocity::Minimos;
383 m_hasUserSaturationVelocity =
false;
388 m_saturationVelocityModel = SaturationVelocity::Canali;
389 m_hasUserSaturationVelocity =
false;
394 m_saturationVelocityModel = SaturationVelocity::Reggiani;
395 m_hasUserSaturationVelocity =
false;
400 m_highFieldMobilityModel = HighFieldMobility::Minimos;
405 m_highFieldMobilityModel = HighFieldMobility::Canali;
410 m_highFieldMobilityModel = HighFieldMobility::Reggiani;
415 m_highFieldMobilityModel = HighFieldMobility::Constant;
419 m_impactIonisationModel = ImpactIonisation::VanOverstraeten;
424 m_impactIonisationModel = ImpactIonisation::Grant;
429 m_impactIonisationModel = ImpactIonisation::Massey;
434 m_impactIonisationModel = ImpactIonisation::Okuto;
439 if (e <= m_eMinG + Small) {
440 std::cerr <<
m_className <<
"::SetMaxElectronEnergy:\n"
441 <<
" Requested upper electron energy limit (" << e
442 <<
" eV) is too small.\n";
448 m_eStepG = m_eFinalG / nEnergyStepsG;
456 const double pz,
double& vx,
double& vy,
457 double& vz,
const int band) {
459 double mx = ElectronMass, my = ElectronMass, mz = ElectronMass;
462 if (band >= 0 && band < m_nValleysX) {
488 std::cerr <<
m_className <<
"::GetElectronEnergy:\n"
489 <<
" Unexpected band index " << band <<
"!\n";
494 const double mc = 3. / (1. / m_mLongX + 2. / m_mTransX);
499 }
else if (band < m_nValleysX + m_nValleysL) {
503 const double mc = 3. / (1. / m_mLongL + 2. / m_mTransL);
507 }
else if (band == m_nValleysX + m_nValleysL) {
511 if (m_nonParabolic) {
514 if (band < m_nValleysX) {
517 }
else if (band < m_nValleysX + m_nValleysL) {
522 const double p2 = 0.5 * (px * px / mx + py * py / my + pz * pz / mz);
524 const double e = 0.5 * (sqrt(1. + 4 * alpha * p2) - 1.) / alpha;
525 const double a = SpeedOfLight / (1. + 2 * alpha * e);
533 const double e = 0.5 * (px * px / mx + py * py / my + pz * pz / mz);
534 vx = SpeedOfLight * px / mx;
535 vy = SpeedOfLight * py / my;
536 vz = SpeedOfLight * pz / mz;
541 double& pz,
int& band) {
543 if (band < 0 || band > m_nValleysX + m_nValleysL ||
544 (e < m_eMinL || band >= m_nValleysX) ||
545 (e < m_eMinG || band == m_nValleysX + m_nValleysL)) {
548 if (band >= m_nValleysX) band = m_nValleysX - 1;
554 const double dosSum = m_nValleysX * dosX + m_nValleysL * dosL + dosG;
555 if (dosSum < Small) {
556 band = m_nValleysX + m_nValleysL;
561 if (band >= m_nValleysX) band = m_nValleysX - 1;
562 }
else if (r < dosX + dosL) {
563 band = m_nValleysX + int(m_nValleysL *
RndmUniform());
564 if (band >= m_nValleysX + m_nValleysL) band = m_nValleysL - 1;
566 band = m_nValleysX + m_nValleysL;
571 std::cout <<
m_className <<
"::GetElectronMomentum:\n"
572 <<
" Randomised band index: " << band <<
"\n";
575 if (band < m_nValleysX) {
577 double pstar = sqrt(2. * ElectronMass * e);
578 if (m_nonParabolic) {
579 const double alpha = m_alphaX;
580 pstar *= sqrt(1. + alpha * e);
584 const double stheta = sqrt(1. - ctheta * ctheta);
588 const double pl = pstar * sqrt(m_mLongX);
589 const double pt = pstar * sqrt(m_mTransX);
595 py = pt * cos(phi) * stheta;
596 pz = pt * sin(phi) * stheta;
601 px = pt * sin(phi) * stheta;
603 pz = pt * cos(phi) * stheta;
608 px = pt * cos(phi) * stheta;
609 py = pt * sin(phi) * stheta;
614 std::cerr <<
m_className <<
"::GetElectronMomentum:\n"
615 <<
" Unexpected band index (" << band <<
").\n";
616 px = pstar * stheta * cos(phi);
617 py = pstar * stheta * sin(phi);
622 pstar *= sqrt(3. / (1. / m_mLongX + 2. / m_mTransX));
623 px = pstar * cos(phi) * stheta;
624 py = pstar * sin(phi) * stheta;
627 }
else if (band < m_nValleysX + m_nValleysL) {
629 double pstar = sqrt(2. * ElectronMass * (e - m_eMinL));
630 if (m_nonParabolic) {
631 const double alpha = m_alphaL;
632 pstar *= sqrt(1. + alpha * (e - m_eMinL));
634 pstar *= sqrt(3. / (1. / m_mLongL + 2. / m_mTransL));
636 }
else if (band == m_nValleysX + m_nValleysL) {
638 const double pstar = sqrt(2. * ElectronMass * e);
645 if (!UpdateTransportParameters()) {
646 std::cerr <<
m_className <<
"::GetElectronNullCollisionRate:\n"
647 <<
" Error calculating the collision rates table.\n";
653 if (band >= 0 && band < m_nValleysX) {
654 return m_cfNullElectronsX;
655 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
656 return m_cfNullElectronsL;
657 }
else if (band == m_nValleysX + m_nValleysL) {
658 return m_cfNullElectronsG;
660 std::cerr <<
m_className <<
"::GetElectronNullCollisionRate:\n"
661 <<
" Band index (" << band <<
") out of range.\n";
667 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
668 <<
" Electron energy must be positive.\n";
673 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
674 <<
" Collision rate at " << e <<
" eV (band " << band
675 <<
") is not included in the current table.\n"
676 <<
" Increasing energy range to " << 1.05 * e <<
" eV.\n";
681 if (!UpdateTransportParameters()) {
682 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
683 <<
" Error calculating the collision rates table.\n";
689 if (band >= 0 && band < m_nValleysX) {
690 int iE = int(e / m_eStepXL);
691 if (iE >= nEnergyStepsXL)
692 iE = nEnergyStepsXL - 1;
695 return m_cfTotElectronsX[iE];
696 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
697 int iE = int(e / m_eStepXL);
698 if (iE >= nEnergyStepsXL)
699 iE = nEnergyStepsXL - 1;
700 else if (iE < m_ieMinL)
702 return m_cfTotElectronsL[iE];
703 }
else if (band == m_nValleysX + m_nValleysL) {
704 int iE = int(e / m_eStepG);
705 if (iE >= nEnergyStepsG)
706 iE = nEnergyStepsG - 1;
707 else if (iE < m_ieMinG)
709 return m_cfTotElectronsG[iE];
712 std::cerr <<
m_className <<
"::GetElectronCollisionRate:\n"
713 <<
" Band index (" << band <<
") out of range.\n";
718 int& level,
double& e1,
double& px,
double& py,
double& pz,
719 std::vector<std::pair<Particle, double> >& secondaries,
int& ndxc,
722 std::cerr <<
m_className <<
"::ElectronCollision:\n"
723 <<
" Requested electron energy (" << e <<
" eV) exceeds the "
724 <<
"current energy range (" << m_eFinalG <<
" eV).\n"
725 <<
" Increasing energy range to " << 1.05 * e <<
" eV.\n";
727 }
else if (e <= 0.) {
728 std::cerr <<
m_className <<
"::ElectronCollision:\n"
729 <<
" Electron energy must be greater than zero.\n";
734 if (!UpdateTransportParameters()) {
735 std::cerr <<
m_className <<
"::ElectronCollision:\n"
736 <<
" Error calculating the collision rates table.\n";
745 if (band >= 0 && band < m_nValleysX) {
748 int iE = int(e / m_eStepXL);
749 if (iE >= nEnergyStepsXL) iE = nEnergyStepsXL - 1;
753 if (r <= m_cfElectronsX[iE][0]) {
755 }
else if (r >= m_cfElectronsX[iE][m_nLevelsX - 1]) {
756 level = m_nLevelsX - 1;
758 const auto begin = m_cfElectronsX[iE].cbegin();
759 level = std::lower_bound(begin, begin + m_nLevelsX, r) - begin;
763 type = m_scatTypeElectronsX[level];
765 ++m_nCollElectronDetailed[level];
766 ++m_nCollElectronBand[band];
767 if (type == ElectronCollisionTypeAcousticPhonon) {
768 ++m_nCollElectronAcoustic;
769 }
else if (type == ElectronCollisionTypeIntervalleyG) {
771 ++m_nCollElectronIntervalley;
795 }
else if (type == ElectronCollisionTypeIntervalleyF) {
797 ++m_nCollElectronIntervalley;
807 if (band > 1) band += 2;
814 }
else if (type == ElectronCollisionTypeInterbandXL) {
816 ++m_nCollElectronIntervalley;
818 band = m_nValleysX + int(
RndmUniform() * m_nValleysL);
819 if (band >= m_nValleysX + m_nValleysL)
820 band = m_nValleysX + m_nValleysL - 1;
821 }
else if (type == ElectronCollisionTypeInterbandXG) {
822 ++m_nCollElectronIntervalley;
823 band = m_nValleysX + m_nValleysL;
824 }
else if (type == ElectronCollisionTypeImpurity) {
825 ++m_nCollElectronImpurity;
826 }
else if (type == ElectronCollisionTypeIonisation) {
827 ++m_nCollElectronIonisation;
829 std::cerr <<
m_className <<
"::ElectronCollision:\n";
830 std::cerr <<
" Unexpected collision type (" << type <<
").\n";
834 loss = m_energyLossElectronsX[level];
836 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
839 int iE = int(e / m_eStepXL);
840 if (iE >= nEnergyStepsXL) iE = nEnergyStepsXL - 1;
841 if (iE < m_ieMinL) iE = m_ieMinL;
844 if (r <= m_cfElectronsL[iE][0]) {
846 }
else if (r >= m_cfElectronsL[iE][m_nLevelsL - 1]) {
847 level = m_nLevelsL - 1;
849 const auto begin = m_cfElectronsL[iE].cbegin();
850 level = std::lower_bound(begin, begin + m_nLevelsL, r) - begin;
854 type = m_scatTypeElectronsL[level];
856 ++m_nCollElectronDetailed[m_nLevelsX + level];
857 ++m_nCollElectronBand[band];
858 if (type == ElectronCollisionTypeAcousticPhonon) {
859 ++m_nCollElectronAcoustic;
860 }
else if (type == ElectronCollisionTypeOpticalPhonon) {
861 ++m_nCollElectronOptical;
862 }
else if (type == ElectronCollisionTypeIntervalleyG ||
863 type == ElectronCollisionTypeIntervalleyF) {
865 ++m_nCollElectronIntervalley;
867 band = m_nValleysX + int(
RndmUniform() * m_nValleysL);
868 if (band >= m_nValleysX + m_nValleysL) band = m_nValleysX + m_nValleysL;
869 }
else if (type == ElectronCollisionTypeInterbandXL) {
871 ++m_nCollElectronIntervalley;
874 if (band >= m_nValleysX) band = m_nValleysX - 1;
875 }
else if (type == ElectronCollisionTypeInterbandLG) {
877 ++m_nCollElectronIntervalley;
878 band = m_nValleysX + m_nValleysL;
879 }
else if (type == ElectronCollisionTypeImpurity) {
880 ++m_nCollElectronImpurity;
881 }
else if (type == ElectronCollisionTypeIonisation) {
882 ++m_nCollElectronIonisation;
884 std::cerr <<
m_className <<
"::ElectronCollision:\n"
885 <<
" Unexpected collision type (" << type <<
").\n";
889 loss = m_energyLossElectronsL[level];
890 }
else if (band == m_nValleysX + m_nValleysL) {
893 int iE = int(e / m_eStepG);
894 if (iE >= nEnergyStepsG) iE = nEnergyStepsG - 1;
895 if (iE < m_ieMinG) iE = m_ieMinG;
898 if (r <= m_cfElectronsG[iE][0]) {
900 }
else if (r >= m_cfElectronsG[iE][m_nLevelsG - 1]) {
901 level = m_nLevelsG - 1;
903 const auto begin = m_cfElectronsG[iE].cbegin();
904 level = std::lower_bound(begin, begin + m_nLevelsG, r) - begin;
908 type = m_scatTypeElectronsG[level];
910 ++m_nCollElectronDetailed[m_nLevelsX + m_nLevelsL + level];
911 ++m_nCollElectronBand[band];
912 if (type == ElectronCollisionTypeAcousticPhonon) {
913 ++m_nCollElectronAcoustic;
914 }
else if (type == ElectronCollisionTypeOpticalPhonon) {
915 ++m_nCollElectronOptical;
916 }
else if (type == ElectronCollisionTypeIntervalleyG ||
917 type == ElectronCollisionTypeIntervalleyF) {
919 ++m_nCollElectronIntervalley;
920 }
else if (type == ElectronCollisionTypeInterbandXG) {
922 ++m_nCollElectronIntervalley;
925 if (band >= m_nValleysX) band = m_nValleysX - 1;
926 }
else if (type == ElectronCollisionTypeInterbandLG) {
928 ++m_nCollElectronIntervalley;
930 band = m_nValleysX + int(
RndmUniform() * m_nValleysL);
931 if (band >= m_nValleysX + m_nValleysL)
932 band = m_nValleysX + m_nValleysL - 1;
933 }
else if (type == ElectronCollisionTypeIonisation) {
934 ++m_nCollElectronIonisation;
936 std::cerr <<
m_className <<
"::ElectronCollision:\n"
937 <<
" Unexpected collision type (" << type <<
").\n";
941 loss = m_energyLossElectronsG[level];
943 std::cerr <<
m_className <<
"::ElectronCollision:\n"
944 <<
" Band index (" << band <<
") out of range.\n";
951 if (type == ElectronCollisionTypeIonisation) {
952 double ee = 0., eh = 0.;
954 loss = ee + eh + m_bandGap;
961 if (e < loss) loss = e - 0.00001;
964 if (e1 < Small) e1 = Small;
967 if (band >= 0 && band < m_nValleysX) {
969 double pstar = sqrt(2. * ElectronMass * e1);
970 if (m_nonParabolic) {
971 const double alpha = m_alphaX;
972 pstar *= sqrt(1. + alpha * e1);
976 const double stheta = sqrt(1. - ctheta * ctheta);
980 const double pl = pstar * sqrt(m_mLongX);
981 const double pt = pstar * sqrt(m_mTransX);
987 py = pt * cos(phi) * stheta;
988 pz = pt * sin(phi) * stheta;
993 px = pt * sin(phi) * stheta;
995 pz = pt * cos(phi) * stheta;
1000 px = pt * cos(phi) * stheta;
1001 py = pt * sin(phi) * stheta;
1008 pstar *= sqrt(3. / (1. / m_mLongX + 2. / m_mTransX));
1009 px = pstar * cos(phi) * stheta;
1010 py = pstar * sin(phi) * stheta;
1011 pz = pstar * ctheta;
1015 }
else if (band >= m_nValleysX && band < m_nValleysX + m_nValleysL) {
1017 double pstar = sqrt(2. * ElectronMass * (e1 - m_eMinL));
1018 if (m_nonParabolic) {
1019 const double alpha = m_alphaL;
1020 pstar *= sqrt(1. + alpha * (e1 - m_eMinL));
1022 pstar *= sqrt(3. / (1. / m_mLongL + 2. / m_mTransL));
1026 const double pstar = sqrt(2. * ElectronMass * e1);
1032 m_nCollElectronAcoustic = m_nCollElectronOptical = 0;
1033 m_nCollElectronIntervalley = 0;
1034 m_nCollElectronImpurity = 0;
1035 m_nCollElectronIonisation = 0;
1036 const auto nLevels = m_nLevelsX + m_nLevelsL + m_nLevelsG;
1037 m_nCollElectronDetailed.assign(nLevels, 0);
1038 const auto nBands = m_nValleysX + m_nValleysL + 1;
1039 m_nCollElectronBand.assign(nBands, 0);
1043 return m_nCollElectronAcoustic + m_nCollElectronOptical +
1044 m_nCollElectronIntervalley + m_nCollElectronImpurity +
1045 m_nCollElectronIonisation;
1049 return m_nLevelsX + m_nLevelsL + m_nLevelsG;
1053 const unsigned int level)
const {
1054 const unsigned int nLevels = m_nLevelsX + m_nLevelsL + m_nLevelsG;
1055 if (level >= nLevels) {
1056 std::cerr <<
m_className <<
"::GetNumberOfElectronCollisions:\n"
1057 <<
" Scattering rate term (" << level <<
") does not exist.\n";
1060 return m_nCollElectronDetailed[level];
1064 return m_nValleysX + m_nValleysL + 1;
1068 const int nBands = m_nValleysX + m_nValleysL + 1;
1069 if (band < 0 || band >= nBands) {
1070 std::cerr <<
m_className <<
"::GetElectronBandPopulation:\n";
1071 std::cerr <<
" Band index (" << band <<
") out of range.\n";
1074 return m_nCollElectronBand[band];
1078 const unsigned int i) {
1080 std::cerr <<
m_className <<
"::GetOpticalDataRange: Index out of range.\n";
1084 if (m_opticalDataEnergies.empty()) {
1085 if (!LoadOpticalData(m_opticalDataFile)) {
1086 std::cerr <<
m_className <<
"::GetOpticalDataRange:\n"
1087 <<
" Optical data table could not be loaded.\n";
1092 emin = m_opticalDataEnergies.front();
1093 emax = m_opticalDataEnergies.back();
1095 std::cout <<
m_className <<
"::GetOpticalDataRange:\n"
1096 <<
" " << emin <<
" < E [eV] < " << emax <<
"\n";
1102 double& eps2,
const unsigned int i) {
1104 std::cerr <<
m_className +
"::GetDielectricFunction: Index out of range.\n";
1109 if (m_opticalDataEnergies.empty()) {
1110 if (!LoadOpticalData(m_opticalDataFile)) {
1111 std::cerr <<
m_className <<
"::GetDielectricFunction:\n";
1112 std::cerr <<
" Optical data table could not be loaded.\n";
1118 const double emin = m_opticalDataEnergies.front();
1119 const double emax = m_opticalDataEnergies.back();
1120 if (e < emin || e > emax) {
1121 std::cerr <<
m_className <<
"::GetDielectricFunction:\n"
1122 <<
" Requested energy (" << e <<
" eV) "
1123 <<
" is outside the range of the optical data table.\n"
1124 <<
" " << emin <<
" < E [eV] < " << emax <<
"\n";
1130 const auto begin = m_opticalDataEnergies.cbegin();
1131 const auto it1 = std::upper_bound(begin, m_opticalDataEnergies.cend(), e);
1133 eps1 = m_opticalDataEpsilon.front().first;
1134 eps2 = m_opticalDataEpsilon.front().second;
1137 const auto it0 = std::prev(it1);
1140 const double x0 = *it0;
1141 const double x1 = *it1;
1142 const double lnx0 = log(*it0);
1143 const double lnx1 = log(*it1);
1144 const double lnx = log(e);
1145 const double y0 = m_opticalDataEpsilon[it0 - begin].first;
1146 const double y1 = m_opticalDataEpsilon[it1 - begin].first;
1147 if (y0 <= 0. || y1 <= 0.) {
1149 eps1 = y0 + (e - x0) * (y1 - y0) / (x1 - x0);
1152 const double lny0 = log(y0);
1153 const double lny1 = log(y1);
1154 eps1 = lny0 + (lnx - lnx0) * (lny1 - lny0) / (lnx1 - lnx0);
1160 const double lnz0 = log(m_opticalDataEpsilon[it0 - begin].second);
1161 const double lnz1 = log(m_opticalDataEpsilon[it1 - begin].second);
1162 eps2 = lnz0 + (lnx - lnx0) * (lnz1 - lnz0) / (lnx1 - lnx0);
1170 std::cerr <<
m_className <<
"::Initialise: Nothing changed.\n";
1174 if (!UpdateTransportParameters()) {
1175 std::cerr <<
m_className <<
"::Initialise:\n Error preparing "
1176 <<
"transport parameters/calculating collision rates.\n";
1182bool MediumSilicon::UpdateTransportParameters() {
1183 std::lock_guard<std::mutex> guard(m_mutex);
1186 UpdateImpactIonisation();
1188 if (!m_hasUserMobility) {
1190 UpdateLatticeMobility();
1193 switch (m_dopingMobilityModel) {
1194 case DopingMobility::Minimos:
1195 UpdateDopingMobilityMinimos();
1197 case DopingMobility::Masetti:
1198 UpdateDopingMobilityMasetti();
1201 std::cerr <<
m_className <<
"::UpdateTransportParameters:\n "
1202 <<
"Unknown doping mobility model. Program bug!\n";
1208 if (!m_hasUserSaturationVelocity) {
1209 UpdateSaturationVelocity();
1213 if (m_highFieldMobilityModel == HighFieldMobility::Canali) {
1214 UpdateHighFieldMobilityCanali();
1218 std::cout <<
m_className <<
"::UpdateTransportParameters:\n"
1219 <<
" Low-field mobility [cm2 V-1 ns-1]\n"
1220 <<
" Electrons: " << m_eMobility <<
"\n"
1221 <<
" Holes: " << m_hMobility <<
"\n";
1222 if (m_highFieldMobilityModel == HighFieldMobility::Constant) {
1223 std::cout <<
" Mobility is not field-dependent.\n";
1225 std::cout <<
" Saturation velocity [cm / ns]\n"
1226 <<
" Electrons: " << m_eSatVel <<
"\n"
1227 <<
" Holes: " << m_hSatVel <<
"\n";
1231 if (!ElectronScatteringRates())
return false;
1232 if (!HoleScatteringRates())
return false;
1240void MediumSilicon::UpdateLatticeMobility() {
1245 switch (m_latticeMobilityModel) {
1246 case LatticeMobility::Minimos:
1250 m_eLatticeMobility = 1.43e-6 *
pow(t, -2.);
1251 m_hLatticeMobility = 0.46e-6 *
pow(t, -2.18);
1253 case LatticeMobility::Sentaurus:
1256 m_eLatticeMobility = 1.417e-6 *
pow(t, -2.5);
1257 m_hLatticeMobility = 0.4705e-6 *
pow(t, -2.2);
1259 case LatticeMobility::Reggiani:
1261 m_eLatticeMobility = 1.320e-6 *
pow(t, -2.);
1262 m_hLatticeMobility = 0.460e-6 *
pow(t, -2.2);
1265 std::cerr <<
m_className <<
"::UpdateLatticeMobility:\n"
1266 <<
" Unknown lattice mobility model. Program bug!\n";
1271void MediumSilicon::UpdateDopingMobilityMinimos() {
1279 double eMuMin = 0.080e-6;
1280 double hMuMin = 0.045e-6;
1291 const double eRefC = 1.12e17 * c1;
1292 const double hRefC = 2.23e17 * c1;
1295 m_eMobility = eMuMin +
1296 (m_eLatticeMobility - eMuMin) /
1297 (1. +
pow(m_dopingConcentration / eRefC, alpha));
1298 m_hMobility = hMuMin +
1299 (m_hLatticeMobility - hMuMin) /
1300 (1. +
pow(m_dopingConcentration / hRefC, alpha));
1303void MediumSilicon::UpdateDopingMobilityMasetti() {
1310 if (m_dopingConcentration < 1.e13) {
1311 m_eMobility = m_eLatticeMobility;
1312 m_hMobility = m_hLatticeMobility;
1317 constexpr double eMuMin1 = 0.0522e-6;
1318 constexpr double eMuMin2 = 0.0522e-6;
1319 constexpr double eMu1 = 0.0434e-6;
1320 constexpr double hMuMin1 = 0.0449e-6;
1321 constexpr double hMuMin2 = 0.;
1322 constexpr double hMu1 = 0.029e-6;
1323 constexpr double eCr = 9.68e16;
1324 constexpr double eCs = 3.42e20;
1325 constexpr double hCr = 2.23e17;
1326 constexpr double hCs = 6.10e20;
1327 constexpr double hPc = 9.23e16;
1328 constexpr double eAlpha = 0.68;
1329 constexpr double eBeta = 2.;
1330 constexpr double hAlpha = 0.719;
1331 constexpr double hBeta = 2.;
1333 m_eMobility = eMuMin1 +
1334 (m_eLatticeMobility - eMuMin2) /
1335 (1. +
pow(m_dopingConcentration / eCr, eAlpha)) -
1336 eMu1 / (1. +
pow(eCs / m_dopingConcentration, eBeta));
1338 m_hMobility = hMuMin1 *
exp(-hPc / m_dopingConcentration) +
1339 (m_hLatticeMobility - hMuMin2) /
1340 (1. +
pow(m_dopingConcentration / hCr, hAlpha)) -
1341 hMu1 / (1. +
pow(hCs / m_dopingConcentration, hBeta));
1344void MediumSilicon::UpdateSaturationVelocity() {
1346 switch (m_saturationVelocityModel) {
1347 case SaturationVelocity::Minimos:
1351 m_eSatVel = 1.e-2 / (1. + 0.74 * (
m_temperature / 300. - 1.));
1352 m_hSatVel = 0.704e-2 / (1. + 0.37 * (
m_temperature / 300. - 1.));
1354 case SaturationVelocity::Canali:
1361 case SaturationVelocity::Reggiani:
1367 std::cerr <<
m_className <<
"::UpdateSaturationVelocity:\n"
1368 <<
" Unknown saturation velocity model. Program bug!\n";
1373void MediumSilicon::UpdateHighFieldMobilityCanali() {
1382 m_eBetaCanaliInv = 1. / m_eBetaCanali;
1383 m_hBetaCanaliInv = 1. / m_hBetaCanali;
1386void MediumSilicon::UpdateImpactIonisation() {
1388 if (m_impactIonisationModel == ImpactIonisation::VanOverstraeten ||
1389 m_impactIonisationModel == ImpactIonisation::Grant) {
1393 constexpr double hbarOmega = 0.063;
1395 const double gamma =
1396 tanh(hbarOmega / (2. * BoltzmannConstant * 300.)) /
1399 if (m_impactIonisationModel == ImpactIonisation::VanOverstraeten) {
1409 m_eImpactA0 = gamma * 7.03e5;
1410 m_eImpactB0 = gamma * 1.231e6;
1411 m_eImpactA1 = gamma * 7.03e5;
1412 m_eImpactB1 = gamma * 1.231e6;
1414 m_hImpactA0 = gamma * 1.582e6;
1415 m_hImpactB0 = gamma * 2.036e6;
1416 m_hImpactA1 = gamma * 6.71e5;
1417 m_hImpactB1 = gamma * 1.693e6;
1421 m_eImpactA0 = 2.60e6 * gamma;
1422 m_eImpactB0 = 1.43e6 * gamma;
1423 m_eImpactA1 = 6.20e5 * gamma;
1424 m_eImpactB1 = 1.08e6 * gamma;
1425 m_eImpactA2 = 5.05e5 * gamma;
1426 m_eImpactB2 = 9.90e5 * gamma;
1428 m_hImpactA0 = 2.00e6 * gamma;
1429 m_hImpactB0 = 1.97e6 * gamma;
1430 m_hImpactA1 = 5.60e5 * gamma;
1431 m_hImpactB1 = 1.32e6 * gamma;
1433 }
else if (m_impactIonisationModel == ImpactIonisation::Massey) {
1436 m_eImpactA0 = 4.43e5;
1439 m_hImpactA0 = 1.13e6;
1441 }
else if (m_impactIonisationModel == ImpactIonisation::Okuto) {
1443 m_eImpactA0 = 0.426 * (1. + 3.05e-4 * dt);
1444 m_hImpactA0 = 0.243 * (1. + 5.35e-4 * dt);
1445 m_eImpactB0 = 4.81e5 * (1. + 6.86e-4 * dt);
1446 m_hImpactB0 = 6.53e5 * (1. + 5.67e-4 * dt);
1448 std::cerr <<
m_className <<
"::UpdateImpactIonisation:\n"
1449 <<
" Unknown impact ionisation model. Program bug!\n";
1455 if (emag < Small)
return 0.;
1457 if (m_highFieldMobilityModel == HighFieldMobility::Minimos) {
1459 const double r = 2 * m_eMobility * emag / m_eSatVel;
1460 return 2. * m_eMobility / (1. +
sqrt(1. + r * r));
1461 }
else if (m_highFieldMobilityModel == HighFieldMobility::Canali) {
1463 const double r = m_eMobility * emag / m_eSatVel;
1464 return m_eMobility /
pow(1. +
pow(r, m_eBetaCanali), m_eBetaCanaliInv);
1465 }
else if (m_highFieldMobilityModel == HighFieldMobility::Reggiani) {
1467 const double r = m_eMobility * emag / m_eSatVel;
1468 constexpr double k = 1. / 1.5;
1469 return m_eMobility /
pow(1. +
pow(r, 1.5), k);
1474double MediumSilicon::ElectronAlpha(
const double emag)
const {
1476 if (emag < Small)
return 0.;
1478 if (m_impactIonisationModel == ImpactIonisation::VanOverstraeten) {
1485 return m_eImpactA0 *
exp(-m_eImpactB0 / emag);
1487 return m_eImpactA1 *
exp(-m_eImpactB1 / emag);
1489 }
else if (m_impactIonisationModel == ImpactIonisation::Grant) {
1492 return m_eImpactA0 *
exp(-m_eImpactB0 / emag);
1493 }
else if (emag < 5.3e5) {
1494 return m_eImpactA1 *
exp(-m_eImpactB1 / emag);
1496 return m_eImpactA2 *
exp(-m_eImpactB2 / emag);
1498 }
else if (m_impactIonisationModel == ImpactIonisation::Massey) {
1499 return m_eImpactA0 *
exp(-m_eImpactB0 / emag);
1500 }
else if (m_impactIonisationModel == ImpactIonisation::Okuto) {
1501 const double f = m_eImpactB0 / emag;
1502 return m_eImpactA0 * emag *
exp(-f * f);
1504 std::cerr <<
m_className <<
"::ElectronAlpha: Unknown model. Program bug!\n";
1510 if (emag < Small)
return 0.;
1512 if (m_highFieldMobilityModel == HighFieldMobility::Minimos) {
1514 return m_hMobility / (1. + m_hMobility * emag / m_eSatVel);
1515 }
else if (m_highFieldMobilityModel == HighFieldMobility::Canali) {
1517 const double r = m_hMobility * emag / m_hSatVel;
1518 return m_hMobility /
pow(1. +
pow(r, m_hBetaCanali), m_hBetaCanaliInv);
1519 }
else if (m_highFieldMobilityModel == HighFieldMobility::Reggiani) {
1521 const double r = m_hMobility * emag / m_hSatVel;
1522 return m_hMobility /
sqrt(1. + r * r);
1527double MediumSilicon::HoleAlpha(
const double emag)
const {
1529 if (emag < Small)
return 0.;
1531 if (m_impactIonisationModel == ImpactIonisation::VanOverstraeten) {
1536 return m_hImpactA0 *
exp(-m_hImpactB0 / emag);
1538 return m_hImpactA1 *
exp(-m_hImpactB1 / emag);
1540 }
else if (m_impactIonisationModel == ImpactIonisation::Grant) {
1543 return m_hImpactA0 *
exp(-m_hImpactB0 / emag);
1545 return m_hImpactA1 *
exp(-m_hImpactB1 / emag);
1547 }
else if (m_impactIonisationModel == ImpactIonisation::Massey) {
1548 return m_hImpactA0 *
exp(-m_hImpactB0 / emag);
1549 }
else if (m_impactIonisationModel == ImpactIonisation::Okuto) {
1550 const double f = m_hImpactB0 / emag;
1551 return m_hImpactA0 * emag *
exp(-f * f);
1553 std::cerr <<
m_className <<
"::HoleAlpha: Unknown model. Program bug!\n";
1557bool MediumSilicon::LoadOpticalData(
const std::string& filename) {
1559 m_opticalDataEnergies.clear();
1560 m_opticalDataEpsilon.clear();
1563 char* pPath = getenv(
"GARFIELD_HOME");
1565 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
1566 <<
" Environment variable GARFIELD_HOME is not set.\n";
1569 const std::string filepath = std::string(pPath) +
"/Data/" + filename;
1572 std::ifstream infile(filepath);
1575 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
1576 <<
" Error opening file " << filename <<
".\n";
1580 double lastEnergy = -1.;
1581 double energy, eps1, eps2, loss;
1584 std::istringstream dataStream;
1586 while (!infile.eof()) {
1589 std::getline(infile, line);
1592 if (line.empty())
continue;
1594 if (line[0] ==
'#' || line[0] ==
'*' || (line[0] ==
'/' && line[1] ==
'/'))
1597 dataStream.str(line);
1598 dataStream >> energy >> eps1 >> eps2 >> loss;
1599 if (dataStream.eof())
break;
1601 if (infile.fail()) {
1602 std::cerr <<
m_className <<
"::LoadOpticalData:\n Error reading file "
1603 << filename <<
" (line " << i <<
").\n";
1612 if (energy <= lastEnergy) {
1613 std::cerr <<
m_className <<
"::LoadOpticalData:\n Table is not in "
1614 <<
"monotonically increasing order (line " << i <<
").\n"
1615 <<
" " << lastEnergy <<
" " << energy <<
" " << eps1
1616 <<
" " << eps2 <<
"\n";
1621 std::cerr <<
m_className <<
"::LoadOpticalData:\n Negative value "
1622 <<
"of the loss function (line " << i <<
").\n";
1626 if (energy <= 0.)
continue;
1628 m_opticalDataEnergies.emplace_back(energy);
1629 m_opticalDataEpsilon.emplace_back(std::make_pair(eps1, eps2));
1630 lastEnergy = energy;
1633 if (m_opticalDataEnergies.empty()) {
1634 std::cerr <<
m_className <<
"::LoadOpticalData:\n"
1635 <<
" Import of data from file " << filepath <<
"failed.\n"
1636 <<
" No valid data found.\n";
1641 std::cout <<
m_className <<
"::LoadOpticalData:\n Read "
1642 << m_opticalDataEnergies.size() <<
" values from file "
1643 << filepath <<
"\n";
1648bool MediumSilicon::ElectronScatteringRates() {
1650 m_cfTotElectronsX.assign(nEnergyStepsXL, 0.);
1651 m_cfTotElectronsL.assign(nEnergyStepsXL, 0.);
1652 m_cfTotElectronsG.assign(nEnergyStepsG, 0.);
1653 m_cfElectronsX.assign(nEnergyStepsXL, std::vector<double>());
1654 m_cfElectronsL.assign(nEnergyStepsXL, std::vector<double>());
1655 m_cfElectronsG.assign(nEnergyStepsG, std::vector<double>());
1656 m_energyLossElectronsX.clear();
1657 m_energyLossElectronsL.clear();
1658 m_energyLossElectronsG.clear();
1659 m_scatTypeElectronsX.clear();
1660 m_scatTypeElectronsL.clear();
1661 m_scatTypeElectronsG.clear();
1662 m_cfNullElectronsX = 0.;
1663 m_cfNullElectronsL = 0.;
1664 m_cfNullElectronsG = 0.;
1670 ElectronAcousticScatteringRates();
1671 ElectronOpticalScatteringRates();
1672 ElectronImpurityScatteringRates();
1673 ElectronIntervalleyScatteringRatesXX();
1674 ElectronIntervalleyScatteringRatesXL();
1675 ElectronIntervalleyScatteringRatesLL();
1676 ElectronIntervalleyScatteringRatesXGLG();
1677 ElectronIonisationRatesXL();
1678 ElectronIonisationRatesG();
1681 std::cout <<
m_className <<
"::ElectronScatteringRates:\n"
1682 <<
" " << m_nLevelsX <<
" X-valley scattering terms\n"
1683 <<
" " << m_nLevelsL <<
" L-valley scattering terms\n"
1684 <<
" " << m_nLevelsG <<
" higher band scattering terms\n";
1687 std::ofstream outfileX;
1688 std::ofstream outfileL;
1690 outfileX.open(
"ratesX.txt", std::ios::out);
1691 outfileL.open(
"ratesL.txt", std::ios::out);
1694 m_ieMinL = int(m_eMinL / m_eStepXL) + 1;
1695 for (
int i = 0; i < nEnergyStepsXL; ++i) {
1697 for (
int j = m_nLevelsX; j--;) m_cfTotElectronsX[i] += m_cfElectronsX[i][j];
1698 for (
int j = m_nLevelsL; j--;) m_cfTotElectronsL[i] += m_cfElectronsL[i][j];
1701 outfileX << i * m_eStepXL <<
" " << m_cfTotElectronsX[i] <<
" ";
1702 for (
int j = 0; j < m_nLevelsX; ++j) {
1703 outfileX << m_cfElectronsX[i][j] <<
" ";
1706 outfileL << i * m_eStepXL <<
" " << m_cfTotElectronsL[i] <<
" ";
1707 for (
int j = 0; j < m_nLevelsL; ++j) {
1708 outfileL << m_cfElectronsL[i][j] <<
" ";
1713 if (m_cfTotElectronsX[i] > m_cfNullElectronsX) {
1714 m_cfNullElectronsX = m_cfTotElectronsX[i];
1716 if (m_cfTotElectronsL[i] > m_cfNullElectronsL) {
1717 m_cfNullElectronsL = m_cfTotElectronsL[i];
1721 if (m_cfTotElectronsX[i] <= 0.) {
1722 std::cerr <<
m_className <<
"::ElectronScatteringRates:\n X-valley "
1723 <<
"scattering rate at " << i * m_eStepXL <<
" eV <= 0.\n";
1727 for (
int j = 0; j < m_nLevelsX; ++j) {
1728 m_cfElectronsX[i][j] /= m_cfTotElectronsX[i];
1729 if (j > 0) m_cfElectronsX[i][j] += m_cfElectronsX[i][j - 1];
1733 if (m_cfTotElectronsL[i] <= 0.) {
1734 if (i < m_ieMinL)
continue;
1735 std::cerr <<
m_className <<
"::ElectronScatteringRates:\n L-valley "
1736 <<
"scattering rate at " << i * m_eStepXL <<
" eV <= 0.\n";
1740 for (
int j = 0; j < m_nLevelsL; ++j) {
1741 m_cfElectronsL[i][j] /= m_cfTotElectronsL[i];
1742 if (j > 0) m_cfElectronsL[i][j] += m_cfElectronsL[i][j - 1];
1751 std::ofstream outfileG;
1753 outfileG.open(
"ratesG.txt", std::ios::out);
1755 m_ieMinG = int(m_eMinG / m_eStepG) + 1;
1756 for (
int i = 0; i < nEnergyStepsG; ++i) {
1758 for (
int j = m_nLevelsG; j--;) m_cfTotElectronsG[i] += m_cfElectronsG[i][j];
1761 outfileG << i * m_eStepG <<
" " << m_cfTotElectronsG[i] <<
" ";
1762 for (
int j = 0; j < m_nLevelsG; ++j) {
1763 outfileG << m_cfElectronsG[i][j] <<
" ";
1768 if (m_cfTotElectronsG[i] > m_cfNullElectronsG) {
1769 m_cfNullElectronsG = m_cfTotElectronsG[i];
1773 if (m_cfTotElectronsG[i] <= 0.) {
1774 if (i < m_ieMinG)
continue;
1775 std::cerr <<
m_className <<
"::ElectronScatteringRates:\n Higher "
1776 <<
"band scattering rate at " << i * m_eStepG <<
" eV <= 0.\n";
1779 for (
int j = 0; j < m_nLevelsG; ++j) {
1780 m_cfElectronsG[i][j] /= m_cfTotElectronsG[i];
1781 if (j > 0) m_cfElectronsG[i][j] += m_cfElectronsG[i][j - 1];
1792bool MediumSilicon::ElectronAcousticScatteringRates() {
1798 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
1804 constexpr double defpot2 = 9. * 9.;
1806 constexpr double u = 9.04e-4;
1808 const double cIntra = TwoPi * SpeedOfLight * SpeedOfLight * kbt * defpot2 /
1809 (Hbar * u * u * rho);
1813 for (
int i = 0; i < nEnergyStepsXL; ++i) {
1817 m_cfElectronsX[i].push_back(cIntra * dosX);
1818 m_cfElectronsL[i].push_back(cIntra * dosL);
1823 for (
int i = 0; i < nEnergyStepsG; ++i) {
1826 m_cfElectronsG[i].push_back(cIntra * dosG);
1831 m_energyLossElectronsX.push_back(0.);
1832 m_energyLossElectronsL.push_back(0.);
1833 m_energyLossElectronsG.push_back(0.);
1834 m_scatTypeElectronsX.push_back(ElectronCollisionTypeAcousticPhonon);
1835 m_scatTypeElectronsL.push_back(ElectronCollisionTypeAcousticPhonon);
1836 m_scatTypeElectronsG.push_back(ElectronCollisionTypeAcousticPhonon);
1844bool MediumSilicon::ElectronOpticalScatteringRates() {
1855 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
1860 constexpr double dtk = 2.2e8;
1862 constexpr double eph = 63.0e-3;
1864 const double nocc = 1. / (
exp(eph / kbt) - 1);
1866 const double c0 = HbarC * SpeedOfLight * Pi / rho;
1867 double c = c0 * dtk * dtk / eph;
1893 for (
int i = 0; i < nEnergyStepsG; ++i) {
1898 m_cfElectronsG[i].push_back(c * nocc * dos);
1900 m_cfElectronsG[i].push_back(0.);
1903 if (en > m_eMinG + eph) {
1906 m_cfElectronsG[i].push_back(c * (nocc + 1) * dos);
1908 m_cfElectronsG[i].push_back(0.);
1915 m_energyLossElectronsG.push_back(-eph);
1918 m_energyLossElectronsG.push_back(eph);
1921 m_scatTypeElectronsG.push_back(ElectronCollisionTypeOpticalPhonon);
1922 m_scatTypeElectronsG.push_back(ElectronCollisionTypeOpticalPhonon);
1930bool MediumSilicon::ElectronIntervalleyScatteringRatesXX() {
1936 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
1940 constexpr unsigned int nPhonons = 6;
1946 constexpr double dtk[nPhonons] = {0.5e8, 0.8e8, 1.1e9, 0.3e8, 2.0e8, 2.0e8};
1948 constexpr double eph[nPhonons] = {12.06e-3, 18.53e-3, 62.04e-3,
1949 18.86e-3, 47.39e-3, 59.03e-3};
1951 double nocc[nPhonons];
1953 const double c0 = HbarC * SpeedOfLight * Pi / rho;
1956 for (
unsigned int j = 0; j < nPhonons; ++j) {
1957 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
1958 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
1959 if (j > 2) c[j] *= 4;
1963 for (
int i = 0; i < nEnergyStepsXL; ++i) {
1964 for (
unsigned int j = 0; j < nPhonons; ++j) {
1967 m_cfElectronsX[i].push_back(c[j] * nocc[j] * dos);
1971 m_cfElectronsX[i].push_back(c[j] * (nocc[j] + 1) * dos);
1973 m_cfElectronsX[i].push_back(0.);
1979 for (
unsigned int j = 0; j < nPhonons; ++j) {
1981 m_energyLossElectronsX.push_back(-eph[j]);
1983 m_energyLossElectronsX.push_back(eph[j]);
1985 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyG);
1986 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyG);
1988 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyF);
1989 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIntervalleyF);
1993 m_nLevelsX += 2 * nPhonons;
1998bool MediumSilicon::ElectronIntervalleyScatteringRatesXL() {
2005 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2009 constexpr unsigned int nPhonons = 4;
2012 constexpr double dtk[nPhonons] = {2.e8, 2.e8, 2.e8, 2.e8};
2014 constexpr double eph[nPhonons] = {58.e-3, 55.e-3, 41.e-3, 17.e-3};
2016 constexpr unsigned int zX = 6;
2017 constexpr unsigned int zL = 8;
2020 double nocc[nPhonons] = {0.};
2022 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2025 for (
unsigned int j = 0; j < nPhonons; ++j) {
2026 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2027 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2031 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2032 for (
unsigned int j = 0; j < nPhonons; ++j) {
2035 if (en + eph[j] > m_eMinL) {
2037 m_cfElectronsX[i].push_back(zL * c[j] * nocc[j] * dos);
2039 m_cfElectronsX[i].push_back(0.);
2042 if (en - eph[j] > m_eMinL) {
2044 m_cfElectronsX[i].push_back(zL * c[j] * (nocc[j] + 1) * dos);
2046 m_cfElectronsX[i].push_back(0.);
2052 m_cfElectronsL[i].push_back(zX * c[j] * nocc[j] * dos);
2055 m_cfElectronsL[i].push_back(zX * c[j] * (nocc[j] + 1) * dos);
2057 m_cfElectronsL[i].push_back(0.);
2058 m_cfElectronsL[i].push_back(0.);
2064 for (
unsigned int j = 0; j < nPhonons; ++j) {
2066 m_energyLossElectronsX.push_back(-eph[j]);
2067 m_energyLossElectronsL.push_back(-eph[j]);
2069 m_energyLossElectronsX.push_back(eph[j]);
2070 m_energyLossElectronsL.push_back(eph[j]);
2071 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXL);
2072 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXL);
2073 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandXL);
2074 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandXL);
2077 m_nLevelsX += 2 * nPhonons;
2078 m_nLevelsL += 2 * nPhonons;
2083bool MediumSilicon::ElectronIntervalleyScatteringRatesLL() {
2092 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2096 const int nPhonons = 1;
2098 const double dtk[nPhonons] = {2.63e8};
2100 const double eph[nPhonons] = {38.87e-3};
2102 double nocc[nPhonons];
2104 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2107 for (
int j = 0; j < nPhonons; ++j) {
2108 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2109 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2115 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2116 for (
int j = 0; j < nPhonons; ++j) {
2119 m_cfElectronsL[i].push_back(c[j] * nocc[j] * dos);
2121 if (en > m_eMinL + eph[j]) {
2123 m_cfElectronsL[i].push_back(c[j] * (nocc[j] + 1) * dos);
2125 m_cfElectronsL[i].push_back(0.);
2131 for (
int j = 0; j < nPhonons; ++j) {
2133 m_energyLossElectronsL.push_back(-eph[j]);
2135 m_energyLossElectronsL.push_back(eph[j]);
2136 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIntervalleyF);
2137 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIntervalleyF);
2140 m_nLevelsL += 2 * nPhonons;
2145bool MediumSilicon::ElectronIntervalleyScatteringRatesXGLG() {
2152 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2156 const int nPhonons = 1;
2160 const double dtk[nPhonons] = {2.43e8};
2162 const double eph[nPhonons] = {37.65e-3};
2169 double nocc[nPhonons] = {0.};
2171 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2174 for (
int j = 0; j < nPhonons; ++j) {
2175 nocc[j] = 1. / (
exp(eph[j] / kbt) - 1);
2176 c[j] = c0 * dtk[j] * dtk[j] / eph[j];
2182 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2183 for (
int j = 0; j < nPhonons; ++j) {
2185 if (en + eph[j] > m_eMinG) {
2187 m_nValleysX + m_nValleysL);
2188 m_cfElectronsX[i].push_back(zG * c[j] * nocc[j] * dos);
2189 m_cfElectronsL[i].push_back(zG * c[j] * nocc[j] * dos);
2191 m_cfElectronsX[i].push_back(0.);
2192 m_cfElectronsL[i].push_back(0.);
2195 if (en - eph[j] > m_eMinG) {
2197 m_nValleysX + m_nValleysL);
2198 m_cfElectronsX[i].push_back(zG * c[j] * (nocc[j] + 1) * dos);
2199 m_cfElectronsL[i].push_back(zG * c[j] * (nocc[j] + 1) * dos);
2201 m_cfElectronsX[i].push_back(0.);
2202 m_cfElectronsL[i].push_back(0.);
2210 double dosX = 0., dosL = 0.;
2211 for (
int i = 0; i < nEnergyStepsG; ++i) {
2212 for (
int j = 0; j < nPhonons; ++j) {
2216 m_cfElectronsG[i].push_back(zX * c[j] * nocc[j] * dosX);
2218 m_cfElectronsG[i].push_back(zL * c[j] * nocc[j] * dosL);
2220 m_cfElectronsG[i].push_back(0.);
2226 m_cfElectronsG[i].push_back(zX * c[j] * (nocc[j] + 1) * dosX);
2228 m_cfElectronsG[i].push_back(0.);
2230 if (en - eph[j] > m_eMinL) {
2231 m_cfElectronsG[i].push_back(zL * c[j] * (nocc[j] + 1) * dosL);
2233 m_cfElectronsG[i].push_back(0.);
2239 for (
int j = 0; j < nPhonons; ++j) {
2241 m_energyLossElectronsX.push_back(-eph[j]);
2242 m_energyLossElectronsL.push_back(-eph[j]);
2244 m_energyLossElectronsX.push_back(eph[j]);
2245 m_energyLossElectronsL.push_back(eph[j]);
2247 m_energyLossElectronsG.push_back(-eph[j]);
2248 m_energyLossElectronsG.push_back(-eph[j]);
2250 m_energyLossElectronsG.push_back(eph[j]);
2251 m_energyLossElectronsG.push_back(eph[j]);
2253 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXG);
2254 m_scatTypeElectronsX.push_back(ElectronCollisionTypeInterbandXG);
2255 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandLG);
2256 m_scatTypeElectronsL.push_back(ElectronCollisionTypeInterbandLG);
2258 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandXG);
2259 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandLG);
2260 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandXG);
2261 m_scatTypeElectronsG.push_back(ElectronCollisionTypeInterbandLG);
2264 m_nLevelsX += 2 * nPhonons;
2265 m_nLevelsL += 2 * nPhonons;
2266 m_nLevelsG += 4 * nPhonons;
2271bool MediumSilicon::ElectronIonisationRatesXL() {
2278 constexpr double p[3] = {6.25e1, 3.e3, 6.8e5};
2280 constexpr double eth[3] = {1.2, 1.8, 3.45};
2283 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2286 fIon += p[0] * (en - eth[0]) * (en - eth[0]);
2289 fIon += p[1] * (en - eth[1]) * (en - eth[1]);
2292 fIon += p[2] * (en - eth[2]) * (en - eth[2]);
2294 m_cfElectronsX[i].push_back(fIon);
2295 m_cfElectronsL[i].push_back(fIon);
2299 m_energyLossElectronsX.push_back(eth[0]);
2300 m_energyLossElectronsL.push_back(eth[0]);
2301 m_scatTypeElectronsX.push_back(ElectronCollisionTypeIonisation);
2302 m_scatTypeElectronsL.push_back(ElectronCollisionTypeIonisation);
2309bool MediumSilicon::ElectronIonisationRatesG() {
2317 constexpr double p[3] = {6.25e1, 3.e3, 6.8e5};
2319 constexpr double eth[3] = {1.2, 1.8, 3.45};
2322 for (
int i = 0; i < nEnergyStepsG; ++i) {
2325 fIon += p[0] * (en - eth[0]) * (en - eth[0]);
2328 fIon += p[1] * (en - eth[1]) * (en - eth[1]);
2331 fIon += p[2] * (en - eth[2]) * (en - eth[2]);
2333 if (en >= m_eMinG) {
2334 m_cfElectronsG[i].push_back(fIon);
2336 m_cfElectronsG[i].push_back(0.);
2341 m_energyLossElectronsG.push_back(eth[0]);
2342 m_scatTypeElectronsG.push_back(ElectronCollisionTypeIonisation);
2348bool MediumSilicon::ElectronImpurityScatteringRates() {
2355 ElectronMass *
pow(m_mLongX * m_mTransX * m_mTransX, 1. / 3.);
2357 ElectronMass *
pow(m_mLongL * m_mTransL * m_mTransL, 1. / 3.);
2362 const double impurityConcentration = m_dopingConcentration;
2363 if (impurityConcentration < Small)
return true;
2366 const double ls =
sqrt(eps * kbt / (4 * Pi * FineStructureConstant * HbarC *
2367 impurityConcentration));
2368 const double ebX = 0.5 * HbarC * HbarC / (mdX * ls * ls);
2369 const double ebL = 0.5 * HbarC * HbarC / (mdL * ls * ls);
2376 const double cX = impurityConcentration * Pi *
2377 pow(FineStructureConstant * HbarC, 2) * SpeedOfLight /
2378 (
sqrt(2 * mdX) * eps * eps);
2379 const double cL = impurityConcentration * Pi *
2380 pow(FineStructureConstant * HbarC, 2) * SpeedOfLight /
2381 (
sqrt(2 * mdL) * eps * eps);
2384 for (
int i = 0; i < nEnergyStepsXL; ++i) {
2385 const double gammaX = en * (1. + m_alphaX * en);
2386 const double gammaL = (en - m_eMinL) * (1. + m_alphaL * (en - m_eMinL));
2390 m_cfElectronsX[i].push_back(0.);
2392 const double b = 4 * gammaX / ebX;
2393 m_cfElectronsX[i].push_back((cX /
pow(gammaX, 1.5)) *
2394 (log(1. + b) - b / (1. + b)));
2396 if (en <= m_eMinL || gammaL <= 0.) {
2397 m_cfElectronsL[i].push_back(0.);
2399 const double b = 4 * gammaL / ebL;
2400 m_cfElectronsL[i].push_back((cL /
pow(gammaL, 1.5)) *
2401 (log(1. + b) - b / (1. + b)));
2406 m_energyLossElectronsX.push_back(0.);
2407 m_energyLossElectronsL.push_back(0.);
2408 m_scatTypeElectronsX.push_back(ElectronCollisionTypeImpurity);
2409 m_scatTypeElectronsL.push_back(ElectronCollisionTypeImpurity);
2416bool MediumSilicon::HoleScatteringRates() {
2418 m_cfTotHoles.assign(nEnergyStepsV, 0.);
2419 m_cfHoles.assign(nEnergyStepsV, std::vector<double>());
2420 m_energyLossHoles.clear();
2421 m_scatTypeHoles.clear();
2426 HoleAcousticScatteringRates();
2427 HoleOpticalScatteringRates();
2429 HoleIonisationRates();
2431 std::ofstream outfile;
2433 outfile.open(
"ratesV.txt", std::ios::out);
2436 for (
int i = 0; i < nEnergyStepsV; ++i) {
2438 for (
int j = m_nLevelsV; j--;) m_cfTotHoles[i] += m_cfHoles[i][j];
2441 outfile << i * m_eStepV <<
" " << m_cfTotHoles[i] <<
" ";
2442 for (
int j = 0; j < m_nLevelsV; ++j) {
2443 outfile << m_cfHoles[i][j] <<
" ";
2448 if (m_cfTotHoles[i] > m_cfNullHoles) {
2449 m_cfNullHoles = m_cfTotHoles[i];
2453 if (m_cfTotHoles[i] <= 0.) {
2454 std::cerr <<
m_className <<
"::HoleScatteringRates:\n"
2455 <<
" Scattering rate at " << i * m_eStepV <<
" eV <= 0.\n";
2459 for (
int j = 0; j < m_nLevelsV; ++j) {
2460 m_cfHoles[i][j] /= m_cfTotHoles[i];
2461 if (j > 0) m_cfHoles[i][j] += m_cfHoles[i][j - 1];
2472bool MediumSilicon::HoleAcousticScatteringRates() {
2480 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2487 constexpr double defpot2 = 4.6 * 4.6;
2489 constexpr double u = 9.04e-4;
2491 const double cIntra = TwoPi * SpeedOfLight * SpeedOfLight * kbt * defpot2 /
2492 (Hbar * u * u * rho);
2496 for (
int i = 0; i < nEnergyStepsV; ++i) {
2498 m_cfHoles[i].push_back(cIntra * dos);
2503 m_energyLossHoles.push_back(0.);
2504 m_scatTypeHoles.push_back(ElectronCollisionTypeAcousticPhonon);
2510bool MediumSilicon::HoleOpticalScatteringRates() {
2518 const double rho =
m_density *
m_a * AtomicMassUnitElectronVolt;
2524 constexpr double dtk = 6.6e8;
2526 constexpr double eph = 63.0e-3;
2528 const double nocc = 1. / (
exp(eph / kbt) - 1);
2530 const double c0 = HbarC * SpeedOfLight * Pi / rho;
2531 double c = c0 * dtk * dtk / eph;
2534 for (
int i = 0; i < nEnergyStepsV; ++i) {
2537 m_cfHoles[i].push_back(c * nocc * dos);
2541 m_cfHoles[i].push_back(c * (nocc + 1) * dos);
2543 m_cfHoles[i].push_back(0.);
2549 m_energyLossHoles.push_back(-eph);
2551 m_energyLossHoles.push_back(eph);
2552 m_scatTypeHoles.push_back(ElectronCollisionTypeOpticalPhonon);
2553 m_scatTypeHoles.push_back(ElectronCollisionTypeOpticalPhonon);
2560bool MediumSilicon::HoleIonisationRates() {
2565 constexpr double p[2] = {2., 1.e3};
2567 constexpr double eth[2] = {1.1, 1.45};
2569 constexpr double b[2] = {6., 4.};
2572 for (
int i = 0; i < nEnergyStepsV; ++i) {
2575 fIon += p[0] *
pow(en - eth[0], b[0]);
2578 fIon += p[1] *
pow(en - eth[1], b[1]);
2580 m_cfHoles[i].push_back(fIon);
2584 m_energyLossHoles.push_back(eth[0]);
2585 m_scatTypeHoles.push_back(ElectronCollisionTypeIonisation);
2594 int iE = int(e / m_eStepDos);
2595 const int nPoints = m_fbDosConduction.size();
2596 if (iE >= nPoints || iE < 0) {
2598 }
else if (iE == nPoints - 1) {
2599 return m_fbDosConduction[nPoints - 1];
2602 const double dos = m_fbDosConduction[iE] +
2603 (m_fbDosConduction[iE + 1] - m_fbDosConduction[iE]) *
2604 (e / m_eStepDos - iE);
2607 }
else if (band < m_nValleysX) {
2609 if (e <= 0.)
return 0.;
2611 const double md3 = pow(ElectronMass, 3) * m_mLongX * m_mTransX * m_mTransX;
2613 if (m_fullBandDos) {
2616 }
else if (e < m_eMinG) {
2622 return dosX / m_nValleysX;
2630 if (dosX <= 0.)
return 0.;
2631 return dosX / m_nValleysX;
2633 }
else if (m_nonParabolic) {
2634 const double alpha = m_alphaX;
2635 return sqrt(md3 * e * (1. + alpha * e) / 2.) * (1. + 2 * alpha * e) /
2636 (Pi2 * pow(HbarC, 3.));
2638 return sqrt(md3 * e / 2.) / (Pi2 * pow(HbarC, 3.));
2640 }
else if (band < m_nValleysX + m_nValleysL) {
2642 if (e <= m_eMinL)
return 0.;
2645 const double md3 = pow(ElectronMass, 3) * m_mLongL * m_mTransL * m_mTransL;
2647 const double alpha = m_alphaL;
2649 if (m_fullBandDos) {
2651 const double ej = m_eMinL + 0.5;
2653 return sqrt(md3 * (e - m_eMinL) * (1. + alpha * (e - m_eMinL))) *
2654 (1. + 2 * alpha * (e - m_eMinL)) /
2655 (Sqrt2 * Pi2 * pow(HbarC, 3.));
2658 double fL = sqrt(md3 * (ej - m_eMinL) * (1. + alpha * (ej - m_eMinL))) *
2659 (1. + 2 * alpha * (ej - m_eMinL)) /
2660 (Sqrt2 * Pi2 * pow(HbarC, 3.));
2668 if (dosXL <= 0.)
return 0.;
2669 return fL * dosXL / 8.;
2671 }
else if (m_nonParabolic) {
2672 return sqrt(md3 * (e - m_eMinL) * (1. + alpha * (e - m_eMinL))) *
2673 (1. + 2 * alpha * (e - m_eMinL)) / (Sqrt2 * Pi2 * pow(HbarC, 3.));
2675 return sqrt(md3 * (e - m_eMinL) / 2.) / (Pi2 * pow(HbarC, 3.));
2677 }
else if (band == m_nValleysX + m_nValleysL) {
2679 const double ej = 2.7;
2680 if (m_eMinG >= ej) {
2681 std::cerr <<
m_className <<
"::GetConductionBandDensityOfStates:\n"
2682 <<
" Cannot determine higher band density-of-states.\n"
2683 <<
" Program bug. Check offset energy!\n";
2688 }
else if (e < ej) {
2692 return dj * (e - m_eMinG) / (ej - m_eMinG);
2698 std::cerr <<
m_className <<
"::GetConductionBandDensityOfStates:\n"
2699 <<
" Band index (" << band <<
") out of range.\n";
2700 return ElectronMass * sqrt(ElectronMass * e / 2.) / (Pi2 * pow(HbarC, 3.));
2707 const int nPoints = m_fbDosValence.size();
2708 int iE = int(e / m_eStepDos);
2709 if (iE >= nPoints || iE < 0) {
2711 }
else if (iE == nPoints - 1) {
2712 return m_fbDosValence[nPoints - 1];
2716 m_fbDosValence[iE] +
2717 (m_fbDosValence[iE + 1] - m_fbDosValence[iE]) * (e / m_eStepDos - iE);
2721 std::cerr <<
m_className <<
"::GetConductionBandDensityOfStates:\n"
2722 <<
" Band index (" << band <<
") out of range.\n";
2728 const int nPointsValence = m_fbDosValence.size();
2729 const int nPointsConduction = m_fbDosConduction.size();
2730 const double widthValenceBand = m_eStepDos * nPointsValence;
2731 const double widthConductionBand = m_eStepDos * nPointsConduction;
2737 int ih = std::min(
int(eh / m_eStepDos), nPointsValence - 1);
2738 while (
RndmUniform() > m_fbDosValence[ih] / m_fbDosMaxV) {
2740 ih = std::min(
int(eh / m_eStepDos), nPointsValence - 1);
2744 int ie = std::min(
int(ee / m_eStepDos), nPointsConduction - 1);
2745 while (
RndmUniform() > m_fbDosConduction[ie] / m_fbDosMaxC) {
2747 ie = std::min(
int(ee / m_eStepDos), nPointsConduction - 1);
2750 const double ep = e0 - m_bandGap - eh - ee;
2751 if (ep < Small)
continue;
2752 if (ep > 5.)
return;
2754 int ip = std::min(
int(ep / m_eStepDos), nPointsConduction - 1);
2755 if (
RndmUniform() > m_fbDosConduction[ip] / m_fbDosMaxC)
continue;
2760void MediumSilicon::InitialiseDensityOfStates() {
2764 {0., 1.28083, 2.08928, 2.70763, 3.28095, 3.89162, 4.50547, 5.15043,
2765 5.89314, 6.72667, 7.67768, 8.82725, 10.6468, 12.7003, 13.7457, 14.0263,
2766 14.2731, 14.5527, 14.8808, 15.1487, 15.4486, 15.7675, 16.0519, 16.4259,
2767 16.7538, 17.0589, 17.3639, 17.6664, 18.0376, 18.4174, 18.2334, 16.7552,
2768 15.1757, 14.2853, 13.6516, 13.2525, 12.9036, 12.7203, 12.6104, 12.6881,
2769 13.2862, 14.0222, 14.9366, 13.5084, 9.77808, 6.15266, 3.47839, 2.60183,
2770 2.76747, 3.13985, 3.22524, 3.29119, 3.40868, 3.6118, 3.8464, 4.05776,
2771 4.3046, 4.56219, 4.81553, 5.09909, 5.37616, 5.67297, 6.04611, 6.47252,
2772 6.9256, 7.51254, 8.17923, 8.92351, 10.0309, 11.726, 16.2853, 18.2457,
2773 12.8879, 7.86019, 6.02275, 5.21777, 4.79054, 3.976, 3.11855, 2.46854,
2774 1.65381, 0.830278, 0.217735}};
2776 m_fbDosConduction = {
2777 {0., 1.5114, 2.71026, 3.67114, 4.40173, 5.05025, 5.6849, 6.28358,
2778 6.84628, 7.43859, 8.00204, 8.80658, 9.84885, 10.9579, 12.0302, 13.2051,
2779 14.6948, 16.9879, 18.4492, 18.1933, 17.6747, 16.8135, 15.736, 14.4965,
2780 13.1193, 12.1817, 12.6109, 15.3148, 19.4936, 23.0093, 24.4106, 22.2834,
2781 19.521, 18.9894, 18.8015, 17.9363, 17.0252, 15.9871, 14.8486, 14.3797,
2782 14.2426, 14.3571, 14.7271, 14.681, 14.3827, 14.2789, 14.144, 14.1684,
2783 14.1418, 13.9237, 13.7558, 13.5691, 13.4567, 13.2693, 12.844, 12.4006,
2784 12.045, 11.7729, 11.3607, 11.14, 11.0586, 10.5475, 9.73786, 9.34423,
2785 9.4694, 9.58071, 9.6967, 9.84854, 10.0204, 9.82705, 9.09102, 8.30665,
2786 7.67306, 7.18925, 6.79675, 6.40713, 6.21687, 6.33267, 6.5223, 6.17877,
2787 5.48659, 4.92208, 4.44239, 4.02941, 3.5692, 3.05953, 2.6428, 2.36979,
2788 2.16273, 2.00627, 1.85206, 1.71265, 1.59497, 1.46681, 1.34913, 1.23951,
2789 1.13439, 1.03789, 0.924155, 0.834962, 0.751017}};
2791 auto it = std::max_element(m_fbDosValence.begin(), m_fbDosValence.end());
2793 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 SetImpactIonisationModelOkutoCrowell()
Calculate α using the Okuto-Crowell model.
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)
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 HoleMobility() override
Low-field mobility [cm2 V-1 ns-1].
double GetConductionBandDensityOfStates(const double e, const int band=0)
bool ElectronCollision(const double e, int &type, int &level, double &e1, double &dx, double &dy, double &dz, std::vector< std::pair< Particle, double > > &secondaries, int &ndxc, int &band) override
Sample the collision type. Update energy and direction vector.
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)
double ElectronMobility() override
Low-field mobility [cm2 V-1 ns-1].
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
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
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 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].
static void Langevin(const double ex, const double ey, const double ez, double bx, double by, double bz, const double mu, double &vx, double &vy, double &vz)
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)