LCOV - code coverage report
Current view: top level - src/pw - pw_gpu.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 1.5 % 273 4
Test Date: 2026-07-25 06:35:44 Functions: 15.4 % 13 2

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \note
      10              : !> This module contains routines necessary to operate on plane waves on GPUs
      11              : !     >  independently of the GPU platform.
      12              : !> \par History
      13              : !>      BGL (06-Mar-2008)  : Created
      14              : !>      AG  (18-May-2012)  : Refacturing:
      15              : !>                           - added explicit interfaces to C routines
      16              : !>                           - enable double precision complex transformations
      17              : !>      AG  (11-Sept-2012) : Modifications:
      18              : !>                          - use pointers if precision mapping is not required
      19              : !>                          - use OMP for mapping
      20              : !>      MT  (Jan 2022)     : Modifications
      21              : !>                          - use a generic interface for fft calls to GPUs
      22              : !>                          - Support both Nvidia and AMD GPUs. Other GPUs manufacturers
      23              : !>                            can be added easily.
      24              : !> \author Benjamin G. Levine
      25              : ! **************************************************************************************************
      26              : MODULE pw_gpu
      27              :    USE ISO_C_BINDING,                   ONLY: C_DOUBLE,&
      28              :                                               C_INT,&
      29              :                                               C_LOC,&
      30              :                                               C_PTR
      31              :    USE fft_tools,                       ONLY: &
      32              :         cube_transpose_1, cube_transpose_2, fft_scratch_sizes, fft_scratch_type, get_fft_scratch, &
      33              :         release_fft_scratch, x_to_yz, xz_to_yz, yz_to_x, yz_to_xz
      34              :    USE kinds,                           ONLY: dp
      35              :    USE mathconstants,                   ONLY: z_zero
      36              :    USE message_passing,                 ONLY: mp_cart_type
      37              :    USE pw_grid_types,                   ONLY: FULLSPACE
      38              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      39              :                                               pw_r3d_rs_type
      40              : #include "../base/base_uses.f90"
      41              : 
      42              :    IMPLICIT NONE
      43              : 
      44              :    PRIVATE
      45              : 
      46              :    PUBLIC :: pw_gpu_r3dc1d_3d
      47              :    PUBLIC :: pw_gpu_c1dr3d_3d
      48              :    PUBLIC :: pw_gpu_r3dc1d_3d_ps
      49              :    PUBLIC :: pw_gpu_c1dr3d_3d_ps
      50              :    PUBLIC :: pw_gpu_init, pw_gpu_finalize
      51              : 
      52              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pw_gpu'
      53              :    LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .FALSE.
      54              : 
      55              : CONTAINS
      56              : 
      57              : ! **************************************************************************************************
      58              : !> \brief Allocates resources on the gpu device for gpu fft acceleration
      59              : !> \author Ole Schuett
      60              : ! **************************************************************************************************
      61        10486 :    SUBROUTINE pw_gpu_init()
      62              :       INTEGER                                            :: dummy
      63              :       INTERFACE
      64              :          SUBROUTINE pw_gpu_init_c() BIND(C, name="pw_gpu_init")
      65              :          END SUBROUTINE pw_gpu_init_c
      66              :       END INTERFACE
      67              : 
      68              :       MARK_USED(dummy) ! TODO: fix fpretty
      69              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
      70              :       CALL pw_gpu_init_c()
      71              : #else
      72              :       ! Nothing to do.
      73              : #endif
      74        10486 :    END SUBROUTINE pw_gpu_init
      75              : 
      76              : ! **************************************************************************************************
      77              : !> \brief Releases resources on the gpu device for gpu fft acceleration
      78              : !> \author Ole Schuett
      79              : ! **************************************************************************************************
      80        10486 :    SUBROUTINE pw_gpu_finalize()
      81              :       INTEGER                                            :: dummy
      82              :       INTERFACE
      83              :          SUBROUTINE pw_gpu_finalize_c() BIND(C, name="pw_gpu_finalize")
      84              :          END SUBROUTINE pw_gpu_finalize_c
      85              :       END INTERFACE
      86              : 
      87              :       MARK_USED(dummy) ! TODO: fix fpretty
      88              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
      89              :       CALL pw_gpu_finalize_c()
      90              : #else
      91              :       ! Nothing to do.
      92              : #endif
      93        10486 :    END SUBROUTINE pw_gpu_finalize
      94              : 
      95              : ! **************************************************************************************************
      96              : !> \brief perform an fft followed by a gather on the gpu
      97              : !> \param pw1 ...
      98              : !> \param pw2 ...
      99              : !> \author Benjamin G Levine
     100              : ! **************************************************************************************************
     101            0 :    SUBROUTINE pw_gpu_r3dc1d_3d(pw1, pw2)
     102              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: pw1
     103              :       TYPE(pw_c1d_gs_type), INTENT(INOUT)                :: pw2
     104              : 
     105              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_gpu_r3dc1d_3d'
     106              : 
     107              :       COMPLEX(KIND=dp), POINTER                          :: ptr_pwout
     108              :       INTEGER                                            :: handle, l1, l2, l3, ngpts
     109            0 :       INTEGER, DIMENSION(:), POINTER                     :: npts
     110              :       INTEGER, POINTER                                   :: ptr_ghatmap
     111              :       REAL(KIND=dp)                                      :: scale
     112              :       REAL(KIND=dp), POINTER                             :: ptr_pwin
     113              :       INTERFACE
     114              :          SUBROUTINE pw_gpu_cfffg_c(din, zout, ghatmap, npts, ngpts, scale) BIND(C, name="pw_gpu_cfffg")
     115              :             IMPORT
     116              :             TYPE(C_PTR), INTENT(IN), VALUE               :: din
     117              :             TYPE(C_PTR), VALUE                           :: zout
     118              :             TYPE(C_PTR), INTENT(IN), VALUE               :: ghatmap
     119              :             INTEGER(KIND=C_INT), DIMENSION(*), INTENT(IN):: npts
     120              :             INTEGER(KIND=C_INT), INTENT(IN), VALUE       :: ngpts
     121              :             REAL(KIND=C_DOUBLE), INTENT(IN), VALUE       :: scale
     122              : 
     123              :          END SUBROUTINE pw_gpu_cfffg_c
     124              :       END INTERFACE
     125              : 
     126            0 :       CALL timeset(routineN, handle)
     127              : 
     128            0 :       scale = 1.0_dp/REAL(pw1%pw_grid%ngpts, KIND=dp)
     129              : 
     130            0 :       ngpts = SIZE(pw2%pw_grid%gsq)
     131              :       l1 = LBOUND(pw1%array, 1)
     132              :       l2 = LBOUND(pw1%array, 2)
     133              :       l3 = LBOUND(pw1%array, 3)
     134            0 :       npts => pw1%pw_grid%npts
     135              : 
     136              :       ! pointers to data arrays
     137            0 :       ptr_pwin => pw1%array(l1, l2, l3)
     138            0 :       ptr_pwout => pw2%array(1)
     139              : 
     140              :       ! pointer to map array
     141            0 :       ptr_ghatmap => pw2%pw_grid%g_hatmap(1, 1)
     142              : 
     143              :       ! invoke the combined transformation
     144              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
     145              :       CALL pw_gpu_cfffg_c(c_loc(ptr_pwin), c_loc(ptr_pwout), c_loc(ptr_ghatmap), npts, ngpts, scale)
     146              : #else
     147            0 :       CPABORT("Compiled without pw offloading.")
     148              : #endif
     149              : 
     150            0 :       CALL timestop(handle)
     151            0 :    END SUBROUTINE pw_gpu_r3dc1d_3d
     152              : 
     153              : ! **************************************************************************************************
     154              : !> \brief perform an scatter followed by a fft on the gpu
     155              : !> \param pw1 ...
     156              : !> \param pw2 ...
     157              : !> \author Benjamin G Levine
     158              : ! **************************************************************************************************
     159            0 :    SUBROUTINE pw_gpu_c1dr3d_3d(pw1, pw2)
     160              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: pw1
     161              :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                :: pw2
     162              : 
     163              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_gpu_c1dr3d_3d'
     164              : 
     165              :       COMPLEX(KIND=dp), POINTER                          :: ptr_pwin
     166              :       INTEGER                                            :: handle, l1, l2, l3, ngpts, nmaps
     167            0 :       INTEGER, DIMENSION(:), POINTER                     :: npts
     168              :       INTEGER, POINTER                                   :: ptr_ghatmap
     169              :       REAL(KIND=dp)                                      :: scale
     170              :       REAL(KIND=dp), POINTER                             :: ptr_pwout
     171              :       INTERFACE
     172              :          SUBROUTINE pw_gpu_sfffc_c(zin, dout, ghatmap, npts, ngpts, nmaps, scale) BIND(C, name="pw_gpu_sfffc")
     173              :             IMPORT
     174              :             TYPE(C_PTR), INTENT(IN), VALUE               :: zin
     175              :             TYPE(C_PTR), VALUE                           :: dout
     176              :             TYPE(C_PTR), INTENT(IN), VALUE               :: ghatmap
     177              :             INTEGER(KIND=C_INT), DIMENSION(*), INTENT(IN):: npts
     178              :             INTEGER(KIND=C_INT), INTENT(IN), VALUE       :: ngpts, nmaps
     179              :             REAL(KIND=C_DOUBLE), INTENT(IN), VALUE       :: scale
     180              :          END SUBROUTINE pw_gpu_sfffc_c
     181              :       END INTERFACE
     182              : 
     183            0 :       CALL timeset(routineN, handle)
     184              : 
     185            0 :       scale = 1.0_dp
     186              : 
     187            0 :       ngpts = SIZE(pw1%pw_grid%gsq)
     188              :       l1 = LBOUND(pw2%array, 1)
     189              :       l2 = LBOUND(pw2%array, 2)
     190              :       l3 = LBOUND(pw2%array, 3)
     191            0 :       npts => pw1%pw_grid%npts
     192              : 
     193              :       ! pointers to data arrays
     194            0 :       ptr_pwin => pw1%array(1)
     195            0 :       ptr_pwout => pw2%array(l1, l2, l3)
     196              : 
     197              :       ! pointer to map array
     198            0 :       nmaps = SIZE(pw1%pw_grid%g_hatmap, 2)
     199            0 :       ptr_ghatmap => pw1%pw_grid%g_hatmap(1, 1)
     200              : 
     201              :       ! invoke the combined transformation
     202              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
     203              :       CALL pw_gpu_sfffc_c(c_loc(ptr_pwin), c_loc(ptr_pwout), c_loc(ptr_ghatmap), npts, ngpts, nmaps, scale)
     204              : #else
     205            0 :       CPABORT("Compiled without pw offloading")
     206              : #endif
     207              : 
     208            0 :       CALL timestop(handle)
     209            0 :    END SUBROUTINE pw_gpu_c1dr3d_3d
     210              : 
     211              : ! **************************************************************************************************
     212              : !> \brief perform an parallel fft followed by a gather on the gpu
     213              : !> \param pw1 ...
     214              : !> \param pw2 ...
     215              : !> \author Andreas Gloess
     216              : ! **************************************************************************************************
     217            0 :    SUBROUTINE pw_gpu_r3dc1d_3d_ps(pw1, pw2)
     218              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: pw1
     219              :       TYPE(pw_c1d_gs_type), INTENT(INOUT)                :: pw2
     220              : 
     221              :       CHARACTER(len=*), PARAMETER :: routineN = 'pw_gpu_r3dc1d_3d_ps'
     222              : 
     223            0 :       COMPLEX(KIND=dp), DIMENSION(:, :), POINTER         :: grays, pbuf, qbuf, rbuf, sbuf
     224            0 :       COMPLEX(KIND=dp), DIMENSION(:, :, :), POINTER      :: tbuf
     225              :       INTEGER                                            :: g_pos, handle, lg, lmax, mg, mmax, mx2, &
     226              :                                                             mz2, n1, n2, ngpts, nmax, numtask, rp
     227            0 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: p2p
     228              :       INTEGER, DIMENSION(2)                              :: r_dim, r_pos
     229            0 :       INTEGER, DIMENSION(:), POINTER                     :: n, nloc, nyzray
     230            0 :       INTEGER, DIMENSION(:, :, :, :), POINTER            :: bo
     231              :       REAL(KIND=dp)                                      :: scale
     232            0 :       TYPE(fft_scratch_sizes)                            :: fft_scratch_size
     233              :       TYPE(fft_scratch_type), POINTER                    :: fft_scratch
     234            0 :       TYPE(mp_cart_type)                                 :: rs_group
     235              : 
     236            0 :       CALL timeset(routineN, handle)
     237              : 
     238            0 :       scale = 1.0_dp/REAL(pw1%pw_grid%ngpts, KIND=dp)
     239              : 
     240              :       ! dimensions
     241            0 :       n => pw1%pw_grid%npts
     242            0 :       nloc => pw1%pw_grid%npts_local
     243            0 :       grays => pw1%pw_grid%grays
     244            0 :       ngpts = nloc(1)*nloc(2)*nloc(3)
     245              : 
     246              :       !..transform
     247            0 :       IF (pw1%pw_grid%para%ray_distribution) THEN
     248            0 :          rs_group = pw1%pw_grid%para%group
     249            0 :          nyzray => pw1%pw_grid%para%nyzray
     250            0 :          bo => pw1%pw_grid%para%bo
     251              : 
     252            0 :          g_pos = rs_group%mepos
     253            0 :          numtask = rs_group%num_pe
     254            0 :          r_dim = rs_group%num_pe_cart
     255            0 :          r_pos = rs_group%mepos_cart
     256              : 
     257            0 :          lg = SIZE(grays, 1)
     258            0 :          mg = SIZE(grays, 2)
     259            0 :          mmax = MAX(mg, 1)
     260            0 :          lmax = MAX(lg, (ngpts/mmax + 1))
     261              : 
     262            0 :          ALLOCATE (p2p(0:numtask - 1))
     263              : 
     264            0 :          CALL rs_group%rank_compare(rs_group, p2p)
     265              : 
     266            0 :          rp = p2p(g_pos)
     267            0 :          mx2 = bo(2, 1, rp, 2) - bo(1, 1, rp, 2) + 1
     268            0 :          mz2 = bo(2, 3, rp, 2) - bo(1, 3, rp, 2) + 1
     269            0 :          n1 = MAXVAL(bo(2, 1, :, 1) - bo(1, 1, :, 1) + 1)
     270            0 :          n2 = MAXVAL(bo(2, 2, :, 1) - bo(1, 2, :, 1) + 1)
     271            0 :          nmax = MAX((2*n2)/numtask, 2)*mx2*mz2
     272            0 :          nmax = MAX(nmax, n1*MAXVAL(nyzray))
     273              : 
     274            0 :          fft_scratch_size%nx = nloc(1)
     275            0 :          fft_scratch_size%ny = nloc(2)
     276            0 :          fft_scratch_size%nz = nloc(3)
     277            0 :          fft_scratch_size%lmax = lmax
     278            0 :          fft_scratch_size%mmax = mmax
     279            0 :          fft_scratch_size%mx1 = bo(2, 1, rp, 1) - bo(1, 1, rp, 1) + 1
     280            0 :          fft_scratch_size%mx2 = mx2
     281            0 :          fft_scratch_size%my1 = bo(2, 2, rp, 1) - bo(1, 2, rp, 1) + 1
     282            0 :          fft_scratch_size%mz2 = mz2
     283            0 :          fft_scratch_size%lg = lg
     284            0 :          fft_scratch_size%mg = mg
     285            0 :          fft_scratch_size%nbx = MAXVAL(bo(2, 1, :, 2))
     286            0 :          fft_scratch_size%nbz = MAXVAL(bo(2, 3, :, 2))
     287            0 :          fft_scratch_size%mcz1 = MAXVAL(bo(2, 3, :, 1) - bo(1, 3, :, 1) + 1)
     288            0 :          fft_scratch_size%mcx2 = MAXVAL(bo(2, 1, :, 2) - bo(1, 1, :, 2) + 1)
     289            0 :          fft_scratch_size%mcz2 = MAXVAL(bo(2, 3, :, 2) - bo(1, 3, :, 2) + 1)
     290            0 :          fft_scratch_size%nmax = nmax
     291            0 :          fft_scratch_size%nmray = MAXVAL(nyzray)
     292            0 :          fft_scratch_size%nyzray = nyzray(g_pos)
     293            0 :          fft_scratch_size%rs_group = rs_group
     294            0 :          fft_scratch_size%g_pos = g_pos
     295            0 :          fft_scratch_size%r_pos = r_pos
     296            0 :          fft_scratch_size%r_dim = r_dim
     297            0 :          fft_scratch_size%numtask = numtask
     298              : 
     299            0 :          IF (r_dim(2) > 1) THEN
     300              :             !
     301              :             ! real space is distributed over x and y coordinate
     302              :             ! we have two stages of communication
     303              :             !
     304            0 :             IF (r_dim(1) == 1) THEN
     305            0 :                CPABORT("This processor distribution is not supported.")
     306              :             END IF
     307              : 
     308            0 :             CALL get_fft_scratch(fft_scratch, tf_type=300, n=n, fft_sizes=fft_scratch_size)
     309              : 
     310              :             ! assign buffers
     311            0 :             qbuf => fft_scratch%p2buf
     312            0 :             rbuf => fft_scratch%p3buf
     313            0 :             pbuf => fft_scratch%p4buf
     314            0 :             sbuf => fft_scratch%p5buf
     315              : 
     316              :             ! FFT along z
     317            0 :             CALL pw_gpu_cf(pw1, qbuf)
     318              : 
     319              :             ! Exchange data ( transpose of matrix )
     320            0 :             CALL cube_transpose_2(qbuf, bo(:, :, :, 1), bo(:, :, :, 2), rbuf, fft_scratch)
     321              : 
     322              :             ! FFT along y
     323              :             ! use the inbuild fft-lib
     324              :             ! CALL fft_1dm(fft_scratch%fft_plan(2), rbuf, pbuf, 1.0_dp, stat)
     325              :             ! or cufft (works faster, but is only faster if plans are stored)
     326            0 :             CALL pw_gpu_f(rbuf, pbuf, +1, n(2), mx2*mz2)
     327              : 
     328              :             ! Exchange data ( transpose of matrix ) and sort
     329              :             CALL xz_to_yz(pbuf, rs_group, r_dim, g_pos, p2p, pw1%pw_grid%para%yzp, nyzray, &
     330            0 :                           bo(:, :, :, 2), sbuf, fft_scratch)
     331              : 
     332              :             ! FFT along x
     333            0 :             CALL pw_gpu_fg(sbuf, pw2, scale)
     334              : 
     335            0 :             CALL release_fft_scratch(fft_scratch)
     336              : 
     337              :          ELSE
     338              :             !
     339              :             ! real space is only distributed over x coordinate
     340              :             ! we have one stage of communication, after the transform of
     341              :             ! direction x
     342              :             !
     343              : 
     344            0 :             CALL get_fft_scratch(fft_scratch, tf_type=200, n=n, fft_sizes=fft_scratch_size)
     345              : 
     346              :             ! assign buffers
     347            0 :             tbuf => fft_scratch%tbuf
     348            0 :             sbuf => fft_scratch%r1buf
     349              : 
     350              :             ! FFT along y and z
     351            0 :             CALL pw_gpu_cff(pw1, tbuf)
     352              : 
     353              :             ! Exchange data ( transpose of matrix ) and sort
     354              :             CALL yz_to_x(tbuf, rs_group, g_pos, p2p, pw1%pw_grid%para%yzp, nyzray, &
     355            0 :                          bo(:, :, :, 2), sbuf, fft_scratch)
     356              : 
     357              :             ! FFT along x
     358            0 :             CALL pw_gpu_fg(sbuf, pw2, scale)
     359              : 
     360            0 :             CALL release_fft_scratch(fft_scratch)
     361              : 
     362              :          END IF
     363              : 
     364            0 :          DEALLOCATE (p2p)
     365              : 
     366              : !--------------------------------------------------------------------------
     367              :       ELSE
     368            0 :          CPABORT("Not implemented (no ray_distr.) in: pw_gpu_r3dc1d_3d_ps.")
     369              :       END IF
     370              : 
     371            0 :       CALL timestop(handle)
     372            0 :    END SUBROUTINE pw_gpu_r3dc1d_3d_ps
     373              : 
     374              : ! **************************************************************************************************
     375              : !> \brief perform an parallel scatter followed by a fft on the gpu
     376              : !> \param pw1 ...
     377              : !> \param pw2 ...
     378              : !> \author Andreas Gloess
     379              : ! **************************************************************************************************
     380            0 :    SUBROUTINE pw_gpu_c1dr3d_3d_ps(pw1, pw2)
     381              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: pw1
     382              :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                :: pw2
     383              : 
     384              :       CHARACTER(len=*), PARAMETER :: routineN = 'pw_gpu_c1dr3d_3d_ps'
     385              : 
     386            0 :       COMPLEX(KIND=dp), DIMENSION(:, :), POINTER         :: grays, pbuf, qbuf, rbuf, sbuf
     387            0 :       COMPLEX(KIND=dp), DIMENSION(:, :, :), POINTER      :: tbuf
     388              :       INTEGER                                            :: g_pos, handle, lg, lmax, mg, mmax, mx2, &
     389              :                                                             mz2, n1, n2, ngpts, nmax, numtask, rp
     390            0 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: p2p
     391              :       INTEGER, DIMENSION(2)                              :: r_dim, r_pos
     392            0 :       INTEGER, DIMENSION(:), POINTER                     :: n, nloc, nyzray
     393            0 :       INTEGER, DIMENSION(:, :, :, :), POINTER            :: bo
     394              :       REAL(KIND=dp)                                      :: scale
     395            0 :       TYPE(fft_scratch_sizes)                            :: fft_scratch_size
     396              :       TYPE(fft_scratch_type), POINTER                    :: fft_scratch
     397            0 :       TYPE(mp_cart_type)                                 :: rs_group
     398              : 
     399            0 :       CALL timeset(routineN, handle)
     400              : 
     401            0 :       scale = 1.0_dp
     402              : 
     403              :       ! dimensions
     404            0 :       n => pw1%pw_grid%npts
     405            0 :       nloc => pw1%pw_grid%npts_local
     406            0 :       grays => pw1%pw_grid%grays
     407            0 :       ngpts = nloc(1)*nloc(2)*nloc(3)
     408              : 
     409              :       !..transform
     410            0 :       IF (pw1%pw_grid%para%ray_distribution) THEN
     411            0 :          rs_group = pw1%pw_grid%para%group
     412            0 :          nyzray => pw1%pw_grid%para%nyzray
     413            0 :          bo => pw1%pw_grid%para%bo
     414              : 
     415            0 :          g_pos = rs_group%mepos
     416            0 :          numtask = rs_group%num_pe
     417            0 :          r_dim = rs_group%num_pe_cart
     418            0 :          r_pos = rs_group%mepos_cart
     419              : 
     420            0 :          lg = SIZE(grays, 1)
     421            0 :          mg = SIZE(grays, 2)
     422            0 :          mmax = MAX(mg, 1)
     423            0 :          lmax = MAX(lg, (ngpts/mmax + 1))
     424              : 
     425            0 :          ALLOCATE (p2p(0:numtask - 1))
     426              : 
     427            0 :          CALL rs_group%rank_compare(rs_group, p2p)
     428              : 
     429            0 :          rp = p2p(g_pos)
     430            0 :          mx2 = bo(2, 1, rp, 2) - bo(1, 1, rp, 2) + 1
     431            0 :          mz2 = bo(2, 3, rp, 2) - bo(1, 3, rp, 2) + 1
     432            0 :          n1 = MAXVAL(bo(2, 1, :, 1) - bo(1, 1, :, 1) + 1)
     433            0 :          n2 = MAXVAL(bo(2, 2, :, 1) - bo(1, 2, :, 1) + 1)
     434            0 :          nmax = MAX((2*n2)/numtask, 2)*mx2*mz2
     435            0 :          nmax = MAX(nmax, n1*MAXVAL(nyzray))
     436              : 
     437            0 :          fft_scratch_size%nx = nloc(1)
     438            0 :          fft_scratch_size%ny = nloc(2)
     439            0 :          fft_scratch_size%nz = nloc(3)
     440            0 :          fft_scratch_size%lmax = lmax
     441            0 :          fft_scratch_size%mmax = mmax
     442            0 :          fft_scratch_size%mx1 = bo(2, 1, rp, 1) - bo(1, 1, rp, 1) + 1
     443            0 :          fft_scratch_size%mx2 = mx2
     444            0 :          fft_scratch_size%my1 = bo(2, 2, rp, 1) - bo(1, 2, rp, 1) + 1
     445            0 :          fft_scratch_size%mz2 = mz2
     446            0 :          fft_scratch_size%lg = lg
     447            0 :          fft_scratch_size%mg = mg
     448            0 :          fft_scratch_size%nbx = MAXVAL(bo(2, 1, :, 2))
     449            0 :          fft_scratch_size%nbz = MAXVAL(bo(2, 3, :, 2))
     450            0 :          fft_scratch_size%mcz1 = MAXVAL(bo(2, 3, :, 1) - bo(1, 3, :, 1) + 1)
     451            0 :          fft_scratch_size%mcx2 = MAXVAL(bo(2, 1, :, 2) - bo(1, 1, :, 2) + 1)
     452            0 :          fft_scratch_size%mcz2 = MAXVAL(bo(2, 3, :, 2) - bo(1, 3, :, 2) + 1)
     453            0 :          fft_scratch_size%nmax = nmax
     454            0 :          fft_scratch_size%nmray = MAXVAL(nyzray)
     455            0 :          fft_scratch_size%nyzray = nyzray(g_pos)
     456            0 :          fft_scratch_size%rs_group = rs_group
     457            0 :          fft_scratch_size%g_pos = g_pos
     458            0 :          fft_scratch_size%r_pos = r_pos
     459            0 :          fft_scratch_size%r_dim = r_dim
     460            0 :          fft_scratch_size%numtask = numtask
     461              : 
     462            0 :          IF (r_dim(2) > 1) THEN
     463              :             !
     464              :             ! real space is distributed over x and y coordinate
     465              :             ! we have two stages of communication
     466              :             !
     467            0 :             IF (r_dim(1) == 1) THEN
     468            0 :                CPABORT("This processor distribution is not supported.")
     469              :             END IF
     470              : 
     471            0 :             CALL get_fft_scratch(fft_scratch, tf_type=300, n=n, fft_sizes=fft_scratch_size)
     472              : 
     473              :             ! assign buffers
     474            0 :             pbuf => fft_scratch%p7buf
     475            0 :             qbuf => fft_scratch%p4buf
     476            0 :             rbuf => fft_scratch%p3buf
     477            0 :             sbuf => fft_scratch%p2buf
     478              : 
     479              :             ! FFT along x
     480            0 :             CALL pw_gpu_sf(pw1, pbuf, scale)
     481              : 
     482              :             ! Exchange data ( transpose of matrix ) and sort
     483            0 :             IF (pw1%pw_grid%grid_span /= FULLSPACE) qbuf = z_zero
     484              :             CALL yz_to_xz(pbuf, rs_group, r_dim, g_pos, p2p, pw1%pw_grid%para%yzp, nyzray, &
     485            0 :                           bo(:, :, :, 2), qbuf, fft_scratch)
     486              : 
     487              :             ! FFT along y
     488              :             ! use the inbuild fft-lib
     489              :             ! CALL fft_1dm(fft_scratch%fft_plan(5), qbuf, rbuf, 1.0_dp, stat)
     490              :             ! or cufft (works faster, but is only faster if plans are stored)
     491            0 :             CALL pw_gpu_f(qbuf, rbuf, -1, n(2), mx2*mz2)
     492              : 
     493              :             ! Exchange data ( transpose of matrix )
     494            0 :             IF (pw1%pw_grid%grid_span /= FULLSPACE) sbuf = z_zero
     495              : 
     496            0 :             CALL cube_transpose_1(rbuf, bo(:, :, :, 2), bo(:, :, :, 1), sbuf, fft_scratch)
     497              : 
     498              :             ! FFT along z
     499            0 :             CALL pw_gpu_fc(sbuf, pw2)
     500              : 
     501            0 :             CALL release_fft_scratch(fft_scratch)
     502              : 
     503              :          ELSE
     504              :             !
     505              :             ! real space is only distributed over x coordinate
     506              :             ! we have one stage of communication, after the transform of
     507              :             ! direction x
     508              :             !
     509              : 
     510            0 :             CALL get_fft_scratch(fft_scratch, tf_type=200, n=n, fft_sizes=fft_scratch_size)
     511              : 
     512              :             ! assign buffers
     513            0 :             sbuf => fft_scratch%r1buf
     514            0 :             tbuf => fft_scratch%tbuf
     515              : 
     516              :             ! FFT along x
     517            0 :             CALL pw_gpu_sf(pw1, sbuf, scale)
     518              : 
     519              :             ! Exchange data ( transpose of matrix ) and sort
     520            0 :             IF (pw1%pw_grid%grid_span /= FULLSPACE) tbuf = z_zero
     521              :             CALL x_to_yz(sbuf, rs_group, g_pos, p2p, pw1%pw_grid%para%yzp, nyzray, &
     522            0 :                          bo(:, :, :, 2), tbuf, fft_scratch)
     523              : 
     524              :             ! FFT along y and z
     525            0 :             CALL pw_gpu_ffc(tbuf, pw2)
     526              : 
     527            0 :             CALL release_fft_scratch(fft_scratch)
     528              : 
     529              :          END IF
     530              : 
     531            0 :          DEALLOCATE (p2p)
     532              : 
     533              : !--------------------------------------------------------------------------
     534              :       ELSE
     535            0 :          CPABORT("Not implemented (no ray_distr.) in: pw_gpu_c1dr3d_3d_ps.")
     536              :       END IF
     537              : 
     538            0 :       CALL timestop(handle)
     539            0 :    END SUBROUTINE pw_gpu_c1dr3d_3d_ps
     540              : 
     541              : ! **************************************************************************************************
     542              : !> \brief perform a parallel real_to_complex copy followed by a 2D-FFT on the gpu
     543              : !> \param pw1 ...
     544              : !> \param pwbuf ...
     545              : !> \author Andreas Gloess
     546              : ! **************************************************************************************************
     547            0 :    SUBROUTINE pw_gpu_cff(pw1, pwbuf)
     548              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: pw1
     549              :       COMPLEX(KIND=dp), DIMENSION(:, :, :), &
     550              :          INTENT(INOUT), TARGET                           :: pwbuf
     551              : 
     552              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_gpu_cff'
     553              : 
     554              :       COMPLEX(KIND=dp), POINTER                          :: ptr_pwout
     555              :       INTEGER                                            :: handle, l1, l2, l3
     556            0 :       INTEGER, DIMENSION(:), POINTER                     :: npts
     557              :       REAL(KIND=dp), POINTER                             :: ptr_pwin
     558              :       INTERFACE
     559              :          SUBROUTINE pw_gpu_cff_c(din, zout, npts) BIND(C, name="pw_gpu_cff")
     560              :             IMPORT
     561              :             TYPE(C_PTR), INTENT(IN), VALUE               :: din
     562              :             TYPE(C_PTR), VALUE                           :: zout
     563              :             INTEGER(KIND=C_INT), DIMENSION(*), INTENT(IN):: npts
     564              :          END SUBROUTINE pw_gpu_cff_c
     565              :       END INTERFACE
     566              : 
     567            0 :       CALL timeset(routineN, handle)
     568              : 
     569              :       ! dimensions
     570            0 :       npts => pw1%pw_grid%npts_local
     571              :       l1 = LBOUND(pw1%array, 1)
     572              :       l2 = LBOUND(pw1%array, 2)
     573              :       l3 = LBOUND(pw1%array, 3)
     574              : 
     575              :       ! pointers to data arrays
     576            0 :       ptr_pwin => pw1%array(l1, l2, l3)
     577            0 :       ptr_pwout => pwbuf(1, 1, 1)
     578              : 
     579              :       ! invoke the combined transformation
     580              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
     581              :       CALL pw_gpu_cff_c(c_loc(ptr_pwin), c_loc(ptr_pwout), npts)
     582              : #else
     583            0 :       CPABORT("Compiled without pw offloading")
     584              : #endif
     585              : 
     586            0 :       CALL timestop(handle)
     587            0 :    END SUBROUTINE pw_gpu_cff
     588              : 
     589              : ! **************************************************************************************************
     590              : !> \brief perform a parallel 2D-FFT followed by a complex_to_real copy on the gpu
     591              : !> \param pwbuf ...
     592              : !> \param pw2 ...
     593              : !> \author Andreas Gloess
     594              : ! **************************************************************************************************
     595            0 :    SUBROUTINE pw_gpu_ffc(pwbuf, pw2)
     596              :       COMPLEX(KIND=dp), DIMENSION(:, :, :), INTENT(IN), &
     597              :          TARGET                                          :: pwbuf
     598              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: pw2
     599              : 
     600              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_gpu_ffc'
     601              : 
     602              :       COMPLEX(KIND=dp), POINTER                          :: ptr_pwin
     603              :       INTEGER                                            :: handle, l1, l2, l3
     604            0 :       INTEGER, DIMENSION(:), POINTER                     :: npts
     605              :       REAL(KIND=dp), POINTER                             :: ptr_pwout
     606              :       INTERFACE
     607              :          SUBROUTINE pw_gpu_ffc_c(zin, dout, npts) BIND(C, name="pw_gpu_ffc")
     608              :             IMPORT
     609              :             TYPE(C_PTR), INTENT(IN), VALUE               :: zin
     610              :             TYPE(C_PTR), VALUE                           :: dout
     611              :             INTEGER(KIND=C_INT), DIMENSION(*), INTENT(IN):: npts
     612              :          END SUBROUTINE pw_gpu_ffc_c
     613              :       END INTERFACE
     614              : 
     615            0 :       CALL timeset(routineN, handle)
     616              : 
     617              :       ! dimensions
     618            0 :       npts => pw2%pw_grid%npts_local
     619              :       l1 = LBOUND(pw2%array, 1)
     620              :       l2 = LBOUND(pw2%array, 2)
     621              :       l3 = LBOUND(pw2%array, 3)
     622              : 
     623              :       ! pointers to data arrays
     624            0 :       ptr_pwin => pwbuf(1, 1, 1)
     625            0 :       ptr_pwout => pw2%array(l1, l2, l3)
     626              : 
     627              :       ! invoke the combined transformation
     628              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
     629              :       CALL pw_gpu_ffc_c(c_loc(ptr_pwin), c_loc(ptr_pwout), npts)
     630              : #else
     631            0 :       CPABORT("Compiled without pw offloading")
     632              : #endif
     633              : 
     634            0 :       CALL timestop(handle)
     635            0 :    END SUBROUTINE pw_gpu_ffc
     636              : 
     637              : ! **************************************************************************************************
     638              : !> \brief perform a parallel real_to_complex copy followed by a 1D-FFT on the gpu
     639              : !> \param pw1 ...
     640              : !> \param pwbuf ...
     641              : !> \author Andreas Gloess
     642              : ! **************************************************************************************************
     643            0 :    SUBROUTINE pw_gpu_cf(pw1, pwbuf)
     644              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: pw1
     645              :       COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(INOUT), &
     646              :          TARGET                                          :: pwbuf
     647              : 
     648              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_gpu_cf'
     649              : 
     650              :       COMPLEX(KIND=dp), POINTER                          :: ptr_pwout
     651              :       INTEGER                                            :: handle, l1, l2, l3
     652            0 :       INTEGER, DIMENSION(:), POINTER                     :: npts
     653              :       REAL(KIND=dp), POINTER                             :: ptr_pwin
     654              :       INTERFACE
     655              :          SUBROUTINE pw_gpu_cf_c(din, zout, npts) BIND(C, name="pw_gpu_cf")
     656              :             IMPORT
     657              :             TYPE(C_PTR), INTENT(IN), VALUE               :: din
     658              :             TYPE(C_PTR), VALUE                           :: zout
     659              :             INTEGER(KIND=C_INT), DIMENSION(*), INTENT(IN):: npts
     660              :          END SUBROUTINE pw_gpu_cf_c
     661              :       END INTERFACE
     662              : 
     663            0 :       CALL timeset(routineN, handle)
     664              : 
     665              :       ! dimensions
     666            0 :       npts => pw1%pw_grid%npts_local
     667              :       l1 = LBOUND(pw1%array, 1)
     668              :       l2 = LBOUND(pw1%array, 2)
     669              :       l3 = LBOUND(pw1%array, 3)
     670              : 
     671              :       ! pointers to data arrays
     672            0 :       ptr_pwin => pw1%array(l1, l2, l3)
     673            0 :       ptr_pwout => pwbuf(1, 1)
     674              : 
     675              :       ! invoke the combined transformation
     676              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
     677              :       CALL pw_gpu_cf_c(c_loc(ptr_pwin), c_loc(ptr_pwout), npts)
     678              : #else
     679            0 :       CPABORT("Compiled without pw offloading")
     680              : #endif
     681            0 :       CALL timestop(handle)
     682            0 :    END SUBROUTINE pw_gpu_cf
     683              : 
     684              : ! **************************************************************************************************
     685              : !> \brief perform a parallel 1D-FFT followed by a complex_to_real copy on the gpu
     686              : !> \param pwbuf ...
     687              : !> \param pw2 ...
     688              : !> \author Andreas Gloess
     689              : ! **************************************************************************************************
     690            0 :    SUBROUTINE pw_gpu_fc(pwbuf, pw2)
     691              :       COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(IN), &
     692              :          TARGET                                          :: pwbuf
     693              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: pw2
     694              : 
     695              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_gpu_fc'
     696              : 
     697              :       COMPLEX(KIND=dp), POINTER                          :: ptr_pwin
     698              :       INTEGER                                            :: handle, l1, l2, l3
     699            0 :       INTEGER, DIMENSION(:), POINTER                     :: npts
     700              :       REAL(KIND=dp), POINTER                             :: ptr_pwout
     701              :       INTERFACE
     702              :          SUBROUTINE pw_gpu_fc_c(zin, dout, npts) BIND(C, name="pw_gpu_fc")
     703              :             IMPORT
     704              :             TYPE(C_PTR), INTENT(IN), VALUE               :: zin
     705              :             TYPE(C_PTR), VALUE                           :: dout
     706              :             INTEGER(KIND=C_INT), DIMENSION(*), INTENT(IN):: npts
     707              :          END SUBROUTINE pw_gpu_fc_c
     708              :       END INTERFACE
     709              : 
     710            0 :       CALL timeset(routineN, handle)
     711              : 
     712            0 :       npts => pw2%pw_grid%npts_local
     713              :       l1 = LBOUND(pw2%array, 1)
     714              :       l2 = LBOUND(pw2%array, 2)
     715              :       l3 = LBOUND(pw2%array, 3)
     716              : 
     717              :       ! pointers to data arrays
     718            0 :       ptr_pwin => pwbuf(1, 1)
     719            0 :       ptr_pwout => pw2%array(l1, l2, l3)
     720              : 
     721              :       ! invoke the combined transformation
     722              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
     723              :       CALL pw_gpu_fc_c(c_loc(ptr_pwin), c_loc(ptr_pwout), npts)
     724              : #else
     725            0 :       CPABORT("Compiled without pw offloading")
     726              : #endif
     727              : 
     728            0 :       CALL timestop(handle)
     729            0 :    END SUBROUTINE pw_gpu_fc
     730              : 
     731              : ! **************************************************************************************************
     732              : !> \brief perform a parallel 1D-FFT on the gpu
     733              : !> \param pwbuf1 ...
     734              : !> \param pwbuf2 ...
     735              : !> \param dir ...
     736              : !> \param n ...
     737              : !> \param m ...
     738              : !> \author Andreas Gloess
     739              : ! **************************************************************************************************
     740            0 :    SUBROUTINE pw_gpu_f(pwbuf1, pwbuf2, dir, n, m)
     741              :       COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(IN), &
     742              :          TARGET                                          :: pwbuf1
     743              :       COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(INOUT), &
     744              :          TARGET                                          :: pwbuf2
     745              :       INTEGER, INTENT(IN)                                :: dir, n, m
     746              : 
     747              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_gpu_f'
     748              : 
     749              :       COMPLEX(KIND=dp), POINTER                          :: ptr_pwin, ptr_pwout
     750              :       INTEGER                                            :: handle
     751              :       INTERFACE
     752              :          SUBROUTINE pw_gpu_f_c(zin, zout, dir, n, m) BIND(C, name="pw_gpu_f")
     753              :             IMPORT
     754              :             TYPE(C_PTR), INTENT(IN), VALUE               :: zin
     755              :             TYPE(C_PTR), VALUE                           :: zout
     756              :             INTEGER(KIND=C_INT), INTENT(IN), VALUE       :: dir, n, m
     757              :          END SUBROUTINE pw_gpu_f_c
     758              :       END INTERFACE
     759              : 
     760            0 :       CALL timeset(routineN, handle)
     761              : 
     762            0 :       IF (n*m /= 0) THEN
     763              :          ! pointers to data arrays
     764            0 :          ptr_pwin => pwbuf1(1, 1)
     765            0 :          ptr_pwout => pwbuf2(1, 1)
     766              : 
     767              :          ! invoke the combined transformation
     768              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
     769              :          CALL pw_gpu_f_c(c_loc(ptr_pwin), c_loc(ptr_pwout), dir, n, m)
     770              : #else
     771              :          MARK_USED(dir)
     772            0 :          CPABORT("Compiled without pw offloading")
     773              : #endif
     774              :       END IF
     775              : 
     776            0 :       CALL timestop(handle)
     777            0 :    END SUBROUTINE pw_gpu_f
     778              : ! **************************************************************************************************
     779              : !> \brief perform a parallel 1D-FFT followed by a gather on the gpu
     780              : !> \param pwbuf ...
     781              : !> \param pw2 ...
     782              : !> \param scale ...
     783              : !> \author Andreas Gloess
     784              : ! **************************************************************************************************
     785            0 :    SUBROUTINE pw_gpu_fg(pwbuf, pw2, scale)
     786              :       COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(IN), &
     787              :          TARGET                                          :: pwbuf
     788              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: pw2
     789              :       REAL(KIND=dp), INTENT(IN)                          :: scale
     790              : 
     791              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_gpu_fg'
     792              : 
     793              :       COMPLEX(KIND=dp), POINTER                          :: ptr_pwin, ptr_pwout
     794              :       INTEGER                                            :: handle, mg, mmax, ngpts
     795            0 :       INTEGER, DIMENSION(:), POINTER                     :: npts
     796              :       INTEGER, POINTER                                   :: ptr_ghatmap
     797              :       INTERFACE
     798              :          SUBROUTINE pw_gpu_fg_c(zin, zout, ghatmap, npts, mmax, ngpts, scale) BIND(C, name="pw_gpu_fg")
     799              :             IMPORT
     800              :             TYPE(C_PTR), INTENT(IN), VALUE               :: zin
     801              :             TYPE(C_PTR), VALUE                           :: zout
     802              :             TYPE(C_PTR), INTENT(IN), VALUE               :: ghatmap
     803              :             INTEGER(KIND=C_INT), DIMENSION(*), INTENT(IN):: npts
     804              :             INTEGER(KIND=C_INT), INTENT(IN), VALUE       :: mmax, ngpts
     805              :             REAL(KIND=C_DOUBLE), INTENT(IN), VALUE       :: scale
     806              : 
     807              :          END SUBROUTINE pw_gpu_fg_c
     808              :       END INTERFACE
     809              : 
     810            0 :       CALL timeset(routineN, handle)
     811              : 
     812            0 :       ngpts = SIZE(pw2%pw_grid%gsq)
     813            0 :       npts => pw2%pw_grid%npts
     814              : 
     815            0 :       IF ((npts(1) /= 0) .AND. (ngpts /= 0)) THEN
     816            0 :          mg = SIZE(pw2%pw_grid%grays, 2)
     817            0 :          mmax = MAX(mg, 1)
     818              : 
     819              :          ! pointers to data arrays
     820            0 :          ptr_pwin => pwbuf(1, 1)
     821            0 :          ptr_pwout => pw2%array(1)
     822              : 
     823              :          ! pointer to map array
     824            0 :          ptr_ghatmap => pw2%pw_grid%g_hatmap(1, 1)
     825              : 
     826              :          ! invoke the combined transformation
     827              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
     828              :          CALL pw_gpu_fg_c(c_loc(ptr_pwin), c_loc(ptr_pwout), c_loc(ptr_ghatmap), npts, mmax, ngpts, scale)
     829              : #else
     830              :          MARK_USED(scale)
     831            0 :          CPABORT("Compiled without pw offloading")
     832              : #endif
     833              :       END IF
     834              : 
     835            0 :       CALL timestop(handle)
     836            0 :    END SUBROUTINE pw_gpu_fg
     837              : 
     838              : ! **************************************************************************************************
     839              : !> \brief perform a parallel scatter followed by a 1D-FFT on the gpu
     840              : !> \param pw1 ...
     841              : !> \param pwbuf ...
     842              : !> \param scale ...
     843              : !> \author Andreas Gloess
     844              : ! **************************************************************************************************
     845            0 :    SUBROUTINE pw_gpu_sf(pw1, pwbuf, scale)
     846              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: pw1
     847              :       COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(INOUT), &
     848              :          TARGET                                          :: pwbuf
     849              :       REAL(KIND=dp), INTENT(IN)                          :: scale
     850              : 
     851              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_gpu_sf'
     852              : 
     853              :       COMPLEX(KIND=dp), POINTER                          :: ptr_pwin, ptr_pwout
     854              :       INTEGER                                            :: handle, mg, mmax, ngpts, nmaps
     855            0 :       INTEGER, DIMENSION(:), POINTER                     :: npts
     856              :       INTEGER, POINTER                                   :: ptr_ghatmap
     857              :       INTERFACE
     858              :          SUBROUTINE pw_gpu_sf_c(zin, zout, ghatmap, npts, mmax, ngpts, nmaps, scale) BIND(C, name="pw_gpu_sf")
     859              :             IMPORT
     860              :             TYPE(C_PTR), INTENT(IN), VALUE               :: zin
     861              :             TYPE(C_PTR), VALUE                           :: zout
     862              :             TYPE(C_PTR), INTENT(IN), VALUE               :: ghatmap
     863              :             INTEGER(KIND=C_INT), DIMENSION(*), INTENT(IN):: npts
     864              :             INTEGER(KIND=C_INT), INTENT(IN), VALUE       :: mmax, ngpts, nmaps
     865              :             REAL(KIND=C_DOUBLE), INTENT(IN), VALUE       :: scale
     866              : 
     867              :          END SUBROUTINE pw_gpu_sf_c
     868              :       END INTERFACE
     869              : 
     870            0 :       CALL timeset(routineN, handle)
     871              : 
     872            0 :       ngpts = SIZE(pw1%pw_grid%gsq)
     873            0 :       npts => pw1%pw_grid%npts
     874              : 
     875            0 :       IF ((npts(1) /= 0) .AND. (ngpts /= 0)) THEN
     876            0 :          mg = SIZE(pw1%pw_grid%grays, 2)
     877            0 :          mmax = MAX(mg, 1)
     878              : 
     879              :          ! pointers to data arrays
     880            0 :          ptr_pwin => pw1%array(1)
     881            0 :          ptr_pwout => pwbuf(1, 1)
     882              : 
     883              :          ! pointer to map array
     884            0 :          nmaps = SIZE(pw1%pw_grid%g_hatmap, 2)
     885            0 :          ptr_ghatmap => pw1%pw_grid%g_hatmap(1, 1)
     886              : 
     887              :          ! invoke the combined transformation
     888              : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
     889              :          CALL pw_gpu_sf_c(c_loc(ptr_pwin), c_loc(ptr_pwout), c_loc(ptr_ghatmap), npts, mmax, ngpts, nmaps, scale)
     890              : #else
     891              :          MARK_USED(scale)
     892            0 :          CPABORT("Compiled without pw offloading")
     893              : #endif
     894              :       END IF
     895              : 
     896            0 :       CALL timestop(handle)
     897            0 :    END SUBROUTINE pw_gpu_sf
     898              : 
     899              : END MODULE pw_gpu
     900              : 
        

Generated by: LCOV version 2.0-1