18 using namespace Hermes::Algebra::DenseMatrixOperations;
23 CubicSpline::CubicSpline(Hermes::vector<double> points, Hermes::vector<double> values,
24 double bc_left,
double bc_right,
25 bool first_der_left,
bool first_der_right,
26 bool extrapolate_der_left,
bool extrapolate_der_right) : Hermes::Hermes1DFunction<double>(), points(points), values(values),
27 bc_left(bc_left), bc_right(bc_right), first_der_left(first_der_left),
28 first_der_right(first_der_right), extrapolate_der_left(extrapolate_der_left),
29 extrapolate_der_right(extrapolate_der_right)
31 this->is_const =
false;
70 if(extrapolate_der_right ==
false)
99 else return derivative_left;
106 if(extrapolate_der_right ==
false)
return 0;
109 else return derivative_right;
117 double derivative_end,
double x_in)
const
119 return value_end + derivative_end * (x_in - point_end);
124 double x2 = x_in * x_in;
125 double x3 = x2 * x_in;
132 double x2 = x_in * x_in;
134 + 3 * this->
coeffs[m].d * x2;
140 int i_right =
points.size() - 1;
144 if(x_in <
points[i_left])
return false;
145 if(x_in >
points[i_right])
return false;
147 while (i_left + 1 < i_right)
149 int i_mid = (i_left + i_right) / 2;
150 if(
points[i_mid] < x_in) i_left = i_mid;
151 else i_right = i_mid;
158 void CubicSpline::plot(
const char* filename,
double extension,
bool plot_derivative,
int subdiv)
const
160 FILE *f = fopen(filename,
"wb");
162 throw Hermes::Exceptions::Exception(
"Could not open a spline file for writing.");
165 throw Hermes::Exceptions::Exception(
"The cubic spline has no coefficients. Calculate using calculate_coeffs.");
169 double h = extension / subdiv;
170 for (
int j = 0; j < subdiv; j++)
172 double x = x_left + j * h;
174 if(!plot_derivative) val =
value(x);
176 fprintf(f,
"%g %g\n", x, val);
180 if(!plot_derivative) val_last =
value(x_last);
182 fprintf(f,
"%g %g\n", x_last, val_last);
185 for (
unsigned int i = 0; i <
points.size() - 1; i++)
188 for (
int j = 0; j < subdiv; j++)
190 double x =
points[i] + j * h;
193 if(!plot_derivative) val = this->
value(x);
195 fprintf(f,
"%g %g\n", x, val);
200 if(!plot_derivative) val_last =
value(x_last);
202 fprintf(f,
"%g %g\n", x_last, val_last);
205 double x_right = point_right + extension;
206 h = extension / subdiv;
207 for (
int j = 0; j < subdiv; j++)
209 double x = point_right + j * h;
211 if(!plot_derivative) val =
value(x);
213 fprintf(f,
"%g %g\n", x, val);
216 if(!plot_derivative) val_last =
value(x_last);
218 fprintf(f,
"%g %g\n", x_last, val_last);
225 int nelem =
points.size() - 1;
230 this->warn(
"Empty points or values vector in CubicSpline, cancelling coefficients calculation.");
235 this->warn(
"At least two points and values required in CubicSpline, cancelling coefficients calculation.");
240 this->warn(
"Mismatched number of points and values in CubicSpline, cancelling coefficients calculation.");
246 for (
int i = 0; i < nelem; i++)
250 this->warn(
"Duplicated or improperly ordered points in CubicSpline detected, cancelling coefficients calculation.");
258 const int n = 4 * nelem;
259 double** matrix = new_matrix<double>(n, n);
260 for (
int i = 0; i < n; i++)
262 for (
int j = 0; j < n; j++)
267 double* rhs =
new double[n];
268 for (
int j = 0; j < n; j++)
274 for (
int i = 0; i < nelem; i++)
277 rhs[2*i + 1] =
values[i + 1];
282 for (
int i = 0; i < nelem; i++) {
285 double xx3 = xx2 * xx;
286 matrix[2*i][4*i + 0] = 1;
287 matrix[2*i][4*i + 1] = xx;
288 matrix[2*i][4*i + 2] = xx2;
289 matrix[2*i][4*i + 3] = xx3;
293 matrix[2*i + 1][4*i + 0] = 1.0;
294 matrix[2*i + 1][4*i + 1] = xx;
295 matrix[2*i + 1][4*i + 2] = xx2;
296 matrix[2*i + 1][4*i + 3] = xx3;
301 int offset = 2*nelem;
302 for (
int i = 1; i < nelem; i++) {
305 matrix[offset + i-1][4*(i-1) + 1] = 1;
306 matrix[offset + i-1][4*(i-1) + 2] = 2*xx;
307 matrix[offset + i-1][4*(i-1) + 3] = 3*xx2;
308 matrix[offset + i-1][4*(i-1) + 5] = -1;
309 matrix[offset + i-1][4*(i-1) + 6] = -2*xx;
310 matrix[offset + i-1][4*(i-1) + 7] = -3*xx2;
315 offset = 2*nelem + nelem - 1;
316 for (
int i = 1; i < nelem; i++) {
318 matrix[offset + i-1][4*(i-1) + 2] = 2;
319 matrix[offset + i-1][4*(i-1) + 3] = 6*xx;
320 matrix[offset + i-1][4*(i-1) + 6] = -2;
321 matrix[offset + i-1][4*(i-1) + 7] = -6*xx;
332 offset = 2*nelem + 2 * (nelem - 1);
336 matrix[offset + 0][2] = 2;
337 matrix[offset + 0][3] = 6*xx;
342 matrix[offset + 0][1] = 1;
343 matrix[offset + 0][2] = 2*xx;
344 matrix[offset + 0][3] = 3*xx*xx;
348 if(first_der_right ==
false)
350 matrix[offset + 1][n-2] = 2;
351 matrix[offset + 1][n-1] = 6*xx;
356 matrix[offset + 1][n-3] = 1;
357 matrix[offset + 1][n-2] = 2*xx;
358 matrix[offset + 1][n-1] = 3*xx*xx;
364 int* perm =
new int[n];
365 ludcmp(matrix, n, perm, &d);
366 lubksb<double>(matrix, n, perm, rhs);
370 for (
int i = 0; i < nelem; i++)
373 coeff.a = rhs[4*i + 0];
374 coeff.b = rhs[4*i + 1];
375 coeff.c = rhs[4*i + 2];
376 coeff.d = rhs[4*i + 3];