00001
00002
00003
00004
00005
00006
00007 #include "Teuchos_TestForException.hpp"
00008 #include "Phalanx_DataLayout.hpp"
00009 #include "Sacado_ParameterRegistration.hpp"
00010 #include "Albany_AbstractDiscretization.hpp"
00011
00012
00013 namespace QCAD {
00014
00015 template<typename EvalT,typename Traits>
00016 PoissonDirichlet<EvalT, Traits>::
00017 PoissonDirichlet(Teuchos::ParameterList& p) :
00018 PHAL::Dirichlet<EvalT,Traits>(p)
00019 {
00020
00021 user_value = p.get<RealType>("Dirichlet Value");
00022 materialDB = p.get< Teuchos::RCP<QCAD::MaterialDatabase> >("MaterialDB");
00023 energy_unit_in_eV = p.get<double>("Energy unit in eV");
00024
00025 Teuchos::ParameterList* psList = p.get<Teuchos::ParameterList*>("Poisson Source Parameter List");
00026
00027 carrierStatistics = psList->get("Carrier Statistics", "Boltzmann Statistics");
00028 incompIonization = psList->get("Incomplete Ionization", "False");
00029
00030
00031
00032
00033
00034 temperature = p.get<double>("Temperature");
00035
00036
00037 std::string nodeSetName = PHAL::DirichletBase<EvalT,Traits>::nodeSetID;
00038 material = materialDB->getNodeSetParam<std::string>(nodeSetName,"material","");
00039 if (material.length() == 0) {
00040 ebName = materialDB->getNodeSetParam<std::string>(nodeSetName,"elementBlock","");
00041 if (ebName.length() > 0)
00042 material = materialDB->getElementBlockParam<std::string>(ebName,"material","");
00043 }
00044
00045
00046 const double kbBoltz = 8.617343e-05;
00047 kbT = kbBoltz*temperature;
00048 V0 = kbBoltz*temperature/1.0;
00049
00050
00051 if ( (material.length() > 0) || (ebName.length() > 0) )
00052 {
00053 std::string refMtrlName, category;
00054 refMtrlName = materialDB->getParam<std::string>("Reference Material");
00055 category = materialDB->getMaterialParam<std::string>(refMtrlName,"Category");
00056 if (category == "Semiconductor") {
00057 double mdn = materialDB->getMaterialParam<double>(refMtrlName,"Electron DOS Effective Mass");
00058 double mdp = materialDB->getMaterialParam<double>(refMtrlName,"Hole DOS Effective Mass");
00059 double Chi = materialDB->getMaterialParam<double>(refMtrlName,"Electron Affinity");
00060 double Eg0 = materialDB->getMaterialParam<double>(refMtrlName,"Zero Temperature Band Gap");
00061 double alpha = materialDB->getMaterialParam<double>(refMtrlName,"Band Gap Alpha Coefficient");
00062 double beta = materialDB->getMaterialParam<double>(refMtrlName,"Band Gap Beta Coefficient");
00063
00064 ScalarT Eg = Eg0-alpha*pow(temperature,2.0)/(beta+temperature);
00065 ScalarT Eic = -Eg/2. + 3./4.*kbT*log(mdp/mdn);
00066 qPhiRef = Chi - Eic;
00067 }
00068 else if (category == "Insulator") {
00069 double Chi = materialDB->getMaterialParam<double>(refMtrlName,"Electron Affinity");
00070 qPhiRef = Chi;
00071 }
00072 else if (category == "Metal") {
00073 double workFn = materialDB->getMaterialParam<double>(refMtrlName,"Work Function");
00074 qPhiRef = workFn;
00075 }
00076 else {
00077 TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl
00078 << "Error! Invalid category " << category
00079 << " for reference material !" << std::endl);
00080 }
00081 }
00082 }
00083
00084
00085
00086 template<typename EvalT,typename Traits>
00087 void PoissonDirichlet<EvalT, Traits>::
00088 evaluateFields(typename Traits::EvalData dirichletWorkset)
00089 {
00090 ScalarT bcValue = 0.0;
00091
00092
00093 if (material.length() > 0)
00094 {
00095 std::string category = materialDB->getMaterialParam<std::string>(material,"Category");
00096
00098 if (category != "Semiconductor") {
00099 double metalWorkFunc = materialDB->getMaterialParam<double>(material,"Work Function");
00100
00101
00102 ScalarT offsetDueToWorkFunc = (metalWorkFunc-qPhiRef)/1.0;
00103
00104 bcValue = (user_value - offsetDueToWorkFunc) / energy_unit_in_eV;
00105 }
00106
00108 else {
00109
00110
00111 const double kbBoltz = 8.617343e-05;
00112 const double eleQ = 1.602176487e-19;
00113 const double m0 = 9.10938215e-31;
00114 const double hbar = 1.054571628e-34;
00115 const double pi = 3.141592654;
00116
00117
00118 double mdn, mdp, Tref, Eg0, alpha, beta, Chi;
00119 if (ebName.length() > 0) {
00120 mdn = materialDB->getElementBlockParam<double>(ebName,"Electron DOS Effective Mass");
00121 mdp = materialDB->getElementBlockParam<double>(ebName,"Hole DOS Effective Mass");
00122 Tref = materialDB->getElementBlockParam<double>(ebName,"Reference Temperature");
00123
00124 Eg0 = materialDB->getElementBlockParam<double>(ebName,"Zero Temperature Band Gap");
00125 alpha = materialDB->getElementBlockParam<double>(ebName,"Band Gap Alpha Coefficient");
00126 beta = materialDB->getElementBlockParam<double>(ebName,"Band Gap Beta Coefficient");
00127 Chi = materialDB->getElementBlockParam<double>(ebName,"Electron Affinity");
00128 }
00129 else {
00130 mdn = materialDB->getMaterialParam<double>(material,"Electron DOS Effective Mass");
00131 mdp = materialDB->getMaterialParam<double>(material,"Hole DOS Effective Mass");
00132 Tref = materialDB->getMaterialParam<double>(material,"Reference Temperature");
00133
00134 Eg0 = materialDB->getMaterialParam<double>(material,"Zero Temperature Band Gap");
00135 alpha = materialDB->getMaterialParam<double>(material,"Band Gap Alpha Coefficient");
00136 beta = materialDB->getMaterialParam<double>(material,"Band Gap Beta Coefficient");
00137 Chi = materialDB->getMaterialParam<double>(material,"Electron Affinity");
00138 }
00139
00140
00141 double NcvFactor = 2.0*pow((kbBoltz*eleQ*m0*Tref)/(2*pi*pow(hbar,2)),3./2.)*1.e-6;
00142
00143
00144
00145 ScalarT Nc;
00146 ScalarT Nv;
00147 ScalarT Eg;
00148
00149 Nc = NcvFactor*pow(mdn,1.5)*pow(temperature/Tref,1.5);
00150 Nv = NcvFactor*pow(mdp,1.5)*pow(temperature/Tref,1.5);
00151 Eg = Eg0-alpha*pow(temperature,2.0)/(beta+temperature);
00152
00153 ScalarT builtinPotential = 0.0;
00154 std::string dopantType;
00155 if (ebName.length() > 0)
00156 dopantType = materialDB->getElementBlockParam<std::string>(ebName,"Dopant Type","None");
00157 else
00158 dopantType = materialDB->getMaterialParam<std::string>(material,"Dopant Type","None");
00159
00160
00161 if (dopantType == "None")
00162 {
00163
00164 builtinPotential = (qPhiRef-Chi-0.5*Eg)/1.0 + 0.5*kbT*log(Nv/Nc)/1.0;
00165 bcValue = (user_value + builtinPotential) / energy_unit_in_eV;
00166 }
00167
00168 else
00169 {
00170 double dopingConc, dopantActE;
00171 if (ebName.length() > 0) {
00172 dopingConc = materialDB->getElementBlockParam<double>(ebName,"Doping Value");
00173 dopantActE = materialDB->getElementBlockParam<double>(ebName,"Dopant Activation Energy", 0.045);
00174 }
00175 else {
00176 dopingConc = materialDB->getMaterialParam<double>(material,"Doping Value");
00177 dopantActE = materialDB->getMaterialParam<double>(material,"Dopant Activation Energy", 0.045);
00178 }
00179
00180 if ((carrierStatistics=="Boltzmann Statistics") && (incompIonization=="False"))
00181 builtinPotential = potentialForMBComplIon(Nc,Nv,Eg,Chi,dopantType,dopingConc);
00182
00183 else if ((carrierStatistics=="Boltzmann Statistics") && (incompIonization=="True"))
00184 builtinPotential = potentialForMBIncomplIon(Nc,Nv,Eg,Chi,dopantType,dopingConc,dopantActE);
00185
00186 else if ((carrierStatistics=="Fermi-Dirac Statistics") && (incompIonization=="False"))
00187 builtinPotential = potentialForFDComplIon(Nc,Nv,Eg,Chi,dopantType,dopingConc);
00188
00189 else if ((carrierStatistics=="0-K Fermi-Dirac Statistics") && (incompIonization=="False"))
00190 builtinPotential = potentialForZeroKFDComplIon(Nc,Nv,Eg,Chi,dopantType,dopingConc);
00191
00192
00193
00194
00195 else
00196 builtinPotential = potentialForMBIncomplIon(Nc,Nv,Eg,Chi,dopantType,dopingConc,dopantActE);
00197
00198 bcValue = (user_value + builtinPotential) / energy_unit_in_eV;
00199 }
00200 }
00201 }
00202
00204
00205 else
00206 bcValue = user_value / energy_unit_in_eV;
00207
00209 PHAL::DirichletBase<EvalT,Traits>::value = bcValue;
00210
00212 PHAL::Dirichlet<EvalT,Traits>::evaluateFields(dirichletWorkset);
00213
00214
00215
00216
00217 }
00218
00219
00220
00221 template<typename EvalT,typename Traits>
00222 inline typename QCAD::PoissonDirichlet<EvalT,Traits>::ScalarT
00223 QCAD::PoissonDirichlet<EvalT,Traits>::inverseFDIntOneHalf(const ScalarT x)
00224 {
00225
00226
00227
00228
00229 const double pi = 3.1415926536;
00230 const double a = 0.24;
00231 const double b = 1.08;
00232
00233 ScalarT nu = pow(3./4.*sqrt(pi)*x, 2./3.);
00234 ScalarT invFDInt = 0.0;
00235
00236 if (x > 0.)
00237 invFDInt = log(x)/(1.-pow(x,2.)) + nu/(1.+pow(a+b*nu,-2.));
00238 else
00239 TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl
00240 << "Error! x in inverseFDIntOneHalf(x) must be greater than 0 " << std::endl);
00241
00242 return invFDInt;
00243 }
00244
00245
00246
00247 template<typename EvalT,typename Traits>
00248 typename QCAD::PoissonDirichlet<EvalT,Traits>::ScalarT
00249 QCAD::PoissonDirichlet<EvalT,Traits>::potentialForMBComplIon(const ScalarT &Nc,
00250 const ScalarT &Nv, const ScalarT &Eg, const double &Chi, const std::string &dopType, const double &dopingConc)
00251 {
00252 ScalarT Cn = Nc*exp((-qPhiRef+Chi)/kbT);
00253 ScalarT Cp = Nv*exp((qPhiRef-Chi-Eg)/kbT);
00254 ScalarT builtinPotential = 0.0;
00255
00256
00257 if ((Cn > 1.e-5) && (Cp > 1.e-5))
00258 {
00259 double signedDopingConc;
00260 if(dopType == "Donor")
00261 signedDopingConc = dopingConc;
00262 else if(dopType == "Acceptor")
00263 signedDopingConc = -dopingConc;
00264 else
00265 {
00266 TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl
00267 << "Error! Unknown dopant type " << dopType << "!"<< std::endl);
00268 }
00269 ScalarT tmp1 = signedDopingConc/(2.0*Cn);
00270 ScalarT tmp2 = tmp1 + sqrt(pow(tmp1,2.0) + Cp/Cn);
00271 if (tmp2 <= 0.0)
00272 {
00273 if(dopType == "Donor")
00274 builtinPotential = (qPhiRef-Chi)/1.0 + V0*log(dopingConc/Nc);
00275 else if(dopType == "Acceptor")
00276 builtinPotential = (qPhiRef-Chi-Eg)/1.0 - V0*log(dopingConc/Nv);
00277 }
00278 else
00279 builtinPotential = V0*log(tmp2);
00280 }
00281
00282
00283 else
00284 {
00285 if(dopType == "Donor")
00286 builtinPotential = (qPhiRef-Chi)/1.0 + V0*log(dopingConc/Nc);
00287 else if(dopType == "Acceptor")
00288 builtinPotential = (qPhiRef-Chi-Eg)/1.0 - V0*log(dopingConc/Nv);
00289 else
00290 {
00291 TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl
00292 << "Error! Unknown dopant type " << dopType << "!"<< std::endl);
00293 }
00294 }
00295
00296 return builtinPotential;
00297 }
00298
00299
00300
00301 template<typename EvalT,typename Traits>
00302 typename QCAD::PoissonDirichlet<EvalT,Traits>::ScalarT
00303 QCAD::PoissonDirichlet<EvalT,Traits>::potentialForMBIncomplIon(const ScalarT &Nc,
00304 const ScalarT &Nv, const ScalarT &Eg, const double &Chi, const std::string &dopType,
00305 const double &dopingConc, const double &dopantActE )
00306 {
00307
00308 const double MAX_EXPONENT = 100.0;
00309 ScalarT builtinPotential;
00310
00311
00312 if(dopType == "Donor")
00313 {
00314 ScalarT offset = (-dopantActE +qPhiRef -Chi) /1.0;
00315 if (dopantActE/kbT > MAX_EXPONENT)
00316 {
00317 builtinPotential = offset +V0 *(0.5*log(dopingConc/(2.*Nc)) + dopantActE/(2.*kbT) );
00318 }
00319 else
00320 {
00321 ScalarT tmp = -1./4.+1./4.*sqrt(1.+8.*dopingConc/Nc*exp(dopantActE/kbT));
00322 builtinPotential = offset + V0*log(tmp);
00323 }
00324 }
00325
00326
00327 else if(dopType == "Acceptor")
00328 {
00329 ScalarT offset = (dopantActE +qPhiRef -Chi -Eg) /1.0;
00330 if (dopantActE/kbT > MAX_EXPONENT)
00331 {
00332 builtinPotential = offset -V0 *(0.5*log(dopingConc/(4.*Nv)) + dopantActE/(2.*kbT) );
00333 }
00334 else
00335 {
00336 ScalarT tmp = -1./8.+1./8.*sqrt(1.+16.*dopingConc/Nv*exp(dopantActE/kbT));
00337 builtinPotential = offset - V0*log(tmp);
00338 }
00339 }
00340
00341 else
00342 {
00343 TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl
00344 << "Error! Unknown dopant type " << dopType << "!"<< std::endl);
00345 }
00346
00347 return builtinPotential;
00348 }
00349
00350
00351
00352 template<typename EvalT,typename Traits>
00353 typename QCAD::PoissonDirichlet<EvalT,Traits>::ScalarT
00354 QCAD::PoissonDirichlet<EvalT,Traits>::potentialForFDComplIon(const ScalarT &Nc,
00355 const ScalarT &Nv, const ScalarT &Eg, const double &Chi, const std::string &dopType, const double &dopingConc)
00356 {
00357 ScalarT builtinPotential;
00358
00359
00360 if(dopType == "Donor")
00361 {
00362 ScalarT invFDInt = inverseFDIntOneHalf(dopingConc/Nc);
00363 builtinPotential = (qPhiRef-Chi)/1.0 + V0*invFDInt;
00364 }
00365
00366
00367 else if(dopType == "Acceptor")
00368 {
00369 ScalarT invFDInt = inverseFDIntOneHalf(dopingConc/Nv);
00370 builtinPotential = (qPhiRef-Chi-Eg)/1.0 - V0*invFDInt;
00371 }
00372 else {
00373 TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl
00374 << "Error! Unknown dopant type " << dopType << "!"<< std::endl);
00375 }
00376
00377 return builtinPotential;
00378 }
00379
00380
00381
00382 template<typename EvalT,typename Traits>
00383 typename QCAD::PoissonDirichlet<EvalT,Traits>::ScalarT
00384 QCAD::PoissonDirichlet<EvalT,Traits>::potentialForZeroKFDComplIon(const ScalarT &Nc,
00385 const ScalarT &Nv, const ScalarT &Eg, const double &Chi, const std::string &dopType, const double &dopingConc)
00386 {
00387 const double pi = 3.1415926536;
00388
00389 ScalarT builtinPotential;
00390
00391
00392 if(dopType == "Donor")
00393 {
00394 if (dopingConc < Nc)
00395 builtinPotential = potentialForFDComplIon(Nc,Nv,Eg,Chi,dopType,dopingConc);
00396 else
00397 {
00398 ScalarT invFDInt = pow(3./4.*sqrt(pi)*(dopingConc/Nc),2./3.);
00399 builtinPotential = (qPhiRef-Chi)/1.0+ V0*invFDInt;
00400 }
00401 }
00402
00403
00404 else if(dopType == "Acceptor")
00405 {
00406 if (dopingConc < Nv)
00407 builtinPotential = potentialForFDComplIon(Nc,Nv,Eg,Chi,dopType,dopingConc);
00408 else
00409 {
00410 ScalarT invFDInt = pow(3./4.*sqrt(pi)*(dopingConc/Nv),2./3.);
00411 builtinPotential = (qPhiRef-Chi-Eg)/1.0- V0*invFDInt;
00412 }
00413 }
00414
00415 else
00416 {
00417 TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl
00418 << "Error! Unknown dopant type " << dopType << "!"<< std::endl);
00419 }
00420
00421 return builtinPotential;
00422 }
00423
00424 }