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