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