Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_poisson_2d_periodic_par.F90
Go to the documentation of this file.
1 
4 !
8 !
18 
19 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20 #include "sll_memory.h"
21 #include "sll_assert.h"
22 #include "sll_working_precision.h"
23 
24  use sll_m_collective, only: &
28 
29  use sll_m_constants, only: &
30  sll_p_pi
31 
32  use sll_m_fft, only: &
38  sll_t_fft
39 
40  use sll_m_remapper, only: &
41  sll_o_apply_remap_2d, &
42  sll_o_compute_local_sizes, &
43  sll_o_get_layout_collective, &
44  sll_o_initialize_layout_with_distributed_array, &
45  sll_t_layout_2d, &
46  sll_o_local_to_global, &
47  sll_f_new_layout_2d, &
48  sll_o_new_remap_plan, &
49  sll_t_remap_plan_2d_comp64, &
50  sll_o_delete
51 
52  use sll_m_utilities, only: &
54 
55  implicit none
56 
57  public :: &
64 
65  private
66 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
67 
72  sll_int32 :: ncx
73  sll_int32 :: ncy
74  sll_real64 :: lx
75  sll_real64 :: ly
76  type(sll_t_fft) :: px
77  type(sll_t_fft) :: py
78  type(sll_t_fft) :: px_inv
79  type(sll_t_fft) :: py_inv
80  type(sll_t_layout_2d), pointer :: layout_seq_x1
81  type(sll_t_layout_2d), pointer :: layout_seq_x2
82  sll_int32 :: seq_x1_local_sz_x1
83  sll_int32 :: seq_x1_local_sz_x2
84  sll_int32 :: seq_x2_local_sz_x1
85  sll_int32 :: seq_x2_local_sz_x2
86  sll_comp64, dimension(:, :), pointer :: fft_x_array
87  sll_comp64, dimension(:, :), pointer :: fft_y_array
88  type(sll_t_remap_plan_2d_comp64), pointer :: rmp_xy
89  type(sll_t_remap_plan_2d_comp64), pointer :: rmp_yx
90  sll_comp64, pointer :: tmp_x(:)
91  sll_comp64, pointer :: tmp_y(:)
92 
94 
95 contains
96 
102  start_layout, &
103  ncx, &
104  ncy, &
105  Lx, &
106  Ly)
107 
108  type(sll_t_poisson_2d_periodic_par) :: plan
109  type(sll_t_layout_2d), pointer :: start_layout
110  sll_int32 :: ncx
111  sll_int32 :: ncy
112  sll_real64 :: lx
113  sll_real64 :: ly
114  sll_int64 :: colsz ! collective size
115  type(sll_t_collective_t), pointer :: collective
116 
117  ! number of processors
118  sll_int32 :: nprocx1
119  sll_int32 :: nprocx2
120  sll_int32 :: ierr
121  sll_int32 :: loc_sz_x1
122  sll_int32 :: loc_sz_x2
123 
124  ! The collective to be used is the one that comes with the given layout.
125  collective => sll_o_get_layout_collective(start_layout)
126  colsz = int(sll_f_get_collective_size(collective), i64)
127 
128  if ((.not. sll_f_is_power_of_two(int(ncx, i64))) .and. &
129  (.not. sll_f_is_power_of_two(int(ncy, i64)))) then
130  print *, 'This test needs to run with numbers of cells which are', &
131  'powers of 2.'
132  print *, 'Exiting...'
133  stop
134  end if
135 
136  ! We use the number of cells since due to periodicity, the last point is
137  ! not considered.
138  plan%ncx = ncx
139  plan%ncy = ncy
140  plan%Lx = lx
141  plan%Ly = ly
142 
143  ! Layout and local sizes for FFTs in x-direction
144  plan%layout_seq_x1 => start_layout
145  call sll_o_compute_local_sizes( &
146  plan%layout_seq_x1, &
147  loc_sz_x1, &
148  loc_sz_x2)
149 
150  plan%seq_x1_local_sz_x1 = loc_sz_x1
151  plan%seq_x1_local_sz_x2 = loc_sz_x2
152 
153  sll_allocate(plan%fft_x_array(loc_sz_x1, loc_sz_x2), ierr)
154  sll_allocate(plan%tmp_x(ncx), ierr)
155 
156  ! For FFTs (in x-direction)
157  call sll_s_fft_init_c2c_1d( &
158  plan%px, &
159  ncx, &
160  plan%tmp_x, plan%tmp_x, &
161  sll_p_fft_forward)!+FFT_NORMALIZE )
162 
163  call sll_s_fft_init_c2c_1d( &
164  plan%px_inv, &
165  ncx, &
166  plan%tmp_x, plan%tmp_x, &
167  sll_p_fft_backward) !+FFT_NORMALIZE )
168 
169  ! Layout and local sizes for FFTs in y-direction (x2)
170  plan%layout_seq_x2 => sll_f_new_layout_2d(collective)
171  nprocx1 = int(colsz, kind=4)
172  nprocx2 = 1
173 
174  call sll_o_initialize_layout_with_distributed_array( &
175  ncx + 1, &
176  ncy + 1, &
177  nprocx1, &
178  nprocx2, &
179  plan%layout_seq_x2)
180 
181  call sll_o_compute_local_sizes( &
182  plan%layout_seq_x2, &
183  loc_sz_x1, &
184  loc_sz_x2)
185 
186  plan%seq_x2_local_sz_x1 = loc_sz_x1
187  plan%seq_x2_local_sz_x2 = loc_sz_x2
188  sll_allocate(plan%fft_y_array(loc_sz_x1, loc_sz_x2), ierr)
189 
190  sll_allocate(plan%tmp_y(ncy), ierr)
191 
192  ! For FFTs (in y-direction)
193 
194  call sll_s_fft_init_c2c_1d( &
195  plan%py, &
196  ncy, &
197  plan%tmp_y, plan%tmp_y, &
198  sll_p_fft_forward)! + FFT_NORMALIZE )
199 
200  call sll_s_fft_init_c2c_1d( &
201  plan%py_inv, &
202  ncy, &
203  plan%tmp_y, plan%tmp_y, &
204  sll_p_fft_backward)! + FFT_NORMALIZE )
205 
206  plan%rmp_xy => &
207  sll_o_new_remap_plan(plan%layout_seq_x1, plan%layout_seq_x2, plan%fft_x_array)
208  plan%rmp_yx => &
209  sll_o_new_remap_plan(plan%layout_seq_x2, plan%layout_seq_x1, plan%fft_y_array)
211 
214  subroutine sll_s_poisson_2d_periodic_par_solve(plan, rho, phi)
215  type(sll_t_poisson_2d_periodic_par) :: plan
216  sll_real64, dimension(:, :) :: rho
217  sll_real64, dimension(:, :) :: phi
218  sll_int32 :: ncx
219  sll_int32 :: ncy
220  sll_int32 :: npx_loc
221  sll_int32 :: npy_loc
222  sll_int32 :: i, j
223  ! Reciprocals of domain lengths.
224  sll_real64 :: r_lx, r_ly
225  sll_real64 :: kx, ky
226  sll_real64 :: normalization
227  type(sll_t_layout_2d), pointer :: layout_x
228  type(sll_t_layout_2d), pointer :: layout_y
229  sll_int32, dimension(1:2) :: global
230  sll_int32 :: gi, gj
231 
232  ncx = plan%ncx
233  ncy = plan%ncy
234  r_lx = 1.0_f64/plan%Lx
235  r_ly = 1.0_f64/plan%Ly
236 
237  !print*, 1.0_f64/plan%Lx, 1.0_f64/plan%Ly
238  ! Get layouts to compute FFTs (in each direction)
239  layout_x => plan%layout_seq_x1
240  layout_y => plan%layout_seq_x2
241  !call verify_argument_sizes_par(layout_x, rho, phi)
242 
243  ! FFTs in x-direction
244  npx_loc = plan%seq_x1_local_sz_x1
245  npy_loc = plan%seq_x1_local_sz_x2
246 
247  ! The input is handled internally as a complex array
248  plan%fft_x_array = cmplx(rho, 0.0_f64, kind=f64)
249 
250  do j = 1, npy_loc
251  call sll_s_fft_exec_c2c_1d(plan%px, plan%fft_x_array(1:ncx, j), plan%tmp_x)
252  plan%fft_x_array(1:ncx, j) = plan%tmp_x
253  end do
254  ! FFTs in y-direction
255  npx_loc = plan%seq_x2_local_sz_x1
256  npy_loc = plan%seq_x2_local_sz_x2
257 
258  call sll_o_apply_remap_2d(plan%rmp_xy, plan%fft_x_array, plan%fft_y_array)
259 
260  do i = 1, npx_loc
261  plan%tmp_y = plan%fft_y_array(i, 1:ncy)
262  call sll_s_fft_exec_c2c_1d(plan%py, plan%tmp_y, plan%fft_y_array(i, 1:ncy))
263  end do
264 
265  ! This should be inside the FFT plan...
266  normalization = 1.0_f64/real(ncx*ncy, f64)
267 
268  ! Apply the kernel
269  do j = 1, npy_loc - 1 ! last point was not transformed
270  do i = 1, npx_loc - 1
271  ! Make sure that the first mode is set to zero so that we get an
272  ! answer with zero mean value. This step assumes that the (1,1) point
273  ! will always be at the border of any splitting of the domains. This
274  ! seems safe in this case.
275 
276  global = sll_o_local_to_global(layout_y, (/i, j/))
277  gi = global(1)
278  gj = global(2)
279 
280  if ((gi == 1) .and. (gj == 1)) then
281  plan%fft_y_array(1, 1) = (0.0_f64, 0.0_f64)
282  else
283  kx = real(gi - 1, f64)
284  ky = real(gj - 1, f64)
285  ! Crucial step: While the results of the FFT are basically a
286  ! list of the modes in the 0..n-1 sense, the algorithm that we
287  ! are using uses a decomposition with negative frequencies,
288  ! i.e.: -n/2..n/2-1. Therefore a step is needed in which we are
289  ! effectively reinterpreting the FFT results in this light.
290  ! More specifically, we take the second half of the transformed
291  ! array and apply a modified factor, proper of a negative
292  ! frequency.
293  if (kx .ge. ncx/2) then
294  kx = kx - ncx
295  end if
296 
297  if (ky .ge. ncy/2) then
298  ky = ky - ncy
299  end if
300 
301  plan%fft_y_array(i, j) = -plan%fft_y_array(i, j)/ &
302  (((kx*r_lx)**2 + (ky*r_ly)**2)*4.0_f64*sll_p_pi**2)
303  end if
304  end do
305  end do
306 
307  ! Inverse FFTs in y-direction
308  do i = 1, npx_loc
309  plan%tmp_y = plan%fft_y_array(i, 1:ncy)
310  call sll_s_fft_exec_c2c_1d(plan%py_inv, plan%tmp_y, plan%fft_y_array(i, :))
311  end do
312 
313  ! Force the periodicity condition in the y-direction. CAN'T USE THE FFT
314  ! INTERFACE SINCE THIS POINT FALLS OUTSIDE OF THE POINTS IN THE ARRAY
315  ! TOUCHED BY THE FFT. This is another reason to permit not including the
316  ! last point in the periodic cases...
317 
318  plan%fft_y_array(:, npy_loc) = plan%fft_y_array(:, 1)
319 
320  ! Prepare to take inverse FFTs in x-direction
321  call sll_o_apply_remap_2d(plan%rmp_yx, plan%fft_y_array, plan%fft_x_array)
322 
323  npx_loc = plan%seq_x1_local_sz_x1
324  npy_loc = plan%seq_x1_local_sz_x2
325 
326  do j = 1, npy_loc
327  call sll_s_fft_exec_c2c_1d(plan%px_inv, plan%fft_x_array(1:ncx, j), plan%tmp_x)
328  plan%fft_x_array(1:ncx, j) = plan%tmp_x
329  end do
330 
331  ! Also ensure the periodicity in x
332  plan%fft_x_array(npx_loc, :) = plan%fft_x_array(1, :)
333 
334  phi(1:npx_loc, 1:npy_loc) = real(plan%fft_x_array(1:npx_loc, 1:npy_loc), f64)
335 
336  phi = phi*normalization
337 
339 
347  plan, &
348  start_layout, &
349  ncx, &
350  ncy, &
351  Lx, &
352  Ly)
353 
354  type(sll_t_poisson_2d_periodic_par) :: plan
355  type(sll_t_layout_2d), pointer :: start_layout
356  sll_int32 :: ncx
357  sll_int32 :: ncy
358  sll_real64 :: lx
359  sll_real64 :: ly
360  sll_int64 :: colsz
361  type(sll_t_collective_t), pointer :: collective
362  ! number of processors
363  sll_int32 :: nprocx1
364  sll_int32 :: nprocx2
365  sll_int32 :: ierr
366  sll_int32 :: loc_sz_x1
367  sll_int32 :: loc_sz_x2
368 
369  ! The collective to be used is the one that comes with the given layout.
370  collective => sll_o_get_layout_collective(start_layout)
371  colsz = int(sll_f_get_collective_size(collective), i64)
372 
373  sll_assert(sll_f_is_power_of_two(int(ncx, i64)))
374  sll_assert(sll_f_is_power_of_two(int(ncy, i64)))
375 
376  ! We use the number of cells since due to periodicity, the last point is
377  ! not considered. It should not even exist...
378  plan%ncx = ncx
379  plan%ncy = ncy
380  plan%Lx = lx
381  plan%Ly = ly
382 
383  ! Layout and local sizes for FFTs in x-direction
384  plan%layout_seq_x1 => start_layout
385  call sll_o_compute_local_sizes( &
386  plan%layout_seq_x1, &
387  loc_sz_x1, &
388  loc_sz_x2)
389 
390  plan%seq_x1_local_sz_x1 = loc_sz_x1 ! ncx
391  plan%seq_x1_local_sz_x2 = loc_sz_x2
392 
393  sll_allocate(plan%fft_x_array(loc_sz_x1, loc_sz_x2), ierr)
394 
395  allocate (plan%tmp_x(ncx))
396  call sll_s_fft_init_c2c_1d( &
397  plan%px, &
398  ncx, &
399  plan%tmp_x, &
400  plan%tmp_x, &
401  sll_p_fft_forward)!+FFT_NORMALIZE )
402 
403  call sll_s_fft_init_c2c_1d( &
404  plan%px_inv, &
405  ncx, &
406  plan%tmp_x, &
407  plan%tmp_x, &
408  sll_p_fft_backward)!+FFT_NORMALIZE )
409 
410  ! Layout and local sizes for FFTs in y-direction (x2)
411  plan%layout_seq_x2 => sll_f_new_layout_2d(collective)
412  nprocx1 = int(colsz, kind=4)
413  nprocx2 = 1
414 
415  call sll_o_initialize_layout_with_distributed_array( &
416  ncx, &
417  ncy, &
418  nprocx1, &
419  nprocx2, &
420  plan%layout_seq_x2)
421 
422  call sll_o_compute_local_sizes( &
423  plan%layout_seq_x2, &
424  loc_sz_x1, &
425  loc_sz_x2)
426 
427  plan%seq_x2_local_sz_x1 = loc_sz_x1
428  plan%seq_x2_local_sz_x2 = ncy ! loc_sz_x2
429  sll_allocate(plan%fft_y_array(loc_sz_x1, loc_sz_x2), ierr)
430 
431  ! For FFTs (in y-direction)
432 
433  allocate (plan%tmp_y(ncy))
434  call sll_s_fft_init_c2c_1d( &
435  plan%py, &
436  ncy, &
437  plan%tmp_y, &
438  plan%tmp_y, &
439  sll_p_fft_forward)! + FFT_NORMALIZE )
440 
441  call sll_s_fft_init_c2c_1d( &
442  plan%py_inv, &
443  ncy, &
444  plan%tmp_y, &
445  plan%tmp_y, &
446  sll_p_fft_backward)! + FFT_NORMALIZE )
447 
448  plan%rmp_xy => &
449  sll_o_new_remap_plan(plan%layout_seq_x1, plan%layout_seq_x2, plan%fft_x_array)
450  plan%rmp_yx => &
451  sll_o_new_remap_plan(plan%layout_seq_x2, plan%layout_seq_x1, plan%fft_y_array)
453 
458  subroutine sll_s_poisson_2d_periodic_par_solve_alt(plan, rho, phi)
459  type(sll_t_poisson_2d_periodic_par) :: plan
460  sll_real64, dimension(:, :) :: rho
461  sll_real64, dimension(:, :) :: phi
462  sll_int32 :: ncx
463  sll_int32 :: ncy
464  sll_int32 :: npx_loc
465  sll_int32 :: npy_loc
466  sll_int32 :: i, j
467  ! Reciprocals of domain lengths.
468  sll_real64 :: r_lx, r_ly
469  sll_real64 :: kx, ky
470  sll_real64 :: normalization
471  type(sll_t_layout_2d), pointer :: layout_x
472  type(sll_t_layout_2d), pointer :: layout_y
473  sll_int32, dimension(1:2) :: global
474  sll_int32 :: gi, gj
475 
476  ncx = plan%ncx
477  ncy = plan%ncy
478  r_lx = 1.0_f64/plan%Lx
479  r_ly = 1.0_f64/plan%Ly
480 
481  !print*, 1.0_f64/plan%Lx, 1.0_f64/plan%Ly
482  ! Get layouts to compute FFTs (in each direction)
483  layout_x => plan%layout_seq_x1
484  layout_y => plan%layout_seq_x2
485  !call verify_argument_sizes_par(layout_x, rho, phi)
486 
487  ! FFTs in x-direction
488  npx_loc = plan%seq_x1_local_sz_x1
489  npy_loc = plan%seq_x1_local_sz_x2
490 
491  ! The input is handled internally as a complex array
492  plan%fft_x_array = cmplx(rho, 0.0_f64, kind=f64)
493 
494  do j = 1, npy_loc
495  call sll_s_fft_exec_c2c_1d(plan%px, plan%fft_x_array(:, j), plan%tmp_x)
496  plan%fft_x_array(:, j) = plan%tmp_x
497  end do
498  ! FFTs in y-direction
499  npx_loc = plan%seq_x2_local_sz_x1
500  npy_loc = plan%seq_x2_local_sz_x2
501 
502  call sll_o_apply_remap_2d(plan%rmp_xy, plan%fft_x_array, plan%fft_y_array)
503 
504  do i = 1, npx_loc
505  plan%tmp_y = plan%fft_y_array(i, :)
506  call sll_s_fft_exec_c2c_1d(plan%py, plan%tmp_y, plan%fft_y_array(i, :))
507  end do
508 
509  ! This should be inside the FFT plan...
510  normalization = 1.0_f64/real(ncx*ncy, f64)
511 
512  ! Apply the kernel
513  do j = 1, npy_loc
514  do i = 1, npx_loc
515  ! Make sure that the first mode is set to zero so that we get an
516  ! answer with zero mean value. This step assumes that the (1,1) point
517  ! will always be at the border of any splitting of the domains. This
518  ! seems safe in this case.
519 
520  global = sll_o_local_to_global(layout_y, (/i, j/))
521  gi = global(1)
522  gj = global(2)
523 
524  if ((gi == 1) .and. (gj == 1)) then
525  plan%fft_y_array(1, 1) = (0.0_f64, 0.0_f64)
526  else
527  kx = real(gi - 1, f64)
528  ky = real(gj - 1, f64)
529  ! Crucial step: While the results of the FFT are basically a
530  ! list of the modes in the 0..n-1 sense, the algorithm that we
531  ! are using uses a decomposition with negative frequencies,
532  ! i.e.: -n/2..n/2-1. Therefore a step is needed in which we are
533  ! effectively reinterpreting the FFT results in this light.
534  ! More specifically, we take the second half of the transformed
535  ! array and apply a modified factor, proper of a negative
536  ! frequency.
537  if (kx .ge. ncx/2) then
538  kx = kx - ncx
539  end if
540 
541  if (ky .ge. ncy/2) then
542  ky = ky - ncy
543  end if
544 
545  plan%fft_y_array(i, j) = -plan%fft_y_array(i, j)/ &
546  (((kx*r_lx)**2 + (ky*r_ly)**2)*4.0_f64*sll_p_pi**2)
547  end if
548  end do
549  end do
550 
551  ! Inverse FFTs in y-direction
552  do i = 1, npx_loc
553  plan%tmp_y = plan%fft_y_array(i, :)
554  call sll_s_fft_exec_c2c_1d(plan%py_inv, plan%tmp_y, plan%fft_y_array(i, :))
555  end do
556 
557  ! Prepare to take inverse FFTs in x-direction
558  call sll_o_apply_remap_2d(plan%rmp_yx, plan%fft_y_array, plan%fft_x_array)
559 
560  npx_loc = plan%seq_x1_local_sz_x1
561  npy_loc = plan%seq_x1_local_sz_x2
562 
563  do j = 1, npy_loc
564  call sll_s_fft_exec_c2c_1d(plan%px_inv, plan%fft_x_array(:, j), plan%tmp_x)
565  plan%fft_x_array(:, j) = plan%tmp_x
566  end do
567 
568  phi = real(plan%fft_x_array, f64)*normalization
569 
571 
574  type(sll_t_poisson_2d_periodic_par) :: plan
575  sll_int32 :: ierr
576 
577  call sll_s_fft_free(plan%px)
578  call sll_s_fft_free(plan%py)
579  call sll_s_fft_free(plan%px_inv)
580  call sll_s_fft_free(plan%py_inv)
581 
582  call sll_o_delete(plan%layout_seq_x1)
583  call sll_o_delete(plan%layout_seq_x2)
584  sll_deallocate_array(plan%fft_x_array, ierr)
585  sll_deallocate_array(plan%fft_y_array, ierr)
586  call sll_o_delete(plan%rmp_xy)
587  call sll_o_delete(plan%rmp_yx)
589 
Parallelizing facility.
integer(kind=i32) function, public sll_f_get_collective_rank(col)
Determines the rank of the calling process in the communicator.
integer(kind=i32) function, public sll_f_get_collective_size(col)
Determines the size of the group associated with a communicator.
Fortran module where set some physical and mathematical constants.
real(kind=f64), parameter, public sll_p_pi
FFT interface for FFTW.
subroutine, public sll_s_fft_free(plan)
Delete a plan.
integer, parameter, public sll_p_fft_forward
Flag to specify forward FFT (negative sign) [value -1].
subroutine, public sll_s_fft_exec_c2c_1d(plan, array_in, array_out)
Compute fast Fourier transform in complex to complex mode.
subroutine, public sll_s_fft_init_c2c_1d(plan, nx, array_in, array_out, direction, normalized, aligned, optimization)
Create new 1d complex to complex plan.
integer, parameter, public sll_p_fft_backward
Flag to specify backward FFT (positive sign) [value 1].
Selalib periodic 2D poisson solver for cartesian coordinates.
subroutine, public sll_s_poisson_2d_periodic_par_solve_alt(plan, rho, phi)
Note that the equation that is solved is: Thus the user is responsible for giving the proper sign to...
subroutine, public sll_s_poisson_2d_periodic_par_solve(plan, rho, phi)
Note that the equation that is solved is: Thus the user is responsible for giving the proper sign to...
subroutine, public sll_s_poisson_2d_periodic_par_free(plan)
Delete the Poisson solver object.
subroutine, public sll_s_poisson_2d_periodic_par_init(plan, start_layout, ncx, ncy, Lx, Ly)
Presently, this function receives the geometric information as individual arguments....
subroutine, public sll_s_poisson_2d_periodic_par_init_alt(plan, start_layout, ncx, ncy, Lx, Ly)
Presently, this function receives the geometric information as individual arguments....
Some common numerical utilities.
logical function, public sll_f_is_power_of_two(n)
Check if an integer is equal to.
Wrapper around the communicator.
Type for FFT plan in SeLaLib.
Structure to store data from Poisson solver. This solver is parallel on structured cartesian mesh....
    Report Typos and Errors