FV3 Bundle
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
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_const_ad
17 public :: lag_interp_weights
18 public :: lag_interp_weights_tl
19 public :: lag_interp_weights_ad
20 public :: lag_interp_smthweights
23 
24 
25 contains
26 
27 subroutine lag_interp_const(q,x,n)
28 ! Precompute the N constant denominator factors of the N-point
29 ! Lagrange polynomial interpolation formula.
30 !
31 ! input argument list:
32 ! X - The N abscissae.
33 ! N - The number of points involved.
34 !
35 ! output argument list:
36 ! Q - The N denominator constants.
37 IMPLICIT NONE
38 
39 INTEGER ,INTENT(in ) :: n
40 REAL(kind_real),INTENT( out) :: q(n)
41 REAL(kind_real),INTENT(in ) :: x(n)
42 !-----------------------------------------------------------------------------
43 INTEGER :: i,j
44 !=============================================================================
45 DO i=1,n
46  q(i)=one
47  DO j=1,n
48  IF(j /= i)q(i)=q(i)/(x(i)-x(j))
49  ENDDO
50 ENDDO
51 end subroutine lag_interp_const
52 
53 
54 !============================================================================
55 subroutine lag_interp_const_tl(q,q_TL,x,x_TL,n)
56 !============================================================================
57 IMPLICIT NONE
58 
59 INTEGER ,INTENT(in ) :: n !number of points involved
60 REAL(kind_real),DIMENSION(n),INTENT( out) :: q,q_tl
61 REAL(kind_real),DIMENSION(n),INTENT(in ) :: x,x_tl
62 !-----------------------------------------------------------------------------
63 INTEGER :: i,j
64 REAL(kind_real) :: rat
65 !=============================================================================
66 DO i=1,n
67  q(i)=one
68  q_tl(i)=zero
69  DO j=1,n
70  IF(j /= i) THEN
71  rat=one/(x(i)-x(j))
72  q_tl(i)=(q_tl(i)-q(i)*(x_tl(i)-x_tl(j))*rat)*rat
73  q(i)=q(i)*rat
74  ENDIF
75  ENDDO
76 ENDDO
77 end subroutine lag_interp_const_tl
78 
79 
80 !============================================================================
81 subroutine lag_interp_const_ad(q_AD,x,x_AD,n)
82 !============================================================================
83 IMPLICIT NONE
84 
85 INTEGER ,INTENT(in ) :: n
86 REAL(kind_real),DIMENSION(n),INTENT(in ) :: x
87 REAL(kind_real),DIMENSION(n),INTENT(inout) :: x_ad
88 REAL(kind_real),DIMENSION(n),INTENT(inout) :: q_ad
89 !-----------------------------------------------------------------------------
90 INTEGER :: i,j
91 REAL(kind_real),DIMENSION(n) :: q
92 REAL(kind_real),DIMENSION(n,n) :: jac
93 !=============================================================================
94 call lag_interp_const(q,x,n)
95 jac=zero
96 DO i=1,n
97  DO j=1,n
98  IF(j /= i) THEN
99  jac(j,i)=q(i)/(x(i)-x(j))
100  jac(i,i)=jac(i,i)-jac(j,i)
101  ENDIF
102  ENDDO
103 ENDDO
104 x_ad=x_ad+matmul(jac,q_ad)
105 end subroutine lag_interp_const_ad
106 
107 !============================================================================
108 subroutine lag_interp_weights(x,xt,q,w,dw,n)
109 ! Construct the Lagrange weights and their derivatives when
110 ! target abscissa is known and denominators Q have already
111 ! been precomputed
112 !
113 ! input argument list:
114 ! X - Grid abscissae
115 ! XT - Target abscissa
116 ! Q - Q factors (denominators of the Lagrange weight formula)
117 ! N - Number of grid points involved in the interpolation
118 !
119 ! output argument list:
120 ! W - Lagrange weights
121 ! DW - Derivatives, dW/dX, of Lagrange weights W
122 !============================================================================
123 IMPLICIT NONE
124 
125 INTEGER ,INTENT(IN ) :: n
126 REAL(kind_real) ,INTENT(IN ) :: xt
127 REAL(kind_real),INTENT(IN ) :: x(n),q(n)
128 REAL(kind_real),INTENT( OUT) :: w(n),dw(n)
129 !-----------------------------------------------------------------------------
130 REAL(kind_real) :: d(n),pa(n),pb(n),dpa(n),dpb(n)
131 INTEGER :: j
132 !============================================================================
133 pa(1)=one
134 dpa(1)=zero
135 do j=1,n-1
136  d(j)=xt-x(j)
137  pa(j+1)=pa(j)*d(j)
138  dpa(j+1)=dpa(j)*d(j)+pa(j)
139 enddo
140 d(n)=xt-x(n)
141 
142 pb(n)=one
143 dpb(n)=zero
144 do j=n,2,-1
145  pb(j-1)=pb(j)*d(j)
146  dpb(j-1)=dpb(j)*d(j)+pb(j)
147 enddo
148 do j=1,n
149  w(j)= pa(j)*pb(j)*q(j)
150  dw(j)=(pa(j)*dpb(j)+dpa(j)*pb(j))*q(j)
151 enddo
152 end subroutine lag_interp_weights
153 
154 
155 !============================================================================
156 subroutine lag_interp_weights_tl(x,x_TL,xt,q,q_TL,w,w_TL,dw,dw_TL,n)
157 !============================================================================
158 IMPLICIT NONE
159 
160 INTEGER ,INTENT(IN ) :: n
161 REAL(kind_real) ,INTENT(IN ) :: xt
162 REAL(kind_real),DIMENSION(n),INTENT(IN ) :: x,q,x_tl,q_tl
163 REAL(kind_real),DIMENSION(n),INTENT( OUT) :: w,dw,w_tl,dw_tl
164 !-----------------------------------------------------------------------------
165 REAL(kind_real),DIMENSION(n) :: d,pa,pb,dpa,dpb
166 REAL(kind_real),DIMENSION(n) :: d_tl,pa_tl,pb_tl,dpa_tl,dpb_tl
167 INTEGER :: j
168 !============================================================================
169 pa(1)=one
170 dpa(1)=zero
171 pa_tl(1)=zero
172 dpa_tl(1)=zero
173 
174 do j=1,n-1
175  d(j)=xt-x(j)
176  d_tl(j)=-x_tl(j)
177  pa(j+1)=pa(j)*d(j)
178  pa_tl(j+1)=pa_tl(j)*d(j)+pa(j)*d_tl(j)
179  dpa(j+1)=dpa(j)*d(j)+pa(j)
180  dpa_tl(j+1)=dpa_tl(j)*d(j)+dpa(j)*d_tl(j)+pa_tl(j)
181 enddo
182 d(n)=xt-x(n)
183 d_tl(n)=-x_tl(n)
184 
185 pb(n)=one
186 dpb(n)=zero
187 pb_tl(n)=zero
188 dpb_tl(n)=zero
189 do j=n,2,-1
190  pb(j-1)=pb(j)*d(j)
191  pb_tl(j-1)=pb_tl(j)*d(j)+pb(j)*d_tl(j)
192  dpb(j-1)=dpb(j)*d(j)+pb(j)
193  dpb_tl(j-1)=dpb_tl(j)*d(j)+dpb(j)*d_tl(j)+pb_tl(j)
194 enddo
195 do j=1,n
196  w(j)= pa(j)*pb(j)*q(j)
197  dw(j)=(pa(j)*dpb(j)+dpa(j)*pb(j))*q(j)
198  w_tl(j)=(pa_tl(j)*pb(j)+pa(j)*pb_tl(j))*q(j)+pa(j)*pb(j)*q_tl(j)
199  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)+ &
200  (pa(j)*dpb(j)+dpa(j)*pb(j))*q_tl(j)
201 enddo
202 end subroutine lag_interp_weights_tl
203 
204 
205 !============================================================================
206 subroutine lag_interp_weights_ad(x,x_AD,xt,q,q_AD,w_AD,dw_AD,n)
208 !============================================================================
209 IMPLICIT NONE
210 
211 INTEGER ,INTENT(IN ) :: n
212 REAL(kind_real) ,INTENT(IN ) :: xt
213 REAL(kind_real),DIMENSION(n),INTENT(IN ) :: x,q
214 REAL(kind_real),DIMENSION(n),INTENT(INOUT) :: q_ad,x_ad,w_ad,dw_ad
215 !-----------------------------------------------------------------------------
216 REAL(kind_real),DIMENSION(n) :: d,pa,pb,dpa,dpb
217 REAL(kind_real),DIMENSION(n) :: d_ad,pa_ad,pb_ad,dpa_ad,dpb_ad
218 INTEGER :: j
219 !============================================================================
220 
221 pa_ad=zero; dpb_ad=zero; dpa_ad=zero; pb_ad=zero
222 d_ad=zero
223 
224 ! passive variables
225 pa(1)=one
226 dpa(1)=zero
227 do j=1,n-1
228  d(j)=xt-x(j)
229  pa(j+1)=pa(j)*d(j)
230  dpa(j+1)=dpa(j)*d(j)+pa(j)
231 enddo
232 d(n)=xt-x(n)
233 pb(n)=one
234 dpb(n)=zero
235 do j=n,2,-1
236  pb(j-1)=pb(j)*d(j)
237  dpb(j-1)=dpb(j)*d(j)+pb(j)
238 enddo
239 !
240 do j=n,1,-1
241  pa_ad(j)=pa_ad(j)+ dpb(j)*q(j)*dw_ad(j)
242  dpb_ad(j)=dpb_ad(j)+ pa(j)*q(j)*dw_ad(j)
243  dpa_ad(j)=dpa_ad(j)+ pb(j)*q(j)*dw_ad(j)
244  pb_ad(j)=pb_ad(j)+ dpa(j)*q(j)*dw_ad(j)
245  q_ad(j)=q_ad(j)+(pa(j)*dpb(j)+dpa(j)*pb(j))*dw_ad(j)
246  pa_ad(j)=pa_ad(j)+ pb(j)*q(j)*w_ad(j)
247  pb_ad(j)=pb_ad(j)+ pa(j)*q(j)*w_ad(j)
248  q_ad(j)=q_ad(j)+ pa(j)*pb(j)*w_ad(j)
249 end do
250 do j=2,n
251  dpb_ad(j)=dpb_ad(j)+d(j)*dpb_ad(j-1)
252  d_ad(j)=d_ad(j)+dpb(j)*dpb_ad(j-1)
253  pb_ad(j)=pb_ad(j) +dpb_ad(j-1)
254  pb_ad(j)=pb_ad(j)+d(j)*pb_ad(j-1)
255  d_ad(j)=d_ad(j)+pb(j)*pb_ad(j-1)
256 enddo
257 
258 dpb_ad(n)=zero ! not sure about it
259 pb_ad(n) =zero ! not sure about it
260 
261 x_ad(n)=x_ad(n)-d_ad(n)
262 do j=n-1,1,-1
263  dpa_ad(j)=dpa_ad(j)+d(j)*dpa_ad(j+1)
264  d_ad(j)=d_ad(j)+dpa(j)*dpa_ad(j+1)
265  pa_ad(j)=pa_ad(j) +dpa_ad(j+1)
266  pa_ad(j)=pa_ad(j)+d(j)*pa_ad(j+1)
267  d_ad(j)=d_ad(j)+pa(j)*pa_ad(j+1)
268  x_ad(j)=x_ad(j) -d_ad(j )
269 enddo
270 
271 end subroutine lag_interp_weights_ad
272 
273 
274 !============================================================================
275 subroutine lag_interp_smthweights(x,xt,aq,bq,w,dw,n)
276 ! Construct weights and their derivatives for interpolation
277 ! to a given target based on a linearly weighted mixture of
278 ! the pair of Lagrange interpolators which omit the respective
279 ! end points of the source nodes provided. The number of source
280 ! points provided must be even and the nominal target interval
281 ! is the unique central one. The linear weighting pair is
282 ! determined by the relative location of the target within
283 ! this central interval, or else the extreme values, 0 and 1,
284 ! when target lies outside this interval. The objective is to
285 ! provide an interpolator whose derivative is continuous.
286 !============================================================================
287 IMPLICIT NONE
288 
289 INTEGER ,INTENT(IN ) :: n
290 REAL(kind_real) ,INTENT(IN ) :: xt
291 REAL(kind_real),INTENT(IN ) :: x(n)
292 REAL(kind_real),INTENT(IN ) :: aq(n-1),bq(n-1)
293 REAL(kind_real),INTENT( OUT) :: w(n),dw(n)
294 !-----------------------------------------------------------------------------
295 REAL(kind_real) :: aw(n),bw(n),daw(n),dbw(n)
296 REAL(kind_real) :: xa,xb,dwb,wb
297 INTEGER :: na
298 !============================================================================
299 CALL lag_interp_weights(x(1:n-1),xt,aq,aw(1:n-1),daw(1:n-1),n-1)
300 CALL lag_interp_weights(x(2:n ),xt,bq,bw(2:n ),dbw(2:n ),n-1)
301 aw(n)=zero
302 daw(n)=zero
303 bw(1)=zero
304 dbw(1)=zero
305 na=n/2
306 IF(na*2 /= n)stop 'In lag_interp_smthWeights; n must be even'
307 xa =x(na )
308 xb =x(na+1)
309 dwb=one/(xb-xa)
310 wb =(xt-xa)*dwb
311 IF (wb>one )THEN
312  wb =one
313  dwb=zero
314 ELSEIF(wb<zero)THEN
315  wb =zero
316  dwb=zero
317 ENDIF
318 bw =bw -aw
319 dbw=dbw-daw
320 
321 w =aw +wb*bw
322 dw=daw+wb*dbw+dwb*bw
323 end subroutine lag_interp_smthweights
324 
325 
326 !============================================================================
327 subroutine lag_interp_smthweights_tl(x,x_TL,xt,aq,aq_TL,bq,bq_TL,dw,dw_TL,n)
328 !============================================================================
329 IMPLICIT NONE
330 
331 INTEGER ,INTENT(IN ) :: n
332 REAL(kind_real) ,INTENT(IN ) :: xt
333 REAL(kind_real),DIMENSION(n) ,INTENT(IN ) :: x,x_tl
334 REAL(kind_real),DIMENSION(n-1),INTENT(IN ) :: aq,bq,aq_tl,bq_tl
335 REAL(kind_real),DIMENSION(n) ,INTENT( OUT) :: dw_tl,dw
336 !-----------------------------------------------------------------------------
337 REAL(kind_real),DIMENSION(n) :: aw,bw,daw,dbw
338 REAL(kind_real),DIMENSION(n) :: aw_tl,bw_tl,daw_tl,dbw_tl
339 REAL(kind_real) :: xa,xb,dwb,wb
340 REAL(kind_real) :: xa_tl,xb_tl,dwb_tl,wb_tl
341 INTEGER :: na
342 !============================================================================
343 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),&
344  daw(1:n-1),daw_tl(1:n-1),n-1)
345 CALL lag_interp_weights_tl(x(2:n ),x_tl(2:n ),xt,bq,bq_tl,bw(2:n ),bw_tl(2:n ),&
346  dbw(2:n ),dbw_tl(2:n ),n-1)
347 aw(n) =zero
348 daw(n)=zero
349 bw(1) =zero
350 dbw(1)=zero
351 !
352 aw_tl(n) =zero
353 daw_tl(n)=zero
354 bw_tl(1) =zero
355 dbw_tl(1)=zero
356 na=n/2
357 IF(na*2 /= n)stop 'In lag_interp_smthWeights; n must be even'
358 xa =x(na)
359 xa_tl=x_tl(na)
360 xb =x(na+1)
361 xb_tl=x_tl(na+1)
362 dwb = one /(xb-xa)
363 dwb_tl=-(xb_tl-xa_tl)/(xb-xa)**2
364 wb = (xt-xa)*dwb
365 wb_tl=(-xa_tl)*dwb+(xt-xa)*dwb_tl
366 IF (wb > one)THEN
367  wb =one
368  dwb =zero
369  wb_tl =zero
370  dwb_tl=zero
371 ELSEIF(wb < zero)THEN
372  wb =zero
373  dwb =zero
374  wb_tl =zero
375  dwb_tl=zero
376 
377 ENDIF
378 
379 bw =bw -aw
380 bw_tl =bw_tl -aw_tl
381 dbw =dbw -daw
382 dbw_tl=dbw_tl-daw_tl
383 
384 !w=aw+wb*bw
385 dw =daw + wb *dbw + dwb *bw
386 dw_tl=daw_tl+(wb_tl*dbw+wb*dbw_tl)+(dwb_tl*bw+dwb*bw_tl)
387 end subroutine lag_interp_smthweights_tl
388 
389 
390 !============================================================================
391 SUBROUTINE lag_interp_smthweights_ad(x,x_AD,xt,aq,aq_AD,bq,bq_AD,w_AD,dw,dw_AD,n)
392 !============================================================================
393 INTEGER ,INTENT(IN ) :: n
394 REAL(kind_real) ,INTENT(IN ) :: xt
395 REAL(kind_real) ,INTENT(IN ) :: x(n)
396 REAL(kind_real), INTENT(IN ) :: aq(n-1),bq(n-1)
397 REAL(kind_real),INTENT(INOUT) :: aq_ad(n-1),bq_ad(n-1)
398 REAL(kind_real),INTENT( OUT) :: dw(n)
399 REAL(kind_real),INTENT(INOUT) :: x_ad(n),dw_ad(n),w_ad(n)
400 !-----------------------------------------------------------------------------
401 REAL(kind_real) :: aw(n),bw(n),daw(n),dbw(n)
402 REAL(kind_real) :: aw_ad(n),bw_ad(n),daw_ad(n),dbw_ad(n)
403 REAL(kind_real) :: xa,xb,dwb,wb
404 REAL(kind_real) :: xa_ad,xb_ad,wb_ad,dwb_ad
405 INTEGER :: na
406 !============================================================================
407 daw_ad=zero;wb_ad=zero;dbw_ad=zero;dwb_ad=zero;bw_ad=zero
408 aw_ad =zero;xb_ad=zero;xa_ad =zero
409 
410 ! passive variables needed (from forward code)
411 CALL lag_interp_weights(x(1:n-1),xt,aq,aw(1:n-1),daw(1:n-1),n-1)
412 CALL lag_interp_weights(x(2:n ),xt,bq,bw(2:n ),dbw(2:n ),n-1)
413 
414 aw(n) =zero
415 daw(n)=zero
416 bw(1) =zero
417 dbw(1)=zero
418 na=n/2
419 IF(na*2 /= n)stop 'In lag_interp_smthWeights; n must be even'
420 xa =x(na )
421 xb =x(na+1)
422 dwb=one/(xb-xa)
423 wb =(xt-xa)*dwb
424 IF (wb>one)THEN
425  wb =one
426  dwb=zero
427 ELSEIF(wb<zero)THEN
428  wb =zero
429  dwb=zero
430 ENDIF
431 bw =bw -aw
432 dbw=dbw-daw
433 !w=aw+wb*bw ! not needed
434 dw=daw+wb*dbw+dwb*bw ! not needed
435 !
436 !
437 daw_ad=daw_ad+dw_ad
438 wb_ad =wb_ad +dot_product(dbw,dw_ad)
439 dbw_ad=dbw_ad+wb*dw_ad
440 dwb_ad=dwb_ad+dot_product(bw,dw_ad)
441 bw_ad =bw_ad +dwb*dw_ad
442 
443 aw_ad=aw_ad+w_ad
444 wb_ad=wb_ad+dot_product(bw,w_ad)
445 bw_ad=bw_ad+wb*w_ad
446 
447 daw_ad=daw_ad-dbw_ad
448 aw_ad =aw_ad -bw_ad
449 
450 IF(wb>one)THEN
451  wb_ad =zero
452  dwb_ad=zero
453 ELSEIF(wb<zero)THEN
454  wb_ad =zero
455  dwb_ad=zero
456 ENDIF
457 
458 xa_ad =xa_ad-wb_ad*dwb
459 dwb_ad =dwb_ad+(xt-xa)*wb_ad
460 xb_ad =xb_ad-(dwb_ad/(xb-xa)**2)
461 xa_ad =xa_ad+(dwb_ad/(xb-xa)**2)
462 x_ad(na+1)=x_ad(na+1)+xb_ad
463 x_ad(na )=x_ad(na )+xa_ad
464 
465 dbw_ad(1)=zero;bw_ad(1)=zero
466 daw_ad(n)=zero;aw_ad(n)=zero
467 
468 CALL lag_interp_weights_ad(x(2:n ),x_ad(2:n ),xt,bq,bq_ad,bw_ad(2:n ),&
469  dbw_ad(2:n ),n-1)
470 
471 CALL lag_interp_weights_ad(x(1:n-1),x_ad(1:n-1),xt,aq,aq_ad,aw_ad(1:n-1),&
472  daw_ad(1:n-1),n-1)
473 
474 end subroutine lag_interp_smthweights_ad
475 !============================================================================
476 end module lag_interp_mod
477 
subroutine, public lag_interp_weights_ad(x, x_AD, xt, q, q_AD, w_AD, dw_AD, n)
Definition: lag_interp.F90:207
real(fp), parameter, public zero
subroutine, public lag_interp_smthweights(x, xt, aq, bq, w, dw, n)
Definition: lag_interp.F90:276
subroutine, public lag_interp_const_tl(q, q_TL, x, x_TL, n)
Definition: lag_interp.F90:56
Fortran module to prepare for Lagrange polynomial interpolation. based on GSI: lagmod.f90.
Definition: lag_interp.F90:4
real(fp), parameter, public one
subroutine, public lag_interp_weights_tl(x, x_TL, xt, q, q_TL, w, w_TL, dw, dw_TL, n)
Definition: lag_interp.F90:157
subroutine, public lag_interp_smthweights_ad(x, x_AD, xt, aq, aq_AD, bq, bq_AD, w_AD, dw, dw_AD, n)
Definition: lag_interp.F90:392
subroutine, public lag_interp_const(q, x, n)
Definition: lag_interp.F90:28
subroutine, public lag_interp_const_ad(q_AD, x, x_AD, n)
Definition: lag_interp.F90:82
integer, parameter, public kind_real
subroutine, public lag_interp_weights(x, xt, q, w, dw, n)
Definition: lag_interp.F90:109
subroutine, public lag_interp_smthweights_tl(x, x_TL, xt, aq, aq_TL, bq, bq_TL, dw, dw_TL, n)
Definition: lag_interp.F90:328