00001
00002
00003
00004
00005
00006
00007 #include "Teuchos_TestForException.hpp"
00008 #include "Phalanx_DataLayout.hpp"
00009
00010 #include "Intrepid_FunctionSpaceTools.hpp"
00011
00012
00013
00014 template<typename EvalT, typename Traits>
00015 QCAD::SchrodingerResid<EvalT, Traits>::
00016 SchrodingerResid(const Teuchos::ParameterList& p,
00017 const Teuchos::RCP<Albany::Layouts>& dl) :
00018 wBF (p.get<std::string> ("Weighted BF Name"), dl->node_qp_scalar),
00019 psi (p.get<std::string> ("QP Variable Name"), dl->qp_scalar),
00020 psiDot (p.get<std::string> ("QP Time Derivative Variable Name"), dl->qp_scalar),
00021 wGradBF (p.get<std::string> ("Weighted Gradient BF Name"), dl->node_qp_gradient),
00022 psiGrad (p.get<std::string> ("Gradient QP Variable Name"), dl->qp_gradient),
00023 V (p.get<std::string> ("Potential Name"), dl->qp_scalar),
00024 coordVec (p.get<std::string> ("QP Coordinate Vector Name"), dl->qp_gradient),
00025 havePotential (p.get<bool>("Have Potential")),
00026 psiResidual (p.get<std::string> ("Residual Name"), dl->node_scalar)
00027 {
00028
00029 Teuchos::ParameterList* psList = p.get<Teuchos::ParameterList*>("Parameter List");
00030 potentialType = psList->get<std::string>("Type", "defaultType");
00031 barrEffMass = psList->get<double>("Barrier Effective Mass", 0.0);
00032 barrWidth = psList->get<double>("Barrier Width", 0.0);
00033 wellEffMass = psList->get<double>("Well Effective Mass", 0.0);
00034 wellWidth = psList->get<double>("Well Width", 0.0);
00035
00036
00037 oxideWidth = psList->get<double>("Oxide Width", 0.0);
00038 siliconWidth = psList->get<double>("Silicon Width", 0.0);
00039
00040 enableTransient = true;
00041 energy_unit_in_eV = p.get<double>("Energy unit in eV");
00042 length_unit_in_m = p.get<double>("Length unit in m");
00043 bOnlyInQuantumBlocks = p.get<bool>("Only solve in quantum blocks");
00044
00045
00046 const double hbar = 1.0546e-34;
00047 const double evPerJ = 6.2415e18;
00048 const double emass = 9.1094e-31;
00049 hbar2_over_2m0 = 0.5*pow(hbar,2)*evPerJ /(emass *energy_unit_in_eV *pow(length_unit_in_m,2));
00050
00051
00052 materialDB = p.get< Teuchos::RCP<QCAD::MaterialDatabase> >("MaterialDB");
00053
00054 std::vector<PHX::DataLayout::size_type> dims;
00055 dl->qp_gradient->dimensions(dims);
00056 numQPs = dims[1];
00057 numDims = dims[2];
00058
00059
00060 psiGradWithMass.resize(dims[0], numQPs, numDims);
00061 psiV.resize(dims[0], numQPs);
00062 V_barrier.resize(dims[0], numQPs);
00063
00064 this->addDependentField(wBF);
00065 this->addDependentField(psi);
00066 this->addDependentField(psiDot);
00067 this->addDependentField(psiGrad);
00068 this->addDependentField(wGradBF);
00069 this->addDependentField(coordVec);
00070 if (havePotential) this->addDependentField(V);
00071
00072 this->addEvaluatedField(psiResidual);
00073
00074 this->setName("SchrodingerResid"+PHX::TypeString<EvalT>::value);
00075 }
00076
00077
00078
00079 template<typename EvalT, typename Traits>
00080 void QCAD::SchrodingerResid<EvalT, Traits>::
00081 postRegistrationSetup(typename Traits::SetupData d,
00082 PHX::FieldManager<Traits>& fm)
00083 {
00084 this->utils.setFieldData(wBF,fm);
00085 this->utils.setFieldData(psi,fm);
00086 this->utils.setFieldData(psiDot,fm);
00087 this->utils.setFieldData(psiGrad,fm);
00088 this->utils.setFieldData(wGradBF,fm);
00089 this->utils.setFieldData(coordVec,fm);
00090 if (havePotential) this->utils.setFieldData(V,fm);
00091
00092 this->utils.setFieldData(psiResidual,fm);
00093 }
00094
00095
00096
00097 template<typename EvalT, typename Traits>
00098 void QCAD::SchrodingerResid<EvalT, Traits>::
00099 evaluateFields(typename Traits::EvalData workset)
00100 {
00101 typedef Intrepid::FunctionSpaceTools FST;
00102 bool bValidRegion = true;
00103 double invEffMass = 1.0;
00104
00105 if(bOnlyInQuantumBlocks)
00106 bValidRegion = materialDB->getElementBlockParam<bool>(workset.EBName,"quantum",false);
00107
00108
00109 if(bValidRegion)
00110 {
00111 if ( potentialType == "From State" || potentialType == "String Formula" || potentialType == "From Aux Data Vector")
00112 {
00113 if ( (numDims == 1) && (oxideWidth > 0.0) )
00114 {
00115 for (std::size_t cell = 0; cell < workset.numCells; ++cell)
00116 {
00117 for (std::size_t qp = 0; qp < numQPs; ++qp)
00118 {
00119 invEffMass = hbar2_over_2m0 * getInvEffMass1DMosCap(&coordVec(cell,qp,0));
00120 for (std::size_t dim = 0; dim < numDims; ++dim)
00121 psiGradWithMass(cell,qp,dim) = invEffMass * psiGrad(cell,qp,dim);
00122 }
00123 }
00124 }
00125
00126
00127
00128
00129
00130
00131 else
00132 {
00133 double ml, mt;
00134
00135 const std::string& matrlCategory = materialDB->getElementBlockParam<std::string>(workset.EBName,"Category","");
00136
00137
00138 if (matrlCategory == "Semiconductor")
00139 {
00140 const std::string& condBandMinVal = materialDB->getElementBlockParam<std::string>(workset.EBName,"Conduction Band Minimum");
00141 ml = materialDB->getElementBlockParam<double>(workset.EBName,"Longitudinal Electron Effective Mass");
00142 mt = materialDB->getElementBlockParam<double>(workset.EBName,"Transverse Electron Effective Mass");
00143
00144 if ((condBandMinVal == "Gamma Valley") && (fabs(ml-mt) > 1e-10))
00145 {
00146 TEUCHOS_TEST_FOR_EXCEPTION (true, std::logic_error, "Gamma Valley's longitudinal and "
00147 << "transverse electron effective mass must be equal ! "
00148 << "Please check the values in materials.xml" << std::endl);
00149 }
00150 }
00151
00152 else if (matrlCategory == "Insulator")
00153 {
00154 ml = materialDB->getElementBlockParam<double>(workset.EBName,"Longitudinal Electron Effective Mass");
00155 mt = materialDB->getElementBlockParam<double>(workset.EBName,"Transverse Electron Effective Mass");
00156 if (fabs(ml-mt) > 1e-10)
00157 {
00158 TEUCHOS_TEST_FOR_EXCEPTION (true, std::logic_error, "Insulator's longitudinal and "
00159 << "transverse electron effective mass must be equal ! "
00160 << "Please check the values in materials.xml" << std::endl);
00161 }
00162 }
00163
00164 else {
00165
00166
00167 ml = mt = 1.0;
00168 }
00169
00170
00171 for (std::size_t cell = 0; cell < workset.numCells; ++cell)
00172 {
00173 for (std::size_t qp = 0; qp < numQPs; ++qp)
00174 {
00175 for (std::size_t dim = 0; dim < numDims; ++dim)
00176 {
00177 if (dim == numDims-1)
00178 invEffMass = hbar2_over_2m0 / ml;
00179 else
00180 invEffMass = hbar2_over_2m0 / mt;
00181 psiGradWithMass(cell,qp,dim) = invEffMass * psiGrad(cell,qp,dim);
00182 }
00183 }
00184 }
00185
00186 }
00187
00188 }
00189
00190
00191
00192 else if ( potentialType == "Finite Wall" )
00193 {
00194 for (std::size_t cell = 0; cell < workset.numCells; ++cell)
00195 {
00196 for (std::size_t qp = 0; qp < numQPs; ++qp)
00197 {
00198 invEffMass = hbar2_over_2m0 * getInvEffMassFiniteWall(&coordVec(cell,qp,0));
00199 for (std::size_t dim = 0; dim < numDims; ++dim)
00200 psiGradWithMass(cell,qp,dim) = invEffMass * psiGrad(cell,qp,dim);
00201 }
00202 }
00203 }
00204
00205
00206 else
00207 {
00208 for (std::size_t cell = 0; cell < workset.numCells; ++cell)
00209 for (std::size_t qp = 0; qp < numQPs; ++qp)
00210 for (std::size_t dim = 0; dim < numDims; ++dim)
00211 psiGradWithMass(cell,qp,dim) = hbar2_over_2m0 * psiGrad(cell,qp,dim);
00212 }
00213
00214
00215 FST::integrate<ScalarT>(psiResidual, psiGradWithMass, wGradBF, Intrepid::COMP_CPP, false);
00216
00217
00218 if (havePotential) {
00219 FST::scalarMultiplyDataData<ScalarT> (psiV, V, psi);
00220 FST::integrate<ScalarT>(psiResidual, psiV, wBF, Intrepid::COMP_CPP, true);
00221 }
00222
00223
00224
00225 if (workset.transientTerms && enableTransient)
00226 FST::integrate<ScalarT>(psiResidual, psiDot, wBF, Intrepid::COMP_CPP, true);
00227
00228 }
00229
00230 else
00231 {
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 if (havePotential)
00244 {
00245 for (std::size_t cell = 0; cell < workset.numCells; ++cell)
00246 for (std::size_t qp = 0; qp < numQPs; ++qp)
00247 V_barrier(cell,qp) = 100.0;
00248
00249 FST::scalarMultiplyDataData<ScalarT> (psiV, V_barrier, psi);
00250
00251 FST::integrate<ScalarT>(psiResidual, psiV, wBF, Intrepid::COMP_CPP, false);
00252 }
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 }
00280 }
00281
00282
00283
00284 template<typename EvalT, typename Traits> double
00285 QCAD::SchrodingerResid<EvalT, Traits>::getInvEffMassFiniteWall(const MeshScalarT* coord)
00286 {
00287 double effMass;
00288 switch (numDims)
00289 {
00290 case 1:
00291 {
00292 if ( (coord[0] >= barrWidth) && (coord[0] <= (barrWidth+wellWidth)) )
00293 effMass = wellEffMass;
00294 else
00295 effMass = barrEffMass;
00296 break;
00297 }
00298 case 2:
00299 {
00300 if ( (coord[0] >= barrWidth) && (coord[0] <= (barrWidth+wellWidth)) &&
00301 (coord[1] >= barrWidth) && (coord[1] <= (barrWidth+wellWidth)) )
00302 effMass = wellEffMass;
00303 else
00304 effMass = barrEffMass;
00305 break;
00306 }
00307 case 3:
00308 {
00309 if ( (coord[0] >= barrWidth) && (coord[0] <= (barrWidth+wellWidth)) &&
00310 (coord[1] >= barrWidth) && (coord[1] <= (barrWidth+wellWidth)) &&
00311 (coord[2] >= barrWidth) && (coord[2] <= (barrWidth+wellWidth)) )
00312
00313 effMass = wellEffMass;
00314 else
00315 effMass = barrEffMass;
00316 break;
00317 }
00318 default:
00319 {
00320 effMass = 0.0;
00321 TEUCHOS_TEST_FOR_EXCEPT( effMass == 0 );
00322 }
00323 }
00324
00325 return 1.0/effMass;
00326 }
00327
00328
00329
00330 template<typename EvalT, typename Traits> double
00331 QCAD::SchrodingerResid<EvalT, Traits>::getInvEffMass1DMosCap(const MeshScalarT* coord)
00332 {
00333 double effMass;
00334
00335
00336 if ((coord[0] >= 0) && (coord[0] <= oxideWidth))
00337 effMass = materialDB->getMaterialParam<double>("SiliconDioxide","Longitudinal Electron Effective Mass",1.0);
00338
00339
00340 else if ((coord[0] > oxideWidth) && (coord[0] <= oxideWidth+siliconWidth))
00341 effMass = materialDB->getMaterialParam<double>("Silicon","Longitudinal Electron Effective Mass",1.0);
00342
00343 else
00344 {
00345 TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter,
00346 std::endl << "Error! x-coord:" << coord[0] << "is outside the oxideWidth" <<
00347 " + siliconWidth range: " << oxideWidth + siliconWidth << "!"<< std::endl);
00348 }
00349
00350 return 1.0/effMass;
00351 }
00352
00353
00354