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