Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_lagrange_interpolation.F90
Go to the documentation of this file.
1 !**************************************************************
2 ! Copyright INRIA
3 ! Authors :
4 ! CALVI project team
5 !
6 ! This code SeLaLib (for Semi-Lagrangian-Library)
7 ! is a parallel library for simulating the plasma turbulence
8 ! in a tokamak.
9 !
10 ! This software is governed by the CeCILL-B license
11 ! under French law and abiding by the rules of distribution
12 ! of free software. You can use, modify and redistribute
13 ! the software under the terms of the CeCILL-B license as
14 ! circulated by CEA, CNRS and INRIA at the following URL
15 ! "http://www.cecill.info".
16 !**************************************************************
17 
19 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20 #include "sll_assert.h"
21 #include "sll_working_precision.h"
22 
24  sll_p_dirichlet, &
25  sll_p_periodic
26 
27  implicit none
28 
29  public :: &
34 
35  private
36 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
37 
38  integer, parameter :: sll_size_stencil_max = 30
39  integer, parameter :: sll_size_stencil_min = -30
40 
42  module procedure weight_product1d, &
44  end interface
45 
47  module procedure weight_product2d_x1
48  end interface
49 
50 contains
51 
52  ! sll_f_lagrange_interpolate returns the value of y(x), using a Lagrange
53  ! interpolation based on the given array values of x(i) and y(x(i)).
54  ! The interpolating polynomial is of degree 'degree'.
55  function sll_f_lagrange_interpolate(x, degree, xi, yi)
56  sll_real64, intent(in) :: x
57  sll_int32, intent(in) :: degree
58  sll_real64, intent(in), dimension(:) :: xi
59  sll_real64, intent(in), dimension(:) :: yi
60  sll_real64 :: sll_f_lagrange_interpolate
61  sll_real64, dimension(1:degree + 1) :: p
62  sll_int32 :: i
63  sll_int32 :: deg
64  sll_int32 :: m ! step size
65 
66  sll_assert(size(xi) >= degree + 1)
67  sll_assert(size(yi) >= degree + 1)
68  sll_assert(degree >= 0)
69 
70  if ((x < xi(1)) .or. (x > xi(degree + 1))) then
71  !print *, 'sll_f_lagrange_interpolate() warning: x is outside of the range ', &
72  ! 'xi given as argument.'
73  !print *, 'x = ', x, 'xmin = ', xi(1), 'xmax = ',xi(degree+1)
74  end if
75 
76  ! Load the local array with the values of y(i), which are also the values
77  ! of the Lagrange polynomials of order 0.
78  do i = 1, degree + 1
79  p(i) = yi(i)
80  end do
81 
82  ! Build the Lagrange polynomials up to the desired degree. Here we use
83  ! Neville's recursive relation, starting from the zeroth-order
84  ! polynomials and working towards the desired degree.
85  m = 1
86  do deg = degree, 1, -1
87  do i = 1, deg
88  p(i) = (1.0_f64/(xi(i) - xi(i + m)))*((x - xi(i + m))*p(i) + (xi(i) - x)*p(i + 1))
89  end do
90  m = m + 1
91  end do
93  end function sll_f_lagrange_interpolate
94 
95  ! compute weights w for the derivatives
96  ! f'_j = sum_{k=r}^{s} w_kf_{j+k}
97  ! such that the formula is exact for f polynomial of degree <= d
98  ! where d is the biggest possible
99  ! we call it sometimes compact finite difference formula
100  ! we suppose that r<=0 and s>=0
102  integer, intent(in)::r, s
103  sll_real64, intent(out)::w(r:s)
104  sll_int32 ::i, j
105  sll_real64::tmp
106 
107  w = 0._f64
108 
109  !maple code for generation of w
110  !for k from r to -1 do
111  ! C[k]:=product((k-j),j=r..k-1)*product((k-j),j=k+1..s):
112  ! C[k]:=1/C[k]*product((-j),j=r..k-1)*product((-j),j=k+1..-1)*product((-j),j=1..s):
113  !od:
114  !for k from 1 to s do
115  ! C[k]:=product((k-j),j=r..k-1)*product((k-j),j=k+1..s):
116  ! C[k]:=1/C[k]*product((-j),j=r..-1)*product((-j),j=1..k-1)*product((-j),j=k+1..s):
117  !od:
118  !C[0]:=-add(C[k],k=r..-1)-add(C[k],k=1..s):
119 
120  do i = r, -1
121  tmp = 1._f64
122  do j = r, i - 1
123  tmp = tmp*real(i - j, f64)
124  end do
125  do j = i + 1, s
126  tmp = tmp*real(i - j, f64)
127  end do
128  tmp = 1._f64/tmp
129  do j = r, i - 1
130  tmp = tmp*real(-j, f64)
131  end do
132  do j = i + 1, -1
133  tmp = tmp*real(-j, f64)
134  end do
135  do j = 1, s
136  tmp = tmp*real(-j, f64)
137  end do
138  w(i) = tmp
139  end do
140 
141  do i = 1, s
142  tmp = 1._f64
143  do j = r, i - 1
144  tmp = tmp*real(i - j, f64)
145  end do
146  do j = i + 1, s
147  tmp = tmp*real(i - j, f64)
148  end do
149  tmp = 1._f64/tmp
150  do j = r, -1
151  tmp = tmp*real(-j, f64)
152  end do
153  do j = 1, i - 1
154  tmp = tmp*real(-j, f64)
155  end do
156  do j = i + 1, s
157  tmp = tmp*real(-j, f64)
158  end do
159  w(i) = tmp
160  end do
161  tmp = 0._f64
162  do i = r, -1
163  tmp = tmp + w(i)
164  end do
165  do i = 1, s
166  tmp = tmp + w(i)
167  end do
168  w(0) = -tmp
169 
170  end subroutine sll_s_compact_derivative_weight
171 
172  subroutine sll_s_compute_stencil_plus(p, r, s)
173  sll_int32, intent(in) :: p
174  sll_int32, intent(out) :: r, s
175  r = -p/2
176  s = (p + 1)/2
177  end subroutine sll_s_compute_stencil_plus
178 
179  subroutine compute_stencil_minus(p, r, s)
180  sll_int32, intent(in) :: p
181  sll_int32, intent(out) :: r, s
182  r = -(p + 1)/2
183  s = p/2
184  end subroutine compute_stencil_minus
185 
186  ! Makes the following operation
187  ! fout(j) = sum_{k=r}^s w(k)fin(j+k),j=1..N+1
188  ! we suppose periodic boundary conditions fin(j+N)=fin(j)
189  ! and that fin(j) ar known j=1,..,N
190  subroutine weight_product1d_per(fin, fout, N, w, r, s)
191  sll_real64, dimension(:), intent(in) :: fin
192  sll_real64, dimension(:), intent(out) :: fout
193  sll_int32, intent(in) :: n
194  sll_int32, intent(in) :: r
195  sll_int32, intent(in) :: s
196  sll_real64, intent(in) :: w(r:s)
197  sll_int32 :: i
198  sll_int32 :: i1
199  sll_int32 :: j
200  sll_real64 :: tmp
201 
202  do i = 1, n
203  tmp = 0._f64
204  do j = r, s
205  i1 = i + j
206  if ((i1 > n) .or. (i1 < 1)) then
207  i1 = modulo(i1 - 1, n) + 1
208  end if
209  tmp = tmp + w(j)*fin(i1)
210  end do
211  fout(i) = tmp
212  end do
213  fout(n + 1) = fout(1)
214  end subroutine weight_product1d_per
215 
216  ! Makes the following operation
217  ! fout(j) = sum_{k=r}^s w(k)fin(j+k),j=1..N+1
218  ! we suppose natural boundary conditions fin(j)=fin(1), j<=1
219  ! and fin(j)=fin(N+1) for j>=N+1
220  ! and that fin(j) ar known j=1,..,N+1
221  subroutine weight_product1d_nat(fin, fout, N, w, r, s)
222  sll_real64, dimension(:), intent(in) :: fin
223  sll_real64, dimension(:), intent(out) :: fout
224  sll_int32, intent(in) :: n
225  sll_int32, intent(in) :: r
226  sll_int32, intent(in) :: s
227  sll_real64, intent(in) :: w(r:s)
228  sll_int32 :: i
229  sll_int32 :: i1
230  sll_int32 :: j
231  sll_real64 :: tmp
232 
233  do i = 1, n + 1
234  tmp = 0._f64
235  do j = r, s
236  i1 = i + j
237  if (i1 >= n + 1) then
238  i1 = n + 1
239  end if
240  if (i1 <= 1) then
241  i1 = 1
242  end if
243  tmp = tmp + w(j)*fin(i1)
244  end do
245  fout(i) = tmp
246  end do
247 
248  end subroutine weight_product1d_nat
249 
250  subroutine weight_product1d(fin, fout, N, w, r, s, bc_type)
251  sll_real64, dimension(:), intent(in) :: fin
252  sll_real64, dimension(:), intent(out) :: fout
253  sll_int32, intent(in) :: n
254  sll_int32, intent(in) :: r
255  sll_int32, intent(in) :: s
256  sll_real64, intent(in) :: w(r:s)
257  sll_int32, intent(in) :: bc_type
258 
259  select case (bc_type)
260  case (sll_p_periodic)
261  call weight_product1d_per(fin, fout, n, w(r:s), r, s)
262  case (sll_p_dirichlet)
263  call weight_product1d_nat(fin, fout, n, w(r:s), r, s)
264  case default
265  print *, '#bad type in weight_product1d'
266  stop
267  end select
268  end subroutine weight_product1d
269 
270 !the two following functions may be not useful
271 
272  subroutine weight_product2d_x1(fin, fout, N, w, r, s, bc_type)
273  sll_real64, dimension(:, :), intent(in) :: fin
274  sll_real64, dimension(:, :), intent(out) :: fout
275  sll_int32, intent(in) :: n(2)
276  sll_int32, intent(in) :: r
277  sll_int32, intent(in) :: s
278  sll_real64, intent(in) :: w(r:s)
279  sll_int32, intent(in) :: bc_type
280  sll_int32 :: i
281  do i = 1, n(2) + 1
282  call weight_product1d(fin(:, i), fout(:, i), n(1), w(r:s), r, s, bc_type)
283  end do
284 
285  end subroutine weight_product2d_x1
286 
287  subroutine weight_product2d_x2(fin, fout, N, w, r, s, bc_type)
288  sll_real64, dimension(:, :), intent(in) :: fin
289  sll_real64, dimension(:, :), intent(out) :: fout
290  sll_int32, intent(in) :: n(2)
291  sll_int32, intent(in) :: r
292  sll_int32, intent(in) :: s
293  sll_real64, intent(in) :: w(r:s)
294  sll_int32, intent(in) :: bc_type
295  sll_int32 :: i
296  sll_real64, dimension(:), allocatable :: bufin
297  sll_real64, dimension(:), allocatable :: bufout
298  allocate (bufin(n(2) + 1))
299  allocate (bufout(n(2) + 1))
300 
301  do i = 1, n(1) + 1
302  bufin(1:n(2) + 1) = fin(i, 1:n(2) + 1)
303  call weight_product1d(bufin, bufout, n(2), w(r:s), r, s, bc_type)
304  fout(i, 1:n(2) + 1) = bufout(1:n(2) + 1)
305  end do
306 
307  deallocate (bufin)
308  deallocate (bufout)
309 
310  end subroutine weight_product2d_x2
311 
312  subroutine compute_size_hermite1d(N, p, N_size, dim_size)
313  sll_int32, intent(in) :: n
314  sll_int32, intent(in) :: p
315  sll_int32, intent(out) :: n_size
316  sll_int32, intent(out) :: dim_size
317 
318  n_size = n + 1
319 
320  if (modulo(p, 2) == 0) then
321  dim_size = 2
322  else
323  dim_size = 3
324  end if
325 
326  end subroutine compute_size_hermite1d
327 
329  sll_real64, dimension(:, :), pointer :: initialize_interpolants_hermite1d
330  sll_int32, intent(in) :: n
331  sll_int32, intent(in) :: p
332  sll_int32 :: n_size
333  sll_int32 :: dim_size
334 
335  call compute_size_hermite1d(n, p, n_size, dim_size)
336  allocate (initialize_interpolants_hermite1d(dim_size, n_size))
337 
339 
341  sll_real64, dimension(:, :, :, :), pointer :: initialize_interpolants_hermite2d
342  sll_int32, intent(in) :: n(2)
343  sll_int32, intent(in) :: p(2)
344  sll_int32 :: dim_size(2), n_size(2)
345  sll_int32 :: i
346  do i = 1, 2
347  call compute_size_hermite1d(n(i), p(i), n_size(i), dim_size(i))
348  end do
349 
350  allocate (initialize_interpolants_hermite2d(dim_size(1), &
351  dim_size(2), &
352  n_size(1), &
353  n_size(2)))
354 
356 
357  subroutine compute_interpolants_hermite1d(fin, coef, N, p, bc_type)
358  sll_real64, dimension(:), intent(in) :: fin
359  sll_real64, dimension(:, :), pointer :: coef
360  sll_int32, intent(in) :: n
361  sll_int32, intent(in) :: p
362  sll_int32, intent(in) :: bc_type
364  sll_int32 :: r, s
365 
366  coef(1, 1:n + 1) = fin(1:n + 1)
367  call sll_s_compute_stencil_plus(p, r, s)
368  call sll_s_compact_derivative_weight(w(r:s), r, s)
369  call sll_o_weight_product_x1(fin, coef(2, :), n, w(r:s), r, s, bc_type)
370  if (modulo(p, 2) == 1) then
371  call compute_stencil_minus(p, r, s)
372  call sll_s_compact_derivative_weight(w(r:s), r, s)
373  call sll_o_weight_product_x1(fin, coef(3, :), n, w(r:s), r, s, bc_type)
374  end if
375 
376  end subroutine compute_interpolants_hermite1d
377 
378  subroutine compute_interpolants_hermite2d(fin, coef, N, p, bc_type)
379  sll_real64, dimension(:, :), intent(in) :: fin
380  sll_real64, dimension(:, :, :, :), pointer :: coef
381  sll_int32, intent(in) :: n(2)
382  sll_int32, intent(in) :: p(2)
383  sll_int32, intent(in) :: bc_type(2)
384  !sll_real64 :: w(SLL_SIZE_STENCIL_MIN:SLL_SIZE_STENCIL_MIN)
385  !sll_int32 :: r,s
386  sll_int32 :: i, j, k
387  sll_real64, dimension(:), pointer :: bufin_x1, bufin_x2
388  sll_real64, dimension(:, :), pointer :: bufout_x1, bufout_x2
389  !sll_int32 :: dim(2)
390  sll_int32 :: n_size(2)
391  sll_int32 :: dim_size(2)
392 
393  do i = 1, 2
394  call compute_size_hermite1d(n(i), p(i), n_size(i), dim_size(i))
395  end do
396 
397  allocate (bufin_x1(n(1) + 1))
398  allocate (bufout_x1(dim_size(1), n_size(1)))
399  allocate (bufin_x2(n(2) + 1))
400  allocate (bufout_x2(dim_size(2), n_size(2)))
401 
402  ! compute_interpolants in x2
403  do i = 1, n(1) + 1
404  bufin_x2(1:n(2) + 1) = fin(i, 1:n(2) + 1)
405  call compute_interpolants_hermite1d(bufin_x2, bufout_x2, n(2), p(2), bc_type(2))
406  do j = 1, dim_size(2)
407  coef(1, j, i, 1:n_size(2)) = bufout_x2(j, 1:n_size(2))
408  end do
409  end do
410 
411  ! compute_interpolants in x1
412  do i = 1, n_size(2)
413  do j = 1, dim_size(2)
414  bufin_x1(1:n(1) + 1) = coef(1, j, 1:n(1) + 1, i)
415  call compute_interpolants_hermite1d(bufin_x1, bufout_x1, n(1), p(1), bc_type(1))
416  do k = 1, dim_size(1)
417  coef(k, j, 1:n_size(1), i) = bufout_x1(k, 1:n_size(1))
418  end do
419  end do
420  end do
421 
422  deallocate (bufin_x1)
423  deallocate (bufout_x1)
424  deallocate (bufin_x2)
425  deallocate (bufout_x2)
426 
427  end subroutine compute_interpolants_hermite2d
428 
429 ! subroutine interpolate_hermite1d_c1(coef,N,i,x,fval)
430 ! sll_real64, dimension(:,:), pointer :: coef
431 ! sll_int32, intent(in) :: N
432 ! sll_int32, intent(in) :: i
433 ! sll_real64, intent(in) :: x
434 ! sll_real64, intent(out) :: fval
435 ! sll_real64 :: w(0:3)
436 ! sll_int32 :: i1
437 !
438 ! w(0)=(2._f64*x+1._f64)*(1._f64-x)*(1._f64-x)
439 ! w(1)=x*x*(3._f64-2._f64*x)
440 ! w(2)=x*(1._f64-x)*(1._f64-x)
441 ! w(3)=x*x*(x-1._f64)
442 ! i1=i+1
443 !
444 ! fval=w(0)*coef(1,i)+w(1)*coef(1,i1)+w(2)*coef(2,i)+w(3)*coef(2,i1)
445 !
446 ! end subroutine interpolate_hermite1d_c1
447 
448 ! subroutine interpolate_hermite1d_c0(coef,N,i,x,fval)
449 ! sll_real64, dimension(:,:), pointer :: coef
450 ! sll_int32, intent(in) :: N
451 ! sll_int32, intent(in) :: i
452 ! sll_real64, intent(in) :: x
453 ! sll_real64, intent(out) :: fval
454 ! sll_real64 :: w(0:3)
455 ! sll_int32 :: i1
456 !
457 ! w(0)=(2._f64*x+1._f64)*(1._f64-x)*(1._f64-x);
458 ! w(1)=x*x*(3._f64-2._f64*x)
459 ! w(2)=x*(1._f64-x)*(1._f64-x)
460 ! w(3)=x*x*(x-1._f64)
461 ! i1=i+1
462 !
463 ! fval=w(0)*coef(1,i)+w(1)*coef(1,i1)+w(2)*coef(2,i)+w(3)*coef(3,i1)
464 !
465 ! end subroutine interpolate_hermite1d_c0
466 
467 ! subroutine interpolate_hermite2d_c0_c1(coef,N,i,x,fval)
468 !
469 ! sll_real64, dimension(:,:,:,:), pointer :: coef
470 ! sll_int32, intent(in) :: N(2)
471 ! sll_int32, intent(in) :: i(2)
472 ! sll_real64, intent(in) :: x(2)
473 ! sll_real64, intent(out) :: fval
474 !
475 ! fval = 0
476 !
477 !
478 ! end subroutine interpolate_hermite2d_c0_c1
479 
subroutine, public sll_s_compact_derivative_weight(w, r, s)
subroutine compute_interpolants_hermite1d(fin, coef, N, p, bc_type)
subroutine weight_product1d_nat(fin, fout, N, w, r, s)
real(kind=f64) function, public sll_f_lagrange_interpolate(x, degree, xi, yi)
subroutine weight_product1d(fin, fout, N, w, r, s, bc_type)
subroutine weight_product2d_x2(fin, fout, N, w, r, s, bc_type)
real(kind=f64) function, dimension(:, :), pointer initialize_interpolants_hermite1d(N, p)
subroutine compute_size_hermite1d(N, p, N_size, dim_size)
real(kind=f64) function, dimension(:, :, :, :), pointer initialize_interpolants_hermite2d(N, p)
subroutine weight_product2d_x1(fin, fout, N, w, r, s, bc_type)
subroutine, public sll_s_compute_stencil_plus(p, r, s)
subroutine compute_interpolants_hermite2d(fin, coef, N, p, bc_type)
subroutine weight_product1d_per(fin, fout, N, w, r, s)
    Report Typos and Errors