Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_periodic_interp.F90
Go to the documentation of this file.
2 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 #include "sll_assert.h"
4 #include "sll_memory.h"
5 #include "sll_working_precision.h"
6 
7 ! use F77_fftpack, only: &
8 ! dfftb, &
9 ! dfftf, &
10 ! dffti, &
11 ! zfftb, &
12 ! zfftf, &
13 ! zffti
14 
15  use sll_m_low_level_bsplines, only: &
16  sll_s_uniform_bsplines_eval_basis
17 
18  use sll_m_constants, only: &
19  sll_p_pi, &
21 
22  use sll_m_fft, only: &
27  sll_t_fft
28 
29  implicit none
30 
31  public :: &
37  sll_p_spline, &
38  sll_p_trigo, &
40 
41  private
42 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
43 
44  sll_int32, parameter :: sll_p_trigo = 0, sll_p_spline = 1, sll_p_lagrange = 2, sll_p_trigo_fft_selalib = 3
45  sll_int32, parameter :: trigo_real = 4
46  sll_comp64, parameter :: ii_64 = (0.0_f64, 1.0_f64)
47 
49  sll_int32 :: n
50  sll_int32 :: interpolator
51  sll_int32 :: order
52  sll_real64, pointer :: eigenvalues_minv(:)
53  sll_comp64, pointer :: eigenvalues_s(:)
54  sll_real64, pointer :: wsave(:)
55  sll_comp64, pointer :: modes(:)
56  sll_comp64, pointer :: ufft(:)
57  sll_real64, pointer :: buf(:)
58  sll_int32 :: sizebuf
59  type(sll_t_fft) :: pinv, pfwd
61 
62 contains
63 
64  subroutine sll_s_periodic_interp_init(this, N, interpolator, order)
65  type(sll_t_periodic_interp_work), intent(inout) :: this
66  sll_int32, intent(in) :: n ! number of cells
67  sll_int32, intent(in) :: interpolator ! interpolation method
68  sll_int32, intent(in) :: order ! order of method
69 
70  sll_int32 :: ierr, i, j
71  sll_int32 :: p ! sll_p_spline degree
72  sll_int32 :: icoarse ! coarsening factor for stabilization of trigonometric interpolation
73  sll_real64 :: biatx(order)
74 
75  this%N = n
76  this%interpolator = interpolator
77  this%order = order
78 
79  ! Allocate arrays
80  sll_allocate(this%wsave(15 + 4*n), ierr)
81  sll_allocate(this%ufft(n), ierr)
82  sll_allocate(this%eigenvalues_Minv(n), ierr)
83  sll_allocate(this%eigenvalues_S(n), ierr)
84  sll_allocate(this%modes(0:n - 1), ierr)
85 
86  ! set up sll_p_spline parameters
87  if (iand(order, 1) /= 0) then
88  print *, 'sll_s_periodic_interp_init: order of interpolators needs to be even.', &
89  'Order here is: ', order
90  stop
91  end if
92  p = order - 1 ! sll_p_spline degree is one less than order
93 
94  ! Initialize fft
95  call zffti(n, this%wsave)
96 
97  select case (interpolator)
98  case (sll_p_trigo)
99  this%buf => null()
100  if (order == 0) then ! no coarsening
101  this%eigenvalues_Minv = 1.0_f64
102  else
103  icoarse = 1
104  ! to be implemented
105  this%eigenvalues_Minv = 1.0_f64
106  end if
107 
108  case (sll_p_spline)
109  this%buf => null()
110  call sll_s_uniform_bsplines_eval_basis(p, 0.0_f64, biatx)
111  do i = 1, n
112  this%modes(i - 1) = exp(ii_64*sll_p_twopi*(i - 1)/n)
113  this%eigenvalues_Minv(i) = biatx((p + 1)/2)
114  do j = 1, (p + 1)/2
115  this%eigenvalues_Minv(i) = this%eigenvalues_Minv(i) &
116  + biatx(j + (p + 1)/2)*2*cos(j*sll_p_twopi*(i - 1)/n)
117  end do
118  this%eigenvalues_Minv(i) = 1.0_f64/this%eigenvalues_Minv(i)
119  end do
120  case (sll_p_lagrange)
121  this%sizebuf = 3*n + 15
122  sll_allocate(this%buf(0:this%sizebuf - 1), ierr)
123  call dffti(n, this%buf(n:3*n + 14))
124  case (trigo_real)
125  this%sizebuf = 2*n + 15
126  sll_allocate(this%buf(1:this%sizebuf), ierr)
127  call dffti(n, this%buf)
129  this%sizebuf = n
130  sll_allocate(this%buf(this%sizebuf), ierr)
131  !SLL_ALLOCATE(buf(N),ierr)
132  call sll_s_fft_init_r2r_1d(this%pfwd, n, this%buf, this%buf, sll_p_fft_forward, normalized=.true.)
133 
134  call sll_s_fft_init_r2r_1d(this%pinv, n, this%buf, this%buf, sll_p_fft_backward)
135  sll_deallocate_array(this%buf, ierr)
136  case default
137  print *, 'sll_m_periodic_interp:interpolator ', interpolator, ' not implemented'
138  stop
139  end select
140 
141  end subroutine sll_s_periodic_interp_init
142 
143  subroutine sll_s_periodic_interp_free(this)
144  type(sll_t_periodic_interp_work), intent(inout) :: this
145 
146  sll_int32 :: ierr
147 
148  sll_deallocate(this%wsave, ierr)
149  sll_deallocate(this%ufft, ierr)
150  sll_deallocate(this%eigenvalues_Minv, ierr)
151  sll_deallocate(this%eigenvalues_S, ierr)
152  sll_deallocate(this%modes, ierr)
153  if (associated(this%buf)) then
154  sll_deallocate(this%buf, ierr)
155  end if
156 
157  end subroutine sll_s_periodic_interp_free
158 
159  subroutine sll_s_periodic_interp(this, u_out, u, alpha)
160  ! interpolate function u given at grid points on a periodic grid
161  ! at positions j-alpha (alpha is normalized to the cell size)
162  type(sll_t_periodic_interp_work), intent(inout) :: this
163  sll_real64, intent(out) :: u_out(:) ! result
164  sll_real64, intent(in) :: u(:) ! function to be interpolated
165  sll_real64, intent(in) :: alpha ! displacement normalized to cell size
166 
167  sll_int32 :: i, j, k, p, ishift
168  sll_int32 :: imode, n
169  sll_real64 :: beta
170  sll_comp64 :: filter
171  sll_comp64 :: tmp, tmp2
172  sll_real64 :: biatx(this%order)
173 
174  sll_assert(size(u_out) >= this%N)
175  sll_assert(size(u) >= this%N)
176 
177  ! Compute eigenvalues of shift matrix
178  select case (this%interpolator)
179  case (sll_p_trigo)
180  ! Perform FFT of u
181  do i = 1, this%N
182  this%ufft(i) = cmplx(u(i), kind=f64)
183  end do
184  call zfftf(this%N, this%ufft, this%wsave)
185  this%eigenvalues_S(1) = (1.0_f64, 0.0_f64)
186  this%eigenvalues_S(this%N/2 + 1) = exp(-ii_64*sll_p_pi*alpha)
187  do k = 1, this%N/2 - 1
188  !filter = 0.5_8*(1+tanh(100*(.35_8*this%N/2-k)/(this%N/2))) !F1
189  !filter = 0.5_8*(1+tanh(100*(.25_8*this%N/2-k)/(this%N/2))) !F2
190  !filter = 0.5_8*(1+tanh(50*(.25_8*this%N/2-k)/(this%N/2))) !F3
191  filter = (1.0_f64, 0.0_f64)
192 
193  this%eigenvalues_S(k + 1) = exp(-ii_64*sll_p_twopi*k*alpha/this%N)*filter
194  this%eigenvalues_S(this%N - k + 1) = exp(ii_64*sll_p_twopi*k*alpha/this%N)*filter
195  end do
196  this%ufft = this%ufft*this%eigenvalues_S
197  ! Perform inverse FFT and normalized
198  call zfftb(this%N, this%ufft, this%wsave)
199  do i = 1, this%N
200  u_out(i) = real(this%ufft(i), f64)/real(this%N, f64)
201  end do
202  case (sll_p_spline)
203  ! Perform FFT of u
204  do i = 1, this%N
205  this%ufft(i) = cmplx(u(i), kind=f64)
206  end do
207  call zfftf(this%N, this%ufft, this%wsave)
208 
209  !compute eigenvalues of splines evaluated at displaced points
210  p = this%order - 1
211  ishift = floor(-alpha)
212  beta = -ishift - alpha
213  call sll_s_uniform_bsplines_eval_basis(p, beta, biatx)
214 
215  this%eigenvalues_S = (0.0_f64, 0.0_f64)
216  do i = 1, this%N
217  do j = -(p - 1)/2, (p + 1)/2
218  imode = modulo((ishift + j)*(i - 1), this%N)
219  this%eigenvalues_S(i) = this%eigenvalues_S(i) &
220  + biatx(j + (p + 1)/2)*this%modes(imode)
221  end do
222 
223  end do
224  this%ufft = this%ufft*this%eigenvalues_S*this%eigenvalues_Minv
225  ! Perform inverse FFT and normalized
226  call zfftb(this%N, this%ufft, this%wsave)
227  do i = 1, this%N
228  u_out(i) = real(this%ufft(i), f64)/real(this%N, f64)
229  end do
230  case (sll_p_lagrange)
231  u_out = u
232  call fourier1dperlagodd(this%buf, this%sizebuf, u_out, this%N, &
233  alpha/this%N, this%order/2 - 1)
234  case (trigo_real)
235  u_out = u
236  !call fourier1dperlagodd(this%buf,this%sizebuf,u_out,this%N, &
237  ! alpha/this%N,this%order/2 - 1 )
238  !print *,this%sizebuf,this%N
239  call fourier1dper(this%buf, this%sizebuf, u_out, this%N, alpha/this%N)
240 
242  u_out = u
243  call sll_s_fft_exec_r2r_1d(this%pfwd, u_out, u_out)
244  n = this%N
245  tmp2 = -ii_64*2._f64*sll_p_pi/n*alpha
246 
247  do i = 1, n/2 - 1
248  tmp = cmplx(u_out(2*i + 1), u_out(2*i + 2), kind=f64)
249  tmp = tmp*exp(tmp2*cmplx(i, 0.0_f64, f64))
250  u_out(2*i + 1) = real(tmp, kind=f64)
251  u_out(2*i + 2) = aimag(tmp)
252  end do
253  tmp = cmplx(u_out(n/2 + 1), 0.0_f64, kind=f64)
254  tmp = tmp*exp(tmp2*cmplx(0.5_f64*n, 0.0_f64, f64))
255  u_out(n/2 + 1) = real(tmp, kind=f64)
256 
257 !*** Without macro
258  ! do i=0,this%N/2
259  ! tmp=fft_get_mode(this%pfwd,u_out,i)
260  ! !print *,i,tmp,alpha
261  ! !tmp=tmp*exp(-ii*2._f64*sll_p_pi/this%N*alpha*real(i,f64))
262  ! tmp=tmp*exp(tmp2*real(i,f64))
263  ! !print *,i,tmp,exp(-ii*2._f64*sll_p_pi/this%N*alpha*real(i,f64))
264  ! call fft_set_mode(this%pfwd,u_out,tmp,i)
265  ! !tmp=fft_get_mode(this%pfwd,u_out,i)
266  ! !print *,i,tmp
267  ! enddo
268 
269  call sll_s_fft_exec_r2r_1d(this%pinv, u_out, u_out)
270 
271  case default
272  print *, 'sll_m_periodic_interp:interpolator ', this%interpolator, ' not implemented'
273  stop
274  end select
275 
276  ! modulate eigenvalues
277  !do k=1, this%N
278  ! print*, k, this%eigenvalues_S(k), &
279  ! 0.5_8*(1+tanh(100*(.25_8*this%N-k)/this%N))!*this%eigenvalues_S(k)
280  !print*, k, this%ufft(k), u(k)
281  !end do
282 
283  !call system_clock(COUNT=clock_end) ! Stop timing
284  ! Calculate the elapsed time in seconds:
285  !elapsed_time=real(clock_end-clock_start,8)/real(clock_rate,8)
286  !print*,'time eigenvalues', elapsed_time
287 
288  end subroutine sll_s_periodic_interp
289 
290  subroutine fourier1dperlagodd(buf, sizebuf, E, N, alpha, d)
291  sll_int32, intent(in) :: n, sizebuf, d
292  sll_real64, intent(inout) :: buf(0:sizebuf - 1)
293  sll_real64, intent(inout) :: e(1:n)
294  sll_real64, intent(in) :: alpha
295 
296  sll_int32 :: i, ix
297  sll_real64 :: rea, ima, reb, imb, tmp, x, a
298 
299  !localization
300  x = alpha
301  !if(abs(x)<1.e-15_rk)then
302  ! print *,x,N
303  ! x=x-real(floor(x),rk)
304  ! print *,x
305  ! x=x*real(N,rk)
306  ! print *,x
307  ! ix=floor(x)
308  ! x=x-real(ix,rk)
309  ! print *,x,ix
310  ! x=0._rk
311  !endif
312  x = x - real(floor(x), f64)
313  !if(x==1)then
314  ! x=0._rk
315  !endif
316  x = x*real(n, f64)
317  ix = floor(x)
318  if (ix == n) then
319  x = 0._f64; ix = 0
320  end if
321  x = x - real(ix, f64)
322  do i = 0, n - 1
323  buf(i) = 0._f64
324  end do
325 
326  a = 1._8;
327  do i = 2, d
328  a = a*(x*x - real(i, f64)*real(i, f64))/(real(d, f64)*real(d, f64))
329  end do
330  a = a*(x + 1._f64)/real(d, f64)
331  a = a*(x - real(d, f64) - 1._f64)/real(d, f64)
332  buf(ix) = a*(x - 1._f64)/real(d, f64)
333  buf(mod(ix + 1, n)) = a*x/real(d, f64)
334  a = a*x*(x - 1._f64)/(real(d, f64)*real(d, f64))
335  do i = -d, -1
336  buf(mod(i + ix + n, n)) = a/((x - real(i, f64))/real(d, f64))
337  end do
338  do i = 2, d + 1
339  buf(mod(i + ix + n, n)) = a/((x - real(i, f64))/real(d, f64));
340  end do
341  a = 1._f64
342  do i = -d, d + 1 ! If Y is not present then the imaginary component is set to 0.
343  buf(mod(i + ix + n, n)) = buf(mod(i + ix + n, n))*a
344  a = a*real(d, f64)/real(d + i + 1, f64)
345  end do
346  a = 1._f64;
347  do i = d + 1, -d, -1
348  buf(mod(i + ix + n, n)) = buf(mod(i + ix + n, n))*a
349  a = a*real(d, f64)/real(i - 1 - d - 1, f64)
350  end do
351 
352  call dfftf(n, buf(0:n - 1), buf(n:3*n + 14))
353 
354  call dfftf(n, e, buf(n:3*n + 14))
355  tmp = 1._f64/real(n, f64)
356  e(1) = e(1)*tmp*buf(0)
357  do i = 1, (n - 2)/2
358  rea = e(2*i); ima = e(2*i + 1)
359  reb = tmp*buf(2*i - 1)
360  imb = tmp*buf(2*i)
361  e(2*i) = rea*reb - ima*imb
362  e(2*i + 1) = rea*imb + reb*ima
363  end do
364  if (mod(n, 2) == 0) e(n) = e(n)*tmp*buf(n - 1)
365  call dfftb(n, e, buf(n:3*n + 14))
366  end subroutine fourier1dperlagodd
367 
368  subroutine fourier1dper(coefd, Ncoef, E, N, alpha)
369  sll_int32, intent(in) :: n, ncoef
370  sll_real64, intent(in) :: coefd(1:ncoef)
371  sll_real64, intent(inout) :: e(1:n)
372  sll_real64, intent(in) :: alpha
373 
374  sll_int32 :: i
375  !sll_int32 :: ix
376  sll_real64 :: rea, ima, reb, imb, tmp, x
377  !localization
378  !
379  x = -alpha
380  !x=alpha
381  x = x - real(floor(x), f64)
382  !x=x*real(N,f64)
383  !ix=floor(x)
384  !x=x-real(ix,f64)
385  x = x*2._f64*sll_p_pi
386 
387  call dfftf(n, e, coefd)
388  !print *,E
389 
390  tmp = 1._f64/real(n, f64)
391  !print *,E
392 
393  e(1) = e(1)*tmp
394  do i = 1, (n - 2)/2
395  rea = e(2*i); ima = e(2*i + 1)
396  reb = tmp*cos(real(i, f64)*x)
397  imb = tmp*sin(real(i, f64)*x)
398  e(2*i) = rea*reb - ima*imb
399  e(2*i + 1) = rea*imb + reb*ima
400  end do
401  if (mod(n, 2) == 0) e(n) = e(n)*tmp*cos(0.5_f64*real(n, f64)*x)
402  call dfftb(n, e, coefd)
403  end subroutine fourier1dper
404 
405 end module sll_m_periodic_interp
Fortran module where set some physical and mathematical constants.
real(kind=f64), parameter, public sll_p_pi
real(kind=f64), parameter, public sll_p_twopi
FFT interface for FFTW.
integer, parameter, public sll_p_fft_forward
Flag to specify forward FFT (negative sign) [value -1].
subroutine, public sll_s_fft_init_r2r_1d(plan, nx, array_in, array_out, direction, normalized, aligned, optimization)
Create new 1d real to real plan.
integer, parameter, public sll_p_fft_backward
Flag to specify backward FFT (positive sign) [value 1].
subroutine, public sll_s_fft_exec_r2r_1d(plan, array_in, array_out)
Compute fast Fourier transform in real to real mode.
Low level arbitrary degree splines.
integer(kind=i32), parameter, public sll_p_trigo_fft_selalib
subroutine fourier1dperlagodd(buf, sizebuf, E, N, alpha, d)
complex(kind=f64), parameter ii_64
subroutine fourier1dper(coefd, Ncoef, E, N, alpha)
subroutine, public sll_s_periodic_interp_free(this)
integer(kind=i32), parameter, public sll_p_spline
integer(kind=i32), parameter, public sll_p_lagrange
subroutine, public sll_s_periodic_interp_init(this, N, interpolator, order)
integer(kind=i32), parameter trigo_real
integer(kind=i32), parameter, public sll_p_trigo
subroutine, public sll_s_periodic_interp(this, u_out, u, alpha)
Type for FFT plan in SeLaLib.
    Report Typos and Errors