Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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-2014 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.61 $
40 //
41 // Revision Date : $Date: 2014/05/13 14:50:41 $
42 //
43 // Current Owner : $Author: dgbaur $
44 //-----------------------------------------------------------------------------
45 
46 #ifndef Xyce_N_DEV_DevicePDEInstance_h
47 #define Xyce_N_DEV_DevicePDEInstance_h
48 
49 // ---------- Standard Includes ----------
50 
51 #include <N_UTL_Misc.h>
52 
53 #ifdef HAVE_CMATH
54 #include <cmath>
55 #else
56 #include <math.h>
57 #endif
58 #include <time.h>
59 
60 #include <Sacado.hpp>
61 
62 // ---------- Xyce Includes ----------
63 #include <N_DEV_fwd.h>
64 #include <N_DEV_DeviceInstance.h>
65 #include <N_DEV_MaterialSupport.h>
66 #include <N_DEV_BernouliSupport.h>
67 #include <N_DEV_Const.h>
68 #include <N_DEV_CompositeParam.h>
69 #include <N_DEV_DopeInfo.h>
70 #include <N_DEV_ScalingVars.h>
71 
72 // ---------- Forward Declarations ----------
73 
74 typedef Sacado::Fad::SFad<double,10> pdeFadType;
75 
76 namespace Xyce {
77 namespace Device {
78 
79 //-----------------------------------------------------------------------------
80 // Class : inverse_fermi_one_half_N
81 // Purpose : inverse fermi-dirac integral. Implemented as a functor.
82 // Special Notes :
83 // Creator : Eric Keiter, SNL
84 // Creation Date : 07/01/11
85 //-----------------------------------------------------------------------------
87 {
88  private:
89  double d__1, d__2, d__3;
90  double a1, a2, a3, a4, a5, a6, a7, a8, x10, y10, yp10, x20, y20, yp20, c1, c2;
91  double pi, delx, dely;
92 
93  public:
94  inverse_fermi_one_half_N () // this stuff gets called 1x.
95  {
96  double c_b2 = 4.0/3.0;
97  pi = 2.0*asin(1.0);
98 
99  a1 = sqrt(2.0) / 4.0;
100  a2 = 0.1875 - sqrt(3.0) / 9.0;
101  a3 = sqrt(2.0) * 5.0 / 48.0 + 0.125 - sqrt(6.0) / 9.0;
102  a4 = sqrt(2.0) * 5.0 / 32.0 + 1585.0/6912.0 - sqrt(3.0) * 5.0/24.0 - sqrt(5.0) / 25.0;
103  d__1 = sqrt(pi) * 3.0/4.0;
104  a5 = pow(d__1, c_b2);
105  a6 = 4.0/3.0;
106  a7 = pi * pi / 6.0;
107  a8 = 1.0/3.0;
108  x10 = 7.5;
109  d__3 = x10*x10;
110  y10 = log(x10) + a1 * x10 + a2 * (x10*x10) + a3*(x10*x10*x10) + a4*(d__3 * d__3);
111  yp10 = 1.0/x10 + a1 + a2 * 2.0 * x10 + a3 * 3.0 * (x10 * x10) + a4 * 4.0 * (x10 * x10 * x10);
112  x20 = 8.5;
113  y20 = sqrt(a5 * pow(x20, a6) - a7);
114  yp20 = 0.5 / sqrt(a5 * pow(x20, a6) - a7) * a6 * a5 * pow(x20, a8);
115  delx = 0.5;
116  dely = y20 - y10;
117  c1 = dely * 0.5 / (delx * delx) - yp10 * 0.75 / delx - yp20 * 0.25 / delx;
118  c2 = dely * 0.5 / (delx * delx) - yp20 * 0.75 / delx - yp10 * 0.25 / delx;
119  }
120 
121  template <typename ScalarT>
122  ScalarT operator()(const ScalarT & ratio)
123  {
124  ScalarT ret_val = 0.0;
125  ScalarT tempVal = 0.0;
126 
127  // Joyce-Dixon expressions as used in Medici
128  if (ratio > 0.0 && ratio <= 7.5)
129  {
130  tempVal = ratio*ratio;
131  ret_val = log(ratio) + a1 * ratio + a2*(ratio*ratio) + a3*(ratio*ratio*ratio) + a4*(tempVal*tempVal);
132  }
133 
134  // These next two clauses from Sam Myers
135  if (ratio > 7.5 && ratio <= 8.0)
136  {
137  ScalarT diff = ratio - 7.5;
138  ret_val = y10 + yp10*diff + c1*(diff*diff);
139  }
140  if (ratio > 8. && ratio < 8.5)
141  {
142  ScalarT diff = 8.5-ratio;
143  ret_val = y20 - yp20*diff - c2*(diff*diff);
144  }
145  if (ratio >= 8.5)
146  {
147  ret_val = sqrt(a5 * pow(ratio, a6) - a7);
148  }
149  return ret_val;
150  }
151 };
152 
153 //-----------------------------------------------------------------------------
154 // Class : DevicePDEInstance
155 // Purpose :
156 // Special Notes :
157 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
158 // Creation Date : 3/16/00
159 //-----------------------------------------------------------------------------
161 {
162  public:
164  const InstanceBlock & IB,
165  ParametricData<void> & parametric_data,
166  const FactoryBlock & factory_block);
167 
168  virtual ~DevicePDEInstance () {};
169 
170  private:
171  DevicePDEInstance(const DevicePDEInstance & right);
173 
174  public:
175  // Fermi-Dirac integral
176  double fermi_one_half_B(double arg)
177  {
178  // Reference: "The Approximation of the Fermi-Dirac Integral F1/2(eta)"
179  // by D. Bednarczyk and J. Bednarczyk, Physics Letters, Vol. 64A, No. 4,
180  // 9 January 1978, pp. 409-410.
181  double pi = 4.0*atan(1.0);
182 
183  double nu_eta = pow(arg, 4.0) + 50.0 +
184  33.6*arg*(1.0 - 0.68*exp(-0.17*pow(arg+1.0,2)));
185 
186  double xi = 3.0*sqrt(pi)/(4.0*pow(nu_eta,0.375));
187 
188  return 1.0/(exp(-arg)+xi);
189  }
190 
191  double getVoltDepHoleDens (double Vmin, double V, double Na)
192  {
193  return Na * exp ( Xycemin(CONSTMAX_EXP_ARG, ((Vmin-V)/Ut)) );
194  }
195 
196  double getVoltDepElecDens (double Vmax, double V, double Nd)
197  {
198  return Nd * exp ( Xycemin(CONSTMAX_EXP_ARG, ((V-Vmax)/Ut)) );
199  }
200 
201  double aux1 (double x);
202  double aux2 (double x);
203 
204 
205  double pd1aux1(double x);
206  double pd1aux2(double x);
207 
208  double Jn (double n1, double n2, double E, double u, double h);
209 
210  double dJndV1 (double n1, double n2, double E, double u, double h);
211  double dJndV2 (double n1, double n2, double E, double u, double h);
212  double dJndn1 (double n1, double n2, double E, double u, double h);
213  double dJndn2 (double n1, double n2, double E, double u, double h);
214 
215  double Jp (double p1, double p2, double E, double u, double h);
216 
217  double dJpdV1 (double p1, double p2, double E, double u, double h);
218  double dJpdV2 (double p1, double p2, double E, double u, double h);
219  double dJpdn1 (double p1, double p2, double E, double u, double h);
220  double dJpdn2 (double p1, double p2, double E, double u, double h);
221 
222  // charge dependent current density calculations
223  double J_qdep (double n1, double n2, double E, double u, double h, int z);
224 
226  {
227  pdeFadType retVal=0.0;
228  if (x < -bernSupport.bp0_MISC) x = -bernSupport.bp0_MISC;
229  else if (x > bernSupport.bp0_MISC) x = bernSupport.bp0_MISC;
230 
231  if (x <= bernSupport.bp0_AUX1) retVal=(x / sinh(x));
232  else if (x <= bernSupport.bp1_AUX1) retVal=(1 - x*x/6.0*(1.0 - 7.0*x*x/60.0));
233  else retVal=(x / sinh(x));
234 
235  return retVal;
236  }
237 
239  {
240  pdeFadType retVal=0.0;
241 
242  if (x <= bernSupport.bp0_AUX2) retVal=(1.0);
243  else if (x <= bernSupport.bp1_AUX2) retVal=(1.0 / (1.0 + exp(x)));
244  else if (x <= bernSupport.bp2_AUX2) retVal=(exp(-x));
245  else retVal=(0.0);
246 
247  return retVal;
248  }
249 
250 
251  pdeFadType nMidpoint(pdeFadType & n1, pdeFadType & n2, pdeFadType & E, double h, int z);
252 
253  double J_qdep (double n1, double n2, double E, pdeFadType & u, double h, int z)
254  { return J_qdep (n1, n2, E, u.val(), h, z); }
255 
256  double dJdV1_qdep (double n1, double n2, double E, double u, double h, int z);
257  double dJdV2_qdep (double n1, double n2, double E, double u, double h, int z);
258  double dJdn1_qdep (double n1, double n2, double E, double u, double h, int z);
259  double dJdn2_qdep (double n1, double n2, double E, double u, double h, int z);
260 
261  double dJdV1_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
262  double dJdV2_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
263  double dJdn1_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
264  double dJdn2_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
265  double dJdp1_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
266  double dJdp2_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
267  double dJdbm1_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
268  double dJdbm2_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
269  double dJdpp1_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
270  double dJdpp2_qdep (double n1, double n2, double E, const pdeFadType & u, double h, int z);
271  //
272 
273 #if 0
274  double nsdep(double x, double W, double Dt);
275 
276  double ngdep(double x, double y, double W, double ax, double ay);
277  double ngdep2(double x, double y, double ax, double ay);
278 #endif
279 
280  double erf(double x);
281  double pd1erf(double x);
282 
283  const std::string timeDateStamp();
284  const std::string tecplotTimeDateStamp();
285 
286  // np0 calculation
287  template <typename ScalarT>
288  ScalarT np0_calculation( ScalarT const& elec_dens,
289  ScalarT const& hole_dens,
290  ScalarT const& Ni,
291  ScalarT const& cond_band,
292  ScalarT const& vale_band,
293  ScalarT const& eff_dens_cond,
294  ScalarT const& eff_dens_vale,
295  ScalarT const& temp);
296 
297  // equilbrium concentrations: (using FD)
298  template <typename ScalarT>
299  void n0_and_p0 ( ScalarT const& elec_dens,
300  ScalarT const& hole_dens,
301  ScalarT const& Ni,
302  ScalarT const& cond_band,
303  ScalarT const& vale_band,
304  ScalarT const& eff_dens_cond,
305  ScalarT const& eff_dens_vale,
306  ScalarT const& temp,
307  ScalarT & n0,
308  ScalarT & p0);
309 
310  public:
311  // physical constants:
312  double Temp; // operating temperature (K)
313  double charge; // electron charge (C)
314  double kb; // boltzmann's constant (J/K)
315  double Vt; // thermal voltage
316  double Ut; // thermal voltage, scaled.
317  double e0; // permittivity of vacuum (F/cm)
318  double eSi; // relative permittivity of Si
319  double eSiO2; // relative permittivity of SiO2
320  double eps; // permittivity of Si (F/cm)
321  double Ni; // intrinsic concentration of Si (cm^-3)
322  double h_planck; // planck's constant
323  double e_mass; // electron mass
324 
325  // scaling variables:
326  double x0_user; // distance scaling, as set by the user (cm)
327  double C0_user; // concentration scaling, as set by the user (cm^-3)
328  double t0_user; // time scaling, as set by the user (sec)
329 
331 
332  std::map<std::string, DopeInfo *> dopeInfoMap;
333 
334  // photogen, seu variables:
336  double xstart, ystart; // starting location.
337  double xend, yend; // ending location.
338  double intensity;
339  double photoA1;
340  double photoTstart;
341  double photoTstop;
342  double photoTd;
343  double photoTr;
344  double photoTf;
345  double photoPw;
346  double photoPer;
349  std::string photoString;
352 
353  double photoA1_old; // old A1 (at begin of cont. loop)
354  double photoA1_final; // final A1 (at end of cont. loop)
355  double photoA1_orig; // original A1 (at begin of cont. step)
356  double photoA1_ramp; // ramped value of A1 (A1 at current cont. step)
357  double photoA1_ramp_old; // ramped value of A1 (A1 at current cont. step)
358  double photoA1_Delta; // 2-level delta.(between ckt iterations)
359  double photoA1_DeltaC; // continuation delta.(between cont. solves)
360  double maxPhotoDelta; // maximum photogen delta.
362 
363  // continuation parameters:
364  double maxVoltDelta;
367 
368  bool sensOn;
373 
374  std::string mobModelName;
377  std::string bulkMaterial;
379 
380  //MaterialSupport matSupport;
382 
383  std::string outputName; // added to remove the Y%PDE% prefix.
384 
385  // inverse fermi integral function functor.
387 
388  protected:
389 
390  private:
391  template <typename T> int sgn(T val)
392  {
393  return (val > T(0)) - (val < T(0));
394  }
395 
396 };
397 
398 //-----------------------------------------------------------------------------
399 // Function : DevicePDEInstance::timeDateStamp_
400 // Purpose : get current date and time and format for .PRINT output
401 // Special Notes : inline
402 // Scope : private
403 // Creator :
404 // Creation Date :
405 //-----------------------------------------------------------------------------
406 inline const std::string DevicePDEInstance::timeDateStamp()
407 {
408  const time_t now = time( NULL );
409  char timeDate[ 80 ];
410 
411  // format for output
412  strftime( timeDate, 80, "TIME='%I:%M:%S %p' DATE='%b %d, %Y' ",
413  localtime( &now ) );
414 
415  return std::string( timeDate );
416 }
417 
418 //-----------------------------------------------------------------------------
419 // Function : DevicePDEInstance::tecplotTimeDateStamp_
420 // Purpose : Get current date and time and format for .PRINT output
421 // Special Notes : tecplot version of timeDateStamp_.
422 // Scope : private
423 // Creator : Eric Keiter, SNL
424 // Creation Date : 9/6/04
425 //-----------------------------------------------------------------------------
426 inline const std::string DevicePDEInstance::tecplotTimeDateStamp()
427 {
428  const time_t now = time( NULL );
429  char timeDate[ 80 ];
430 
431  // format for output
432  strftime( timeDate, 80, "TIME= \" %I:%M:%S %p %b %d, %Y \" ",
433  localtime( &now ) );
434 
435  return std::string( timeDate );
436 }
437 
438 
439 
440 //-----------------------------------------------------------------------------
441 // Function : DevicePDEInstance::np0_calculation
442 // Purpose : np0 is calculated using Fermi-Dirac statistics
443 // Special Notes :
444 // Scope : public
445 // Creator : Eric R. Keiter, SNL
446 // Creation Date :
447 //-----------------------------------------------------------------------------
448 template <typename ScalarT>
450 ( ScalarT const& elec_dens,
451  ScalarT const& hole_dens,
452  ScalarT const& Ni,
453  ScalarT const& cond_band,
454  ScalarT const& vale_band,
455  ScalarT const& eff_dens_cond,
456  ScalarT const& eff_dens_vale,
457  ScalarT const& temp)
458 {
459  ScalarT product = 0.0;
460  ScalarT a_ = 0.0;
461  ScalarT eta_ = 0.0;
462  ScalarT n0 = 0.0;
463  ScalarT p0 = 0.0;
464  ScalarT kbq = 8.6173324e-5; // boltzmann's constant in eV K^-1
465 
466  if (elec_dens > hole_dens)
467  {
468  a_ = elec_dens - hole_dens;
469 
470  // Solve for equilibrium electron concentration
471  n0 = (a_ + std::sqrt(a_*a_ + 4.0*Ni*Ni))/2.0;
472  ScalarT n_ratio = n0/eff_dens_cond;
473  eta_ = fdinvObj(n_ratio);
474  ScalarT fermi_lev = cond_band + (kbq *temp)*eta_;
475  p0 = eff_dens_vale * exp((vale_band - fermi_lev)/(kbq*temp));
476  n0 = a_ + p0;
477  product = n0*p0;
478  }
479  else
480  {
481  a_ = hole_dens - elec_dens;
482 
483  // Solve for equilibrium hole concentration
484  p0 = (a_ + std::sqrt(a_*a_ + 4.0*Ni*Ni))/2.0;
485  ScalarT p_ratio = p0/eff_dens_vale;
486  eta_ = fdinvObj(p_ratio);
487  ScalarT fermi_lev = vale_band - (kbq*temp)*eta_;
488  n0 = eff_dens_cond * exp((fermi_lev - cond_band)/(kbq*temp));
489  p0 = a_ + n0;
490  product = n0 * p0;
491  }
492 
493  return product;
494 }
495 
496 //-----------------------------------------------------------------------------
497 // Function : DevicePDEInstance::n0_and_p0
498 //
499 // Purpose : computes equilibrium concentrations of n and p using
500 // Fermi-Dirac statistics.
501 //
502 // Special Notes :
503 // Scope : public
504 // Creator : Eric R. Keiter, SNL
505 // Creation Date : 7/25/11
506 //-----------------------------------------------------------------------------
507 template <typename ScalarT>
509 ( ScalarT const& elec_dens,
510  ScalarT const& hole_dens,
511  ScalarT const& Ni,
512  ScalarT const& cond_band,
513  ScalarT const& vale_band,
514  ScalarT const& eff_dens_cond,
515  ScalarT const& eff_dens_vale,
516  ScalarT const& temp,
517  ScalarT & n0,
518  ScalarT & p0)
519 {
520  ScalarT a_ = 0.0;
521  ScalarT eta_ = 0.0;
522  ScalarT kbq = 8.6173324e-5; // boltzmann's constant in eV K^-1
523 
524  if (elec_dens > hole_dens)
525  {
526  a_ = elec_dens - hole_dens;
527 
528  // Solve for equilibrium electron concentration
529  n0 = (a_ + std::sqrt(a_*a_ + 4.0*Ni*Ni))/2.0;
530  ScalarT n_ratio = n0/eff_dens_cond;
531  eta_ = fdinvObj(n_ratio);
532  ScalarT fermi_lev = cond_band + (kbq *temp)*eta_;
533  p0 = eff_dens_vale * exp((vale_band - fermi_lev)/(kbq*temp));
534  n0 = a_ + p0;
535  }
536  else
537  {
538  a_ = hole_dens - elec_dens;
539 
540  // Solve for equilibrium hole concentration
541  p0 = (a_ + std::sqrt(a_*a_ + 4.0*Ni*Ni))/2.0;
542  ScalarT p_ratio = p0/eff_dens_vale;
543  eta_ = fdinvObj(p_ratio);
544  ScalarT fermi_lev = vale_band - (kbq*temp)*eta_;
545  n0 = eff_dens_cond * exp((fermi_lev - cond_band)/(kbq*temp));
546  p0 = a_ + n0;
547  }
548 }
549 
550 
551 } // namespace Device
552 } // namespace Xyce
553 
555 
556 #endif // Xyce_N_DEV_DevicePDEInstance_h