1 /*!
2 *
3 * \file hermite_cubic.cpp
4 * \brief Some routines from the hermite_cubic library
5 * \details TODO A more detailed description of these routines.
6 * \author John Burkardt
7 * \author Modified by David Favis-Mortlock, Andres Payo, Jim Hall
8 * \date 2017
9 * \copyright GNU Lesser General Public License
10 *
11 */
12
13 /*==============================================================================================================================
14
15 This is part of hermite_cubic.h: a C++ library from http://people.sc.fsu.edu/~jburkardt/cpp_src/hermite_cubic/hermite_cubic.html. It demonstrates the use of cubic polynomials in the Hermite form.
16
17 hermite_cubic_spline_value() evaluates a Hermite cubic spline.
18 hermite_cubic_value() evaluates a Hermite cubic polynomial.
19 r8vec_bracket3() finds the interval containing or nearest a given value.
20
21 ===============================================================================================================================*/
22 #include <iostream>
23 using std::cout;
24 using std::cerr;
25 using std::endl;
26 using std::ios;
27
28 #include "cliffmetrics.h"
29 #include "hermite_cubic.h"
30
31
32 //****************************************************************************80
33 //
34 // Purpose:
35 //
36 // R8VEC_BRACKET3 finds the interval containing or nearest a given value.
37 //
38 // Discussion:
39 //
40 // An R8VEC is a vector of R8's.
41 //
42 // The routine always returns the index LEFT of the sorted array
43 // T with the property that either
44 // * T is contained in the interval [ T[LEFT], T[LEFT+1] ], or
45 // * T < T[LEFT] = T[0], or
46 // * T > T[LEFT+1] = T[N-1].
47 //
48 // The routine is useful for interpolation problems, where
49 // the abscissa must be located within an interval of data
50 // abscissas for interpolation, or the "nearest" interval
51 // to the (extreme) abscissa must be found so that extrapolation
52 // can be carried out.
53 //
54 // This version of the function has been revised so that the value of
55 // LEFT that is returned uses the 0-based indexing natural to C++.
56 //
57 // Licensing:
58 //
59 // This code is distributed under the GNU LGPL license.
60 //
61 // Modified:
62 //
63 // 30 April 2009
64 //
65 // Author:
66 //
67 // John Burkardt
68 //
69 // Parameters:
70 //
71 // Input, int N, length of the input array.
72 //
73 // Input, double T[N], an array that has been sorted into ascending order.
74 //
75 // Input, double TVAL, a value to be bracketed by entries of T.
76 //
77 // Input/output, int *LEFT.
78 // On input, if 0 <= LEFT <= N-2, LEFT is taken as a suggestion for the
79 // interval [ T[LEFT-1] T[LEFT] ] in which TVAL lies. This interval
80 // is searched first, followed by the appropriate interval to the left
81 // or right. After that, a binary search is used.
82 // On output, LEFT is set so that the interval [ T[LEFT], T[LEFT+1] ]
83 // is the closest to TVAL; it either contains TVAL, or else TVAL
84 // lies outside the interval [ T[0], T[N-1] ].
85 //
r8vec_bracket3(int const n,double * const t,double const tval,int * left)86 void r8vec_bracket3(int const n, double* const t, double const tval, int* left)
87 {
88 int high;
89 int low;
90 int mid;
91 //
92 // Check the input data.
93 //
94 if ( n < 2 )
95 {
96 cerr << "\n";
97 cerr << "R8VEC_BRACKET3 - Fatal error!\n";
98 cerr << " N must be at least 2.\n";
99 return;
100 }
101 //
102 // If *LEFT is not between 0 and N-2, set it to the middle value.
103 //
104 if ( *left < 0 || n - 2 < *left )
105 {
106 *left = ( n - 1 ) / 2;
107 }
108 //
109 // CASE 1: TVAL < T[*LEFT]:
110 // Search for TVAL in (T[I],T[I+1]), for I = 0 to *LEFT-1.
111 //
112 if ( tval < t[*left] )
113 {
114 if ( *left == 0 )
115 {
116 return;
117 }
118 else if ( *left == 1 )
119 {
120 *left = 0;
121 return;
122 }
123 else if ( t[*left-1] <= tval )
124 {
125 *left = *left - 1;
126 return;
127 }
128 else if ( tval <= t[1] )
129 {
130 *left = 0;
131 return;
132 }
133 //
134 // ...Binary search for TVAL in (T[I],T[I+1]), for I = 1 to *LEFT-2.
135 //
136 low = 1;
137 high = *left - 2;
138
139 for ( ; ; )
140 {
141 if ( low == high )
142 {
143 *left = low;
144 return;
145 }
146
147 mid = ( low + high + 1 ) / 2;
148
149 if ( t[mid] <= tval )
150 {
151 low = mid;
152 }
153 else
154 {
155 high = mid - 1;
156 }
157 }
158 }
159 //
160 // CASE 2: T[*LEFT+1] < TVAL:
161 // Search for TVAL in (T[I],T[I+1]) for intervals I = *LEFT+1 to N-2.
162 //
163 else if ( t[*left+1] < tval )
164 {
165 if ( *left == n - 2 )
166 {
167 return;
168 }
169 else if ( *left == n - 3 )
170 {
171 *left = *left + 1;
172 return;
173 }
174 else if ( tval <= t[*left+2] )
175 {
176 *left = *left + 1;
177 return;
178 }
179 else if ( t[n-2] <= tval )
180 {
181 *left = n - 2;
182 return;
183 }
184 //
185 // ...Binary search for TVAL in (T[I],T[I+1]) for intervals I = *LEFT+2 to N-3.
186 //
187 low = *left + 2;
188 high = n - 3;
189
190 for ( ; ; )
191 {
192
193 if ( low == high )
194 {
195 *left = low;
196 return;
197 }
198
199 mid = ( low + high + 1 ) / 2;
200
201 if ( t[mid] <= tval )
202 {
203 low = mid;
204 }
205 else
206 {
207 high = mid - 1;
208 }
209 }
210 }
211 //
212 // CASE 3: T[*LEFT] <= TVAL <= T[*LEFT+1]:
213 // T is just where the user said it might be.
214 //
215 else
216 {
217 }
218
219 return;
220 }
221
222
223 //****************************************************************************80
224 //
225 // Purpose:
226 //
227 // HERMITE_CUBIC_VALUE evaluates a Hermite cubic polynomial.
228 //
229 // Discussion:
230 //
231 // The input arguments can be vectors.
232 //
233 // Licensing:
234 //
235 // This code is distributed under the GNU LGPL license.
236 //
237 // Modified:
238 //
239 // 13 February 2011
240 //
241 // Author:
242 //
243 // John Burkardt
244 //
245 // Reference:
246 //
247 // Fred Fritsch, Ralph Carlson,
248 // Monotone Piecewise Cubic Interpolation,
249 // SIAM Journal on Numerical Analysis,
250 // Volume 17, Number 2, April 1980, pages 238-246.
251 //
252 // Parameters:
253 //
254 // Input, double X1, F1, D1, the left endpoint, function value
255 // and derivative.
256 //
257 // Input, double X2, F2, D2, the right endpoint, function value
258 // and derivative.
259 //
260 // Input, int N, the number of evaluation points.
261 //
262 // Input, double X[N], the points at which the Hermite cubic
263 // is to be evaluated.
264 //
265 // Output, double F[N], D[N], S[N], T[N], the value and first
266 // three derivatives of the Hermite cubic at X.
267 //
hermite_cubic_value(double const x1,double const f1,double const d1,double const x2,double const f2,double const d2,int const n,double * const x,double * f,double * d,double * s,double * t)268 void hermite_cubic_value (double const x1, double const f1, double const d1, double const x2, double const f2, double const d2, int const n, double* const x, double* f, double* d, double* s, double* t)
269 {
270 double c2;
271 double c3;
272 double df;
273 double h;
274 int i;
275
276 h = x2 - x1;
277 df = (f2 - f1) / h;
278
279 c2 = - ( 2.0 * d1 - 3.0 * df + d2 ) / h;
280 c3 = ( d1 - 2.0 * df + d2 ) / h / h;
281
282 for (i = 0; i < n; i++)
283 {
284 f[i] = f1 + ( x[i] - x1 ) * ( d1
285 + ( x[i] - x1 ) * ( c2
286 + ( x[i] - x1 ) * c3 ) );
287 d[i] = d1 + ( x[i] - x1 ) * ( 2.0 * c2
288 + ( x[i] - x1 ) * 3.0 * c3 );
289 s[i] = 2.0 * c2 + ( x[i] - x1 ) * 6.0 * c3;
290 t[i] = 6.0 * c3;
291 }
292 return;
293 }
294
295 //****************************************************************************80
296 //
297 // Purpose:
298 //
299 // HERMITE_CUBIC_SPLINE_VALUE evaluates a Hermite cubic spline.
300 //
301 // Licensing:
302 //
303 // This code is distributed under the GNU LGPL license.
304 //
305 // Modified:
306 //
307 // 13 February 2011
308 //
309 // Author:
310 //
311 // John Burkardt
312 //
313 // Reference:
314 //
315 // Fred Fritsch, Ralph Carlson,
316 // Monotone Piecewise Cubic Interpolation,
317 // SIAM Journal on Numerical Analysis,
318 // Volume 17, Number 2, April 1980, pages 238-246.
319 //
320 // Parameters:
321 //
322 // Input, int NN, the number of data points.
323 //
324 // Input, double XN[NN], the coordinates of the data points.
325 // The entries in XN must be in strictly ascending order.
326 //
327 // Input, double FN[NN], the function values.
328 //
329 // Input, double DN[NN], the derivative values.
330 //
331 // Input, int N, the number of sample points.
332 //
333 // Input, double X[N], the coordinates of the sample points.
334 //
335 // Output, double F[N], the function value at the sample points.
336 //
337 // Output, double D[N], the derivative value at the sample points.
338 //
339 // Output, double S[N], the second derivative value at the
340 // sample points.
341 //
342 // Output, double T[N], the third derivative value at the
343 // sample points.
344 //
hermite_cubic_spline_value(int const nn,double * const xn,double * const fn,double * const dn,int const n,double * const x,double * f,double * d,double * s,double * t)345 void hermite_cubic_spline_value(int const nn, double* const xn, double* const fn, double* const dn, int const n, double* const x, double* f, double* d, double* s, double* t)
346 {
347 int left = n / 2;
348
349 for (int i = 0; i < n; i++)
350 {
351 r8vec_bracket3(nn, xn, x[i], &left);
352
353 hermite_cubic_value(xn[left], fn[left], dn[left], xn[left+1], fn[left+1], dn[left+1], 1, x+i, f+i, d+i, s+i, t+i);
354 }
355 return;
356 }
357
358