Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_BernouliSupport.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_BernouliSupport.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 08/01/04
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.22 $
40 //
41 // Revision Date : $Date: 2014/02/24 23:49:18 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 
49 // ---------- Standard Includes ----------
50 #ifdef Xyce_DEBUG_DEVICE
51 #include <iostream>
52 #endif
53 
54 #ifdef HAVE_CMATH
55 #include <cmath>
56 #else
57 #include <math.h>
58 #endif
59 
60 
61 #ifdef HAVE_CSTDIO
62 #include <cstdio>
63 #else
64 #include <stdio.h>
65 #endif
66 
67 // ---------- Xyce Includes ----------
68 #include <N_DEV_BernouliSupport.h>
69 #include <N_ERH_ErrorMgr.h>
70 
71 // These are the old Bernouli breakpoint numbers. They were generated
72 // using the SGF program brkpnts.c . They are appropriate for linux
73 // They should be removed soon, as Xyce can generate these internally now.
74 #define BP0_BERN -3.742945958815751e+01
75 #define BP1_BERN -1.948848145621305e-02
76 #define BP2_BERN 1.230611609815494e-02
77 #define BP3_BERN 3.742945958815751e+01
78 #define BP4_BERN 7.451332191019408e+02
79 #define BP0_DBERN -4.117119704160766e+01
80 #define BP1_DBERN -3.742945958815751e+01
81 #define BP2_DBERN -1.848271746976161e-02
82 #define BP3_DBERN 8.806697697210611e-03
83 #define BP4_DBERN 3.742945958815751e+01
84 #define BP5_DBERN 7.451332191019408e+02
85 #define BP0_AUX1 -8.301056680276218e-03
86 #define BP1_AUX1 8.301056680276218e-03
87 #define BP0_DAUX1 -4.826242066078996e-03
88 #define BP1_DAUX1 4.826242066078996e-03
89 #define BP0_AUX2 -4.436141955583643e+01
90 #define BP1_AUX2 3.680808162809191e+01
91 #define BP2_AUX2 7.451332191019419e+02
92 #define BP0_DAUX2 -7.451332191019419e+02
93 #define BP1_DAUX2 -4.436141955583643e+01
94 #define BP2_DAUX2 3.680808162809191e+01
95 #define BP3_DAUX2 7.451332191019419e+02
96 #define BP0_MISC 7.097827128183643e+02
97 
98 // Other defines. MAXDOUBLE is probably set up elsewhere in Xyce - check this.
99 #define PRECISION 1.0e-15
100 #define MAX_ITERATIONS 100
101 
102 #ifndef MAXDOUBLE
103 #define MAXDOUBLE 1.797693E+308
104 #endif
105 
106 namespace Xyce {
107 namespace Device {
108 
109 namespace {
110 
111 // ERK, 8/1/2004: I would prefer to just put these functions inside of the
112 // Bernouli support
113 // class, but the functions Bisection, Asymtotic and Secant all rely on
114 // function pointers, and function pointers are a lot easier to use if the
115 // functions they point to are old-fashioned C functions.
116 //
117 // The brkpnts.c program, which is in C, rather than C++ had a very C-oriented
118 // style. I haven't had time to move this stuff closer to a C++ style.
119 
120 double Bbp0a(double x) { return exp(x) - 1.0; }
121 double Bbp0b(double x) { return - 1.0; }
122 
123 double Bbp1a(double x) { return x / (exp(x) - 1.0); }
124 double Bbp1b(double x)
125 {
126  return 1.0 - x/2.0 * (1.0 - x/6.0 * (1.0 - x*x/60.0));
127 }
128 
129 double Bbp2a(double x)
130 {
131  return 1.0 - x/2.0 * (1.0 - x/6.0 * (1.0 - x*x/60.0));
132 }
133 
134 double Bbp2b(double x)
135 {
136  return x * exp(-x) / (1.0 - exp(-x));
137 }
138 
139 double Bbp3a(double x) { return 1.0 - exp(-x); }
140 double Bbp3b(double x) { return 1.0; }
141 
142 double Bbp4a(double x) { return x * exp(-x); }
143 double Bbp4b(double x) { return 0.0; }
144 
145 double dBbp0a(double x) { return (1.0 - x) * exp(x) - 1.0; }
146 double dBbp0b(double x) { return -1.0; }
147 
148 double dBbp2a(double x)
149 {
150  return ((1.0 - x) * exp(x) - 1.0) / ((exp(x) - 1.0) * (exp(x) - 1.0));
151 }
152 
153 double dBbp2b(double x) { return -0.5 + x/6.0 * (1.0 - x*x/30.0); }
154 
155 double dBbp3a(double x) { return -0.5 + x/6.0 * (1.0 - x*x/30.0); }
156 double dBbp3b(double x)
157 {
158  return (exp(-x)*(1.0 - x) - exp(-2.0 * x))/((1.0 - exp(-x))*(1.0 - exp(-x)));
159 }
160 
161 double dBbp5a(double x) { return exp(-x) * (1.0 - x) - exp(-2.0 * x); }
162 double dBbp5b(double x) { return 0.0; }
163 
164 double AUX1bp0a(double x) { return x / sinh(x); }
165 double AUX1bp0b(double x) { return 1.0 - x*x/6.0 * (1.0 - 7.0*x*x/60.0); }
166 
167 double dAUX1bp0a(double x)
168 {
169  return (sinh(x) - x*cosh(x)) / (sinh(x) * sinh(x));
170 }
171 
172 double dAUX1bp0b(double x) { return -x/3.0 * (1.0 - 7*x*x/30.0); }
173 
174 double AUX2bp0a(double x) { return 1.0; }
175 double AUX2bp0b(double x) { return 1.0 + exp(x); }
176 
177 double AUX2bp1a(double x) { return 1.0 + exp(x); }
178 double AUX2bp1b(double x) { return exp(x); }
179 
180 double AUX2bp2a(double x) { return exp(-x); }
181 double AUX2bp2b(double x) { return 0.0; }
182 
183 double dAUX2bp0a(double x) { return exp(x); }
184 double dAUX2bp0b(double x) { return 0.0; }
185 
186 } // namespace <empty>
187 
188 //-----------------------------------------------------------------------------
189 // Function : BernouliSupport::BernouliSupport
190 // Purpose : constructor.
191 // Special Notes :
192 // Scope : public
193 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
194 // Creation Date : 08/01/04
195 //-----------------------------------------------------------------------------
197  // use the numbers generated by brkpnts.c (for a single platform, linux)
198  // bernouli function breakpoints:
199  bp0_BERN ( BP0_BERN ),
200  bp1_BERN ( BP1_BERN ),
201  bp2_BERN ( BP2_BERN ),
202  bp3_BERN ( BP3_BERN ),
203  bp4_BERN ( BP4_BERN ),
204 
205  // bernouli derivative function breakpoints:
206  bp0_DBERN ( BP0_DBERN ),
207  bp1_DBERN ( BP1_DBERN ),
208  bp2_DBERN ( BP2_DBERN ),
209  bp3_DBERN ( BP3_DBERN ),
210  bp4_DBERN ( BP4_DBERN ),
211  bp5_DBERN ( BP5_DBERN ),
212 
213  // aux1 function breakpoints:
214  bp0_AUX1 ( BP0_AUX1 ),
215  bp1_AUX1 ( BP1_AUX1 ),
216 
217  // aux1 derivative function breakpoints:
218  bp0_DAUX1 ( BP0_DAUX1 ),
219  bp1_DAUX1 ( BP1_DAUX1 ),
220 
221  // aux2 function breakpoints:
222  bp0_AUX2 ( BP0_AUX2 ),
223  bp1_AUX2 ( BP1_AUX2 ),
224  bp2_AUX2 ( BP2_AUX2 ),
225 
226  // aux2 derivative function breakpoints:
227  bp0_DAUX2 ( BP0_DAUX2 ),
228  bp1_DAUX2 ( BP1_DAUX2 ),
229  bp2_DAUX2 ( BP2_DAUX2 ),
230  bp3_DAUX2 ( BP3_DAUX2 ),
231 
232  // This is supposed to be the log of MAXDOUBLE.
233  bp0_MISC ( BP0_MISC )
234 {
235  // using the hardwired numbers b/c the calculated numbers do not work
236  // on the alpha.
237 #define Xyce_NEW_BERN_CALCULATION 1
238 #ifndef Xyce_NEW_BERN_CALCULATION
239  // generate breakpoints internally. This is better as it will be specific to
240  // the current platform.
241 
242 #if 0
243  // Bernouli breakpoints:
244  // these are commented out b/c they aren't needed, and they seem to
245  // cause problems on OSX. I don't know why...
246  bp0_BERN = Asymptotic(Bbp0a, Bbp0b, 0.0e+00, -1.0e+02);
247  bp1_BERN = Secant (Bbp1a, Bbp1b, -1.0e+00);
248  bp2_BERN = Secant (Bbp2a, Bbp2b, +1.0e+00);
249  bp3_BERN = Asymptotic(Bbp3a, Bbp3b, 0.0e+00, +1.0e+02);
250  bp4_BERN = Asymptotic(Bbp4a, Bbp4b, 1.0e+00, +1.0e+03);
251 
252  // Bernouli derivative breakpoints:
253  bp0_DBERN = Asymptotic(dBbp0a, dBbp0b, 0.0e+00, -1.0e+02);
255  bp2_DBERN = Secant (dBbp2a, dBbp2b, -1.0e+00);
256 //bp2_DBERN = Bisection (dBbp2a, dBbp2b, dB[1], -1.0e-6);
257  bp3_DBERN = Secant (dBbp3a, dBbp3b, +1.0e+00);
259  bp5_DBERN = Asymptotic(dBbp5a, dBbp5b, 1.0e+00, +1.0e+03);
260 #endif
261 
262  // Aux1 breakpoints:
263  bp0_AUX1 = Secant(AUX1bp0a, AUX1bp0b, -1.0e+00);
264  bp1_AUX1 = Secant(AUX1bp0a, AUX1bp0b, 1.0e+00);
265 
266  // Aux1 derivative breakpoints:
267  bp0_DAUX1 = Secant(dAUX1bp0a, dAUX1bp0b, -1.0e+00);
268  bp1_DAUX1 = Secant(dAUX1bp0a, dAUX1bp0b, 1.0e+00);
269 
270  // Aux2 breakpoints:
271  bp0_AUX2 = Asymptotic(AUX2bp0a, AUX2bp0b, 0.0e+00, -1.0e+02);
272  bp1_AUX2 = Asymptotic(AUX2bp1a, AUX2bp1b, 0.0e+00, 1.0e+02);
273  bp2_AUX2 = Asymptotic(AUX2bp2a, AUX2bp2b, 0.0e+00, 1.0e+02);
274 
275  // Aux2 derivative breakpoints:
276  bp0_DAUX2 = Asymptotic(dAUX2bp0a, dAUX2bp0b, 0.0e+00, -1.0e+02);
280 
281  // miscellaneous
282  bp0_MISC = log(MAXDOUBLE);
283 #endif
284 
285 #ifdef Xyce_DEBUG_DEVICE
286 #if 0
287  Xyce::dout() << Xyce::section_divider << std::endl;
288  Xyce::dout().width(21); Xyce::dout().precision(13); Xyce::dout().setf(std::ios::scientific);
289  Xyce::dout() << std::endl;
290  Xyce::dout() << "Bernouli function breakpoints: " <<endl;
291  Xyce::dout() << "bp0_AUX1 = " << bp0_AUX1 << std::endl;
292  Xyce::dout() << "bp1_AUX1 = " << bp1_AUX1 << std::endl;
293  Xyce::dout() << "bp0_DAUX1 = " << bp0_DAUX1 << std::endl;
294  Xyce::dout() << "bp1_DAUX1 = " << bp1_DAUX1 << std::endl;
295 
296  Xyce::dout() << "bp0_AUX2 = " << bp0_AUX2 << std::endl;
297  Xyce::dout() << "bp1_AUX2 = " << bp1_AUX2 << std::endl;
298  Xyce::dout() << "bp2_AUX2 = " << bp2_AUX2 << std::endl;
299  Xyce::dout() << "bp0_DAUX2 = " << bp0_DAUX2 << std::endl;
300  Xyce::dout() << "bp1_DAUX2 = " << bp1_DAUX2 << std::endl;
301  Xyce::dout() << "bp2_DAUX2 = " << bp2_DAUX2 << std::endl;
302  Xyce::dout() << "bp3_DAUX2 = " << bp3_DAUX2 << std::endl;
303  Xyce::dout() << "bp0_MISC = " << bp0_MISC << std::endl;
304  Xyce::dout() << Xyce::section_divider << std::endl;
305 #endif
306 #endif
307 }
308 
309 //-----------------------------------------------------------------------------
310 // Function : BernouliSupport::~BernouliSupport
311 // Purpose : constructor.
312 // Special Notes :
313 // Scope : public
314 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
315 // Creation Date : 08/01/04
316 //-----------------------------------------------------------------------------
318 {
319 
320 }
321 
322 //-----------------------------------------------------------------------------
323 // Function : BernouliSupport::BernouliSupport
324 // Purpose : copy constructor.
325 // Special Notes :
326 // Scope : public
327 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
328 // Creation Date : 08/01/04
329 //-----------------------------------------------------------------------------
331  (const BernouliSupport & right)
332 {
333 
334 }
335 
336 //-----------------------------------------------------------------------------
337 // Function : BernouliSupport::BernouliSupport
338 // Purpose : copy constructor.
339 // Special Notes :
340 // Scope : public
341 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
342 // Creation Date : 08/01/04
343 //-----------------------------------------------------------------------------
345 {
346  if (x < 0.0) return(-1);
347  else if (x > 0.0) return(+1);
348  else return(0);
349 }
350 
351 //-----------------------------------------------------------------------------
352 // Function : double BernouliSupport::Bisection
353 // Purpose :
354 // Special Notes :
355 // Scope : public
356 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
357 // Creation Date : 08/01/04
358 //-----------------------------------------------------------------------------
360  (FUNC func1, FUNC func2, double Xpos, double Xneg)
361 {
362  double Fpos = func1(Xpos) - func2(Xpos);
363  double Fneg = func1(Xneg) - func2(Xneg);
364  double Xmid, Fmid, Xlast;
365 
366  if (Fpos == 0.0) return(Xpos);
367  else if (Fneg == 0.0) return(Xneg);
368  else if ((Fpos > 0.0) && (Fneg < 0.0)) ;
369  else if ((Fpos < 0.0) && (Fneg > 0.0))
370  {
371  Xmid = Xpos;
372  Xpos = Xneg;
373  Xneg = Xmid;
374  }
375  else
376  {
377  std::string msg = "BernouliSupport::Bisection ";
378  msg += " Initial interval may not contain a root";
379  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::DEV_FATAL_0,msg);
380  }
381 
382  Xlast = 0.0;
383  do
384  {
385  Xmid = 0.5 * (Xpos + Xneg);
386  Fmid = func1(Xmid) - func2(Xmid);
387  if (Fmid < 0.0) Xneg = Xmid;
388  else if (Fmid > 0.0) Xpos = Xmid;
389  if (Xlast == Xmid) return(Xmid);
390  else Xlast = Xmid;
391  } while (Xneg != Xpos);
392 
393  return(Xmid);
394 
395 }
396 
397 //-----------------------------------------------------------------------------
398 // Function : BernouliSupport::Secant
399 // Purpose :
400 // Special Notes :
401 // Scope : public
402 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
403 // Creation Date : 08/01/04
404 //-----------------------------------------------------------------------------
405 double BernouliSupport::Secant(FUNC func1, FUNC func2, double x1)
406 {
407  double slope, dx, x3, f3;
408  int s3, iteration;
409 
410  double x2 = 0.9 * x1;
411  double f1 = func1(x1) - func2(x1);
412  double f2 = func1(x2) - func2(x2);
413  int s2 = sign(x2);
414 
415  for(;;)
416  {
417  iteration = 0;
418  slope = (f2 - f1) / (x2 - x1);
419  dx = f2 / slope;
420  x3 = x2 - dx;
421  f3 = func1(x3) - func2(x3);
422  s3 = sign(x3);
423 
424  while ((fabs(f3) >= fabs(f2)) || (s3 != s2))
425  {
426  dx /= 2.0;
427  x3 += dx;
428  f3 = func1(x3) - func2(x3);
429  s3 = sign(x3);
430  if (++iteration > MAX_ITERATIONS)
431  {
432  if (fabs(f2) <= 100.0 * PRECISION) return(x2);
433  std::string msg = "BernouliSupport::Secant ";
434  msg += " method not converging.";
435  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::DEV_FATAL_0,msg);
436  }
437  }
438 
439  x1 = x2;
440  x2 = x3;
441  f1 = f2;
442  f2 = f3;
443 
444  if ((fabs(dx / x2) <= PRECISION) || (fabs(f2) <= PRECISION)) break;
445  }
446 
447  return(x3);
448 }
449 
450 //-----------------------------------------------------------------------------
451 // Function : BernouliSupport::Asymptotic
452 // Purpose :
453 // Special Notes :
454 // Scope : public
455 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
456 // Creation Date : 08/01/04
457 //-----------------------------------------------------------------------------
458 double BernouliSupport::Asymptotic(FUNC func1, FUNC func2, double x, double dx)
459 {
460  double test = 1.0;
461  while (1)
462  {
463 
464  if (x==0.0) test = 1.0;
465  else test = fabs(dx/x);
466  if (test <= PRECISION) return(x);
467 
468  while (func1(x) != func2(x))
469  x += dx;
470  dx *= -0.1;
471 
472  if (x==0.0) test = 1.0;
473  else test = fabs(dx/x);
474  if (test <= PRECISION) return(x);
475 
476  while (func1(x) == func2(x))
477  x += dx;
478  dx *= -0.1;
479  }
480 }
481 
482 } // namespace Device
483 } // namespace Xyce