![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006-2012, Andrew W. Steiner 00005 00006 This file is part of O2scl. 00007 00008 O2scl is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 O2scl is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with O2scl. If not, see <http://www.gnu.org/licenses/>. 00020 00021 ------------------------------------------------------------------- 00022 */ 00023 #ifndef O2SCL_INTERP_H 00024 #define O2SCL_INTERP_H 00025 00026 #include <iostream> 00027 #include <string> 00028 00029 #include <o2scl/err_hnd.h> 00030 #include <o2scl/ovector_tlate.h> 00031 #include <o2scl/ovector_rev_tlate.h> 00032 #include <o2scl/search_vec.h> 00033 #include <o2scl/tridiag.h> 00034 00035 #ifndef DOXYGENP 00036 namespace o2scl { 00037 #endif 00038 00039 /** \brief Base low-level interpolation class [abstract base] 00040 00041 For any pair of vectors \c x and \c y into which you would like 00042 to interpolate, you need to call allocate() and init() first, 00043 and then the interpolation functions, and then free(). If the 00044 next pair of vectors has the same size, then you need only to 00045 call init() before the next call to an interpolation function 00046 (you don't need to reallocate). If the \c x and \c y vectors do 00047 not change, then you may call the interpolation functions in 00048 succession. 00049 00050 These interpolation class work so long as the vector \c x is 00051 either monotonically increasing or monotonically decreasing. All 00052 of the descendants give identical results to the GSL 00053 interpolation routines when the vector is monotonically 00054 increasing. 00055 */ 00056 template<class vec_t> class base_interp { 00057 00058 #ifndef DOXYGEN_INTERNAL 00059 00060 protected: 00061 00062 /// To perform binary searches 00063 search_vec <vec_t> *sv; 00064 00065 /// The size of the allocated \ref search_vec object 00066 size_t n_sv; 00067 00068 /// True if memory has been allocated 00069 bool mem_alloc; 00070 00071 /** \brief An internal function to assist in computing the 00072 integral for both the cspline and Akima types 00073 */ 00074 double integ_eval(double ai, double bi, double ci, double di, double xi, 00075 double a, double b) { 00076 00077 const double r1=a-xi; 00078 const double r2=b-xi; 00079 const double r12=r1+r2; 00080 const double bterm=0.5*bi*r12; 00081 const double cterm=(1.0/3.0)*ci*(r1*r1+r2*r2+r1*r2); 00082 const double dterm=0.25*di*r12*(r1*r1+r2*r2); 00083 00084 return (b-a)*(ai+bterm+cterm+dterm); 00085 } 00086 00087 #endif 00088 00089 public: 00090 00091 // This empty constructor is required since the 00092 // default copy constructor is private. 00093 base_interp() { 00094 sv=0; 00095 n_sv=0; 00096 mem_alloc=false; 00097 } 00098 00099 virtual ~base_interp() { 00100 if (sv!=0) delete sv; 00101 if (mem_alloc) free(); 00102 } 00103 00104 /** \brief The minimum size of the vectors to interpolate between 00105 00106 This needs to be set in the constructor of the children for 00107 access by the class user 00108 */ 00109 size_t min_size; 00110 00111 /// Allocate memory, assuming x and y have size \c size 00112 virtual int allocate(size_t size) { return 0; } 00113 00114 /// Free allocated memory 00115 virtual int free() { return 0; } 00116 00117 /// Initialize interpolation routine 00118 virtual int init(const vec_t &x, const vec_t &y, size_t size) { 00119 return 0; 00120 } 00121 00122 /// Give the value of the function \f$ y(x=x_0) \f$ . 00123 virtual int interp(const vec_t &x, const vec_t &y, size_t size, 00124 double x0, double &y0)=0; 00125 00126 /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ . 00127 virtual int deriv(const vec_t &x, const vec_t &y, size_t size, 00128 double x0, double &dydx)=0; 00129 00130 /** \brief Give the value of the second derivative 00131 \f$ y^{\prime \prime}(x=x_0) \f$ . 00132 */ 00133 virtual int deriv2(const vec_t &x, const vec_t &y, size_t size, 00134 double x0, double &d2ydx2)=0; 00135 00136 /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ . 00137 virtual int integ(const vec_t &x, const vec_t &y, size_t size, 00138 double a, double b, double &result)=0; 00139 00140 /// Return the type, \c "base_interp". 00141 virtual const char *type() { return "base_interp"; } 00142 00143 #ifndef DOXYGEN_INTERNAL 00144 00145 private: 00146 00147 base_interp<vec_t>(const base_interp<vec_t> &); 00148 base_interp<vec_t>& operator=(const base_interp<vec_t>&); 00149 00150 #endif 00151 00152 }; 00153 00154 /** \brief Linear interpolation (GSL) 00155 00156 Linear interpolation requires no calls to allocate() or free() 00157 as there is no internal storage required. 00158 */ 00159 template<class vec_t> class linear_interp : public base_interp<vec_t> { 00160 00161 public: 00162 00163 linear_interp() { 00164 this->min_size=2; 00165 } 00166 00167 virtual ~linear_interp() {} 00168 00169 /// Initialize interpolation routine 00170 virtual int init(const vec_t &x, const vec_t &y, size_t size) { 00171 if (this->sv!=0) delete this->sv; 00172 this->sv=new search_vec<vec_t>(size,x); 00173 return 0; 00174 } 00175 00176 /// Give the value of the function \f$ y(x=x_0) \f$ . 00177 virtual int interp(const vec_t &x_array, const vec_t &y_array, 00178 size_t size, double x, double &y) { 00179 00180 double x_lo, x_hi; 00181 double y_lo, y_hi; 00182 double dx; 00183 size_t index; 00184 00185 index=this->sv->find(x); 00186 00187 /* evaluate */ 00188 x_lo=x_array[index]; 00189 x_hi=x_array[index+1]; 00190 y_lo=y_array[index]; 00191 y_hi=y_array[index+1]; 00192 dx=x_hi-x_lo; 00193 00194 y=y_lo+(x-x_lo)/dx*(y_hi-y_lo); 00195 return gsl_success; 00196 } 00197 00198 /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ . 00199 virtual int deriv(const vec_t &x_array, const vec_t &y_array, 00200 size_t size, double x, double &dydx) { 00201 00202 double x_lo, x_hi; 00203 double y_lo, y_hi; 00204 double dx; 00205 double dy; 00206 size_t index; 00207 00208 index=this->sv->find(x); 00209 00210 /* evaluate */ 00211 x_lo=x_array[index]; 00212 x_hi=x_array[index+1]; 00213 y_lo=y_array[index]; 00214 y_hi=y_array[index+1]; 00215 dx=x_hi-x_lo; 00216 dy=y_hi-y_lo; 00217 00218 dydx=dy/dx; 00219 return gsl_success; 00220 } 00221 00222 /** \brief Give the value of the second derivative 00223 \f$ y^{\prime \prime}(x=x_0) \f$ (always zero) 00224 */ 00225 virtual int deriv2(const vec_t &x, const vec_t &y, size_t size, 00226 double x0, double &d2ydx2) { 00227 d2ydx2=0.0; 00228 return gsl_success; 00229 } 00230 00231 /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ . 00232 virtual int integ(const vec_t &x_array, const vec_t &y_array, 00233 size_t size, double a, double b, 00234 double &result) { 00235 00236 size_t i, index_a, index_b; 00237 00238 double tmp; 00239 bool flip=false; 00240 if ((x_array[0]<x_array[size-1] && a>b) || 00241 (x_array[0]>x_array[size-1] && a<b)) { 00242 tmp=a; 00243 a=b; 00244 b=tmp; 00245 flip=true; 00246 } 00247 00248 index_a=this->sv->find(a); 00249 index_b=this->sv->find(b); 00250 00251 /* endpoints span more than one interval */ 00252 00253 result=0.0; 00254 00255 /* interior intervals */ 00256 for(i=index_a; i<=index_b; i++) { 00257 const double x_hi=x_array[i+1]; 00258 const double x_lo=x_array[i]; 00259 const double y_lo=y_array[i]; 00260 const double y_hi=y_array[i+1]; 00261 const double dx=x_hi-x_lo; 00262 00263 if(dx != 0.0) { 00264 if (i == index_a || i == index_b) { 00265 double x1=(i == index_a) ? a : x_lo; 00266 double x2=(i == index_b) ? b : x_hi; 00267 const double D=(y_hi-y_lo)/dx; 00268 result += (x2-x1)*(y_lo+0.5*D*((x2-x_lo)+(x1-x_lo))); 00269 } else { 00270 result += 0.5*dx*(y_lo+y_hi); 00271 } 00272 } 00273 } 00274 00275 if (flip) result*=-1.0; 00276 return gsl_success; 00277 } 00278 00279 /// Return the type, \c "linear_interp". 00280 virtual const char *type() { return "linear_interp"; } 00281 00282 #ifndef DOXYGEN_INTERNAL 00283 00284 private: 00285 00286 linear_interp<vec_t>(const linear_interp<vec_t> &); 00287 linear_interp<vec_t>& operator=(const linear_interp<vec_t>&); 00288 00289 #endif 00290 00291 }; 00292 00293 /** \brief Cubic spline interpolation (GSL) 00294 00295 By default, this class uses natural boundary conditions, where 00296 the second derivative vanishes at each end point. Extrapolation 00297 effectively assumes that the second derivative is linear outside 00298 of the endpoints. 00299 */ 00300 template<class vec_t> class cspline_interp : public base_interp<vec_t> { 00301 00302 #ifndef DOXYGEN_INTERNAL 00303 00304 protected: 00305 00306 /// \name Storage for cubic spline interpolation 00307 //@{ 00308 double *c; 00309 double *g; 00310 double *diag; 00311 double *offdiag; 00312 //@} 00313 00314 /// Memory for the tridiagonalization 00315 o2scl_linalg::uvector_4_mem p4m; 00316 00317 /// Compute coefficients for cubic spline interpolation 00318 void coeff_calc(const double c_array[], double dy, double dx, 00319 size_t index, double *b, double *c2, double *d) { 00320 00321 const double c_i=c_array[index]; 00322 const double c_ip1=c_array[index+1]; 00323 *b=(dy/dx)-dx*(c_ip1+2.0*c_i)/3.0; 00324 *c2=c_i; 00325 *d=(c_ip1-c_i)/(3.0*dx); 00326 } 00327 00328 #endif 00329 00330 public: 00331 00332 /** \brief Create a base interpolation object with natural or 00333 periodic boundary conditions 00334 */ 00335 cspline_interp() { 00336 this->min_size=3; 00337 } 00338 00339 virtual ~cspline_interp() {} 00340 00341 /// Allocate memory, assuming x and y have size \c size 00342 virtual int allocate(size_t size) { 00343 00344 c=(double *)malloc(size*sizeof(double)); 00345 if (c == 0) { 00346 O2SCL_ERR2_RET("Failed to allocate space for c", 00347 " in cspline_interp::allocate().",gsl_enomem); 00348 } 00349 00350 g=(double *)malloc(size*sizeof(double)); 00351 if (g == 0) { 00352 std::free(c); 00353 O2SCL_ERR2_RET("Failed to allocate space for g", 00354 " in cspline_interp::allocate().",gsl_enomem); 00355 } 00356 00357 diag=(double *)malloc(size*sizeof(double)); 00358 if (diag == 0) { 00359 std::free(g); 00360 std::free(c); 00361 O2SCL_ERR2_RET("Failed to allocate space for diag", 00362 " in cspline_interp::allocate().",gsl_enomem); 00363 } 00364 00365 offdiag=(double *)malloc(size*sizeof(double)); 00366 if (offdiag == 0) { 00367 std::free(diag); 00368 std::free(g); 00369 std::free(c); 00370 O2SCL_ERR2_RET("Failed to allocate space for offdiag", 00371 " in cspline_interp::allocate().",gsl_enomem); 00372 } 00373 00374 p4m.allocate(size); 00375 00376 this->mem_alloc=true; 00377 00378 return 0; 00379 } 00380 00381 /** \brief Initialize interpolation routine 00382 */ 00383 virtual int init(const vec_t &xa, const vec_t &ya, size_t size) { 00384 00385 if (this->mem_alloc==false) { 00386 O2SCL_ERR2_RET("Memory allocation not performed in ", 00387 "cspline_interp::init().",gsl_efailed); 00388 } 00389 00390 if (this->sv!=0) delete this->sv; 00391 this->sv=new search_vec<vec_t>(size,xa); 00392 00393 /// Natural boundary conditions 00394 00395 size_t i; 00396 size_t num_points=size; 00397 size_t max_index=num_points-1; 00398 size_t sys_size=max_index-1; 00399 00400 c[0]=0.0; 00401 c[max_index]=0.0; 00402 00403 for (i=0; i < sys_size; i++) { 00404 const double h_i=xa[i+1]-xa[i]; 00405 const double h_ip1=xa[i+2]-xa[i+1]; 00406 const double ydiff_i=ya[i+1]-ya[i]; 00407 const double ydiff_ip1=ya[i+2]-ya[i+1]; 00408 const double g_i=(h_i != 0.0) ? 1.0/h_i : 0.0; 00409 const double g_ip1=(h_ip1 != 0.0) ? 1.0/h_ip1 : 0.0; 00410 offdiag[i]=h_ip1; 00411 diag[i]=2.0*(h_ip1+h_i); 00412 g[i]=3.0*(ydiff_ip1*g_ip1- ydiff_i*g_i); 00413 } 00414 00415 if (sys_size == 1) { 00416 00417 c[1]= g[0]/ diag[0]; 00418 return gsl_success; 00419 00420 } else { 00421 00422 double *cp1=c+1; 00423 o2scl_linalg::solve_tridiag_sym<double *,double *,double *, 00424 double *,o2scl_linalg::uvector_4_mem,uvector> 00425 (diag,offdiag,g,cp1,sys_size,p4m); 00426 return 0; 00427 00428 } 00429 } 00430 00431 /// Free allocated memory 00432 virtual int free() { 00433 p4m.free(); 00434 std::free(c); 00435 std::free(g); 00436 std::free(diag); 00437 std::free(offdiag); 00438 this->mem_alloc=false; 00439 return 0; 00440 } 00441 00442 /// Give the value of the function \f$ y(x=x_0) \f$ . 00443 virtual int interp(const vec_t &x_array, const vec_t &y_array, 00444 size_t size, double x, double &y) { 00445 00446 double x_lo, x_hi; 00447 double dx; 00448 size_t index; 00449 00450 index=this->sv->find(x); 00451 00452 /* evaluate */ 00453 x_hi=x_array[index+1]; 00454 x_lo=x_array[index]; 00455 dx=x_hi-x_lo; 00456 00457 const double y_lo=y_array[index]; 00458 const double y_hi=y_array[index+1]; 00459 const double dy=y_hi-y_lo; 00460 double delx=x-x_lo; 00461 double b_i, c_i, d_i; 00462 coeff_calc(c, dy, dx, index, &b_i, &c_i, &d_i); 00463 y=y_lo+delx*(b_i+delx*(c_i+delx*d_i)); 00464 return gsl_success; 00465 } 00466 00467 /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ . 00468 virtual int deriv(const vec_t &x_array, const vec_t &y_array, 00469 size_t size, double x, double &dydx) { 00470 00471 double x_lo, x_hi; 00472 double dx; 00473 size_t index; 00474 00475 index=this->sv->find(x); 00476 00477 /* evaluate */ 00478 x_hi=x_array[index+1]; 00479 x_lo=x_array[index]; 00480 dx=x_hi-x_lo; 00481 00482 const double y_lo=y_array[index]; 00483 const double y_hi=y_array[index+1]; 00484 const double dy=y_hi-y_lo; 00485 double delx=x-x_lo; 00486 double b_i, c_i, d_i; 00487 coeff_calc(c, dy, dx, index, &b_i, &c_i, &d_i); 00488 dydx=b_i+delx*(2.0*c_i+3.0*d_i*delx); 00489 return gsl_success; 00490 } 00491 00492 /** \brief Give the value of the second derivative 00493 \f$ y^{\prime \prime}(x=x_0) \f$ . 00494 */ 00495 virtual int deriv2(const vec_t &x_array, const vec_t &y_array, 00496 size_t size, double x, double &d2ydx2) { 00497 00498 double x_lo, x_hi; 00499 double dx; 00500 size_t index; 00501 00502 index=this->sv->find(x); 00503 00504 /* evaluate */ 00505 x_hi=x_array[index+1]; 00506 x_lo=x_array[index]; 00507 dx=x_hi-x_lo; 00508 00509 const double y_lo=y_array[index]; 00510 const double y_hi=y_array[index+1]; 00511 const double dy=y_hi-y_lo; 00512 double delx=x-x_lo; 00513 double b_i, c_i, d_i; 00514 coeff_calc(c, dy, dx, index, &b_i, &c_i, &d_i); 00515 d2ydx2=2.0*c_i+6.0*d_i*delx; 00516 return gsl_success; 00517 } 00518 00519 public: 00520 00521 /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ . 00522 virtual int integ(const vec_t &x_array, const vec_t &y_array, 00523 size_t size, double a, double b, double &result) { 00524 00525 size_t i, index_a, index_b; 00526 00527 double tmp; 00528 bool flip=false; 00529 if ((x_array[0]<x_array[size-1] && a>b) || 00530 (x_array[0]>x_array[size-1] && a<b)) { 00531 tmp=a; 00532 a=b; 00533 b=tmp; 00534 flip=true; 00535 } 00536 00537 index_a=this->sv->find(a); 00538 index_b=this->sv->find(b); 00539 00540 result=0.0; 00541 00542 /* interior intervals */ 00543 for(i=index_a; i<=index_b; i++) { 00544 00545 const double x_hi=x_array[i+1]; 00546 const double x_lo=x_array[i]; 00547 const double y_lo=y_array[i]; 00548 const double y_hi=y_array[i+1]; 00549 const double dx=x_hi-x_lo; 00550 const double dy=y_hi-y_lo; 00551 00552 if(dx != 0.0) { 00553 double b_i, c_i, d_i; 00554 coeff_calc(c, dy, dx, i, &b_i, &c_i, &d_i); 00555 if (i == index_a || i == index_b) { 00556 double x1=(i == index_a) ? a : x_lo; 00557 double x2=(i == index_b) ? b : x_hi; 00558 result += this->integ_eval(y_lo, b_i, c_i, d_i, x_lo, x1, x2); 00559 } else { 00560 result += dx*(y_lo+dx*(0.5*b_i+ 00561 dx*(c_i/3.0+0.25*d_i*dx))); 00562 } 00563 } else { 00564 result=0.0; 00565 // We don't throw an error here so smart_interp classes can 00566 // attempt to recover. 00567 return gsl_failure; 00568 } 00569 00570 } 00571 00572 if (flip) result*=-1.0; 00573 return gsl_success; 00574 } 00575 00576 /// Return the type, \c "cspline_interp". 00577 virtual const char *type() { return "cspline_interp"; } 00578 00579 #ifndef DOXYGEN_INTERNAL 00580 00581 private: 00582 00583 cspline_interp<vec_t>(const cspline_interp<vec_t> &); 00584 cspline_interp<vec_t>& operator=(const cspline_interp<vec_t>&); 00585 00586 #endif 00587 00588 }; 00589 00590 /** \brief Cubic spline interpolation with periodic 00591 boundary conditions (GSL) 00592 */ 00593 template<class vec_t> class cspline_peri_interp : 00594 public cspline_interp<vec_t> { 00595 00596 protected: 00597 00598 /// Desc 00599 o2scl_linalg::uvector_5_mem p5m; 00600 00601 public: 00602 00603 cspline_peri_interp() : cspline_interp<vec_t>() { 00604 this->min_size=3; 00605 } 00606 00607 virtual ~cspline_peri_interp() {} 00608 00609 /// Allocate memory, assuming x and y have size \c size 00610 virtual int allocate(size_t size) { 00611 00612 this->c=(double *)malloc(size*sizeof(double)); 00613 if (this->c == 0) { 00614 O2SCL_ERR2_RET("Failed to allocate space for c", 00615 " in cspline_interp::allocate().",gsl_enomem); 00616 } 00617 00618 this->g=(double *)malloc(size*sizeof(double)); 00619 if (this->g == 0) { 00620 std::free(this->c); 00621 O2SCL_ERR2_RET("Failed to allocate space for g", 00622 " in cspline_interp::allocate().",gsl_enomem); 00623 } 00624 00625 this->diag=(double *)malloc(size*sizeof(double)); 00626 if (this->diag == 0) { 00627 std::free(this->g); 00628 std::free(this->c); 00629 O2SCL_ERR2_RET("Failed to allocate space for diag", 00630 " in cspline_interp::allocate().",gsl_enomem); 00631 } 00632 00633 this->offdiag=(double *)malloc(size*sizeof(double)); 00634 if (this->offdiag == 0) { 00635 std::free(this->diag); 00636 std::free(this->g); 00637 std::free(this->c); 00638 O2SCL_ERR2_RET("Failed to allocate space for offdiag", 00639 " in cspline_interp::allocate().",gsl_enomem); 00640 } 00641 00642 p5m.allocate(size); 00643 00644 this->mem_alloc=true; 00645 00646 return 0; 00647 } 00648 00649 /// Return the type, \c "cspline_peri_interp". 00650 virtual const char *type() { return "cspline_peri_interp"; } 00651 00652 virtual int init(const vec_t &xa, const vec_t &ya, size_t size) { 00653 00654 if (this->mem_alloc==false) { 00655 O2SCL_ERR2_RET("Memory allocation not performed in ", 00656 "cspline_peri_interp::init().",gsl_efailed); 00657 } 00658 00659 if (this->sv!=0) delete this->sv; 00660 this->sv=new search_vec<vec_t>(size,xa); 00661 00662 double *lc=this->c; 00663 double *lg=this->g; 00664 double *ldiag=this->diag; 00665 double *loffdiag=this->offdiag; 00666 00667 /// Periodic boundary conditions 00668 00669 size_t i; 00670 size_t num_points=size; 00671 /* Engeln-Mullges+Uhlig "n" */ 00672 size_t max_index=num_points-1; 00673 /* linear system is sys_size x sys_size */ 00674 size_t sys_size=max_index; 00675 00676 if (sys_size == 2) { 00677 /* solve 2x2 system */ 00678 00679 const double h0=xa[1]-xa[0]; 00680 const double h1=xa[2]-xa[1]; 00681 const double h2=xa[3]-xa[2]; 00682 const double A=2.0*(h0+h1); 00683 const double B=h0+h1; 00684 double gx[2]; 00685 double det; 00686 00687 gx[0]=3.0*((ya[2]-ya[1])/h1-(ya[1]-ya[0])/h0); 00688 gx[1]=3.0*((ya[1]-ya[2])/h2-(ya[2]-ya[1])/h1); 00689 00690 det=3.0*(h0+h1)*(h0+h1); 00691 lc[1]=( A*gx[0]-B*gx[1])/det; 00692 lc[2]=(-B*gx[0]+A*gx[1])/det; 00693 lc[0]=lc[2]; 00694 00695 return gsl_success; 00696 00697 } else { 00698 00699 for (i=0; i < sys_size-1; i++) { 00700 const double h_i=xa[i+1]-xa[i]; 00701 const double h_ip1=xa[i+2]-xa[i+1]; 00702 const double ydiff_i=ya[i+1]-ya[i]; 00703 const double ydiff_ip1=ya[i+2]-ya[i+1]; 00704 const double g_i=(h_i != 0.0) ? 1.0/h_i : 0.0; 00705 const double g_ip1=(h_ip1 != 0.0) ? 1.0/h_ip1 : 0.0; 00706 loffdiag[i]=h_ip1; 00707 ldiag[i]=2.0*(h_ip1+h_i); 00708 lg[i]=3.0*(ydiff_ip1*g_ip1-ydiff_i*g_i); 00709 } 00710 00711 i=sys_size-1; 00712 { 00713 const double h_i=xa[i+1]-xa[i]; 00714 const double h_ip1=xa[1]-xa[0]; 00715 const double ydiff_i=ya[i+1]-ya[i]; 00716 const double ydiff_ip1=ya[1]-ya[0]; 00717 const double g_i=(h_i != 0.0) ? 1.0/h_i : 0.0; 00718 const double g_ip1=(h_ip1 != 0.0) ? 1.0/h_ip1 : 0.0; 00719 loffdiag[i]=h_ip1; 00720 ldiag[i]=2.0*(h_ip1+h_i); 00721 lg[i]=3.0*(ydiff_ip1*g_ip1-ydiff_i*g_i); 00722 } 00723 00724 double *cp1=lc+1; 00725 o2scl_linalg::solve_cyc_tridiag_sym<double *,double *,double *, 00726 double *,o2scl_linalg::uvector_5_mem,uvector> 00727 (ldiag,loffdiag,lg,cp1,sys_size,p5m); 00728 lc[0]=lc[max_index]; 00729 return gsl_success; 00730 00731 } 00732 00733 } 00734 00735 /// Free allocated memory 00736 virtual int free() { 00737 p5m.free(); 00738 std::free(this->c); 00739 std::free(this->g); 00740 std::free(this->diag); 00741 std::free(this->offdiag); 00742 this->mem_alloc=false; 00743 return 0; 00744 } 00745 00746 #ifndef DOXYGEN_INTERNAL 00747 00748 private: 00749 00750 cspline_peri_interp<vec_t>(const cspline_peri_interp<vec_t> &); 00751 cspline_peri_interp<vec_t>& operator=(const cspline_peri_interp<vec_t>&); 00752 00753 #endif 00754 00755 }; 00756 00757 /** \brief Akima spline interpolation (GSL) 00758 00759 This class uses natural boundary conditions, where the second 00760 derivative vanishes at each end point. Extrapolation effectively 00761 assumes that the second derivative is linear outside of the 00762 endpoints. Use \ref akima_peri_interp for perodic boundary 00763 conditions. 00764 */ 00765 template<class vec_t> class akima_interp : public base_interp<vec_t> { 00766 00767 #ifndef DOXYGEN_INTERNAL 00768 00769 protected: 00770 00771 /// \name Storage for Akima spline interpolation 00772 //@{ 00773 double *b; 00774 double *c; 00775 double *d; 00776 double *um; 00777 //@} 00778 00779 /// For initializing the interpolation 00780 void akima_calc(const vec_t &x_array, size_t size, double m[]) { 00781 00782 for(size_t i=0; i < (size-1); i++) { 00783 00784 const double NE=fabs(m[i+1]-m[i])+fabs(m[i-1]-m[i-2]); 00785 00786 if (NE == 0.0) { 00787 b[i]=m[i]; 00788 c[i]=0.0; 00789 d[i]=0.0; 00790 } else { 00791 const double h_i=x_array[i+1]-x_array[i]; 00792 const double NE_next=fabs(m[i+2]-m[i+1])+ 00793 fabs(m[i]-m[i-1]); 00794 const double alpha_i=fabs(m[i-1]-m[i-2])/NE; 00795 double alpha_ip1; 00796 double tL_ip1; 00797 if (NE_next == 0.0) { 00798 tL_ip1=m[i]; 00799 } else { 00800 alpha_ip1=fabs(m[i]-m[i-1])/NE_next; 00801 tL_ip1=(1.0-alpha_ip1)*m[i]+alpha_ip1*m[i+1]; 00802 } 00803 b[i]=(1.0-alpha_i)*m[i-1]+alpha_i*m[i]; 00804 c[i]=(3.0*m[i]-2.0*b[i]-tL_ip1)/h_i; 00805 d[i]=(b[i]+tL_ip1-2.0*m[i])/(h_i*h_i); 00806 } 00807 } 00808 } 00809 00810 #endif 00811 00812 public: 00813 00814 /** \brief Create a base interpolation object with or without 00815 periodic boundary conditions 00816 */ 00817 akima_interp() { 00818 this->min_size=5; 00819 } 00820 00821 virtual ~akima_interp() {} 00822 00823 /// Allocate memory, assuming x and y have size \c size 00824 virtual int allocate(size_t size) { 00825 00826 b=(double *)malloc(size*sizeof (double)); 00827 if (b==0) { 00828 O2SCL_ERR2_RET("Failed to allocate space for c", 00829 " in akima_interp::allocate().",gsl_enomem); 00830 } 00831 00832 c=(double *)malloc(size*sizeof (double)); 00833 if (c==0) { 00834 std::free(b); 00835 O2SCL_ERR2_RET("Failed to allocate space for g", 00836 " in akima_interp::allocate().",gsl_enomem); 00837 } 00838 00839 d=(double *)malloc(size*sizeof (double)); 00840 if (d==0) { 00841 std::free(b); 00842 std::free(c); 00843 O2SCL_ERR2_RET("Failed to allocate space for diag", 00844 " in akima_interp::allocate().",gsl_enomem); 00845 } 00846 00847 um=(double *)malloc((size+4)*sizeof (double)); 00848 if (um==0) { 00849 std::free(b); 00850 std::free(c); 00851 std::free(d); 00852 O2SCL_ERR2_RET("Failed to allocate space for offdiag", 00853 " in akima_interp::allocate().",gsl_enomem); 00854 } 00855 00856 this->mem_alloc=true; 00857 00858 return 0; 00859 } 00860 00861 /// Initialize interpolation routine 00862 virtual int init(const vec_t &xa, const vec_t &ya, size_t size) { 00863 00864 if (this->mem_alloc==false) { 00865 O2SCL_ERR2_RET("Memory allocation not performed in ", 00866 "akima_interp::init().",gsl_efailed); 00867 } 00868 00869 if (this->sv!=0) delete this->sv; 00870 this->sv=new search_vec<vec_t>(size,xa); 00871 00872 /// Non-periodic boundary conditions 00873 00874 double *m=um+2; 00875 size_t i; 00876 for (i=0; i <= size-2; i++) { 00877 m[i]=(ya[i+1]-ya[i])/(xa[i+1]-xa[i]); 00878 } 00879 00880 /* non-periodic boundary conditions */ 00881 m[-2]=3.0*m[0]-2.0*m[1]; 00882 m[-1]=2.0*m[0]-m[1]; 00883 m[size-1]=2.0*m[size-2]-m[size-3]; 00884 m[size]=3.0*m[size-2]-2.0*m[size-3]; 00885 00886 akima_calc (xa, size, m); 00887 00888 return 0; 00889 } 00890 00891 /// Free allocated memory 00892 virtual int free() { 00893 std::free(b); 00894 std::free(c); 00895 std::free(d); 00896 std::free(um); 00897 this->mem_alloc=false; 00898 return 0; 00899 } 00900 00901 /// Give the value of the function \f$ y(x=x_0) \f$ . 00902 virtual int interp(const vec_t &x_array, const vec_t &y_array, 00903 size_t size, double x, double &y) { 00904 00905 size_t index; 00906 00907 index=this->sv->find(x); 00908 00909 const double x_lo=x_array[index]; 00910 const double delx=x-x_lo; 00911 const double bb=b[index]; 00912 const double cc=c[index]; 00913 const double dd=d[index]; 00914 y=y_array[index]+delx*(bb+delx*(cc+dd*delx)); 00915 return gsl_success; 00916 } 00917 00918 /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ . 00919 virtual int deriv(const vec_t &x_array, const vec_t &y_array, 00920 size_t size, double x, double &dydx) { 00921 00922 size_t index; 00923 00924 index=this->sv->find(x); 00925 00926 double x_lo=x_array[index]; 00927 double delx=x-x_lo; 00928 double bb=b[index]; 00929 double cc=c[index]; 00930 double dd=d[index]; 00931 dydx=bb+delx*(2.0*cc+3.0*dd*delx); 00932 return gsl_success; 00933 00934 } 00935 00936 /** \brief Give the value of the second derivative 00937 \f$ y^{\prime \prime}(x=x_0) \f$ . 00938 */ 00939 virtual int deriv2(const vec_t &x_array, const vec_t &y_array, 00940 size_t size, double x, double &d2ydx2) { 00941 00942 size_t index; 00943 00944 index=this->sv->find(x); 00945 00946 const double x_lo=x_array[index]; 00947 const double delx=x-x_lo; 00948 const double cc=c[index]; 00949 const double dd=d[index]; 00950 d2ydx2=2.0*cc+6.0*dd*delx; 00951 return gsl_success; 00952 00953 } 00954 00955 /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ . 00956 virtual int integ(const vec_t &x_array, const vec_t &y_array, 00957 size_t size, double aa, double bb, 00958 double &result) { 00959 00960 size_t i, index_a, index_b; 00961 00962 double tmp; 00963 bool flip=false; 00964 if ((x_array[0]<x_array[size-1] && aa>bb) || 00965 (x_array[0]>x_array[size-1] && aa<bb)) { 00966 tmp=aa; 00967 aa=bb; 00968 bb=tmp; 00969 flip=true; 00970 } 00971 00972 index_a=this->sv->find(aa); 00973 index_b=this->sv->find(bb); 00974 00975 result=0.0; 00976 00977 /* interior intervals */ 00978 00979 for(i=index_a; i<=index_b; i++) { 00980 00981 const double x_hi=x_array[i+1]; 00982 const double x_lo=x_array[i]; 00983 const double y_lo=y_array[i]; 00984 const double dx=x_hi-x_lo; 00985 00986 if (dx != 0.0) { 00987 00988 if (i==index_a || i==index_b) { 00989 double x1=(i==index_a) ? aa : x_lo; 00990 double x2=(i==index_b) ? bb : x_hi; 00991 result += this->integ_eval(y_lo,b[i],c[i],d[i],x_lo,x1,x2); 00992 } else { 00993 result+=dx*(y_lo+dx*(0.5*b[i]+dx*(c[i]/3.0+0.25*d[i]*dx))); 00994 } 00995 00996 } else { 00997 result=0.0; 00998 // We don't throw an error here so smart_interp classes can 00999 // attempt to recover. 01000 return gsl_failure; 01001 } 01002 } 01003 01004 if (flip) result*=-1.0; 01005 return gsl_success; 01006 } 01007 01008 /// Return the type, \c "akima_interp". 01009 virtual const char *type() { return "akima_interp"; } 01010 01011 #ifndef DOXYGEN_INTERNAL 01012 01013 private: 01014 01015 akima_interp<vec_t>(const akima_interp<vec_t> &); 01016 akima_interp<vec_t>& operator=(const akima_interp<vec_t>&); 01017 01018 #endif 01019 01020 }; 01021 01022 /** \brief Akima spline interpolation with periodic 01023 boundary conditions (GSL) 01024 */ 01025 template<class vec_t> class akima_peri_interp : 01026 public akima_interp<vec_t> { 01027 01028 public: 01029 01030 akima_peri_interp() : akima_interp<vec_t>() { 01031 } 01032 01033 virtual ~akima_peri_interp() {} 01034 01035 /// Return the type, \c "akima_peri_interp". 01036 virtual const char *type() { return "akima_peri_interp"; } 01037 01038 /// Initialize interpolation routine 01039 virtual int init(const vec_t &xa, const vec_t &ya, size_t size) { 01040 01041 if (this->mem_alloc==false) { 01042 O2SCL_ERR2_RET("Memory allocation not performed in ", 01043 "akima_peri_interp::init().",gsl_efailed); 01044 } 01045 01046 if (this->sv!=0) delete this->sv; 01047 this->sv=new search_vec<vec_t>(size,xa); 01048 01049 /// Periodic boundary conditions 01050 01051 double *m=this->um+2; 01052 size_t i; 01053 // Form the required set of divided differences 01054 for (i=0;i<=size-2;i++) { 01055 m[i]=(ya[i+1]-ya[i])/(xa[i+1]-xa[i]); 01056 } 01057 01058 /* periodic boundary conditions */ 01059 m[-2]=m[size-1-2]; 01060 m[-1]=m[size-1-1]; 01061 m[size-1]=m[0]; 01062 m[size]=m[1]; 01063 01064 akima_calc (xa,size, m); 01065 01066 return 0; 01067 } 01068 01069 #ifndef DOXYGEN_INTERNAL 01070 01071 private: 01072 01073 akima_peri_interp<vec_t>(const akima_peri_interp<vec_t> &); 01074 akima_peri_interp<vec_t>& operator=(const akima_peri_interp<vec_t>&); 01075 01076 #endif 01077 01078 }; 01079 01080 /** \brief A base interpolation object manager [abstract base] 01081 */ 01082 template<class vec_t> class base_interp_mgr { 01083 01084 public: 01085 01086 virtual ~base_interp_mgr() {} 01087 01088 /// Create a new interpolation object 01089 virtual base_interp<vec_t> *new_interp()=0; 01090 01091 /// Deallocate an interpolation object 01092 virtual int free_interp(base_interp<vec_t> *b) { 01093 delete b; 01094 return 0; 01095 } 01096 }; 01097 01098 /** \brief A base interpolation object manager template 01099 */ 01100 template<class vec_t, template<class> class interp_t> class def_interp_mgr : 01101 public base_interp_mgr<vec_t> { 01102 01103 public: 01104 01105 virtual ~def_interp_mgr() {} 01106 01107 /// Create a new interpolation object 01108 virtual base_interp<vec_t> *new_interp() { 01109 interp_t<vec_t> *b=new interp_t<vec_t>; 01110 return b; 01111 } 01112 01113 }; 01114 01115 /** \brief Interpolation class 01116 01117 Interpolation of \ref ovector like objects is performed with the 01118 default template parameters, and \ref array_interp is provided 01119 for simple interpolation on C-style arrays. 01120 01121 The type of interpolation to be performed can be specified using 01122 the set_type() function or in the constructor. The default is 01123 cubic splines with natural boundary conditions. 01124 */ 01125 template<class vec_t=ovector_const_view> class o2scl_interp { 01126 01127 #ifndef DOXYGEN_INTERNAL 01128 01129 protected: 01130 01131 /// Pointer to base interpolation object 01132 base_interp<vec_t> *itp; 01133 01134 /// Pointer to base interpolation manager 01135 base_interp_mgr<vec_t> *bim1; 01136 01137 #endif 01138 01139 public: 01140 01141 /** \brief Default base interpolation object (cubic spline with 01142 natural boundary conditions) 01143 */ 01144 def_interp_mgr<vec_t,cspline_interp> dim1; 01145 01146 /// Create with base interpolation object \c it 01147 o2scl_interp(base_interp_mgr<vec_t> &it) { 01148 bim1=⁢ 01149 itp=bim1->new_interp(); 01150 } 01151 01152 /** \brief Create an interpolator using the default 01153 cubic spline interpolation 01154 */ 01155 o2scl_interp() { 01156 bim1=&dim1; 01157 itp=bim1->new_interp(); 01158 } 01159 01160 virtual ~o2scl_interp() { 01161 bim1->free_interp(itp); 01162 } 01163 01164 /// Give the value of the function \f$ y(x=x_0) \f$ . 01165 virtual double interp(const double x0, size_t n, const vec_t &x, 01166 const vec_t &y) { 01167 01168 double ret=0.0; 01169 01170 if (n<itp->min_size) { 01171 O2SCL_ERR("Vector size too small in interp().",gsl_edom); 01172 } 01173 01174 int r1=itp->allocate(n); 01175 if (r1==0) { 01176 int r2=itp->init(x,y,n); 01177 if (r2==0) { 01178 itp->interp(x,y,n,x0,ret); 01179 } 01180 itp->free(); 01181 } 01182 01183 return ret; 01184 } 01185 01186 /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ . 01187 virtual double deriv(const double x0, size_t n, const vec_t &x, 01188 const vec_t &y) { 01189 01190 double ret=0.0; 01191 01192 if (n<itp->min_size) { 01193 O2SCL_ERR("Vector size too small in deriv().",gsl_edom); 01194 } 01195 01196 int r1=itp->allocate(n); 01197 if (r1==0) { 01198 int r2=itp->init(x,y,n); 01199 if (r2==0) { 01200 itp->deriv(x,y,n,x0,ret); 01201 } 01202 itp->free(); 01203 } 01204 01205 return ret; 01206 } 01207 01208 /** \brief Give the value of the second derivative 01209 \f$ y^{\prime \prime}(x=x_0) \f$ . 01210 */ 01211 virtual double deriv2(const double x0, size_t n, const vec_t &x, 01212 const vec_t &y) { 01213 01214 double ret=0.0; 01215 01216 if (n<itp->min_size) { 01217 O2SCL_ERR("Vector size too small in deriv2().",gsl_edom); 01218 } 01219 01220 // Increasing case 01221 01222 int r1=itp->allocate(n); 01223 if (r1==0) { 01224 int r2=itp->init(x,y,n); 01225 if (r2==0) { 01226 itp->deriv2(x,y,n,x0,ret); 01227 } 01228 itp->free(); 01229 } 01230 01231 return ret; 01232 } 01233 01234 /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ . 01235 virtual double integ(const double x1, const double x2, size_t n, 01236 const vec_t &x, const vec_t &y) { 01237 01238 double ret=0.0; 01239 01240 if (n<itp->min_size) { 01241 O2SCL_ERR("Vector size too small in integ().",gsl_edom); 01242 } 01243 01244 // Increasing case 01245 01246 int r1=itp->allocate(n); 01247 if (r1==0) { 01248 int r2=itp->init(x,y,n); 01249 if (r2==0) { 01250 itp->integ(x,y,n,x1,x2,ret); 01251 } 01252 itp->free(); 01253 } 01254 01255 return ret; 01256 } 01257 01258 /// Set base interpolation object 01259 int set_type(base_interp_mgr<vec_t> &it) { 01260 bim1->free_interp(itp); 01261 bim1=⁢ 01262 itp=bim1->new_interp(); 01263 return 0; 01264 } 01265 01266 #ifndef DOXYGEN_INTERNAL 01267 01268 private: 01269 01270 o2scl_interp<vec_t>(const o2scl_interp<vec_t> &); 01271 o2scl_interp<vec_t>& operator=(const o2scl_interp<vec_t>&); 01272 01273 #endif 01274 01275 }; 01276 01277 /** \brief Interpolation class for pre-specified vector 01278 01279 This interpolation class is intended to be sufficiently general 01280 to handle any vector type. Interpolation of \ref ovector like 01281 objects is performed with the default template parameters, and 01282 \ref array_interp_vec is provided for simple interpolation on 01283 C-style arrays. 01284 01285 This class does not double check the vector to ensure that 01286 all of the intervals for the abcissa are all increasing or 01287 all decreasing. 01288 01289 The type of interpolation to be performed can be specified 01290 using the set_type() function. The default is cubic splines 01291 with natural boundary conditions. 01292 */ 01293 template<class vec_t=ovector_const_view> class o2scl_interp_vec { 01294 01295 #ifndef DOXYGEN_INTERNAL 01296 01297 protected: 01298 01299 /// Base interpolation object 01300 base_interp<vec_t> *itp; 01301 01302 /// The interpolation manager 01303 base_interp_mgr<vec_t> *bim; 01304 01305 /// True if the original array was increasing 01306 bool inc; 01307 01308 /// Pointer to the user-specified x vector 01309 const vec_t *lx; 01310 01311 /// Pointer to the user-specified x vector 01312 const vec_t *ly; 01313 01314 /// Size of user-specified vectors 01315 size_t ln; 01316 01317 #endif 01318 01319 public: 01320 01321 /// Create with base interpolation object \c it 01322 o2scl_interp_vec(base_interp_mgr<vec_t> &it, 01323 size_t n, const vec_t &x, const vec_t &y) { 01324 01325 bim=⁢ 01326 itp=bim->new_interp(); 01327 ln=0; 01328 lx=0; 01329 ly=0; 01330 01331 if (n<itp->min_size) { 01332 O2SCL_ERR("Vector size too small in o2scl_interp_vec().",gsl_edom); 01333 } 01334 01335 size_t iend=n-1; 01336 01337 if (x[0]==x[iend]) { 01338 O2SCL_ERR("Vector endpoints equal in o2scl_interp_vec().", 01339 gsl_einval); 01340 } 01341 01342 int r1=itp->allocate(n); 01343 if (r1==0) { 01344 int r2=itp->init(x,y,n); 01345 if (r2==0) { 01346 ln=n; 01347 lx=&x; 01348 ly=&y; 01349 inc=true; 01350 } else { 01351 itp->free(); 01352 } 01353 } 01354 01355 } 01356 01357 virtual ~o2scl_interp_vec() { 01358 if (ln>0) { 01359 itp->free(); 01360 } 01361 bim->free_interp(itp); 01362 } 01363 01364 /// Give the value of the function \f$ y(x=x_0) \f$ . 01365 virtual double interp(const double x0) { 01366 double ret=0.0; 01367 if (ln>0) { 01368 itp->interp(*lx,*ly,ln,x0,ret); 01369 return ret; 01370 } 01371 O2SCL_ERR2_RET("No data to interpolate in ", 01372 "o2scl_interp_vec::interp().",gsl_efailed); 01373 return ret; 01374 } 01375 01376 /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ . 01377 virtual double deriv(const double x0) { 01378 double ret=0.0; 01379 if (ln>0) { 01380 itp->deriv(*lx,*ly,ln,x0,ret); 01381 return ret; 01382 } 01383 O2SCL_ERR2_RET("No data to interpolate in ", 01384 "o2scl_interp_vec::deriv().",gsl_efailed); 01385 return ret; 01386 } 01387 01388 /** \brief Give the value of the second derivative 01389 \f$ y^{\prime \prime}(x=x_0) \f$ . 01390 */ 01391 virtual double deriv2(const double x0) { 01392 double ret=0.0; 01393 if (ln>0) { 01394 itp->deriv2(*lx,*ly,ln,x0,ret); 01395 return ret; 01396 } 01397 O2SCL_ERR2_RET("No data to interpolate in ", 01398 "o2scl_interp_vec::deriv2().",gsl_efailed); 01399 return ret; 01400 } 01401 01402 /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ . 01403 virtual double integ(const double x1, const double x2) { 01404 double ret=0.0; 01405 if (ln>0) { 01406 itp->integ(*lx,*ly,ln,x1,x2,ret); 01407 return ret; 01408 } 01409 O2SCL_ERR2_RET("No data to interpolate in ", 01410 "o2scl_interp_vec::integ().",gsl_efailed); 01411 return ret; 01412 } 01413 01414 /// Set base interpolation object 01415 int set_type(base_interp_mgr<vec_t> &it) { 01416 bim=⁢ 01417 return 0; 01418 } 01419 01420 #ifndef DOXYGEN_INTERNAL 01421 01422 private: 01423 01424 o2scl_interp_vec<vec_t>(const o2scl_interp_vec<vec_t> &); 01425 o2scl_interp_vec<vec_t>& operator=(const o2scl_interp_vec<vec_t>&); 01426 01427 01428 #endif 01429 01430 }; 01431 01432 /** \brief A specialization of o2scl_interp for C-style double arrays 01433 */ 01434 template<size_t n> class array_interp : public o2scl_interp<double[n]> { 01435 01436 public: 01437 01438 /// Create with base interpolation objects \c it and \c rit 01439 array_interp(base_interp_mgr<double[n]> &it) 01440 : o2scl_interp<double[n]>(it) {} 01441 01442 /** \brief Create an interpolator using the default base 01443 interpolation objects 01444 */ 01445 array_interp() : o2scl_interp<double[n]>() {} 01446 01447 }; 01448 01449 /** \brief A specialization of o2scl_interp_vec for C-style arrays 01450 */ 01451 template<class arr_t> class array_interp_vec : 01452 public o2scl_interp_vec<arr_t> { 01453 01454 public: 01455 01456 /// Create with base interpolation object \c it 01457 array_interp_vec(base_interp_mgr<arr_t> &it, 01458 size_t nv, const arr_t &x, const arr_t &y) : 01459 o2scl_interp_vec<arr_t>(it,nv,x,y) {} 01460 01461 }; 01462 01463 #ifndef DOXYGENP 01464 } 01465 #endif 01466 01467 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).