~jose-soler/siesta/unfolding

« back to all changes in this revision

Viewing changes to Pseudo/atom/Util/Ps2Inp/flib_spline.f90

  • Committer: Alberto Garcia
  • Date: 2016-01-25 16:00:16 UTC
  • mto: (483.3.1 rel-4.0)
  • mto: This revision was merged to the branch mainline in revision 485.
  • Revision ID: albertog@icmab.es-20160125160016-c1qivg1zw06kgyfd
Prepare GPL release

* Include proper headers

* Add Docs/Contributors.txt and NOTICE.txt files.

* Update READMEs and LICENSE files in several directories.

* Remove Pseudo/atom, Util/test-xml

* Remove DOM files from Src/xmlparser

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
module flib_spline
2
 
!
3
 
! Spline interpolation, based on code in "Numerical Recipes"
4
 
!
5
 
implicit none
6
 
      integer, parameter :: dp = selected_real_kind(16,100)
7
 
      integer, parameter :: sp = selected_real_kind(5,10)
8
 
private
9
 
 
10
 
public :: generate_spline
11
 
interface generate_spline
12
 
  module procedure generate_spline_sp
13
 
  module procedure generate_spline_dp
14
 
end interface generate_spline
15
 
 
16
 
public :: evaluate_spline
17
 
interface evaluate_spline
18
 
  module procedure evaluate_spline_sp
19
 
  module procedure evaluate_spline_dp
20
 
end interface evaluate_spline
21
 
 
22
 
 
23
 
private :: generate_spline_sp
24
 
private :: generate_spline_dp
25
 
private :: evaluate_spline_sp
26
 
private :: evaluate_spline_dp
27
 
 
28
 
CONTAINS  !=================
29
 
 
30
 
SUBROUTINE generate_spline_sp(X,Y,N,Y2,YP1,YPN,stat)
31
 
!
32
 
! Given arrays x and y of size n, this routine computes
33
 
! an array y2 holding information about the second derivative
34
 
! of the interpolating spline. YP1 and YPN, if present, are the
35
 
! requested values of the first derivative of the spline at the
36
 
! end points. If not given, a "natural" spline with zero second
37
 
! derivative at the extremes is constructed.
38
 
! The array y2 is needed to evaluate the spline, but it only needs
39
 
! to be computed once.
40
 
!
41
 
integer, intent(in)                          :: n
42
 
real(kind=sp), dimension(:), intent(in)  :: x, y
43
 
real(kind=sp), dimension(:), intent(out) :: y2
44
 
real(kind=sp), intent(in), optional      :: yp1, ypn
45
 
integer, intent(out), optional               :: stat
46
 
 
47
 
real(kind=sp)  ::  P,QN,SIG,UN
48
 
INTEGER            ::  I,K
49
 
integer            ::  flag
50
 
 
51
 
real(kind=sp), parameter  :: zero = 0.0_sp, &
52
 
                                 half = 0.5_sp, &
53
 
                                 one  = 1.0_sp, &
54
 
                                 two  = 2.0_sp, &
55
 
                                 three= 3.0_sp, &
56
 
                                 six  = 6.0_sp
57
 
 
58
 
real(kind=sp), dimension(n)  ::   U    ! Automatic array
59
 
 
60
 
!--------------------------------------------------------
61
 
! Check that the nodes are different
62
 
!
63
 
flag = 0
64
 
do i =2, n
65
 
  if (x(i) == x(i-1)) then
66
 
   flag = -1
67
 
   if (present(stat)) stat = flag
68
 
   RETURN
69
 
  endif
70
 
enddo
71
 
        
72
 
IF (present(YP1)) THEN
73
 
    Y2(1) = -half
74
 
    U(1) = (three/ (X(2)-X(1)))* ((Y(2)-Y(1))/ (X(2)-X(1))-YP1)
75
 
ELSE
76
 
    Y2(1) = zero
77
 
    U(1) = zero
78
 
END IF
79
 
 
80
 
DO I = 2,N - 1
81
 
    SIG = (X(I)-X(I-1))/ (X(I+1)-X(I-1))
82
 
    P = SIG*Y2(I-1) + two
83
 
    Y2(I) = (SIG-one)/P
84
 
    U(I) = ( six * ((Y(I+1)-Y(I))/ (X(I+1)-X(I))- (Y(I)-Y(I-1))/ &
85
 
            (X(I)-X(I-1)))/ (X(I+1)-X(I-1))-SIG*U(I-1))/P
86
 
enddo
87
 
IF (present(YPN)) THEN
88
 
    QN = half
89
 
    UN = (three/(X(N)-X(N-1)))* (YPN - (Y(N)-Y(N-1))/ (X(N)-X(N-1)))
90
 
ELSE
91
 
    QN = zero
92
 
    UN = zero
93
 
END IF
94
 
 
95
 
Y2(N) = (UN-QN*U(N-1))/ (QN*Y2(N-1) + one)
96
 
DO K = N-1 , 1 , -1
97
 
    Y2(K) = Y2(K)*Y2(K+1) + U(K)
98
 
enddo
99
 
 
100
 
if (present(stat)) stat = flag
101
 
 
102
 
end subroutine generate_spline_sp
103
 
 
104
 
!..............................................
105
 
SUBROUTINE generate_spline_dp(X,Y,N,Y2,YP1,YPN,stat)
106
 
!
107
 
! Given arrays x and y of size n, this routine computes
108
 
! an array y2 holding information about the second derivative
109
 
! of the interpolating spline. YP1 and YPN, if present, are the
110
 
! requested values of the first derivative of the spline at the
111
 
! end points. If not given, a "natural" spline with zero second
112
 
! derivative at the extremes is constructed.
113
 
! The array y2 is needed to evaluate the spline, but it only needs
114
 
! to be computed once.
115
 
!
116
 
integer, intent(in)                          :: n
117
 
real(kind=dp), dimension(:), intent(in)  :: x, y
118
 
real(kind=dp), dimension(:), intent(out) :: y2
119
 
real(kind=dp), intent(in), optional      :: yp1, ypn
120
 
integer, intent(out), optional               :: stat
121
 
 
122
 
real(kind=dp)  ::  P,QN,SIG,UN
123
 
INTEGER            ::  I,K
124
 
integer            ::  flag
125
 
 
126
 
real(kind=dp), parameter  :: zero = 0.0_dp, &
127
 
                                 half = 0.5_dp, &
128
 
                                 one  = 1.0_dp, &
129
 
                                 two  = 2.0_dp, &
130
 
                                 three= 3.0_dp, &
131
 
                                 six  = 6.0_dp
132
 
 
133
 
real(kind=dp), dimension(n)  ::   U    ! Automatic array
134
 
 
135
 
!--------------------------------------------------------
136
 
! Check that the nodes are different
137
 
!
138
 
flag = 0
139
 
do i =2, n
140
 
  if (x(i) == x(i-1)) then
141
 
   flag = -1
142
 
   if (present(stat)) stat = flag
143
 
   RETURN
144
 
  endif
145
 
enddo
146
 
        
147
 
IF (present(YP1)) THEN
148
 
    Y2(1) = -half
149
 
    U(1) = (three/ (X(2)-X(1)))* ((Y(2)-Y(1))/ (X(2)-X(1))-YP1)
150
 
ELSE
151
 
    Y2(1) = zero
152
 
    U(1) = zero
153
 
END IF
154
 
 
155
 
DO I = 2,N - 1
156
 
    SIG = (X(I)-X(I-1))/ (X(I+1)-X(I-1))
157
 
    P = SIG*Y2(I-1) + two
158
 
    Y2(I) = (SIG-one)/P
159
 
    U(I) = ( six * ((Y(I+1)-Y(I))/ (X(I+1)-X(I))- (Y(I)-Y(I-1))/ &
160
 
            (X(I)-X(I-1)))/ (X(I+1)-X(I-1))-SIG*U(I-1))/P
161
 
enddo
162
 
IF (present(YPN)) THEN
163
 
    QN = half
164
 
    UN = (three/(X(N)-X(N-1)))* (YPN - (Y(N)-Y(N-1))/ (X(N)-X(N-1)))
165
 
ELSE
166
 
    QN = zero
167
 
    UN = zero
168
 
END IF
169
 
 
170
 
Y2(N) = (UN-QN*U(N-1))/ (QN*Y2(N-1) + one)
171
 
DO K = N-1 , 1 , -1
172
 
    Y2(K) = Y2(K)*Y2(K+1) + U(K)
173
 
enddo
174
 
 
175
 
if (present(stat)) stat = flag
176
 
 
177
 
end subroutine generate_spline_dp
178
 
 
179
 
!..............................................
180
 
!------------------------------------------------
181
 
SUBROUTINE evaluate_spline_sp(XA,YA,Y2A,N,X,Y)
182
 
!
183
 
! Given arrays xa and ya of size n, and an array y2a computed
184
 
! previously by routine spline, this routine computes the value
185
 
! at x of the interpolating spline. The value is returned in y.
186
 
!
187
 
integer, intent(in)                          :: n
188
 
real(kind=sp), dimension(:), intent(in)  :: xa, ya, y2a
189
 
real(kind=sp), intent(in)                :: x
190
 
real(kind=sp), intent(out)               :: y
191
 
 
192
 
 
193
 
real(kind=sp)    ::  A,B,H
194
 
integer              ::  K,KHI,KLO
195
 
 
196
 
KLO = 1
197
 
KHI = N
198
 
do
199
 
   IF (KHI-KLO <= 1) exit
200
 
   K = (KHI+KLO)/2
201
 
   IF (XA(K) > X) THEN
202
 
      KHI = K
203
 
   ELSE
204
 
      KLO = K
205
 
   END IF
206
 
enddo
207
 
 
208
 
H = XA(KHI) - XA(KLO)
209
 
 
210
 
A = (XA(KHI)-X)/H
211
 
B = (X-XA(KLO))/H
212
 
Y = A*YA(KLO) + B*YA(KHI) + ((A**3-A)*Y2A(KLO)+  &
213
 
   (B**3-B)*Y2A(KHI))* (H**2)/6.0_sp
214
 
 
215
 
end subroutine evaluate_spline_sp
216
 
!..............................................
217
 
SUBROUTINE evaluate_spline_dp(XA,YA,Y2A,N,X,Y)
218
 
!
219
 
! Given arrays xa and ya of size n, and an array y2a computed
220
 
! previously by routine spline, this routine computes the value
221
 
! at x of the interpolating spline. The value is returned in y.
222
 
!
223
 
integer, intent(in)                          :: n
224
 
real(kind=dp), dimension(:), intent(in)  :: xa, ya, y2a
225
 
real(kind=dp), intent(in)                :: x
226
 
real(kind=dp), intent(out)               :: y
227
 
 
228
 
 
229
 
real(kind=dp)    ::  A,B,H
230
 
integer              ::  K,KHI,KLO
231
 
 
232
 
KLO = 1
233
 
KHI = N
234
 
do
235
 
   IF (KHI-KLO <= 1) exit
236
 
   K = (KHI+KLO)/2
237
 
   IF (XA(K) > X) THEN
238
 
      KHI = K
239
 
   ELSE
240
 
      KLO = K
241
 
   END IF
242
 
enddo
243
 
 
244
 
H = XA(KHI) - XA(KLO)
245
 
 
246
 
A = (XA(KHI)-X)/H
247
 
B = (X-XA(KLO))/H
248
 
Y = A*YA(KLO) + B*YA(KHI) + ((A**3-A)*Y2A(KLO)+  &
249
 
   (B**3-B)*Y2A(KHI))* (H**2)/6.0_dp
250
 
 
251
 
end subroutine evaluate_spline_dp
252
 
!..............................................
253
 
!------------------------------------------------
254
 
end module flib_spline