Xyce  6.1
N_DEV_DevicePDEInstance.h
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2015 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-----------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_DevicePDEInstance.h,v $
27 //
28 // Purpose : This file contains the PDE device instance base class.
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 05/15/01
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.66.2.1 $
40 //
41 // Revision Date : $Date: 2015/04/02 18:20:12 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-----------------------------------------------------------------------------
45 
46 #ifndef Xyce_N_DEV_DevicePDEInstance_h
47 #define Xyce_N_DEV_DevicePDEInstance_h
48 
49 // ---------- Standard Includes ----------
50 #include <N_UTL_Math.h>
51 #include <time.h>
52 
53 #include <Sacado.hpp>
54 
55 // ---------- Xyce Includes ----------
56 #include <N_DEV_fwd.h>
57 #include <N_DEV_DeviceInstance.h>
58 #include <N_DEV_MaterialSupport.h>
59 #include <N_DEV_BernouliSupport.h>
60 #include <N_DEV_Const.h>
61 #include <N_DEV_CompositeParam.h>
62 #include <N_DEV_DopeInfo.h>
63 #include <N_DEV_ScalingVars.h>
64 #include <N_DEV_FermiIntegrals.h>
65 
66 // ---------- Forward Declarations ----------
67 
68 typedef Sacado::Fad::SFad<double,10> pdeFadType;
69 
70 namespace Xyce {
71 namespace Device {
72 
73 
74 //-----------------------------------------------------------------------------
75 // Class : DevicePDEInstance
76 // Purpose :
77 // Special Notes :
78 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
79 // Creation Date : 3/16/00
80 //-----------------------------------------------------------------------------
82 {
83  public:
85  const InstanceBlock & IB,
86  ParametricData<void> & parametric_data,
87  const FactoryBlock & factory_block);
88 
89  virtual ~DevicePDEInstance () {};
90 
91  private:
92  DevicePDEInstance(const DevicePDEInstance & right);
94 
95  public:
96  // Fermi-Dirac integral
97  double fermi_one_half_B(double arg)
98  {
99  // Reference: "The Approximation of the Fermi-Dirac Integral F1/2(eta)"
100  // by D. Bednarczyk and J. Bednarczyk, Physics Letters, Vol. 64A, No. 4,
101  // 9 January 1978, pp. 409-410.
102  double pi = 4.0*atan(1.0);
103 
104  double nu_eta = pow(arg, 4.0) + 50.0 +
105  33.6*arg*(1.0 - 0.68*exp(-0.17*pow(arg+1.0,2)));
106 
107  double xi = 3.0*sqrt(pi)/(4.0*pow(nu_eta,0.375));
108 
109  return 1.0/(exp(-arg)+xi);
110  }
111 
112  double getVoltDepHoleDens (double Vmin, double V, double Na)
113  {
114  return Na * exp ( std::min(CONSTMAX_EXP_ARG, ((Vmin-V)/Ut)) );
115  }
116 
117  double getVoltDepElecDens (double Vmax, double V, double Nd)
118  {
119  return Nd * exp ( std::min(CONSTMAX_EXP_ARG, ((V-Vmax)/Ut)) );
120  }
121 
122  double aux1 (double x);
123  double aux2 (double x);
124 
125 
126  double pd1aux1(double x);
127  double pd1aux2(double x);
128 
129  double Jn (double n1, double n2, double E, double u, double h);
130 
131  double dJndV1 (double n1, double n2, double E, double u, double h);
132  double dJndV2 (double n1, double n2, double E, double u, double h);
133  double dJndn1 (double n1, double n2, double E, double u, double h);
134  double dJndn2 (double n1, double n2, double E, double u, double h);
135 
136  double Jp (double p1, double p2, double E, double u, double h);
137 
138  double dJpdV1 (double p1, double p2, double E, double u, double h);
139  double dJpdV2 (double p1, double p2, double E, double u, double h);
140  double dJpdn1 (double p1, double p2, double E, double u, double h);
141  double dJpdn2 (double p1, double p2, double E, double u, double h);
142 
143  // charge dependent current density calculations
144  double J_qdep (double n1, double n2, double E, double u, double h, int z);
145 
147  {
148  pdeFadType retVal=0.0;
149  if (x < -bernSupport.bp0_MISC) x = -bernSupport.bp0_MISC;
150  else if (x > bernSupport.bp0_MISC) x = bernSupport.bp0_MISC;
151 
152  if (x <= bernSupport.bp0_AUX1) retVal=(x / sinh(x));
153  else if (x <= bernSupport.bp1_AUX1) retVal=(1 - x*x/6.0*(1.0 - 7.0*x*x/60.0));
154  else retVal=(x / sinh(x));
155 
156  return retVal;
157  }
158 
160  {
161  pdeFadType retVal=0.0;
162 
163  if (x <= bernSupport.bp0_AUX2) retVal=(1.0);
164  else if (x <= bernSupport.bp1_AUX2) retVal=(1.0 / (1.0 + exp(x)));
165  else if (x <= bernSupport.bp2_AUX2) retVal=(exp(-x));
166  else retVal=(0.0);
167 
168  return retVal;
169  }
170 
171 
172  pdeFadType nMidpoint(pdeFadType & n1, pdeFadType & n2, pdeFadType & E, double h, int z);
173 
174  double J_qdep (double n1, double n2, double E, pdeFadType & u, double h, int z)
175  { return J_qdep (n1, n2, E, u.val(), h, z); }
176 
177  double dJdV1_qdep (double n1, double n2, double E, double u, double h, int z);
178  double dJdV2_qdep (double n1, double n2, double E, double u, double h, int z);
179  double dJdn1_qdep (double n1, double n2, double E, double u, double h, int z);
180  double dJdn2_qdep (double n1, double n2, double E, double u, double h, int z);
181 
182  double dJdV1_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
183  double dJdV2_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
184  double dJdn1_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
185  double dJdn2_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
186  double dJdp1_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
187  double dJdp2_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
188  double dJdbm1_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
189  double dJdbm2_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
190  double dJdpp1_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
191  double dJdpp2_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
192  //
193 
194 #if 0
195  double nsdep(double x, double W, double Dt);
196 
197  double ngdep(double x, double y, double W, double ax, double ay);
198  double ngdep2(double x, double y, double ax, double ay);
199 #endif
200 
201  double erf(double x);
202  double pd1erf(double x);
203 
204  const std::string timeDateStamp();
205  const std::string tecplotTimeDateStamp();
206 
207  // np0 calculation
208  template <typename ScalarT>
209  ScalarT np0_calculation( ScalarT const& elec_dens,
210  ScalarT const& hole_dens,
211  ScalarT const& Ni,
212  ScalarT const& cond_band,
213  ScalarT const& vale_band,
214  ScalarT const& eff_dens_cond,
215  ScalarT const& eff_dens_vale,
216  ScalarT const& temp);
217 
218  // equilbrium concentrations: (using FD)
219  template <typename ScalarT>
220  void n0_and_p0 ( ScalarT const& elec_dens,
221  ScalarT const& hole_dens,
222  ScalarT const& Ni,
223  ScalarT const& cond_band,
224  ScalarT const& vale_band,
225  ScalarT const& eff_dens_cond,
226  ScalarT const& eff_dens_vale,
227  ScalarT const& temp,
228  ScalarT & n0,
229  ScalarT & p0);
230 
231  //Fermi-Dirac fluxes
232  template <typename ScalarT>
233  ScalarT FDCarrierFlux( ScalarT n1,
234  ScalarT n2,
235  ScalarT V1,
236  ScalarT V2,
237  ScalarT mu,
238  ScalarT temp,
239  double h,
240  double z,
241  double DOS);
242 
243  public:
244  // physical constants:
245  double Temp; // operating temperature (K)
246  double charge; // electron charge (C)
247  double kb; // boltzmann's constant (J/K)
248  double Vt; // thermal voltage
249  double Ut; // thermal voltage, scaled.
250  double e0; // permittivity of vacuum (F/cm)
251  double eSi; // relative permittivity of Si
252  double eSiO2; // relative permittivity of SiO2
253  double eps; // permittivity of Si (F/cm)
254  double Ni; // intrinsic concentration of Si (cm^-3)
255  double h_planck; // planck's constant
256  double e_mass; // electron mass
257 
258  // scaling variables:
259  double x0_user; // distance scaling, as set by the user (cm)
260  double C0_user; // concentration scaling, as set by the user (cm^-3)
261  double t0_user; // time scaling, as set by the user (sec)
262 
264 
265  std::map<std::string, DopeInfo *> dopeInfoMap;
266 
267  // continuation parameters:
268  double maxVoltDelta;
271 
272  bool sensOn;
277 
278  std::string mobModelName;
281  std::string bulkMaterial;
283 
284  //MaterialSupport matSupport;
286 
287  std::string outputName; // added to remove the Y%PDE% prefix.
288 
289  // inverse fermi integral function functor.
293  protected:
294 
295  private:
296  template <typename T> int sgn(T val)
297  {
298  return (val > T(0)) - (val < T(0));
299  }
300 
301 };
302 
303 //-----------------------------------------------------------------------------
304 // Function : DevicePDEInstance::timeDateStamp_
305 // Purpose : get current date and time and format for .PRINT output
306 // Special Notes : inline
307 // Scope : private
308 // Creator :
309 // Creation Date :
310 //-----------------------------------------------------------------------------
311 inline const std::string DevicePDEInstance::timeDateStamp()
312 {
313  const time_t now = time( NULL );
314  char timeDate[ 80 ];
315 
316  // format for output
317  strftime( timeDate, 80, "TIME='%I:%M:%S %p' DATE='%b %d, %Y' ",
318  localtime( &now ) );
319 
320  return std::string( timeDate );
321 }
322 
323 //-----------------------------------------------------------------------------
324 // Function : DevicePDEInstance::tecplotTimeDateStamp_
325 // Purpose : Get current date and time and format for .PRINT output
326 // Special Notes : tecplot version of timeDateStamp_.
327 // Scope : private
328 // Creator : Eric Keiter, SNL
329 // Creation Date : 9/6/04
330 //-----------------------------------------------------------------------------
331 inline const std::string DevicePDEInstance::tecplotTimeDateStamp()
332 {
333  const time_t now = time( NULL );
334  char timeDate[ 80 ];
335 
336  // format for output
337  strftime( timeDate, 80, "TIME= \" %I:%M:%S %p %b %d, %Y \" ",
338  localtime( &now ) );
339 
340  return std::string( timeDate );
341 }
342 
343 
344 
345 //-----------------------------------------------------------------------------
346 // Function : DevicePDEInstance::np0_calculation
347 // Purpose : np0 is calculated using Fermi-Dirac statistics
348 // Special Notes :
349 // Scope : public
350 // Creator : Eric R. Keiter, SNL
351 // Creation Date :
352 //-----------------------------------------------------------------------------
353 template <typename ScalarT>
355 ( ScalarT const& elec_dens,
356  ScalarT const& hole_dens,
357  ScalarT const& Ni,
358  ScalarT const& cond_band,
359  ScalarT const& vale_band,
360  ScalarT const& eff_dens_cond,
361  ScalarT const& eff_dens_vale,
362  ScalarT const& temp)
363 {
364  ScalarT product = 0.0;
365  ScalarT a_ = 0.0;
366  ScalarT eta_ = 0.0;
367  ScalarT n0 = 0.0;
368  ScalarT p0 = 0.0;
369  ScalarT kbq = 8.6173324e-5; // boltzmann's constant in eV K^-1
370 
371  if (elec_dens > hole_dens)
372  {
373  a_ = elec_dens - hole_dens;
374 
375  // Solve for equilibrium electron concentration
376  n0 = (a_ + std::sqrt(a_*a_ + 4.0*Ni*Ni))/2.0;
377  ScalarT n_ratio = n0/eff_dens_cond;
378  eta_ = fdinvObj(n_ratio);
379  ScalarT fermi_lev = cond_band + (kbq *temp)*eta_;
380  p0 = eff_dens_vale * exp((vale_band - fermi_lev)/(kbq*temp));
381  n0 = a_ + p0;
382  product = n0*p0;
383  }
384  else
385  {
386  a_ = hole_dens - elec_dens;
387 
388  // Solve for equilibrium hole concentration
389  p0 = (a_ + std::sqrt(a_*a_ + 4.0*Ni*Ni))/2.0;
390  ScalarT p_ratio = p0/eff_dens_vale;
391  eta_ = fdinvObj(p_ratio);
392  ScalarT fermi_lev = vale_band - (kbq*temp)*eta_;
393  n0 = eff_dens_cond * exp((fermi_lev - cond_band)/(kbq*temp));
394  p0 = a_ + n0;
395  product = n0 * p0;
396  }
397 
398  return product;
399 }
400 
401 //-----------------------------------------------------------------------------
402 // Function : DevicePDEInstance::n0_and_p0
403 //
404 // Purpose : computes equilibrium concentrations of n and p using
405 // Fermi-Dirac statistics.
406 //
407 // Special Notes :
408 // Scope : public
409 // Creator : Eric R. Keiter, SNL
410 // Creation Date : 7/25/11
411 //-----------------------------------------------------------------------------
412 template <typename ScalarT>
414 ( ScalarT const& elec_dens,
415  ScalarT const& hole_dens,
416  ScalarT const& Ni,
417  ScalarT const& cond_band,
418  ScalarT const& vale_band,
419  ScalarT const& eff_dens_cond,
420  ScalarT const& eff_dens_vale,
421  ScalarT const& temp,
422  ScalarT & n0,
423  ScalarT & p0)
424 {
425  ScalarT a_ = 0.0;
426  ScalarT eta_ = 0.0;
427  ScalarT kbq = 8.6173324e-5; // boltzmann's constant in eV K^-1
428 
429  if (elec_dens > hole_dens)
430  {
431  a_ = elec_dens - hole_dens;
432 
433  // Solve for equilibrium electron concentration
434  n0 = (a_ + std::sqrt(a_*a_ + 4.0*Ni*Ni))/2.0;
435  ScalarT n_ratio = n0/eff_dens_cond;
436  eta_ = fdinvObj(n_ratio);
437  ScalarT fermi_lev = cond_band + (kbq *temp)*eta_;
438  p0 = eff_dens_vale * exp((vale_band - fermi_lev)/(kbq*temp));
439  n0 = a_ + p0;
440  }
441  else
442  {
443  a_ = hole_dens - elec_dens;
444 
445  // Solve for equilibrium hole concentration
446  p0 = (a_ + std::sqrt(a_*a_ + 4.0*Ni*Ni))/2.0;
447  ScalarT p_ratio = p0/eff_dens_vale;
448  eta_ = fdinvObj(p_ratio);
449  ScalarT fermi_lev = vale_band - (kbq*temp)*eta_;
450  n0 = eff_dens_cond * exp((fermi_lev - cond_band)/(kbq*temp));
451  p0 = a_ + n0;
452  }
453 }
454 
455 //-----------------------------------------------------------------------------
456 // Function : DevicePDEInstance::FDCarrierFlux
457 //
458 // Purpose : computes carrier fluxes with Fermi-Dirac statistics
459 //
460 // Special Notes :
461 // Scope : public
462 // Creator : Lawrence C Musson
463 // Creation Date : 9/30/14
464 //-----------------------------------------------------------------------------
465 template <typename ScalarT>
467  ScalarT n2,
468  ScalarT V1,
469  ScalarT V2,
470  ScalarT mu,
471  ScalarT temp,
472  double h,
473  double z,
474  double DOS)
475 {
476 
477  ScalarT kbq = 8.6173324e-5; // boltzmann's constant in eV K^-1
478 
479  ScalarT kT = kbq*temp;
480 
481  ScalarT fermiArg1 = n1/DOS;
482 
483  ScalarT fermiArg2 = n2/DOS;
484 
485  ScalarT fdFactor = -0.5*z*(fdinvObj(fermiArg2) - fdinvObj(fermiArg1));
486 
487  ScalarT commonFactor = (V1-V2)/(2.0*kT);
488 
489  //If there's no field, it could present a problem
490 
491  ScalarT buffer = kT*1.e-3;
492 
493  if(-z*commonFactor < 0.0)buffer *= -1.0;
494 
495  ScalarT fluxDenominator = exp(-z*commonFactor+buffer/(2.0*kT)) - exp(z*commonFactor-buffer/(2.0*kT));
496 
497  ScalarT concProduct = n1*n2;
498 
499  if(n1*n2 < 0.0)concProduct = abs(buffer);
500 
501  ScalarT fluxPrefactor = -mu*(-z*(V1-V2)+buffer)/h*sqrt(concProduct);
502 
503  ScalarT fluxNumerator = exp(-z*(commonFactor + fdFactor)) -
504  exp( z*(commonFactor + fdFactor));
505 
506  //If commonFactor AND commonFactor relative to fdFactor becomes large enough, the formulas can produce
507  //overflow. However, really, fluxNumerator/fluxDenominator -> 1.0. Capture this event.
508 
509  if(abs(commonFactor) > 50.0 || abs(fdFactor) > 50.00)
510  {
511  fluxNumerator = 1.0;
512  if(fdFactor < 0.0)
513  fluxDenominator = -1.0;
514  else
515  fluxDenominator = 1.0;
516  }
517 
518  ScalarT flux = fluxPrefactor*fluxNumerator/fluxDenominator;
519 
520  return flux;
521 
522 }
523 
524 
525 } // namespace Device
526 } // namespace Xyce
527 
528 #endif // Xyce_N_DEV_DevicePDEInstance_h
double Jn(double n1, double n2, double E, double u, double h)
double J_qdep(double n1, double n2, double E, pdeFadType &u, double h, int z)
double dJdbm1_qdep(double n1, double n2, double E, const pdeFadType &u, double h, int z)
double dJndV2(double n1, double n2, double E, double u, double h)
pdeFadType nMidpoint(pdeFadType &n1, pdeFadType &n2, pdeFadType &E, double h, int z)
void n0_and_p0(ScalarT const &elec_dens, ScalarT const &hole_dens, ScalarT const &Ni, ScalarT const &cond_band, ScalarT const &vale_band, ScalarT const &eff_dens_cond, ScalarT const &eff_dens_vale, ScalarT const &temp, ScalarT &n0, ScalarT &p0)
ScalarT FDCarrierFlux(ScalarT n1, ScalarT n2, ScalarT V1, ScalarT V2, ScalarT mu, ScalarT temp, double h, double z, double DOS)
Pure virtual class to augment a linear system.
double Jp(double p1, double p2, double E, double u, double h)
ScalarT np0_calculation(ScalarT const &elec_dens, ScalarT const &hole_dens, ScalarT const &Ni, ScalarT const &cond_band, ScalarT const &vale_band, ScalarT const &eff_dens_cond, ScalarT const &eff_dens_vale, ScalarT const &temp)
#define CONSTMAX_EXP_ARG
Definition: N_DEV_Const.h:107
DevicePDEInstance(const InstanceBlock &IB, ParametricData< void > &parametric_data, const FactoryBlock &factory_block)
double dJdp2_qdep(double n1, double n2, double E, const pdeFadType &u, double h, int z)
double dJdpp2_qdep(double n1, double n2, double E, const pdeFadType &u, double h, int z)
Sacado::Fad::SFad< double, 10 > pdeFadType
double dJdV2_qdep(double n1, double n2, double E, double u, double h, int z)
double dJpdV2(double p1, double p2, double E, double u, double h)
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
double dJdn1_qdep(double n1, double n2, double E, double u, double h, int z)
Class ParametricData manages the configuration information and the parameter binding map...
Definition: N_DEV_Pars.h:1303
double getVoltDepElecDens(double Vmax, double V, double Nd)
double dJndn2(double n1, double n2, double E, double u, double h)
double dJpdn2(double p1, double p2, double E, double u, double h)
double dJdV1_qdep(double n1, double n2, double E, double u, double h, int z)
std::map< std::string, DopeInfo * > dopeInfoMap
double dJpdV1(double p1, double p2, double E, double u, double h)
double dJndV1(double n1, double n2, double E, double u, double h)
double J_qdep(double n1, double n2, double E, double u, double h, int z)
double dJdn2_qdep(double n1, double n2, double E, double u, double h, int z)
double dJpdn1(double p1, double p2, double E, double u, double h)
double dJdbm2_qdep(double n1, double n2, double E, const pdeFadType &u, double h, int z)
double getVoltDepHoleDens(double Vmin, double V, double Na)
#define W
double dJdpp1_qdep(double n1, double n2, double E, const pdeFadType &u, double h, int z)
InstanceBlock represent a device instance line from the netlist.
double dJdp1_qdep(double n1, double n2, double E, const pdeFadType &u, double h, int z)
DevicePDEInstance & operator=(const DevicePDEInstance &right)
double dJndn1(double n1, double n2, double E, double u, double h)