UFO
lag_interp.F90
Go to the documentation of this file.
1 !> Fortran module to prepare for Lagrange polynomial interpolation.
2 !> based on GSI: lagmod.f90
3 
5 
6 use kinds, only: kind_real
7 use gnssro_mod_constants,only: zero, one
8 
9 implicit none
10 
11 ! set default to private
12 private
13 ! set subroutines to public
14 public :: lag_interp_const
15 public :: lag_interp_const_tl
16 public :: lag_interp_weights
17 public :: lag_interp_weights_tl
18 public :: lag_interp_smthweights
20 
21 contains
22 
23 subroutine lag_interp_const(q,x,n)
24 ! Precompute the N constant denominator factors of the N-point
25 ! Lagrange polynomial interpolation formula.
26 !
27 ! input argument list:
28 ! X - The N abscissae.
29 ! N - The number of points involved.
30 !
31 ! output argument list:
32 ! Q - The N denominator constants.
33 IMPLICIT NONE
34 
35 INTEGER ,INTENT(in ) :: n
36 REAL(kind_real),INTENT( out) :: q(n)
37 REAL(kind_real),INTENT(in ) :: x(n)
38 !-----------------------------------------------------------------------------
39 INTEGER :: i,j
40 !=============================================================================
41 DO i=1,n
42  q(i)=one
43  DO j=1,n
44  IF(j /= i)q(i)=q(i)/(x(i)-x(j))
45  ENDDO
46 ENDDO
47 end subroutine lag_interp_const
48 
49 
50 !============================================================================
51 subroutine lag_interp_const_tl(q,q_TL,x,x_TL,n)
52 !============================================================================
53 IMPLICIT NONE
54 
55 INTEGER ,INTENT(in ) :: n !number of points involved
56 REAL(kind_real),DIMENSION(n),INTENT( out) :: q,q_tl
57 REAL(kind_real),DIMENSION(n),INTENT(in ) :: x,x_tl
58 !-----------------------------------------------------------------------------
59 INTEGER :: i,j
60 REAL(kind_real) :: rat
61 !=============================================================================
62 DO i=1,n
63  q(i)=one
64  q_tl(i)=zero
65  DO j=1,n
66  IF(j /= i) THEN
67  rat=one/(x(i)-x(j))
68  q_tl(i)=(q_tl(i)-q(i)*(x_tl(i)-x_tl(j))*rat)*rat
69  q(i)=q(i)*rat
70  ENDIF
71  ENDDO
72 ENDDO
73 end subroutine lag_interp_const_tl
74 
75 !============================================================================
76 subroutine lag_interp_weights(x,xt,q,w,dw,n)
77 ! Construct the Lagrange weights and their derivatives when
78 ! target abscissa is known and denominators Q have already
79 ! been precomputed
80 !
81 ! input argument list:
82 ! X - Grid abscissae
83 ! XT - Target abscissa
84 ! Q - Q factors (denominators of the Lagrange weight formula)
85 ! N - Number of grid points involved in the interpolation
86 !
87 ! output argument list:
88 ! W - Lagrange weights
89 ! DW - Derivatives, dW/dX, of Lagrange weights W
90 !============================================================================
91 IMPLICIT NONE
92 
93 INTEGER ,INTENT(IN ) :: n
94 REAL(kind_real) ,INTENT(IN ) :: xt
95 REAL(kind_real),INTENT(IN ) :: x(n),q(n)
96 REAL(kind_real),INTENT( OUT) :: w(n),dw(n)
97 !-----------------------------------------------------------------------------
98 REAL(kind_real) :: d(n),pa(n),pb(n),dpa(n),dpb(n)
99 INTEGER :: j
100 !============================================================================
101 pa(1)=one
102 dpa(1)=zero
103 do j=1,n-1
104  d(j)=xt-x(j)
105  pa(j+1)=pa(j)*d(j)
106  dpa(j+1)=dpa(j)*d(j)+pa(j)
107 enddo
108 d(n)=xt-x(n)
109 
110 pb(n)=one
111 dpb(n)=zero
112 do j=n,2,-1
113  pb(j-1)=pb(j)*d(j)
114  dpb(j-1)=dpb(j)*d(j)+pb(j)
115 enddo
116 do j=1,n
117  w(j)= pa(j)*pb(j)*q(j)
118  dw(j)=(pa(j)*dpb(j)+dpa(j)*pb(j))*q(j)
119 enddo
120 end subroutine lag_interp_weights
121 
122 
123 !============================================================================
124 subroutine lag_interp_weights_tl(x,x_TL,xt,q,q_TL,w,w_TL,dw,dw_TL,n)
125 !============================================================================
126 IMPLICIT NONE
127 
128 INTEGER ,INTENT(IN ) :: n
129 REAL(kind_real) ,INTENT(IN ) :: xt
130 REAL(kind_real),DIMENSION(n),INTENT(IN ) :: x,q,x_tl,q_tl
131 REAL(kind_real),DIMENSION(n),INTENT( OUT) :: w,dw,w_tl,dw_tl
132 !-----------------------------------------------------------------------------
133 REAL(kind_real),DIMENSION(n) :: d,pa,pb,dpa,dpb
134 REAL(kind_real),DIMENSION(n) :: d_tl,pa_tl,pb_tl,dpa_tl,dpb_tl
135 INTEGER :: j
136 !============================================================================
137 pa(1)=one
138 dpa(1)=zero
139 pa_tl(1)=zero
140 dpa_tl(1)=zero
141 
142 do j=1,n-1
143  d(j)=xt-x(j)
144  d_tl(j)=-x_tl(j)
145  pa(j+1)=pa(j)*d(j)
146  pa_tl(j+1)=pa_tl(j)*d(j)+pa(j)*d_tl(j)
147  dpa(j+1)=dpa(j)*d(j)+pa(j)
148  dpa_tl(j+1)=dpa_tl(j)*d(j)+dpa(j)*d_tl(j)+pa_tl(j)
149 enddo
150 d(n)=xt-x(n)
151 d_tl(n)=-x_tl(n)
152 
153 pb(n)=one
154 dpb(n)=zero
155 pb_tl(n)=zero
156 dpb_tl(n)=zero
157 do j=n,2,-1
158  pb(j-1)=pb(j)*d(j)
159  pb_tl(j-1)=pb_tl(j)*d(j)+pb(j)*d_tl(j)
160  dpb(j-1)=dpb(j)*d(j)+pb(j)
161  dpb_tl(j-1)=dpb_tl(j)*d(j)+dpb(j)*d_tl(j)+pb_tl(j)
162 enddo
163 do j=1,n
164  w(j)= pa(j)*pb(j)*q(j)
165  dw(j)=(pa(j)*dpb(j)+dpa(j)*pb(j))*q(j)
166  w_tl(j)=(pa_tl(j)*pb(j)+pa(j)*pb_tl(j))*q(j)+pa(j)*pb(j)*q_tl(j)
167  dw_tl(j)=(pa_tl(j)*dpb(j)+pa(j)*dpb_tl(j)+dpa_tl(j)*pb(j)+dpa(j)*pb_tl(j))*q(j)+ &
168  (pa(j)*dpb(j)+dpa(j)*pb(j))*q_tl(j)
169 enddo
170 end subroutine lag_interp_weights_tl
171 
172 !============================================================================
173 subroutine lag_interp_smthweights(x,xt,aq,bq,w,dw,n)
174 ! Construct weights and their derivatives for interpolation
175 ! to a given target based on a linearly weighted mixture of
176 ! the pair of Lagrange interpolators which omit the respective
177 ! end points of the source nodes provided. The number of source
178 ! points provided must be even and the nominal target interval
179 ! is the unique central one. The linear weighting pair is
180 ! determined by the relative location of the target within
181 ! this central interval, or else the extreme values, 0 and 1,
182 ! when target lies outside this interval. The objective is to
183 ! provide an interpolator whose derivative is continuous.
184 !============================================================================
185 IMPLICIT NONE
186 
187 INTEGER ,INTENT(IN ) :: n
188 REAL(kind_real) ,INTENT(IN ) :: xt
189 REAL(kind_real),INTENT(IN ) :: x(n)
190 REAL(kind_real),INTENT(IN ) :: aq(n-1),bq(n-1)
191 REAL(kind_real),INTENT( OUT) :: w(n),dw(n)
192 !-----------------------------------------------------------------------------
193 REAL(kind_real) :: aw(n),bw(n),daw(n),dbw(n)
194 REAL(kind_real) :: xa,xb,dwb,wb
195 INTEGER :: na
196 !============================================================================
197 CALL lag_interp_weights(x(1:n-1),xt,aq,aw(1:n-1),daw(1:n-1),n-1)
198 CALL lag_interp_weights(x(2:n ),xt,bq,bw(2:n ),dbw(2:n ),n-1)
199 aw(n)=zero
200 daw(n)=zero
201 bw(1)=zero
202 dbw(1)=zero
203 na=n/2
204 IF(na*2 /= n)stop 'In lag_interp_smthWeights; n must be even'
205 xa =x(na )
206 xb =x(na+1)
207 dwb=one/(xb-xa)
208 wb =(xt-xa)*dwb
209 IF(wb>one )THEN
210  wb =one
211  dwb=zero
212 ELSEIF(wb<zero)THEN
213  wb =zero
214  dwb=zero
215 ENDIF
216 
217 bw =bw -aw
218 dbw=dbw-daw
219 
220 w =aw +wb*bw
221 dw=daw+wb*dbw+dwb*bw
222 end subroutine lag_interp_smthweights
223 
224 !============================================================================
225 subroutine lag_interp_smthweights_tl(x,x_TL,xt,aq,aq_TL,bq,bq_TL,dw,dw_TL,n)
226 !============================================================================
227 IMPLICIT NONE
228 
229 INTEGER ,INTENT(IN ) :: n
230 REAL(kind_real) ,INTENT(IN ) :: xt
231 REAL(kind_real),DIMENSION(n) ,INTENT(IN ) :: x,x_tl
232 REAL(kind_real),DIMENSION(n-1),INTENT(IN ) :: aq,bq,aq_tl,bq_tl
233 REAL(kind_real),DIMENSION(n) ,INTENT( OUT) :: dw_tl,dw
234 !-----------------------------------------------------------------------------
235 REAL(kind_real),DIMENSION(n) :: aw,bw,daw,dbw
236 REAL(kind_real),DIMENSION(n) :: aw_tl,bw_tl,daw_tl,dbw_tl
237 REAL(kind_real) :: xa,xb,dwb,wb
238 REAL(kind_real) :: xa_tl,xb_tl,dwb_tl,wb_tl
239 INTEGER :: na
240 !============================================================================
241 CALL lag_interp_weights_tl(x(1:n-1),x_tl(1:n-1),xt,aq,aq_tl,aw(1:n-1),aw_tl(1:n-1),&
242  daw(1:n-1),daw_tl(1:n-1),n-1)
243 CALL lag_interp_weights_tl(x(2:n ),x_tl(2:n ),xt,bq,bq_tl,bw(2:n ),bw_tl(2:n ),&
244  dbw(2:n ),dbw_tl(2:n ),n-1)
245 aw(n) =zero
246 daw(n)=zero
247 bw(1) =zero
248 dbw(1)=zero
249 !
250 aw_tl(n) =zero
251 daw_tl(n)=zero
252 bw_tl(1) =zero
253 dbw_tl(1)=zero
254 na=n/2
255 IF(na*2 /= n)stop 'In lag_interp_smthWeights; n must be even'
256 xa =x(na)
257 xa_tl=x_tl(na)
258 xb =x(na+1)
259 xb_tl=x_tl(na+1)
260 dwb = one /(xb-xa)
261 dwb_tl=-(xb_tl-xa_tl)/(xb-xa)**2
262 wb = (xt-xa)*dwb
263 wb_tl=(-xa_tl)*dwb+(xt-xa)*dwb_tl
264 IF(wb > one)THEN
265  wb =one
266  dwb =zero
267  wb_tl =zero
268  dwb_tl=zero
269 ELSEIF(wb < zero)THEN
270  wb =zero
271  dwb =zero
272  wb_tl =zero
273  dwb_tl=zero
274 ENDIF
275 
276 bw =bw -aw
277 bw_tl =bw_tl -aw_tl
278 dbw =dbw -daw
279 dbw_tl=dbw_tl-daw_tl
280 
281 !w=aw+wb*bw
282 dw =daw + wb *dbw + dwb *bw
283 dw_tl=daw_tl+(wb_tl*dbw+wb*dbw_tl)+(dwb_tl*bw+dwb*bw_tl)
284 end subroutine lag_interp_smthweights_tl
285 
286 end module lag_interp_mod
287 
Fortran module to prepare for Lagrange polynomial interpolation. based on GSI: lagmod....
Definition: lag_interp.F90:4
subroutine, public lag_interp_weights(x, xt, q, w, dw, n)
Definition: lag_interp.F90:77
subroutine, public lag_interp_smthweights_tl(x, x_TL, xt, aq, aq_TL, bq, bq_TL, dw, dw_TL, n)
Definition: lag_interp.F90:226
subroutine, public lag_interp_const(q, x, n)
Definition: lag_interp.F90:24
subroutine, public lag_interp_const_tl(q, q_TL, x, x_TL, n)
Definition: lag_interp.F90:52
subroutine, public lag_interp_weights_tl(x, x_TL, xt, q, q_TL, w, w_TL, dw, dw_TL, n)
Definition: lag_interp.F90:125
subroutine, public lag_interp_smthweights(x, xt, aq, bq, w, dw, n)
Definition: lag_interp.F90:174