LCOV - code coverage report
Current view: top level - src/46_ghc_omp - m_ompgpu_fourwf.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 15 0
Test Date: 2026-09-21 22:40:37 Functions: 0.0 % 5 0

            Line data    Source code
       1              : !!****m* ABINIT/m_ompgpu_fourwf
       2              : !! NAME
       3              : !!  m_ompgpu_fourwf
       4              : !!
       5              : !! FUNCTION
       6              : !!  Fake module to dupe the build system and allow it to include cuda files
       7              : !!   in the chain of dependencies.
       8              : !!
       9              : !! COPYRIGHT
      10              : !!  Copyright (C) 2000-2026 ABINIT group (MT)
      11              : !!  This file is distributed under the terms of the
      12              : !!  GNU General Public License, see ~abinit/COPYING
      13              : !!  or http://www.gnu.org/copyleft/gpl.txt .
      14              : !!
      15              : !! SOURCE
      16              : 
      17              : #if defined HAVE_CONFIG_H
      18              : #include "config.h"
      19              : #endif
      20              : 
      21              : #include "abi_common.h"
      22              : 
      23              : module m_ompgpu_fourwf
      24              : 
      25              :  use defs_basis
      26              :  use m_abicore
      27              :  use m_gputk
      28              :  use m_abi_linalg
      29              :  use m_errors
      30              :  use m_xomp
      31              :  use iso_c_binding
      32              : 
      33              : #ifdef HAVE_GPU
      34              :  use m_gpu_toolbox
      35              : #endif
      36              : 
      37              :  implicit none
      38              : 
      39              :  private
      40              : 
      41              : #ifdef HAVE_OPENMP_OFFLOAD
      42              : 
      43              : ! STATIC vars to avoid too much cuda overhead
      44              : integer :: fourdp_initialized=0
      45              : integer :: fourwf_initialized=0
      46              : 
      47              : #define FOURDP_ID 1
      48              : #define FOURWF_ID 0
      49              : 
      50              : ! FFT plans
      51              : integer :: fft_size_fourdp=-1
      52              : integer :: ndat_fourdp=-1
      53              : integer :: fft_size_fourwf=-1
      54              : integer :: ndat_fourwf=-1
      55              : 
      56              : #endif
      57              : 
      58              :  public :: ompgpu_fourdp
      59              :  !public :: alloc_ompgpu_fourdp
      60              :  !public :: free_ompgpu_fourdp
      61              :  public :: ompgpu_fourwf
      62              :  public :: alloc_ompgpu_fourwf
      63              :  public :: free_ompgpu_fourwf
      64              : 
      65              :  ! This routine is here to assess memory requirements
      66              :  public :: ompgpu_fourwf_work_mem
      67              : contains
      68              : 
      69            0 : function ompgpu_fourwf_work_mem(ngfft, ndat) result(req_mem)
      70              : 
      71              :  integer, intent(in) :: ngfft(:), ndat
      72              :  integer(kind=c_size_t) :: req_mem
      73              : 
      74            0 :  req_mem = int(2, c_size_t) * dp * ngfft(1) * ngfft(2) * ngfft(3) * ndat
      75              : 
      76            0 : end function ompgpu_fourwf_work_mem
      77              : 
      78              : !Tested usecases :
      79              : ! - Nvidia GPUs : FC_NVHPC + CUDA
      80              : ! - AMD GPUs    : FC_LLVM + HIP
      81              : ! An eventual Intel implementation would use the OneAPI LLVM compiler.
      82              : ! Homemade CUDA/HIP interfaces would allow the use of GCC.
      83              : ! But it is likely that OpenMP performance won't be optimal outside GPU vendors compilers.
      84              : #ifdef HAVE_OPENMP_OFFLOAD
      85              : 
      86              : subroutine ompgpu_fourdp(cplex,ngfft,ldx,ldy,ldz,ndat,isign,fofg,fofr)
      87              : 
      88              : !Arguments ------------------------------------
      89              : !scalars
      90              :  integer,intent(in) :: cplex,ngfft(18),ldx,ldy,ldz,ndat,isign
      91              : !arrays
      92              :  real(dp),target,intent(inout) :: fofg(2*ldx*ldy*ldz*ndat)
      93              :  real(dp),target,intent(inout) :: fofr(cplex*ldx*ldy*ldz*ndat)
      94              : 
      95              : !Local variables-------------------------------
      96              : !scalars
      97              :  integer      :: n1,n2,n3,nfft_tot
      98              :  complex(dp) :: norm
      99              :  logical      :: transfer_fofr, transfer_fofg
     100              :  character(len=500) :: msg
     101              : ! *************************************************************************
     102              : 
     103              :  n1=ngfft(1);
     104              :  n2=ngfft(2);
     105              :  n3=ngfft(3);
     106              :  nfft_tot=n1*n2*n3;
     107              :  norm=dcmplx(one/(n1*n2*n3), 0.0_dp)
     108              : 
     109              :  !*********** CHECK some compatibilities **************
     110              :  if( (n1/=ldx) .or. (n2/=ldy) .or. (n3/=ldz)) then
     111              :    write(msg,"(a,a,i5,i5,i5,a,i5,i5,i5,a)") "FFT SIZE ERROR: \n when gpu mode is on the fft grid must not be augmented",&
     112              :     "(n1,n2,n3) = (", n1,n2,n3,") whereas (ldx,ldy,ldz) = (", ldx,ldy,ldz, ")"
     113              :    ABI_ERROR(msg)
     114              :  end if
     115              : 
     116              :  ! ***********  GPU ALLOCATIONS  ***********************
     117              : 
     118              :  if (fourdp_initialized == 0) then
     119              :    call alloc_ompgpu_fourdp(ngfft,ndat)
     120              :  endif !end of initialisation
     121              : 
     122              :  ! If fft size has changed, we realloc our buffers
     123              :  if((nfft_tot/=fft_size_fourdp) .or. (ndat/=ndat_fourdp)) then
     124              :    call free_ompgpu_fourdp()
     125              :    call alloc_ompgpu_fourdp(ngfft,ndat)
     126              :  end if !end if "fft size changed"
     127              : 
     128              :  transfer_fofg=   .not. xomp_target_is_present(c_loc(fofg))
     129              :  transfer_fofr=   .not. xomp_target_is_present(c_loc(fofr))
     130              : 
     131              :  !$OMP TARGET ENTER DATA MAP(alloc:fofg)    IF(transfer_fofg)
     132              :  !$OMP TARGET ENTER DATA MAP(alloc:fofr)    IF(transfer_fofr)
     133              :  !$OMP TARGET UPDATE TO(fofg) IF(transfer_fofg .and. isign==FFT_INVERSE)
     134              :  !$OMP TARGET UPDATE TO(fofr) IF(transfer_fofr .and. isign==FFT_FORWARD)
     135              : 
     136              :  select case (cplex)
     137              :  case (2)
     138              :    ! Complex to Complex.
     139              :    select case (isign)
     140              :    case (FFT_INVERSE) ! +1
     141              :      !$OMP TARGET DATA USE_DEVICE_ADDR(fofg,fofr)
     142              :      call gpu_fft_exec_z2z(FOURDP_ID, c_loc(fofg), c_loc(fofr), FFT_INVERSE)
     143              :      !$OMP END TARGET DATA
     144              :      call gpu_fft_stream_synchronize(FOURDP_ID)
     145              :    case (FFT_FORWARD) ! -1
     146              :      !$OMP TARGET DATA USE_DEVICE_ADDR(fofg,fofr)
     147              :      call gpu_fft_exec_z2z(FOURDP_ID, c_loc(fofr), c_loc(fofg), FFT_FORWARD)
     148              :      !$OMP END TARGET DATA
     149              :      call gpu_fft_stream_synchronize(FOURDP_ID)
     150              :      ! Normalize here
     151              :      call abi_xscal(ldx*ldy*ldz*ndat,norm,fofg,1,x_cplx=2,gpu_option=ABI_GPU_OPENMP)
     152              :    case default
     153              :      ABI_BUG("Wrong isign")
     154              :    end select
     155              :  case (1)
     156              :    ! Real case.
     157              :    ABI_BUG("Real case for OpenMP GPU fourdp not handled yet !")
     158              :    !select case (isign)
     159              :    !case (ABI_FFTW_BACKWARD) ! +1
     160              :    !  ! +1; G --> R
     161              :    !  call fftw3_c2r_op(nx,ny,nz,ldx,ldy,ldz,ndat,fofg,fofr)
     162              :    !case (ABI_FFTW_FORWARD)  ! -1
     163              :    !  ! -1; R --> G
     164              :    !  call fftw3_r2c_op(nx,ny,nz,ldx,ldy,ldz,ndat,fofr,fofg)
     165              :    !case default
     166              :    !  ABI_BUG("Wrong isign")
     167              :    !end select
     168              :  end select
     169              : 
     170              :  !$OMP TARGET UPDATE FROM(fofg) IF(transfer_fofg .and. isign==FFT_FORWARD)
     171              :  !$OMP TARGET UPDATE FROM(fofr) IF(transfer_fofr .and. isign==FFT_INVERSE)
     172              :  !$OMP TARGET EXIT DATA MAP(delete:fofg)    IF(transfer_fofg)
     173              :  !$OMP TARGET EXIT DATA MAP(delete:fofr)    IF(transfer_fofr)
     174              : 
     175              : end subroutine ompgpu_fourdp
     176              : 
     177              : subroutine ompgpu_fourwf(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,&
     178              : &  kg_kin,kg_kout,mgfft,me_g0,ndat,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i,&
     179              : &  use_ndo,fofginb)
     180              : 
     181              : !Arguments ------------------------------------
     182              : !scalars
     183              :  integer,intent(in) :: cplex,istwf_k,ldx,ldy,ldz,me_g0,ndat,npwin,npwout,option,mgfft
     184              :  real(dp),intent(in) :: weight_i(ndat),weight_r(ndat)
     185              :  integer,intent(in),optional :: use_ndo
     186              : !arrays
     187              :  integer,intent(in) :: gboundin(2*mgfft+8,2),gboundout(2*mgfft+8,2)
     188              :  integer,intent(in) :: kg_kin(3,npwin),kg_kout(3,npwout),ngfft(18)
     189              :  real(dp),target,intent(inout) :: denpot(cplex*ldx,ldy,ldz)
     190              :  real(dp),target,intent(in)    :: fofgin(2,npwin*ndat)
     191              :  real(dp),target,intent(inout) :: fofr(2,ldx,ldy,ldz*ndat)
     192              :  real(dp),target,intent(out)   :: fofgout(2,npwout*ndat)
     193              :  real(dp),target,intent(inout),optional :: fofginb(2,npwin*ndat)
     194              : 
     195              : !Local variables-------------------------------
     196              : !scalars
     197              :  character(len=500) :: msg
     198              :  real(dp),allocatable,target :: fofrb(:,:,:,:)
     199              :  logical :: l_use_ndo
     200              : 
     201              :  real(dp) :: xnorm,one,tmp
     202              : 
     203              :  integer :: n1,n2,n3,nfft_tot,npwmin,izd
     204              :  integer :: cfft_size
     205              :  integer :: shift_inv1,shift_inv2,shift_inv3
     206              :  integer :: i1,i2,i3,ipw,idat;
     207              :  integer :: i1inv,i2inv,i3inv
     208              :  logical :: transfer_fofgin, transfer_fofginb, transfer_fofgout, transfer_denpot, transfer_fofr
     209              :  integer(C_SIZE_T) :: byte_count
     210              :  real(dp), ABI_CONTIGUOUS pointer :: work_gpu(:,:,:,:)
     211              : 
     212              :  npwmin=1; if(me_g0==1 .and. istwf_k==2) npwmin=2
     213              :  l_use_ndo=.false.; if(present(use_ndo)) l_use_ndo=use_ndo==1
     214              : 
     215              :  n1=ngfft(1);
     216              :  n2=ngfft(2);
     217              :  n3=ngfft(3);
     218              :  nfft_tot=n1*n2*n3;
     219              : 
     220              :  !*********** CHECK some compatibilities **************
     221              :  if( (n1/=ldx) .or. (n2/=ldy) .or. (n3/=ldz)) then
     222              :    write(msg,"(a,a,i5,i5,i5,a,i5,i5,i5,a)") "FFT SIZE ERROR: \n when gpu mode is on the fft grid must not be augmented",&
     223              :     "(n1,n2,n3) = (", n1,n2,n3,") whereas (ldx,ldy,ldz) = (", ldx,ldy,ldz, ")"
     224              :    ABI_ERROR(msg)
     225              :  end if
     226              : 
     227              :  !*************** CUDA INITIALISATION STAGE ****
     228              :  if (fourwf_initialized == 0) then
     229              :    call alloc_ompgpu_fourwf(ngfft,ndat)
     230              :  endif !end of initialisation
     231              : 
     232              : 
     233              :  ! ***********  GPU ALLOCATIONS  ***********************
     234              : 
     235              :  ! If fft size has changed, we realloc our buffers
     236              :  if((nfft_tot/=fft_size_fourwf) .or. (ndat/=ndat_fourwf)) then
     237              :    call free_ompgpu_fourwf()
     238              :    call alloc_ompgpu_fourwf(ngfft,ndat)
     239              :  end if !end if "fft size changed"
     240              : 
     241              :  transfer_fofgin= .not. xomp_target_is_present(c_loc(fofgin))  .and. (option/=3)
     242              :  transfer_fofgout=.not. xomp_target_is_present(c_loc(fofgout)) .and. (option==2 .or. option==3)
     243              :  transfer_denpot =.not. xomp_target_is_present(c_loc(denpot))  .and. (option==2 .or. option==1)
     244              :  transfer_fofr=   .not. xomp_target_is_present(c_loc(fofr))
     245              :  if(l_use_ndo) then
     246              :    transfer_fofginb= .not. xomp_target_is_present(c_loc(fofginb))  .and. (option/=3)
     247              :  end if
     248              : 
     249              :  !$OMP TARGET ENTER DATA MAP(to:fofgin)     IF(transfer_fofgin)
     250              :  !$OMP TARGET ENTER DATA MAP(alloc:fofgout) IF(transfer_fofgout)
     251              :  !$OMP TARGET ENTER DATA MAP(alloc:denpot)  IF(transfer_denpot)
     252              :  !$OMP TARGET ENTER DATA MAP(alloc:fofr)    IF(transfer_fofr)
     253              :  if(l_use_ndo) then
     254              :    !$OMP TARGET ENTER DATA MAP(to:fofginb)     IF(transfer_fofginb)
     255              :    ABI_MALLOC(fofrb, (2,n1,n2,n3*ndat))
     256              :    !$OMP TARGET ENTER DATA MAP(alloc:fofrb)
     257              :  end if
     258              : 
     259              :  if(option==3) then
     260              :    ! We don't want to erase fofr initial value so we alloc a separate array.
     261              :    ABI_MALLOC(work_gpu, (2,n1,n2,n3*ndat))
     262              :    !$OMP TARGET ENTER DATA MAP(alloc:work_gpu)
     263              :  else
     264              :    work_gpu => fofr
     265              :  end if
     266              : 
     267              :  if(option==3) then
     268              :    !$OMP TARGET UPDATE TO(fofr) IF(transfer_fofr)
     269              :  endif
     270              : 
     271              :  if(option==1 .or. option==2) then
     272              :    ! We launch async transfert of denpot
     273              :    !FIXME This async transfer might be better handled through CUDA/HIP after all...
     274              :    ! Issues randomly occurs when using Cray compiler, seems fine with NVHPC.
     275              : #ifdef FC_CRAY
     276              :    !$OMP TARGET UPDATE TO(denpot) IF(transfer_denpot)
     277              : #else
     278              :    !$OMP TARGET UPDATE TO(denpot) NOWAIT IF(transfer_denpot)
     279              : #endif
     280              :    if(option == 1) then
     281              : #ifdef FC_CRAY
     282              :      !$OMP TARGET ENTER DATA MAP(to:weight_r,weight_i)
     283              : #else
     284              :      !$OMP TARGET ENTER DATA MAP(to:weight_r,weight_i) NOWAIT
     285              : #endif
     286              :    endif
     287              :  endif
     288              : 
     289              :  if(option/=3) then
     290              : 
     291              :    ! GPU_SPHERE_IN
     292              : 
     293              :    cfft_size = 2*n1*n2*n3*ndat
     294              : 
     295              :    call gpu_set_to_zero(work_gpu,int(2,c_size_t)*n1*n2*n3*ndat)
     296              : 
     297              :    ! During GPU calculation we do some pre-calculation on symetries
     298              :    if((istwf_k==2) .or. (istwf_k==4) .or. (istwf_k==6) .or. (istwf_k==8)) then
     299              :      shift_inv1 = n1;
     300              :    else
     301              :      shift_inv1 = n1-1;
     302              :    end if
     303              : 
     304              :    if((istwf_k>=2) .and. (istwf_k<=5))  then
     305              :      shift_inv2 = n2;
     306              :    else
     307              :      shift_inv2 = n2-1;
     308              :    end if
     309              : 
     310              :    if((istwf_k==2) .or. (istwf_k==3) .or. (istwf_k==6) .or. (istwf_k==7)) then
     311              :      shift_inv3 = n3;
     312              :    else
     313              :      shift_inv3 = n3-1;
     314              :    end if
     315              : 
     316              : 
     317              :    ! !$OMP TARGET TEAMS DISTRIBUTE MAP(to:work_gpu,kg_kin,fofgin)
     318              :    !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(2) PRIVATE(i1,i2,i3) MAP(to:work_gpu,kg_kin,fofgin)
     319              :    do idat = 1, ndat
     320              :      !!! $OMP PARALLEL DO PRIVATE(i1,i2,i3)
     321              :      do ipw = 1, npwin
     322              :        i1=kg_kin(1,ipw); if(i1<0)i1=i1+n1; i1=i1+1
     323              :        i2=kg_kin(2,ipw); if(i2<0)i2=i2+n2; i2=i2+1
     324              :        i3=kg_kin(3,ipw); if(i3<0)i3=i3+n3; i3=i3+1
     325              :        ! We write cfft(i1,i2,i3)
     326              :        ! (double2): cfft[i1 + n1*(i2 + n2*(i3 + n3*idat))] = cg[ipw + npw*idat]
     327              :        work_gpu(1, i1, i2, i3+n3*(idat-1)) = fofgin(1, (ipw + npwin*(idat-1)))
     328              :        work_gpu(2, i1, i2, i3+n3*(idat-1)) = fofgin(2, (ipw + npwin*(idat-1)))
     329              :      end do
     330              :    end do
     331              : 
     332              :    if(istwf_k > 1) then
     333              :      if (istwf_k==2 .and. me_g0==1) then
     334              :        !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO MAP(to:work_gpu,fofgin)
     335              :        do idat = 1, ndat
     336              :          work_gpu(1, 1, 1, 1+n3*(idat-1)) = fofgin(1, (1 + npwin*(idat-1)))
     337              :          work_gpu(2, 1, 1, 1+n3*(idat-1)) = zero
     338              :        end do
     339              :      end if
     340              :      ! !$OMP TARGET TEAMS DISTRIBUTE MAP(to:work_gpu,kg_kin,fofgin)
     341              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(2) PRIVATE(i1,i2,i3,i1inv,i2inv,i3inv) MAP(to:work_gpu,kg_kin,fofgin)
     342              :      do idat = 1, ndat
     343              :        ! !$OMP PARALLEL DO PRIVATE(i1,i2,i3,i1inv,i2inv,i3inv)
     344              :        do ipw = npwmin, npwin
     345              :          i1=kg_kin(1,ipw); if(i1<0)i1=i1+n1;
     346              :          i2=kg_kin(2,ipw); if(i2<0)i2=i2+n2;
     347              :          i3=kg_kin(3,ipw); if(i3<0)i3=i3+n3;
     348              : #if defined HAVE_GPU_CUDA
     349              :          i1inv = modulo(shift_inv1 - i1, n1) + 1
     350              :          i2inv = modulo(shift_inv2 - i2, n2) + 1
     351              :          i3inv = modulo(shift_inv3 - i3, n3) + 1
     352              : #elif defined HAVE_GPU_HIP
     353              :          i1inv = (shift_inv1-i1) - ( ((shift_inv1-i1)/n1) * n1 ) + 1
     354              :          i2inv = (shift_inv2-i2) - ( ((shift_inv2-i2)/n2) * n2 ) + 1
     355              :          i3inv = (shift_inv3-i3) - ( ((shift_inv3-i3)/n3) * n3 ) + 1
     356              : #endif
     357              :          work_gpu(1, i1inv, i2inv, i3inv+n3*(idat-1)) =  fofgin(1, (ipw + npwin*(idat-1)))
     358              :          work_gpu(2, i1inv, i2inv, i3inv+n3*(idat-1)) = -fofgin(2, (ipw + npwin*(idat-1)))
     359              :        end do
     360              :      end do
     361              :    end if
     362              : 
     363              :    ! call backward fourier transform on gpu work_gpu => fofr_gpu
     364              :    !$OMP TARGET DATA USE_DEVICE_ADDR(work_gpu,fofr)
     365              :    call gpu_fft_exec_z2z(FOURWF_ID, c_loc(work_gpu), c_loc(fofr), FFT_INVERSE)
     366              :    !$OMP END TARGET DATA
     367              :    call gpu_fft_stream_synchronize(FOURWF_ID)
     368              : 
     369              :    ! In non-diagonal specific use-case, perform same operation with fofginb:
     370              :    ! - box-to-sphere : fofginb => fofrb
     371              :    ! - backward FFT  : fofrb => fofrb
     372              :    if(l_use_ndo) then
     373              : 
     374              :      call gpu_set_to_zero(fofrb,int(2,c_size_t)*n1*n2*n3*ndat)
     375              : 
     376              :      ! !$OMP TARGET TEAMS DISTRIBUTE MAP(to:fofrb,kg_kin,fofginb)
     377              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(2) PRIVATE(i1,i2,i3) MAP(to:fofrb,kg_kin,fofginb)
     378              :      do idat = 1, ndat
     379              :        ! !$OMP PARALLEL DO PRIVATE(i1,i2,i3)
     380              :        do ipw = 1, npwin
     381              :          i1=kg_kin(1,ipw); if(i1<0)i1=i1+n1; i1=i1+1
     382              :          i2=kg_kin(2,ipw); if(i2<0)i2=i2+n2; i2=i2+1
     383              :          i3=kg_kin(3,ipw); if(i3<0)i3=i3+n3; i3=i3+1
     384              :          ! We write cfft(i1,i2,i3)
     385              :          ! (double2): cfft[i1 + n1*(i2 + n2*(i3 + n3*idat))] = cg[ipw + npw*idat]
     386              :          fofrb(1, i1, i2, i3+n3*(idat-1)) = fofginb(1, (ipw + npwin*(idat-1)))
     387              :          fofrb(2, i1, i2, i3+n3*(idat-1)) = fofginb(2, (ipw + npwin*(idat-1)))
     388              :        end do
     389              :      end do
     390              : 
     391              :      !$OMP TARGET DATA USE_DEVICE_ADDR(fofrb)
     392              :      call gpu_fft_exec_z2z(FOURWF_ID, c_loc(fofrb), c_loc(fofrb), FFT_INVERSE)
     393              :      !$OMP END TARGET DATA
     394              :      call gpu_fft_stream_synchronize(FOURWF_ID)
     395              :    end if
     396              :  end if
     397              : 
     398              :  if(option==0) then
     399              :    ! We copy back fofr
     400              :    !$OMP TARGET UPDATE from(fofr)    IF(transfer_fofr)
     401              :  end if
     402              : 
     403              :  if(option==1) then
     404              :    ! We finish denpot and weight transferts
     405              :    !!$OMP TASKWAIT depend(in:denpot,weight_r,weight_i)
     406              :    !$OMP TASKWAIT
     407              : 
     408              :    ! Perform density accumulation
     409              : 
     410              :    ! Non-diagonal case
     411              :    if(l_use_ndo) then
     412              : 
     413              :      ! Collapse(4) would lead to race conditions here
     414              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(3) MAP(to:fofr,fofrb,denpot,weight_r,weight_i)
     415              :      do i3=1, n3
     416              :        do i2=1, n2
     417              :          do i1=1, n1
     418              :            do idat = 1, ndat
     419              :              denpot(i1,i2,i3) = denpot(i1,i2,i3) + weight_r(idat) *&
     420              :              &    (fofr(1, i1, i2, i3+(idat-1)*n3)*fofrb(1, i1, i2, i3+(idat-1)*n3)&
     421              :              &    +fofr(2, i1, i2, i3+(idat-1)*n3)*fofrb(2, i1, i2, i3+(idat-1)*n3))
     422              :              denpot(i1,i2,i3) = denpot(i1,i2,i3) + weight_i(idat) *&
     423              :              &    (fofrb(2, i1, i2, i3+(idat-1)*n3)*fofr(1, i1, i2, i3+(idat-1)*n3)&
     424              :              &    -fofrb(1, i1, i2, i3+(idat-1)*n3)*fofr(2, i1, i2, i3+(idat-1)*n3))
     425              :            end do
     426              :          end do
     427              :        end do
     428              :      end do
     429              : 
     430              :    ! General case
     431              :    else
     432              : 
     433              :      ! Collapse(4) would lead to race conditions here
     434              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(3) MAP(to:fofr,denpot,weight_r,weight_i)
     435              :      do i3=1, n3
     436              :        do i2=1, n2
     437              :          do i1=1, n1
     438              :            do idat = 1, ndat
     439              :              denpot(i1,i2,i3) = denpot(i1,i2,i3) + fofr(1, i1, i2, i3+(idat-1)*n3)*fofr(1, i1, i2, i3+(idat-1)*n3)*weight_r(idat)
     440              :              denpot(i1,i2,i3) = denpot(i1,i2,i3) + fofr(2, i1, i2, i3+(idat-1)*n3)*fofr(2, i1, i2, i3+(idat-1)*n3)*weight_i(idat)
     441              :            end do
     442              :          end do
     443              :        end do
     444              :      end do
     445              :    end if
     446              : 
     447              :    !$OMP TARGET UPDATE from(denpot) IF(transfer_denpot)
     448              : 
     449              :  end if
     450              : 
     451              :  if(option==2) then
     452              :    ! We finished denpot transfert
     453              :    !!$OMP TASKWAIT depend(in:denpot)
     454              :    !$OMP TASKWAIT
     455              : 
     456              :    ! call gpu routine to  Apply local potential
     457              :    if(cplex==1) then
     458              :      ! !$OMP TARGET TEAMS DISTRIBUTE MAP(to:denpot,fofr)
     459              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(4) PRIVATE(izd, tmp) MAP(to:denpot,fofr)
     460              :      do idat = 1, ndat
     461              :        ! !$OMP PARALLEL DO PRIVATE(izd, tmp) COLLAPSE(3)
     462              :        do i3=1, n3
     463              :          do i2=1, n2
     464              :            do i1=1, n1
     465              :              izd = i3+(idat-1)*n3
     466              :              tmp = denpot(i1,i2,i3)
     467              :              fofr(1, i1, i2, izd) = fofr(1, i1, i2, izd) * tmp
     468              :              fofr(2, i1, i2, izd) = fofr(2, i1, i2, izd) * tmp
     469              :            end do
     470              :          end do
     471              :        end do
     472              :      end do
     473              :    else ! cplex==2
     474              : 
     475              :      ! !$OMP TARGET TEAMS DISTRIBUTE MAP(to:denpot,fofr)
     476              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(4) PRIVATE(tmp) MAP(to:denpot,fofr)
     477              :      do idat = 1, ndat
     478              :        ! !$OMP PARALLEL DO COLLAPSE(3) PRIVATE(tmp)
     479              :        do i3=1, n3
     480              :          do i2=1, n2
     481              :            do i1=1, n1
     482              :              tmp = fofr(1, i1, i2, i3+(idat-1)*n3)
     483              :              fofr(1, i1, i2, i3+(idat-1)*n3) = &
     484              :              fofr(1, i1, i2, i3+(idat-1)*n3) * denpot(2*i1-1,i2,i3) &
     485              :            - fofr(2, i1, i2, i3+(idat-1)*n3) * denpot(2*i1,i2,i3)
     486              : 
     487              :              fofr(2, i1, i2, i3+(idat-1)*n3) = &
     488              :              fofr(2, i1, i2, i3+(idat-1)*n3) * denpot(2*i1-1,i2,i3) &
     489              :              + tmp * denpot(2*i1,i2,i3)
     490              :            end do
     491              :          end do
     492              :        end do
     493              :      end do
     494              :    end if
     495              :  end if
     496              : 
     497              :  if(option==2 .or. option==3) then
     498              : 
     499              :    ! call forward fourier transform on gpu: fofr_gpu ==> work_gpu
     500              :    !$OMP TARGET DATA USE_DEVICE_ADDR(work_gpu,fofr)
     501              :    call gpu_fft_exec_z2z(FOURWF_ID, c_loc(fofr), c_loc(work_gpu), FFT_FORWARD)
     502              :    !$OMP END TARGET DATA
     503              :    call gpu_fft_stream_synchronize(FOURWF_ID)
     504              : 
     505              :    one=1
     506              :    xnorm=one/dble(n1*n2*n3)
     507              :    if (istwf_k==2 .and. me_g0==1) then
     508              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO MAP(to:work_gpu,fofgout)
     509              :      do idat = 1, ndat
     510              :        fofgout (1, 1 + npwout*(idat-1)) = work_gpu(1, 1, 1, 1+n3*(idat-1)) * xnorm
     511              :        fofgout (2, 1 + npwout*(idat-1)) = zero
     512              :      end do
     513              :    end if
     514              : 
     515              :    ! !$OMP TARGET TEAMS DISTRIBUTE MAP(to:work_gpu,kg_kout,fofgout)
     516              :    !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(2) PRIVATE(i1,i2,i3) MAP(to:work_gpu,kg_kout,fofgout)
     517              :    do idat = 1, ndat
     518              :      ! !$OMP PARALLEL DO PRIVATE(i1,i2,i3)
     519              :      do ipw = npwmin, npwout
     520              :        i1=kg_kout(1,ipw); if(i1<0)i1=i1+n1; i1=i1+1
     521              :        i2=kg_kout(2,ipw); if(i2<0)i2=i2+n2; i2=i2+1
     522              :        i3=kg_kout(3,ipw); if(i3<0)i3=i3+n3; i3=i3+1
     523              : 
     524              :        ! We write cg(ig)
     525              :        fofgout (1, ipw + npwout*(idat-1)) = work_gpu(1, i1, i2, i3+n3*(idat-1)) * xnorm
     526              :        fofgout (2, ipw + npwout*(idat-1)) = work_gpu(2, i1, i2, i3+n3*(idat-1)) * xnorm
     527              :      end do
     528              :    end do
     529              : 
     530              :    !$OMP TARGET UPDATE FROM(fofgout)   IF(transfer_fofgout)
     531              :  end if
     532              : 
     533              :  if(option==1 .or. option==2) then
     534              :    !$OMP TARGET EXIT DATA MAP(delete:denpot)  IF(transfer_denpot)
     535              :    if(option == 1) then
     536              :      !$OMP TARGET EXIT DATA MAP(delete:weight_r,weight_i)
     537              :    endif
     538              :  endif
     539              : 
     540              :  if(option==3) then
     541              :    !$OMP TARGET EXIT DATA MAP(delete:work_gpu)
     542              :    ABI_FREE(work_gpu)
     543              :  end if
     544              : 
     545              :  !$OMP TARGET EXIT DATA MAP(delete:fofgin)  IF(transfer_fofgin)
     546              :  !$OMP TARGET EXIT DATA MAP(delete:fofgout) IF(transfer_fofgout)
     547              :  !$OMP TARGET EXIT DATA MAP(delete:fofr)    IF(transfer_fofr)
     548              : 
     549              :  if(l_use_ndo) then
     550              :    !$OMP TARGET EXIT DATA MAP(delete:fofginb)     IF(transfer_fofginb)
     551              :    !$OMP TARGET EXIT DATA MAP(delete:fofrb)
     552              :    ABI_FREE(fofrb)
     553              :  end if
     554              : 
     555              : end subroutine ompgpu_fourwf
     556              : !!***
     557              : 
     558              : !!****************************************************************************************************************
     559              : !!****************************************************************************************************************
     560              : !!****************************************************************************************************************
     561              : 
     562              : ! Memory allocation routine
     563              : subroutine alloc_ompgpu_fourdp(ngfft, ndat)
     564              :  integer, intent(in) :: ngfft(18), ndat
     565              : 
     566              :  integer :: n1,n2,n3, ldx, ldy, ldz
     567              :  integer, target :: t_fft(3)
     568              : 
     569              :  fourdp_initialized = 1
     570              : 
     571              :  ! Size modification if too little memory allocation
     572              :  n1=ngfft(1)
     573              :  n2=ngfft(2)
     574              :  n3=ngfft(3)
     575              :  ldx = ngfft(4)
     576              :  ldy = ngfft(5)
     577              :  ldz = ngfft(6)
     578              :  fft_size_fourdp=n1*n2*n3
     579              :  ndat_fourdp = ndat
     580              : 
     581              :  ! Initialisation des plans FFT
     582              :  t_fft(1) = n3;
     583              :  t_fft(2) = n2;
     584              :  t_fft(3) = n1;
     585              : 
     586              :  ! Creation du plan
     587              :  call gpu_fft_plan_many(FOURDP_ID, 3, c_loc(t_fft), c_null_ptr, 1, ldx*ldy*ldz, c_null_ptr, 1, ldx*ldy*ldz, FFT_Z2Z, ndat);
     588              : 
     589              : end subroutine alloc_ompgpu_fourdp
     590              : 
     591              : subroutine free_ompgpu_fourdp()
     592              : 
     593              :  if(fourdp_initialized==0) return
     594              : 
     595              :  ! On detruit l'ancien plan
     596              :  call gpu_fft_plan_destroy(FOURDP_ID)
     597              : 
     598              :  fourdp_initialized = 0;
     599              : 
     600              : end subroutine free_ompgpu_fourdp
     601              : 
     602              : subroutine alloc_ompgpu_fourwf(ngfft, ndat)
     603              :  integer, intent(in) :: ngfft(18), ndat
     604              : 
     605              :  integer :: n1,n2,n3, ldx, ldy, ldz
     606              :  integer, target :: t_fft(3),embed(3)
     607              : 
     608              :  fourwf_initialized = 1
     609              : 
     610              :  ! Size modification if too little memory allocation
     611              :  n1=ngfft(1)
     612              :  n2=ngfft(2)
     613              :  n3=ngfft(3)
     614              :  ldx = ngfft(4)
     615              :  ldy = ngfft(5)
     616              :  ldz = ngfft(6)
     617              :  fft_size_fourwf=n1*n2*n3
     618              :  ndat_fourwf = ndat
     619              : 
     620              :  ! Initialisation des plans FFT
     621              :  t_fft(1) = n3;
     622              :  t_fft(2) = n2;
     623              :  t_fft(3) = n1;
     624              : 
     625              :  embed(1) = ldz
     626              :  embed(2) = ldy
     627              :  embed(3) = ldx
     628              : 
     629              :  ! Creation du plan
     630              :  call gpu_fft_plan_many(FOURWF_ID, 3, c_loc(t_fft), c_loc(embed), 1, ldx*ldy*ldz, c_loc(embed), 1, ldx*ldy*ldz, FFT_Z2Z, ndat);
     631              : 
     632              : end subroutine alloc_ompgpu_fourwf
     633              : 
     634              : subroutine free_ompgpu_fourwf()
     635              : 
     636              :  if(fourwf_initialized==0) return
     637              : 
     638              :  ! On detruit l'ancien plan
     639              :  call gpu_fft_plan_destroy(FOURWF_ID)
     640              : 
     641              :  fourwf_initialized = 0
     642              : 
     643              : end subroutine free_ompgpu_fourwf
     644              : 
     645              : #else
     646              : ! interface for unsupported compilers
     647            0 : subroutine ompgpu_fourdp(cplex,ngfft,ldx,ldy,ldz,ndat,isign,fofg,fofr)
     648              : 
     649              : !Arguments ------------------------------------
     650              : !scalars
     651              :  integer,intent(in) :: cplex,ngfft(18),ldx,ldy,ldz,ndat,isign
     652              : !arrays
     653              :  real(dp),intent(inout) :: fofg(2*ldx*ldy*ldz*ndat)
     654              :  real(dp),intent(inout) :: fofr(cplex*ldx*ldy*ldz*ndat)
     655              : 
     656              : ! *************************************************************************
     657              : 
     658              :  ABI_UNUSED((/cplex,ldx,ldy,ldz,ndat,isign/))
     659              :  ABI_UNUSED((/ngfft/))
     660              :  ABI_UNUSED((/fofg,fofr/))
     661              : 
     662            0 : end subroutine ompgpu_fourdp
     663              : 
     664            0 : subroutine ompgpu_fourwf(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,&
     665            0 : &  kg_kin,kg_kout,mgfft,ndat,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
     666              : 
     667              : !Arguments ------------------------------------
     668              : !scalars
     669              :  integer,intent(in) :: cplex,istwf_k,ldx,ldy,ldz,ndat,npwin,npwout,option,mgfft
     670              :  real(dp),intent(in) :: weight_i(:),weight_r(:)
     671              : !arrays
     672              :  integer,intent(in) :: gboundin(2*mgfft+8,2),gboundout(2*mgfft+8,2)
     673              :  integer,intent(in) :: kg_kin(3,npwin),kg_kout(3,npwout),ngfft(18)
     674              :  real(dp),target,intent(inout) :: denpot(cplex*ldx,ldy,ldz)
     675              :  real(dp),intent(in) :: fofgin(2,npwin*ndat)
     676              :  real(dp),intent(inout),target :: fofr(2,ldx,ldy,ldz*ndat)
     677              :  real(dp),intent(out) :: fofgout(2,npwout*ndat)
     678              : 
     679              :  ! Marking unused variables to please code quality checks
     680              :  ABI_UNUSED((/cplex,istwf_k,ldx,ldy,ldz,ndat,npwin,npwout,option,mgfft/))
     681              :  ABI_UNUSED((/weight_i,weight_r/))
     682              :  ABI_UNUSED((/gboundin,gboundout/))
     683              :  ABI_UNUSED((/kg_kin,kg_kout,ngfft/))
     684              :  ABI_UNUSED((/denpot,fofgin,fofgout,fofr/))
     685            0 :  ABI_BUG("Unhandled configuration for OpenMP GPU immplementation")
     686            0 : end subroutine ompgpu_fourwf
     687              : 
     688            0 : subroutine alloc_ompgpu_fourwf(ngfft, ndat)
     689              : !Arguments ------------------------------------
     690              :  integer, intent(in) :: ngfft(6), ndat
     691              : 
     692              :  ABI_UNUSED((/ngfft,ndat/))
     693            0 :  ABI_BUG("Unhandled configuration for OpenMP GPU immplementation")
     694            0 : end subroutine alloc_ompgpu_fourwf
     695              : 
     696            0 : subroutine free_ompgpu_fourwf()
     697            0 :  ABI_BUG("Unhandled configuration for OpenMP GPU immplementation")
     698            0 : end subroutine free_ompgpu_fourwf
     699              : 
     700              : #endif
     701              : 
     702              : end module m_ompgpu_fourwf
     703              : !!***
        

Generated by: LCOV version 2.3-1