Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_DeviceSupport.C
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_DeviceSupport.C,v $
27 //
28 // Purpose : This file contains similar functions to the spice3f5
29 // file, devsup.c. It contains support routines for
30 // device models
31 //
32 // Special Notes :
33 //
34 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
35 //
36 // Creation Date : 01/17/01
37 //
38 // Revision Information:
39 // ---------------------
40 //
41 // Revision Number: $Revision: 1.43 $
42 //
43 // Revision Date : $Date: 2014/02/24 23:49:15 $
44 //
45 // Current Owner : $Author: tvrusso $
46 //-------------------------------------------------------------------------
47 
48 #include <Xyce_config.h>
49 
50 
51 // ---------- Standard Includes ----------
52 
53 #ifdef HAVE_CMATH
54 #include <cmath>
55 #else
56 #include <math.h>
57 #endif
58 
59 #if( defined HAVE_FLOAT_H && defined HAVE__ISNAN_AND__FINITE_SUPPORT )
60 #include <float.h>
61 #define isnan(x) _isnan(x)
62 #define isinf(x) (!_finite(x))
63 #else
64 using std::isnan;
65 using std::isinf;
66 #endif
67 
68 
69 // ---------- Xyce Includes ----------
70 
71 #include <N_UTL_Misc.h>
72 #include <N_DEV_DeviceSupport.h>
73 #include <N_DEV_Const.h>
74 
75 namespace Xyce {
76 namespace Device {
77 
78 //-----------------------------------------------------------------------------
79 // Function : DeviceSupport::lambertw
80 // Purpose : provides a lambert-w function for diodes and BJT's.
81 // Special Notes :
82 //
83 // Purpose. Evaluate principal branch of Lambert W function at x.
84 //
85 // w = w(x) is the value of Lambert's function.
86 // ierr = 0 indicates a safe return.
87 // ierr = 1 if x is not in the domain.
88 // ierr = 2 if the computer arithmetic contains a bug.
89 // xi may be disregarded (it is the error).
90 //
91 // Prototype: void lambertw( double, double, int, double);
92 //
93 // Reference:
94 // T.C. Banwell
95 // Bipolar transistor circuit analysis using the Lambert W-function,
96 // IEEE Transactions on Circuits and Systems I: Fundamental Theory
97 // and Applications
98 //
99 // vol. 47, pp. 1621-1633, Nov. 2000.
100 //
101 // Scope : public
102 // Creator : David Day, SNL
103 // Creation Date : 04/16/02
104 //-----------------------------------------------------------------------------
105 void DeviceSupport::lambertw(double x, double &w, int &ierr, double &xi)
106 {
107  int i=0, maxit = 10;
108  const double turnpt = -exp(-1.), c1 = 1.5, c2 = .75;
109  double r, r2, r3, s, mach_eps, relerr = 1., diff;
110  mach_eps = 2.e-15; // float:2e-7
111  ierr = 0;
112 
113  if( x > c1)
114  {
115  w = c2*log(x);
116  xi = log( x/ w) - w;
117  }
118  else
119  {
120  if( x >= 0.0)
121  {
122  w = x;
123  if( x == 0. ) return;
124  if( x < (1-c2) ) w = x*(1.-x + c1*x*x);
125  xi = - w;
126  }
127  else
128  {
129  if( x >= turnpt)
130  {
131  if( x > -0.2 )
132  {
133  w = x*(1.0-x + c1*x*x);
134  xi = log(1.0-x + c1*x*x) - w;
135  }
136  else
137  {
138  diff = x-turnpt;
139  if( diff < 0.0 ) diff = -diff;
140  w = -1 + sqrt(2.0*exp(1.))*sqrt(x-turnpt);
141  if( diff == 0.0 ) return;
142  xi = log( x/ w) - w;
143  }
144  }
145  else
146  {
147  ierr = 1; // x is not in the domain.
148  w = -1.0;
149  return;
150  }
151  }
152  }
153 
154  while( relerr > mach_eps && i<maxit)
155  {
156  r = xi/(w+1.0); //singularity at w=-1
157  r2 = r*r;
158  r3 = r2*r;
159  s = 6.*(w+1.0)*(w+1.0);
160  w = w * ( 1.0 + r + r2/(2.0*( w+1.0)) - (2. * w -1.0)*r3/s );
161  if( w * x < 0.0 ) w = -w;
162  xi = log( x/ w) - w;
163 
164  if( x>1.0 )
165  {
166  relerr = xi / w;
167  }
168  else
169  {
170  relerr = xi;
171  }
172  if(relerr < 0.0 ) relerr = -relerr;
173  ++i;
174  }
175  if( i == maxit ) ierr = 2;
176 }
177 
178 //-----------------------------------------------------------------------------
179 // Function : DeviceSupport::limvds
180 // Purpose : limit the per-iteration change of VDS
181 // Special Notes :
182 // Scope : public
183 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
184 // Creation Date : 01/17/01
185 //-----------------------------------------------------------------------------
186 double DeviceSupport::limvds ( double vnew, double vold)
187 {
188 
189  if(vold >= 3.5)
190  {
191  if(vnew > vold) vnew = Xycemin(vnew,(3.0 * vold) + 2.0);
192  else
193  {
194  if (vnew < 3.5) vnew = Xycemax(vnew,2.0);
195  }
196  }
197  else
198  {
199  if(vnew > vold) vnew = Xycemin(vnew, 4.0);
200  else vnew = Xycemax(vnew,-0.5);
201  }
202  return(vnew);
203 }
204 
205 
206 //-----------------------------------------------------------------------------
207 // Function : DeviceSupport::pnjlim
208 // Purpose : limit the per-iteration change of PN junction voltages
209 // Special Notes :
210 // Scope : public
211 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
212 // Creation Date : 01/17/01
213 //-----------------------------------------------------------------------------
215  double vnew,
216  double vold,
217  double vt,
218  double vcrit,
219  int *icheck
220  )
221 {
222  double arg;
223 
224  if((vnew > vcrit) && (fabs(vnew - vold) > (vt + vt)))
225  {
226  if(vold > 0)
227  {
228  arg = 1 + (vnew - vold) / vt;
229 
230  if(arg > 0)
231  {
232  vnew = vold + vt * log(arg);
233  }
234  else
235  {
236  vnew = vcrit;
237  }
238  }
239  else
240  {
241  vnew = vt *log(vnew/vt);
242  }
243 
244  *icheck = 1;
245  }
246  else
247  {
248  *icheck = 0;
249  }
250 
251  return(vnew);
252 }
253 
254 //-----------------------------------------------------------------------------
255 // Function : DeviceSupport::pnjlim_new
256 // Purpose : limit the per-iteration change of PN junction voltages
257 // Special Notes : Copied from NGSpice, which has the following comment:
258 // This code has been fixed by Alan Gillespie adding limiting
259 // for negative voltages
260 // Scope : public
261 // Creator : Tom Russo, SNL 1445, Electrical Systems Modeling
262 // Creation Date : 11/19/2012
263 //-----------------------------------------------------------------------------
265  double vnew,
266  double vold,
267  double vt,
268  double vcrit,
269  int *icheck
270  )
271 {
272  double arg;
273 
274  if((vnew > vcrit) && (fabs(vnew - vold) > (vt + vt)))
275  {
276  if(vold > 0)
277  {
278  arg = (vnew - vold) / vt;
279 
280  if(arg > 0)
281  {
282  vnew = vold + vt * (2+log(arg-2));
283  }
284  else
285  {
286  vnew = vold - vt*(2+log(2-arg));
287  }
288  }
289  else
290  {
291  vnew = vt *log(vnew/vt);
292  }
293 
294  *icheck = 1;
295  }
296  else
297  {
298  if (vnew < 0)
299  {
300  if (vold > 0)
301  {
302  arg= -vold -1;
303  }
304  else
305  {
306  arg = 2*vold -1;
307  }
308  if (vnew < arg)
309  {
310  vnew = arg;
311  *icheck=1;
312  }
313  else
314  {
315  *icheck = 0;
316  }
317  }
318  else
319  {
320 
321  *icheck = 0;
322  }
323  }
324 
325  return(vnew);
326 }
327 
328 
329 //-----------------------------------------------------------------------------
330 // Function : DeviceSupport::fetlim
331 // Purpose : limit the per-iteration change of FET voltages
332 // Special Notes :
333 // Scope : public
334 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
335 // Creation Date : 01/17/01
336 //-----------------------------------------------------------------------------
338  double vnew,
339  double vold,
340  double vto
341  )
342 {
343  double vtsthi;
344  double vtstlo;
345  double vtox;
346  double delv;
347  double vtemp;
348 
349 #ifdef Xyce_FETLIM_NAN_CHECK
350  // Make sure that vto is not a Nan.
351  if (finiteNumberTest(vto) < 0)
352  {
353  vto = 1.0; // kludge.
354  }
355 #endif
356 
357  vtsthi = fabs(2*(vold-vto))+2;
358  vtstlo = vtsthi/2 +2;
359  vtox = vto + 3.5;
360  delv = vnew-vold;
361 
362  if (vold >= vto)
363  {
364  if(vold >= vtox)
365  {
366  if(delv <= 0)
367  {
368  // going off
369  if(vnew >= vtox)
370  {
371  if(-delv >vtstlo) vnew = vold - vtstlo;
372  }
373  else
374  {
375  vnew = Xycemax(vnew,vto+2.0);
376  }
377  }
378  else
379  {
380  // staying on
381  if(delv >= vtsthi) vnew = vold + vtsthi;
382  }
383  }
384  else
385  {
386  // middle region
387  if(delv <= 0)
388  {
389  // decreasing
390  vnew = Xycemax(vnew,vto-0.5);
391  }
392  else
393  {
394  // increasing
395  vnew = Xycemin(vnew,vto+4.0);
396  }
397  }
398  }
399  else
400  {
401  // off
402  if(delv <= 0)
403  {
404  if(-delv >vtsthi) vnew = vold - vtsthi;
405  }
406  else
407  {
408  vtemp = vto + 0.5;
409  if(vnew <= vtemp)
410  {
411  if(delv >vtstlo) vnew = vold + vtstlo;
412  }
413  else
414  {
415  vnew = vtemp;
416  }
417  }
418  }
419  return(vnew);
420 }
421 
422 //-----------------------------------------------------------------------------
423 // Function : DeviceSupport::cmeyer
424 // Purpose : Compute the MOS overlap capacitances as functions of the
425 // device terminal voltages
426 // Special Notes :
427 // Scope : public
428 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
429 // Creation Date : 01/17/01
430 //-----------------------------------------------------------------------------
431 
433  double vgs0, // initial voltage gate-source
434  double vgd0, // initial voltage gate-drain
435  double vgb0, // initial voltage gate-bulk
436  double von0,
437  double vdsat0,
438  double vgs1, // final voltage gate-source
439  double vgd1, // final voltage gate-drain
440  double vgb1, // final voltage gate-bulk
441  double covlgs, // overlap capacitance gate-source
442  double covlgd, // overlap capacitance gate-drain
443  double covlgb, // overlap capacitance gate-bulk
444  register double *cgs,
445  register double *cgd,
446  register double *cgb,
447  double phi,
448  double cox,
449  double von,
450  double vdsat
451  )
452 {
453  double vdb;
454  double vdbsat;
455  double vddif;
456  double vddif1;
457  double vddif2;
458  double vgbt;
459 
460  *cgs = 0;
461  *cgd = 0;
462  *cgb = 0;
463 
464  vgbt = vgs1-von;
465  if (vgbt <= -phi)
466  {
467  *cgb = cox;
468  }
469  else if (vgbt <= -phi/2)
470  {
471  *cgb = -vgbt*cox/phi;
472  }
473  else if (vgbt <= 0)
474  {
475  *cgb = -vgbt*cox/phi;
476  *cgs = cox/(7.5e-1*phi)*vgbt+cox/1.5;
477  }
478  else
479  {
480  vdbsat = vdsat-(vgs1-vgb1);
481  vdb = vgb1-vgd1;
482  if (vdbsat <= vdb)
483  {
484  *cgs = cox/1.5;
485  }
486  else
487  {
488  vddif = 2.0*vdbsat-vdb;
489  vddif1 = vdbsat-vdb-1.0e-12;
490  vddif2 = vddif*vddif;
491  *cgd = cox*(1.0-vdbsat*vdbsat/vddif2)/1.5;
492  *cgs = cox*(1.0-vddif1*vddif1/vddif2)/1.5;
493  }
494  }
495 
496  vgbt = vgs0-von0;
497  if (vgbt <= -phi)
498  {
499  *cgb += cox;
500  }
501  else if (vgbt <= -phi/2)
502  {
503  *cgb += -vgbt*cox/phi;
504  }
505  else if (vgbt <= 0)
506  {
507  *cgb += -vgbt*cox/phi;
508  *cgs += cox/(7.5e-1*phi)*vgbt+cox/1.5;
509  }
510  else
511  {
512  vdbsat = vdsat0-(vgs0-vgb0);
513  vdb = vgb0-vgd0;
514  if (vdbsat <= vdb)
515  {
516  *cgs += cox/1.5;
517  }
518  else
519  {
520  vddif = 2.0*vdbsat-vdb;
521  vddif1 = vdbsat-vdb-1.0e-12;
522  vddif2 = vddif*vddif;
523  *cgd += cox*(1.0-vdbsat*vdbsat/vddif2)/1.5;
524  *cgs += cox*(1.0-vddif1*vddif1/vddif2)/1.5;
525  }
526  }
527 
528  *cgs = *cgs *.5 + covlgs;
529  *cgd = *cgd *.5 + covlgd;
530  *cgb = *cgb *.5 + covlgb;
531 }
532 
533 
534 //-----------------------------------------------------------------------------
535 // Function : DeviceSupport::qmeyer
536 // Purpose : Compute the MOS overlap capacitances as functions of the
537 // device terminal voltages
538 //
539 // Special Notes : ARGSUSED because vgb is no longer used
540 //
541 // Scope : public
542 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
543 // Creation Date : 01/17/01
544 //-----------------------------------------------------------------------------
546  double vgs, // initial voltage gate-source
547  double vgd, // initial voltage gate-drain
548  double vgb, // initial voltage gate-bulk
549  double von,
550  double vdsat,
551  double & capgs, // non-constant portion of g-s overlap capacitance
552  double & capgd, // non-constant portion of g-d overlap capacitance
553  double & capgb, // non-constant portion of g-b overlap capacitance
554  double phi,
555  double cox // oxide capactiance
556  )
557 {
558  double vds;
559  double vddif;
560  double vddif1;
561  double vddif2;
562  double vgst;
563 
564  //double vgdt;
565  //double vdenom;
566  //double vdenom2;
567 
568 
569  vgst = vgs-von;
570  if (vgst <= -phi)
571  {
572  capgb = cox/2;
573  capgs = 0;
574  capgd = 0;
575  }
576  else if (vgst <= -phi/2)
577  {
578  capgb = -vgst*cox/(2*phi);
579  capgs = 0;
580  capgd = 0;
581  }
582  else if (vgst <= 0)
583  {
584  capgb = -vgst*cox/(2*phi);
585  capgs = vgst*cox/(1.5*phi)+cox/3;
586  capgd = 0;
587  }
588  else
589  {
590  vds = vgs-vgd;
591  if (vdsat <= vds)
592  {
593  capgs = cox/3;
594  capgd = 0;
595  capgb = 0;
596  }
597  else
598  {
599 
600  vddif = 2.0*vdsat-vds;
601  vddif1 = vdsat-vds/*-1.0e-12*/;
602  vddif2 = vddif*vddif;
603  capgd = cox*(1.0-vdsat*vdsat/vddif2)/3;
604  capgs = cox*(1.0-vddif1*vddif1/vddif2)/3;
605  capgb = 0;
606 
607 
608  //vgdt = vgd-von;
609  //vdenom=vgst + vgdt;
610  //vdenom2=vdenom*vdenom;
611 
612  //capgd = cox*(1.0-vgst*vgst/vdenom2)/3.0;
613  //capgs = cox*(1.0-vgdt*vgdt/vdenom2)/3.0;
614 
615  }
616  }
617 
618 }
619 
620 //-----------------------------------------------------------------------------
621 // Function : DeviceSupport::qmeyerderivs
622 // Purpose : Computes the partial derivatives of the Meyer capacitances
623 // with respect to various voltages.
624 //
625 // Special Notes : We need this in order to make the Meyer model MPDE
626 // compatible.
627 //
628 // Scope : public
629 // Creator : Keith R. Santarelli, SNL, Electrical & Microsystems Modeling
630 // Creation Date : 02/08/08
631 //-----------------------------------------------------------------------------
632 
634  (
635  double vgs, // initial voltage gate-source
636  double vgd, // initial voltage gate-drain
637  double vgb, // initial voltage gate-bulk
638  double von,
639  double vdsat,
640  double & dcapgsdvgs, //partial deriv. of capgs with respect to vgs
641  double & dcapgsdvgb, //partial deriv. of capgs with respect to vgb
642  double & dcapgsdvgd, //partial deriv. of capgs with respect to vgd
643  double & dcapgddvgs, //partial deriv. of capgd with respect to vgs
644  double & dcapgddvgb, //partial deriv. of capgd with respect to vgb
645  double & dcapgddvgd, //partial deriv. of capgd with respect to vgd
646  double & dcapgbdvgs, //partial deriv. of capgb with respect to vgs
647  double & dcapgbdvgb, //partial deriv. of capgb with respect to vgb
648  double & dcapgbdvgd, //partial deriv. of capgb with respect to vgd
649  double phi,
650  double cox, // oxide capactiance
651  int Dtype //transistor type
652  )
653 {
654  double vgst;
655  double vds;
656  double vdenom, vdenom3;
657  double vgdt;
658 
659  vgst = vgs-von;
660  if (vgst <= -phi)
661  {
662  dcapgsdvgs=0;
663  dcapgsdvgb=0;
664  dcapgsdvgd=0;
665  dcapgddvgs=0;
666  dcapgddvgb=0;
667  dcapgddvgd=0;
668  dcapgbdvgs=0;
669  dcapgbdvgb=0;
670  dcapgbdvgd=0;
671 
672  }
673  else if (vgst <= -phi/2)
674  {
675  dcapgsdvgs=0;
676  dcapgsdvgb=0;
677  dcapgsdvgd=0;
678  dcapgddvgs=0;
679  dcapgddvgb=0;
680  dcapgddvgd=0;
681  dcapgbdvgs=-1.0*cox/(2.0*phi);
682  dcapgbdvgb=0;
683  dcapgbdvgd=0;
684  }
685  else if (vgst <= 0)
686  {
687  dcapgsdvgs=cox/(1.5*phi);
688  dcapgsdvgb=0;
689  dcapgsdvgd=0;
690  dcapgddvgs=0;
691  dcapgddvgb=0;
692  dcapgddvgd=0;
693  dcapgbdvgs=-1.0*cox/(2.0*phi);
694  dcapgbdvgb=0;
695  dcapgbdvgd=0;
696  }
697  else
698  {
699  vds = vgs-vgd;
700  if (vdsat <= vds)
701  {
702  dcapgsdvgs=0;
703  dcapgsdvgb=0;
704  dcapgsdvgd=0;
705  dcapgddvgs=0;
706  dcapgddvgb=0;
707  dcapgddvgd=0;
708  dcapgbdvgs=0;
709  dcapgbdvgb=0;
710  dcapgbdvgd=0;
711  }
712  else
713  {
714  vgdt = vgd-von;
715  vdenom=vgst + vgdt;
716  vdenom3=vdenom*vdenom*vdenom;
717 
718  dcapgsdvgs=4.0/3.0*cox*vgdt*vgdt/vdenom3;
719  dcapgsdvgb=0;
720  dcapgsdvgd=-4.0/3.0*cox*vgst*vgdt/vdenom3;
721  dcapgddvgs=-4.0/3.0*cox*vgst*vgdt/vdenom3;
722  dcapgddvgb=0;
723  dcapgddvgd=4.0/3.0*cox*vgst*vgst/vdenom3;
724  dcapgbdvgs=0;
725  dcapgbdvgb=0;
726  dcapgbdvgd=0;
727 
728  }
729  }
730 
731  //Now have to "type-ize" the cap. derivatives:
732 
733  //dcapgsdvgs=Dtype*dcapgsdvgs;
734  //dcapgsdvgb=Dtype*dcapgsdvgb;
735  //dcapgsdvgd=Dtype*dcapgsdvgd;
736  //dcapgddvgs=Dtype*dcapgddvgs;
737  //dcapgddvgb=Dtype*dcapgddvgb;
738  //dcapgddvgd=Dtype*dcapgddvgd;
739  //dcapgbdvgs=Dtype*dcapgbdvgs;
740  //dcapgbdvgb=Dtype*dcapgbdvgb;
741  //dcapgbdvgd=Dtype*dcapgbdvgd;
742 }
743 
744 
745 
746 #ifdef notdef
747 
748 //-----------------------------------------------------------------------------
749 // Function : DeviceSupport::cap
750 // Purpose : compute equivalent conductances
751 // divide up the channel charge (1-xqc)/xqc to
752 // source and drain
753 //
754 // Special Notes : XXX This is no longer used, apparently
755 //
756 // Scope : public
757 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
758 // Creation Date : 01/17/01
759 //-----------------------------------------------------------------------------
760 void DeviceSupport::cap (
761  register CKTcircuit *ckt,
762  double vgd,
763  double vgs,
764  double vgb,
765  double covlgd,
766  double covlgs,
767  double covlgb,
768  double capbd,
769  double capbs,
770  double cggb,
771  double cgdb,
772  double cgsb,
773  double cbgb,
774  double cbdb,
775  double cbsb,
776  double *gcggb,
777  double *gcgdb,
778  double *gcgsb,
779  double *gcbgb,
780  double *gcbdb,
781  double *gcbsb,
782  double *gcdgb,
783  double *gcddb,
784  double *gcdsb,
785  double *gcsgb,
786  double *gcsdb,
787  double *gcssb,
788  double qgate,
789  double qchan,
790  double qbulk,
791  double *qdrn,
792  double *qsrc,
793  double xqc)
794 {
795  double gcd;
796  double gcdxd;
797  double gcdxs;
798  double gcg;
799  double gcgxd;
800  double gcgxs;
801  double gcs;
802  double gcsxd;
803  double gcsxs;
804  double qgb;
805  double qgd;
806  double qgs;
807 
808  gcg = (cggb+cbgb)*ckt->CKTag[1];
809  gcd = (cgdb+cbdb)*ckt->CKTag[1];
810  gcs = (cgsb+cbsb)*ckt->CKTag[1];
811  gcgxd = -xqc*gcg;
812  gcgxs = -(1-xqc)*gcg;
813  gcdxd = -xqc*gcd;
814  gcdxs = -(1-xqc)*gcd;
815  gcsxd = -xqc*gcs;
816  gcsxs = -(1-xqc)*gcs;
817  *gcdgb = gcgxd-covlgd*ckt->CKTag[1];
818  *gcddb = gcdxd+(capbd+covlgd)*ckt->CKTag[1];
819  *gcdsb = gcsxd;
820  *gcsgb = gcgxs-covlgs*ckt->CKTag[1];
821  *gcsdb = gcdxs;
822  *gcssb = gcsxs+(capbs+covlgs)*ckt->CKTag[1];
823  *gcggb = (cggb+covlgd+covlgs+covlgb)*ckt->CKTag[1];
824  *gcgdb = (cgdb-covlgd)*ckt->CKTag[1];
825  *gcgsb = (cgsb-covlgs)*ckt->CKTag[1];
826  *gcbgb = (cbgb-covlgb)*ckt->CKTag[1];
827  *gcbdb = (cbdb-capbd)*ckt->CKTag[1];
828  *gcbsb = (cbsb-capbs)*ckt->CKTag[1];
829  /*
830  * compute total terminal charges
831  */
832  qgd = covlgd*vgd;
833  qgs = covlgs*vgs;
834  qgb = covlgb*vgb;
835  qgate = qgate+qgd+qgs+qgb;
836  qbulk = qbulk-qgb;
837  *qdrn = xqc*qchan-qgd;
838  *qsrc = (1-xqc)*qchan-qgs;
839  /*
840  * finished
841  */
842 }
843 #endif
844 
845 #if 0
846 double DeviceSupport::pred
847  (
848  CKTcircuit *ckt,
849  int loct
850  )
851 {
852 
853  /* predict a value for the capacitor at loct by
854  * extrapolating from previous values
855  */
856 
857 #ifndef NEWTRUNC
858  double xfact;
859  xfact = ckt->CKTdelta/ckt->CKTdeltaOld[1];
860  return( ( (1+xfact) * *(ckt->CKTstate1+loct) ) -
861  ( xfact * *(ckt->CKTstate2+loct) ) );
862 #endif /*NEWTRUNC*/
863 
864 }
865 #endif
866 
867 //-----------------------------------------------------------------------------
868 // Function : DeviceSupport::contVds
869 // Purpose : continuation adjustment for MOSFET drain-source voltage.
870 //
871 // Special Notes : min*vds is the value returned for vds when alpha=0.
872 //
873 // This idea is based, loosely, on a paper by Jaijeet
874 // Rosychowdhury.
875 //
876 // Scope : public
877 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
878 // Creation Date : 09/04/03
879 //-----------------------------------------------------------------------------
880 double DeviceSupport::contVds (double vds, double alpha, double min)
881 {
882  if (min <= 0.0) min = 0.3;
883  return ( vds * (alpha*(1.0-min) + min) );
884 }
885 
886 //-----------------------------------------------------------------------------
887 // Function : DeviceSupport::contVgst
888 // Purpose : continuation adjustment for MOSFET drain-source voltage.
889 //
890 // Special Notes : vgstConst is the value returned for vgst when alpha=0.
891 //
892 // This idea is based, loosely, on a paper by Jaijeet
893 // Rosychowdhury.
894 //
895 // The alpha=0 condition, for which vgs, or vgst is
896 // considered constant, essentially makes the device a
897 // single-state device. No matter what actual voltage is
898 // applied across Vg-Vs, the device will act as though
899 // there is a fixed applied voltage. If vgstconst is set
900 // to a high voltage (like the default, 3.0) then the
901 // devices are all in an "on" state for alpha=0. If
902 // vgstconst is set to zero, then the devices are all in an
903 // off state for alpha=0.
904 //
905 // As the alpha parameter is swept from zero to 1, at some
906 // point the MOSFET will start behaving, functionally like
907 // a MOSFET. At alpha=0, it doesn't - it kind of acts like
908 // a capacitor. At what point in the sweep this
909 // functionality kicks in, depends on the point at which
910 // the Ids vs Vgs curve has an intersection with Ids=0, for
911 // reasonable values of Vgs. (reasonable values probably
912 // being -1 to +5 volts)
913 //
914 // If Vgstconst is set to zero, this intersection happens
915 // immediately, on the first step where alpha is nonzero.
916 // If Vgstconst is fairly high (say 4.0 volts), this
917 // intersection happens late. If it is too high, it never
918 // happens.
919 //
920 // Unfortunately, during the sweep, once it kicks in, it
921 // kicks in for every MOSFET almost all at once, and there
922 // is a sharp transition in the continuation curve. The
923 // trick to making this homotopy work well, is to make this
924 // transition as gentle as possible, I think.
925 //
926 // Scope : public
927 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
928 // Creation Date : 09/04/03
929 //-----------------------------------------------------------------------------
931  (double vgst, double alpha, double vgstConst)
932 {
933  return ((alpha)*vgst + (1.0-alpha)*vgstConst);
934 }
935 
936 //-----------------------------------------------------------------------------
937 // Function : DeviceSupport::getGainScaleBlockID
938 // Purpose : determines which block to associate the mosfet device
939 // This is used for a multi-block gainscale continuation.
940 // Scope : public
941 // Creator : Roger Pawlowski, SNL
942 // Creation Date : 01/28/05
943 //-----------------------------------------------------------------------------
945 {
946  double val = u.RandomDouble();
947 
948  // get rid of negatives
949  val = val * val;
950  val = sqrt(val);
951 
952  double interval = 1.0 / numBlocks;
953 
954  for (int i = 0; i < numBlocks; ++i) {
955  double lowBound = ((double) i) * interval;
956  double highBound = ((double) (i+1)) * interval;
957  if ((val >= lowBound) && (val < highBound)) {
958  return i;
959  }
960  }
961 
962  return (numBlocks-1);
963 }
964 
965 //-----------------------------------------------------------------------------
966 // Function : DeviceSupport::getGainScaleBlockID
967 // Purpose : computes random perturbation for stretched homotopy.
968 // Scope : public
969 // Creator : Roger Pawlowski, SNL
970 // Creation Date : 01/28/05
971 //-----------------------------------------------------------------------------
973 {
974  double val = u.RandomDouble();
975  val = val * val;
976  val = sqrt(val);
977  return val;
978 }
979 
980 //-----------------------------------------------------------------------------
981 // Function : DeviceSupport::getGainScaleBlockID
982 // Purpose : sets seed for random number generator used in getRandomPerturbation().
983 // Scope : public
984 // Creator : Richard Schie, Electrical Systems Modeling
985 // Creation Date : 10/01/12
986 //-----------------------------------------------------------------------------
987 int DeviceSupport::SetSeed(unsigned int seedIn)
988 {
989  int retVal = u.SetSeed( seedIn );
990  return retVal;
991 }
992 
993 //-----------------------------------------------------------------------------
994 // Function : DeviceSupport::Xexp
995 //
996 // Purpose : Exponential function with range checking and truncation
997 // for improved convergence when searching for DCOP
998 //
999 // Special Notes : This function provides a Taylor series approximation
1000 // to an exponential (out to N=order terms),
1001 // unless order >=20, in which case it just returns an
1002 // exponential.
1003 //
1004 // Scope : public
1005 //
1006 // Creator : Dave Shirley, PSSI
1007 // Creation Date : 01/13/06
1008 //-----------------------------------------------------------------------------
1009 double DeviceSupport::Xexp(double X, double &ddX, double order)
1010 {
1011  if (X > CONSTMAX_EXP_ARG)
1012  {
1013  X = CONSTMAX_EXP_ARG;
1014  }
1015 #if 1
1016  if (order > 19.999)
1017  {
1018  ddX=exp(X);
1019  return ddX;
1020  }
1021  int i, ord;
1022  double ans, term;
1023 
1024  double base;
1025 
1026  // It is very important to return and use the correct derivative, otherwise
1027  // conductances are not correct.
1028  {
1029  term = 1;
1030  ans = 1;
1031  ddX = 1;
1032  ord = static_cast<int>( order );
1033  for (i=1 ; i<=ord ; ++i)
1034  {
1035  term *= X/i;
1036  ans += term;
1037  if (i<ord)
1038  {
1039  ddX += term;
1040  }
1041  }
1042  // If we are partway between two integer orders "ord", linear combination
1043  // of the order=ord and order=ord+1 series.
1044  if (order > ord)
1045  {
1046  ddX += (order-ord)*term;
1047  term *= X/(ord+1);
1048  ans += (order-ord)*term;
1049  }
1050  }
1051  return ans;
1052 #else
1053 
1054  // An attempt at a lambertw replacement of the exponential.
1055  // At the moment it is not as effective a homotopy as the taylor series.
1056  // For NAND chains longer than 276 it starts to have big trouble around
1057  // order 9, getting NaN's in the RHS.
1058  if (order > 19.999)
1059  {
1060  ddX=exp(X);
1061  return ddX;
1062  }
1063 
1064  double rs,wreturn,xi;
1065  int i,ierr;
1066  // rs=1e-{order}
1067  rs=pow(10.0,-order);
1068  lambertw(rs*exp(X+rs),wreturn,ierr,xi);
1069  if (ierr != 0)
1070  {
1071  ddX = exp(X);
1072  return (ddX);
1073  }
1074  else
1075  {
1076  ddX = wreturn/(1+wreturn)/rs;
1077  return (wreturn/rs);
1078  }
1079 #endif
1080 }
1081 
1082 //-----------------------------------------------------------------------------
1083 // Function : DeviceSupport::finiteNumberTest
1084 //
1085 // Purpose : The motivation for this function is that as of
1086 // this writing, it is possible for some of the MOSFET
1087 // models to pass in Nan's for the "von" parameter.
1088 //
1089 // Special Notes : This is copied over from a similar
1090 // function in the nonlinear solver.
1091 //
1092 // Scope : public
1093 // Creator : Eric Keiter, SNL.
1094 // Creation Date : 01/05/07
1095 //-----------------------------------------------------------------------------
1097 {
1098 #if( defined HAVE_NAN_INF_SUPPORT || defined HAVE__ISNAN_AND__FINITE_SUPPORT )
1099  if (isnan(x))
1100  return -1;
1101 
1102  if (isinf(x))
1103  return -2;
1104 
1105 #else
1106 
1107  // Can pretty much use any number here
1108  double tol = 1.0e-6;
1109 
1110  // NaN check
1111  if (!(x <= tol) && !(x > tol))
1112  return -1;
1113 
1114  // Inf check:
1115  // Use the fact that: Inf * 0 = NaN
1116  double z = 0.0 * x;
1117  if (!(z <= tol) && !(z > tol))
1118  return -2;
1119 
1120 #endif
1121 
1122  return 0;
1123 }
1124 
1125 //-----------------------------------------------------------------------------
1126 // Function : DeviceSupport::spline
1127 // Purpose :
1128 // Special Notes : This method adapted from "Numerical Recipes in C++"
1129 // Scope : public
1130 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1131 // Creation Date : 4/12/06
1132 //-----------------------------------------------------------------------------
1134  std::vector<double> & x,
1135  std::vector<double> & y,
1136  std::vector<double> & y2)
1137 {
1138  double p=0;
1139  double qn=0;
1140  double sig=0;
1141  double un=0;
1142 
1143  int n = y2.size();
1144  std::vector<double> u(n-1,0.0);
1145 
1146  // Setting the upper and lower boundary conditions to a
1147  // "natural boundary condition".
1148  y2[0] = 0.0;
1149  y2[n-1] = 0.0;
1150 
1151  // This is the decomposition loop of the tridiagonal
1152  // algorithm. y2 and u are used for temporary storage
1153  // of the decomposed factors.
1154  for (int i=1; i<n-1; i++)
1155  {
1156  sig = (x[i]-x[i-1])/(x[i+1]-x[i-1]);
1157  p = sig*y2[i-1] + 2.0;
1158  y2[i] = (sig-1.0)/p;
1159  u[i] = (y[i+1]-y[i])/(x[i+1]-x[i]) -
1160  (y[i]-y[i-1])/(x[i]-x[i-1]);
1161  u[i] = (6.0*u[i]/(x[i+1]-x[i-1]) - sig*u[i-1])/p;
1162  }
1163 
1164  for (int l=n-2; l>=0; l--)
1165  {
1166  y2[l] = y2[l]*y2[l+1]+u[l];
1167  }
1168 }
1169 
1170 //-----------------------------------------------------------------------------
1171 // Function : DeviceSupport::splint
1172 // Purpose :
1173 // Special Notes : This method adapted from "Numerical Recipes in C++"
1174 // Scope : public
1175 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1176 // Creation Date : 4/12/06
1177 //-----------------------------------------------------------------------------
1179  std::vector<double> & xa,
1180  std::vector<double> & ya,
1181  std::vector<double> & y2a,
1182  double x_position,
1183  double & y_spline)
1184 {
1185  // This method taken from "Numerical Recipes in C++"
1186  int n = xa.size();
1187  // Find the right place in the table by means of bisection.
1188  double h = 0.0;
1189  double a = 0.0;
1190  double b = 0.0;
1191  int k = 0;
1192  int klo = 0;
1193  int khi = n-1;
1194  while (khi-klo > 1)
1195  {
1196  k = (khi+klo) >> 1;
1197  if (xa[k] > x_position) khi=k;
1198  else klo=k;
1199  }
1200 
1201  h = xa[khi] - xa[klo];
1202  if (h == 0.0)
1203  {
1204  //std::string err_msg =
1205  //"Bad input to cubic spline.";
1206  //throw charon::Exception("This shouldn't happen! Please notify "
1207  //"developers!", __FILE__, __LINE__);
1208 
1209  exit (0);
1210  }
1211  a = (xa[khi] - x_position)/h;
1212  b = (x_position - xa[klo])/h;
1213  // cubic spline polynomial is now evaluated
1214  y_spline = a*ya[klo]+b*ya[khi]+((a*a*a-a)*y2a[klo] + (b*b*b-b)*y2a[khi])*(h*h)/6.0;
1215 
1216 
1217  // capping the spline value so that it doesn't extend
1218  // the bounds of the endpoints
1219  // this prevents wiggles and non-physical values
1220  if ( (y_spline > ya[klo]) && (y_spline > ya[khi]) )
1221  {
1222  if (ya[klo] > ya[khi]) y_spline = ya[klo];
1223  else y_spline = ya[khi];
1224  }
1225 
1226  if ( (y_spline < ya[klo]) && (y_spline < ya[khi]) )
1227  {
1228  if (ya[klo] < ya[khi]) y_spline = ya[klo];
1229  else y_spline = ya[khi];
1230  }
1231 
1232 }
1233 
1234 } // namespace Device
1235 } // namespace Xyce