Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

num_interpolate.h

Go to the documentation of this file.
00001 // SuperMix version 1.0  C++ source file
00002 //
00003 // Copyright (c) 1999 California Institute of Technology.
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms for noncommercial
00007 // purposes are permitted provided that the above copyright notice and
00008 // this paragraph are duplicated in all such forms and that any
00009 // documentation and other materials related to such distribution and
00010 // use acknowledge that the software was developed by California
00011 // Institute of Technology. Redistribution and/or use in source or
00012 // binary forms is not permitted for any commercial purpose. Use of
00013 // this software does not include a permitted use of the Institute's
00014 // name or trademark for any purpose.
00015 //
00016 // DISCLAIMER:
00017 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT
00018 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR
00019 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET
00020 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
00021 // LICENSED PRODUCT, HOWEVER USED.  IN NO EVENT SHALL CALTECH/JPL BE
00022 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO
00023 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC
00024 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF
00025 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN
00026 // FACT SHALL KNOW OF THE POSSIBILITY.  THE USER BEARS ALL RISK
00027 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED
00028 // MATERIALS.
00029 //
00030 // ********************************************************************
00031 // Definitions of functions in class interpolator<>
00032 //
00033 // F. Rice 4/9/99
00034 // ********************************************************************
00035 
00036 #include "error.h"
00037 #include <algorithm>
00038 
00039 // --------------------------------------------------------------------
00040 // used by search routines: true if x(d1) < d2, where d1 is an (x,y) pair:
00041 
00042 template < class Y > inline bool operator < 
00043 (const pair<double,Y> & d1, const double & d2)
00044 { return d1.first < d2; }
00045 
00046 
00047 // --------------------------------------------------------------------
00048 // constructors; clear(); operator =
00049 
00050 template < class Y_type > inline 
00051 interpolator<Y_type>::interpolator()
00052   : ready_(false), no_warn_(false), type_(SPLINE), user_ls(false), user_rs(false)
00053 { }
00054 
00055 
00056 template < class Y_type > inline 
00057 interpolator<Y_type>::interpolator(const interpolator<Y_type> & f)
00058   : data(f.data), aux(f.aux), table(),
00059     ready_(false), no_warn_(f.no_warn_), type_(f.type_),
00060     user_ls(f.user_ls), user_rs(f.user_rs)
00061 { 
00062   if (user_ls) lslope = f.lslope;
00063   if (user_rs) rslope = f.rslope;
00064   if (f.ready_) build(); 
00065 }
00066 
00067 
00068 template < class Y_type > inline 
00069 interpolator<Y_type> & interpolator<Y_type>::clear()
00070 {
00071   // conditions on exit from clear():
00072   //   (1) data and aux are empty
00073   //   (2) table is empty
00074   //   (3) ready() == false, user_ls == false, user_rs == false, type_ = SPLINE
00075 
00076   data.erase(data.begin(), data.end());
00077   aux.erase(aux.begin(), aux.end());
00078   table.erase(table.begin(), table.end());
00079   ready_ = user_ls = user_rs = false;
00080   type_ = SPLINE;
00081 
00082   return *this;
00083 }
00084 
00085 
00086 template < class Y_type > inline 
00087 interpolator<Y_type> & interpolator<Y_type>::operator =
00088 (const interpolator<Y_type> & f)
00089 {
00090   data = f.data; aux = f.aux; table.erase(table.begin(),table.end());
00091   ready_ = false; no_warn_ = f.no_warn_; type_ = f.type_;
00092   user_ls = f.user_ls; user_rs = f.user_rs;
00093   if (user_ls) lslope = f.lslope;
00094   if (user_rs) rslope = f.rslope;
00095   if (f.ready_) build(); 
00096   return *this;
00097 }
00098 
00099 
00100 // --------------------------------------------------------------------
00101 // set-up routines: add(), type(), left_slope(), right_slope()
00102 
00103 template < class Y_type > inline 
00104 interpolator<Y_type> & interpolator<Y_type>::add(const double x, const Y_type & y)
00105 {
00106   static data_type temp;             // declared static so allocation occurs once
00107   temp.first = x, temp.second = y;
00108 
00109   // invariants on entry to and exit from add():
00110   //   (1) data is sorted by x values, lowest x first, all x's unique
00111   //   (2) aux has the same size as data
00112 
00113   if ( data.size() == 0 || data.back() < x ) {
00114     // new data just goes to the back
00115     data.push_back(temp);   // just add new data to back
00116   }
00117   else {
00118     // need to enter data somewhere else
00119     data_iter j = lower_bound(data.begin(), data.end(), x);
00120     if ((j->first) == x)  // a duplicate x value
00121       error::fatal("x values input to interpolator are not all unique.");
00122     data.insert(j, temp); // maintain invariant (1)
00123   }
00124 
00125   aux.push_front(temp); // now restore invariant (2), using temp as junk
00126 
00127   return *this;
00128 }
00129 
00130 template < class Y_type > inline 
00131 interpolator<Y_type> & interpolator<Y_type>::add(const interpolator<Y_type> & Z)
00132 {
00133   data_type temp;
00134   double & x = temp.first;
00135   Y_type & y = temp.second;
00136 
00137   // loop through the supplied interpolator's data list
00138   for(interpolator::const_data_iter i = Z.data.begin(); i != Z.data.end(); ++i) {
00139     x = i->first; y = i->second;
00140 
00141     // invariants on entry to and exit from add():
00142     //   (1) data is sorted by x values, lowest x first, all x's unique
00143     //   (2) aux has the same size as data
00144 
00145     if ( data.size() == 0 || data.back() < x ) {
00146       // new data just goes to the back
00147       data.push_back(temp);   // just add new data to back
00148     }
00149     else {
00150       // need to enter data somewhere else
00151       data_iter j = lower_bound(data.begin(), data.end(), x);
00152       if ((j->first) != x)  // not a duplicate x value
00153         data.insert(j, temp); // maintain invariant (1)
00154     }
00155 
00156     aux.push_front(temp); // now restore invariant (2), using temp as junk
00157   }
00158 
00159   return *this;
00160 }
00161 
00162 
00163 template < class Y_type > inline 
00164 interpolator<Y_type> & interpolator<Y_type>::type(int t)
00165 {
00166   ready_ = false;     // must rebuild before using
00167   switch(t) {
00168   default:
00169   case LINEAR: { type_ = LINEAR; break; }
00170   case SPLINE: { type_ = SPLINE; break; }
00171   }
00172   return *this;
00173 }
00174 
00175 
00176 template < class Y_type > inline 
00177 interpolator<Y_type> & interpolator<Y_type>::left_slope(const Y_type & y)
00178 { lslope = y; user_ls = true; ready_ = false; return *this; }
00179 
00180 
00181 template < class Y_type > inline 
00182 interpolator<Y_type> & interpolator<Y_type>::right_slope(const Y_type & y)
00183 { rslope = y; user_rs = true; ready_ = false; return *this; }
00184 
00185 
00186 // --------------------------------------------------------------------
00187 // build routines: build(), build_linear(), build_spline()
00188 
00189 
00190 template < class Y_type > inline 
00191 interpolator<Y_type> & interpolator<Y_type>::build()
00192 {
00193   // assumed conditions on entry to build()
00194   //   (1) data.size() == aux.size()
00195   //   (2) data is sorted by x with all x's unique
00196   //
00197   // conditions on entry for build() to do anything useful
00198   //   (1) data and aux each have size() > 1
00199   //
00200   // conditions on successful exit from build():
00201   //   (1) table, data and aux all have the same size() > 1
00202   //   (2) ready() == 1
00203   //   and for all i (except the last i for (6))
00204   //   (3) table[i].first == data[i].first == x[i]
00205   //   (4) table[i].second.first == data.begin()+i => (x[i],y[i])
00206   //   (5) table[i].second.second == aux.begin()+i => (dx[i],yp[i])
00207   //   (6) (aux.begin()+i)->first
00208   //          == (data.begin()+i+1)->first - (data.begin()+i)->first
00209   //          == dx[i] = x[i+1]-x[i]
00210 
00211   data_list::size_type size = data.size();
00212 
00213   if (size != aux.size())
00214     error::fatal("Internal error in interpolator: "
00215                  "internal tables inconsistent");
00216 
00217   if (size <= 1) {
00218     error::warning("Not enough data to interpolate in interpolator. "
00219                    "Add more data and build again.");
00220     return *this;
00221   }
00222 
00223   // passed the tests, so here goes:
00224 
00225   table.erase(table.begin(), table.end());  // clear out old table
00226   table.reserve(size);                      // and get enough space for new
00227 
00228   data_iter i_data = data.begin(), i_aux = aux.begin();
00229   data_list::size_type i = 0;  // counts elements we've processed
00230   double x;
00231   entry  t;
00232   while ( ++i < size ) {  // loop over all but the final entry
00233     x = i_data->first;    // x[i] value here
00234     t.first = x; t.second.first = i_data; t.second.second = i_aux;
00235     table.push_back(t);
00236 
00237     // The next line computes aux[i].first = x[i+1] - x[i], incrementing iterators. 
00238     (i_aux++)->first = (++i_data)->first - x;
00239 
00240   } // while
00241 
00242   // now i_data and i_aux point to the final entries
00243   t.first = i_data->first; t.second.first = i_data; t.second.second = i_aux;
00244   table.push_back(t);
00245 
00246   // processing of the aux Y data here
00247   switch (type_) {
00248   case LINEAR: { build_linear(); break; }
00249   case SPLINE: { build_spline(); break; }
00250   default: 
00251     { error::fatal("Unknown interpolation type in interpolator."); }
00252   }
00253 
00254   ready_ = true;
00255   return *this;
00256 }
00257 
00258 
00259 template < class Y_type > inline 
00260 void interpolator<Y_type>::build_linear()
00261 { 
00262   // aux Y values contain Y' to next point, to speed up interpolations
00263   // Endpoint slopes are calculated and stored in lslope, rslope if required.
00264 
00265   // convenient readablility macros:
00266   #define Y(i)  ((i)->second.first->second)
00267   #define Yp(i) ((i)->second.second->second)
00268   #define Dx(i) ((i)->second.second->first)
00269 
00270   table_iter i, last = table.end() - 1;
00271   for (i = table.begin(); i != last; ++i) {
00272     Yp(i) = Y(i+1);  Yp(i) -= Y(i); Yp(i) *= 1.0/Dx(i);
00273   }
00274 
00275   // left extrapolation slope value
00276   if (!user_ls) lslope = Yp(table.begin());
00277 
00278   // right extrapolation slope value
00279   if (!user_rs) rslope = Yp(last-1);
00280 
00281   #undef Y
00282   #undef Yp
00283   #undef Dx
00284 }
00285 
00286 
00287 template < class Y_type > inline 
00288 void interpolator<Y_type>::build_spline()
00289 { 
00290   // the aux Y[i] will hold Y''(x[i]) for the cubic spline interpolation.
00291   // boundary conditions: if an endpoint slope is specified, use it; otherwise
00292   // set Y'' at the endpoint to 0. The Y(x[i]) and the continuity of Y'' now
00293   // give a tridiagonal set of equations for the Y''[i] like:
00294   //    a[i]*Y''[i-1] + b[i]*Y''[i] + c[i]*Y''[i+1] == r[i]
00295   // Note that the a,b,c are scalars (double); the r are Y_type
00296   //
00297   // This algorithm is a highly modified form of that in Numerical Recipes.
00298 
00299   static vector<double> c;    // holds the -c[i]; static avoids reallocation,
00300                               // so multiple builds are faster
00301   c.empty(); c.reserve(table.size());
00302 
00303   index i;
00304   index last = table.size()-1;  // the last data element
00305 
00306   // convenient readablility macros:
00307   #define Y(i)  (table[(i)].second.first->second)
00308   #define Yp(i) (table[(i)].second.second->second)
00309   #define Dx(i) (table[(i)].second.second->first)
00310   #define C(i)  (c[(i)])
00311   #define R(i)  (Yp(i))
00312 
00313   // The equations relating the various y''[i] form the following tridiagonal system,
00314   // for 0 < i < table.size() (first eqn (i == 0) comes from boundary condition):
00315   //                a y''[i-1] + b y''[i] + c y''[i+1] = r
00316   // where:
00317   //   a = (x[i]-x[i-1])/(x[i+1]-x[i-1])
00318   //   b = 2
00319   //   c = (x[i+1]-x[i])/(x[i+1]-x[i-1])
00320   //   r = 6((y[i+1]-y[i])/(x[i+1]-x[i]) - (y[i]-y[i-1])/(x[i]-x[i-1]))/(x[i+1]-x[i-1])
00321 
00322   // The first step: diagonalize the system using Gaussian elimination:
00323   // invariants in the elimination loop, 0 <= j < i < table.size()-1
00324   //  (1) a[j]  == 0
00325   //  (2) b[j]  == 1
00326   //  (3) C(j)  == -c[j]       ( use vector c to temporarily hold the -c[j] )
00327   //  (4) Yp(j) == r[j]        ( use the aux Y list to temporarily hold the r[j] )
00328   //  (5) b[i]  == 2  (a literal constant) at start of each iteration i
00329   //
00330   // Also recall that the Dx(i) == x[i+1]-x[i], stored in aux X values.
00331 
00332   // set up the equation for i == 0; (b[0] == 1, c[0] == -C(0), r[0] == R(0)):
00333   if (user_ls) {
00334     C(0) = -0.5;
00335     R(0) = Y(1); R(0) -= Y(0); R(0) *= (1.0/Dx(0));  // r = linear slope between points
00336     R(0) -= lslope;       // subtract off user-specified slope
00337     R(0) *= (3.0/Dx(0));  // this is the final r[0]
00338   }
00339   else {
00340     R(0) *= (C(0) = 0.0); // the natural spline: Y''[0] == 0  ( b y''[0] == 0; b == 1 )
00341   }
00342 
00343   double b, a;
00344   Y_type m1, m2;
00345   m1 = Y(1); m1 -= Y(0); m1 *= 6.0/Dx(0);      // 6 * slope from point 0 to 1
00346   for (i = 1; i < last; ++i) {
00347     // the initial a, b, c, r for row i:
00348     a = 1.0/(Dx(i)+Dx(i-1));                   // temporarily == 1/(x[i+1]-x[i-1])
00349     m2 = Y(i+1); m2 -= Y(i); m2 *= 6.0/Dx(i);  // 6 * slope from i to i+1
00350     R(i) = m2; R(i) -= m1; R(i) *= a;          // initial r (m1=m2 from the last iter)
00351     m1 = m2;                                   // for the next iteration
00352     a *= Dx(i-1);                              // == (x[i]-x[i-1])/(x[i+1]-x[i-1])
00353     b = 2.0;
00354     C(i) = a - 1.0;                            // == -(x[i+1]-x[i])/(x[i+1]-x[i-1])
00355 
00356     // now the Gaussian elimiation step (b[i-1] == 1 from the loop invariants):
00357     b += a*C(i-1);                  // b[i] = b[i] - a[i]*c[i-1]; now a[i] == 0
00358     m2 = R(i-1); m2 *= -a;          // avoids a Y_type temporary allocation in next line
00359     R(i) += m2;                     // r[i] = r[i] - a[i]*r[i-1]
00360                                     // c[i] = c[i] - a[i]*0 (tridiagonal), so no change
00361     b = 1.0/b;                      // to multiply instead of divide below
00362     C(i) *= b;                      // normalize so b[i] == 1
00363     R(i) *= b;                      // normalize so b[i] == 1
00364   }
00365 
00366   // Gaussian elimination and back substitution of the last row, where there is no C[i]
00367   if (user_rs) {
00368     Yp(last) = rslope; Yp(last) *= 6.0;
00369     Yp(last) -= m1;  // m1 == 6*slope from previous point
00370     Yp(last) *= 1.0/Dx(last-1);
00371     Yp(last) -= R(last-1);
00372     Yp(last) *= 1.0/(2.0 + C(last-1));
00373   }
00374   else {
00375     Yp(last) *= 0.0;  // the natural spline: Y''[last] == 0
00376   }
00377 
00378   // back substitution of the remaining rows
00379   for (i = last; i > 0; --i) {
00380     m2 = Yp(i); m2 *= C(i-1);
00381     Yp(i-1) += m2;             // remember, C(j) == -c for jth row
00382   }
00383 
00384   // now set lslope and rslope if necessary
00385   if (!user_ls) {
00386     lslope = Y(0); lslope *= -1.0; lslope += Y(1); lslope *= 1.0/Dx(0); // slope fm 0 to 1
00387     m2 = Yp(0); m2 *= 2.0; m2 += Yp(1); m2 *= -Dx(0)/6.0;
00388     lslope += m2;
00389   }
00390   if (!user_rs) {
00391     rslope = Y(last-1); rslope *= -1.0; 
00392     rslope += Y(last); rslope *= 1.0/Dx(last-1); // slope fm last-1 to last
00393     m2 = Yp(last); m2 *= 2.0; m2 += Yp(last-1); m2 *= Dx(last-1)/6.0;
00394     rslope += m2;
00395   }
00396 
00397   #undef Y
00398   #undef Yp
00399   #undef Dx
00400   #undef C
00401   #undef R
00402 }
00403 
00404 
00405 // --------------------------------------------------------------------
00406 // interpolation routines: (), linear(), spline(), lextrapolate(), rextrapolate()
00407 //                         prime(), val_prime(), prime_linear(), prime_spline()
00408 
00409 template < class Y_type > inline 
00410 Y_type interpolator<Y_type>::operator ()(double x) const
00411 {
00412   if (!ready_)
00413     error::fatal("Must build interpolator before use.");
00414 
00415   // attempt to find where in table to interpolate:
00416   const const_table_iter j = lower_bound(table.begin(), table.end(), x); // table[j] >= x;
00417 
00418   // check if extrapolation is needed, else perform the interpolation
00419   if (j == table.begin()) {
00420     lextrapolate(x);
00421     if (!no_warn_ && x < j->first)
00422       error::warning("Interpolator extrapolating beyond range of data points.");
00423   }
00424   else if (j == table.end()) {
00425     rextrapolate(x);
00426     if (!no_warn_)
00427       error::warning("Interpolator extrapolating beyond range of data points.");
00428   }
00429   else {
00430     index i = (j - table.begin()) - 1;  // now i is such that: x[i] < x <= x[i+1]
00431     switch (type_) {
00432     case LINEAR: { linear(i,x); break; }
00433     case SPLINE: { spline(i,x); break; }
00434     default: 
00435       { error::fatal("Unknown interpolation type in interpolator."); }
00436     }
00437   }
00438 
00439   return result;
00440 }
00441 
00442 
00443 template < class Y_type > inline 
00444 void interpolator<Y_type>::linear
00445 (interpolator<Y_type>::index i, double x, Y_type & r) const
00446 { 
00447   r = table[i].second.second->second;  // Y'[i]
00448   r *= x - table[i].first;             // Y'[i]*(x - x[i])
00449   r += table[i].second.first->second;  // Y[i] + Y'[i]*(x - x[i])
00450 }
00451 
00452 
00453 template < class Y_type > inline 
00454 void interpolator<Y_type>::spline
00455 (interpolator<Y_type>::index i, double x, Y_type & r) const
00456 {
00457   double D  = x - table[i].first;                // D  == x - x[i]
00458   double Do = table[i].second.second->first;     // Do == x[i+1] - x[i]
00459   double A = D/Do, B = 1.0 - A;
00460 
00461   Y_type & T1 = r;   // T1 aliases r, and will hold result
00462   T1 = table[i].second.second->second;           // T1 == Y''[i]
00463   Y_type T2(table[i+1].second.second->second);   // T2 == Y''[i+1]
00464 
00465   T1 *= -Do*Do*A*(B+1)/6.0; T2 *= -Do*Do*B*(A+1)/6.0;
00466   T1 += table[i].second.first->second; T1 *= B;
00467   T2 += table[i+1].second.first->second; T2 *= A;
00468   T1 += T2;   // T1 has the result
00469 }
00470 
00471 
00472 template < class Y_type > inline 
00473 void interpolator<Y_type>::lextrapolate(double x, Y_type & r) const
00474 {
00475   r = lslope;
00476   r *= (x - table[0].first);
00477   r += table[0].second.first->second;
00478 }
00479 
00480 
00481 template < class Y_type > inline 
00482 void interpolator<Y_type>::rextrapolate(double x, Y_type & r) const
00483 {
00484   r = rslope;
00485   index last = table.size() - 1;
00486   r *= (x - table[last].first);
00487   r += table[last].second.first->second;
00488 }
00489 
00490 
00491 template < class Y_type > inline 
00492 Y_type interpolator<Y_type>::prime(double x) const
00493 {
00494   if (!ready_)
00495     error::fatal("Must build interpolator before use.");
00496 
00497   // attempt to find where in table to interpolate:
00498   const const_table_iter j = lower_bound(table.begin(), table.end(), x); // table[j] >= x;
00499 
00500   // check if an extrapolation, else perform the interpolation
00501   if (j == table.begin()) {
00502     result = lslope;   // linear extrapolation has a constant slope
00503     if (!no_warn_ && x < j->first)
00504       error::warning("Interpolator extrapolating beyond range of data points.");
00505   }
00506   else if (j == table.end()) {
00507     result = rslope;
00508     if (!no_warn_)
00509       error::warning("Interpolator extrapolating beyond range of data points.");
00510   }
00511   else {
00512     index i = (j - table.begin()) - 1;  // now i is such that: x[i] < x <= x[i+1]
00513     switch (type_) {
00514     case LINEAR: { prime_linear(i,x); break; }
00515     case SPLINE: { prime_spline(i,x); break; }
00516     default: 
00517       { error::fatal("Unknown interpolation type in interpolator."); }
00518     }
00519   }
00520 
00521   return result;
00522 }
00523 
00524 
00525 template < class Y_type > inline 
00526 void interpolator<Y_type>::prime_linear
00527 (interpolator<Y_type>::index i, double x, Y_type & r) const
00528 {
00529   // convenient readablility macros:
00530   #define Y(i)  (table[(i)].second.first->second)
00531   #define Yp(i) (table[(i)].second.second->second)
00532   #define Dx(i) (table[(i)].second.second->first)
00533 
00534   // calculate slopes at points i and i+1:
00535   Y_type yp1;
00536   Y_type & yp2 = r;  // alias r with yp2;
00537   if (i == 0) {    // i is left endpoint
00538     yp1 = lslope;
00539   }
00540   else {
00541     yp1 = Yp(i-1); yp1 *= Dx(i)/Dx(i-1); yp1 += Yp(i);
00542     yp1 *= Dx(i-1)/(Dx(i)+Dx(i-1));
00543   }
00544   if (i == table.size()-2) {   // i+1 is right endpoint
00545     yp2 = rslope;
00546   }
00547   else {
00548     yp2 = Yp(i+1); yp2 *= Dx(i)/Dx(i+1); yp2 += Yp(i);
00549     yp2 *= Dx(i+1)/(Dx(i)+Dx(i+1));
00550   }
00551 
00552   // now do a linear interpolation between yp1 and yp2:
00553   double A = (x-table[i].first)/Dx(i);
00554   yp2 -= yp1; yp2 *= A; yp2 += yp1;    // yp2 is the result
00555 
00556   #undef Y
00557   #undef Yp
00558   #undef Dx
00559 }
00560 
00561 
00562 template < class Y_type > inline 
00563 void interpolator<Y_type>::prime_spline
00564 (interpolator<Y_type>::index i, double x, Y_type & r) const
00565 { 
00566   // convenient readablility macros:
00567   #define Y(i)  (table[(i)].second.first->second)
00568   #define Yp(i) (table[(i)].second.second->second)
00569   #define Dx(i) (table[(i)].second.second->first)
00570 
00571   Y_type yp(Y(i+1)); yp -= Y(i); yp *= 1.0/Dx(i);  // the average slope from i to i+1
00572   double B = (x-table[i].first)/Dx(i), A = 1.0-B;  // B == (x-x[i])/(x[i+1]-x[i])
00573 
00574   // using the yp, A and B defined above, the formula for Y'(x) is:
00575   // Y'(x) = yp - (3 A^2 - 1)/6 Dx(i) Y''(i) + (3 B^2 - 1)/6 Dx(i) Y''(i+1)
00576  
00577   A = (3.0*A*A-1.0)*Dx(i)/6.0; B = (3.0*B*B-1.0)*Dx(i)/6.0;
00578 
00579   r = Yp(i+1); r *= B/A; r -= Yp(i); r *= A;
00580   r += yp;
00581 
00582   #undef Y
00583   #undef Yp
00584   #undef Dx
00585 }
00586 
00587 
00588 template < class Y_type > inline 
00589 int interpolator<Y_type>::val_prime
00590 (double x, Y_type & y, Y_type & y_prime) const
00591 {
00592   if (!ready_)
00593     error::fatal("Must build interpolator before use.");
00594   int flag = 0;  // will hold the returned extrapolation flag value
00595 
00596   // attempt to find where in table to interpolate:
00597   const const_table_iter j = lower_bound(table.begin(), table.end(), x); // table[j] >= x;
00598 
00599   // check if an extrapolation, else perform the interpolation
00600   if (j == table.begin()) {
00601     lextrapolate(x,y);
00602     y_prime = lslope;   // linear extrapolation has a constant slope
00603     if ( x < j->first) {
00604       flag = -1;
00605       if (!no_warn_)
00606         error::warning("Interpolator extrapolating beyond range of data points.");
00607     }
00608   }
00609   else if (j == table.end()) {
00610     rextrapolate(x,y);
00611     y_prime = rslope;
00612     flag = 1;
00613     if (!no_warn_)
00614       error::warning("Interpolator extrapolating beyond range of data points.");
00615   }
00616   else {
00617     index i = (j - table.begin()) - 1;  // now i is such that: x[i] < x <= x[i+1]
00618     switch (type_) {
00619     case LINEAR: { linear(i,x,y); prime_linear(i,x,y_prime); break; }
00620     case SPLINE: { spline(i,x,y); prime_spline(i,x,y_prime); break; }
00621     default: 
00622       { error::fatal("Unknown interpolation type in interpolator."); }
00623     }  
00624   }
00625   return flag;
00626 }
00627 
00628 
00629 // ********************************************************************
00630 // debug functions for interpolator class
00631 
00632 template < class Y_type > inline 
00633 void interpolator<Y_type>::list_data_list() const
00634 {
00635   for (interpolator::const_data_iter i = data.begin(); i != data.end(); ++i)
00636     cout << i->first <<" , " << i->second << endl;
00637 } 
00638 
00639 template < class Y_type > inline 
00640 void interpolator<Y_type>::list_lists() const
00641 {
00642   for (unsigned i = 0; i < table.size(); ++i) {
00643     const entry & t = table[i];
00644     cout << t.first 
00645          << "\t|\t" << t.second.first->first << " , " << t.second.first->second
00646          << "\t|\t" << t.second.second->first << " , " << t.second.second->second
00647          << endl;
00648   }
00649 }
00650 
00651 // end num_interpolate.h

Please direct comments and corrections to supermix@submm.caltech.edu
Go to the supermix home page
Generated by doxygen1.2.7