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