V3FIT
spline1_mod.f90
1 MODULE spline1_mod
2 !-------------------------------------------------------------------------------
3 !SPLINE1-SPLINE interpolation in 1d
4 !
5 !SPLINE1_MOD is an F90 module of cubic interpolating spline routines in 1d
6 !
7 !References:
8 !
9 ! Forsythe, Malcolm, Moler, Computer Methods for Mathematical
10 ! Computations, Prentice-Hall, 1977, p.76
11 ! Engeln-Muellges, Uhlig, Numerical Algorithms with Fortran, Springer,
12 ! 1996, p.251
13 ! W.A.Houlberg, P.I.Strand, D.McCune 8/2001
14 ! W.A.Houlberg, F90 free form 8/2004
15 !
16 !Contains PUBLIC routines:
17 !
18 ! SPLINE1_FIT -get the coefficients
19 ! SPLINE1_EVAL -evaluate the spline
20 ! SPLINE1_INTERP -interpolate from one grid to another
21 ! SPLINE1_INTEG -integrate the spline fit
22 !
23 !Comments:
24 !
25 ! Spline interpolation routines are C2 (f, f', and f'' are continuous)
26 !
27 ! The modernization of the code structure into an F90 module takes advantage of
28 ! some of the more attractive features of F90:
29 ! -use of KIND for precision declarations
30 ! -optional arguments for I/O
31 ! -generic names for all intrinsic functions
32 ! -compilation using either free or fixed form
33 ! -no common blocks or other deprecated Fortran features
34 ! -dynamic and automatic alocation of variables
35 ! -array syntax for vector operations
36 !-------------------------------------------------------------------------------
37 USE spec_kind_mod
38 IMPLICIT NONE
39 
40 !-------------------------------------------------------------------------------
41 ! Private procedures
42 !-------------------------------------------------------------------------------
43 PRIVATE :: &
44  spline1_search !find the indices that bracket an abscissa value
45  ! called from SPLINE1_EVAL
46 
47 !-------------------------------------------------------------------------------
48 ! Public procedures
49 !-------------------------------------------------------------------------------
50 CONTAINS
51 
52 SUBROUTINE spline1_fit(n,x,f, &
53  K_BC1,K_BCN)
54 !-------------------------------------------------------------------------------
55 !SPLINE1_FIT gets the coefficients for a 1d cubic interpolating spline
56 !
57 !References:
58 ! Forsythe, Malcolm, Moler, Computer Methods for Mathematical
59 ! Computations, Prentice-Hall, 1977, p.76
60 ! Engeln-Muellges, Uhlig, Numerical Algorithms with Fortran, Springer,
61 ! 1996, p.251
62 ! W.A.Houlberg, P.I.Strand, D.McCune 8/2001
63 ! D.McCune, W.A.Houlberg 3/2004
64 ! W.A.Houlberg, F90 free form 8/2004
65 !
66 !Comments:
67 ! For x(i).le.x.le.x(i+1)
68 ! s(x) = f(1,i) + f(2,i)*(x-x(i)) + f(3,i)*(x-x(i))**2/2!
69 ! +f(4,i)*(x-x(i))**3/3!
70 ! The cubic spline is twice differentiable (C2)
71 ! The BCs default to not-a-knot conditions, K_BC1=0 and K_BCN=0
72 ! Two errors fixed in 3/2004 version:
73 ! Logic for not-a-knot on f(3,1) and f(3,n) after back substitution
74 ! Treatment of asymmetrix coefficient matrix for s''=0 BC
75 ! For s''=0 the off-diagonal elements nearest the corners are not symmetric,
76 ! i.e., el(1,2) /= el(2,1) and el(n-1,n) /= el(n,n-1). The correct values:
77 ! el(1,2)=0, el(2,1)=x(2)-x(1), el(n,n-1)=0, el(n-1,n)=x(n)-x(n-1) are fixed
78 ! by adding variables to hold the el21 and elnn1 values.
79 !-------------------------------------------------------------------------------
80 
81 !Declaration of input variables
82 INTEGER, INTENT(IN) :: &
83  n !number of data points or knots [>=2]
84 
85 REAL(KIND=rspec), INTENT(IN) :: &
86  x(:) !abscissas of the knots in increasing order [arb]
87 
88 !Declaration of input/output variables
89 REAL(KIND=rspec), INTENT(INOUT) :: &
90  f(:,:) !ordinates of the knots [arb]
91  !f(2,1)=input value of s'(x1) for K_BC1=1 [arb]
92  !f(2,n)=input value of s'(xn) for K_BCN=1 [arb]
93  !f(3,1)=input value of s''(x1) for K_BC1=2 [arb]
94  !f(3,n)=input value of s''(xn) for K_BCN=2 [arb]
95  !f(2,i)=output s'(x(i)) [arb]
96  !f(3,i)=output s''(x(i)) [arb]
97  !f(4,i)=output s'''(x(i)) [arb]
98 
99 !Declaration of optional input variables
100 INTEGER, INTENT(IN), OPTIONAL :: &
101  K_BC1, & !option for BC at x(1) [-]
102  !=-1 periodic, ignore K_BCN
103  !=0 not-a-knot (default)
104  !=1 s'(x1) = input value of f(2,1)
105  !=2 s''(x1) = input value of f(3,1)
106  !=3 s'(x1) = 0.0
107  !=4 s''(x1) = 0.0
108  !=5 match first derivative to first 2 points
109  !=6 match second derivative to first 3 points
110  !=7 match third derivative to first 4 points
111  !=else use not-a-knot
112  k_bcn !option for boundary condition at x(n) [-]
113  !=0 not-a-knot (default)
114  !=1 s'(x1) = input value of f(2,1)
115  !=2 s''(x1) = input value of f(3,1)
116  !=3 s'(x1) = 0.0
117  !=4 s''(x1) = 0.0
118  !=5 match first derivative to first 2 points
119  !=6 match second derivative to first 3 points
120  !=7 match third derivative to first 4 points
121  !=else use knot-a-knot
122 
123 !-------------------------------------------------------------------------------
124 !Declaration of local variables
125 INTEGER :: &
126  i,ib,imax,imin,kbc1,kbcn
127 
128 REAL(KIND=rspec) :: &
129  a1,an,b1,bn,el21,elnn1,hn,q,t,wk(1:n)
130 
131 !-------------------------------------------------------------------------------
132 !Initialization
133 !-------------------------------------------------------------------------------
134 !Set left BC option, and leftmost node
135 !Default to not-a-knot
136 kbc1=0
137 
138 !Otherwise use requested value
139 IF(PRESENT(k_bc1)) THEN
140 
141  IF(k_bc1 >= -1 .AND. &
142  k_bc1 <= 7) kbc1=k_bc1
143 
144 ENDIF
145 
146 !Include first node for all but not-a-knot
147 imin=1
148 
149 !Not-a-knot condition removes first node
150 IF(kbc1 == 0) imin=2
151 
152 !Set left BC values
153 !Default for not-a-knot
154 a1=0
155 b1=0
156 
157 IF(kbc1 == 1) THEN
158 
159  !First derivative specified
160  a1=f(2,1)
161 
162 ELSEIF(kbc1 == 2) THEN
163 
164  !Second derivative specified
165  b1=f(3,1)
166 
167 ELSEIF(kbc1 == 5) THEN
168 
169  !Match first derivative to first two points
170  a1=(f(1,2)-f(1,1))/(x(2)-x(1))
171 
172 ELSEIF(kbc1 == 6) THEN
173 
174  !Match second derivative to first three points
175  b1=2*((f(1,3)-f(1,2))/(x(3)-x(2))-(f(1,2)-f(1,1))/(x(2)-x(1)))/(x(3)-x(1))
176 
177 ENDIF
178 
179 !Set right BC option, and rightmost node
180 !Default to not-a-knot
181 kbcn=0
182 
183 !Otherwise use requested value
184 IF(PRESENT(k_bcn)) THEN
185 
186  IF(k_bcn >= -1 .AND. &
187  k_bcn <= 7) kbcn=k_bcn
188 
189 ENDIF
190 
191 !Include last node for all but not-a-knot
192 imax=n
193 
194 !Not-a-knot condition removes last node
195 IF(kbcn == 0) imax=n-1
196 
197 !Set right BC values
198 !Default for not-a-knot
199 an=0
200 bn=0
201 
202 IF(kbcn == 1) THEN
203 
204  !First derivative specified
205  an=f(2,n)
206 
207 ELSEIF(kbcn == 2) THEN
208 
209  !Second derivative specified
210  bn=f(3,n)
211 
212 ELSEIF(kbcn == 5) THEN
213 
214  !Match first derivative to last two points
215  an=(f(1,n)-f(1,n-1))/(x(n)-x(n-1))
216 
217 ELSEIF(kbcn == 6) THEN
218 
219  !Match second derivative to first three points
220  bn=2*((f(1,n)-f(1,n-1))/(x(n)-x(n-1)) &
221  -(f(1,n-1)-f(1,n-2))/(x(n-1)-x(n-2)))/(x(n)-x(n-2))
222 
223 ENDIF
224 
225 !Clear derivatives, f(2:4,1:n), and work array
226 f(2:4,1:n)=0
227 wk(1:n)=0
228 
229 !-------------------------------------------------------------------------------
230 !Evaluate coefficients
231 !-------------------------------------------------------------------------------
232 !Two and three nodes are special cases
233 IF(n == 2) THEN
234 
235  !Coefficients for n=2
236  f(2,1)=(f(1,2)-f(1,1))/(x(2)-x(1))
237  f(3,1)=0
238  f(4,1)=0
239  f(2,2)=f(2,1)
240  f(3,2)=0
241  f(4,2)=0
242 
243 !Set up tridiagonal system for A*y=B where y(i) are the second
244 ! derivatives at the knots
245 ! f(2,i) are the diagonal elements of A
246 ! f(4,i) are the off-diagonal elements of A
247 ! f(3,i) are the B elements/3, and will become c/3 upon solution
248 
249 ELSEIF(n > 2) THEN
250 
251  f(4,1)=x(2)-x(1)
252  f(3,2)=(f(1,2)-f(1,1))/f(4,1)
253 
254  DO i=2,n-1 !Over nodes
255 
256  f(4,i)=x(i+1)-x(i)
257  f(2,i)=2*(f(4,i-1)+f(4,i))
258  f(3,i+1)=(f(1,i+1)-f(1,i))/f(4,i)
259  f(3,i)=f(3,i+1)-f(3,i)
260 
261  ENDDO !Over nodes
262 
263  !Save elements for non-symmetric matrix cases
264  el21=f(4,1)
265  elnn1=f(4,n-1)
266 
267 !Apply left BC
268  IF(kbc1 == -1) THEN
269 
270  !Periodic
271  f(2,1)=2*(f(4,1)+f(4,n-1))
272  f(3,1)=(f(1,2)-f(1,1))/f(4,1)-(f(1,n)-f(1,n-1))/f(4,n-1)
273  wk(1)=f(4,n-1)
274  wk(2:n-3)=0
275  wk(n-2)=f(4,n-2)
276  wk(n-1)=f(4,n-1)
277 
278  ELSEIF((kbc1 == 1) .OR. &
279  (kbc1 == 3) .OR. &
280  (kbc1 == 5)) THEN
281 
282  !First derivative conditions
283  f(2,1)=2*f(4,1)
284  f(3,1)=(f(1,2)-f(1,1))/f(4,1)-a1
285 
286  ELSEIF((kbc1 == 2) .OR. (kbc1 == 4) .OR. (kbc1 == 6)) THEN
287 
288  !Second derivative conditions
289  f(2,1)=2*f(4,1)
290  f(3,1)=f(4,1)*b1/3
291  f(4,1)=0
292 
293  ELSEIF(kbc1 == 7) THEN
294 
295  !Third derivative condition
296  f(2,1)=-f(4,1)
297  f(3,1)=f(3,3)/(x(4)-x(2))-f(3,2)/(x(3)-x(1))
298  f(3,1)=f(3,1)*f(4,1)**2/(x(4)-x(1))
299 
300  ELSE
301 
302  !Not-a-knot condition
303  f(2,2)=f(4,1)+2*f(4,2)
304  f(3,2)=f(3,2)*f(4,2)/(f(4,1)+f(4,2))
305 
306  ENDIF
307 
308  !Apply right BC
309  IF((kbcn == 1) .OR. &
310  (kbcn == 3) .OR. &
311  (kbcn == 5)) THEN
312 
313  !First derivative conditions
314  f(2,n)=2*f(4,n-1)
315  f(3,n)=-(f(1,n)-f(1,n-1))/f(4,n-1)+an
316 
317  ELSEIF((kbcn == 2) .OR. &
318  (kbcn == 4) .OR. &
319  (kbcn == 6)) THEN
320 
321  !Second derivative conditions
322  f(2,n)=2*f(4,n-1)
323  f(3,n)=f(4,n-1)*bn/3
324  elnn1=0
325 
326  ELSEIF(kbcn == 7) THEN
327 
328  !Third derivative condition
329  f(2,n)=-f(4,n-1)
330  f(3,n)=f(3,n-1)/(x(n)-x(n-2))-f(3,n-2)/(x(n-1)-x(n-3))
331  f(3,n)=-f(3,n)*f(4,n-1)**2/(x(n)-x(n-3))
332 
333  ELSEIF(kbc1 /= -1) THEN
334 
335  !Not-a-knot condition
336  f(2,n-1)=2*f(4,n-2)+f(4,n-1)
337  f(3,n-1)=f(3,n-1)*f(4,n-2)/(f(4,n-1)+f(4,n-2))
338 
339  ENDIF
340 
341  !Limit solution for only three points in domain
342  IF(n == 3) THEN
343 
344  f(3,1)=0
345  f(3,n)=0
346 
347  ENDIF
348 
349  !Solve system of equations for second derivatives at the knots
350  IF(kbc1 == -1) THEN
351 
352  !Periodic BC - requires special treatment at ends
353  !Forward elimination
354  DO i=2,n-2 !Over nodes in forward elimination
355 
356  t=f(4,i-1)/f(2,i-1)
357  f(2,i)=f(2,i)-t*f(4,i-1)
358  f(3,i)=f(3,i)-t*f(3,i-1)
359  wk(i)=wk(i)-t*wk(i-1)
360  q=wk(n-1)/f(2,i-1)
361  wk(n-1)=-q*f(4,i-1)
362  f(2,n-1)=f(2,n-1)-q*wk(i-1)
363  f(3,n-1)=f(3,n-1)-q*f(3,i-1)
364 
365  ENDDO !Over nodes in forward elimination
366 
367  !Correct the n-1 element
368  wk(n-1)=wk(n-1)+f(4,n-2)
369 
370  !Complete the forward elimination
371  !wk(n-1) and wk(n-2) are the off-diag elements of the lower corner
372  t=wk(n-1)/f(2,n-2)
373  f(2,n-1)=f(2,n-1)-t*wk(n-2)
374  f(3,n-1)=f(3,n-1)-t*f(3,n-2)
375 
376  !Back substitution
377  f(3,n-1)=f(3,n-1)/f(2,n-1)
378  f(3,n-2)=(f(3,n-2)-wk(n-2)*f(3,n-1))/f(2,n-2)
379 
380  DO ib=3,n-1 !Over nodes in back substitution
381 
382  i=n-ib
383  f(3,i)=(f(3,i)-f(4,i)*f(3,i+1)-wk(i)*f(3,n-1))/f(2,i)
384 
385  ENDDO !Over nodes in back substitution
386 
387  f(3,n)=f(3,1)
388 
389  ELSE
390 
391  !Non-periodic BC
392  !Forward elimination
393  !For not-a-knot and s''=0 BCs the off-diagonal end elements are not equal
394  DO i=imin+1,imax !Over nodes in forward elimination
395 
396  IF((i == n-1) .AND. &
397  (imax == n-1)) THEN
398 
399  t=(f(4,i-1)-f(4,i))/f(2,i-1)
400 
401  ELSE
402 
403  IF(i == 2) THEN
404 
405  t=el21/f(2,i-1)
406 
407  ELSEIF(i == n) THEN
408 
409  t=elnn1/f(2,i-1)
410 
411  ELSE
412 
413  t=f(4,i-1)/f(2,i-1)
414 
415  ENDIF
416 
417  ENDIF
418 
419  IF((i == imin+1) .AND. &
420  (imin == 2)) THEN
421 
422  f(2,i)=f(2,i)-t*(f(4,i-1)-f(4,i-2))
423 
424  ELSE
425 
426  f(2,i)=f(2,i)-t*f(4,i-1)
427 
428  ENDIF
429 
430  f(3,i)=f(3,i)-t*f(3,i-1)
431 
432  ENDDO !Over nodes in forward elimination
433 
434  !Back substitution
435  f(3,imax)=f(3,imax)/f(2,imax)
436 
437  DO ib=1,imax-imin !Over nodes in back substitution
438 
439  i=imax-ib
440 
441  IF((i == 2) .AND. &
442  (imin == 2)) THEN
443 
444  f(3,i)=(f(3,i)-(f(4,i)-f(4,i-1))*f(3,i+1))/f(2,i)
445 
446  ELSE
447 
448  f(3,i)=(f(3,i)-f(4,i)*f(3,i+1))/f(2,i)
449 
450  ENDIF
451 
452  ENDDO !Over nodes in back substitution
453 
454  !Reset d array to step size
455  f(4,1)=x(2)-x(1)
456  f(4,n-1)=x(n)-x(n-1)
457 
458  !Set f(3,1) for not-a-knot; 5 changed to 7 in 3/2004
459  IF((kbc1 <= 0) .OR. &
460  (kbc1 > 7)) THEN
461 
462  f(3,1)=(f(3,2)*(f(4,1)+f(4,2))-f(3,3)*f(4,1))/f(4,2)
463 
464  ENDIF
465 
466  !Set f(3,n) for not-a-knot; 5 changed to 7 in 3/2004
467  IF((kbcn <= 0) .OR. &
468  (kbcn > 7)) THEN
469 
470  f(3,n)=f(3,n-1)+(f(3,n-1)-f(3,n-2))*f(4,n-1)/f(4,n-2)
471 
472  ENDIF
473 
474  ENDIF
475 
476  !f(3,i) is now the sigma(i) of the text and f(4,i) is the step size
477  !Compute polynomial coefficients
478  DO i=1,n-1 !Over nodes
479 
480  f(2,i)=(f(1,i+1)-f(1,i))/f(4,i)-f(4,i)*(f(3,i+1)+2*f(3,i))
481  f(4,i)=(f(3,i+1)-f(3,i))/f(4,i)
482  f(3,i)=6*f(3,i)
483  f(4,i)=6*f(4,i)
484 
485  ENDDO !Over nodes
486 
487  IF(kbc1 == -1) THEN
488 
489  !Periodic BC
490  f(2,n)=f(2,1)
491  f(3,n)=f(3,1)
492  f(4,n)=f(4,1)
493 
494  ELSE
495 
496  !All other BCs
497  hn=x(n)-x(n-1)
498  f(2,n)=f(2,n-1)+hn*(f(3,n-1)+hn*f(4,n-1)/2)
499  f(3,n)=f(3,n-1)+hn*f(4,n-1)
500  f(4,n)=f(4,n-1)
501 
502  IF((kbcn == 1) .OR. &
503  (kbcn == 3) .OR. &
504  (kbcn == 5)) THEN
505 
506  !First derivative BC
507  f(2,n)=an
508 
509  ELSEIF((kbcn == 2) .OR. &
510  (kbcn == 4) .OR. &
511  (kbcn == 6)) THEN
512 
513  !Second derivative BC
514  f(3,n)=bn
515 
516  ENDIF
517 
518  ENDIF
519 
520 ENDIF
521 
522 END SUBROUTINE spline1_fit
523 
524 SUBROUTINE spline1_eval(k_vopt,n,u,x,f, &
525  i, &
526  value)
527 !-------------------------------------------------------------------------------
528 !SPLINE1_EVAL evaluates the cubic spline function and its derivatives
529 !
530 !References:
531 ! W.A.Houlberg, P.I. Strand, D.McCune 8/2001
532 ! W.A.Houlberg, F90 free form 8/2004
533 !
534 !Comments:
535 ! s=f(1,i)+f(2,i)*dx+f(3,i)*dx**2/2!+f(4,i)*dx**3/3!
536 ! s'=f(2,i)+f(3,i)*dx+f(4,i)*dx**2/2!
537 ! s''=f(3,i)+f(4,i)*dx
538 ! where dx=u-x(i) and x(i).lt.u.lt.x(i+1)
539 ! If u <= x(1) then i=1 is used
540 ! If u >= x(n) then i=n is used
541 !-------------------------------------------------------------------------------
542 
543 !Declaration of input variables
544 INTEGER, INTENT(IN) :: &
545  k_vopt(:), & !k_vopt(1)=calculate the function [0=off]
546  !k_vopt(2)=calculate the first derivative [0=off]
547  !k_vopt(3)=calculate the second derivative [0=off]
548  n !number of data points [-]
549 
550 REAL(KIND=rspec), INTENT(IN) :: &
551  u, & !abscissa at which the spline is to be evaluated [arb]
552  f(:,:), & !array containing the data ordinates [arb]
553  x(:) !array containing the data abcissas [arb]
554 
555 !Declaration of input/output variables
556 INTEGER, INTENT(INOUT) :: &
557  i !in=guess for target lower bound if 1<i<n [-]
558  !out=target lower bound [-]
559 
560 !Declaration of output variables
561 REAL(KIND=rspec), INTENT(OUT) :: &
562  value(:) !ordering is a subset of the sequence under k_vopt [arb]
563  !value(1)=function or lowest order derivative requested [arb]
564  !value(2)=next order derivative requested [arb]
565  !value(3)=second derivative if all k_vopt are non-zero [arb]
566 
567 !-------------------------------------------------------------------------------
568 !Declaration of local variables
569 INTEGER :: &
570  j
571 
572 REAL(KIND=rspec) :: &
573  dx
574 
575 !-------------------------------------------------------------------------------
576 !Find target cell
577 !-------------------------------------------------------------------------------
578 CALL spline1_search(x,n,u, &
579  i)
580 
581 !-------------------------------------------------------------------------------
582 !Set values outside of range to endpoints
583 !-------------------------------------------------------------------------------
584 IF(i <= 0) THEN
585 
586  i=1
587  dx=0
588 
589 ELSEIF(i >= n) THEN
590 
591  i=n
592  dx=0
593 
594 ELSE
595 
596  dx=u-x(i)
597 
598 ENDIF
599 
600 !-------------------------------------------------------------------------------
601 !Evaluate spline
602 !-------------------------------------------------------------------------------
603 j=0
604 
605 !Value
606 IF(k_vopt(1) /= 0) THEN
607 
608  j=j+1
609  value(j)=f(1,i)+dx*(f(2,i)+dx/2*(f(3,i)+f(4,i)*dx/3))
610 
611 ENDIF
612 
613 !First derivative
614 IF(k_vopt(2) /= 0) THEN
615 
616  j=j+1
617  value(j)=f(2,i)+dx*(f(3,i)+f(4,i)*dx/2)
618 
619 ENDIF
620 
621 !Second derivative
622 IF(k_vopt(3) /= 0) THEN
623 
624  j=j+1
625  value(j)=f(3,i)+dx*f(4,i)
626 
627 ENDIF
628 
629 END SUBROUTINE spline1_eval
630 
631 SUBROUTINE spline1_interp(k_vopt,n0,x0,f,n1,x1,value, &
632  iflag,message, &
633  K_BC1,K_BCN)
634 !-------------------------------------------------------------------------------
635 !SPLINE1_INTERP performs a spline interpolation from the x0 mesh to the x1 mesh
636 !
637 !References:
638 ! W.A.Houlberg, P.I.Strand, D.McCune 8/2001
639 ! W.A.Houlberg, F90 free form 8/2004
640 !-------------------------------------------------------------------------------
641 
642 !Declaration of input variables
643 INTEGER, INTENT(IN) :: &
644  k_vopt(:), & !option for output values
645  !k_vopt(1)=calculate the function [0=off]
646  !k_vopt(2)=calculate the first derivative [0=off]
647  !k_vopt(3)=calculate the second derivative [0=off]
648  n0, & !number of source abscissas [-]
649  n1 !number of target abscissas [-]
650 
651 REAL(KIND=rspec), INTENT(IN) :: &
652  x0(:), & !source abscissas (in increasing order) [arb]
653  x1(:) !target abscissas (in increasing order) [arb]
654 
655 !Declaration of input/output variables
656 REAL(KIND=rspec), INTENT(INOUT) :: &
657  f(:,:) !f(1,n0)=input source values [arb]
658  !f(2,1)=input value of s'(x1) for K_BC1=1 [arb]
659  !f(2,n0)=input value of s'(xn) for K_BCN=1 [arb]
660  !f(3,1)=input value of s''(x1) for K_BC1=2 [arb]
661  !f(3,n0)=input value of s''(xn) for K_BCN=2 [arb]
662  !f(4,n)=output arrays of n0 spline coefficients
663  !f(2,i)=output s'(x0(i))/1!
664  !f(3,i)=output s''(x0(i))/2!
665  !f(4,i)=output s'''(x0(i))/3!
666 
667 !Declaration of output variables
668 CHARACTER(len=*), INTENT(OUT) :: &
669  message !warning or error message [character]
670 
671 INTEGER, INTENT(OUT) :: &
672  iflag !error and warning flag [-]
673  !=-1 warning
674  !=0 none
675  !=1 error
676 
677 REAL(KIND=rspec), INTENT(OUT) :: &
678  value(:,:) !ordering is a subset of the sequence under k_vopt [arb]
679  !value(1,j)=function or lowest order derivative requested [arb]
680  !value(2,j)=next order derivative requested [arb]
681  !value(3,j)=second derivative if all k_vopt are non-zero [arb]
682 
683 
684 !Declaration of optional input variables
685 INTEGER, INTENT(IN), OPTIONAL :: &
686  K_BC1, & !option for BC at x0(1) [-]
687  !=-1 periodic, ignore K_BCN
688  !=0 not-a-knot (default)
689  !=1 s'(x1) = input value of f(2,1)
690  !=2 s''(x1) = input value of f(3,1)
691  !=3 s'(x1) = 0.0
692  !=4 s''(x1) = 0.0
693  !=5 match first derivative to first 2 points
694  !=6 match second derivative to first 3 points
695  !=7 match third derivative to first 4 points
696  !=else use not-a-knot
697  k_bcn !option for boundary condition at x0(n0) [-]
698  !=0 not-a-knot (default)
699  !=1 s'(x1) = input value of f(2,1)
700  !=2 s''(x1) = input value of f(3,1)
701  !=3 s'(x1) = 0.0
702  !=4 s''(x1) = 0.0
703  !=5 match first derivative to first 2 points
704  !=6 match second derivative to first 3 points
705  !=7 match third derivative to first 4 points
706  !=else use knot-a-knot
707 
708 !-------------------------------------------------------------------------------
709 !Declaration of local variables
710 INTEGER :: &
711  i,j
712 
713 !-------------------------------------------------------------------------------
714 !Initialization
715 !-------------------------------------------------------------------------------
716 !If no target values are requested, return
717 IF(n1 <= 0) THEN
718 
719  iflag=-1
720  message='SPLINE1_INTERP/WARNING(1):no points in output array'
721  GOTO 9999
722 
723 ENDIF
724 
725 !Make sure there are at least two nodes in the input grid
726 IF(n0 < 2) THEN
727 
728  iflag=1
729  message='SPLINE1_INTERP/ERROR(2):<2 points in source array'
730  GOTO 9999
731 
732 ENDIF
733 
734 !-------------------------------------------------------------------------------
735 !Get spline coefficients
736 !-------------------------------------------------------------------------------
737 IF(PRESENT(k_bc1) .AND. &
738  PRESENT(k_bcn)) THEN
739 
740  CALL spline1_fit(n0,x0,f, &
741  k_bc1=k_bc1, &
742  k_bcn=k_bcn)
743 
744  ELSEIF(PRESENT(k_bc1)) THEN
745 
746  CALL spline1_fit(n0,x0,f, &
747  k_bc1=k_bc1)
748 
749  ELSEIF(PRESENT(k_bcn)) THEN
750 
751  CALL spline1_fit(n0,x0,f, &
752  k_bcn=k_bcn)
753 
754  ELSE
755 
756  CALL spline1_fit(n0,x0,f)
757 
758 ENDIF
759 
760 !-------------------------------------------------------------------------------
761 !Interpolate onto x1 mesh
762 !-------------------------------------------------------------------------------
763 i=1
764 
765 DO j=1,n1 !Over nodes
766 
767  CALL spline1_eval(k_vopt,n0,x1(j),x0,f,i,value(1:3,j))
768 
769 ENDDO !Over nodes
770 
771 !-------------------------------------------------------------------------------
772 !Cleanup and exit
773 !-------------------------------------------------------------------------------
774  9999 CONTINUE
775 
776 END SUBROUTINE spline1_interp
777 
778 SUBROUTINE spline1_integ(k_order,n0,x0,f,n1,x1, &
779  value,iflag,message)
780 !-------------------------------------------------------------------------------
781 !SPLINE1_INTEG evaluates the integral f(x)*x**k_order, where f(x) is a cubic
782 ! spline function and k_order is 0 or 1
783 !
784 !References:
785 ! Forsythe, Malcolm, Moler, Computer Methods for Mathematical
786 ! Computations, Prentice-Hall (1977) 76
787 ! W.A.Houlberg, P.I.Strand, D.McCune 8/2001
788 ! W.A.Houlberg, F90 free form 8/2004
789 !-------------------------------------------------------------------------------
790 
791 !Declaration of input variables
792 INTEGER, INTENT(IN) :: &
793  k_order, & !exponent in integral (s(x)*x**k_order) [-]
794  !=0 or 1 only
795  n0, & !number of source nodes [-]
796  n1 !number of output nodes (may be 1) [-]
797 
798 REAL(KIND=rspec), INTENT(IN) :: &
799  x0(:), & !source abcissas [arb]
800  x1(:), & !output abcissas at which the integral is wanted [arb]
801  f(:,:) !f(1,n0)=source ordinates [arb]
802  !f(2-4,n0)=spline coefficients computed by SPLINE1_FIT [arb]
803 
804 
805 !Declaration of output variables
806 CHARACTER(len=*), INTENT(OUT) :: &
807  message !warning or error message [character]
808 
809 INTEGER, INTENT(OUT) :: &
810  iflag !error and warning flag [-]
811  !=-1 warning
812  !=0 none
813  !=1 error
814 
815 REAL(KIND=rspec), INTENT(OUT) :: &
816  value(:) !integral of f(x)*x**k_order from x0(1) to x1(i) [arb]
817 
818 !-------------------------------------------------------------------------------
819 !Declaration of local variables
820 INTEGER :: &
821  i,j,ido,jdo
822 
823 REAL(KIND=rspec) :: &
824  add,dx,sum,xnew,xold
825 
826 !-------------------------------------------------------------------------------
827 !Initialization
828 !-------------------------------------------------------------------------------
829 !If no target values are requested, return
830 IF(n1 <= 0) GOTO 9999
831 
832 value(1:n1)=0
833 
834 !Integral value
835 sum=0
836 
837 !Source index and abscissa
838 j=1
839 xold=x0(j)
840 
841 !-------------------------------------------------------------------------------
842 !Integrate over target abscissas
843 !-------------------------------------------------------------------------------
844 DO i=1,n1 !Over target abscissas
845 
846  !Find dx to next source or target abscissa
847  ido=0
848 
849  DO WHILE(ido == 0) !Over source abscissas
850 
851  IF(x1(i) < x0(j+1)) THEN
852 
853  !Hit target abscissa
854  xnew=x1(i)
855  ido=1
856  jdo=0
857 
858  ELSEIF(x1(i) == x0(j+1)) THEN
859 
860  !Hit both source and target abscissas
861  xnew=x1(i)
862  ido=1
863  jdo=1
864 
865  ELSEIF(x1(i) > x0(j+1)) THEN
866 
867  !Hit source abscissa
868  xnew=x0(j+1)
869  ido=0
870  jdo=1
871 
872  ENDIF
873 
874  !Integrate over dx
875  dx=xnew-xold
876 
877  IF(k_order == 1) THEN
878 
879  !Integral x s(x)dx
880  add= dx*(xold*f(1,j) &
881  +dx*((xold*f(2,j)+f(1,j))/2 &
882  +dx*((xold*f(3,j)/2+f(2,j))/3 &
883  +dx*((xold*f(4,j)/3+f(3,j))/8 &
884  +dx*f(4,j)/30))))
885 
886  ELSE
887 
888  !Integral s(x)dx
889  add=dx*(f(1,j)+dx*(f(2,j)+dx*(f(3,j)+dx*f(4,j)/4)/3)/2)
890 
891  ENDIF
892 
893  !Add increment and update endpoint
894  sum=sum+add
895  xold=xnew
896 
897  !Check whether to increment source index
898  IF(jdo == 1) j=j+1
899 
900  !Check whether target index is in range
901  IF(j > n0) THEN
902 
903  iflag=1
904  message='LINEAR1_INTEG/ERROR:target node out of range'
905  GOTO 9999
906 
907  ENDIF
908 
909  !Set integral value
910  value(i)=sum
911 
912  ENDDO !Over source abscissas
913 
914 ENDDO !Over target abscissas
915 
916 !-------------------------------------------------------------------------------
917 !Cleanup and exit
918 !-------------------------------------------------------------------------------
919 9999 CONTINUE
920 
921 END SUBROUTINE spline1_integ
922 
923 SUBROUTINE spline1_search(x,n,xl, &
924  jlo)
925 !-------------------------------------------------------------------------------
926 !SPLINE1_SEARCH is a correlated table search routine to find the indices of the
927 ! array x that bound xl
928 !
929 !References:
930 ! W.A.Houlberg, P.I.Strand, D.McCune 8/2001
931 !
932 !Comments:
933 ! This is similar to the Numerical Recipes routine HUNT
934 !-------------------------------------------------------------------------------
935 
936 !Declaration of input variables
937 INTEGER, INTENT(IN) :: &
938  n !number of abscissas [-]
939 
940 REAL(KIND=rspec), INTENT(IN) :: &
941  xl, & !target value [arb]
942  x(:) !monotonically increasing array of abscissas [arb]
943 
944 !Declaration of input/output variables
945 INTEGER, INTENT(INOUT) :: &
946  jlo !input starting lower index [-]
947 
948  !=1,n-1 use value
950  !output starting lower index [-]
951  !=0 xl < x(1)
952  !=1 x(1) <= xl <= x(2)
953  !=2,n-1 x(jlo) < xl <= x(jlo+1)
954  !=n x(jlo) > x(n)
955 
956 !-------------------------------------------------------------------------------
957 !Declaration of local variables
958 INTEGER :: &
959  inc,jhi,jmid
960 
961 !-------------------------------------------------------------------------------
962 !Check lower end of array, first two points
963 !-------------------------------------------------------------------------------
964 IF(xl < x(1)) THEN
965 
966  !Target is below node 1
967  jlo=0
968 
969 ELSEIF(xl <= x(2)) THEN
970 
971  !Target is between nodes 1 and 2 inclusive
972  jlo=1
973 
974 !-------------------------------------------------------------------------------
975 !Check middle range
976 !-------------------------------------------------------------------------------
977 ELSEIF(xl <= x(n)) THEN
978 
979  !Target is between nodes 2 and n
980  IF(jlo < 1 .OR. &
981  jlo > (n-1)) THEN
982 
983  !jlo from previous call is unusable
984  jlo=2
985  jhi=n
986 
987  !Bracket target value
988  ELSE
989 
990  !Start with jlo from previous call
991  inc=1
992 
993  IF(xl > x(jlo)) THEN
994 
995  !Search up
996  jhi=jlo+1
997 
998  DO WHILE(xl > x(jhi))
999 
1000  inc=2*inc
1001  jlo=jhi
1002  jhi=min(jlo+inc,n)
1003 
1004  ENDDO
1005 
1006  ELSE
1007 
1008  !Search down
1009  jhi=jlo
1010  jlo=jlo-1
1011 
1012  DO WHILE(xl <= x(jlo))
1013 
1014  inc=inc+inc
1015  jhi=jlo
1016  jlo=max(jlo-inc,1)
1017 
1018  ENDDO
1019 
1020  ENDIF
1021 
1022  ENDIF
1023 
1024  !Bisection
1025  DO WHILE(jhi-jlo > 1)
1026 
1027  jmid=(jhi+jlo)/2
1028 
1029  IF(xl > x(jmid)) THEN
1030 
1031  jlo=jmid
1032 
1033  ELSE
1034 
1035  jhi=jmid
1036 
1037  ENDIF
1038 
1039  ENDDO
1040 
1041 !-------------------------------------------------------------------------------
1042 !Target is above node n
1043 !-------------------------------------------------------------------------------
1044 ELSE
1045 
1046  jlo=n
1047 
1048 ENDIF
1049 
1050 END SUBROUTINE spline1_search
1051 
1052 END MODULE spline1_mod