#include <BTSpline1D.hh>
Public Member Functions | |
double | operator() (double x) const |
BTSpline1D (const BTSpline1D &s) | |
BTSpline1D () | |
BTSpline1D (int extent, const Data_t *nodes, const Data_t *values) | |
BTSpline1D (int extent, const Data_t *nodes, double values_function(double x)) | |
BTSpline1D (int extent, const Data_t *nodes, const Data_t *values, Data_t slope0, Data_t slopeN) | |
BTSpline1D (int extent, const Data_t *nodes, double values_function(double x), Data_t slope0, Data_t slopeN) | |
BTSpline1D (int extent, const Data_t *nodes, const Data_t *values, const Data_t *gradients) | |
BTSpline1D (int extent, const Data_t *nodes, void values_grads_function(double x, double *val, double *grads)) | |
~BTSpline1D () | |
Protected Member Functions | |
void | captureGrid (int extent, const Data_t *nodes) |
void | captureValues (int extent, const Data_t *values) |
void | fillValues (int extent, double values_function(double x)) |
void | computeSecondDerivs () |
Protected Attributes | |
int | extent_ |
Data_t * | nodePoints_ |
Data_t * | distances_ |
Data_t * | values_ |
Data_t * | grads_ |
Data_t * | secondDerivs_ |
bool | naturalBoundaryConditions |
Data_t | slope0_ |
Data_t | slopeN_ |
Private Types | |
typedef double | Data_t |
typedef double BTSpline1D::Data_t [private] |
BTSpline1D::BTSpline1D | ( | const BTSpline1D & | s | ) |
References distances_, extent_, grads_, nodePoints_, secondDerivs_, and values_.
00047 : grads_(0), secondDerivs_(0) { 00048 extent_ = s.extent_; 00049 int i; 00050 nodePoints_ = new Data_t[extent_]; 00051 distances_ = new Data_t[extent_]; 00052 values_ = new Data_t[extent_]; 00053 for (i=0; i<extent_; ++i) { 00054 nodePoints_[i] = s.nodePoints_[i]; 00055 } 00056 for (i=0; i<extent_; ++i) { 00057 distances_[i] = s.distances_[i]; 00058 } 00059 for (i=0; i<extent_; ++i) { 00060 values_[i] = s.values_[i]; 00061 } 00062 if (s.grads_) { 00063 grads_ = new Data_t[extent_]; 00064 for (i=0; i<extent_; ++i) { 00065 grads_[i] = s.grads_[i]; 00066 } 00067 } 00068 if (s.secondDerivs_) { 00069 secondDerivs_ = new Data_t[extent_]; 00070 for (i=0; i<extent_; ++i) { 00071 secondDerivs_[i] = s.secondDerivs_[i]; 00072 } 00073 } 00074 00075 }
BTSpline1D::BTSpline1D | ( | ) |
References captureGrid(), captureValues(), and computeSecondDerivs().
00255 : grads_(0), naturalBoundaryConditions (true) { 00256 00257 captureGrid ( extent, nodes ); 00258 captureValues ( extent, values ); 00259 computeSecondDerivs (); 00260 00261 } // BTSpline1D
BTSpline1D::BTSpline1D | ( | int | extent, | |
const Data_t * | nodes, | |||
double | values_functiondouble x | |||
) |
References captureGrid(), computeSecondDerivs(), and fillValues().
00267 : grads_(0), naturalBoundaryConditions (true) { 00268 00269 captureGrid ( extent, nodes ); 00270 fillValues (extent, values_function); 00271 computeSecondDerivs (); 00272 00273 } // BTSpline1D
BTSpline1D::BTSpline1D | ( | int | extent, | |
const Data_t * | nodes, | |||
const Data_t * | values, | |||
Data_t | slope0, | |||
Data_t | slopeN | |||
) |
References captureGrid(), captureValues(), and computeSecondDerivs().
00280 : grads_(0), naturalBoundaryConditions (false), 00281 slope0_ (slope0), slopeN_ (slopeN) { 00282 00283 captureGrid ( extent, nodes ); 00284 captureValues ( extent, values ); 00285 computeSecondDerivs (); 00286 00287 } // BTSpline1D
BTSpline1D::BTSpline1D | ( | int | extent, | |
const Data_t * | nodes, | |||
double | values_functiondouble x, | |||
Data_t | slope0, | |||
Data_t | slopeN | |||
) |
References captureGrid(), computeSecondDerivs(), and fillValues().
00294 : grads_(0), naturalBoundaryConditions (false), 00295 slope0_ (slope0), slopeN_ (slopeN) { 00296 00297 captureGrid ( extent, nodes ); 00298 fillValues (extent, values_function); 00299 computeSecondDerivs (); 00300 00301 } // BTSpline1D
BTSpline1D::BTSpline1D | ( | int | extent, | |
const Data_t * | nodes, | |||
const Data_t * | values, | |||
const Data_t * | gradients | |||
) |
References captureGrid(), extent_, grads_, and values_.
00316 : secondDerivs_(0) { 00317 00318 captureGrid ( extent, nodes ); 00319 00320 // Capture values and grads by copying the arrays. 00321 //-| This could be sped up by the use of memcopy, 00322 //-| but is a one-shot deal so I opt for maximal clarity. 00323 00324 const Data_t* valp = values; 00325 const Data_t* gradp = gradients; 00326 Data_t* vp = values_; 00327 Data_t* gp = grads_; 00328 for ( int i=0; i < extent_; i++ ) { 00329 *vp++ = *valp++; 00330 *gp++ = *gradp++; 00331 } 00332 00333 } // BTSpline1D - separate tables for values, grads
BTSpline1D::BTSpline1D | ( | int | extent, | |
const Data_t * | nodes, | |||
void | values_grads_functiondouble x,double *val,double *grads | |||
) |
References captureGrid(), extent_, grads_, nodePoints_, and values_.
00344 : secondDerivs_(0) { 00345 00346 captureGrid ( extent, nodes ); 00347 00348 // Fill values and grads arrays by calling the supplied function across all 00349 // the nodes. 00350 00351 float x; 00352 Data_t* vp = values_; 00353 Data_t* gp = grads_; 00354 double vpTemp; 00355 double gpTemp; 00356 for ( int i = 0; i < extent_; i++ ) { 00357 x = nodePoints_[i]; 00358 values_grads_function ( x, &vpTemp, &gpTemp ); 00359 *vp++ = vpTemp; 00360 *gp++ = gpTemp; 00361 } 00362 00363 } // BTSpline1D - function returning value and grad supplied
BTSpline1D::~BTSpline1D | ( | ) |
References distances_, grads_, nodePoints_, secondDerivs_, and values_.
00365 { 00366 00367 delete[] nodePoints_; 00368 delete[] distances_; 00369 delete[] values_; 00370 if (grads_) delete[] grads_; 00371 if (secondDerivs_) delete[] secondDerivs_; 00372 00373 } // Destructor
double BTSpline1D::operator() | ( | double | x | ) | const |
References distances_, extent_, grads_, nodePoints_, secondDerivs_, and values_.
00375 { 00376 00377 // Find the interval that x lies within. This has a lower coordinate 00378 // of origin. Also compute the f0, f1, g0 and g1 functions. 00379 // (See mathematics comment at end of this file): 00380 //-| This step will point to the exactly matching point if there is one, 00381 //-| and to the first or next-to-last point if out of range. 00382 00383 double f0; 00384 double f1; 00385 double g0; 00386 double g1; 00387 00388 int a = 0; // Highest node value known NOT to exceed x. 00389 // Will end up as highest node which 00390 // DOES not exceed x. 00391 int b = extent_ - 1; // Lowest node value which must exceed xd, 00392 // assuming x is not outside the range. 00393 00394 while (b != (a+1) ) { 00395 int c = (a+b+1)>>1; 00396 if (x > nodePoints_[c]) { 00397 a = c; 00398 } else { 00399 b = c; 00400 } 00401 } 00402 00403 // Now use either the f0,f1, g0, g1 algorithm if gradients are knowen, 00404 // or the method in Numerical Recipes if second derivs have been computed: 00405 00406 double spline; 00407 00408 double dx; 00409 double oneMinusDx; 00410 00411 dx = (x - nodePoints_[a])/distances_[a]; 00412 oneMinusDx = 1 - dx; 00413 00414 if ( grads_ ) { 00415 00416 double oneMinusX2; 00417 double x2; 00418 00419 x2 = dx * dx; 00420 oneMinusX2 = oneMinusDx * oneMinusDx; 00421 00422 f0 = (2. * dx + 1.) * oneMinusX2; 00423 f1 = (3. - 2. * dx) * x2; 00424 g0 = distances_[a] * dx * oneMinusX2; 00425 g1 = -distances_[a] * oneMinusDx * x2; 00426 00427 // Sum these F and G elements times the corresponding value (for F) and 00428 // gradient in each direction (for G) to get the answer. 00429 00430 spline = f0 * values_[a] + f1 * values_[a+1] 00431 + g0 * grads_[a] + g1 * grads_[a+1] ; 00432 00433 } else { 00434 double spacingFactor = distances_[a] * distances_[a] / 6.0; 00435 double leftCubic = (dx*dx*dx - dx) * secondDerivs_[b]; 00436 double rightCubic = 00437 (oneMinusDx*oneMinusDx*oneMinusDx-oneMinusDx) * secondDerivs_[a]; 00438 spline = dx * values_[b] + oneMinusDx * values_[a] 00439 + (leftCubic + rightCubic) * spacingFactor; 00440 } 00441 00442 return spline; 00443 00444 } /* operator() */
void BTSpline1D::captureGrid | ( | int | extent, | |
const Data_t * | nodes | |||
) | [protected] |
References distances_, extent_, and nodePoints_.
Referenced by BTSpline1D().
00080 { 00081 00082 // Operations common to all the constructors of BTSpline1D: Capture the 00083 // shape and nodes of the grid, and compute differences. 00084 00085 int i; 00086 00087 // Capture N_, extents, and nodes 00088 00089 extent_ = extent; 00090 00091 nodePoints_ = new Data_t[extent]; 00092 for ( i = 0; i < extent_; i++ ) { 00093 nodePoints_[i] = nodes[i]; 00094 } 00095 00096 // Compute h_ -- the differences between consecutive grid points 00097 00098 distances_ = new Data_t[extent]; 00099 for ( i = 0; i < extent_-1; i++ ) { 00100 distances_[i] = nodePoints_[i+1] - nodePoints_[i]; 00101 if ( distances_[i] <= 0 ) { 00102 std::cout << 00103 "Spline1D initialized with nodePoints not monotonic increasing\n"; 00104 std::abort(); 00105 } 00106 } 00107 00108 } /* captureGrid() */
void BTSpline1D::captureValues | ( | int | extent, | |
const Data_t * | values | |||
) | [protected] |
void BTSpline1D::fillValues | ( | int | extent, | |
double | values_functiondouble x | |||
) | [protected] |
References extent_, nodePoints_, and values_.
Referenced by BTSpline1D().
00119 { 00120 values_ = new Data_t[extent_]; 00121 double x; 00122 Data_t* vp = values_; 00123 for ( int i = 0; i < extent_; i++ ) { 00124 x = nodePoints_[i]; 00125 *vp = values_function ( x ); 00126 vp++; 00127 } 00128 } // fillValues
void BTSpline1D::computeSecondDerivs | ( | ) | [protected] |
References distances_, extent_, naturalBoundaryConditions, secondDerivs_, slope0_, slopeN_, and values_.
Referenced by BTSpline1D().
00130 { 00131 00132 secondDerivs_ = new Data_t[extent_]; 00133 00134 // Based on Numerical Recipes page 114. 00135 00136 #ifdef MATH 00137 00138 For 1 <= j <= N-2, we have equations matching first derivatives at the 00139 node points. These are 00140 00141 distance[j-1]/6 * y[j-1] 00142 + (distance[j]+distance[j-1])/3 * y[j] 00143 + distance[j]/6 * y[j+1] 00144 = dyRight/dxRight - dyLeft/dxLeft 00145 00146 We also have, for "natural" boundary conditions, y2[0] = y2[N-1] = 0. 00147 (Or for specified slopes, a different relation, reflected in the elses.) 00148 00149 So our equations are 00150 00151 M Y2 = S 00152 00153 where Y2 are the desired second derivatives, 00154 00155 S is a vector {0, (dyRight/dxRight - dyLeft/dxLeft) from 1...N-2, 0} 00156 or for slope boundaries, 00157 S[0] = 3 * ( (y[1]-y[0])/(x[1]-x[0]) - v ) / (x[1]-x[0]) = S(v) 00158 S[N-1] = 3 * ( w - (y[N-1]-y[N-2])/(x[N-1]-x[N-2]) ) / (x[N-1]-x[N-2]) = S(w) 00159 00160 and M is a matrix of the form 00161 00162 1 0 or .5 00163 d0/6 (d0+d1)/3 d1/6 00164 d1/6 (d1+d2)/3 d2/6 00165 d2/6 (d2+d3)/3 d3/6 00166 ... 00167 dN-3/6 (dN-3+DN-2)/3 DN-2/3 00168 0 or .5 1 00169 00170 Step 1 in solving this tridiagonal system is to eliminate the lower part. 00171 That only affects the first rank above the diagonal; we will call the 00172 affected rank u. (u is a vector with indices ranging from 0 to N-2 (not N-1)). 00173 By inspection of M, u[0] starts out as 0 for our natural condition. 00174 00175 We will also hold S in the place where we want y2 to end up. S[0] starts out 00176 as 0 as well, for the natural condition. 00177 00178 We will not form u in advance, nor form the below-diagonal, because they are 00179 simple expressions in terns of the distances. For each row, we get a new 00180 pivot from the original diagonal element modified by the u above it when 00181 eliminating the below-diagonal term, and a new y2 similarly, and then we divide 00182 thru by the pivot. 00183 00184 #endif 00185 00186 // Decompose the tridiagonal matrix representing the conditions of 00187 // continuous second derivative. 00188 00189 double* u = new double[extent_]; 00190 00191 Data_t* y = values_; // aliases just to shorten the expressions. 00192 Data_t* y2 = secondDerivs_; 00193 int N = extent_; 00194 00195 if (naturalBoundaryConditions) { 00196 y2[0] = u[0] = 0; 00197 } else { 00198 y2[0] = 3 * ( (y[1]-y[0])/distances_[0] - slope0_ ) / distances_[0]; 00199 } 00200 00201 double dxLeft; 00202 double dyLeft; 00203 double dxRight; 00204 double dyRight; 00205 double pivot; 00206 for ( int i=1; i < N-1; ++i ) { 00207 dxLeft = distances_[i-1]; 00208 dxRight = distances_[i]; 00209 dyLeft = y[i] - y[i-1]; 00210 dyRight = y[i+1]- y[i]; 00211 pivot = (dxLeft+dxRight)/3.0 - dxLeft * u[i-1] / 6.0; 00212 y2[i] = dyRight/dxRight - dyLeft/dxLeft - dxLeft * y2[i-1] / 6.0; 00213 u[i] = dxRight / (6.0 * pivot); 00214 y2[i] = y2[i] / pivot; 00215 } 00216 00217 double lower; // The element one to the left of the bottom right of M 00218 if (naturalBoundaryConditions) { 00219 y2[N-1] = 0; 00220 lower = 0; 00221 } else { 00222 y2[N-1] = 00223 3 * ( slopeN_ - (y[N-1]-y[N-2])/distances_[N-2] ) / distances_[N-2]; 00224 lower = .5; 00225 } 00226 pivot = 1 - lower*u[N-2]; 00227 y2[N-1] -= lower * y2[N-2]; 00228 y2[N-1] = y2[N-1] / pivot; 00229 00230 // Backsolve that decomposition to get the second dervatives. 00231 00232 for ( int k=N-2; k >= 0; --k) { 00233 y2[k] -= u[k] * y2[k+1]; 00234 } 00235 00236 // secondDerivs_ is already y2, and we no longer need u 00237 00238 delete[] u; 00239 00240 return; 00241 }
int BTSpline1D::extent_ [protected] |
Referenced by BTSpline1D(), captureGrid(), captureValues(), computeSecondDerivs(), fillValues(), and operator()().
Data_t* BTSpline1D::nodePoints_ [protected] |
Referenced by BTSpline1D(), captureGrid(), fillValues(), operator()(), and ~BTSpline1D().
Data_t* BTSpline1D::distances_ [protected] |
Referenced by BTSpline1D(), captureGrid(), computeSecondDerivs(), operator()(), and ~BTSpline1D().
Data_t* BTSpline1D::values_ [protected] |
Referenced by BTSpline1D(), captureValues(), computeSecondDerivs(), fillValues(), operator()(), and ~BTSpline1D().
Data_t* BTSpline1D::grads_ [protected] |
Referenced by BTSpline1D(), operator()(), and ~BTSpline1D().
Data_t* BTSpline1D::secondDerivs_ [protected] |
Referenced by BTSpline1D(), computeSecondDerivs(), operator()(), and ~BTSpline1D().
bool BTSpline1D::naturalBoundaryConditions [protected] |
Referenced by computeSecondDerivs().
Data_t BTSpline1D::slope0_ [protected] |
Referenced by computeSecondDerivs().
Data_t BTSpline1D::slopeN_ [protected] |
Referenced by computeSecondDerivs().