Xyce  6.1
N_DEV_Interpolators.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_Interpolators.h,v $
27 //
28 // Purpose : Interpolator classes
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 01/31/12
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.11 $
40 //
41 // Revision Date : $Date: 2015/04/08 19:18:22 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-----------------------------------------------------------------------------
45 
46 #ifndef Xyce_N_DEV_Interpolators_h
47 #define Xyce_N_DEV_Interpolators_h
48 
49 #include <N_UTL_Math.h>
50 
51 #include <Sacado.hpp>
52 
53 namespace Xyce {
54 namespace Device {
55 
56 //-----------------------------------------------------------------------------
57 // Class : interpolator base class
58 // Purpose :
59 // Special Notes :
60 // Creator : Eric Keiter, SNL
61 // Creation Date : 1/31/2012
62 //-----------------------------------------------------------------------------
63 template <typename ScalarT>
65 {
66 public:
68 
69  virtual void clear (){};
70 
71  virtual void init (const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya){};
72 
73  virtual void eval (
74  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
75  const ScalarT & x, ScalarT & y){};
76 
77  virtual void eval_deriv (
78  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
79  const ScalarT & x, ScalarT & dydx){};
80 
81  virtual void eval_deriv2 (
82  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
83  const ScalarT & x, ScalarT & ypp){};
84 
85  virtual void eval_integ (
86  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
87  const ScalarT & a, const ScalarT & b, ScalarT & result){};
88 
89  inline size_t
91  const std::vector<ScalarT> & xa,
92  const ScalarT & x,
93  size_t index_lo,
94  size_t index_hi);
95 
96  inline ScalarT
97  integ_eval (
98  const ScalarT & ai, const ScalarT & bi, const ScalarT & ci,
99  const ScalarT & di, const ScalarT & xi, const ScalarT & a,
100  const ScalarT & b);
101 };
102 
103 //-----------------------------------------------------------------------------
104 // Function : interpolator<ScalarT>::binarySearch
105 //
106 // Purpose : Perform a binary search of an array of values.
107 //
108 // Special Notes : adapted from GSL, version 1.15:
109 //
110 // The parameters index_lo and index_hi provide an initial bracket,
111 // and it is assumed that index_lo < index_hi. The resulting index
112 // is guaranteed to be strictly less than index_hi and greater than
113 // or equal to index_lo, so that the implicit bracket [index, index+1]
114 // always corresponds to a region within the implicit value range of
115 // the value array.
116 //
117 // Note that this means the relationship of 'x' to xa[index]
118 // and xa[index+1] depends on the result region, i.e. the
119 // behaviour at the boundaries may not correspond to what you
120 // expect. We have the following complete specification of the
121 // behaviour.
122 // Suppose the input is xa[] = { x0, x1, ..., xN }
123 // if ( x == x0 ) then index == 0
124 // if ( x > x0 && x <= x1 ) then index == 0, and sim. for other interior pts
125 // if ( x == xN ) then index == N-1
126 // if ( x > xN ) then index == N-1
127 // if ( x < x0 ) then index == 0
128 //
129 // Scope : public
130 // Creator : Eric Keiter, SNL
131 // Creation Date : 01/31/2012
132 // ----------------------------------------------------------------------------
133 template <typename ScalarT>
134 inline size_t
136  const std::vector<ScalarT> & xa,
137  const ScalarT & x,
138  size_t index_lo,
139  size_t index_hi)
140 {
141  size_t ilo = index_lo;
142  size_t ihi = index_hi;
143  while(ihi > ilo + 1)
144  {
145  size_t i = (ihi + ilo)/2;
146  if(xa[i] > x)
147  {
148  ihi = i;
149  }
150  else
151  {
152  ilo = i;
153  }
154  }
155  return ilo;
156 }
157 
158 //-----------------------------------------------------------------------------
159 // Function : interpolator<ScalarT>::integ_eval
160 //
161 // Purpose : function for doing the spline integral evaluation
162 // which is common to both the cspline and akima methods
163 //
164 // Special Notes : adapted from GSL, version 1.15
165 // Scope : public
166 // Creator : Eric Keiter, SNL
167 // Creation Date : 01/31/2012
168 // ----------------------------------------------------------------------------
169 template <typename ScalarT>
170 inline ScalarT
172  const ScalarT & ai,
173  const ScalarT & bi,
174  const ScalarT & ci,
175  const ScalarT & di,
176  const ScalarT & xi,
177  const ScalarT & a,
178  const ScalarT & b)
179 {
180  const ScalarT r1 = a - xi;
181  const ScalarT r2 = b - xi;
182  const ScalarT r12 = r1 + r2;
183  const ScalarT bterm = 0.5 * bi * r12;
184  const ScalarT cterm = (1.0 / 3.0) * ci * (r1 * r1 + r2 * r2 + r1 * r2);
185  const ScalarT dterm = 0.25 * di * r12 * (r1 * r1 + r2 * r2);
186  return (b - a) * (ai + bterm + cterm + dterm);
187 }
188 
189 //-----------------------------------------------------------------------------
190 // Class : akima spline class
191 // Purpose :
192 // Special Notes : adapted from the GNU Scientific library (GSL) version 1.15.
193 // Creator : Eric Keiter, SNL
194 // Creation Date : 1/31/2012
195 //-----------------------------------------------------------------------------
196 template <typename ScalarT>
197 class akima: public interpolator<ScalarT>
198 {
199 public:
200  akima () {};
201 
202  void init ( const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya);
203 
204  void clear () { b.clear(); c.clear(); d.clear(); _m.clear(); };
205 
206  void eval (
207  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
208  const ScalarT & x, ScalarT & y);
209 
210  void eval_deriv (
211  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
212  const ScalarT & x, ScalarT & dydx);
213 
214  void eval_deriv2 (
215  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
216  const ScalarT & x, ScalarT & ypp);
217 
218  void eval_integ (
219  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
220  const ScalarT & a, const ScalarT & b, ScalarT & result);
221 
222  void calc (
223  const std::vector<ScalarT> & xa,
224  std::vector<ScalarT> & b,
225  std::vector<ScalarT> & c,
226  std::vector<ScalarT> & d,
227  std::vector<ScalarT> & m);
228 
229 public:
230  std::vector<ScalarT> b;
231  std::vector<ScalarT> c;
232  std::vector<ScalarT> d;
233  std::vector<ScalarT> _m;
234 };
235 
236 //-----------------------------------------------------------------------------
237 // Function : akima<ScalarT>::calc
238 // Purpose :
239 //
240 // Special Notes : adapted from GSL, version 1.15
241 //
242 // Note that the 'm' indices are offset by 2 on either side of the array,
243 // compared with the x indices. ie, m[2] corresponds to x[0], etc.
244 //
245 // The original GSL implementation used indicies starting at -2 for the
246 // m array, by having the local pointer start at +2. This was to accomodate
247 // boundary conditions. I didn't bother with this as I found it confusing,
248 // and slightly harder to deal with correctly for STL vectors.
249 //
250 // Scope : public
251 // Creator : Eric Keiter, SNL
252 // Creation Date : 1/31/2012
253 // ----------------------------------------------------------------------------
254 template <typename ScalarT>
256  const std::vector<ScalarT> & xa,
257  std::vector<ScalarT> & b,
258  std::vector<ScalarT> & c,
259  std::vector<ScalarT> & d,
260  std::vector<ScalarT> & m)
261 {
262  size_t i;
263  size_t size = xa.size();
264 
265  for (i = 0; i < (size - 1); i++)
266  {
267  const ScalarT NE = std::fabs (m[i + 3] - m[i+2]) + fabs (m[i + 1] - m[i]);
268  if (NE == 0.0)
269  {
270  b[i] = m[i+2];
271  c[i] = 0.0;
272  d[i] = 0.0;
273  }
274  else
275  {
276  const ScalarT h_i = xa[i + 1] - xa[i];
277  const ScalarT NE_next = std::fabs (m[i + 4] - m[i + 3]) + fabs (m[i+2] - m[i + 1]);
278  const ScalarT alpha_i = std::fabs (m[i + 1] - m[i]) / NE;
279  ScalarT alpha_ip1;
280  ScalarT tL_ip1;
281  if (NE_next == 0.0)
282  {
283  tL_ip1 = m[i+2];
284  }
285  else
286  {
287  alpha_ip1 = std::fabs (m[i+2] - m[i + 1]) / NE_next;
288  tL_ip1 = (1.0 - alpha_ip1) * m[i+2] + alpha_ip1 * m[i + 3];
289  }
290  b[i] = (1.0 - alpha_i) * m[i + 1] + alpha_i * m[i+2];
291  c[i] = (3.0 * m[i+2] - 2.0 * b[i] - tL_ip1) / h_i;
292  d[i] = (b[i] + tL_ip1 - 2.0 * m[i+2]) / (h_i * h_i);
293  }
294  }
295 }
296 
297 //-----------------------------------------------------------------------------
298 // Function : akima<ScalarT>::init
299 // Purpose :
300 // Special Notes : adapted from GSL, version 1.15
301 //
302 // Note that the 'm' indices are offset by 2 on either side of the array,
303 // compared with the x indices. ie, m[2] corresponds to x[0], etc.
304 //
305 // Scope : public
306 // Creator : Eric Keiter, SNL
307 // Creation Date : 1/31/2012
308 // ----------------------------------------------------------------------------
309 template <typename ScalarT>
311  const std::vector<ScalarT> & xa,
312  const std::vector<ScalarT> & ya)
313 {
314  size_t size = xa.size();
315 
316  if (b.size() != size) b.resize(size);
317  if (c.size() != size) c.resize(size);
318  if (d.size() != size) d.resize(size);
319  if (_m.size() != size+4) _m.resize(size+4);
320 
321  for (int i = 0; i <= size - 2; i++)
322  {
323  _m[i+2] = (ya[i + 1] - ya[i]) / (xa[i + 1] - xa[i]);
324  }
325 
326  // non-periodic boundary conditions
327  _m[0] = 3.0 * _m[2] - 2.0 * _m[3];
328  _m[1] = 2.0 * _m[2] - _m[3];
329  _m[size + 1] = 2.0 * _m[size] - _m[size-1];
330  _m[size + 2] = 3.0 * _m[size] - 2.0 * _m[size-1];
331 
332  calc (xa, b, c, d, _m);
333 }
334 
335 //-----------------------------------------------------------------------------
336 // Function : akima<ScalarT>::eval
337 // Purpose :
338 // Special Notes : adapted from GSL, version 1.15
339 // Scope : public
340 // Creator : Eric Keiter, SNL
341 // Creation Date : 1/31/2012
342 // ----------------------------------------------------------------------------
343 template <typename ScalarT>
345  const std::vector<ScalarT> & xa,
346  const std::vector<ScalarT> & ya,
347  const ScalarT & x,
348  ScalarT & y)
349 {
350  size_t size = xa.size();
351  size_t index = this->binarySearch (xa, x, 0, size - 1);
352 
353  const ScalarT x_lo = xa[index];
354  const ScalarT delx = x - x_lo;
355  y = ya[index] + delx * (b[index] + delx * (c[index] + d[index] * delx));
356  return;
357 }
358 
359 //-----------------------------------------------------------------------------
360 // Function : akima<ScalarT>::eval_deriv
361 // Purpose :
362 // Special Notes : adapted from GSL, version 1.15
363 // Scope : public
364 // Creator : Eric Keiter, SNL
365 // Creation Date : 1/31/2012
366 // ----------------------------------------------------------------------------
367 template <typename ScalarT>
369  const std::vector<ScalarT> & xa,
370  const std::vector<ScalarT> & ya,
371  const ScalarT & x,
372  ScalarT & dydx)
373 {
374  size_t size = xa.size();
375  size_t index = this->binarySearch (xa, x, 0, size - 1);
376 
377  ScalarT x_lo = xa[index];
378  ScalarT delx = x - x_lo;
379  dydx = b[index] + delx * (2.0 * c[index] + 3.0 * d[index] * delx);
380  return;
381 }
382 
383 //-----------------------------------------------------------------------------
384 // Function : akima<ScalarT>::eval_deriv2
385 // Purpose :
386 // Special Notes : adapted from GSL, version 1.15
387 // Scope : public
388 // Creator : Eric Keiter, SNL
389 // Creation Date : 1/31/2012
390 // ----------------------------------------------------------------------------
391 template <typename ScalarT>
393  const std::vector<ScalarT> & xa,
394  const std::vector<ScalarT> & ya,
395  const ScalarT & x,
396  ScalarT & ypp)
397 {
398  size_t size = xa.size();
399  size_t index = this->binarySearch (xa, x, 0, size - 1);
400 
401  const ScalarT x_lo = xa[index];
402  const ScalarT delx = x - x_lo;
403  ypp = 2.0 * c[index] + 6.0 * d[index] * delx;
404  return;
405 }
406 
407 //-----------------------------------------------------------------------------
408 // Function : akima<ScalarT>::eval_integ
409 // Purpose :
410 // Special Notes : adapted from GSL, version 1.15
411 // Scope : public
412 // Creator : Eric Keiter, SNL
413 // Creation Date : 1/31/2012
414 // ----------------------------------------------------------------------------
415 template <typename ScalarT>
417  const std::vector<ScalarT> & xa,
418  const std::vector<ScalarT> & ya,
419  const ScalarT & ai,
420  const ScalarT & bi,
421  ScalarT & result)
422 {
423  size_t size = xa.size();
424  size_t index_a = this->binarySearch (xa, ai, 0, size - 1);
425  size_t index_b = this->binarySearch (xa, bi, 0, size - 1);
426  result = 0.0;
427 
428  // interior intervals
429  for(size_t i=index_a; i<=index_b; i++)
430  {
431  const ScalarT x_hi = xa[i + 1];
432  const ScalarT x_lo = xa[i];
433  const ScalarT y_lo = ya[i];
434  const ScalarT dx = x_hi - x_lo;
435  if(dx != 0.0)
436  {
437  if (i == index_a || i == index_b)
438  {
439  ScalarT x1 = (i == index_a) ? ai : x_lo;
440  ScalarT x2 = (i == index_b) ? bi : x_hi;
441  result += this->integ_eval (y_lo, b[i], c[i], d[i], x_lo, x1, x2);
442  }
443  else
444  {
445  result += dx * (y_lo + dx*(0.5*b[i] + dx*(c[i]/3.0 + 0.25*d[i]*dx)));
446  }
447  }
448  else
449  {
450  result = 0.0;
451  return;
452  }
453  }
454  return;
455 }
456 
457 //-----------------------------------------------------------------------------
458 // Class : cubic spline class
459 // Purpose :
460 // Special Notes : adapted from Numerical Recipies.
461 // Creator : Eric Keiter, SNL
462 // Creation Date : 1/31/2012
463 //-----------------------------------------------------------------------------
464 template <typename ScalarT>
465 class cubicSpline: public interpolator<ScalarT>
466 {
467 public:
468  cubicSpline () {};
469 
470  void init ( const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya);
471 
472  void clear () { y2.clear(); };
473 
474  void eval (
475  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
476  const ScalarT & x, ScalarT & y);
477 
478  void eval_deriv (
479  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
480  const ScalarT & x, ScalarT & dydx);
481 
482  void eval_deriv2 (
483  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
484  const ScalarT & x, ScalarT & ypp);
485 
486  // not implemented
487  void eval_integ (
488  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
489  const ScalarT & a, const ScalarT & b, ScalarT & result) {};
490 
491 public:
492  std::vector<ScalarT> y2;
493 };
494 
495 //-----------------------------------------------------------------------------
496 // Function : cubicSpline<ScalarT>::init
497 // Purpose :
498 // Special Notes : adapted from Numerical Recipies. This roughly correponds
499 // to the "spline" function, which mainly creates the y2 array.
500 //
501 // Scope : public
502 // Creator : Eric Keiter, SNL
503 // Creation Date : 1/31/2012
504 //-----------------------------------------------------------------------------
505 template <typename ScalarT>
507 (const std::vector<ScalarT> & xa,
508  const std::vector<ScalarT> & ya)
509 {
510  if (y2.size() != xa.size())
511  {
512  y2.resize(xa.size());
513  }
514 
515  ScalarT p=0; ScalarT qn=0; ScalarT sig=0; ScalarT un=0;
516  int n = y2.size(); std::vector <ScalarT> u(n-1,0.0);
517 
518  // Setting the upper and lower boundary conditions to a
519  // "natural boundary condition".
520  y2[0] = 0.0;
521  y2[n-1] = 0.0;
522 
523  // This is the decomposition loop of the tridiagonal
524  // algorithm. y2 and u are used for temporary storage
525  // of the decomposed factors.
526  for (int i=1; i<n-1; i++)
527  {
528  sig = (xa[i]-xa[i-1])/(xa[i+1]-xa[i-1]);
529  p = sig*y2[i-1] + 2.0;
530  y2[i] = (sig-1.0)/p;
531  u[i] = (ya[i+1]-ya[i])/(xa[i+1]-xa[i]) -
532  (ya[i]-ya[i-1])/(xa[i]-xa[i-1]);
533  u[i] = (6.0*u[i]/(xa[i+1]-xa[i-1]) - sig*u[i-1])/p;
534  }
535 
536  for (int l=n-2; l>=0; l--)
537  {
538  y2[l] = y2[l]*y2[l+1]+u[l];
539  }
540 };
541 
542 //-----------------------------------------------------------------------------
543 // Function : spline<ScalarT>::eval
544 // Purpose :
545 // Special Notes : adapted from Numerical Recipies. This roughly correponds
546 // to the "splint" function.
547 //
548 // Scope : public
549 // Creator : Eric Keiter, SNL
550 // Creation Date : 1/31/2012
551 //-----------------------------------------------------------------------------
552 template <typename ScalarT>
554  const std::vector<ScalarT> & xa,
555  const std::vector<ScalarT> & ya,
556  const ScalarT & x_position,
557  ScalarT & y_spline)
558 {
559  // This method adapted from "Numerical Recipes in C++"
560  int n = xa.size();
561  // Find the right place in the table by means of bisection.
562  ScalarT h = 0.0; ScalarT a = 0.0; ScalarT b = 0.0;
563  int k = 0; int klo = 0; int khi = n-1;
564  while (khi-klo > 1)
565  {
566  k = (khi+klo) >> 1;
567  if (xa[k] > x_position) khi=k;
568  else klo=k;
569  }
570  h = xa[khi] - xa[klo];
571  if (h == 0.0)
572  {
573  // if out of range, then use the formula for dy/dx to extrapolate
574  // beyond the range. (formula 3.3.5 from numerical recipies in C)
575  if (khi == 0)
576  {
577  ScalarT h0 = xa[1]-xa[0];
578  ScalarT dx = x_position - xa[0];
579  ScalarT dydx = (ya[1]-ya[0])/h0 - h0*y2[0]/3.0 - h0*y2[1]/6.0;
580  y_spline = ya[0] + dx * dydx;
581  }
582  else if (klo == n-1)
583  {
584  ScalarT h1 = xa[n-1]-xa[n-2];
585  ScalarT dx = x_position - xa[n-1];
586  ScalarT dydx = (ya[n-1]-ya[n-2])/h1 + h1*y2[n-2]/6.0 + h1*y2[n-1]/3.0;
587  y_spline = ya[n-1] + dx * dydx;
588  }
589  }
590  else
591  {
592  a = (xa[khi] - x_position)/h;
593  b = (x_position - xa[klo])/h;
594  // cubic spline polynomial: (formula 3.3.3 from numerical recipies in C)
595  y_spline = a*ya[klo]+b*ya[khi]+((a*a*a-a)*y2[klo] + (b*b*b-b)*y2[khi])*(h*h)/6.0;
596  }
597 }
598 
599 //-----------------------------------------------------------------------------
600 // Function : cubicSpline<ScalarT>::eval_deriv
601 // Purpose :
602 // Special Notes : adapted from Numerical Recipies. This roughly correponds
603 // to the "splint" function.
604 //
605 // Scope : public
606 // Creator : Eric Keiter, SNL
607 // Creation Date : 1/31/2012
608 //-----------------------------------------------------------------------------
609 template <typename ScalarT>
611  const std::vector<ScalarT> & xa,
612  const std::vector<ScalarT> & ya,
613  const ScalarT & x_position,
614  ScalarT & dydx_spline)
615 {
616  // This method adapted from "Numerical Recipes in C++"
617  int n = xa.size();
618  // Find the right place in the table by means of bisection.
619  ScalarT h = 0.0; ScalarT a = 0.0; ScalarT b = 0.0;
620  int k = 0; int klo = 0; int khi = n-1;
621  while (khi-klo > 1)
622  {
623  k = (khi+klo) >> 1;
624  if (xa[k] > x_position) khi=k;
625  else klo=k;
626  }
627  h = xa[khi] - xa[klo];
628  if (h == 0.0)
629  {
630  // if out of range, then use the formula for dy/dx to extrapolate
631  // beyond the range. (formula 3.3.5 from numerical recipies in C)
632  if (khi == 0)
633  {
634  ScalarT h0 = xa[1]-xa[0];
635  dydx_spline = (ya[1]-ya[0])/h0 - h0*y2[0]/3.0 - h0*y2[1]/6.0;
636  }
637  else if (klo == n-1)
638  {
639  ScalarT h1 = xa[n-1]-xa[n-2];
640  dydx_spline = (ya[n-1]-ya[n-2])/h1 + h1*y2[n-2]/6.0 + h1*y2[n-1]/3.0;
641  }
642  }
643  else
644  {
645  a = (xa[khi] - x_position)/h;
646  b = (x_position - xa[klo])/h;
647 
648  // derivative: (formula 3.3.5 from numerical recipies in C)
649  dydx_spline = (ya[khi]-ya[klo])/h - ((3*a*a-1)*y2[klo] - (3*b*b-1)*y2[khi])*h/6.0;
650  }
651 }
652 
653 //-----------------------------------------------------------------------------
654 // Function : cubicSpline<ScalarT>::eval_deriv2
655 // Purpose :
656 // Special Notes : adapted from Numerical Recipies. This roughly correponds
657 // to the "splint" function.
658 //
659 // Scope : public
660 // Creator : Eric Keiter, SNL
661 // Creation Date : 1/31/2012
662 //-----------------------------------------------------------------------------
663 template <typename ScalarT>
665  const std::vector<ScalarT> & xa,
666  const std::vector<ScalarT> & ya,
667  const ScalarT & x_position,
668  ScalarT & ypp)
669 {
670  // This method adapted from "Numerical Recipes in C++"
671  int n = xa.size();
672  // Find the right place in the table by means of bisection.
673  ScalarT h = 0.0; ScalarT a = 0.0; ScalarT b = 0.0;
674  int k = 0; int klo = 0; int khi = n-1;
675  while (khi-klo > 1)
676  {
677  k = (khi+klo) >> 1;
678  if (xa[k] > x_position) khi=k;
679  else klo=k;
680  }
681  h = xa[khi] - xa[klo];
682  if (h == 0.0)
683  {
684  // if out of range, assume no curvature.
685  if (khi == 0)
686  {
687  ypp = 0.0;
688  }
689  else if (klo == n-1)
690  {
691  ypp = 0.0;
692  }
693  }
694  else
695  {
696  a = (xa[khi] - x_position)/h;
697  b = (x_position - xa[klo])/h;
698 
699  // derivative: (formula 3.3.6 from numerical recipies in C)
700  ypp = a*y2[klo] + b*y2[khi];
701  }
702 }
703 
704 //-----------------------------------------------------------------------------
705 // Class : linear interpolation class
706 // Purpose :
707 // Special Notes : adapted from Numerical Recipies.
708 // Creator : Eric Keiter, SNL
709 // Creation Date : 1/31/2012
710 //-----------------------------------------------------------------------------
711 template <typename ScalarT>
712 class linear: public interpolator<ScalarT>
713 {
714 public:
715  linear () {};
716 
717  void init ( const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya) {};
718 
719  void clear () { };
720 
721  void eval (
722  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
723  const ScalarT & x, ScalarT & y);
724 
725  void eval_deriv (
726  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
727  const ScalarT & x, ScalarT & dydx);
728 
729  void eval_deriv2 (
730  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
731  const ScalarT & x, ScalarT & ypp);
732 
733  void eval_integ (
734  const std::vector<ScalarT> & xa, const std::vector<ScalarT> & ya,
735  const ScalarT & a, const ScalarT & b, ScalarT & result);
736 
737 public:
738 
739 };
740 
741 
742 //-----------------------------------------------------------------------------
743 // Function : linear<ScalarT>::eval
744 // Purpose :
745 // Special Notes :
746 // Scope : public
747 // Creator : Eric Keiter, SNL
748 // Creation Date : 1/31/2012
749 //-----------------------------------------------------------------------------
750 template <typename ScalarT>
752  const std::vector<ScalarT> & xa,
753  const std::vector<ScalarT> & ya,
754  const ScalarT & x,
755  ScalarT & y)
756 {
757  int n = xa.size();
758 
759  // Find the right place in the table by means of bisection.
760  ScalarT h = 0.0; ScalarT a = 0.0; ScalarT b = 0.0;
761  int k = 0; int klo = 0; int khi = n-1;
762  while (khi-klo > 1)
763  {
764  k = (khi+klo) >> 1;
765  if (xa[k] > x) khi=k;
766  else klo=k;
767  }
768  h = xa[khi] - xa[klo];
769 
770  if (h == 0.0)
771  {
772  if (khi == 0)
773  {
774  y = xa[khi];
775  }
776  else if (klo == n-1)
777  {
778  y = xa[klo];
779  }
780  }
781  else
782  {
783  ScalarT dx = x - xa[klo];
784  ScalarT ya0 = ya[khi] - ya[klo];
785  y = (dx/h) * ya0 + ya[klo];
786  }
787 }
788 
789 //-----------------------------------------------------------------------------
790 // Function : linear<ScalarT>::eval_deriv
791 // Purpose :
792 // Special Notes :
793 // Scope : public
794 // Creator : Eric Keiter, SNL
795 // Creation Date : 1/31/2012
796 //-----------------------------------------------------------------------------
797 template <typename ScalarT>
799  const std::vector<ScalarT> & xa,
800  const std::vector<ScalarT> & ya,
801  const ScalarT & x,
802  ScalarT & dydx)
803 {
804  int n = xa.size();
805 
806  // Find the right place in the table by means of bisection.
807  ScalarT h = 0.0; ScalarT a = 0.0; ScalarT b = 0.0;
808  int k = 0; int klo = 0; int khi = n-1;
809  while (khi-klo > 1)
810  {
811  k = (khi+klo) >> 1;
812  if (xa[k] > x) khi=k;
813  else klo=k;
814  }
815  h = xa[khi] - xa[klo];
816 
817  if (h == 0.0)
818  {
819  if (khi == 0)
820  {
821  dydx = 0.0;
822  }
823  else if (klo == n-1)
824  {
825  dydx = 0.0;
826  }
827  }
828  else
829  {
830  ScalarT dx = xa[khi] - xa[klo];
831  ScalarT dy = ya[khi] - ya[klo];
832  dydx = dy/dx;
833  }
834 }
835 
836 //-----------------------------------------------------------------------------
837 // Function : linear<ScalarT>::eval_deriv2
838 // Purpose :
839 // Special Notes :
840 // Scope : public
841 // Creator : Eric Keiter, SNL
842 // Creation Date : 1/31/2012
843 //-----------------------------------------------------------------------------
844 template <typename ScalarT>
846  const std::vector<ScalarT> & xa,
847  const std::vector<ScalarT> & ya,
848  const ScalarT & x,
849  ScalarT & ypp)
850 {
851  ypp = 0.0;
852 }
853 
854 //-----------------------------------------------------------------------------
855 // Function : linear<ScalarT>::eval_integ
856 // Purpose :
857 // Special Notes : adapted from GSL, version 1.15
858 // Scope : public
859 // Creator : Eric Keiter, SNL
860 // Creation Date : 1/31/2012
861 // ----------------------------------------------------------------------------
862 template <typename ScalarT>
864  const std::vector<ScalarT> & xa,
865  const std::vector<ScalarT> & ya,
866  const ScalarT & a,
867  const ScalarT & b,
868  ScalarT & result)
869 {
870 
871  int size = xa.size();
872  int index_a = this->binarySearch (xa, a, 0, size - 1);
873  int index_b = this->binarySearch (xa, b, 0, size - 1);
874 
875  // endpoints span more than one interval
876  result = 0.0;
877 
878  // interior intervals
879  for(int i=index_a; i<=index_b; i++)
880  {
881  const ScalarT x_hi = xa[i + 1];
882  const ScalarT x_lo = xa[i];
883  const ScalarT y_lo = ya[i];
884  const ScalarT y_hi = ya[i + 1];
885  const ScalarT dx = x_hi - x_lo;
886 
887  if(dx != 0.0)
888  {
889  if (i == index_a || i == index_b)
890  {
891  ScalarT x1 = (i == index_a) ? a : x_lo;
892  ScalarT x2 = (i == index_b) ? b : x_hi;
893  const ScalarT D = (y_hi-y_lo)/dx;
894  result += (x2-x1) * (y_lo + 0.5*D*((x2-x_lo)+(x1-x_lo)));
895  }
896  else
897  {
898  result += 0.5 * dx * (y_lo + y_hi);
899  }
900  }
901  }
902  return;
903 }
904 
905 } // namespace Device
906 } // namespace Xyce
907 
908 #endif
909 
virtual void eval(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &y)
void init(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya)
std::vector< ScalarT > d
virtual void eval_deriv(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &dydx)
Pure virtual class to augment a linear system.
void eval_deriv(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &dydx)
void eval_deriv(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &dydx)
virtual void eval_integ(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &a, const ScalarT &b, ScalarT &result)
void eval(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &y)
void eval(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &y)
void eval(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &y)
std::vector< ScalarT > _m
void eval_integ(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &a, const ScalarT &b, ScalarT &result)
void eval_deriv2(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &ypp)
std::vector< ScalarT > b
void eval_deriv(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &dydx)
std::vector< ScalarT > c
void calc(const std::vector< ScalarT > &xa, std::vector< ScalarT > &b, std::vector< ScalarT > &c, std::vector< ScalarT > &d, std::vector< ScalarT > &m)
void eval_integ(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &a, const ScalarT &b, ScalarT &result)
size_t binarySearch(const std::vector< ScalarT > &xa, const ScalarT &x, size_t index_lo, size_t index_hi)
void init(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya)
void eval_deriv2(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &ypp)
void eval_integ(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &a, const ScalarT &b, ScalarT &result)
void eval_deriv2(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &ypp)
void init(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya)
ScalarT integ_eval(const ScalarT &ai, const ScalarT &bi, const ScalarT &ci, const ScalarT &di, const ScalarT &xi, const ScalarT &a, const ScalarT &b)
virtual void eval_deriv2(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya, const ScalarT &x, ScalarT &ypp)
std::vector< ScalarT > y2
virtual void init(const std::vector< ScalarT > &xa, const std::vector< ScalarT > &ya)