/* * This is modification of Tino Kluge tk spline * https://github.com/ttk592/spline/ * * the modification is in LU caclulation, * optimized for tridiagonal matrices */ #include "spline.h" namespace catima{ band_matrix::band_matrix(int dim) { resize(dim); } void band_matrix::resize(int dim) { assert(dim>0); a.resize(dim); d.resize(dim); c.resize(dim); } int band_matrix::dim() const { return d.size(); } // defines the new operator (), so that we can access the elements // by A(i,j), index going from i=0,...,dim()-1 double & band_matrix::operator () (int i, int j) { int k=j-i; // what band is the entry assert( (i>=0) && (i=0) && (j-2); if(k>0)return c[i]; else if(k==0) return d[i]; else return a[i]; } double band_matrix::operator () (int i, int j) const { int k=j-i; // what band is the entry assert( (i>=0) && (i=0) && (j0)return c[i]; else if(k==0) return d[i]; else return a[i]; } std::vector band_matrix::trig_solve(const std::vector& b) const { assert( this->dim()==(int)b.size() ); std::vector x(this->dim()); std::vector g(this->dim()); int j_stop; double sum; assert(d[0]!=0.0); x[0] = b[0]/d[0]; double bet = d[0]; for(int j=1;jdim();j++){ g[j] = c[j-1]/bet; bet = d[j] - (a[j]*g[j]); assert(bet != 0.0); x[j] = (b[j]-a[j]*x[j-1])/bet; } for(int j=this->dim()-2;j>=0;j--){ x[j] -= g[j+1]*x[j+1]; } return x; } // spline implementation // ----------------------- void spline::set_boundary(spline::bd_type left, double left_value, spline::bd_type right, double right_value, bool force_linear_extrapolation) { assert(n==0); // set_points() must not have happened yet m_left=left; m_right=right; m_left_value=left_value; m_right_value=right_value; m_force_linear_extrapolation=force_linear_extrapolation; } void spline::set_points(const double *x, const double *y, const size_t num ) { assert(num>2); m_x=x; m_y=y; n=num; // TODO: maybe sort x and y, rather than returning an error for(int i=0; i rhs(n); for(int i=1; i2); // find the closest point m_x[idx] < x, idx=0 even if xm_x[n-1]) { // extrapolation to the right interpol=(m_b[n-1]*h + m_c[n-1])*h + m_y[n-1]; } else { // interpolation interpol=((m_a[idx]*h + m_b[idx])*h + m_c[idx])*h + m_y[idx]; } return interpol; } double spline::deriv(int order, double x) const { assert(order>0); // find the closest point m_x[idx] < x, idx=0 even if xm_x[n-1]) { // extrapolation to the right switch(order) { case 1: interpol=2.0*m_b[n-1]*h + m_c[n-1]; break; case 2: interpol=2.0*m_b[n-1]; break; default: interpol=0.0; break; } } else { // interpolation switch(order) { case 1: interpol=(3.0*m_a[idx]*h + 2.0*m_b[idx])*h + m_c[idx]; break; case 2: interpol=6.0*m_a[idx]*h + 2.0*m_b[idx]; break; case 3: interpol=6.0*m_a[idx]; break; default: interpol=0.0; break; } } return interpol; } } // namespace tk