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_SMART_INTERP_H 00024 #define O2SCL_SMART_INTERP_H 00025 00026 #include <o2scl/interp.h> 00027 00028 #ifndef DOXYGENP 00029 namespace o2scl { 00030 #endif 00031 00032 /** 00033 \brief Smart interpolation class 00034 00035 This class can semi-intelligently handle arrays which are 00036 not-well formed outside the interpolation region. In particular, 00037 if an initial interpolation or derivative calculation fails, the 00038 arrays are searched for the largest neighborhood around the 00039 point \c x for which an interpolation or differentiation will 00040 likely produce a finite result. 00041 00042 \note This attempts to determine if the array is increasing or 00043 decreasing by examining the relative size of the first 00044 and last elements. 00045 00046 \future Change the determination of the array is increasing 00047 to be a bit more intelligent. 00048 00049 */ 00050 template<class vec_t=ovector_const_view, 00051 class rvec_t=ovector_const_reverse, 00052 class svec_t=ovector_const_subvector, 00053 class srvec_t=ovector_const_subvector_reverse> class smart_interp { 00054 00055 #ifndef DOXYGEN_INTERNAL 00056 00057 protected: 00058 00059 /// \name Storage internally created subvectors 00060 //@{ 00061 bool sxalloc; 00062 const svec_t *sx; 00063 const svec_t *sy; 00064 00065 bool srxalloc; 00066 const srvec_t *srx; 00067 const srvec_t *sry; 00068 //@} 00069 00070 /// \name Pointers to interpolation objects 00071 //@{ 00072 base_interp<vec_t> *rit1; 00073 base_interp<rvec_t> *rit2; 00074 base_interp<svec_t> *rit3; 00075 base_interp<srvec_t> *rit4; 00076 //@} 00077 00078 /// \name Pointers to interpolation managers 00079 //@{ 00080 base_interp_mgr<vec_t> *bim1; 00081 base_interp_mgr<rvec_t> *bim2; 00082 base_interp_mgr<svec_t> *bim3; 00083 base_interp_mgr<srvec_t> *bim4; 00084 //@} 00085 00086 #endif 00087 00088 public: 00089 00090 /** \brief Create a new interpolation object with the specified 00091 interpolation managers 00092 */ 00093 smart_interp(base_interp_mgr<vec_t> &im1, 00094 base_interp_mgr<rvec_t> &im2, 00095 base_interp_mgr<svec_t> &im3, 00096 base_interp_mgr<srvec_t> &im4) { 00097 00098 sxalloc=false; 00099 sx=0; 00100 sy=0; 00101 srxalloc=false; 00102 srx=0; 00103 sry=0; 00104 00105 bim1=&im1; 00106 bim2=&im2; 00107 bim3=&im3; 00108 bim4=&im4; 00109 00110 rit1=bim1->new_interp(); 00111 rit2=bim2->new_interp(); 00112 rit3=bim3->new_interp(); 00113 rit4=bim4->new_interp(); 00114 }; 00115 00116 /** \brief Create an interpolation object with the default 00117 cubic spline interpolation managers 00118 */ 00119 smart_interp() { 00120 sxalloc=false; 00121 sx=0; 00122 sy=0; 00123 srxalloc=false; 00124 srx=0; 00125 sry=0; 00126 00127 bim1=&dim1; 00128 bim2=&dim2; 00129 bim3=&dim3; 00130 bim4=&dim4; 00131 00132 rit1=bim1->new_interp(); 00133 rit2=bim2->new_interp(); 00134 rit3=bim3->new_interp(); 00135 rit4=bim4->new_interp(); 00136 }; 00137 00138 virtual ~smart_interp() { 00139 if (sxalloc) { 00140 delete sx; 00141 delete sy; 00142 } 00143 if (srxalloc) { 00144 delete srx; 00145 delete sry; 00146 } 00147 00148 /* 00149 We don't want to use "bim1->free_interp(rit1)" here instead 00150 of "delete rit1" because the pointer "bim1" may refer to 00151 a user-defined interpolation manager, and it may have gone 00152 out of scope earlier. 00153 */ 00154 delete rit1; 00155 delete rit2; 00156 delete rit3; 00157 delete rit4; 00158 } 00159 00160 /** 00161 \brief Give the value of the function \f$ y(x=x_0) \f$ . 00162 00163 \todo After calling find_subset, I think we might need 00164 to double check that \c nn is larger than the minimum 00165 interpolation size. 00166 */ 00167 virtual double interp(const double x0, size_t n, const vec_t &x, 00168 const vec_t &y) { 00169 00170 bool increasing=true, to_subset=false; 00171 double ret=0.0; 00172 int err0, err1, err2; 00173 00174 // Determine if array is increasing or decreasing 00175 00176 if (x[0]==x[n-1]) { 00177 to_subset=true; 00178 } else if (x[0]>x[n-1]) { 00179 increasing=false; 00180 } 00181 00182 if (increasing) { 00183 00184 if (n<rit1->min_size || n<rit2->min_size) { 00185 O2SCL_ERR("Vector size too small in interp().",gsl_edom); 00186 return 0.0; 00187 } 00188 err0=rit1->allocate(n); 00189 if (err0==0) { 00190 err1=rit1->init(x,y,n); 00191 if (err1==0) { 00192 err2=rit1->interp(x,y,n,x0,ret); 00193 if (err2!=0) to_subset=true; 00194 } else { 00195 to_subset=true; 00196 } 00197 rit1->free(); 00198 } 00199 00200 } else { 00201 00202 if (n<rit2->min_size) { 00203 O2SCL_ERR("Vector size too small in interp().",gsl_edom); 00204 return 0.0; 00205 } 00206 00207 rvec_t rx(x); 00208 rvec_t ry(y); 00209 00210 err0=rit2->allocate(n); 00211 if (err0==0) { 00212 err1=rit2->init(rx,ry,n); 00213 if (err1==0) { 00214 err2=rit2->interp(rx,ry,n,x0,ret); 00215 if (err2!=0) to_subset=true; 00216 } else { 00217 to_subset=true; 00218 } 00219 rit2->free(); 00220 } 00221 00222 } 00223 00224 if (!finite(ret)) to_subset=true; 00225 00226 if (to_subset) { 00227 00228 size_t nn=0; 00229 int retfs=find_subset(x0,x0,n,x,y,nn,increasing); 00230 00231 if (retfs!=0 || nn<=1) { 00232 O2SCL_ERR("Interpolation failed in interp().",gsl_efailed); 00233 return 0; 00234 } 00235 00236 if (increasing) { 00237 if (nn>=rit3->min_size) { 00238 err0=rit3->allocate(nn); 00239 if (err0==0) { 00240 err1=rit3->init(*sx,*sy,nn); 00241 if (err1==0) { 00242 err2=rit3->interp(*sx,*sy,nn,x0,ret); 00243 } 00244 rit3->free(); 00245 } 00246 } else { 00247 O2SCL_ERR("Interpolation failed in interp().",gsl_efailed); 00248 } 00249 } else { 00250 if (nn>=rit4->min_size) { 00251 err0=rit4->allocate(nn); 00252 if (err0==0) { 00253 err1=rit4->init(*srx,*sry,nn); 00254 if (err1==0) { 00255 err2=rit4->interp(*srx,*sry,nn,x0,ret); 00256 } 00257 rit4->free(); 00258 } 00259 } else { 00260 O2SCL_ERR("Interpolation failed in interp().",gsl_efailed); 00261 } 00262 } 00263 00264 } 00265 00266 return ret; 00267 } 00268 00269 /// Give the value of the derivative \f$ y^{prime}(x=x_0) \f$ . 00270 virtual double deriv(const double x0, size_t n, const vec_t &x, 00271 const vec_t &y) { 00272 00273 bool increasing=true, to_subset=false; 00274 double ret=0.0; 00275 int err0, err1, err2; 00276 00277 // Determine if array is increasing or decreasing 00278 00279 if (x[0]==x[n-1]) { 00280 to_subset=true; 00281 } else if (x[0]>x[n-1]) { 00282 increasing=false; 00283 } 00284 00285 if (increasing) { 00286 00287 if (n<rit1->min_size || n<rit2->min_size) { 00288 O2SCL_ERR("Vector size too small in deriv().",gsl_edom); 00289 return 0.0; 00290 } 00291 err0=rit1->allocate(n); 00292 if (err0==0) { 00293 err1=rit1->init(x,y,n); 00294 if (err1==0) { 00295 err2=rit1->deriv(x,y,n,x0,ret); 00296 if (err2!=0) to_subset=true; 00297 } else { 00298 to_subset=true; 00299 } 00300 rit1->free(); 00301 } 00302 00303 } else { 00304 00305 if (n<rit2->min_size) { 00306 O2SCL_ERR("Vector size too small in deriv().",gsl_edom); 00307 return 0.0; 00308 } 00309 00310 rvec_t rx(x); 00311 rvec_t ry(y); 00312 00313 err0=rit2->allocate(n); 00314 if (err0==0) { 00315 err1=rit2->init(rx,ry,n); 00316 if (err1==0) { 00317 err2=rit2->deriv(rx,ry,n,x0,ret); 00318 if (err2!=0) to_subset=true; 00319 } else { 00320 to_subset=true; 00321 } 00322 rit2->free(); 00323 } 00324 00325 } 00326 00327 if (!finite(ret)) to_subset=true; 00328 00329 if (to_subset) { 00330 00331 size_t nn=0; 00332 int retfs=find_subset(x0,x0,n,x,y,nn,increasing); 00333 00334 if (retfs!=0 || nn<=1) { 00335 O2SCL_ERR("Interpolation failed in deriv().",gsl_efailed); 00336 return 0; 00337 } 00338 00339 if (increasing) { 00340 if (nn>=rit3->min_size) { 00341 err0=rit3->allocate(nn); 00342 if (err0==0) { 00343 err1=rit3->init(*sx,*sy,nn); 00344 if (err1==0) { 00345 err2=rit3->deriv(*sx,*sy,nn,x0,ret); 00346 } 00347 rit3->free(); 00348 } 00349 } else { 00350 O2SCL_ERR("Interpolation failed in deriv().",gsl_efailed); 00351 } 00352 } else { 00353 if (nn>=rit4->min_size) { 00354 err0=rit4->allocate(nn); 00355 if (err0==0) { 00356 err1=rit4->init(*srx,*sry,nn); 00357 if (err1==0) { 00358 err2=rit4->deriv(*srx,*sry,nn,x0,ret); 00359 } 00360 rit4->free(); 00361 } 00362 } else { 00363 O2SCL_ERR("Interpolation failed in deriv().",gsl_efailed); 00364 } 00365 } 00366 00367 } 00368 00369 return ret; 00370 } 00371 00372 /** \brief Give the value of the second derivative 00373 \f$ y^{prime \prime}(x=x_0) \f$ . 00374 */ 00375 virtual double deriv2(const double x0, size_t n, const vec_t &x, 00376 const vec_t &y) { 00377 00378 bool increasing=true, to_subset=false; 00379 double ret=0.0; 00380 int err0, err1, err2; 00381 00382 // Determine if array is increasing or decreasing 00383 00384 if (x[0]==x[n-1]) { 00385 to_subset=true; 00386 } else if (x[0]>x[n-1]) { 00387 increasing=false; 00388 } 00389 00390 if (increasing) { 00391 00392 if (n<rit1->min_size || n<rit2->min_size) { 00393 O2SCL_ERR("Vector size too small in deriv2().",gsl_edom); 00394 return 0.0; 00395 } 00396 err0=rit1->allocate(n); 00397 if (err0==0) { 00398 err1=rit1->init(x,y,n); 00399 if (err1==0) { 00400 err2=rit1->deriv2(x,y,n,x0,ret); 00401 if (err2!=0) to_subset=true; 00402 } else { 00403 to_subset=true; 00404 } 00405 rit1->free(); 00406 } 00407 00408 } else { 00409 00410 if (n<rit2->min_size) { 00411 O2SCL_ERR("Vector size too small in deriv2().",gsl_edom); 00412 return 0.0; 00413 } 00414 00415 rvec_t rx(x); 00416 rvec_t ry(y); 00417 00418 err0=rit2->allocate(n); 00419 if (err0==0) { 00420 err1=rit2->init(rx,ry,n); 00421 if (err1==0) { 00422 err2=rit2->deriv2(rx,ry,n,x0,ret); 00423 if (err2!=0) to_subset=true; 00424 } else { 00425 to_subset=true; 00426 } 00427 rit2->free(); 00428 } 00429 00430 } 00431 00432 if (!finite(ret)) to_subset=true; 00433 00434 if (to_subset) { 00435 00436 size_t nn=0; 00437 int retfs=find_subset(x0,x0,n,x,y,nn,increasing); 00438 00439 if (retfs!=0 || nn<=1) { 00440 O2SCL_ERR("Interpolation failed in deriv2().",gsl_efailed); 00441 return 0; 00442 } 00443 00444 if (increasing) { 00445 if (nn>=rit3->min_size) { 00446 err0=rit3->allocate(nn); 00447 if (err0==0) { 00448 err1=rit3->init(*sx,*sy,nn); 00449 if (err1==0) { 00450 err2=rit3->deriv2(*sx,*sy,nn,x0,ret); 00451 } 00452 rit3->free(); 00453 } 00454 } else { 00455 O2SCL_ERR("Interpolation failed in deriv2().",gsl_efailed); 00456 } 00457 } else { 00458 if (nn>=rit4->min_size) { 00459 err0=rit4->allocate(nn); 00460 if (err0==0) { 00461 err1=rit4->init(*srx,*sry,nn); 00462 if (err1==0) { 00463 err2=rit4->deriv2(*srx,*sry,nn,x0,ret); 00464 } 00465 rit4->free(); 00466 } 00467 } else { 00468 O2SCL_ERR("Interpolation failed in deriv2().",gsl_efailed); 00469 } 00470 } 00471 00472 } 00473 00474 return ret; 00475 } 00476 00477 /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ . 00478 virtual double integ(const double a, const double b, 00479 size_t n, const vec_t &x, const vec_t &y) { 00480 00481 bool increasing=true, to_subset=false; 00482 double ret=0.0; 00483 int err0, err1, err2; 00484 00485 // Determine if array is increasing or decreasing 00486 00487 if (x[0]==x[n-1]) { 00488 to_subset=true; 00489 } else if (x[0]>x[n-1]) { 00490 increasing=false; 00491 } 00492 00493 if (increasing) { 00494 00495 if (n<rit1->min_size || n<rit2->min_size) { 00496 O2SCL_ERR("Vector size too small in integ().",gsl_edom); 00497 return 0.0; 00498 } 00499 err0=rit1->allocate(n); 00500 if (err0==0) { 00501 err1=rit1->init(x,y,n); 00502 if (err1==0) { 00503 err2=rit1->integ(x,y,n,a,b,ret); 00504 if (err2!=0) to_subset=true; 00505 } else { 00506 to_subset=true; 00507 } 00508 rit1->free(); 00509 } 00510 00511 } else { 00512 00513 if (n<rit2->min_size) { 00514 O2SCL_ERR("Vector size too small in integ().",gsl_edom); 00515 return 0.0; 00516 } 00517 00518 rvec_t rx(x); 00519 rvec_t ry(y); 00520 00521 err0=rit2->allocate(n); 00522 if (err0==0) { 00523 err1=rit2->init(rx,ry,n); 00524 if (err1==0) { 00525 err2=rit2->integ(rx,ry,n,a,b,ret); 00526 if (err2!=0) to_subset=true; 00527 } else { 00528 to_subset=true; 00529 } 00530 rit2->free(); 00531 } 00532 00533 } 00534 00535 if (!finite(ret)) to_subset=true; 00536 00537 if (to_subset) { 00538 00539 size_t nn=0; 00540 int retfs=find_subset(a,b,n,x,y,nn,increasing); 00541 00542 if (retfs!=0 || nn<=1) { 00543 O2SCL_ERR("Interpolation failed in integ().",gsl_efailed); 00544 return 0; 00545 } 00546 00547 if (increasing) { 00548 if (nn>=rit3->min_size) { 00549 err0=rit3->allocate(nn); 00550 if (err0==0) { 00551 err1=rit3->init(*sx,*sy,nn); 00552 if (err1==0) { 00553 err2=rit3->integ(*sx,*sy,nn,a,b,ret); 00554 } 00555 rit3->free(); 00556 } 00557 } else { 00558 O2SCL_ERR("Interpolation failed in integ().",gsl_efailed); 00559 } 00560 } else { 00561 if (nn>=rit4->min_size) { 00562 err0=rit4->allocate(nn); 00563 if (err0==0) { 00564 err1=rit4->init(*srx,*sry,nn); 00565 if (err1==0) { 00566 err2=rit4->integ(*srx,*sry,nn,a,b,ret); 00567 } 00568 rit4->free(); 00569 } 00570 } else { 00571 O2SCL_ERR("Interpolation failed in integ().",gsl_efailed); 00572 } 00573 } 00574 00575 } 00576 00577 return ret; 00578 } 00579 00580 /// \name Default interpolation managers 00581 //@{ 00582 def_interp_mgr<vec_t,cspline_interp> dim1; 00583 def_interp_mgr<rvec_t,cspline_interp> dim2; 00584 def_interp_mgr<svec_t,cspline_interp> dim3; 00585 def_interp_mgr<srvec_t,cspline_interp> dim4; 00586 //@} 00587 00588 #ifndef DOXGYEN_INTERNAL 00589 00590 protected: 00591 00592 /** \brief A lookup function for generic vectors 00593 */ 00594 size_t local_lookup(size_t n, const vec_t &x, double x0) { 00595 size_t row=0, i=0; 00596 while(!finite(x[i]) && i<n-1) i++; 00597 if (i==n-1) { 00598 return 0; 00599 } 00600 double best=x[i], bdiff=fabs(x[i]-x0); 00601 for(;i<n;i++) { 00602 if (finite(x[i]) && fabs(x[i]-x0)<bdiff) { 00603 row=i; 00604 best=x[i]; 00605 bdiff=fabs(x[i]-x0); 00606 } 00607 } 00608 return row; 00609 } 00610 00611 /** \brief Try to find the largest monotonic and finite region 00612 around the desired location 00613 00614 This function tries to find the largest monotonic region 00615 enclosing both \c a and \c b in the vector \c x. If it succeeds, 00616 it returns \ref gsl_success, and if it fails, it returns \ref 00617 gsl_efailed. It does not call the error handler. 00618 00619 \todo The error handling is a bit off here, as it can return 00620 a non-zero value even with there is no real "error". We should 00621 just make a new bool reference paramter. 00622 */ 00623 int find_subset(const double a, const double b, size_t sz, const vec_t &x, 00624 const vec_t &y, size_t &nsz, bool &increasing) 00625 { 00626 00627 size_t left, right; 00628 00629 // Lookup the point 00630 size_t row=local_lookup(sz,x,a); 00631 if (!finite(x[row]) || !finite(y[row])) { 00632 return gsl_efailed; 00633 } 00634 size_t row2=local_lookup(sz,x,b); 00635 if (!finite(x[row2]) || !finite(y[row2])) { 00636 return gsl_efailed; 00637 } 00638 00639 // Get a neighboring point if necessary 00640 if (row2==row) { 00641 row2=row++; 00642 if (row2>=sz) row2=row-1; 00643 } 00644 00645 // Arrange 00646 if (row<row2) { 00647 left=row; 00648 right=row2; 00649 } else { 00650 left=row2; 00651 right=row; 00652 } 00653 00654 // Establish whether we're increasing or decreasing 00655 increasing=true; 00656 if (row2<row && x[row]<x[row2]) increasing=false; 00657 if (row2>row && x[row2]<x[row]) increasing=false; 00658 00659 // Check region between row and row2 00660 00661 if (increasing) { 00662 size_t lo, hi; 00663 if (row2<row) { 00664 lo=row2; 00665 hi=row; 00666 } else { 00667 lo=row; 00668 hi=row2; 00669 } 00670 for(size_t i=lo;i<hi-1;i++) { 00671 if (x[i]>x[i+1]) return gsl_efailed; 00672 } 00673 } else { 00674 size_t lo, hi; 00675 if (row2<row) { 00676 lo=row2; 00677 hi=row; 00678 } else { 00679 lo=row; 00680 hi=row2; 00681 } 00682 for(size_t i=lo;i<hi-1;i++) { 00683 if (x[i]<x[i+1]) return gsl_efailed; 00684 } 00685 } 00686 00687 // Increasing case 00688 00689 if (increasing) { 00690 00691 while(left>0 && x[left-1]<x[left] && 00692 finite(x[left-1]) && finite(y[left-1])) left--; 00693 while(right<sz-1 && x[right]<x[right+1] && 00694 finite(x[right+1]) && finite(y[right+1])) right++; 00695 00696 nsz=right-left+1; 00697 00698 if (sxalloc) { 00699 delete sx; 00700 delete sy; 00701 } 00702 sx=new svec_t(x,left,nsz); 00703 sy=new svec_t(y,left,nsz); 00704 sxalloc=true; 00705 00706 } else { 00707 00708 while(left>0 && x[left-1]>x[left] && 00709 finite(x[left-1]) && finite(y[left-1])) left--; 00710 while(right<sz-1 && x[right]>x[right+1] && 00711 finite(x[right+1]) && finite(y[right+1])) right++; 00712 00713 nsz=right-left+1; 00714 00715 if (srxalloc==true) { 00716 delete srx; 00717 delete sry; 00718 } 00719 srx=new srvec_t(x,left,nsz); 00720 sry=new srvec_t(y,left,nsz); 00721 srxalloc=true; 00722 00723 } 00724 00725 return 0; 00726 } 00727 00728 #endif 00729 00730 }; 00731 00732 /** 00733 \brief Smart interpolation class with pre-specified vectors 00734 00735 This class can semi-intelligently handle arrays which are 00736 not-well formed outside the interpolation region. In particular, 00737 if an initial interpolation or derivative calculation fails, the 00738 arrays are searched for the largest neighborhood around the 00739 point \c x for which an interpolation or differentiation will 00740 likely produce a finite result. 00741 00742 \future Properly implement handling of non-monotonic regions 00743 in the derivative functions as well as the interpolation function. 00744 00745 */ 00746 template<class vec_t, class svec_t, class alloc_vec_t, class alloc_t> 00747 class smart_interp_vec { 00748 00749 #ifndef DOXYGEN_INTERNAL 00750 00751 protected: 00752 00753 /// If true, then \ref sx and \ref sy have been allocated 00754 bool sxalloc; 00755 /// Storage for internally created subvector 00756 svec_t *sx; 00757 /// Storage for internally created subvector 00758 svec_t *sy; 00759 00760 /// Pointer to base interpolation object 00761 base_interp<vec_t> *rit1; 00762 /// Pointer to base interpolation object 00763 base_interp<svec_t> *rit2; 00764 00765 /// Pointer to base interpolation manager 00766 base_interp_mgr<vec_t> *bim1; 00767 00768 /// Pointer to base interpolation manager 00769 base_interp_mgr<svec_t> *bim2; 00770 00771 /// Memory allocator for objects of type \c alloc_vec_t 00772 alloc_t ao; 00773 00774 /// True if the user-specified x vector is increasing 00775 bool inc; 00776 00777 /// Pointer to user-specified vector 00778 const vec_t *lx; 00779 /// Pointer to user-specified vector 00780 const vec_t *ly; 00781 00782 /// Reversed version of vector 00783 alloc_vec_t lrx; 00784 /// Reversed version of vector 00785 alloc_vec_t lry; 00786 00787 /// Size of user-specifed vector 00788 size_t ln; 00789 00790 #endif 00791 00792 public: 00793 00794 /// Create with base interpolation objects \c it and \c rit 00795 smart_interp_vec(size_t n, const vec_t &x, const vec_t &y) { 00796 sx=0; 00797 sy=0; 00798 sxalloc=false; 00799 00800 bim1=&dim1; 00801 bim2=&dim2; 00802 00803 rit1=bim1->new_interp(); 00804 rit2=bim2->new_interp(); 00805 ln=0; 00806 00807 if (n<rit1->min_size || n<rit2->min_size) { 00808 O2SCL_ERR("Vector size too small in o2scl_interp_vec().",gsl_edom); 00809 } else { 00810 00811 if (x[0]>x[n-1]) { 00812 00813 ao.allocate(lrx,n); 00814 ao.allocate(lry,n); 00815 00816 for(size_t i=0;i<n;i++) { 00817 lrx[n-1-i]=x[i]; 00818 lry[n-1-i]=y[i]; 00819 } 00820 00821 int r1=rit1->allocate(n); 00822 if (r1==0) { 00823 rit1->init(lrx,lry,n); 00824 ln=n; 00825 inc=false; 00826 } 00827 00828 } else { 00829 00830 int r1=rit1->allocate(n); 00831 if (r1==0) { 00832 rit1->init(x,y,n); 00833 ln=n; 00834 lx=&x; 00835 ly=&y; 00836 inc=true; 00837 } 00838 00839 } 00840 00841 } 00842 00843 } 00844 00845 /// Create with base interpolation objects \c it and \c rit 00846 smart_interp_vec(base_interp_mgr<vec_t> &it1, 00847 base_interp_mgr<svec_t> &it2, 00848 size_t n, const vec_t &x, const vec_t &y) { 00849 sx=0; 00850 sy=0; 00851 sxalloc=false; 00852 00853 bim1=&it1; 00854 bim2=&it2; 00855 00856 rit1=bim1->new_interp(); 00857 rit2=bim2->new_interp(); 00858 ln=0; 00859 00860 if (n<rit1->min_size || n<rit2->min_size) { 00861 O2SCL_ERR("Vector size too small in o2scl_interp_vec().",gsl_edom); 00862 } else { 00863 00864 if (x[0]>x[n-1]) { 00865 00866 ao.allocate(lrx,n); 00867 ao.allocate(lry,n); 00868 00869 for(size_t i=0;i<n;i++) { 00870 lrx[n-1-i]=x[i]; 00871 lry[n-1-i]=y[i]; 00872 } 00873 00874 int r1=rit1->allocate(n); 00875 if (r1==0) { 00876 rit1->init(lrx,lry,n); 00877 ln=n; 00878 inc=false; 00879 } 00880 00881 } else { 00882 00883 int r1=rit1->allocate(n); 00884 if (r1==0) { 00885 rit1->init(x,y,n); 00886 ln=n; 00887 lx=&x; 00888 ly=&y; 00889 inc=true; 00890 } 00891 00892 } 00893 00894 } 00895 00896 } 00897 00898 virtual ~smart_interp_vec() { 00899 if (sxalloc) { 00900 delete sx; 00901 delete sy; 00902 } 00903 00904 if (ln>0) { 00905 rit1->free(); 00906 if (inc==false) { 00907 ao.free(lrx); 00908 ao.free(lry); 00909 } 00910 } 00911 00912 /* 00913 We don't want to use "bim1->free_interp(rit1)" here instead 00914 of "delete rit1" because the pointer "bim1" may refer to 00915 a user-defined interpolation manager, and it may have gone 00916 out of scope earlier. 00917 */ 00918 delete rit1; 00919 delete rit2; 00920 } 00921 00922 /// Give the value of the function \f$ y(x=x_0) \f$ . 00923 virtual double interp(const double x0) { 00924 00925 double ret=0.0; 00926 int err; 00927 if (ln>0) { 00928 00929 if (inc) { 00930 00931 err=rit1->interp(*lx,*ly,ln,x0,ret); 00932 if (err!=gsl_success) { 00933 size_t nn=0; 00934 int retfs=find_inc_subset(x0,ln,*lx,*ly,nn); 00935 00936 if (retfs==0 && nn>1 && nn>=rit2->min_size) { 00937 rit2->allocate(nn); 00938 rit2->init(*sx,*sy,nn); 00939 err=rit2->interp(*sx,*sy,nn,x0,ret); 00940 rit2->free(); 00941 } else { 00942 O2SCL_ERR2("Interpolation failed in ", 00943 "smart_interp_vec::interp().",gsl_efailed); 00944 return 0.0; 00945 } 00946 00947 } 00948 00949 } else { 00950 00951 err=rit1->interp(lrx,lry,ln,x0,ret); 00952 if (err!=gsl_success) { 00953 size_t nn=0; 00954 int retfs=find_inc_subset(x0,ln,lrx,lry,nn); 00955 00956 if (retfs==0 && nn>1 && nn>=rit2->min_size) { 00957 rit2->allocate(nn); 00958 rit2->init(*sx,*sy,nn); 00959 err=rit2->interp(*sx,*sy,nn,x0,ret); 00960 rit2->free(); 00961 } else { 00962 O2SCL_ERR2("Interpolation failed in ", 00963 "smart_interp_vec::interp().",gsl_efailed); 00964 return 0.0; 00965 } 00966 } 00967 00968 } 00969 00970 } 00971 00972 return ret; 00973 } 00974 00975 /// Give the value of the derivative \f$ y^{prime}(x=x_0) \f$ . 00976 virtual double deriv(const double x0) { 00977 double ret=0.0; 00978 if (ln>0) { 00979 if (inc) rit1->deriv(*lx,*ly,ln,x0,ret); 00980 else rit1->deriv(lrx,lry,ln,x0,ret); 00981 } 00982 return ret; 00983 } 00984 00985 /** \brief Give the value of the second derivative 00986 \f$ y^{prime \prime}(x=x_0) \f$ . 00987 */ 00988 virtual double deriv2(const double x0) { 00989 double ret=0.0; 00990 if (ln>0) { 00991 if (inc) rit1->deriv2(*lx,*ly,ln,x0,ret); 00992 else rit1->deriv2(lrx,lry,ln,x0,ret); 00993 } 00994 return ret; 00995 } 00996 00997 /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ . 00998 virtual double integ(const double x1, const double x2) { 00999 double ret=0.0; 01000 if (ln>0) { 01001 if (inc) rit1->integ(*lx,*ly,ln,x1,x2,ret); 01002 else rit1->integ(lrx,lry,ln,x1,x2,ret); 01003 } 01004 return ret; 01005 } 01006 01007 /// Default interpolation manager 01008 def_interp_mgr<vec_t,cspline_interp> dim1; 01009 01010 /// Default interpolation manager 01011 def_interp_mgr<svec_t,cspline_interp> dim2; 01012 01013 #ifndef DOXYGEN_INTERNAL 01014 01015 protected: 01016 01017 /// A lookup function for generic vectors 01018 size_t local_lookup(size_t n, const vec_t &x, double x0) { 01019 size_t row=0, i=0; 01020 while(!finite(x[i]) && i<n-1) i++; 01021 if (i==n-1) { 01022 return 0; 01023 } 01024 double best=x[i], bdiff=fabs(x[i]-x0); 01025 for(;i<n;i++) { 01026 if (finite(x[i]) && fabs(x[i]-x0)<bdiff) { 01027 row=i; 01028 best=x[i]; 01029 bdiff=fabs(x[i]-x0); 01030 } 01031 } 01032 return row; 01033 } 01034 01035 /** \brief Try to find the largest monotonic and finite region 01036 around the desired location 01037 01038 This function looks through the vector \c x near the element 01039 closest to \c x0 to find the largest possible monotonic 01040 region. If it succeeds, it returns \ref gsl_success, and if it 01041 fails, it returns \ref gsl_efailed. It does not call 01042 the error handler. 01043 */ 01044 int find_inc_subset(const double x0, size_t sz, const vec_t &x, 01045 const vec_t &y, size_t &nsz) { 01046 01047 size_t row=local_lookup(sz,x,x0), row2=row++; 01048 size_t left=row, right=row; 01049 01050 if (row2>sz) row2=row-1; 01051 01052 if (!finite(x[row]) || !finite(y[row])) { 01053 return gsl_efailed; 01054 } 01055 01056 // Increasing case 01057 01058 while(left>0 && x[left-1]<x[left] && 01059 finite(x[left-1]) && finite(y[left-1])) left--; 01060 while(right<sz-1 && x[right]<x[right+1] && 01061 finite(x[right+1]) && finite(y[right+1])) right++; 01062 01063 nsz=right-left+1; 01064 01065 if (sxalloc) { 01066 delete sx; 01067 delete sy; 01068 } 01069 sx=new svec_t(x,left,nsz); 01070 sy=new svec_t(y,left,nsz); 01071 sxalloc=true; 01072 01073 return 0; 01074 } 01075 01076 #endif 01077 01078 }; 01079 01080 // sm_interp typedef 01081 typedef smart_interp<ovector_const_view,ovector_const_reverse, 01082 ovector_const_subvector,ovector_const_subvector_reverse> sm_interp; 01083 01084 // sm_interp_vec typedef 01085 typedef smart_interp_vec<ovector_const_view,ovector_const_subvector,ovector, 01086 ovector_alloc> sm_interp_vec; 01087 01088 #ifndef DOXYGENP 01089 01090 /* 01091 At the moment, Doxygen seems to have a real problem correctly 01092 parsing this documentation, so we create a separate version 01093 for documentation below. This is the real class definition here. 01094 */ 01095 template<size_t n> class sma_interp : 01096 public smart_interp<double[n],array_const_reverse<n>,array_const_subvector, 01097 array_const_subvector_reverse> 01098 { 01099 01100 public: 01101 01102 sma_interp(base_interp_mgr<double[n]> &it1, 01103 base_interp_mgr<array_const_reverse<n> > &it2, 01104 base_interp_mgr<array_const_subvector> &it3, 01105 base_interp_mgr<array_const_subvector_reverse> &it4) : 01106 smart_interp<double[n],array_const_reverse<n>, 01107 array_const_subvector, 01108 array_const_subvector_reverse>(it1,it2,it3,it4) { 01109 } 01110 01111 sma_interp() : smart_interp<double[n],array_const_reverse<n>, 01112 array_const_subvector,array_const_subvector_reverse>() { 01113 } 01114 }; 01115 01116 template<class arr_t> class sma_interp_vec : 01117 public smart_interp_vec<arr_t,array_const_subvector,arr_t, 01118 array_alloc<arr_t> > 01119 { 01120 01121 public: 01122 01123 sma_interp_vec(base_interp_mgr<arr_t> &it, 01124 base_interp_mgr<array_const_subvector> &it2, 01125 size_t n, const arr_t &x, const arr_t &y) : 01126 smart_interp_vec<arr_t,array_const_subvector,arr_t, 01127 array_alloc<arr_t> >(it,it2,n,x,y) { 01128 } 01129 01130 sma_interp_vec(size_t n, const arr_t &x, const arr_t &y) : 01131 smart_interp_vec<arr_t,array_const_subvector,arr_t, 01132 array_alloc<arr_t> >(n,x,y) { 01133 } 01134 01135 }; 01136 01137 #endif 01138 01139 /* 01140 This is the separate version of the class documentation for Doxygen 01141 */ 01142 01143 #ifdef DOXYGENP 01144 01145 /** \brief A specialization of smart_interp for C-style double arrays 01146 */ 01147 template<size_t n> class sma_interp : public smart_interp { 01148 01149 public: 01150 01151 /** 01152 \brief Create an interpolation object with user-specified 01153 interpolation types 01154 */ 01155 sma_interp(bim1_t &it1, bim2_t &it2, bim3_t &it3, bim4_t &it4); 01156 01157 /// Create an interpolation object with the default interpolation types 01158 sma_interp(); 01159 01160 }; 01161 01162 /** \brief A specialization of smart_interp_vec for C-style double arrays 01163 */ 01164 template<class arr_t> class sma_interp_vec : smart_interp_vec { 01165 01166 public: 01167 01168 /** 01169 \brief Create an interpolation object with user-specified 01170 interpolation types 01171 */ 01172 sma_interp_vec(bim1_t &it, bim2_t &it2, 01173 size_t n, const arr_t &x, const arr_t &y); 01174 01175 /// Create an interpolation object with the default interpolation types 01176 sma_interp_vec(size_t n, const arr_t &x, const arr_t &y); 01177 01178 }; 01179 01180 #endif 01181 01182 #ifndef DOXYGENP 01183 } 01184 #endif 01185 01186 #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