libmoost
|
00001 /* vim:set ts=3 sw=3 sts=3 et: */ 00036 #ifndef MOOST_ALGORITHM_SPLINE_INTERPOLATION_HPP 00037 #define MOOST_ALGORITHM_SPLINE_INTERPOLATION_HPP 00038 00039 #include <cassert> 00040 #include <vector> 00041 #include <algorithm> 00042 00043 #include <gsl/gsl_spline.h> // gnu scientific library 00044 00045 #include <boost/noncopyable.hpp> 00046 00047 #include "../utils/scope_exit.hpp" 00048 00049 00050 namespace moost { namespace algorithm { 00051 00060 class spline_interpolation : private boost::noncopyable 00061 { 00062 private: 00063 typedef moost::utils::scope_exit::type< 00064 gsl_interp *>::call_free_function_with_val interp_t; 00065 00066 typedef moost::utils::scope_exit::type< 00067 gsl_interp_accel *>::call_free_function_with_val accel_t; 00068 00069 public: 00070 00071 00085 spline_interpolation( 00086 std::vector<double> const & x, 00087 std::vector<double> const & y) 00088 : interp_(gsl_interp_alloc(gsl_interp_cspline, x.size()), &gsl_interp_free) 00089 , accel_(gsl_interp_accel_alloc(), &gsl_interp_accel_free) 00090 , x_(x) 00091 , y_(y) 00092 00093 { 00094 validate_construction(); // throws on fail 00095 gsl_interp_init(interp_->get(), &x_[0], &y_[0], x_.size()); 00096 } 00097 00098 00113 bool operator () (double const x, double & y, double const z = 0) const 00114 { 00115 bool ok = 0 == gsl_interp_eval_e( 00116 interp_->get(), 00117 &x_[0], &y_[0], x, 00118 accel_->get(), &y 00119 ); 00120 00121 if(!ok) { y = z;} 00122 00123 return ok; 00124 } 00125 00137 double operator () (double const x) const 00138 { 00139 double y = 0.0; 00140 00141 if(!(*this)(x, y)) 00142 { 00143 throw std::range_error("out of range"); 00144 } 00145 00146 return y; 00147 } 00148 00149 private: 00150 00151 void validate_construction() const 00152 { 00153 // x and y must be the same size 00154 assert(x_.size() == y_.size()); 00155 if(x_.size() != y_.size()) 00156 { 00157 throw std::runtime_error("the size of x and y must be the same"); 00158 } 00159 00160 // x must be sorted by-asc (not my rule, gsl demands it) 00161 bool const sorted = (std::adjacent_find(x_.begin(), x_.end(), std::greater_equal<double>()) == x_.end()); 00162 assert(sorted); 00163 if(!sorted) 00164 { 00165 throw std::runtime_error("x must be sorted in assending order"); 00166 } 00167 } 00168 00169 private: 00170 interp_t interp_; 00171 accel_t accel_; 00172 std::vector<double> const & x_; 00173 std::vector<double> const & y_; 00174 }; 00175 00176 00177 }} 00178 00179 #endif // MOOST_ALGORITHM_SPLINE_INTERPOLATION_HPP