V3FIT
r8v_spline.f
1  SUBROUTINE r8v_spline(k_bc1,k_bcn,n,x,f,wk)
2 !***********************************************************************
3 !V_SPLINE evaluates the coefficients for a 1d cubic interpolating spline
4 !References:
5 ! Forsythe, Malcolm, Moler, Computer Methods for Mathematical
6 ! Computations, Prentice-Hall, 1977, p.76
7 ! Engeln-Muellges, Uhlig, Numerical Algorithms with Fortran, Springer,
8 ! 1996, p.251
9 ! W.A.Houlberg, D.McCune 3/2000
10 !Input:
11 ! k_bc1-option for BC at x1 = x(1)
12 ! =-1 periodic, ignore k_bcn
13 ! =0 not-a-knot
14 ! =1 s'(x1) = input value of f(2,1)
15 ! =2 s''(x1) = input value of f(3,1)
16 ! =3 s'(x1) = 0.0
17 ! =4 s''(x1) = 0.0
18 ! =5 match first derivative to first 2 points
19 ! =6 match second derivative to first 3 points
20 ! =7 match third derivative to first 4 points
21 ! =else use not-a-knot
22 ! k_bcn-option for boundary condition at xn = x(n)
23 ! =0 not-a-knot
24 ! =1 s'(xn) = input value of f(2,n)
25 ! =2 s''(xn) = input value of f(3,n)
26 ! =3 s'(xn) = 0.0
27 ! =4 s''(xn) = 0.0
28 ! =5 match first derivative to last 2 points
29 ! =6 match second derivative to lasst 3 points
30 ! =7 match third derivative to last 4 points
31 ! =else use knot-a-knot
32 ! n-number of data points or knots-(n.ge.2)
33 ! x(n)-abscissas of the knots in strictly increasing order
34 ! f(1,i)-ordinates of the knots
35 ! f(2,1)-input value of s'(x1) for k_bc1=1
36 ! f(2,n)-input value of s'(xn) for k_bcn=1
37 ! f(3,1)-input value of s''(x1) for k_bc1=2
38 ! f(3,n)-input value of s''(xn) for k_bcn=2
39 ! wk(n)-scratch work area for periodic BC
40 !Output:
41 ! f(2,i)=s'(x(i))
42 ! f(3,i)=s''(x(i))
43 ! f(4,i)=s'''(x(i))
44 !Comments:
45 ! s(x)=f(1,i)+f(2,i)*(x-x(i))+f(3,i)*(x-x(i))**2/2!
46 ! +f(4,i)*(x-x(i))**3/3! for x(i).le.x.le.x(i+1)
47 ! W_SPLINE can be used to evaluate the spline and its derivatives
48 ! The cubic spline is twice differentiable (C2)
49 !
50 ! modifications -- dmc 18 Feb 2010:
51 ! Deal with n.lt.4 -- the general tridiagonal spline method
52 ! does not have the right formulation for n.eq.3 "not a knot" or periodic
53 ! boundary conditions, nor for n.eq.2 with any boundary conditions.
54 !
55 ! Apply boundary conditions even for n=2, when the "spline" is really
56 ! just a single cubic polynomial.
57 ! In this case, several boundary condition (BC) options are mapped to
58 ! BC option 5, 1st divided difference. If 5 is used on both sides
59 ! of an n=2 "spline" you get a linear piece which is what the old
60 ! code always gave, regardless of BC option settings. The following
61 ! BC controls are mapped to 5:
62 ! periodic (-1)
63 ! not a knot (0) (for n=2 no grid point exists for knot location).
64 ! option (5) is preserved
65 ! options 6 and 7 -- mapped to (5); higher divided differences
66 ! need n>2; in fact 7 needs n>3; for n=3 option 6 is substituted.
67 !
68 ! The boundary condition screening is done at the start of the code;
69 ! passed controls k_bc1 and k_bcn are mapped to i_bc1 and i_bcn.
70 !
71 ! ALSO: for n=3, "not a knot" from both left and right needs special
72 ! interpretation, since the 2 boundary conditions overlap. The
73 ! chosen interpretation is a parabolic fit to the 3 given data points.
74 ! and so f''' = 0 and f'' = constant. If "not a knot" is used on
75 ! one side only, the solution is a single cubic piece and special
76 ! code is also needed.
77 ! ALSO: for n=3, "periodic" boundary condition needs special code; this
78 ! is added.
79 !
80 ! bugfixes -- dmc 24 Feb 2004:
81 ! (a) fixed logic for not-a-knot:
82 ! ! Set f(3,1) for not-a-knot
83 ! IF(k_bc1.le.0.or.k_bc1.gt.7) THEN ...
84 ! instead of
85 ! ! Set f(3,1) for not-a-knot
86 ! IF(k_bc1.le.0.or.k_bc1.gt.5) THEN ...
87 ! and similarly for logic after cmt
88 ! ! Set f(3,n) for not-a-knot
89 ! as required since k_bc*=6 and k_bc*=7 are NOT not-a-knot BCs.
90 !
91 ! (b) the BCs to fix 2nd derivative at end points did not work if that
92 ! 2nd derivative were non-zero. The reason is that in those cases
93 ! the off-diagonal matrix elements nearest the corners are not
94 ! symmetric; i.e. elem(1,2).ne.elem(2,1) and
95 ! elem(n-1,n).ne.elem(n,n-1) where I use "elem" to refer to
96 ! the tridiagonal matrix elements. The correct values for the
97 ! elements is: elem(1,2)=0, elem(2,1)=x(2)-x(1)
98 ! elem(n,n-1)=0, elem(n-1,n)=x(n)-x(n-1)
99 ! the old code in effect had these as all zeroes. Since this
100 ! meant the wrong set of linear equations was solved, the
101 ! resulting spline had a discontinuity in its 1st derivative
102 ! at x(2) and x(n-1). Fixed by introducing elem21 and elemnn1
103 ! to represent the non-symmetric lower-diagonal values. Since
104 ! elem21 & elemnn1 are both on the lower diagonals, logic to
105 ! use them occurs in the non-periodic forward elimination loop
106 ! only. DMC 24 Feb 2004.
107 !***********************************************************************
108 !Declaration of input variables
109  IMPLICIT NONE
110  INTEGER, PARAMETER :: R8=selected_real_kind(12,100)
111  INTEGER k_bc1, k_bcn,
112  & n
113  real*8 x(*), wk(*),
114  & f(4,*)
115 !Declaration in local variables
116  INTEGER i, ib,
117  & imax, imin
118  real*8 a1, an,
119  & b1, bn,
120  & q, t,
121  & hn
122  real*8 elem21, elemnn1 ! (dmc)
123 
124  integer :: i_bc1,i_bcn ! screened BC controls
125 
126  integer :: iord1,iord2 ! used for n=2 only
127  real*8 :: h,f0,fh ! used for n=2,3 only
128  real*8 :: h1,h2,h3,dels ! used for n=3 special cases
129  real*8 :: f1,f2,f3,aa,bb ! used for n=3
130 
131  integer :: i3knots ! for n=3, number of not-a-knot BCs
132  integer :: i3perio ! for n=3, periodic BC
133 
134 !------------------------------------------------------------
135 ! screen the BC options (DMC Feb. 2010...)
136 
137  i_bc1=k_bc1
138  i_bcn=k_bcn
139 
140  if((i_bc1.lt.-1).or.(i_bc1.gt.7)) i_bc1=0 ! outside [-1:7] -> not-a-knot
141  if((i_bcn.lt.0).or.(i_bcn.gt.7)) i_bcn=0 ! outside [0:7] -> not-a-knot
142 
143  if(i_bc1.eq.-1) i_bcn=-1 ! periodic BC
144 
145  i3knots=0
146  i3perio=0
147  if(n.eq.3) then
148  i_bc1=min(6,i_bc1)
149  i_bcn=min(6,i_bcn)
150  if(i_bc1.eq.0) i3knots = i3knots + 1
151  if(i_bcn.eq.0) i3knots = i3knots + 1
152  if(i_bc1.eq.-1) i3perio = 1
153  endif
154 
155  if(n.eq.2) then
156  if(i_bc1.eq.-1) then
157  i_bc1=5
158  i_bcn=5
159  endif
160  if((i_bc1.eq.0).or.(i_bc1.gt.5)) i_bc1=5
161  if((i_bcn.eq.0).or.(i_bcn.gt.5)) i_bcn=5
162 
163  if((i_bc1.eq.1).or.(i_bc1.eq.3).or.(i_bc1.eq.5)) then
164  iord1=1 ! 1st derivative match on LHS
165  else
166  iord1=2 ! 2nd derivative match on LHS
167  endif
168 
169  if((i_bcn.eq.1).or.(i_bcn.eq.3).or.(i_bcn.eq.5)) then
170  iord2=1 ! 1st derivative match on RHS
171  else
172  iord2=2 ! 2nd derivative match on RHS
173  endif
174  endif
175 
176 !Set default range
177  imin=1
178  imax=n
179 !Set first and second BC values
180  a1=0.0_r8
181  b1=0.0_r8
182  an=0.0_r8
183  bn=0.0_r8
184  IF(i_bc1.eq.1) THEN
185  a1=f(2,1)
186  ELSEIF(i_bc1.eq.2) THEN
187  b1=f(3,1)
188  ELSEIF(i_bc1.eq.5) THEN
189  a1=(f(1,2)-f(1,1))/(x(2)-x(1))
190  ELSEIF(i_bc1.eq.6) THEN
191  b1=2.0_r8*((f(1,3)-f(1,2))/(x(3)-x(2))
192  & -(f(1,2)-f(1,1))/(x(2)-x(1)))/(x(3)-x(1))
193  ENDIF
194  IF(i_bcn.eq.1) THEN
195  an=f(2,n)
196  ELSEIF(i_bcn.eq.2) THEN
197  bn=f(3,n)
198  ELSEIF(i_bcn.eq.5) THEN
199  an=(f(1,n)-f(1,n-1))/(x(n)-x(n-1))
200  ELSEIF(i_bcn.eq.6) THEN
201  bn=2.0_r8*((f(1,n)-f(1,n-1))/(x(n)-x(n-1))
202  & -(f(1,n-1)-f(1,n-2))/(x(n-1)-x(n-2)))/(x(n)-x(n-2))
203  ENDIF
204 !Clear f(2:4,n)
205  f(2,n)=0.0_r8
206  f(3,n)=0.0_r8
207  f(4,n)=0.0_r8
208  IF(n.eq.2) THEN
209  if((i_bc1.eq.5).and.(i_bcn.eq.5)) then
210 !Coefficients for n=2 (this was the original code)
211  f(2,1)=(f(1,2)-f(1,1))/(x(2)-x(1))
212  f(3,1)=0.0_r8
213  f(4,1)=0.0_r8
214  f(2,2)=f(2,1)
215  f(3,2)=0.0_r8
216  f(4,2)=0.0_r8
217  else if((iord1.eq.1).and.(iord2.eq.1)) then
218  ! LHS: match a1 for 1st deriv; RHS: match an for 1st deriv.
219  f(2,1)=a1
220  f(2,2)=an
221  h = (x(2)-x(1))
222  f0 = f(1,1)
223  fh = f(1,2)
224 
225  ! setting xx = x-x(1),
226  ! f = c1*xx**3 + c2*xx**2 + a1*xx + f0
227  ! --> c1*h**3 + c2*h**2 = fh - f0 - a1*h
228  ! and 3*c1*h**2 + 2*c2*h = an - a1
229  ! f' = 3*c1*xx*2 + 2*c2*xx + a1
230  ! f'' = 6*c1*xx + 2*c2
231  ! f''' = 6*c1
232 
233  ! solve 2x2 system for c1 -> f(4,1)/6 and c2 -> f(3,1)/2
234 
235  f(3,1) = (3*(fh-f0)/(h*h) - (2*a1 + an)/h)*2 ! 2*c2
236  f(4,1) = (-2*(fh-f0)/(h*h*h) + (a1 + an)/(h*h))*6 ! 6*c1
237 
238  f(4,2) = f(4,1)
239  f(3,2) = f(4,1)*h + f(3,1)
240 
241  else if((iord1.eq.1).and.(iord2.eq.2)) then
242  ! LHS: match a1 for 1st deriv; RHS: match bn for 2nd deriv.
243  f(2,1)=a1
244  f(3,2)=bn
245  h = (x(2)-x(1))
246  f0 = f(1,1)
247  fh = f(1,2)
248 
249  ! setting xx = x-x(1),
250  ! f = c1*xx**3 + c2*xx**2 + a1*xx + f0
251  ! --> c1*h**3 + c2*h**2 = fh - f0 - a1*h
252  ! and 6*c1*h + 2*c2 = bn
253  ! f' = 3*c1*xx*2 + 2*c2*xx + a1
254  ! f'' = 6*c1*xx + 2*c2
255  ! f''' = 6*c1
256 
257  ! solve 2x2 system for c1 -> f(4,1)/6 and c2 -> f(3,1)/2
258 
259  f(3,1) = (-bn/4 + 3*(fh-f0)/(2*h*h) - 3*a1/(2*h))*2 ! 2*c2
260  f(4,1) = (bn/(4*h) - (fh-f0)/(2*h*h*h) + a1/(2*h*h))*6 ! 6*c1
261 
262  f(4,2) = f(4,1)
263  f(2,2) = f(4,1)*h*h/2 + f(3,1)*h + a1
264  else if((iord1.eq.2).and.(iord2.eq.1)) then
265  ! LHS: match b1 for 2nd deriv; RHS: match an for 1st deriv.
266  f(3,1)=b1
267  f(2,2)=an
268  h = (x(2)-x(1))
269  f0 = f(1,1)
270  fh = f(1,2)
271 
272  ! setting xx = x-x(1),
273  ! f = c1*xx**3 + (b1/2)*xx**2 + c3*xx + f0
274  ! --> c1*h**3 + c3*h = fh - f0 - b1*h**2/2
275  ! and 3*c1*h**2 + c3 = an - b1*h
276  ! f' = 3*c1*xx*2 + b1*xx + c3
277  ! f'' = 6*c1*xx + b1
278  ! f''' = 6*c1
279 
280  ! solve 2x2 system for c1 -> f(4,1)/6 and c2 -> f(3,1)/2
281 
282  f(2,1) = 3*(fh-f0)/(2*h) - b1*h/4 - an/2 ! c3
283  f(4,1) = (an/(2*h*h) - (fh-f0)/(2*h*h*h) - b1/(4*h))*6 ! 6*c1
284 
285  f(4,2) = f(4,1)
286  f(3,2) = f(4,1)*h + f(3,1)
287  else if((iord1.eq.2).and.(iord2.eq.2)) then
288  ! LHS: match b1 for 2nd deriv; RHS: match bn for 2nd deriv.
289  f(3,1)=b1
290  f(3,2)=bn
291  h = (x(2)-x(1))
292  f0 = f(1,1)
293  fh = f(1,2)
294 
295  ! setting xx = x-x(1),
296  ! f = c1*xx**3 + (b1/2)*xx**2 + c3*xx + f0
297  ! --> c1*h**3 + c3*h = fh - f0 - b1*h**2/2
298  ! and 6*c1*h = bn - b1
299  ! f' = 3*c1*xx*2 + b1*xx + c3
300  ! f'' = 6*c1*xx + b1
301  ! f''' = 6*c1
302 
303  ! solve 2x2 system for c1 -> f(4,1)/6 and c2 -> f(3,1)/2
304 
305  f(2,1) = (fh-f0)/h -b1*h/3 -bn*h/6 ! c3
306  f(4,1) = (bn-b1)/h ! 6*c1
307 
308  f(4,2) = f(4,1)
309  f(2,2) = f(4,1)*h*h/2 + b1*h + f(2,1)
310  endif
311 
312  ELSE IF(i3perio.eq.1) then
313 !Special case: nx=3 periodic spline
314  h1=x(2)-x(1)
315  h2=x(3)-x(2)
316  h=h1+h2
317 
318  dels=(f(1,3)-f(1,2))/h2 - (f(1,2)-f(1,1))/h1
319 
320  f(2,1)= (f(1,2)-f(1,1))/h1 + (h1*dels)/h
321  f(3,1)= -6*dels/h
322  f(4,1)= 12*dels/(h1*h)
323 
324  f(2,2)= (f(1,3)-f(1,2))/h2 - (h2*dels)/h
325  f(3,2)= 6*dels/h
326  f(4,2)= -12*dels/(h2*h)
327 
328  f(2,3)=f(2,1)
329  f(3,3)=f(3,1)
330  f(4,3)=f(4,1)
331 
332 
333  ELSE IF(i3knots.eq.2) then
334 !Special case: nx=3, not-a-knot on both sides
335  h1=x(2)-x(1)
336  h2=x(3)-x(2)
337  h=h1+h2
338  ! this is just a quadratic fit through 3 pts
339  f1=f(1,1)-f(1,2)
340  f2=f(1,3)-f(1,2)
341 
342 ! quadratic around origin at (x(2),f(1,2))
343 ! aa*h1**2 - bb*h1 = f1
344 ! aa*h2**2 + bb*h2 = f2
345 
346  aa = (f2*h1 + f1*h2)/(h1*h2*h)
347  bb = (f2*h1*h1 - f1*h2*h2)/(h1*h2*h)
348 
349  f(4,1:3)=0.0_r8 ! f''' = 0 (quadratic polynomial)
350  f(3,1:3)=2*aa ! f'' = const
351 
352  f(2,1)=bb-2*aa*h1
353  f(2,2)=bb
354  f(2,3)=bb+2*aa*h2
355 
356  ELSE IF(i3knots.eq.1) then
357 !Special cases: nx=3, not-a-knot on single side
358  if((i_bc1.eq.1).or.(i_bc1.eq.3).or.(i_bc1.eq.5)) then
359  ! f' LHS condition; not-a-knot RHS
360 ! a1 = f' LHS BC
361  h2=x(2)-x(1)
362  h3=x(3)-x(1)
363 
364  f2=f(1,2)-f(1,1)
365  f3=f(1,3)-f(1,1)
366 
367 ! find cubic aa*xx**3 + bb*xx**2 + a1*xx
368 ! satisfying aa*h2**3 + bb*h2**2 + a1*h2 = f2
369 ! and aa*h3**3 + bb*h3**2 + a1*h3 = f3
370 
371  aa=a1/(h2*h3) + f3/(h3*h3*(h3-h2)) - f2/(h2*h2*(h3-h2))
372  bb=-a1*(h3*h3-h2*h2)/(h2*h3*(h3-h2))
373  > + f2*h3/(h2*h2*(h3-h2)) - f3*h2/(h3*h3*(h3-h2))
374 
375  f(2,1)=a1
376  f(3,1)=2*bb
377  f(4,1)=6*aa
378 
379  f(2,2)=3*aa*h2*h2 + 2*bb*h2 + a1
380  f(3,2)=6*aa*h2 + 2*bb
381  f(4,2)=6*aa
382 
383  f(2,3)=3*aa*h3*h3 + 2*bb*h3 + a1
384  f(3,3)=6*aa*h3 + 2*bb
385  f(4,3)=6*aa
386 
387  else if((i_bc1.eq.2).or.(i_bc1.eq.4).or.(i_bc1.eq.6)) then
388  ! f'' LHS condition; not-a-knot RHS
389 ! b1 = f'' LHS BC
390  h2=x(2)-x(1)
391  h3=x(3)-x(1)
392 
393  f2=f(1,2)-f(1,1)
394  f3=f(1,3)-f(1,1)
395 
396 ! find cubic aa*xx**3 + (b1/2)*xx**2 + bb*xx
397 ! satisfying aa*h2**3 + bb*h2 = f2 -(b1/2)*h2**2
398 ! and aa*h3**3 + bb*h3 = f3 -(b1/2)*h3**2
399 
400  aa= -(b1/2)*(h3-h2)/(h3*h3-h2*h2)
401  > -f2/(h2*(h3*h3-h2*h2)) + f3/(h3*(h3*h3-h2*h2))
402  bb= -(b1/2)*h2*h3*(h3-h2)/(h3*h3-h2*h2)
403  > +f2*h3*h3/(h2*(h3*h3-h2*h2))
404  > -f3*h2*h2/(h3*(h3*h3-h2*h2))
405 
406  f(2,1)=bb
407  f(3,1)=b1
408  f(4,1)=6*aa
409 
410  f(2,2)=3*aa*h2*h2 + b1*h2 + bb
411  f(3,2)=6*aa*h2 + b1
412  f(4,2)=6*aa
413 
414  f(2,3)=3*aa*h3*h3 + b1*h3 + bb
415  f(3,3)=6*aa*h3 + b1
416  f(4,3)=6*aa
417 
418  else if((i_bcn.eq.1).or.(i_bcn.eq.3).or.(i_bcn.eq.5)) then
419  ! f' RHS condition; not-a-knot LHS
420 ! an = f' RHS BC
421  h2=x(2)-x(3)
422  h3=x(1)-x(3)
423 
424  f2=f(1,2)-f(1,3)
425  f3=f(1,1)-f(1,3)
426 
427 ! find cubic aa*xx**3 + bb*xx**2 + an*xx
428 ! satisfying aa*h2**3 + bb*h2**2 + an*h2 = f2
429 ! and aa*h3**3 + bb*h3**2 + an*h3 = f3
430 
431  aa=an/(h2*h3) + f3/(h3*h3*(h3-h2)) - f2/(h2*h2*(h3-h2))
432  bb=-an*(h3*h3-h2*h2)/(h2*h3*(h3-h2))
433  > + f2*h3/(h2*h2*(h3-h2)) - f3*h2/(h3*h3*(h3-h2))
434 
435  f(2,3)=an
436  f(3,3)=2*bb
437  f(4,3)=6*aa
438 
439  f(2,2)=3*aa*h2*h2 + 2*bb*h2 + an
440  f(3,2)=6*aa*h2 + 2*bb
441  f(4,2)=6*aa
442 
443  f(2,1)=3*aa*h3*h3 + 2*bb*h3 + an
444  f(3,1)=6*aa*h3 + 2*bb
445  f(4,1)=6*aa
446 
447  else if((i_bcn.eq.2).or.(i_bcn.eq.4).or.(i_bcn.eq.6)) then
448  ! f'' RHS condition; not-a-knot LHS
449 ! bn = f'' RHS BC
450  h2=x(2)-x(3)
451  h3=x(1)-x(3)
452 
453  f2=f(1,2)-f(1,3)
454  f3=f(1,1)-f(1,3)
455 
456 ! find cubic aa*xx**3 + (bn/2)*xx**2 + bb*xx
457 ! satisfying aa*h2**3 + bb*h2 = f2 -(bn/2)*h2**2
458 ! and aa*h3**3 + bb*h3 = f3 -(bn/2)*h3**2
459 
460  aa= -(bn/2)*(h3-h2)/(h3*h3-h2*h2)
461  > -f2/(h2*(h3*h3-h2*h2)) + f3/(h3*(h3*h3-h2*h2))
462  bb= -(bn/2)*h2*h3*(h3-h2)/(h3*h3-h2*h2)
463  > +f2*h3*h3/(h2*(h3*h3-h2*h2))
464  > -f3*h2*h2/(h3*(h3*h3-h2*h2))
465 
466  f(2,3)=bb
467  f(3,3)=bn
468  f(4,3)=6*aa
469 
470  f(2,2)=3*aa*h2*h2 + bn*h2 + bb
471  f(3,2)=6*aa*h2 + bn
472  f(4,2)=6*aa
473 
474  f(2,1)=3*aa*h3*h3 + bn*h3 + bb
475  f(3,1)=6*aa*h3 + bn
476  f(4,1)=6*aa
477 
478  endif
479  ELSE IF(n.gt.2) THEN
480 !Set up tridiagonal system for A*y=B where y(i) are the second
481 ! derivatives at the knots
482 ! f(2,i) are the diagonal elements of A
483 ! f(4,i) are the off-diagonal elements of A
484 ! f(3,i) are the B elements/3, and will become c/3 upon solution
485  f(4,1)=x(2)-x(1)
486  f(3,2)=(f(1,2)-f(1,1))/f(4,1)
487  DO i=2,n-1
488  f(4,i)=x(i+1)-x(i)
489  f(2,i)=2.0_r8*(f(4,i-1)+f(4,i))
490  f(3,i+1)=(f(1,i+1)-f(1,i))/f(4,i)
491  f(3,i)=f(3,i+1)-f(3,i)
492  ENDDO
493 !
494 ! (dmc): save now:
495 !
496  elem21=f(4,1)
497  elemnn1=f(4,n-1)
498 !
499 ! BC's
500 ! Left
501  IF(i_bc1.eq.-1) THEN
502  f(2,1)=2.0_r8*(f(4,1)+f(4,n-1))
503  f(3,1)=(f(1,2)-f(1,1))/f(4,1)-(f(1,n)-f(1,n-1))/f(4,n-1)
504  wk(1)=f(4,n-1)
505  DO i=2,n-3
506  wk(i)=0.0_r8
507  ENDDO
508  wk(n-2)=f(4,n-2)
509  wk(n-1)=f(4,n-1)
510  ELSEIF(i_bc1.eq.1.or.i_bc1.eq.3.or.i_bc1.eq.5) THEN
511  f(2,1)=2.0_r8*f(4,1)
512  f(3,1)=(f(1,2)-f(1,1))/f(4,1)-a1
513  ELSEIF(i_bc1.eq.2.or.i_bc1.eq.4.or.i_bc1.eq.6) THEN
514  f(2,1)=2.0_r8*f(4,1)
515  f(3,1)=f(4,1)*b1/3.0_r8
516  f(4,1)=0.0_r8 ! upper diagonal only (dmc: cf elem21)
517  ELSEIF(i_bc1.eq.7) THEN
518  f(2,1)=-f(4,1)
519  f(3,1)=f(3,3)/(x(4)-x(2))-f(3,2)/(x(3)-x(1))
520  f(3,1)=f(3,1)*f(4,1)**2/(x(4)-x(1))
521  ELSE ! not a knot:
522  imin=2
523  f(2,2)=f(4,1)+2.0_r8*f(4,2)
524  f(3,2)=f(3,2)*f(4,2)/(f(4,1)+f(4,2))
525  ENDIF
526 ! Right
527  IF(i_bcn.eq.1.or.i_bcn.eq.3.or.i_bcn.eq.5) THEN
528  f(2,n)=2.0_r8*f(4,n-1)
529  f(3,n)=-(f(1,n)-f(1,n-1))/f(4,n-1)+an
530  ELSEIF(i_bcn.eq.2.or.i_bcn.eq.4.or.i_bcn.eq.6) THEN
531  f(2,n)=2.0_r8*f(4,n-1)
532  f(3,n)=f(4,n-1)*bn/3.0_r8
533 !xxx f(4,n-1)=0.0 ! dmc: preserve f(4,n-1) for back subst.
534  elemnn1=0.0_r8 ! lower diaganol only (dmc)
535  ELSEIF(i_bcn.eq.7) THEN
536  f(2,n)=-f(4,n-1)
537  f(3,n)=f(3,n-1)/(x(n)-x(n-2))-f(3,n-2)/(x(n-1)-x(n-3))
538  f(3,n)=-f(3,n)*f(4,n-1)**2/(x(n)-x(n-3))
539  ELSEIF(i_bc1.ne.-1) THEN ! not a knot:
540  imax=n-1
541  f(2,n-1)=2.0_r8*f(4,n-2)+f(4,n-1)
542  f(3,n-1)=f(3,n-1)*f(4,n-2)/(f(4,n-1)+f(4,n-2))
543  ENDIF
544  IF(i_bc1.eq.-1) THEN
545 !Solve system of equations for second derivatives at the knots
546 ! Periodic BC
547 ! Forward elimination
548  DO i=2,n-2
549  t=f(4,i-1)/f(2,i-1)
550  f(2,i)=f(2,i)-t*f(4,i-1)
551  f(3,i)=f(3,i)-t*f(3,i-1)
552  wk(i)=wk(i)-t*wk(i-1)
553  q=wk(n-1)/f(2,i-1)
554  wk(n-1)=-q*f(4,i-1)
555  f(2,n-1)=f(2,n-1)-q*wk(i-1)
556  f(3,n-1)=f(3,n-1)-q*f(3,i-1)
557  ENDDO
558 ! Correct the n-1 element
559  wk(n-1)=wk(n-1)+f(4,n-2)
560 ! Complete the forward elimination
561 ! wk(n-1) and wk(n-2) are the off-diag elements of the lower corner
562  t=wk(n-1)/f(2,n-2)
563  f(2,n-1)=f(2,n-1)-t*wk(n-2)
564  f(3,n-1)=f(3,n-1)-t*f(3,n-2)
565 ! Back substitution
566  f(3,n-1)=f(3,n-1)/f(2,n-1)
567  f(3,n-2)=(f(3,n-2)-wk(n-2)*f(3,n-1))/f(2,n-2)
568  DO ib=3,n-1
569  i=n-ib
570  f(3,i)=(f(3,i)-f(4,i)*f(3,i+1)-wk(i)*f(3,n-1))/f(2,i)
571  ENDDO
572  f(3,n)=f(3,1)
573  ELSE
574 ! Non-periodic BC
575 ! Forward elimination
576 ! For Not-A-Knot BC the off-diagonal end elements are not equal
577  DO i=imin+1,imax
578  IF((i.eq.n-1).and.(imax.eq.n-1)) THEN
579  t=(f(4,i-1)-f(4,i))/f(2,i-1)
580  ELSE
581  if(i.eq.2) then
582  t=elem21/f(2,i-1)
583  else if(i.eq.n) then
584  t=elemnn1/f(2,i-1)
585  else
586  t=f(4,i-1)/f(2,i-1)
587  endif
588  ENDIF
589  IF((i.eq.imin+1).and.(imin.eq.2)) THEN
590  f(2,i)=f(2,i)-t*(f(4,i-1)-f(4,i-2))
591  ELSE
592  f(2,i)=f(2,i)-t*f(4,i-1)
593  ENDIF
594  f(3,i)=f(3,i)-t*f(3,i-1)
595  ENDDO
596 ! Back substitution
597  f(3,imax)=f(3,imax)/f(2,imax)
598  DO ib=1,imax-imin
599  i=imax-ib
600  IF((i.eq.2).and.(imin.eq.2)) THEN
601  f(3,i)=(f(3,i)-(f(4,i)-f(4,i-1))*f(3,i+1))/f(2,i)
602  ELSE
603  f(3,i)=(f(3,i)-f(4,i)*f(3,i+1))/f(2,i)
604  ENDIF
605  ENDDO
606 ! Reset d array to step size
607  f(4,1)=x(2)-x(1)
608  f(4,n-1)=x(n)-x(n-1)
609 ! Set f(3,1) for not-a-knot
610  IF(i_bc1.le.0.or.i_bc1.gt.7) THEN
611  f(3,1)=(f(3,2)*(f(4,1)+f(4,2))-f(3,3)*f(4,1))/f(4,2)
612  ENDIF
613 ! Set f(3,n) for not-a-knot
614  IF(i_bcn.le.0.or.i_bcn.gt.7) THEN
615  f(3,n)=f(3,n-1)+(f(3,n-1)-f(3,n-2))*f(4,n-1)/f(4,n-2)
616  ENDIF
617  ENDIF
618 !f(3,i) is now the sigma(i) of the text and f(4,i) is the step size
619 !Compute polynomial coefficients
620  DO i=1,n-1
621  f(2,i)=
622  > (f(1,i+1)-f(1,i))/f(4,i)-f(4,i)*(f(3,i+1)+2.0_r8*f(3,i))
623  f(4,i)=(f(3,i+1)-f(3,i))/f(4,i)
624  f(3,i)=6.0_r8*f(3,i)
625  f(4,i)=6.0_r8*f(4,i)
626  ENDDO
627  IF(i_bc1.eq.-1) THEN
628  f(2,n)=f(2,1)
629  f(3,n)=f(3,1)
630  f(4,n)=f(4,1)
631  ELSE
632  hn=x(n)-x(n-1)
633  f(2,n)=f(2,n-1)+hn*(f(3,n-1)+0.5_r8*hn*f(4,n-1))
634  f(3,n)=f(3,n-1)+hn*f(4,n-1)
635  f(4,n)=f(4,n-1)
636  IF(i_bcn.eq.1.or.i_bcn.eq.3.or.i_bcn.eq.5) THEN
637  f(2,n)=an
638  ELSE IF(i_bcn.eq.2.or.i_bcn.eq.4.or.i_bcn.eq.6) THEN
639  f(3,n)=bn
640  ENDIF
641  ENDIF
642  ENDIF
643  RETURN
644  END