-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpoly_interp.f90
114 lines (86 loc) · 2.52 KB
/
poly_interp.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
!> Performs a Lagrange interpolation of a function and gives its
!> Derivatives.
!> Based on D. B. Hunter, The Computer Journal, 3, 270 (1961)
!> with the small difference algorithm of Numerical Recipes Eq. 3.1.5
!>
!> \author Jose Luis Martins
!> \version 6.0.6
!> \date 5 July 2021, 6 November 2021.
!> \copyright GNU Public License v3
subroutine poly_interp(y, dy, xin, yin, n, nd)
implicit none
integer, parameter :: REAL64 = selected_real_kind(12)
! input
integer, intent(in) :: n !< order of interpolation
integer, intent(in) :: nd !< order of derivative
real(REAL64), intent(in) :: xin(0:n) !< grid points
real(REAL64), intent(in) :: yin(0:n) !< f(xin)
! output
real(REAL64), intent(out) :: y(0:nd) !< f(0) interpolated value at x=0
real(REAL64), intent(out) :: dy(0:nd) !< error estimate (last correction)
! work arrays
real(REAL64), allocatable :: cmi(:,:), dmi(:,:) ! difference arrays of Neville's algorithm
real(REAL64), allocatable :: xnum(:)
! local variables
integer :: ns
real(REAL64) :: dp, dm
! constants
real(REAL64), parameter :: ZERO = 0.0_REAL64
! counters
integer :: i, m, k, kmax
allocate(cmi(0:nd,0:n),dmi(0:nd,0:n))
allocate(xnum(0:nd))
ns = 0
do i = 0,n
if( abs(xin(i)) < abs(xin(ns)) ) ns = i
enddo
y(0) = yin(ns)
ns = ns - 1
do i = 0,n
cmi(0,i) = yin(i)
dmi(0,i) = yin(i)
enddo
if(nd > 0) then
do k = 1,nd
y(k) = ZERO
enddo
do i = 0,n
do k = 1,nd
cmi(k,i) = ZERO
dmi(k,i) = ZERO
enddo
enddo
endif
do m = 1,n
kmax = min(m,nd)
do i = 0,n-m
dm = xin(i)
dp = xin(i+m)
do k = 0,kmax
xnum(k) = (dmi(k,i) - cmi(k,i+1)) / (dp - dm)
enddo
dmi(0,i) = dp*xnum(0)
cmi(0,i) = dm*xnum(0)
if(nd > 0) then
do k = 1,kmax
dmi(k,i) = dp*xnum(k) - k*xnum(k-1)
cmi(k,i) = dm*xnum(k) - k*xnum(k-1)
enddo
endif
enddo
if (2*ns+1 < n - m) then
do k = 0,kmax
dy(k) = cmi(k,ns+1)
enddo
else
do k = 0,kmax
dy(k) = dmi(k,ns)
enddo
ns = ns - 1
endif
do k = 0,kmax
y(k) = y(k) + dy(k)
enddo
enddo
return
end subroutine poly_interp