PageRenderTime 113ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/src/grid/fourier_space_inc.F90

https://gitlab.com/neelravi/octopus
FORTRAN Modern | 264 lines | 162 code | 56 blank | 46 comment | 14 complexity | 209ae7d8b602aea3f140ad085c1d53b0 MD5 | raw file
  1. !! Copyright (C) 2002-2011 M. Marques, A. Castro, A. Rubio, G. Bertsch, M.Oliveira
  2. !!
  3. !! This program is free software; you can redistribute it and/or modify
  4. !! it under the terms of the GNU General Public License as published by
  5. !! the Free Software Foundation; either version 2, or (at your option)
  6. !! any later version.
  7. !!
  8. !! This program is distributed in the hope that it will be useful,
  9. !! but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. !! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. !! GNU General Public License for more details.
  12. !!
  13. !! You should have received a copy of the GNU General Public License
  14. !! along with this program; if not, write to the Free Software
  15. !! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. !! 02110-1301, USA.
  17. !!
  18. !! $Id$
  19. ! ---------------------------------------------------------
  20. !> The following routines convert the function between real space and Fourier space
  21. !! Note that the dimensions of the function in fs are different depending on whether
  22. !! f is real or complex, because the FFT representation is different (FFTW scheme).
  23. subroutine X(cube_function_rs2fs)(cube, cf)
  24. type(cube_t), intent(in) :: cube
  25. type(cube_function_t), intent(inout) :: cf
  26. PUSH_SUB(X(cube_function_rs2fs))
  27. ASSERT(associated(cube%fft))
  28. ASSERT(cube%fft%library /= FFTLIB_NONE)
  29. if(cf%in_device_memory) then
  30. call X(fft_forward_cl)(cube%fft, cf%real_space_buffer, cf%fourier_space_buffer)
  31. else
  32. ASSERT(associated(cf%X(rs)))
  33. ASSERT(associated(cf%fs))
  34. call X(fft_forward)(cube%fft, cf%X(rs), cf%fs)
  35. end if
  36. POP_SUB(X(cube_function_rs2fs))
  37. end subroutine X(cube_function_rs2fs)
  38. ! ---------------------------------------------------------
  39. subroutine X(cube_function_fs2rs)(cube, cf)
  40. type(cube_t), intent(in) :: cube
  41. type(cube_function_t), intent(inout) :: cf
  42. PUSH_SUB(X(cube_function_fs2rs))
  43. ASSERT(associated(cube%fft))
  44. ASSERT(cube%fft%library /= FFTLIB_NONE)
  45. if(cf%in_device_memory) then
  46. call X(fft_backward_cl)(cube%fft, cf%fourier_space_buffer, cf%real_space_buffer)
  47. else
  48. ASSERT(associated(cf%X(rs)))
  49. ASSERT(associated(cf%fs))
  50. call X(fft_backward)(cube%fft, cf%fs, cf%X(rs))
  51. end if
  52. POP_SUB(X(cube_function_fs2rs))
  53. end subroutine X(cube_function_fs2rs)
  54. ! ---------------------------------------------------------
  55. subroutine X(fourier_space_op_init)(this, cube, op, in_device)
  56. type(fourier_space_op_t), intent(out) :: this
  57. type(cube_t), intent(in) :: cube
  58. R_TYPE, intent(in) :: op(:, :, :)
  59. logical, optional, intent(in) :: in_device
  60. integer :: ii, jj, kk, ii_linear, size
  61. R_TYPE, allocatable :: op_linear(:)
  62. PUSH_SUB(X(fourier_space_op_init))
  63. ASSERT(associated(cube%fft))
  64. ASSERT(cube%fft%library /= FFTLIB_NONE)
  65. nullify(this%dop)
  66. nullify(this%zop)
  67. if(cube%fft%library /= FFTLIB_ACCEL .or. .not. optional_default(in_device, .true.)) then
  68. this%in_device_memory = .false.
  69. SAFE_ALLOCATE(this%X(op)(1:cube%fs_n(1), 1:cube%fs_n(2), 1:cube%fs_n(3)))
  70. forall (kk = 1:cube%fs_n(3), jj = 1:cube%fs_n(2), ii = 1:cube%fs_n(1))
  71. this%X(op)(ii, jj, kk) = op(ii, jj, kk)
  72. end forall
  73. else
  74. this%in_device_memory = .true.
  75. ASSERT(all(cube%fs_n(1:3) == ubound(op)))
  76. size = product(cube%fs_n(1:3))
  77. SAFE_ALLOCATE(op_linear(1:size))
  78. do kk = 1, cube%fs_n(3)
  79. do jj = 1, cube%fs_n(2)
  80. do ii = 1, cube%fs_n(1)
  81. ii_linear = 1 + (ii - 1)*cube%fft%stride_fs(1) + (jj - 1)*cube%fft%stride_fs(2) + (kk - 1)*cube%fft%stride_fs(3)
  82. op_linear(ii_linear) = fft_scaling_factor(cube%fft)*op(ii, jj, kk)
  83. end do
  84. end do
  85. end do
  86. call accel_create_buffer(this%op_buffer, ACCEL_MEM_READ_ONLY, R_TYPE_VAL, size)
  87. call accel_write_buffer(this%op_buffer, size, op_linear)
  88. SAFE_DEALLOCATE_A(op_linear)
  89. end if
  90. POP_SUB(X(fourier_space_op_init))
  91. end subroutine X(fourier_space_op_init)
  92. ! ---------------------------------------------------------
  93. !> Applies a multiplication factor to the Fourier space grid.
  94. !! This is a local function.
  95. subroutine X(fourier_space_op_apply)(this, cube, cf)
  96. type(fourier_space_op_t), intent(in) :: this
  97. type(cube_t), intent(in) :: cube
  98. type(cube_function_t), intent(inout) :: cf
  99. integer :: ii, jj, kk
  100. integer :: bsize
  101. type(profile_t), save :: prof_g, prof
  102. PUSH_SUB(X(fourier_space_op_apply))
  103. ASSERT(associated(cube%fft))
  104. ASSERT(cube%fft%library /= FFTLIB_NONE)
  105. ASSERT(cf%in_device_memory .eqv. this%in_device_memory)
  106. call cube_function_alloc_fs(cube, cf)
  107. call profiling_in(prof, "OP_APPLY")
  108. call X(cube_function_rs2fs)(cube, cf)
  109. call profiling_in(prof_g,"G_APPLY")
  110. if(cube%fft%library == FFTLIB_PFFT) then
  111. !Note that the function in fourier space returned by PFFT is transposed
  112. ! Probably in this case this%X(op) should be also transposed
  113. !$omp parallel do private(ii, jj, kk)
  114. do ii = 1, cube%fs_n(1)
  115. do jj = 1, cube%fs_n(2)
  116. do kk = 1, cube%fs_n(3)
  117. cf%fs(kk, ii, jj) = cf%fs(kk, ii, jj)*this%X(op) (ii, jj, kk)
  118. end do
  119. end do
  120. end do
  121. !$omp end parallel do
  122. else if(cube%fft%library == FFTLIB_FFTW .or. .not. this%in_device_memory) then
  123. !$omp parallel do private(ii, jj, kk)
  124. do kk = 1, cube%fs_n(3)
  125. do jj = 1, cube%fs_n(2)
  126. do ii = 1, cube%fs_n(1)
  127. cf%fs(ii, jj, kk) = cf%fs(ii, jj, kk)*this%X(op)(ii, jj, kk)
  128. end do
  129. end do
  130. end do
  131. !$omp end parallel do
  132. else if(cube%fft%library == FFTLIB_ACCEL) then
  133. call accel_set_kernel_arg(X(zmul), 0, product(cube%fs_n(1:3)))
  134. call accel_set_kernel_arg(X(zmul), 1, this%op_buffer)
  135. call accel_set_kernel_arg(X(zmul), 2, cf%fourier_space_buffer)
  136. bsize = accel_kernel_workgroup_size(X(zmul))
  137. call accel_kernel_run(X(zmul), (/pad(product(cube%fs_n(1:3)), bsize)/), (/bsize/))
  138. call accel_finish()
  139. end if
  140. #ifdef R_TREAL
  141. call profiling_count_operations(2*R_MUL*product(cube%fs_n(1:3)))
  142. #else
  143. call profiling_count_operations(R_MUL*product(cube%fs_n(1:3)))
  144. #endif
  145. call profiling_out(prof_g)
  146. call X(cube_function_fs2rs)(cube, cf)
  147. call cube_function_free_fs(cube, cf)
  148. call profiling_out(prof)
  149. POP_SUB(X(fourier_space_op_apply))
  150. end subroutine X(fourier_space_op_apply)
  151. ! ---------------------------------------------------------
  152. !> The next two subroutines convert a function in Fourier space
  153. !! between the normal mesh and the cube.
  154. !!
  155. !! Note that the function in the mesh should be defined
  156. !! globally, not just in a partition (when running in
  157. !! parallel in real-space domains).
  158. ! ---------------------------------------------------------
  159. subroutine X(mesh_to_fourier) (mesh, mf, cube, cf)
  160. type(mesh_t), intent(in) :: mesh
  161. CMPLX, intent(in) :: mf(:) !< mf(mesh%np_global)
  162. type(cube_t), intent(in) :: cube
  163. type(cube_function_t), intent(inout) :: cf
  164. integer :: ip, ix, iy, iz
  165. PUSH_SUB(X(mesh_to_fourier))
  166. ASSERT(associated(cube%fft))
  167. ASSERT(associated(cf%fs))
  168. cf%fs = M_z0
  169. do ip = 1, mesh%np_global
  170. ix = pad_feq(mesh%idx%lxyz(ip, 1), cube%rs_n_global(1), .false.)
  171. if(ix > cube%fs_n_global(1)) cycle ! negative frequencies are redundant
  172. iy = pad_feq(mesh%idx%lxyz(ip, 2), cube%rs_n_global(2), .false.)
  173. iz = pad_feq(mesh%idx%lxyz(ip, 3), cube%rs_n_global(3), .false.)
  174. cf%fs(ix, iy, iz) = mf(ip)
  175. end do
  176. POP_SUB(X(mesh_to_fourier))
  177. end subroutine X(mesh_to_fourier)
  178. ! ---------------------------------------------------------
  179. subroutine X(fourier_to_mesh) (cube, cf, mesh, mf)
  180. type(cube_t), intent(in) :: cube
  181. type(cube_function_t), intent(in) :: cf
  182. type(mesh_t), intent(in) :: mesh
  183. CMPLX, intent(out) :: mf(:) !< mf(mesh%np_global)
  184. integer :: ip, ix, iy, iz
  185. PUSH_SUB(X(fourier_to_mesh))
  186. ASSERT(associated(cube%fft))
  187. ASSERT(associated(cf%fs))
  188. do ip = 1, mesh%np_global
  189. ix = pad_feq(mesh%idx%lxyz(ip, 1), cube%rs_n_global(1), .false.)
  190. iy = pad_feq(mesh%idx%lxyz(ip, 2), cube%rs_n_global(2), .false.)
  191. iz = pad_feq(mesh%idx%lxyz(ip, 3), cube%rs_n_global(3), .false.)
  192. #ifdef R_TREAL
  193. if(ix > cube%fs_n_global(1)) then
  194. ix = pad_feq(-mesh%idx%lxyz(ip, 1), cube%rs_n_global(1), .false.)
  195. mf(ip) = conjg(cf%fs(ix, iy, iz))
  196. else
  197. mf(ip) = cf%fs(ix, iy, iz)
  198. end if
  199. #else
  200. mf(ip) = cf%fs(ix, iy, iz)
  201. #endif
  202. end do
  203. POP_SUB(X(fourier_to_mesh))
  204. end subroutine X(fourier_to_mesh)
  205. !! Local Variables:
  206. !! mode: f90
  207. !! coding: utf-8
  208. !! End: