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