BTSpline1D Class Reference

#include <BTSpline1D.hh>

List of all members.

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_tnodePoints_
Data_tdistances_
Data_tvalues_
Data_tgrads_
Data_tsecondDerivs_
bool naturalBoundaryConditions
Data_t slope0_
Data_t slopeN_

Private Types

typedef double Data_t


Member Typedef Documentation

typedef double BTSpline1D::Data_t [private]


Constructor & Destructor Documentation

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 (  ) 

00077                       : extent_(0), nodePoints_(0),
00078                             values_(0), grads_(0), secondDerivs_(0){}

BTSpline1D::BTSpline1D ( int  extent,
const Data_t nodes,
const Data_t values 
)

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 


Member Function Documentation

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]

References extent_, and values_.

Referenced by BTSpline1D().

00110                                                                   {
00111   values_ = new Data_t[extent_];
00112   const Data_t* valp  = values;
00113   Data_t* vp = values_;
00114   for ( int i=0; i < extent_; i++ ) {
00115     *vp++ = *valp++;
00116   }
00117 } // captureValues

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 }


Member Data Documentation

int BTSpline1D::extent_ [protected]

Data_t* BTSpline1D::grads_ [protected]

Referenced by BTSpline1D(), operator()(), and ~BTSpline1D().

Referenced by computeSecondDerivs().

Referenced by computeSecondDerivs().

Referenced by computeSecondDerivs().


The documentation for this class was generated from the following files:
g4beamline