LCOV - code coverage report
Current view: top level - src/53_ffts - m_fft.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 64.7 % 1720 1112
Test Date: 2026-09-21 22:40:37 Functions: 55.3 % 47 26

            Line data    Source code
       1              : !!****m* ABINIT/m_fft
       2              : !! NAME
       3              : !!  m_fft
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module provides driver routines for sequential FFTs (OpenMP threads are supported).
       7              : !!  It also defines generic interfaces for single or double precision FFTs.
       8              : !!
       9              : !! COPYRIGHT
      10              : !! Copyright (C) 2009-2026 ABINIT group (MG, MM, GZ, MT, MF, XG, PT, FF)
      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              : ! nvtx related macro definition
      24              : #include "nvtx_macros.h"
      25              : 
      26              : module m_fft
      27              : 
      28              :  use, intrinsic :: iso_c_binding
      29              :  use defs_basis
      30              :  use m_abicore
      31              :  use m_errors
      32              :  use m_xomp
      33              :  USE_MPI
      34              :  use m_xmpi
      35              :  use m_cplxtools
      36              :  use m_cgtools
      37              :  use m_sgfft
      38              :  use m_sg2002
      39              :  use m_fftw3
      40              :  use m_dfti
      41              : #if defined HAVE_GPU_CUDA
      42              :  use m_manage_cuda
      43              : #endif
      44              :  use m_ompgpu_fourwf
      45              : 
      46              :  use defs_abitypes,   only : MPI_type
      47              :  use defs_fftdata,    only : mg
      48              :  use m_time,          only : cwtime, timab
      49              :  use m_numeric_tools, only : r2c
      50              :  use m_fstrings,      only : sjoin, itoa
      51              :  use m_geometry,      only : metric
      52              :  use m_hide_blas,     only : xscal
      53              :  use m_fftcore,       only : get_cache_kb, kpgsph, get_kg, sphere_fft, sphere_fft1, sphere, change_istwfk, &
      54              :                              fftalg_info, fftalg_has_mpi, print_ngfft, getng, sphereboundary, ngfft_seq
      55              :  use m_mpinfo,        only : destroy_mpi_enreg, ptabs_fourdp, ptabs_fourwf, initmpi_seq
      56              :  use m_distribfft,    only : distribfft_type
      57              :  use m_gputk     ,    only : gpu_set_to_zero_complex, gpu_set_to_zero_complex_sp
      58              : 
      59              :  implicit none
      60              : 
      61              :  private
      62              : 
      63              : #if defined HAVE_MPI1
      64              :  include 'mpif.h'
      65              : #endif
      66              : 
      67              :  public :: fft_ug               ! Driver for zero-padded FFTs u(g) --> u(r)
      68              :  public :: fft_ur               ! Driver for zero-padded FFTs u(r) --> u(g)
      69              :  public :: fftpad               ! Driver for (low-level) zero-padded FFTs, note that fft_ug is the preferred interface.
      70              :  public :: fft_poisson          ! Solve the poisson equation in G-space starting from n(r).
      71              :  public :: fourdp_6d            ! Calculate a 6-dimensional Fast Fourier Transform
      72              :  public :: fftpac               ! Copy to change the stride of a three-dimension array for more efficient FFT.
      73              :  public :: indirect_parallel_Fourier
      74              : 
      75              :  public :: fft_use_lib_threads
      76              :  public :: fft_allow_ialltoall  ! Allow the use of non-blocking IALLOTOALL in MPI-FFTs algorithms
      77              :  public :: zerosym              ! Symmetrize an array on the FFT grid by vanishing some term on the boundaries.
      78              : 
      79              : ! Main entry points.
      80              :  public :: fourdp
      81              :  public :: fourwf
      82              : 
      83              : ! Alternate routine wrapping fourwf, for memory sensitive regions
      84              :  public :: fourwf_optmem
      85              : 
      86              :  integer,public,save :: fourdp_counter = -1
      87              :  integer,public,save :: fourwf_counter = -1
      88              :  public :: fft_init_counters
      89              :  public :: fft_stop_counters
      90              :  public :: fft_output_counters
      91              : 
      92              : ! Driver routines for MPI version.
      93              :  public :: fourdp_mpi           ! MPI FFT of densities/potentials on the full box.
      94              :  public :: fourwf_mpi           ! specialized MPI-FFT for wavefunctions.
      95              :  !public :: fftmpi_u
      96              : 
      97              :  interface fft_ug
      98              :    module procedure fft_ug_sp
      99              :    module procedure fft_ug_dp
     100              :    module procedure fft_ug_spc
     101              :    module procedure fft_ug_dpc
     102              :  end interface fft_ug
     103              : 
     104              :  interface fft_ur
     105              :    module procedure fft_ur_dp
     106              :    module procedure fft_ur_spc
     107              :    module procedure fft_ur_dpc
     108              :  end interface fft_ur
     109              : 
     110              :  interface fftpad
     111              :    module procedure fftpad_spc
     112              :    module procedure fftpad_dpc
     113              :  end interface fftpad
     114              : !!***
     115              : 
     116              : !----------------------------------------------------------------------
     117              : 
     118              : !!****t* m_fft/fftbox_plan3_t
     119              : !! NAME
     120              : !! fftbox_plan3_t
     121              : !!
     122              : !! FUNCTION
     123              : !!  Options passed to the fftbox_* routines to perform dense 3d FFTs.
     124              : !!
     125              : !! SOURCE
     126              : 
     127              :  type,public :: fftbox_plan3_t
     128              : 
     129              :    integer :: fftalg = 112       ! The library to call on the CPU
     130              :    integer :: fftcache = 16      ! Cache size in kB. Only used in SG routines.
     131              :    integer(c_size_t) :: nfft = -1  ! Total number of points in the FFT box.
     132              :    integer(c_size_t) :: ldxyz = -1 ! Physical dimension of the array to transform
     133              :    integer :: batch_size = -1    ! MAXIMUM number of FFTs associated to the plan.
     134              :    integer :: dims(3) = -1       ! The number of FFT divisions.
     135              :    integer :: embed(3) = -1      ! Leading dimensions of the input, output arrays.
     136              :    integer :: gpu_option = ABI_GPU_DISABLED  ! /= 0 if FFTs should be offloaded to the GPU
     137              : 
     138              :    type(c_ptr) :: gpu_ctx_spc = c_null_ptr, gpu_ctx_dpc = c_null_ptr
     139              : 
     140              :  contains
     141              : 
     142              :    procedure :: init => fftbox_plan3_init                 ! Low-level constructor
     143              :    procedure :: from_ngfft => fftbox_plan3_from_ngfft     ! Build object from ngfft.
     144              : 
     145              :    procedure :: execute_ip_spc => fftbox_execute_ip_spc
     146              :    procedure :: execute_ip_dpc => fftbox_execute_ip_dpc
     147              :    procedure :: execute_op_spc => fftbox_execute_op_spc
     148              :    procedure :: execute_op_dpc => fftbox_execute_op_dpc
     149              : 
     150              :    ! Main entry point for performing FFTs on the full box
     151              :    ! complex-to-complex version, operating on complex arrays
     152              :    generic :: execute => execute_ip_spc, &
     153              :                          execute_ip_dpc, &
     154              :                          execute_op_spc, &
     155              :                          execute_op_dpc
     156              : 
     157              :    procedure :: free => fftbox_plan3_free
     158              :    ! Free dynamic memory
     159              : 
     160              :  end type fftbox_plan3_t
     161              : !!***
     162              : 
     163              : #if defined HAVE_GPU_CUDA
     164              :  ! The c functions are declared in shared/common/src/17_gpu_toolbox
     165              :  ! gpu_fft_cuda.cpp or gpu_fft_hip.cpp
     166              :  interface
     167              :    subroutine gpu_ctx_init(ctx, f_dims, f_embed, batch, kind) bind(C, name="gpu_ctx_init_cpp")
     168              :      use, intrinsic :: iso_c_binding
     169              :      type(c_ptr), intent(out) :: ctx
     170              :      integer(c_int), intent(in) :: f_dims(3), f_embed(3)
     171              :      integer(c_int), value :: batch, kind
     172              :    end subroutine
     173              :    subroutine gpu_ctx_synch(ctx) bind(C, name="gpu_ctx_synch_cpp")
     174              :      use, intrinsic :: iso_c_binding
     175              :      type(c_ptr), value :: ctx
     176              :    end subroutine gpu_ctx_synch
     177              :    subroutine gpu_ctx_free(ctx) bind(C, name="gpu_ctx_free_cpp")
     178              :      use, intrinsic :: iso_c_binding
     179              :      type(c_ptr) :: ctx
     180              :    end subroutine
     181              :    subroutine gpu_fftbox_c2c_ip(ctx, nfft, ndat, isign, iscale, kind, d_ff) bind(C, name="gpu_fftbox_c2c_ip_cpp")
     182              :      use, intrinsic :: iso_c_binding
     183              :      type(c_ptr),value,intent(in) :: ctx
     184              :      integer(c_int),value, intent(in) :: nfft, ndat, isign, iscale, kind
     185              :      type(c_ptr),intent(in) :: d_ff
     186              :    end subroutine gpu_fftbox_c2c_ip
     187              :    subroutine gpu_fftbox_c2c_op(ctx, nfft, ndat, isign, iscale, kind, d_ff, d_gg) bind(C, name="gpu_fftbox_c2c_op_cpp")
     188              :      use, intrinsic :: iso_c_binding
     189              :      type(c_ptr),value,intent(in) :: ctx
     190              :      integer(c_int),value, intent(in) :: nfft, ndat, isign, iscale, kind
     191              :      type(c_ptr),intent(in) :: d_ff, d_gg
     192              :    end subroutine gpu_fftbox_c2c_op
     193              :  end interface
     194              : #endif
     195              : 
     196              : !----------------------------------------------------------------------
     197              : 
     198              : !!****t* m_fft/uplan_t
     199              : !! NAME
     200              : !! uplan_t
     201              : !!
     202              : !! FUNCTION
     203              : !!
     204              : !! SOURCE
     205              : 
     206              :  type, public :: uplan_t
     207              : 
     208              :    integer(c_size_t) :: npw = -1
     209              :    integer :: nspinor = -1
     210              :    integer :: batch_size = -1  ! MAXIMUM number of FFTs associated to the plan.
     211              :    integer :: istwfk = -1
     212              :    integer :: kind = -1
     213              :    integer :: gpu_option = ABI_GPU_DISABLED  ! /= 0 if FFTs should be offloaded to the GPU.
     214              :    integer(c_size_t) :: nfft = -1
     215              :    integer :: mgfft = -1
     216              :    integer :: ngfft(18)
     217              :    integer, contiguous, pointer :: kg_k(:,:)
     218              :    integer, allocatable :: gbound(:,:)
     219              : 
     220              :    integer, allocatable :: ig2ifft(:)
     221              :    ! (npw)
     222              :    ! Mapping gvec index --> FFT box
     223              : 
     224              :    integer, allocatable :: ifft2ig(:)
     225              :    ! (nfft)
     226              :    ! Mapping FFT box -> gvec index. 0 if FFT point is not in g-sphere.
     227              : 
     228              :    type(c_ptr) :: gpu_ctx_spc = c_null_ptr, gpu_ctx_dpc = c_null_ptr
     229              : 
     230              :  contains
     231              :    procedure :: init => uplan_init    ! Build object
     232              :    procedure :: free => uplan_free    ! Free dynamic memory
     233              : 
     234              :    procedure :: execute_gr_spc => uplan_execute_gr_spc
     235              :    procedure :: execute_gr_dpc => uplan_execute_gr_dpc
     236              :    procedure :: execute_rg_spc => uplan_execute_rg_spc
     237              :    procedure :: execute_rg_dpc => uplan_execute_rg_dpc
     238              : 
     239              :    ! Main entry points for performing FFTs on the full box.
     240              :    ! complex-to-complex version, operating on complex arrays
     241              :    generic :: execute_gr => execute_gr_spc, execute_gr_dpc
     242              :    generic :: execute_rg => execute_rg_spc, execute_rg_dpc
     243              :  end type uplan_t
     244              : !!***
     245              : 
     246              : !----------------------------------------------------------------------
     247              : 
     248              :  ! unit tests
     249              :  public :: fftbox_utests          ! Unit tests for FFTs on the full box.
     250              :  public :: fftu_utests            ! Unit tests for the FFTs of wavefunctions.
     251              :  public :: uplan_utests           ! Unit tests for the FFTs of wavefunctions (including GPU support)
     252              :  public :: fftbox_mpi_utests      ! Unit tests for MPI-FFT on the full box.
     253              :  public :: fftu_mpi_utests        ! Unit tests for MPI-FFT of the wavefunctions.
     254              : !!***
     255              : 
     256              :  ! Flag used to enable/disable the use of non-blocking IALLTOALL
     257              : #ifdef HAVE_MPI_IALLTOALL
     258              :  logical,save,private :: ALLOW_IALLTOALL = .True.
     259              : #else
     260              :  logical,save,private :: ALLOW_IALLTOALL = .False.
     261              : #endif
     262              : 
     263              : CONTAINS  !===========================================================
     264              : !!***
     265              : 
     266              : !----------------------------------------------------------------------
     267              : 
     268              : !!****f* m_fft/fft_allow_ialltoall
     269              : !! NAME
     270              : !!  fft_allow_ialltoall
     271              : !!
     272              : !! FUNCTION
     273              : !!  Allow the use of non-blocking IALLOTOALL in MPI-FFTs algorithms
     274              : !!  Mainly used for profiling purposes.
     275              : !!
     276              : !! SOURCE
     277              : 
     278            0 : subroutine fft_allow_ialltoall(bool)
     279              : 
     280              : !Arguments ------------------------------------
     281              :  logical,intent(in) :: bool
     282              : ! *************************************************************************
     283              : 
     284            0 :  ALLOW_IALLTOALL = bool
     285              : #ifndef HAVE_MPI_IALLTOALL
     286              :  ALLOW_IALLTOALL = .False.
     287              : #endif
     288              : 
     289            0 : end subroutine fft_allow_ialltoall
     290              : !!***
     291              : 
     292              : !----------------------------------------------------------------------
     293              : 
     294              : !!****f* m_fft/fftbox_plan3_init
     295              : !! NAME
     296              : !!  fftbox_plan3_init
     297              : !!
     298              : !! FUNCTION
     299              : !!  Initialize the plan with the options passed to the fttbox_ routines.
     300              : !!  Low-level constructor.
     301              : !!
     302              : !! INPUTS
     303              : !!  See fftbox_plan3_t for the meaning of the different arguments.
     304              : !!
     305              : !! SOURCE
     306              : 
     307        14981 : subroutine fftbox_plan3_init(plan, batch_size, dims, embed, fftalg, fftcache, gpu_option)
     308              : 
     309              : !Arguments ------------------------------------
     310              : !scalars
     311              :  class(fftbox_plan3_t),intent(out) :: plan
     312              :  integer,intent(in) :: batch_size, fftalg, fftcache, gpu_option
     313              : !arrays
     314              :  integer,intent(in) :: dims(3), embed(3)
     315              : ! *************************************************************************
     316              : 
     317        14981 :  plan%batch_size = batch_size
     318        59924 :  plan%dims     = dims                       ! ngfft(1:3)
     319        59924 :  plan%embed    = embed                      ! ngfft(4:6)
     320        14981 :  plan%fftalg   = fftalg                     ! ngfft(7)
     321        14981 :  if (fftcache > 0) plan%fftcache = fftcache ! ngfft(8)
     322        14981 :  plan%gpu_option  = gpu_option
     323        59924 :  plan%nfft  = product(plan%dims)
     324        59924 :  plan%ldxyz = product(plan%embed)
     325              : 
     326        14981 :  plan%gpu_ctx_spc = c_null_ptr; plan%gpu_ctx_dpc = c_null_ptr
     327              : 
     328        14981 :  if (gpu_option /= ABI_GPU_DISABLED) then
     329            0 :    if (any(dims /= embed)) then
     330            0 :      ABI_ERROR("FFTs on GPUs with fftbox_plan3 do not support dims != embed")
     331              :    end if
     332              :  end if
     333              : 
     334        14981 : end subroutine fftbox_plan3_init
     335              : !!***
     336              : 
     337              : !----------------------------------------------------------------------
     338              : 
     339              : !!****f* m_fft/fftbox_plan3_from_ngfft
     340              : !! NAME
     341              : !!  fftbox_plan3_from_ngfft
     342              : !!
     343              : !! FUNCTION
     344              : !!  Initialize plan from ngfft.
     345              : !!
     346              : !! SOURCE
     347              : 
     348            0 : subroutine fftbox_plan3_from_ngfft(plan, ngfft, batch_size, gpu_option)
     349              : 
     350              : !Arguments ------------------------------------
     351              :  class(fftbox_plan3_t),intent(out) :: plan
     352              :  integer,intent(in) :: ngfft(18), batch_size, gpu_option
     353              : ! *************************************************************************
     354              : 
     355            0 :  call plan%init(batch_size, ngfft(1:3), ngfft(4:6), ngfft(7), ngfft(8), gpu_option)
     356              : 
     357            0 : end subroutine fftbox_plan3_from_ngfft
     358              : !!***
     359              : 
     360              : !----------------------------------------------------------------------
     361              : 
     362              : !!****f* m_fft/fftbox_plan3_free
     363              : !! NAME
     364              : !!  fftbox_plan3_free
     365              : !!
     366              : !! FUNCTION
     367              : !!  Free dynamic memory.
     368              : !!
     369              : !! SOURCE
     370              : 
     371        14957 : subroutine fftbox_plan3_free(plan)
     372              : 
     373              : !Arguments ------------------------------------
     374              :  class(fftbox_plan3_t),target,intent(inout) :: plan
     375              : ! *************************************************************************
     376              : 
     377              :  ABI_UNUSED(plan%ldxyz)
     378              : 
     379              : #ifdef HAVE_GPU_CUDA
     380              :  call gpu_ctx_free(plan%gpu_ctx_spc)
     381              :  call gpu_ctx_free(plan%gpu_ctx_dpc)
     382              : #endif
     383              : 
     384        14957 : end subroutine fftbox_plan3_free
     385              : !!***
     386              : 
     387              : !----------------------------------------------------------------------
     388              : 
     389              : !!****f* m_fft/fftbox_execute_ip_spc
     390              : !! NAME
     391              : !!  fftbox_execute_ip_spc
     392              : !!
     393              : !! FUNCTION
     394              : !!  In-place FFT transform of complex array.
     395              : !!  Call (FFTW3|DFTI) routines if available, otherwise fallback to SG routines
     396              : !!  TARGET: spc arrays
     397              : !!
     398              : !! INPUTS
     399              : !!  isign= Sign of the exponential in the FFT
     400              : !!  ndat: Number of FFTs.
     401              : !!  [iscale]= 0 if G --> R FFT should not be scaled. Default: 1 i.e. scale
     402              : !!
     403              : !! SIDE EFFECTS
     404              : !!  ff(plan%ldxyz*ndat) =
     405              : !!    In input: the data to transform.
     406              : !!    Changed in output, filled with the FFT results.
     407              : !!
     408              : !! SOURCE
     409              : 
     410           48 : subroutine fftbox_execute_ip_spc(plan, ff, isign, ndat, &
     411              :                                  iscale, gpu_mode)  ! optional
     412              : 
     413              : !Arguments ------------------------------------
     414              : !scalars
     415              :  class(fftbox_plan3_t),target,intent(inout) :: plan
     416              :  integer,intent(in) :: isign, ndat
     417              :  integer,optional,intent(in) :: iscale, gpu_mode
     418              : !arrays
     419              :  complex(sp),target,intent(inout) :: ff(plan%ldxyz*ndat)
     420              : 
     421              : !Local variables-------------------------------
     422              :  integer :: ndat__, iscale__, gpu_mode__
     423              : #ifdef HAVE_GPU_CUDA
     424              :  logical :: transfer_ff
     425              : #endif
     426              : ! *************************************************************************
     427              : 
     428           48 :  ndat__ = ndat
     429           48 :  ABI_DEFAULT(iscale__, iscale, 1)
     430           48 :  ABI_DEFAULT(gpu_mode__, gpu_mode, 0)
     431              : 
     432              :  if (plan%gpu_option == ABI_GPU_OPENMP) then
     433              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
     434              :    ! Build plan if not yet done. note batch_size instead of ndat.
     435              :    if (.not. c_associated(plan%gpu_ctx_spc)) then
     436              :      call gpu_ctx_init(plan%gpu_ctx_spc, plan%dims, plan%embed, plan%batch_size, sp)
     437              :    end if
     438              : 
     439              :    if (ndat__ /= plan%batch_size) then
     440              :      ! Have to rebuild the plan with batch_size == ndat.
     441              :      call gpu_ctx_free(plan%gpu_ctx_spc)
     442              :      call gpu_ctx_init(plan%gpu_ctx_spc, plan%dims, plan%embed, ndat__, sp)
     443              :    end if
     444              : 
     445              :    plan%batch_size = ndat__
     446              : 
     447              :    transfer_ff = .False.
     448              :    if (gpu_mode__ /= 0) then
     449              :      transfer_ff = .not. xomp_target_is_present(c_loc(ff))
     450              :      !$OMP TARGET ENTER DATA MAP(alloc:ff) IF(transfer_ff)
     451              :      !$OMP TARGET UPDATE TO(ff) IF(transfer_ff)
     452              :    end if
     453              : 
     454              :    !$OMP TARGET DATA USE_DEVICE_ADDR(ff)
     455              :    call gpu_fftbox_c2c_ip(plan%gpu_ctx_spc, int(plan%nfft), ndat__, isign, iscale__, sp, c_loc(ff))
     456              :    call gpu_ctx_synch(plan%gpu_ctx_spc)
     457              :    !$OMP END TARGET DATA
     458              : 
     459              :    if (gpu_mode__ /= 0) then
     460              :      !$OMP TARGET UPDATE FROM(ff) IF(transfer_ff)
     461              :      !$OMP TARGET EXIT DATA MAP(delete:ff) IF(transfer_ff)
     462              :    end if
     463              : 
     464              :    return
     465              : #endif
     466              :  end if
     467              : 
     468              :  ! CPU version
     469              : #include "fftbox_ip_driver.finc"
     470              : 
     471           48 : end subroutine fftbox_execute_ip_spc
     472              : !!***
     473              : 
     474              : !----------------------------------------------------------------------
     475              : 
     476              : !!****f* m_fft/fftbox_execute_ip_dpc
     477              : !! NAME
     478              : !!  fftbox_execute_ip_dpc
     479              : !!
     480              : !! FUNCTION
     481              : !!  In-place FFT transform of complex arrays
     482              : !!  Call (FFTW3|DFTI) routines if available, otherwise fallback to SG routines
     483              : !!  TARGET: dp arrays
     484              : !!
     485              : !! INPUTS
     486              : !!  isign= Sign of the exponential in the FFT
     487              : !!  ndat: Number of FFTs.
     488              : !!  [iscale]= 0 if G --> R FFT should not be scaled. Default: 1 i.e. scale
     489              : !!
     490              : !! SIDE EFFECTS
     491              : !!  ff(plan%ldxyz*ndat) =
     492              : !!    In input: the data to transform.
     493              : !!    Changed in output, filled with the FFT results.
     494              : !!
     495              : !! SOURCE
     496              : 
     497        12175 : subroutine fftbox_execute_ip_dpc(plan, ff, isign, ndat, &
     498              :                                  iscale, gpu_mode)  ! optional
     499              : 
     500              : !Arguments ------------------------------------
     501              : !scalars
     502              :  class(fftbox_plan3_t),target,intent(inout) :: plan
     503              :  integer,intent(in) :: isign, ndat
     504              :  integer,optional,intent(in) :: iscale, gpu_mode
     505              : !arrays
     506              :  complex(dp),target,intent(inout) :: ff(plan%ldxyz*ndat)
     507              : !Local variables-------------------------------
     508              :  integer :: ndat__, iscale__, gpu_mode__
     509              : #ifdef HAVE_GPU_CUDA
     510              :  logical :: transfer_ff
     511              : #endif
     512              : ! *************************************************************************
     513              : 
     514              :  !call wrtout(std_out, "in fftbox_execute_ip_dpc")
     515              : 
     516        12175 :  ndat__ = ndat
     517        12175 :  ABI_DEFAULT(iscale__, iscale, 1)
     518        12175 :  ABI_DEFAULT(gpu_mode__, gpu_mode, 0)
     519              : 
     520              :  if (plan%gpu_option == ABI_GPU_OPENMP) then
     521              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
     522              :    ! Build plan if not yet done. note batch_size instead of ndat.
     523              :    if (.not. c_associated(plan%gpu_ctx_dpc)) then
     524              :      call gpu_ctx_init(plan%gpu_ctx_dpc, plan%dims, plan%embed, plan%batch_size, dp)
     525              :    end if
     526              : 
     527              :    if (ndat__ /= plan%batch_size) then
     528              :      ! Have to rebuild the plan with batch_size == ndat.
     529              :      call gpu_ctx_free(plan%gpu_ctx_dpc)
     530              :      call gpu_ctx_init(plan%gpu_ctx_dpc, plan%dims, plan%embed, ndat__, dp)
     531              :    end if
     532              : 
     533              :    plan%batch_size = ndat__
     534              : 
     535              :    transfer_ff = .False.
     536              :    if (gpu_mode__ /= 0) then
     537              :      transfer_ff = .not. xomp_target_is_present(c_loc(ff))
     538              :      !$OMP TARGET ENTER DATA MAP(alloc:ff) IF(transfer_ff)
     539              :      !$OMP TARGET UPDATE TO(ff) IF(transfer_ff)
     540              :    end if
     541              : 
     542              :    !$OMP TARGET DATA USE_DEVICE_ADDR(ff)
     543              :    call gpu_fftbox_c2c_ip(plan%gpu_ctx_dpc, int(plan%nfft), ndat__, isign, iscale__, dp, c_loc(ff))
     544              :    call gpu_ctx_synch(plan%gpu_ctx_dpc)
     545              :    !$OMP END TARGET DATA
     546              : 
     547              :    if (gpu_mode__ /= 0) then
     548              :      !$OMP TARGET UPDATE FROM(ff) IF(transfer_ff)
     549              :      !$OMP TARGET EXIT DATA MAP(delete:ff) IF(transfer_ff)
     550              :    end if
     551              : 
     552              :    return
     553              : #endif
     554              :  end if
     555              : 
     556              :  ! CPU version
     557              : #include "fftbox_ip_driver.finc"
     558              : 
     559        12175 : end subroutine fftbox_execute_ip_dpc
     560              : !!***
     561              : 
     562              : !----------------------------------------------------------------------
     563              : 
     564              : !!****f* m_fft/fftbox_execute_op_spc
     565              : !! NAME
     566              : !!  fftbox_execute_op_spc
     567              : !!
     568              : !! FUNCTION
     569              : !!  Out-of-place FFT transform of complex arrays.
     570              : !!  Call (FFTW3|DFTI) routines if available, otherwise fallback to SG routines
     571              : !!  TARGET: spc arrays
     572              : !!
     573              : !! INPUTS
     574              : !! ff(plan%ldxyz*plan%batch_size)=The input array to be transformed.
     575              : !! isign= Sign of the exponential in the FFT
     576              : !! ndat= Number of FFTs.
     577              : !! [iscale]= 0 if G --> R FFT should not be scaled. Default: 1 i.e. scale
     578              : !!
     579              : !! OUTPUT
     580              : !!  gg(plan%ldxyz*ndat)= The FFT results.
     581              : !!
     582              : !! SOURCE
     583              : 
     584           48 : subroutine fftbox_execute_op_spc(plan, ff, gg, isign, &
     585              :                                  ndat, iscale, gpu_mode)
     586              : 
     587              : !Arguments ------------------------------------
     588              : !scalars
     589              :  class(fftbox_plan3_t),intent(inout) :: plan
     590              :  integer,intent(in) :: isign, ndat
     591              :  integer,optional,intent(in) :: iscale, gpu_mode
     592              : !arrays
     593              :  complex(sp),target,intent(in) :: ff(plan%ldxyz*ndat)
     594              :  complex(sp),target,intent(inout) :: gg(plan%ldxyz*ndat)
     595              : !Local variables-------------------------------
     596              :  integer :: ndat__, iscale__, gpu_mode__
     597              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
     598              :  logical :: transfer_ff, transfer_gg
     599              : #endif
     600              : ! *************************************************************************
     601              : 
     602              :  !call wrtout(std_out, "in fftbox_execute_op_spc")
     603              : 
     604           48 :  ndat__ = ndat
     605           48 :  ABI_DEFAULT(iscale__, iscale, 1)
     606           48 :  ABI_DEFAULT(gpu_mode__, gpu_mode, 0)
     607              : 
     608              :  if (plan%gpu_option == ABI_GPU_OPENMP) then
     609              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
     610              :    ! Build plan if not yet done. note batch_size instead of ndat.
     611              :    if (.not. c_associated(plan%gpu_ctx_spc)) then
     612              :      call gpu_ctx_init(plan%gpu_ctx_spc, plan%dims, plan%embed, plan%batch_size, sp)
     613              :    end if
     614              : 
     615              :    if (ndat__ /= plan%batch_size) then
     616              :      ! Have to rebuild the plan with batch_size == ndat.
     617              :      call gpu_ctx_free(plan%gpu_ctx_spc)
     618              :      call gpu_ctx_init(plan%gpu_ctx_spc, plan%dims, plan%embed, ndat__, sp)
     619              :    end if
     620              : 
     621              :    plan%batch_size = ndat__
     622              : 
     623              :    transfer_ff = .False.; transfer_gg = .False.
     624              :    if (gpu_mode__ /= 0) then
     625              :      transfer_ff = .not. xomp_target_is_present(c_loc(ff))
     626              :      transfer_gg = .not. xomp_target_is_present(c_loc(gg))
     627              :      !$OMP TARGET ENTER DATA MAP(alloc:ff) IF(transfer_ff)
     628              :      !$OMP TARGET UPDATE TO(ff) IF(transfer_ff)
     629              :      !$OMP TARGET ENTER DATA MAP(alloc:gg) IF(transfer_gg)
     630              :    end if
     631              : 
     632              :    !$OMP TARGET DATA USE_DEVICE_ADDR(ff, gg)
     633              :    call gpu_fftbox_c2c_op(plan%gpu_ctx_spc, int(plan%nfft), ndat__, isign, iscale__, sp, c_loc(ff), c_loc(gg))
     634              :    call gpu_ctx_synch(plan%gpu_ctx_spc)
     635              :    !$OMP END TARGET DATA
     636              : 
     637              :    if (gpu_mode__ /= 0) then
     638              :      !$OMP TARGET UPDATE FROM(gg) IF(transfer_gg)
     639              :      !$OMP TARGET EXIT DATA MAP(delete:gg) IF(transfer_gg)
     640              :    end if
     641              : 
     642              :    return
     643              : #endif
     644              :  end if
     645              : 
     646              :  ! CPU version
     647              : #include "fftbox_op_driver.finc"
     648              : 
     649           48 : end subroutine fftbox_execute_op_spc
     650              : !!***
     651              : 
     652              : !----------------------------------------------------------------------
     653              : 
     654              : !!****f* m_fft/fftbox_execute_op_dpc
     655              : !! NAME
     656              : !!  fftbox_execute_op_dpc
     657              : !!
     658              : !! FUNCTION
     659              : !!  Out-of-place FFT transform of complex arrays.
     660              : !!  Call (FFTW3|DFTI) routines if available, otherwise fallback to SG routines
     661              : !!  TARGET: dp arrays
     662              : !!
     663              : !! INPUTS
     664              : !! ff(plan%ldxyz*plan%batch_size)=The input array to be transformed.
     665              : !! isign= Sign of the exponential in the FFT
     666              : !! ndat=Number of FFTs.
     667              : !! [iscale]= 0 if G --> R FFT should not be scaled. Default: 1 i.e. scale
     668              : !!
     669              : !! OUTPUT
     670              : !!  gg(plan%ldxyz*ndat)= The FFT results.
     671              : !!
     672              : !! SOURCE
     673              : 
     674         2910 : subroutine fftbox_execute_op_dpc(plan, ff, gg, isign, ndat, &
     675              :                                  iscale, gpu_mode)  ! optional
     676              : 
     677              : !Arguments ------------------------------------
     678              : !scalars
     679              :  class(fftbox_plan3_t),intent(inout) :: plan
     680              :  integer,intent(in) :: isign, ndat
     681              :  integer,optional,intent(in) :: iscale, gpu_mode
     682              : !arrays
     683              :  complex(dp),target,intent(in) :: ff(plan%ldxyz*ndat)
     684              :  complex(dp),target,intent(inout) :: gg(plan%ldxyz*ndat)
     685              : 
     686              : !Local variables-------------------------------
     687              :  integer :: ndat__, iscale__, gpu_mode__
     688              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
     689              :  logical :: transfer_ff, transfer_gg
     690              : #endif
     691              : ! *************************************************************************
     692              : 
     693              :  !call wrtout(std_out, "in fftbox_execute_op_dpc")
     694              : 
     695         2910 :  ndat__ = ndat
     696         2910 :  ABI_DEFAULT(iscale__, iscale, 1)
     697         2910 :  ABI_DEFAULT(gpu_mode__, gpu_mode, 0)
     698              : 
     699              :  if (plan%gpu_option == ABI_GPU_OPENMP) then
     700              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
     701              :    ! Build plan if not yet done. note batch_size instead of ndat.
     702              :    if (.not. c_associated(plan%gpu_ctx_dpc)) then
     703              :      call gpu_ctx_init(plan%gpu_ctx_dpc, plan%dims, plan%embed, plan%batch_size, dp)
     704              :    end if
     705              : 
     706              :    if (ndat__ /= plan%batch_size) then
     707              :      ! Have to rebuild the plan with batch_size == ndat.
     708              :      call gpu_ctx_free(plan%gpu_ctx_dpc)
     709              :      call gpu_ctx_init(plan%gpu_ctx_dpc, plan%dims, plan%embed, ndat__, dp)
     710              :    end if
     711              : 
     712              :    plan%batch_size = ndat__
     713              : 
     714              :    transfer_ff = .False.; transfer_gg = .False.
     715              :    if (gpu_mode__ /= 0) then
     716              :      transfer_ff = .not. xomp_target_is_present(c_loc(ff))
     717              :      transfer_gg = .not. xomp_target_is_present(c_loc(gg))
     718              :      !$OMP TARGET ENTER DATA MAP(alloc:ff) IF(transfer_ff)
     719              :      !$OMP TARGET UPDATE TO(ff) IF(transfer_ff)
     720              :      !$OMP TARGET ENTER DATA MAP(alloc:gg) IF(transfer_gg)
     721              :    end if
     722              : 
     723              :    !$OMP TARGET DATA USE_DEVICE_ADDR(ff, gg)
     724              :    call gpu_fftbox_c2c_op(plan%gpu_ctx_dpc, int(plan%nfft), ndat__, isign, iscale__, dp, c_loc(ff), c_loc(gg))
     725              :    call gpu_ctx_synch(plan%gpu_ctx_dpc)
     726              :    !$OMP END TARGET DATA
     727              : 
     728              :    if (gpu_mode__ /= 0) then
     729              :      !$OMP TARGET UPDATE FROM(gg) IF(transfer_gg)
     730              :      !$OMP TARGET EXIT DATA MAP(delete:gg) IF(transfer_gg)
     731              :    end if
     732              : 
     733              :    return
     734              : #endif
     735              :  end if
     736              : 
     737              :  ! CPU version
     738              : #include "fftbox_op_driver.finc"
     739              : 
     740         2910 : end subroutine fftbox_execute_op_dpc
     741              : !!***
     742              : 
     743              : !----------------------------------------------------------------------
     744              : 
     745              : !!****f* m_fft/fft_ug_sp
     746              : !! NAME
     747              : !! fft_ug_sp
     748              : !!
     749              : !! FUNCTION
     750              : !! Driver routine for G-->R transform of wavefunctions with zero-padded FFT.
     751              : !! TARGET: single precision real arrays with Re/Im.
     752              : !!
     753              : !! INPUTS
     754              : !!  See fft_ug_dpc
     755              : !!
     756              : !! SOURCE
     757              : 
     758            0 : subroutine fft_ug_sp(npw_k, nfft, nspinor, ndat, mgfft, ngfft, istwf_k, kg_k, gbound_k, ug, ur)
     759              : 
     760              : !Arguments ------------------------------------
     761              : !scalars
     762              :  integer,intent(in) :: npw_k,nfft,nspinor,istwf_k,mgfft,ndat
     763              : !arrays
     764              :  integer,intent(in) :: ngfft(18),gbound_k(2*mgfft+8,2),kg_k(3,npw_k)
     765              :  real(sp),target,intent(in) :: ug(2*npw_k*nspinor*ndat)
     766              :  real(sp),target,intent(out) :: ur(2*nfft*nspinor*ndat)
     767              : 
     768              : !Local variables-------------------------------
     769            0 :  complex(sp),contiguous,pointer :: ug_cplx(:), ur_cplx(:)
     770              : ! *************************************************************************
     771              : 
     772            0 :  call C_F_pointer(c_loc(ug), ug_cplx, shape=[npw_k*nspinor*ndat])
     773            0 :  call C_F_pointer(c_loc(ur), ur_cplx, shape=[nfft*nspinor*ndat])
     774              : 
     775            0 :  call fft_ug_spc(npw_k, nfft, nspinor, ndat, mgfft, ngfft, istwf_k, kg_k, gbound_k, ug_cplx, ur_cplx)
     776              : 
     777            0 : end subroutine fft_ug_sp
     778              : !!***
     779              : 
     780              : !!****f* m_fft/fft_ug_dp
     781              : !! NAME
     782              : !! fft_ug_dp
     783              : !!
     784              : !! FUNCTION
     785              : !! Driver routine for G-->R transform of wavefunctions with zero-padded FFT.
     786              : !! TARGET: double precision real arrays with Re/Im.
     787              : !!
     788              : !! INPUTS
     789              : !!  See fft_ug_dpc
     790              : !!
     791              : !! SOURCE
     792              : 
     793            0 : subroutine fft_ug_dp(npw_k, nfft, nspinor, ndat, mgfft, ngfft, istwf_k, kg_k, gbound_k, ug, ur)
     794              : 
     795              : !Arguments ------------------------------------
     796              : !scalars
     797              :  integer,intent(in) :: npw_k,nfft,nspinor,istwf_k,mgfft,ndat
     798              : !arrays
     799              :  integer,intent(in) :: ngfft(18),gbound_k(2*mgfft+8,2),kg_k(3,npw_k)
     800              :  real(dp),target,intent(in) :: ug(*)  !2*npw_k*nspinor*ndat)
     801              :  real(dp),target,intent(out) :: ur(*) !2*nfft*nspinor*ndat)
     802              : 
     803              : !Local variables-------------------------------
     804            0 :  complex(dp),contiguous,pointer :: ug_cplx(:), ur_cplx(:)
     805              : ! *************************************************************************
     806              : 
     807            0 :  call C_F_pointer(c_loc(ug), ug_cplx, shape=[npw_k*nspinor*ndat])
     808            0 :  call C_F_pointer(c_loc(ur), ur_cplx, shape=[nfft*nspinor*ndat])
     809              : 
     810            0 :  call fft_ug_dpc(npw_k, nfft, nspinor, ndat, mgfft, ngfft, istwf_k, kg_k, gbound_k, ug_cplx, ur_cplx)
     811              : 
     812            0 : end subroutine fft_ug_dp
     813              : !!***
     814              : 
     815              : !----------------------------------------------------------------------
     816              : 
     817              : !!****f* m_fft/fft_ug_spc
     818              : !! NAME
     819              : !! fft_ug_spc
     820              : !!
     821              : !! FUNCTION
     822              : !! Driver routine for G-->R transform of wavefunctions with zero-padded FFT.
     823              : !! TARGET: single precision arrays
     824              : !!
     825              : !! INPUTS
     826              : !! npw_k=number of plane waves for this k-point.
     827              : !! nfft=Number of FFT points.
     828              : !! nspinor=number of spinorial components
     829              : !! ndat=Number of wavefunctions to transform.
     830              : !! mgfft=Max number of FFT divisions
     831              : !! ngfft(18)=information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
     832              : !! istwfk=Option describing the storage of the wavefunction. (at present must be 1)
     833              : !! kg_k(3,npw_k)=G-vectors in reduced coordinates
     834              : !! gbound_k_k(2*mgfft+8,2)=Table for padded-FFT. See sphereboundary.
     835              : !! ug(npw_k*nspinor*ndat)=wavefunctions in reciprocal space
     836              : !!
     837              : !! OUTPUT
     838              : !!  ur(nfft*nspinor*ndat)=wavefunctions in real space.
     839              : !!
     840              : !! SOURCE
     841              : 
     842           36 : subroutine fft_ug_spc(npw_k, nfft, nspinor, ndat, mgfft, ngfft, istwf_k, kg_k, gbound_k, ug, ur)
     843              : 
     844              : !Arguments ------------------------------------
     845              : !scalars
     846              :  integer,intent(in) :: npw_k,nfft,nspinor,istwf_k,mgfft,ndat
     847              : !arrays
     848              :  integer,intent(in) :: ngfft(18),gbound_k(2*mgfft+8,2),kg_k(3,npw_k)
     849              :  complex(sp),intent(in) :: ug(*)  !npw_k*nspinor*ndat)
     850              :  complex(sp),intent(out) :: ur(*) !nfft*nspinor*ndat)
     851              : ! *************************************************************************
     852              : 
     853              : #include "fftug_driver.finc"
     854              : 
     855           36 : end subroutine fft_ug_spc
     856              : !!***
     857              : 
     858              : !----------------------------------------------------------------------
     859              : 
     860              : !!****f* m_fft/fft_ug_dpc
     861              : !! NAME
     862              : !! fft_ug_dpc
     863              : !!
     864              : !! FUNCTION
     865              : !! Driver routine for G-->R transform of wavefunctions with zero-padded FFT.
     866              : !! TARGET: double precision arrays
     867              : !!
     868              : !! INPUTS
     869              : !! npw_k=number of plane waves for this k-point.
     870              : !! nfft=Number of FFT points.
     871              : !! nspinor=number of spinorial components
     872              : !! ndat=Number of wavefunctions to transform.
     873              : !! mgfft=Max number of FFT divisions
     874              : !! ngfft(18)=information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
     875              : !! istwfk=Option describing the storage of the wavefunction. (at present must be 1)
     876              : !! kg_k(3,npw_k)=G-vectors in reduced coordinates
     877              : !! gbound_k_k(2*mgfft+8,2)=Table for padded-FFT. See sphereboundary.
     878              : !! ug(npw_k*nspinor*ndat)=wavefunctions in reciprocal space
     879              : !!
     880              : !! OUTPUT
     881              : !!  ur(nfft*nspinor*ndat)=wavefunctions in real space.
     882              : !!
     883              : !! SOURCE
     884              : 
     885       215011 : subroutine fft_ug_dpc(npw_k, nfft, nspinor, ndat, mgfft, ngfft, istwf_k, kg_k, gbound_k, ug, ur)
     886              : 
     887              : !Arguments ------------------------------------
     888              : !scalars
     889              :  integer,intent(in) :: npw_k,nfft,nspinor,istwf_k,mgfft,ndat
     890              : !arrays
     891              :  integer,intent(in) :: ngfft(18),gbound_k(2*mgfft+8,2),kg_k(3,npw_k)
     892              :  complex(dp),intent(in) :: ug(*)  !npw_k*nspinor*ndat)
     893              :  complex(dp),intent(out) :: ur(*) !nfft*nspinor*ndat)
     894              : ! *************************************************************************
     895              : 
     896              : #include "fftug_driver.finc"
     897              : 
     898       215011 : end subroutine fft_ug_dpc
     899              : !!***
     900              : 
     901              : !!****f* m_fft/fft_ur_dp
     902              : !! NAME
     903              : !! fft_ur_dp
     904              : !!
     905              : !! FUNCTION
     906              : !! Compute ndat zero-padded FFTs from R- to G-space .
     907              : !! Mainly used for the transform of wavefunctions.
     908              : !! TARGET: double precision real arrays with re/im
     909              : !!
     910              : !! INPUTS
     911              : !!  See fft_ur_dpc
     912              : !!
     913              : !! SOURCE
     914              : 
     915            0 : subroutine fft_ur_dp(npw_k, nfft, nspinor, ndat, mgfft, ngfft, istwf_k, kg_k, gbound_k, ur, ug)
     916              : 
     917              : !Arguments ------------------------------------
     918              : !scalars
     919              :  integer,intent(in) :: npw_k,nfft,nspinor,ndat,istwf_k,mgfft
     920              : !arrays
     921              :  integer,intent(in) :: ngfft(18),gbound_k(2*mgfft+8,2), kg_k(3,npw_k)
     922              :  real(dp),target,intent(inout) :: ur(*) !2*nfft*nspinor*ndat)
     923              :  real(dp),target,intent(out) :: ug(*)   !2*npw_k*nspinor*ndat)
     924              : 
     925              : !Local variables-------------------------------
     926            0 :  complex(dp),contiguous,pointer :: ug_cplx(:), ur_cplx(:)
     927              : ! *************************************************************************
     928              : 
     929            0 :  call C_F_pointer(c_loc(ug), ug_cplx, shape=[npw_k*nspinor*ndat])
     930            0 :  call C_F_pointer(c_loc(ur), ur_cplx, shape=[nfft*nspinor*ndat])
     931            0 :  call fft_ur_dpc(npw_k, nfft, nspinor, ndat, mgfft, ngfft, istwf_k, kg_k, gbound_k, ur_cplx, ug_cplx)
     932              : 
     933            0 : end subroutine fft_ur_dp
     934              : !!***
     935              : 
     936              : !----------------------------------------------------------------------
     937              : 
     938              : !!****f* m_fft/fft_ur_spc
     939              : !! NAME
     940              : !! fft_ur_spc
     941              : !!
     942              : !! FUNCTION
     943              : !! Compute ndat zero-padded FFTs from R- to G-space .
     944              : !! Mainly used for the transform of wavefunctions.
     945              : !! TARGET: spc complex arrays
     946              : !!
     947              : !! INPUTS
     948              : !! npw_k=number of plane waves for this k-point.
     949              : !! nfft=Number of FFT points.
     950              : !! nspinor=number of spinorial components
     951              : !! ndat=Number of wavefunctions to transform.
     952              : !! mgfft=Max number of FFT divisions
     953              : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
     954              : !! istwfk=Option describing the storage of the wavefunction. (at present must be 1)
     955              : !! kg_k(3,npw_k)=G-vectors in reduced coordinates
     956              : !! gbound_k(2*mgfft+8,2)=Table for padded-FFT. See sphereboundary.
     957              : !!
     958              : !! SIDE EFFECTS
     959              : !!  ur(nfft*nspinor*ndat)=In input: wavefunctions in real space
     960              : !!                        Destroyed in output. Do not use ur anymore!
     961              : !!
     962              : !! OUTPUT
     963              : !!  ug(npw_k*nspinor*ndat)=wavefunctions in reciprocal space given on the G-sphere.
     964              : !!
     965              : !! SOURCE
     966              : 
     967           36 : subroutine fft_ur_spc(npw_k, nfft, nspinor, ndat, mgfft, ngfft, istwf_k, kg_k, gbound_k, ur, ug)
     968              : 
     969              : !Arguments ------------------------------------
     970              : !scalars
     971              :  integer,intent(in) :: npw_k,nfft,nspinor,ndat,istwf_k,mgfft
     972              : !arrays
     973              :  integer,intent(in) :: ngfft(18),gbound_k(2*mgfft+8,2),kg_k(3,npw_k)
     974              :  complex(sp),intent(inout) :: ur(*) !nfft*nspinor*ndat)
     975              :  complex(sp),intent(out) :: ug(*)   !npw_k*nspinor*ndat)
     976              : ! *************************************************************************
     977              : 
     978              : #include "fftur_driver.finc"
     979              : 
     980           36 : end subroutine fft_ur_spc
     981              : !!***
     982              : 
     983              : !----------------------------------------------------------------------
     984              : 
     985              : !!****f* m_fft/fft_ur_dpc
     986              : !! NAME
     987              : !! fft_ur_dpc
     988              : !!
     989              : !! FUNCTION
     990              : !! Compute ndat zero-padded FFTs from R- to G-space .
     991              : !! Mainly used for the transform of wavefunctions.
     992              : !! TARGET: dp complex arrays
     993              : !!
     994              : !! INPUTS
     995              : !! npw_k=number of plane waves for this k-point.
     996              : !! nfft=Number of FFT points.
     997              : !! nspinor=number of spinorial components
     998              : !! ndat=Number of wavefunctions to transform.
     999              : !! mgfft=Max number of FFT divisions
    1000              : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    1001              : !! istwfk=Option describing the storage of the wavefunction. (at present must be 1)
    1002              : !! kg_k(3,npw_k)=G-vectors in reduced coordinates
    1003              : !! gbound_k(2*mgfft+8,2)=Table for padded-FFT. See sphereboundary.
    1004              : !!
    1005              : !! SIDE EFFECTS
    1006              : !!  ur(nfft*nspinor*ndat)=In input: wavefunctions in real space
    1007              : !!                        Destroyed in output. Do not use ur anymore!
    1008              : !!
    1009              : !! OUTPUT
    1010              : !!  ug(npw_k*nspinor*ndat)=wavefunctions in reciprocal space given on the G-sphere.
    1011              : !!
    1012              : !! SOURCE
    1013              : 
    1014       780009 : subroutine fft_ur_dpc(npw_k, nfft, nspinor, ndat, mgfft, ngfft, istwf_k, kg_k, gbound_k, ur, ug)
    1015              : 
    1016              : !Arguments ------------------------------------
    1017              : !scalars
    1018              :  integer,intent(in) :: npw_k,nfft,nspinor,ndat,istwf_k,mgfft
    1019              : !arrays
    1020              :  integer,intent(in) :: ngfft(18),gbound_k(2*mgfft+8,2),kg_k(3,npw_k)
    1021              :  complex(dp),intent(inout) :: ur(*) ! nfft*nspinor*ndat)
    1022              :  complex(dp),intent(out) :: ug(*)   ! npw_k*nspinor*ndat)
    1023              : ! *************************************************************************
    1024              : 
    1025              : #include "fftur_driver.finc"
    1026              : 
    1027       780009 : end subroutine fft_ur_dpc
    1028              : !!***
    1029              : 
    1030              : !----------------------------------------------------------------------
    1031              : 
    1032              : !!****f* m_fft/fftpad_spc
    1033              : !! NAME
    1034              : !!  fftpad_spc
    1035              : !!
    1036              : !! FUNCTION
    1037              : !!  Driver routine used to transform COMPLEX arrays using 3D zero-padded FFTs.
    1038              : !!  TARGET: single-precision complex.
    1039              : !!
    1040              : !! INPUTS
    1041              : !!  ngfft(18)=Info on the 3D FFT.
    1042              : !!  nx,ny,nz=Logical dimensions of the FFT mesh.
    1043              : !!  ldx,ldy,ldz=Physical dimension of the f array (to avoid cache conflicts).
    1044              : !!  ndat=Number of FFTs
    1045              : !!  mgfft=MAX(nx,ny,nz), only used to dimension gbound
    1046              : !!  isign=The sign of the transform.
    1047              : !!  gbound(2*mgfft+8,2)= The boundaries of the basis sphere of G vectors at a given k-point.
    1048              : !!    See sphereboundary for more info.
    1049              : !!
    1050              : !! SIDE EFFECTS
    1051              : !!  ff(ldx*ldy*ldz*ndat)=
    1052              : !!    input: The array with the data to be transformed.
    1053              : !!    output: The results of the FFT.
    1054              : !!
    1055              : !! SOURCE
    1056              : 
    1057            0 : subroutine fftpad_spc(ff, ngfft, nx, ny, nz, ldx, ldy, ldz, ndat, mgfft, isign, gbound)
    1058              : 
    1059              : !Arguments ------------------------------------
    1060              : !scalars
    1061              :  integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,isign
    1062              : !arrays
    1063              :  integer,intent(in) :: ngfft(18),gbound(2*mgfft+8,2)
    1064              :  complex(sp),target,intent(inout) :: ff(ldx*ldy*ldz*ndat)
    1065              : 
    1066              : !Local variables-------------------------------
    1067              : !scalars
    1068              :  integer :: fftalg,fftalga,fftalgc,ncount,p
    1069              :  character(len=500) :: msg
    1070              : !arrays
    1071            0 :  real(dp),allocatable :: fofr(:,:),ftarr(:,:)
    1072              : ! *************************************************************************
    1073              : 
    1074            0 :  fftalg=ngfft(7); fftalga=fftalg/100; fftalgc=MOD(fftalg,10)
    1075              : 
    1076            0 :  select case (fftalga)
    1077              : 
    1078              :  case (FFT_FFTW3)
    1079            0 :    call fftw3_fftpad(ff, nx, ny, nz, ldx, ldy, ldz, ndat, mgfft, isign, gbound)
    1080              : 
    1081              :  case (FFT_DFTI)
    1082            0 :    call dfti_fftpad(ff, nx, ny, nz, ldx, ldy, ldz, ndat, mgfft, isign, gbound)
    1083              : 
    1084              :  case (FFT_SG)
    1085              :    ! Goedecker"s routines.
    1086              :    ! TODO: sg_fftpad is not the fastest routine, here I should call sg_fftrisc but I need
    1087              :    ! kg_kin that are not available in rho_tw_g, actually one should pass G-G0 due to
    1088              :    ! the shift introduced by the umklapp.
    1089            0 :    ncount = ldx*ldy*ldz*ndat
    1090              : 
    1091            0 :    ABI_MALLOC(fofr,(2,ldx*ldy*ldz*ndat))
    1092            0 :    ABI_MALLOC(ftarr,(2,ldx*ldy*ldz*ndat))
    1093              : 
    1094            0 :    do p=1,ldx*ldy*ldz*ndat
    1095            0 :      fofr(1,p) = REAL(ff(p))
    1096            0 :      fofr(2,p) = AIMAG(ff(p))
    1097              :    end do
    1098              : 
    1099            0 :    call sg_fftpad(ngfft(8),mgfft,nx,ny,nz,ldx,ldy,ldz,ndat,gbound,isign,fofr,ftarr)
    1100              :    !
    1101              :    ! Copy the results.
    1102            0 :    do p=1,ldx*ldy*ldz*ndat
    1103            0 :      ff(p) = CMPLX(ftarr(1,p), ftarr(2,p))
    1104              :    end do
    1105              : 
    1106            0 :    if (isign==-1) then  ! Here there might be numerical exceptions due to the holes.
    1107            0 :      ff = ff/(nx*ny*nz)
    1108              :    end if
    1109              : 
    1110            0 :    ABI_FREE(ftarr)
    1111            0 :    ABI_FREE(fofr)
    1112              : 
    1113              :  case default
    1114            0 :    write(msg,'(a,i0,a)')"fftalga = ", fftalga," not coded "
    1115            0 :    ABI_ERROR(msg)
    1116              :  end select
    1117              : 
    1118            0 : end subroutine fftpad_spc
    1119              : !!***
    1120              : 
    1121              : !----------------------------------------------------------------------
    1122              : 
    1123              : !!****f* m_fft/fftpad_dpc
    1124              : !! NAME
    1125              : !!  fftpad_dpc
    1126              : !!
    1127              : !! FUNCTION
    1128              : !!  Driver routine used to transform COMPLEX arrays using 3D zero-padded FFTs.
    1129              : !!  TARGET: DP arrays
    1130              : !!
    1131              : !! INPUTS
    1132              : !!  ngfft(18)=Info on the 3D FFT.
    1133              : !!  nx,ny,nz=Logical dimensions of the FFT mesh.
    1134              : !!  ldx,ldy,ldz=Physical dimension of the f array (to avoid cache conflicts).
    1135              : !!  ndat=Number of FFTs
    1136              : !!  mgfft=MAX(nx,ny,nz), only used to dimension gbound
    1137              : !!  isign=The sign of the transform.
    1138              : !!  gbound(2*mgfft+8,2)= The boundaries of the basis sphere of G vectors at a given k-point. See sphereboundary for more info.
    1139              : !!
    1140              : !! SIDE EFFECTS
    1141              : !!  ff(ldx*ldy*ldz*ndat)=
    1142              : !!    input: The array with the data to be transformed.
    1143              : !!    output: The results of the FFT.
    1144              : !!
    1145              : !! SOURCE
    1146              : 
    1147      5733916 : subroutine fftpad_dpc(ff, ngfft, nx, ny, nz, ldx, ldy, ldz, ndat, mgfft, isign, gbound)
    1148              : 
    1149              : !Arguments ------------------------------------
    1150              : !scalars
    1151              :  integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,isign
    1152              : !arrays
    1153              :  integer,intent(in) :: ngfft(18),gbound(2*mgfft+8,2)
    1154              :  complex(dp),target,intent(inout) :: ff(ldx*ldy*ldz*ndat)
    1155              : 
    1156              : !Local variables-------------------------------
    1157              : !scalars
    1158              :  integer :: fftalg,fftalga,fftalgc,ncount, ivz
    1159              : !arrays
    1160      5733916 :  real(dp),allocatable :: fofr(:,:,:,:,:), fofrvz(:,:)
    1161      5733916 :  real(dp),contiguous, pointer :: fpt_ftarr(:,:,:,:,:)
    1162              : ! *************************************************************************
    1163              : 
    1164      5733916 :  fftalg=ngfft(7); fftalga=fftalg/100; fftalgc=MOD(fftalg,10)
    1165              : 
    1166            0 :  select case (fftalga)
    1167              : 
    1168              :  case (FFT_FFTW3)
    1169            0 :    call fftw3_fftpad(ff, nx, ny, nz, ldx, ldy, ldz, ndat, mgfft, isign, gbound)
    1170              : 
    1171              :  case (FFT_DFTI)
    1172      5733911 :    call dfti_fftpad(ff, nx, ny, nz, ldx, ldy, ldz, ndat, mgfft, isign, gbound)
    1173              : 
    1174              :  case (FFT_SG)
    1175              :    ! Goedecker"s routines.
    1176              :    ! TODO: sg_fftpad is not the fastest routine, here I should call sg_fftrisc but I need
    1177              :    ! kg_kin that is not available in rho_tw_g, actually one should pass G-G0 due to
    1178              :    ! the shift introduced by the umklapp.
    1179            5 :    ncount = ldx*ldy*ldz*ndat
    1180              : 
    1181           30 :    ABI_MALLOC(fofr, (2,ldx,ldy,ldz,ndat))
    1182              :    !call ZCOPY(ncount,ff,1,fofr,1) !vz_d
    1183              :    !call DCOPY(2*ncount,ff,1,fofr,1)  ! MG
    1184              :    ! alternative of ZCOPY from vz
    1185           15 :    ABI_MALLOC(fofrvz,(2,ncount))
    1186      3645005 :    do ivz=1,ncount
    1187      3645000 :      fofrvz(1,ivz)= real(ff(ivz))
    1188      3645005 :      fofrvz(2,ivz)=aimag(ff(ivz))
    1189              :    end do
    1190            5 :    call DCOPY(2*ncount,fofrvz,1,fofr,1)
    1191            5 :    ABI_FREE(fofrvz)
    1192              : 
    1193            5 :    call C_F_pointer(C_loc(ff),fpt_ftarr, shape=(/2,ldx,ldy,ldz,ndat/))
    1194              : 
    1195              :    !  MT nov. 2012: with xlf, need to put explicit boundaries for the 4th dimension
    1196              :    !  this looks like a compiler bug...
    1197              :    !if (size(fpt_ftarr)==2*size(ff)) then
    1198            5 :    call sg_fftpad(ngfft(8),mgfft,nx,ny,nz,ldx,ldy,ldz,ndat,gbound,isign,fofr,fpt_ftarr)
    1199              :    !else
    1200              :    !  call sg_fftpad(ngfft(8),mgfft,nx,ny,nz,ldx,ldy,ldz,ndat,gbound,isign,fofr,fpt_ftarr(:,:,:,1:ldz,dat))
    1201              :    !end if
    1202              : 
    1203            5 :    ABI_FREE(fofr)
    1204              : 
    1205            5 :    if (isign==-1) then  ! Here there might be numerical exceptions due to the holes.
    1206            5 :      call xscal(ncount,one/(nx*ny*nz),ff,1)
    1207              :    end if
    1208              : 
    1209              :  case default
    1210            0 :    ABI_BUG(sjoin("Wrong value for fftalga: ",itoa(fftalga)))
    1211              :  end select
    1212              : 
    1213      5733916 : end subroutine fftpad_dpc
    1214              : !!***
    1215              : 
    1216              : !----------------------------------------------------------------------
    1217              : 
    1218              : !!****f* m_fft/fft_poisson
    1219              : !! NAME
    1220              : !! fft_poisson
    1221              : !!
    1222              : !! FUNCTION
    1223              : !!  Driver routine to solve the Poisson equation in G-space given the density, n(r),
    1224              : !!  in real space of the FFT box.
    1225              : !!
    1226              : !! INPUTS
    1227              : !! ngfft(18)=Info on the 3D FFT.
    1228              : !! cplex=1 if fofr is real, 2 if fofr is complex
    1229              : !! nx,ny,nz=Number of FFT points along the three directions.
    1230              : !! ldx,ldy,ldz=Leading dimension of the array nr and vg.
    1231              : !! ndat = Number of densities
    1232              : !! vg(nx*ny*nz)=Potential in reciprocal space.
    1233              : !!
    1234              : !! SIDE EFFECTS
    1235              : !! nr(cplex*ldx*ldy*ldz*ndat)
    1236              : !!    input: n(r) (real or complex)
    1237              : !!    output: the hartree potential in real space
    1238              : !!
    1239              : !! NOTES
    1240              : !!   vg is given on the FFT mesh instead of the augmented mesh [ldx,ldy,ldz]
    1241              : !!   in order to simplify the interface with the other routines operating of vg
    1242              : !!
    1243              : !! SOURCE
    1244              : 
    1245            0 : subroutine fft_poisson(ngfft, cplex, nx, ny, nz, ldx, ldy, ldz, ndat, vg, nr)
    1246              : 
    1247              : !Arguments ------------------------------------
    1248              : !scalars
    1249              :  integer,intent(in) :: cplex,nx,ny,nz,ldx,ldy,ldz,ndat
    1250              :  integer,intent(in) :: ngfft(18)
    1251              : !arrays
    1252              :  real(dp),intent(inout) :: nr(cplex*ldx*ldy*ldz*ndat)
    1253              :  real(dp),intent(in) :: vg(nx*ny*nz)
    1254              : 
    1255              : !Local variables-------------------------------
    1256              :  integer :: fftalga, fftcache
    1257              : ! *************************************************************************
    1258              : 
    1259            0 :  fftalga = ngfft(7)/100; fftcache = ngfft(8)
    1260              : 
    1261            0 :  select case (fftalga)
    1262              :  case (FFT_SG, FFT_SG2002)
    1263              :    ! Note: according to my tests fftalg 1xx is always faster than 4xx in sequential
    1264              :    ! hence it does not make sense to provide a fallback for fftalg 4xx.
    1265              :    ! Use external FFT libraries if you want to run at top-level speed.
    1266            0 :    call sg_poisson(fftcache,cplex,nx,ny,nz,ldx,ldy,ldz,ndat,vg,nr)
    1267              : 
    1268              :  case (FFT_FFTW3)
    1269            0 :    call fftw3_poisson(cplex,nx,ny,nz,ldx,ldy,ldz,ndat,vg,nr)
    1270              : 
    1271              :  !case (FFT_DFTI)
    1272              :  !  call dfti_poisson(cplex,nx,ny,nz,ldx,ldy,ldz,ndat,vg,nr)
    1273              : 
    1274              :  case default
    1275            0 :    ABI_BUG(sjoin("Wrong value for fftalga: ",itoa(fftalga)))
    1276              :  end select
    1277              : 
    1278            0 : end subroutine fft_poisson
    1279              : !!***
    1280              : 
    1281              : !----------------------------------------------------------------------
    1282              : 
    1283              : !!****f* m_fft/fft_use_lib_threads
    1284              : !! NAME
    1285              : !! fft_use_lib_threads
    1286              : !!
    1287              : !! FUNCTION
    1288              : !!
    1289              : !! INPUTS
    1290              : !!
    1291              : !! OUTPUT
    1292              : !!
    1293              : !! SOURCE
    1294              : 
    1295           19 : subroutine fft_use_lib_threads(logvar)
    1296              : 
    1297              : !Arguments ------------------------------------
    1298              :  logical,intent(in) :: logvar
    1299              : ! *************************************************************************
    1300              : 
    1301           19 :  call dfti_use_lib_threads(logvar)
    1302           19 :  call fftw3_use_lib_threads(logvar)
    1303              : 
    1304           19 : end subroutine fft_use_lib_threads
    1305              : !!***
    1306              : 
    1307              : !----------------------------------------------------------------------
    1308              : 
    1309              : !!****f* m_fft/fftbox_utests
    1310              : !! NAME
    1311              : !!  fftbox_utests
    1312              : !!
    1313              : !! FUNCTION
    1314              : !! Driver routine for base unitary tests of the FFT routines (sequential version).
    1315              : !!
    1316              : !! INPUTS
    1317              : !! fftalg =fftalg input variable.
    1318              : !! ndat = Number of transform to execute
    1319              : !! nthreads = Number of OpenMP threads.
    1320              : !! gpu_option= GPU version to active (0: no GPU).
    1321              : !! [unit]=Output Unit number (DEFAULT std_out)
    1322              : !!
    1323              : !! OUTPUT
    1324              : !!  nfailed=number of failures.
    1325              : !!
    1326              : !! SOURCE
    1327              : 
    1328            4 : integer function fftbox_utests(fftalg, ndat, nthreads, gpu_option, unit) result(nfailed)
    1329              : 
    1330              : !Arguments -----------------------------------
    1331              : !scalars
    1332              :  integer,intent(in) :: fftalg, ndat, nthreads, gpu_option
    1333              :  integer,optional,intent(in) :: unit
    1334              : 
    1335              : !Local variables-------------------------------
    1336              : !scalars
    1337              :  integer,parameter :: NSETS=6, fftcache0 = 0
    1338              :  integer :: ifft,ierr,ldxyz,old_nthreads,ount,cplex,ii
    1339              :  integer :: iset,nx,ny,nz,ldx,ldy,ldz,fftalga,fftalgc
    1340              :  real(dp),parameter :: ATOL_SP=tol6,ATOL_DP=tol12 ! Tolerances on the absolute errors
    1341              :  real(dp) :: max_abserr
    1342              :  character(len=500) :: msg,info,library,cplex_mode,padding_mode
    1343              :  type(fftbox_plan3_t) :: box_plan
    1344              : !arrays
    1345              :  integer :: pars(6,NSETS), ngfft(18)
    1346              :  real(dp) :: crand(2)
    1347            4 :  real(dp),allocatable :: fofg(:),fofr_ref(:),fofr(:)
    1348            4 :  complex(dp),allocatable :: ff(:),ff_ref(:),gg(:)
    1349            4 :  complex(sp),allocatable :: ffsp(:),ff_refsp(:),ggsp(:)
    1350              : ! *************************************************************************
    1351              : 
    1352            4 :  nfailed = 0
    1353            0 :  ount = std_out; if (PRESENT(unit)) ount = unit
    1354              :  !return
    1355              : 
    1356            4 :  if (nthreads > 0) then
    1357            4 :    old_nthreads = xomp_get_max_threads()
    1358            4 :    call xomp_set_num_threads(nthreads)
    1359              :  end if
    1360              : 
    1361              :  ! These values must be compatible with all the FFT routines.
    1362              :  ! SG library is the most restrictive (only powers of 2,3,5).
    1363              :  pars = RESHAPE( [   &
    1364              :    12, 18, 15, 12, 18, 15, &
    1365              :    12, 18, 15, 13, 19, 16, &
    1366              :    12, 18, 15, 13, 19, 15, &
    1367              :    12, 18, 15, 12, 18, 16, &
    1368              :    12, 18, 15, 13, 18, 15, &
    1369              :    12, 18, 15, 15, 21, 18  &
    1370            4 :  ], [6, NSETS])
    1371              :  !pars = 10 * pars
    1372              : 
    1373            4 :  if (gpu_option /= ABI_GPU_DISABLED) then
    1374              :    ! Augmentation is not supported for GPUS.
    1375            0 :    do ii=1,NSETS
    1376            0 :      pars(4:6, ii) = pars(1:3, ii)
    1377              :    end do
    1378              :  end if
    1379              : 
    1380            4 :  fftalga=fftalg/100; fftalgc=mod(fftalg,10)
    1381              : 
    1382            4 :  call fftalg_info(fftalg, library, cplex_mode, padding_mode)
    1383              : 
    1384           28 :  do iset=1,SIZE(pars,DIM=2)
    1385              :    !if (iset == 2) return
    1386           24 :    nx =pars(1,iset);  ny=pars(2,iset);  nz=pars(3,iset)
    1387           24 :    ldx=pars(4,iset); ldy=pars(5,iset); ldz=pars(6,iset)
    1388              : 
    1389           96 :    call ngfft_seq(ngfft, [nx,ny,nz])
    1390           96 :    ngfft(4:6) = [ldx, ldy, ldz]
    1391              : 
    1392              :    ! Create the FFT plan
    1393           24 :    call box_plan%init(ndat, pars(1,iset), pars(4,iset), fftalg, fftcache0, gpu_option)
    1394              : 
    1395           24 :    ldxyz = ldx*ldy*ldz
    1396              : 
    1397              :    ! ======================================
    1398              :    ! === TEST the single precision version
    1399              :    ! ======================================
    1400           72 :    ABI_MALLOC(ff_refsp, (ldxyz*ndat))
    1401           48 :    ABI_MALLOC(ffsp,     (ldxyz*ndat))
    1402           48 :    ABI_MALLOC(ggsp,     (ldxyz*ndat))
    1403              : 
    1404       235354 :    do ifft=1,ldxyz*ndat
    1405       235330 :      call RANDOM_NUMBER(crand)
    1406       235354 :      ff_refsp(ifft) = DCMPLX(crand(1), crand(2))
    1407              :    end do
    1408              :    ! Set the augmentation region to zero to avoid SIGFPE, as FFTW3 wrappers use zscal to scale the results.
    1409           24 :    call cplx_setaug_zero_spc(nx,ny,nz,ldx,ldy,ldz,ndat,ff_refsp)
    1410              : 
    1411              :    ! in-place version.
    1412       235378 :    ffsp = ff_refsp
    1413              : #ifdef HAVE_OPENMP_OFFLOAD
    1414              :    !$OMP TARGET ENTER DATA MAP(to:ffsp) IF (gpu_option == ABI_GPU_OPENMP)
    1415              : #endif
    1416           24 :    call box_plan%execute(ffsp, +1, ndat)
    1417           24 :    call box_plan%execute(ffsp, -1, ndat)
    1418              : #ifdef HAVE_OPENMP_OFFLOAD
    1419              :    !$OMP TARGET EXIT DATA MAP(from:ffsp) IF (gpu_option == ABI_GPU_OPENMP)
    1420              : #endif
    1421              : 
    1422       235354 :    ierr = COUNT(ABS(ffsp - ff_refsp) > ATOL_SP)
    1423           24 :    nfailed = nfailed + ierr
    1424           24 :    info = sjoin(library, "c2c_ip_spc :")
    1425           24 :    write(msg,"(a)")" OK"
    1426           24 :    if (ierr /= 0) then
    1427            0 :      max_abserr = MAXVAL(ABS(ffsp - ff_refsp))
    1428            0 :      write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1429              :    end if
    1430           24 :    call wrtout(ount, sjoin(info,msg))
    1431              : 
    1432              :    ! out-of-place version.
    1433       235378 :    ffsp = ff_refsp
    1434              : #ifdef HAVE_OPENMP_OFFLOAD
    1435              :    !$OMP TARGET ENTER DATA MAP(to:ffsp) MAP(alloc: ggsp) IF (gpu_option == ABI_GPU_OPENMP)
    1436              : #endif
    1437           24 :    call box_plan%execute(ffsp, ggsp, +1, ndat)
    1438       235354 :    ffsp = zero
    1439           24 :    call box_plan%execute(ggsp, ffsp, -1, ndat)
    1440              : #ifdef HAVE_OPENMP_OFFLOAD
    1441              :    !$OMP TARGET EXIT DATA MAP(from:ffsp) IF (gpu_option == ABI_GPU_OPENMP)
    1442              : #endif
    1443              : 
    1444       235354 :    ierr = COUNT(ABS(ffsp - ff_refsp) > ATOL_SP)
    1445           24 :    nfailed = nfailed + ierr
    1446           24 :    info = sjoin(library, "c2c_op_spc :")
    1447           24 :    write(msg,"(a)")" OK"
    1448           24 :    if (ierr /= 0) then
    1449            0 :      max_abserr = MAXVAL(ABS(ffsp - ff_refsp))
    1450            0 :      write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1451              :    end if
    1452           24 :    call wrtout(ount, sjoin(info, msg))
    1453              : 
    1454              : #ifdef HAVE_OPENMP_OFFLOAD
    1455              :    !$OMP TARGET EXIT DATA MAP(delete: ffsp, ggsp) if (gpu_option == ABI_GPU_OPENMP)
    1456              : #endif
    1457           24 :    ABI_FREE(ffsp)
    1458           24 :    ABI_FREE(ggsp)
    1459           24 :    ABI_FREE(ff_refsp)
    1460              : 
    1461              :    ! =======================================
    1462              :    ! === TEST the double precision version
    1463              :    ! =======================================
    1464           72 :    ABI_MALLOC(ff_ref, (ldxyz*ndat))
    1465           48 :    ABI_MALLOC(ff,     (ldxyz*ndat))
    1466           48 :    ABI_MALLOC(gg,     (ldxyz*ndat))
    1467              : 
    1468       235354 :    do ifft=1,ldxyz*ndat
    1469       235330 :      call RANDOM_NUMBER(crand)
    1470       235354 :      ff_ref(ifft) = DCMPLX(crand(1), crand(2))
    1471              :    end do
    1472              : 
    1473              :    ! Set the augmentation region to zero to avoid SIGFPE, as FFTW3 wrappers use zscal to scale the results.
    1474           24 :    call cplx_setaug_zero_dpc(nx,ny,nz,ldx,ldy,ldz,ndat,ff_ref)
    1475              : 
    1476              :    ! in-place version.
    1477       235378 :    ff = ff_ref
    1478              : #ifdef HAVE_OPENMP_OFFLOAD
    1479              :    !$OMP TARGET ENTER DATA MAP(to:ff) IF (gpu_option == ABI_GPU_OPENMP)
    1480              : #endif
    1481           24 :    call box_plan%execute(ff, +1, ndat)
    1482           24 :    call box_plan%execute(ff, -1, ndat)
    1483              : #ifdef HAVE_OPENMP_OFFLOAD
    1484              :    !$OMP TARGET EXIT DATA MAP(from:ff) IF (gpu_option == ABI_GPU_OPENMP)
    1485              : #endif
    1486              : 
    1487       235354 :    ierr = COUNT(ABS(ff - ff_ref) > ATOL_DP)
    1488           24 :    nfailed = nfailed + ierr
    1489              : 
    1490           24 :    info = sjoin(library, "c2c_ip_dpc :")
    1491           24 :    write(msg,"(a)")" OK"
    1492           24 :    if (ierr /= 0) then
    1493            0 :      max_abserr = MAXVAL(ABS(ff - ff_ref))
    1494            0 :      write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1495              :    end if
    1496           24 :    call wrtout(ount,sjoin(info, msg))
    1497              : 
    1498              :    ! out-of-place version.
    1499       235378 :    ff = ff_ref
    1500              : #ifdef HAVE_OPENMP_OFFLOAD
    1501              :    !$OMP TARGET ENTER DATA MAP(to:ff) MAP(alloc:gg) IF (gpu_option == ABI_GPU_OPENMP)
    1502              : #endif
    1503           24 :    call box_plan%execute(ff, gg, +1, ndat)
    1504       235354 :    ff = zero
    1505           24 :    call box_plan%execute(gg, ff, -1, ndat)
    1506              : #ifdef HAVE_OPENMP_OFFLOAD
    1507              :    !$OMP TARGET EXIT DATA MAP(from:ff) IF (gpu_option == ABI_GPU_OPENMP)
    1508              : #endif
    1509              : 
    1510       235354 :    ierr = COUNT(ABS(ff - ff_ref) > ATOL_DP)
    1511           24 :    nfailed = nfailed + ierr
    1512              : 
    1513           24 :    info = sjoin(library, "c2c_op_dpc :")
    1514           24 :    write(msg,"(a)")" OK"
    1515           24 :    if (ierr /= 0) then
    1516            0 :      max_abserr = MAXVAL(ABS(ff - ff_ref))
    1517            0 :      write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1518              :    end if
    1519           24 :    call wrtout(ount, sjoin(info, msg))
    1520              : 
    1521              : #ifdef HAVE_OPENMP_OFFLOAD
    1522              :    !$OMP TARGET EXIT DATA MAP(delete: ff, gg) if (gpu_option == ABI_GPU_OPENMP)
    1523              : #endif
    1524           24 :    ABI_FREE(ff)
    1525           24 :    ABI_FREE(gg)
    1526           24 :    ABI_FREE(ff_ref)
    1527              : 
    1528           24 :    call box_plan%free() !; stop
    1529              : 
    1530           76 :    do cplex=1,2
    1531              :      !if (fftalga == FFT_FFTW3 .and. ndat > 1 .and. cplex==1) then
    1532              :      !  call wrtout(ount,"Warning: fourdp with FFTW3-wrappers, cplex=2 and ndat>1, might crash if MKL is used")
    1533              :      !  !CYCLE
    1534              :      !end if
    1535              : 
    1536              :      ! MG: June 24. 2025
    1537              :      ! dfti_seqfourdp does not work as expected when cplex= 1 and ngfft(1:3) != ngfft(4:6)
    1538              :      ! very likely do the use of r->c, c->r transforms.
    1539              :      ! I don't know if it's a bug as the error seems to depend on the mkl version.
    1540              :      ! To bypass this problem, we change the params on the fly so that ngfft(1:3) == ngfft(4:6)
    1541              :      ! when FFT_DFTI is used.
    1542              :      ! Note however that we never call fourdp with ngfft(1:3) != ngftt(4:6) so this is not a serious problem.
    1543              :      ! An additional check is done inside dfti_seqfourdp
    1544           48 :      if (fftalga == FFT_DFTI) then
    1545           24 :        ldx=nx; ldy=ny; ldz=nz
    1546           24 :        ldxyz = ldx*ldy*ldz
    1547              :      endif
    1548              : 
    1549          144 :      ABI_MALLOC(fofg,     (2*ldxyz*ndat))
    1550          144 :      ABI_MALLOC(fofr_ref, (cplex*ldxyz*ndat))
    1551           96 :      ABI_MALLOC(fofr,     (cplex*ldxyz*ndat))
    1552              : 
    1553           48 :      call RANDOM_NUMBER(fofr_ref)
    1554           48 :      call cg_setaug_zero(cplex,nx,ny,nz,ldx,ldy,ldz,ndat,fofr_ref)
    1555       644691 :      fofr = fofr_ref
    1556              : 
    1557           48 :      if (gpu_option == ABI_GPU_OPENMP) then
    1558              :         if (cplex == 2) then
    1559              :          ! FIXME
    1560              :          !!!$OMP TARGET ENTER DATA MAP(to:fofg, fofr) IF (gpu_option == ABI_GPU_OPENMP)
    1561              :          !call ompgpu_fourdp(cplex, ngfft, ldx, ldy, ldz, ndat, -1, fofg, fofr)
    1562              :          !call ompgpu_fourdp(cplex, ngfft, ldx, ldy, ldz, ndat, +1, fofg, fofr)
    1563              :          !!!$OMP TARGET EXIT DATA MAP(from:fofr) IF (gpu_option == ABI_GPU_OPENMP)
    1564              :         end if
    1565              :      else
    1566              :        ! CPU version.
    1567            0 :        select case (fftalga)
    1568              :        case (FFT_FFTW3)
    1569            0 :          call fftw3_seqfourdp(cplex,nx,ny,nz,ldx,ldy,ldz,ndat,-1,fofg,fofr)
    1570            0 :          call fftw3_seqfourdp(cplex,nx,ny,nz,ldx,ldy,ldz,ndat,+1,fofg,fofr)
    1571              : 
    1572              :        case (FFT_DFTI)
    1573           24 :          call dfti_seqfourdp(cplex,nx,ny,nz,ldx,ldy,ldz,ndat,-1,fofg,fofr)
    1574           24 :          call dfti_seqfourdp(cplex,nx,ny,nz,ldx,ldy,ldz,ndat,+1,fofg,fofr)
    1575              : 
    1576              :        case default
    1577              :          ! TODO
    1578           48 :          continue
    1579              :        end select
    1580              :      end if
    1581              : 
    1582           48 :      call cg_setaug_zero(cplex,nx,ny,nz,ldx,ldy,ldz,ndat,fofr)
    1583              : 
    1584       644643 :      ierr = COUNT(ABS(fofr - fofr_ref) > ATOL_DP)
    1585           48 :      nfailed = nfailed + ierr
    1586              : 
    1587           48 :      write(info,"(a,i1,a)")sjoin(library, "fourdp (cplex "),cplex,") :"
    1588              :      !write(info,"(2a,i1,a,i0,a)")trim(library), "fourdp (cplex ", cplex,"), ndata = ",ndat," :"
    1589           48 :      write(msg,"(a)")" OK"
    1590           48 :      if (ierr /= 0) then
    1591            0 :        max_abserr = MAXVAL(ABS(fofr - fofr_ref))
    1592            0 :        write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1593              :        !write(std_out, *)"abs_diff fofr fofr_ref"
    1594              :        !do ifft=1,cplex*ldxyz*ndat
    1595              :        !  write(std_out, *)abs(fofr(ifft) - fofr_ref(ifft)), fofr(ifft), fofr_ref(ifft)
    1596              :        !end do
    1597              :      end if
    1598           48 :      call wrtout(ount,sjoin(info, msg))
    1599              : 
    1600              :      !!$OMP TARGET EXIT DATA MAP(delete: fofg, fofr) if (gpu_option == ABI_GPU_OPENMP)
    1601           48 :      ABI_FREE(fofg)
    1602           48 :      ABI_FREE(fofr)
    1603           48 :      ABI_FREE(fofr_ref)
    1604              : 
    1605           72 :     if (fftalga == FFT_DFTI) then
    1606              :       ! Revert changes. See comment above.
    1607           24 :       ldx=pars(4,iset); ldy=pars(5,iset); ldz=pars(6,iset)
    1608           24 :       ldxyz = ldx*ldy*ldz
    1609              :     end if
    1610              : 
    1611              :    end do
    1612              :  end do
    1613              : 
    1614            4 :  if (nthreads > 0) call xomp_set_num_threads(old_nthreads)
    1615              : 
    1616           32 : end function fftbox_utests
    1617              : !!***
    1618              : 
    1619              : !----------------------------------------------------------------------
    1620              : 
    1621              : !!****f* m_fft/fftu_utests
    1622              : !! NAME
    1623              : !! fftu_utests
    1624              : !!
    1625              : !! FUNCTION
    1626              : !! Unit tests for the FFTs of wavefunctions (sequential version).
    1627              : !!
    1628              : !! INPUTS
    1629              : !!
    1630              : !! OUTPUT
    1631              : !!  nfailed=number of failed tests.
    1632              : !!
    1633              : !! SOURCE
    1634              : 
    1635            4 : integer function fftu_utests(ecut, ngfft, rprimd, ndat, nthreads, unit) result(nfailed)
    1636              : 
    1637              : !Arguments ------------------------------------
    1638              : !scalars
    1639              :  real(dp),intent(in) :: ecut
    1640              :  integer,intent(in) :: ndat, nthreads
    1641              :  integer,optional,intent(in) :: unit
    1642              : !arrays
    1643              :  integer,intent(in) :: ngfft(18)
    1644              :  real(dp),intent(in) :: rprimd(3,3)
    1645              : 
    1646              : !Local variables-------------------------------
    1647              : !scalars
    1648              :  integer,parameter :: nspinor=1
    1649              :  integer :: nx,ny,nz,nxyz,ldx,ldy,ldz,ierr,npw_k,mgfft,istwf_k,ikpt,ldxyz,ipw,old_nthreads,ount, fftalg
    1650              :  real(dp),parameter :: ATOL_SP=tol6, ATOL_DP=tol12 ! Tolerances on the absolute error
    1651              :  real(dp) :: max_abserr,ucvol
    1652              :  character(len=500) :: msg,info,library,cplex_mode,padding_mode
    1653              : !arrays
    1654            4 :  integer,allocatable :: gbound_k(:,:),kg_k(:,:)
    1655              :  real(dp) :: kpoint(3),crand(2),kpoints(3,9), gmet(3,3),gprimd(3,3),rmet(3,3)
    1656            4 :  real(dp),allocatable :: cg(:,:),cg_ref(:,:),cr(:,:)
    1657            4 :  complex(sp),allocatable :: ugsp(:),ug_refsp(:),ursp(:)
    1658            4 :  complex(dp),allocatable :: ug(:),ug_ref(:),ur(:)
    1659              : ! *************************************************************************
    1660              : 
    1661            4 :  ount = std_out; if (PRESENT(unit)) ount = unit
    1662              : 
    1663            4 :  nfailed = 0
    1664            4 :  fftalg = ngfft(7)
    1665              : 
    1666            4 :  if (nthreads > 0) then
    1667            4 :    old_nthreads = xomp_get_max_threads()
    1668            4 :    call xomp_set_num_threads(nthreads)
    1669              :  end if
    1670              : 
    1671            4 :  call metric(gmet,gprimd,-1,rmet,rprimd,ucvol)
    1672              : 
    1673            4 :  nx  = ngfft(1);  ny = ngfft(2);  nz = ngfft(3)
    1674            4 :  ldx = ngfft(4); ldy = ngfft(5); ldz = ngfft(6)
    1675           16 :  mgfft = MAXVAL(ngfft(1:3))
    1676              : 
    1677            4 :  nxyz =  nx* ny* nz
    1678            4 :  ldxyz = ldx*ldy*ldz
    1679              : 
    1680     30603012 :  ABI_CALLOC(cg_ref, (2, ldxyz*ndat))
    1681     30603008 :  ABI_CALLOC(cg,     (2, ldxyz*ndat))
    1682     30603008 :  ABI_CALLOC(cr,     (2, ldxyz*ndat))
    1683     10201012 :  ABI_CALLOC(ug_ref, (ldxyz*ndat))
    1684     10201008 :  ABI_CALLOC(ug,     (ldxyz*ndat))
    1685     10201008 :  ABI_CALLOC(ur,     (ldxyz*ndat))
    1686     10201012 :  ABI_CALLOC(ug_refsp, (ldxyz*ndat))
    1687     10201008 :  ABI_CALLOC(ugsp,     (ldxyz*ndat))
    1688     10201008 :  ABI_CALLOC(ursp,     (ldxyz*ndat))
    1689              : 
    1690              :  kpoints = RESHAPE([ &
    1691              :    0.1, 0.2, 0.3, &
    1692              :    0.0, 0.0, 0.0, &
    1693              :    0.5, 0.0, 0.0, &
    1694              :    0.0, 0.0, 0.5, &
    1695              :    0.5, 0.0, 0.5, &
    1696              :    0.0, 0.5, 0.0, &
    1697              :    0.5, 0.5, 0.0, &
    1698              :    0.0, 0.5, 0.5, &
    1699            4 :    0.5, 0.5, 0.5], [3, 9])
    1700              : 
    1701            4 :  call fftalg_info(fftalg, library, cplex_mode, padding_mode)
    1702              : 
    1703           40 :  do ikpt=1,SIZE(kpoints,DIM=2)
    1704          144 :    kpoint = kpoints(:,ikpt)
    1705           36 :    istwf_k = set_istwfk(kpoint)
    1706              : 
    1707              :    ! Allocate and calculate the set of G-vectors.
    1708           36 :    call get_kg(kpoint, istwf_k, ecut, gmet, npw_k, kg_k)
    1709              : 
    1710          144 :    ABI_MALLOC(gbound_k, (2*mgfft+8,2))
    1711           36 :    call sphereboundary(gbound_k,istwf_k,kg_k,mgfft,npw_k)
    1712              : 
    1713              :    ! =================================================
    1714              :    ! === Test the single precision complex version ===
    1715              :    ! =================================================
    1716      3140026 :    do ipw=1,npw_k*ndat
    1717      3139990 :      call RANDOM_NUMBER(crand)
    1718      3140026 :      ug_refsp(ipw) = CMPLX(crand(1), crand(2))
    1719              :    end do
    1720              : 
    1721           36 :    if (istwf_k == 2) then
    1722            4 :      do ipw=1,npw_k*ndat,npw_k
    1723           10 :        ug_refsp(ipw) = REAL(ug_refsp(ipw))
    1724              :      end do
    1725              :    end if
    1726              : 
    1727     91809072 :    ugsp = ug_refsp
    1728           36 :    call fft_ug(npw_k,nxyz,nspinor,ndat,mgfft,ngfft,istwf_k,kg_k,gbound_k,ugsp,ursp)
    1729           36 :    call fft_ur(npw_k,nxyz,nspinor,ndat,mgfft,ngfft,istwf_k,kg_k,gbound_k,ursp,ugsp)
    1730              : 
    1731     91809036 :    ierr = COUNT(ABS(ugsp - ug_refsp) > ATOL_SP)
    1732           36 :    nfailed = nfailed + ierr
    1733              : 
    1734           36 :    write(info,"(a,i1,a)")sjoin(library,"fftu_spc, istwfk "),istwf_k," :"
    1735           36 :    write(msg,"(a)")" OK"
    1736           36 :    if (ierr /= 0) then
    1737            0 :      max_abserr = MAXVAL(ABS(ugsp - ug_refsp))
    1738            0 :      write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1739              :    end if
    1740           36 :    call wrtout(ount,sjoin(info, msg))
    1741              : 
    1742              :    ! =================================================
    1743              :    ! === Test the double precision complex version ===
    1744              :    ! =================================================
    1745      3140026 :    do ipw=1,npw_k*ndat
    1746      3139990 :      call RANDOM_NUMBER(crand)
    1747      3140026 :      ug_ref(ipw) = DCMPLX(crand(1), crand(2))
    1748              :    end do
    1749              : 
    1750           36 :    if (istwf_k == 2) then
    1751            4 :      do ipw=1,npw_k*ndat,npw_k
    1752           10 :        ug_ref(ipw) = REAL(ug_ref(ipw))
    1753              :      end do
    1754              :    end if
    1755              : 
    1756     91809072 :    ug = ug_ref
    1757           36 :    call fft_ug(npw_k,nxyz,nspinor,ndat,mgfft,ngfft,istwf_k,kg_k,gbound_k,ug,ur)
    1758           36 :    call fft_ur(npw_k,nxyz,nspinor,ndat,mgfft,ngfft,istwf_k,kg_k,gbound_k,ur,ug)
    1759              : 
    1760     91809036 :    ierr = COUNT(ABS(ug - ug_ref) > ATOL_DP)
    1761           36 :    nfailed = nfailed + ierr
    1762              : 
    1763           36 :    write(info,"(a,i1,a)")sjoin(library,"fftu_dpc, istwfk "),istwf_k," :"
    1764           36 :    write(msg,"(a)")" OK"
    1765           36 :    if (ierr /= 0) then
    1766            0 :      max_abserr = MAXVAL(ABS(ug - ug_ref))
    1767            0 :      write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1768              :    end if
    1769           36 :    call wrtout(ount, sjoin(info, msg))
    1770              : 
    1771           36 :    ABI_FREE(kg_k)
    1772           40 :    ABI_FREE(gbound_k)
    1773              :  end do
    1774              : 
    1775            4 :  ABI_FREE(cg_ref)
    1776            4 :  ABI_FREE(cg)
    1777            4 :  ABI_FREE(cr)
    1778            4 :  ABI_FREE(ug_ref)
    1779            4 :  ABI_FREE(ug)
    1780            4 :  ABI_FREE(ur)
    1781            4 :  ABI_FREE(ug_refsp)
    1782            4 :  ABI_FREE(ugsp)
    1783            4 :  ABI_FREE(ursp)
    1784              : 
    1785            4 :  if (nthreads > 0) call xomp_set_num_threads(old_nthreads)
    1786              : 
    1787            4 : end function fftu_utests
    1788              : !!***
    1789              : 
    1790              : !----------------------------------------------------------------------
    1791              : 
    1792              : !!****f* m_fft/uplan_utests
    1793              : !! NAME
    1794              : !! uplan_utests
    1795              : !!
    1796              : !! FUNCTION
    1797              : !! Unit tests for the FFTs of wavefunctions (sequential version).
    1798              : !!
    1799              : !! INPUTS
    1800              : !!
    1801              : !! OUTPUT
    1802              : !!  nfailed=number of failed tests.
    1803              : !!
    1804              : !! SOURCE
    1805              : 
    1806            0 : integer function uplan_utests(ecut, ngfft, rprimd, ndat, nthreads, gpu_option, unit) result(nfailed)
    1807              : 
    1808              : !Arguments ------------------------------------
    1809              : !scalars
    1810              :  real(dp),intent(in) :: ecut
    1811              :  integer,intent(in) :: ndat, nthreads, gpu_option
    1812              :  integer,optional,intent(in) :: unit
    1813              : !arrays
    1814              :  integer,intent(in) :: ngfft(18)
    1815              :  real(dp),intent(in) :: rprimd(3,3)
    1816              : 
    1817              : !Local variables-------------------------------
    1818              : !scalars
    1819              :  integer,parameter :: nspinor=1
    1820              :  integer :: nx,ny,nz,nxyz,ldx,ldy,ldz,ierr,npw_k,mgfft,istwf_k,ikpt,ldxyz,ipw,old_nthreads,ount, fftalg, ii, ndat__
    1821              :  real(dp),parameter :: ATOL_SP=tol6, ATOL_DP=tol12 ! Tolerances on the absolute error
    1822              :  real(dp) :: max_abserr,ucvol
    1823              :  character(len=500) :: msg,info,library,cplex_mode,padding_mode
    1824              : !arrays
    1825            0 :  integer,allocatable :: kg_k(:,:)
    1826              :  real(dp) :: kpoint(3),crand(2),kpoints(3,1), gmet(3,3),gprimd(3,3),rmet(3,3)
    1827            0 :  complex(sp),allocatable :: ugsp(:),ug_refsp(:),ursp(:)
    1828            0 :  complex(dp),allocatable :: ug(:),ug_ref(:),ur(:)
    1829            0 :  type(uplan_t) :: uplan_k
    1830              : ! *************************************************************************
    1831              : 
    1832            0 :  ount = std_out; if (PRESENT(unit)) ount = unit
    1833              : 
    1834            0 :  nfailed = 0
    1835            0 :  fftalg = ngfft(7)
    1836              : 
    1837            0 :  if (nthreads > 0) then
    1838            0 :    old_nthreads = xomp_get_max_threads()
    1839            0 :    call xomp_set_num_threads(nthreads)
    1840              :  end if
    1841              : 
    1842            0 :  call metric(gmet,gprimd,-1,rmet,rprimd,ucvol)
    1843              : 
    1844            0 :  nx  = ngfft(1);  ny = ngfft(2);  nz = ngfft(3)
    1845            0 :  ldx = ngfft(4); ldy = ngfft(5); ldz = ngfft(6)
    1846              :  mgfft = MAXVAL(ngfft(1:3))
    1847              : 
    1848            0 :  nxyz =  nx*ny*nz
    1849            0 :  ldxyz = ldx*ldy*ldz
    1850              : 
    1851            0 :  ABI_CALLOC(ug_ref, (ldxyz*ndat))
    1852            0 :  ABI_CALLOC(ug,     (ldxyz*ndat))
    1853            0 :  ABI_CALLOC(ur,     (ldxyz*ndat))
    1854            0 :  ABI_CALLOC(ug_refsp, (ldxyz*ndat))
    1855            0 :  ABI_CALLOC(ugsp,     (ldxyz*ndat))
    1856            0 :  ABI_CALLOC(ursp,     (ldxyz*ndat))
    1857              : 
    1858              :  kpoints = RESHAPE([ &
    1859              :    0.1, 0.2, 0.3   &
    1860              :    !0.0, 0.0, 0.0, &
    1861              :    !0.5, 0.0, 0.0, &
    1862              :    !0.0, 0.0, 0.5, &
    1863              :    !0.5, 0.0, 0.5, &
    1864              :    !0.0, 0.5, 0.0, &
    1865              :    !0.5, 0.5, 0.0, &
    1866              :    !0.0, 0.5, 0.5, &
    1867              :    !0.5, 0.5, 0.5
    1868            0 :    ], [3, 1])
    1869              : 
    1870            0 :  call fftalg_info(fftalg, library, cplex_mode, padding_mode)
    1871              : 
    1872            0 :  do ikpt=1,SIZE(kpoints,DIM=2)
    1873            0 :    kpoint = kpoints(:,ikpt)
    1874            0 :    istwf_k = set_istwfk(kpoint)
    1875              : 
    1876              :    ! Allocate and calculate the set of G-vectors.
    1877            0 :    call get_kg(kpoint, istwf_k, ecut, gmet, npw_k, kg_k)
    1878              : 
    1879              :    ! =================================================
    1880              :    ! === Test the single precision complex version ===
    1881              :    ! =================================================
    1882            0 :    do ipw=1,npw_k*ndat
    1883            0 :      call RANDOM_NUMBER(crand)
    1884            0 :      ug_refsp(ipw) = CMPLX(crand(1), crand(2))
    1885              :    end do
    1886              : 
    1887            0 :    if (istwf_k == 2) then
    1888            0 :      do ipw=1,npw_k*ndat,npw_k
    1889            0 :        ug_refsp(ipw) = REAL(ug_refsp(ipw))
    1890              :      end do
    1891              :    end if
    1892              : 
    1893            0 :    call uplan_k%init(npw_k, nspinor, ndat, ngfft, istwf_k, kg_k, sp, gpu_option)
    1894              : 
    1895            0 :    call wrtout(ount, "Test version with gpu_mode 1 (GPU only)")
    1896            0 :    do ii=1,2
    1897              :    !do ii=2,1,-1
    1898            0 :      ugsp = ug_refsp
    1899            0 :      ndat__ = ndat
    1900            0 :      if (ii == 2) ndat__ = max(ndat / 2, 1)
    1901            0 :      call uplan_k%execute_gr(ndat__, ugsp, ursp, gpu_mode=1)
    1902            0 :      ugsp = zero
    1903            0 :      call uplan_k%execute_rg(ndat__, ursp, ugsp, gpu_mode=1)
    1904              : 
    1905            0 :      ierr = COUNT(ABS(ugsp(1:npw_k*ndat__) - ug_refsp(1:npw_k*ndat__)) > ATOL_SP); nfailed = nfailed + ierr
    1906            0 :      write(info,"(a,i1,a)")sjoin(library,"uplan_k spc, gpu_mode 1, istwfk "),istwf_k," :"; write(msg,"(a)")" OK"
    1907            0 :      if (ierr /= 0) then
    1908            0 :        max_abserr = MAXVAL(ABS(ugsp - ug_refsp)); write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1909              :      end if
    1910            0 :      call wrtout(ount, sjoin(info, msg))
    1911              :    end do ! ii
    1912              : 
    1913            0 :    call wrtout(ount, "Test version with explicit GPU offloading.")
    1914            0 :    ugsp = ug_refsp
    1915              : #ifdef HAVE_OPENMP_OFFLOAD
    1916              :    !$OMP TARGET ENTER DATA MAP(to:ugsp, ursp) IF (gpu_option == ABI_GPU_OPENMP)
    1917              : #endif
    1918            0 :    call uplan_k%execute_gr(ndat, ugsp, ursp)
    1919            0 :    ugsp = zero
    1920            0 :    call uplan_k%execute_rg(ndat, ursp, ugsp)
    1921              : #ifdef HAVE_OPENMP_OFFLOAD
    1922              :    !$OMP TARGET EXIT DATA MAP(from:ugsp) IF (gpu_option == ABI_GPU_OPENMP)
    1923              : #endif
    1924            0 :    call uplan_k%free()
    1925              : 
    1926            0 :    ierr = COUNT(ABS(ugsp - ug_refsp) > ATOL_SP); nfailed = nfailed + ierr
    1927            0 :    write(info,"(a,i1,a)")sjoin(library,"uplan_k spc, gpu_mode 0, istwfk "),istwf_k," :"; write(msg,"(a)")" OK"
    1928            0 :    if (ierr /= 0) then
    1929            0 :      max_abserr = MAXVAL(ABS(ugsp - ug_refsp)); write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1930              :    end if
    1931            0 :    call wrtout(ount, sjoin(info, msg))
    1932              : 
    1933              :    ! =================================================
    1934              :    ! === Test the double precision complex version ===
    1935              :    ! =================================================
    1936            0 :    do ipw=1,npw_k*ndat
    1937            0 :      call RANDOM_NUMBER(crand)
    1938            0 :      ug_ref(ipw) = DCMPLX(crand(1), crand(2))
    1939              :    end do
    1940              : 
    1941            0 :    if (istwf_k == 2) then
    1942            0 :      do ipw=1,npw_k*ndat,npw_k
    1943            0 :        ug_ref(ipw) = REAL(ug_ref(ipw))
    1944              :      end do
    1945              :    end if
    1946              : 
    1947              :    ! Test uplan_k transforms with double precision.
    1948            0 :    call uplan_k%init(npw_k, nspinor, ndat, ngfft, istwf_k, kg_k, dp, gpu_option)
    1949              : 
    1950            0 :    call wrtout(ount, "Test version with gpu_mode 1 (GPU only)")
    1951            0 :    do ii=1,2
    1952              :    !do ii=2,1,-1
    1953            0 :      ug = ug_ref
    1954            0 :      if (ii == 2) ndat__ = max(ndat__ / 2, 1)
    1955            0 :      call uplan_k%execute_gr(ndat__, ug, ur, gpu_mode=1)
    1956            0 :      ug = zero
    1957            0 :      call uplan_k%execute_rg(ndat__, ur, ug, gpu_mode=1)
    1958              : 
    1959            0 :      ierr = COUNT(ABS(ug(1:npw_k*ndat__) - ug_ref(1:npw_k*ndat__))  > ATOL_DP); nfailed = nfailed + ierr
    1960            0 :      write(info,"(a,i1,a)")sjoin(library,"uplan_k dpc, gpu_mode 1, istwfk "),istwf_k," :"; write(msg,"(a)")" OK"
    1961            0 :      if (ierr /= 0) then
    1962            0 :        max_abserr = MAXVAL(ABS(ug - ug_ref)); write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1963              :      end if
    1964            0 :      call wrtout(ount, sjoin(info, msg))
    1965              :    end do ! ii
    1966              : 
    1967            0 :    call wrtout(ount, "Test version with explicit GPU offloading.")
    1968            0 :    ug = ug_ref
    1969              : #ifdef HAVE_OPENMP_OFFLOAD
    1970              :    !$OMP TARGET ENTER DATA MAP(to:ug, ur) IF (gpu_option == ABI_GPU_OPENMP)
    1971              : #endif
    1972            0 :    call uplan_k%execute_gr(ndat, ug, ur)
    1973            0 :    ug = zero
    1974            0 :    call uplan_k%execute_rg(ndat, ur, ug)
    1975              : #ifdef HAVE_OPENMP_OFFLOAD
    1976              :    !$OMP TARGET EXIT DATA MAP(from:ug) IF (gpu_option == ABI_GPU_OPENMP)
    1977              : #endif
    1978            0 :    call uplan_k%free()
    1979              : 
    1980            0 :    ierr = COUNT(ABS(ug - ug_ref) > ATOL_DP); nfailed = nfailed + ierr
    1981            0 :    write(info,"(a,i1,a)")sjoin(library,"uplan_k, dpc, gpu_mode 0, istwfk "),istwf_k," :"; write(msg,"(a)")" OK"
    1982            0 :    if (ierr /= 0) then
    1983            0 :      max_abserr = MAXVAL(ABS(ug - ug_ref)); write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    1984              :    end if
    1985            0 :    call wrtout(ount, sjoin(info, msg))
    1986              : 
    1987            0 :    ABI_FREE(kg_k)
    1988              :  end do
    1989              : 
    1990            0 :  ABI_FREE(ug_ref)
    1991            0 :  ABI_FREE(ug)
    1992            0 :  ABI_FREE(ur)
    1993            0 :  ABI_FREE(ug_refsp)
    1994            0 :  ABI_FREE(ugsp)
    1995            0 :  ABI_FREE(ursp)
    1996              : 
    1997            0 :  if (nthreads > 0) call xomp_set_num_threads(old_nthreads)
    1998              : 
    1999            0 : end function uplan_utests
    2000              : !!***
    2001              : 
    2002              : !----------------------------------------------------------------------
    2003              : 
    2004              : !!****f* m_fft/fftbox_mpi_utests
    2005              : !! NAME
    2006              : !!  fftbox_mpi_utests
    2007              : !!
    2008              : !! FUNCTION
    2009              : !! Driver routine for unit tests of the MPI FFT routines.
    2010              : !!
    2011              : !! INPUTS
    2012              : !! fftalg =fftalg input variable.
    2013              : !! cplex=1 for r2c, 2 for c2c transforms.
    2014              : !! ndat = Number of transform to execute
    2015              : !! nthreads = Number of OpenMP threads.
    2016              : !! comm_fft=MPI communicator for the FFT
    2017              : !! [unit]=Output Unit number (DEFAULT std_out)
    2018              : !!
    2019              : !! OUTPUT
    2020              : !!  nfailed=number of failures.
    2021              : !!
    2022              : !! SOURCE
    2023              : 
    2024            8 : integer function fftbox_mpi_utests(fftalg, cplex, ndat, nthreads, comm_fft, unit) result(nfailed)
    2025              : 
    2026              : !Arguments -----------------------------------
    2027              : !scalars
    2028              :  integer,intent(in) :: fftalg,cplex,ndat,nthreads,comm_fft
    2029              :  integer,optional,intent(in) :: unit
    2030              : 
    2031              : !Local variables-------------------------------
    2032              : !scalars
    2033              :  integer,parameter :: NSETS=6
    2034              :  integer :: ierr,old_nthreads,ount,iset,mpierr,nfft,me_fft
    2035              :  integer :: nproc_fft,fftalga,fftalgc,n1,n2,n3,n4,n5,n6
    2036              :  real(dp),parameter :: ATOL_DP=tol12
    2037              :  real(dp) :: max_abserr, ctime, wtime, gflops
    2038              :  character(len=500) :: msg,info,library,cplex_mode,padding_mode
    2039            8 :  type(distribfft_type),target :: fftabs
    2040              : !arrays
    2041              :  integer :: pars(6,NSETS),ngfft(18)
    2042            8 :  integer, contiguous, pointer :: fftn2_distrib(:),ffti2_local(:)
    2043            8 :  integer, contiguous, pointer :: fftn3_distrib(:),ffti3_local(:)
    2044            8 :  real(dp),allocatable :: fofg(:,:),fofr(:),fofr_copy(:)
    2045              : ! *************************************************************************
    2046              : 
    2047            0 :  ount = std_out; if (PRESENT(unit)) ount = unit
    2048            8 :  nfailed = 0
    2049              : 
    2050            8 :  if (nthreads > 0) then
    2051            0 :    old_nthreads = xomp_get_max_threads()
    2052            0 :    call xomp_set_num_threads(nthreads)
    2053              :  end if
    2054              : 
    2055              :  ! These values must be compatible with all the FFT routines.
    2056              :  ! SG library is the most restrictive (only powers of 2,3,5).
    2057              :  pars = RESHAPE( [    &
    2058              :    12, 18, 15, 12, 18, 15, &
    2059              :    12, 18, 15, 13, 19, 16, &
    2060              :    12, 18, 15, 13, 19, 15, &
    2061              :    12, 18, 15, 12, 18, 16, &
    2062              :    12, 18, 15, 13, 18, 15, &
    2063              :    12, 18, 15, 15, 21, 18  &
    2064            8 :   ], [6, NSETS] )
    2065              : 
    2066            8 :  fftalga=fftalg/100; fftalgc=mod(fftalg,10)
    2067              : 
    2068            8 :  nproc_fft = xmpi_comm_size(comm_fft); me_fft = xmpi_comm_rank(comm_fft)
    2069              : 
    2070            8 :  call fftalg_info(fftalg,library,cplex_mode,padding_mode)
    2071              : 
    2072              :  !do iset=1,SIZE(pars,DIM=2)
    2073           16 :  do iset=1,1
    2074            8 :    n1=pars(1,iset); n2=pars(2,iset); n3=pars(3,iset)
    2075              :    ! For the time being, ngfft(2) and ngfft(3) must be multiple of nproc_fft
    2076            8 :    n2 = n2 * nproc_fft; n3 = n3 * nproc_fft
    2077              :    !n4=pars(4,iset); n5=pars(5,iset); n6=pars(6,iset)
    2078            8 :    n4=n1; n5=n2; n6=n3
    2079              : 
    2080              :    ! Init ngfft
    2081              :    ! TODO Propagate more info via ngfft, define helper functions, write routine to get fftcache
    2082            8 :    ngfft = 0
    2083           64 :    ngfft(1:7) = [n1,n2,n3,n4,n5,n6,fftalg]
    2084            8 :    ngfft(8)= get_cache_kb()        ! cache
    2085            8 :    ngfft(9)=1                      ! paral_fft_
    2086            8 :    ngfft(10)=nproc_fft             ! nproc_fft
    2087            8 :    ngfft(11)=xmpi_comm_rank(comm_fft)  ! me_fft
    2088            8 :    ngfft(12)=ngfft(2)/nproc_fft    ! n2proc
    2089            8 :    ngfft(13)=ngfft(3)/nproc_fft    ! n3proc
    2090              : 
    2091              :    !call print_ngfft([std_out], ngfft, header="ngfft for MPI-fourdp", prtvol=0)
    2092              : 
    2093              :    ! Allocate arrays, fill fofr with random numbers and keep a copy.
    2094            8 :    nfft = (n1 * n2 * n3) / nproc_fft
    2095           24 :    ABI_MALLOC(fofg, (2,nfft*ndat))
    2096           24 :    ABI_MALLOC(fofr, (cplex*nfft*ndat))
    2097           16 :    ABI_MALLOC(fofr_copy, (cplex*nfft*ndat))
    2098              : 
    2099            8 :    call RANDOM_NUMBER(fofr)
    2100        77776 :    fofr_copy = fofr
    2101              : 
    2102            8 :    call fftabs%init("c",nproc_fft,n2,n3)
    2103            8 :    fftn2_distrib => fftabs%tab_fftdp2_distrib
    2104            8 :    ffti2_local => fftabs%tab_fftdp2_local
    2105            8 :    fftn3_distrib => fftabs%tab_fftdp3_distrib
    2106            8 :    ffti3_local => fftabs%tab_fftdp3_local
    2107              : 
    2108            8 :    call cwtime(ctime,wtime,gflops,"start")
    2109              : 
    2110            8 :    select case (fftalga)
    2111              : 
    2112              :    case (FFT_SG2002)
    2113            8 :      call sg2002_mpifourdp(cplex,nfft,ngfft,ndat,-1,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    2114            8 :      call sg2002_mpifourdp(cplex,nfft,ngfft,ndat,+1,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    2115              : 
    2116              :    case (FFT_FFTW3)
    2117            0 :      call fftw3_mpifourdp(cplex,nfft,ngfft,ndat,-1,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    2118            0 :      call fftw3_mpifourdp(cplex,nfft,ngfft,ndat,+1,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    2119              : 
    2120              :    !case (FFT_DFTI)
    2121              :    !  call dfti_mpifourdp(cplex,nfft,ngfft,ndat,-1,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    2122              :    !  call dfti_mpifourdp(cplex,nfft,ngfft,ndat,+1,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    2123              : 
    2124              :    case default
    2125            8 :      ABI_BUG(sjoin("fftalg: ", itoa(fftalg), " does not support MPI-FFT"))
    2126              :    end select
    2127              : 
    2128            8 :    call cwtime(ctime,wtime,gflops,"stop")
    2129              :    if (me_fft == 0) then
    2130              :      !write(std_out,'(a,i0,2(a,f10.4))')"fftalg: ",fftalg,", cpu_time: ",ctime,", wall_time: ",wtime
    2131              :    end if
    2132              : 
    2133              :    ! Check if F^{-1} F = I within ATOL_DP
    2134        77768 :    ierr = COUNT(ABS(fofr - fofr_copy) > ATOL_DP)
    2135            8 :    call xmpi_sum(ierr,comm_fft,mpierr)
    2136            8 :    nfailed = nfailed + ierr
    2137              : 
    2138            8 :    if (cplex == 1) info = sjoin(library,"r2c --> c2r :")
    2139            8 :    if (cplex == 2) info = sjoin(library,"c2c :")
    2140              : 
    2141            8 :    write(msg,"(a)")" OK"
    2142            8 :    if (ierr /= 0) then
    2143              :      ! Compute the maximum of the absolute error.
    2144            0 :      max_abserr = MAXVAL(ABS(fofr - fofr_copy))
    2145            0 :      call xmpi_max(max_abserr,comm_fft,mpierr)
    2146            0 :      write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    2147              :    end if
    2148            8 :    call wrtout(ount,sjoin(info, msg))
    2149              : 
    2150            8 :    call fftabs%free()
    2151              : 
    2152            8 :    ABI_FREE(fofg)
    2153            8 :    ABI_FREE(fofr_copy)
    2154           40 :    ABI_FREE(fofr)
    2155              :  end do
    2156              : 
    2157            8 :  if (nthreads > 0) call xomp_set_num_threads(old_nthreads)
    2158              : 
    2159           16 : end function fftbox_mpi_utests
    2160              : !!***
    2161              : 
    2162              : !----------------------------------------------------------------------
    2163              : 
    2164              : !!****f* m_fft/fftu_mpi_utests
    2165              : !! NAME
    2166              : !! fftu_mpi_utests
    2167              : !!
    2168              : !! FUNCTION
    2169              : !! Unit tests for the FFTs of wavefunctions (MPI version).
    2170              : !!
    2171              : !! INPUTS
    2172              : !!
    2173              : !! OUTPUT
    2174              : !!  nfailed=number of failed tests.
    2175              : !!
    2176              : !! SOURCE
    2177              : 
    2178            4 : integer function fftu_mpi_utests(fftalg, ecut, rprimd, ndat, nthreads, comm_fft, paral_kgb, unit) result(nfailed)
    2179              : 
    2180              : !Arguments ------------------------------------
    2181              : !scalars
    2182              :  integer,intent(in) :: fftalg,ndat,nthreads,comm_fft,paral_kgb
    2183              :  integer,optional,intent(in) :: unit
    2184              :  real(dp),intent(in) :: ecut
    2185              : !arrays
    2186              :  real(dp),intent(in) :: rprimd(3,3)
    2187              : 
    2188              : !Local variables-------------------------------
    2189              : !scalars
    2190              :  integer,parameter :: nsym1=1,npw0=0,cplex_one=1,istwfk_one=1
    2191              :  integer :: n1,n2,n3,idat,n4,n5,n6,ierr,npw_k,full_npw_k,istwf_npw_k,cplexwf
    2192              :  integer :: mgfft,istwf_k,ikpt,old_nthreads,ount,isign,fftalga,fftalgc
    2193              :  integer :: ig,i1,i2,i3,i3_glob,i3dat,nd3proc,i3_local,g0sender
    2194              :  integer :: step,me_g0,me_fft,nproc_fft,mpierr,nfft,cplex,chksymtnons
    2195              :  real(dp),parameter :: boxcutmin2=two,ATOL_DP=tol12,RTOL_DP=tol3 ! Tolerances on the absolute and relative error
    2196              :  real(dp),parameter :: weight_r=one,weight_i=one
    2197              :  real(dp) :: max_abserr,max_relerr,ucvol,relerr,den,refden
    2198              :  real(dp) :: ctime,wtime,gflops
    2199              :  character(len=500) :: msg,info,library,cplex_mode,padding_mode
    2200            4 :  type(distribfft_type) :: fftabs
    2201              : !arrays
    2202              :  integer :: symrel(3,3,nsym1),ngfft(18)
    2203            4 :  integer,allocatable :: full_kg_k(:,:),istw_kg_k(:,:)
    2204            4 :  integer,allocatable :: gbound_k(:,:),kg_k(:,:)
    2205              :  real(dp) :: dummy_fofg(0,0) !dummy_denpot(0,0,0)
    2206              :  real(dp) :: kpoint(3),kpoints(3,2)
    2207              :  real(dp) :: gmet(3,3),gprimd(3,3),rmet(3,3),tnons(3,nsym1)
    2208            4 :  real(dp),allocatable :: fofg(:,:),ref_fofg(:,:),fofg_out(:,:),fofr(:,:,:,:)
    2209            4 :  real(dp),allocatable :: density(:,:,:),pot(:,:,:),invpot(:,:,:)
    2210            4 :  real(dp),allocatable :: full_fofg(:,:),istwf_fofg(:,:)
    2211              : ! *************************************************************************
    2212              : 
    2213            4 :  nfailed = 0
    2214            4 :  ount = std_out; if (PRESENT(unit)) ount = unit
    2215              : 
    2216            4 :  if (nthreads > 0) then
    2217            0 :    old_nthreads = xomp_get_max_threads()
    2218            0 :    call xomp_set_num_threads(nthreads)
    2219              :  end if
    2220              : 
    2221            4 :  if (.not. fftalg_has_mpi(fftalg)) then
    2222            0 :    write(msg,'(a,i0,a)')"fftalg: ",fftalg," does not support MPI"
    2223            0 :    ABI_ERROR(msg)
    2224              :  end if
    2225              : 
    2226            4 :  nproc_fft = xmpi_comm_size(comm_fft); me_fft = xmpi_comm_rank(comm_fft)
    2227              : 
    2228            4 :  symrel = reshape([1,0,0,0,1,0,0,0,1],[3,3,nsym1])
    2229            4 :  tnons=zero
    2230            4 :  chksymtnons=0
    2231            4 :  call metric(gmet,gprimd,-1,rmet,rprimd,ucvol)
    2232              : 
    2233              :  kpoints = RESHAPE( [ &
    2234              :    0.1, 0.2, 0.3, &
    2235            4 :    0.0, 0.0, 0.0 ], [3,2] )
    2236              : 
    2237            4 :  call fftalg_info(fftalg,library,cplex_mode,padding_mode)
    2238              : 
    2239            4 :  fftalga=fftalg/100; fftalgc=mod(fftalg,10)
    2240              : 
    2241           12 :  do ikpt=1,size(kpoints, dim=2)
    2242           32 :    kpoint = kpoints(:,ikpt)
    2243              : 
    2244              :    ! Get full G-sphere (no MPI distribution, no time-reversal)
    2245            8 :    call get_kg(kpoint,istwfk_one,ecut,gmet,full_npw_k,full_kg_k)
    2246              : 
    2247              :    ! Get full G-sphere (no MPI distribution, use time-reversal if possible)
    2248            8 :    istwf_k = set_istwfk(kpoint)
    2249            8 :    call get_kg(kpoint,istwf_k,ecut,gmet,istwf_npw_k,istw_kg_k)
    2250              : 
    2251              :    ! Get FFT box dims.
    2252          152 :    ngfft = -1
    2253            8 :    ngfft(7) = fftalg
    2254            8 :    ngfft(8) = get_cache_kb()
    2255              : 
    2256              :    call getng(boxcutmin2,chksymtnons,ecut,gmet,kpoint,me_fft,mgfft,nfft,ngfft,nproc_fft,nsym1,&
    2257            8 :               paral_kgb,symrel,tnons,unit=dev_null)
    2258              : 
    2259            8 :    n1 = ngfft(1); n2 = ngfft(2); n3 = ngfft(3)
    2260              :    ! Do not use augmentation.
    2261              :    !ngfft(4:6) = ngfft(1:3)
    2262            8 :    n4 = ngfft(4); n5 = ngfft(5); n6 = ngfft(6)
    2263              : 
    2264           16 :    call print_ngfft([std_out], ngfft, header="ngfft for MPI-fourwf", prtvol=0)
    2265              : 
    2266              :    ! Compute FFT distribution tables.
    2267            8 :    call fftabs%init("c",nproc_fft,n2,n3)
    2268              : 
    2269              :    ! Set to 1 if this node owns G = 0.
    2270            8 :    me_g0 = 0; if (fftabs%tab_fftwf2_distrib(1) == me_fft) me_g0 = 1
    2271            8 :    g0sender = fftabs%tab_fftwf2_distrib(1)
    2272              : 
    2273              :    ! Allocate u(g) on the full sphere, initialize with random numbers.
    2274              :    ! and broadcast full data to the other nodes.
    2275           24 :    ABI_MALLOC(full_fofg, (2,full_npw_k*ndat))
    2276              : 
    2277            8 :    if (me_fft == g0sender) then
    2278            8 :      if (istwf_k == 1) then
    2279            4 :        call RANDOM_NUMBER(full_fofg)
    2280              :        !full_fofg = one
    2281              : 
    2282            4 :      else if (istwf_k == 2) then
    2283              :        ! Special treatment for real wavefunctions.
    2284              :        ! Fill the irreducible G-vectors first so that we have the u(g) of a real u(r)
    2285              :        ! Then get u(g) on the full G-sphere.
    2286              :        ! TODO: Sequential version OK, SIGSEV if mpi_ncpus > 1!
    2287           12 :        ABI_MALLOC(istwf_fofg, (2,istwf_npw_k*ndat))
    2288            4 :        call RANDOM_NUMBER(istwf_fofg)
    2289              :        ! Enforce real u in G-space.
    2290           12 :        do idat=1,ndat
    2291           12 :          istwf_fofg(2,1+(idat-1)*istwf_npw_k) = zero
    2292              :        end do
    2293              : 
    2294              :        ! from istwfk 2 to 1.
    2295            4 :        call change_istwfk(istwf_npw_k,istw_kg_k,istwf_k,full_npw_k,full_kg_k,istwfk_one,n1,n2,n3,ndat,istwf_fofg,full_fofg)
    2296            4 :        ABI_FREE(istwf_fofg)
    2297              : 
    2298              :      else
    2299            0 :        ABI_ERROR("istwf_k /= [1,2] not available in MPI-FFT mode")
    2300              :      end if
    2301              :    end if
    2302              : 
    2303            8 :    call xmpi_bcast(full_fofg,g0sender,comm_fft,ierr)
    2304              : 
    2305              :    ! Compute sphere boundaries for zero-padded FFTs
    2306           32 :    ABI_MALLOC(gbound_k,(2*mgfft+8,2))
    2307            8 :    call sphereboundary(gbound_k,istwfk_one,full_kg_k,mgfft,full_npw_k)
    2308              : 
    2309              :    ! Extract my G-vectors from full_kg_k and store them in kg_k.
    2310              :    !write(std_out,*)"fftwf2_distrib",fftabs%tab_fftwf2_distrib
    2311           24 :    do step=1,2
    2312           16 :      if (step == 2) then
    2313              :        ! Allocate my u(g) and my Gs.
    2314              :        ! Set fofg to zero to bypass a bug with XLF!
    2315           24 :        ABI_MALLOC(kg_k, (3, npw_k))
    2316      4648344 :        ABI_CALLOC(fofg, (2,npw_k*ndat))
    2317              :      end if
    2318              : 
    2319           16 :      npw_k = 0
    2320      1549464 :      do ig=1,full_npw_k
    2321      1549440 :        i1=full_kg_k(1,ig); if(i1<0) i1=i1+n1; i1=i1+1
    2322      1549440 :        i2=full_kg_k(2,ig); if(i2<0) i2=i2+n2; i2=i2+1
    2323      1549440 :        i3=full_kg_k(3,ig); if(i3<0) i3=i3+n3; i3=i3+1
    2324      1549456 :        if (fftabs%tab_fftwf2_distrib(i2) == me_fft) then
    2325      1549440 :          npw_k = npw_k + 1
    2326      1549440 :          if (step == 2) then
    2327      3098880 :            kg_k(:,npw_k) = full_kg_k(:,ig)
    2328      2324160 :            fofg(:,npw_k) = full_fofg(:,ig)
    2329              :          end if
    2330              :        end if
    2331              :      end do
    2332              :    end do ! step
    2333              : 
    2334            8 :    ABI_FREE(istw_kg_k)
    2335              : 
    2336              :    !write(std_out,*)"dist",trim(itoa(me_fft)),fftabs%tab_fftdp3_distrib(:) !== me_fft)
    2337              :    !write(std_out,*)"local",trim(itoa(me_fft)),fftabs%tab_fftdp3_local(:)
    2338              : 
    2339              :    ! Allocate my local portion of u(r), and keep a copy my u(g).
    2340           40 :    ABI_MALLOC(fofr, (2,n4,n5,n6*ndat))
    2341           24 :    ABI_MALLOC(ref_fofg, (2,npw_k*ndat))
    2342      4648336 :    ref_fofg = fofg
    2343              : 
    2344            8 :    call cwtime(ctime,wtime,gflops,"start")
    2345              : 
    2346              :    ! ----------------------------------------------------------------
    2347              :    ! Test the the backward and the forward transform of wavefunctions
    2348              :    ! ----------------------------------------------------------------
    2349              :    ! c2c or [c2r, r2c]
    2350              :    cplexwf = 2; if (istwf_k==2) cplexwf = 1
    2351              :    ! FIXME:
    2352              :    ! There's a bug somewhere in the MPI routines if cplexwf == 1 is used and ndat > 1
    2353              :    ! Not a serious problem at present since cplexwf==1 is never used in abinit.
    2354              :    if (ndat>1) cplexwf = 2
    2355              :    if (nproc_fft > 1) cplexwf = 2
    2356            8 :    cplexwf = 2
    2357              :    !cplexwf = 2; if (istwf_k==2) cplexwf = 1
    2358              : 
    2359           24 :    do isign = 1,-1,-2
    2360              :      call fftmpi_u(npw_k,n4,n5,n6,ndat,mgfft,ngfft,&
    2361           24 :        istwfk_one,gbound_k,kg_k,me_g0,fftabs,isign,fofg,fofr,comm_fft,cplexwf=cplexwf)
    2362              :    end do
    2363              : 
    2364              :    ! The final interface should be:
    2365              :    !subroutine fftmpi_u(npw_k,n4,n5,n6,nspinor,ndat,mgfft,ngfft,istwf_k,kg_k,gbound_k,fftabs,isign,fofg,fofr)
    2366              : 
    2367              :    ! Parallel version (must support augmentation in forf(:,:,:,:), hence we have a different API wrt the seq case!
    2368              :    !call fftmpi_ug(npw_k,n4,n5,n6,nspinor,ndat,mgfft,ngfft,istwf_k,kg_k,gbound_k,fftabs,fofg,fofr)
    2369              :    !call fftmpi_ur(npw_k,n4,n5,n6,nspinor,ndat,mgfft,ngfft,istwf_k,kg_k,gbound_k,fftabs,fofr,fofgout)
    2370              : 
    2371              :    ! Seq version.
    2372              :    !call fft_ug(npw_k,nxyz,nspinor,ndat,mgfft,ngfft,istwf_k,kg_k,gbound_k,ugsp,ursp)
    2373              :    !call fft_ur(npw_k,nxyz,nspinor,ndat,mgfft,ngfft,istwf_k,kg_k,gbound_k,ursp,ugsp)
    2374              : 
    2375            8 :    call cwtime(ctime,wtime,gflops,"stop")
    2376              :    if (me_fft == 0) then
    2377              :      !write(std_out,'(a,i0,3(a,f10.4))')"fftalg: ",fftalg,", ecut: ",ecut,", cpu_time: ",ctime,", wall_time: ",wtime
    2378              :    end if
    2379              : 
    2380              :    ! Check if F^{-1} F = I within ATOL_DP
    2381      4648328 :    ierr = COUNT(ABS(fofg - ref_fofg) > ATOL_DP)
    2382            8 :    call xmpi_sum(ierr,comm_fft,mpierr)
    2383            8 :    nfailed = nfailed + ierr
    2384              : 
    2385            8 :    write(info,"(a,i1,a)")sjoin(library,"fftu_mpi, istwfk "),istwf_k," :"
    2386              : 
    2387            8 :    write(msg,"(a)")" OK"
    2388            8 :    if (ierr /= 0) then
    2389            0 :      max_abserr = MAXVAL(ABS(fofg - ref_fofg))
    2390            0 :      call xmpi_max(max_abserr,comm_fft,mpierr)
    2391            0 :      write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    2392              :    end if
    2393            8 :    call wrtout(ount,sjoin(info, msg))
    2394              : 
    2395              :    ! -------------------------------------------
    2396              :    ! Test the accumulation of density (option 1)
    2397              :    ! -------------------------------------------
    2398     14172520 :    ABI_CALLOC(density, (cplex_one*n4,n5,n6))
    2399              :    !fofg = one
    2400              : 
    2401              :    ! Accumulate density. Does not work if cplexwf==1
    2402              :    call fourwf_mpi(cplex_one,density,fofg,dummy_fofg,fofr,&
    2403              :      gbound_k,gbound_k,istwfk_one,kg_k,kg_k,me_g0,mgfft,ngfft,fftabs,n1,n2,n3,&
    2404            8 :      npw_k,npw_k,n4,n5,n6,ndat,1,weight_r,weight_i,comm_fft,cplexwf=cplexwf)
    2405              : 
    2406              : !   Recompute u(r)
    2407              : !   call fourwf_mpi(cplex_one,density,fofg,dummy_fofg,fofr,&
    2408              : !&    gbound_k,gbound_k,istwf_one,kg_k,kg_k,me_g0,mgfft,ngfft,fftabs,n1,n2,n3,&
    2409              : !&    npw_k,npw_k,n4,n5,n6,ndat,0,weight_r,weight_i,comm_fft,cplexwf=cplexwf)
    2410              : !   call xmpi_sum(density,comm_fft,ierr)
    2411              : !   if (me_fft == 0) write(std_out,*)"sum density", sum(density)
    2412              : 
    2413              :    !do i3=1,n6
    2414              :    !  write(110+me_fft,*)i3,density(:,:,i3)
    2415              :    !end do
    2416              : 
    2417            8 :    max_relerr = zero
    2418              : 
    2419              :    ! FIXME: This is wrong if ndat > 1
    2420              :    ! Must unify the treatment of fofr and rhor on the augmented mesh (n4,n5,n6)
    2421              :    ! back_wf and for_wf return a MPI distributed arrays but fofr is allocated with
    2422              :    ! the global dimensions.
    2423            8 :    nd3proc=(n3-1)/nproc_fft+1
    2424          968 :    do i3=1,n3
    2425              :    !do i3=1,nd3proc
    2426          968 :      if( me_fft == fftabs%tab_fftdp3_distrib(i3) ) then
    2427          960 :        i3_local = fftabs%tab_fftdp3_local(i3) !+ nd3proc*(idat-1)
    2428              :        !i3_local = i3
    2429          960 :        i3_glob = i3
    2430              :        !i3_glob = i3_local
    2431              :        !i3_glob = i3 + nd3proc * me_fft
    2432              :        !i3dat = i3  + n6 * (idat-1)
    2433       116160 :        do i2=1,n2
    2434     13940160 :          do i1=1,n1
    2435     13824000 :             den = density(i1,i2,i3_glob)
    2436     13824000 :             refden = zero
    2437     41472000 :             do idat=1,ndat
    2438     27648000 :               i3dat = i3_local + n6 * (idat-1)
    2439     41472000 :               refden = refden + weight_r*fofr(1,i1,i2,i3dat)**2+ weight_i*fofr(2,i1,i2,i3dat)**2
    2440              :             end do
    2441     13824000 :             relerr = abs(refden - den)
    2442     13824000 :             if (abs(refden) < tol12) refden = tol12
    2443     13824000 :             relerr = relerr / abs(refden)
    2444     13939200 :             max_relerr = max(max_relerr, relerr)
    2445              :             !if (relerr > RTOL_DP) write(std_out,*)trim(itoa(me_fft)),i1,i2,i3,idat,den,refden
    2446              :          end do
    2447              :        end do
    2448              :      end if
    2449              :    end do
    2450              : 
    2451            8 :    call xmpi_max(max_relerr,comm_fft,mpierr)
    2452              : 
    2453            8 :    write(info,"(a,i1,a)")sjoin(library,"accrho_mpi, istwfk "),istwf_k," :"
    2454            8 :    write(msg,"(a)")" OK"
    2455            8 :    if (max_relerr > RTOL_DP) then
    2456            0 :      write(msg,"(a,es9.2,a)")" FAILED (max_relerr = ",max_relerr,")"
    2457              :    end if
    2458            8 :    call wrtout(ount, sjoin(info, msg))
    2459              : 
    2460            8 :    ABI_FREE(density)
    2461              : 
    2462              :    ! -------------------------------------------
    2463              :    ! Test the application of the local potential
    2464              :    ! -------------------------------------------
    2465            8 :    cplex = 1
    2466           32 :    ABI_MALLOC(pot, (cplex*n4,n5,n6))
    2467           32 :    ABI_MALLOC(invpot, (cplex*n4,n5,n6))
    2468              : 
    2469            8 :    if (me_fft == g0sender) then
    2470              :      !pot = fofr(1,:,:,:)
    2471              :      !call RANDOM_NUMBER(pot)
    2472              :      !where (abs(pot) < tol4) pot = tol4
    2473              :      ! Simplest potential ever (G=0 to reduce errors due to aliasing)
    2474     14172488 :      pot = four
    2475     14172496 :      invpot = one/pot
    2476              :    end if
    2477              : 
    2478            8 :    call xmpi_bcast(pot,g0sender,comm_fft,ierr)
    2479            8 :    call xmpi_bcast(invpot,g0sender,comm_fft,ierr)
    2480              : 
    2481           16 :    ABI_MALLOC(fofg_out, (2,npw_k*ndat))
    2482              : 
    2483              :    ! Compute fofg_out = <G|pot(r)|fofg>
    2484              :    call fourwf_mpi(cplex,pot,fofg,fofg_out,fofr,&
    2485              :      gbound_k,gbound_k,istwfk_one,kg_k,kg_k,me_g0,mgfft,ngfft,fftabs,n1,n2,n3,&
    2486            8 :      npw_k,npw_k,n4,n5,n6,ndat,2,weight_r,weight_i,comm_fft,cplexwf=cplexwf)
    2487              : 
    2488              :    ! Compute fofg = <G|1/pot(r)|fofg_out>
    2489              :    call fourwf_mpi(cplex,invpot,fofg_out,fofg,fofr,&
    2490              :      gbound_k,gbound_k,istwfk_one,kg_k,kg_k,me_g0,mgfft,ngfft,fftabs,n1,n2,n3,&
    2491            8 :      npw_k,npw_k,n4,n5,n6,ndat,2,weight_r,weight_i,comm_fft,cplexwf=cplexwf)
    2492              : 
    2493              :    ! Check if we got the initial u(g) within ATOL_DP
    2494      4648328 :    ierr = COUNT(ABS(fofg - ref_fofg) > ATOL_DP)
    2495            8 :    call xmpi_sum(ierr,comm_fft,mpierr)
    2496            8 :    nfailed = nfailed + ierr
    2497              : 
    2498            8 :    write(info,"(a,i1,a)")sjoin(library,"<G|vloc|u>, istwfk "),istwf_k," :"
    2499            8 :    write(msg,"(a)")" OK"
    2500            8 :    if (ierr /= 0) then
    2501            0 :      max_abserr = MAXVAL(ABS(fofg - ref_fofg))
    2502            0 :      call xmpi_max(max_abserr,comm_fft,mpierr)
    2503            0 :      write(msg,"(a,es9.2,a)")" FAILED (max_abserr = ",max_abserr,")"
    2504              :      !if (me_fft == 0) write(std_out,*)(fofg(:,ig),ref_fofg(:,ig), ig=1,npw_k*ndat)
    2505              :    end if
    2506            8 :    call wrtout(ount, sjoin(info, msg))
    2507              : 
    2508            8 :    ABI_FREE(fofg_out)
    2509            8 :    ABI_FREE(pot)
    2510            8 :    ABI_FREE(invpot)
    2511            8 :    ABI_FREE(kg_k)
    2512            8 :    ABI_FREE(gbound_k)
    2513            8 :    ABI_FREE(fofg)
    2514            8 :    ABI_FREE(ref_fofg)
    2515            8 :    ABI_FREE(fofr)
    2516            8 :    ABI_FREE(full_kg_k)
    2517            8 :    ABI_FREE(full_fofg)
    2518              : 
    2519           68 :    call fftabs%free()
    2520              :  end do
    2521              : 
    2522            4 :  if (nthreads > 0) call xomp_set_num_threads(old_nthreads)
    2523              : 
    2524            4 : end function fftu_mpi_utests
    2525              : !!***
    2526              : 
    2527              : !!****f* ABINIT/fourwf_optmem
    2528              : !! NAME
    2529              : !! fourwf_optmem
    2530              : !!
    2531              : !! FUNCTION
    2532              : !! Wrapper on fourwf call, meant to be called on a fofr array smaller than ndat.
    2533              : !! Mainly used in sections where this array may explode in size, thus requiring
    2534              : !! fourwf computation to be done in many times to save on memory.
    2535              : !! For now, only GPU usecases are handled, where lack of memory is problematic
    2536              : !! even if CPU usecases can be handled by this routine.
    2537              : !! Arguments are identical to fourwf, except for extra 'nblocks', and the size of fofr array.
    2538              : !! For option={0,3} or gpu_option=ABI_GPU_DISABLED, regular fourwf is used and fofr is assumed sized by ndat
    2539              : !!
    2540              : !! Carry out composite Fourier transforms between real and reciprocal (G) space.
    2541              : !! Wavefunctions, contained in a sphere in reciprocal space,
    2542              : !! can be FFT to real space. They can also be FFT from real space
    2543              : !! to a sphere. Also, the density maybe accumulated, and a local
    2544              : !! potential can be applied.
    2545              : !!
    2546              : !! The different options are :
    2547              : !! - option=0 --> reciprocal to real space and output the result.
    2548              : !! - option=1 --> reciprocal to real space and accumulate the density.
    2549              : !! - option=2 --> reciprocal to real space, apply the local potential to the wavefunction
    2550              : !!                in real space and produce the result in reciprocal space.
    2551              : !! - option=3 --> real space to reciprocal space.
    2552              : !!                NOTE that in this case, fftalg=1x1 MUST be used. This may be changed in the future.
    2553              : !!
    2554              : !! The different sections of this routine corresponds to different
    2555              : !! algorithms, used independently of each others :
    2556              : !!(read first the description of the fftalg input variable in abinit_help)
    2557              : !! - fftalg=xx0 : use simple complex-to-complex routines, without zero padding
    2558              : !!     (rather simple, so can be used to understand how fourwf.f works);
    2559              : !! - fftalg=1x1 : use S Goedecker routines, with zero padding
    2560              : !!     (7/12 savings in execution time);
    2561              : !! - fftalg=1x2 : call even more sophisticated coding also based on S Goedecker routines
    2562              : !!
    2563              : !! This routine contains many parts that differ only
    2564              : !! by small details, in order to treat each case with the better speed.
    2565              : !! Also for better speed, it uses no F90 construct, except the allocate command
    2566              : !! and for zeroing arrays.
    2567              : !!
    2568              : !! INPUTS
    2569              : !! cplex= if 1 , denpot is real, if 2 , denpot is complex
    2570              : !!    (cplex=2 only allowed for option=2, and istwf_k=1)
    2571              : !!    not relevant if option=0 or option=3, so cplex=0 can be used to minimize memory
    2572              : !! fofgin(2,npwin)=holds input wavefunction in G vector basis sphere.
    2573              : !!                 (intent(in) but the routine sphere can modify it for another iflag)
    2574              : !! gboundin(2*mgfft+8,2)=sphere boundary info for reciprocal to real space
    2575              : !! gboundout(2*mgfft+8,2)=sphere boundary info for real to reciprocal space
    2576              : !! istwf_k=option parameter that describes the storage of wfs
    2577              : !! kg_kin(3,npwin)=reduced planewave coordinates, input
    2578              : !! kg_kout(3,npwout)=reduced planewave coordinates, output
    2579              : !! mgfft=maximum size of 1D FFTs
    2580              : !! mpi_enreg=information about MPI parallelization
    2581              : !! ndat=number of FFT to do in //
    2582              : !! nblocks=number of FFT to split computation into
    2583              : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    2584              : !! npwin=number of elements in fofgin array (for option 0, 1 and 2)
    2585              : !! npwout=number of elements in fofgout array (for option 2 and 3)
    2586              : !! n4,n5,n6=ngfft(4),ngfft(5),ngfft(6), dimensions of fofr.
    2587              : !! option= if 0: do direct FFT
    2588              : !!         if 1: do direct FFT, then sum the density
    2589              : !!         if 2: do direct FFT, multiply by the potential, then do reverse FFT
    2590              : !!         if 3: do reverse FFT only
    2591              : !! tim_fourwf=timing code of the calling routine (can be set to 0 if not attributed)
    2592              : !! weight_r=weight to be used for the accumulation of the density in real space
    2593              : !!         (needed only when option=1)
    2594              : !! weight_i=weight to be used for the accumulation of the density in real space
    2595              : !!         (needed only when option=1 and (fftalg=4 and fftalgc/=0))
    2596              : !! [weight_array_r]= -- optional -- same as weight_r when ndat>1
    2597              : !!                   weight_array_r(i)=weight_r to be used for band i
    2598              : !!                   at present only used for the GPU version
    2599              : !! [weight_array_i]= -- optional -- same as weight_i when ndat>1
    2600              : !!                   weight_array_i(i)=weight_i to be used for band i
    2601              : !!                   at present only used for the GPU version
    2602              : !! [fofginb(2,npwin)]=holds second input wavefunction in G vector basis sphere.
    2603              : !!                 (intent(in) but the routine sphere can modify it for another iflag)
    2604              : !!                 (for non diagonal occupation)
    2605              : !! [use_ndo] = use non diagonal occupations.
    2606              : !! [gpu_option] = GPU implementation to use, i.e. cuda, openMP, ... (0=not using GPU)
    2607              : !!
    2608              : !! OUTPUT
    2609              : !!  (see side effects)
    2610              : !!
    2611              : !! SIDE EFFECTS
    2612              : !! Input/Output
    2613              : !! for option==0, fofgin(2,npwin*ndat)=holds input wavefunction in G sphere;
    2614              : !!                fofr(2,n4,n5,n6*ndat) contains the output Fourier Transform of fofgin;
    2615              : !!                no use of denpot, fofgout and npwout.
    2616              : !! for option==1, fofgin(2,npwin*ndat)=holds input wavefunction in G sphere;
    2617              : !!                denpot(cplex*n4,n5,n6) contains the input density at input,
    2618              : !!                and the updated density at output (accumulated);
    2619              : !!                no use of fofgout and npwout.
    2620              : !! for option==2, fofgin(2,npwin*ndat)=holds input wavefunction in G sphere;
    2621              : !!                denpot(cplex*n4,n5,n6) contains the input local potential;
    2622              : !!                fofgout(2,npwout*ndat) contains the output function;
    2623              : !! for option==3, fofr(2,n4,n5,n6*ndat) contains the input real space wavefunction;
    2624              : !!                fofgout(2,npwout*ndat) contains its output Fourier transform;
    2625              : !!                no use of fofgin and npwin.
    2626              : !!
    2627              : !! NOTES
    2628              : !!   DO NOT CHANGE THE API OF THIS FUNCTION.
    2629              : !!   If you need a specialized routine for the FFT of the wavefunctions, create
    2630              : !!   a wrapper that uses fourwf to accomplish your task. This routine, indeed,
    2631              : !!   has already too many parameters and each change in the API requires a careful
    2632              : !!   modification of the different wrappers used for specialized FFTs such as FFTW3 and MKL-DFTI
    2633              : !!
    2634              : !! SOURCE
    2635              : 
    2636     41292771 : subroutine fourwf_optmem(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,&
    2637     41292771 :                   kg_kin,kg_kout,mgfft,mpi_enreg,ndat,nblocks,ngfft,npwin,npwout,n4,n5,n6,option,&
    2638              :                   tim_fourwf,weight_r,weight_i, &
    2639     41292771 :                   weight_array_r,weight_array_i,gpu_option,use_ndo,fofginb) ! Optional arguments
    2640              : 
    2641              : !Arguments ------------------------------------
    2642              : !scalars
    2643              :  integer,intent(in) :: cplex,istwf_k,mgfft,n4,n5,n6,ndat,nblocks,npwin,npwout,option
    2644              :  integer,intent(in) :: tim_fourwf
    2645              :  integer,intent(in),optional :: gpu_option,use_ndo
    2646              :  real(dp),intent(in) :: weight_r,weight_i
    2647              :  real(dp),intent(in),optional,target :: weight_array_r(ndat),weight_array_i(ndat)
    2648              :  type(MPI_type),intent(in) :: mpi_enreg
    2649              : !arrays
    2650              :  integer,intent(in) :: gboundin(2*mgfft+8,2),gboundout(2*mgfft+8,2)
    2651              :  integer,intent(in) :: kg_kin(3,npwin),kg_kout(3,npwout),ngfft(18)
    2652              :  real(dp),intent(inout) :: denpot(cplex*n4,n5,n6),fofgin(2,npwin*ndat)
    2653              :  real(dp),intent(inout),optional :: fofginb(:,:) ! (2,npwin*ndat)
    2654              :  real(dp),intent(inout) :: fofr(:,:,:,:) !(2,n4,n5,n6*(ndat/nblocks+ndat-(ndat/nblocks)*nblocks))
    2655              :  real(dp),intent(out) :: fofgout(2,npwout*ndat)
    2656              : 
    2657     41292771 :  real(dp),pointer :: weight_ptr_r(:),weight_ptr_i(:)
    2658              : 
    2659              :  integer :: ii,chunk,residuchunk,iblock,gpu_option_
    2660              :  integer :: firstelt,firstelt_out,firstband,lastelt,lastelt_out,lastband
    2661              : 
    2662     41292771 :  gpu_option_=ABI_GPU_DISABLED; if(present(gpu_option)) gpu_option_=gpu_option
    2663              : 
    2664     41292771 :  ABI_CHECK_IEQ(size(fofr,dim=1), 2,  'wrong size for fofr (dim 1)')
    2665     41292771 :  ABI_CHECK_IEQ(size(fofr,dim=2), n4, 'wrong size for fofr (dim 2)')
    2666     41292771 :  ABI_CHECK_IEQ(size(fofr,dim=3), n5, 'wrong size for fofr (dim 3)')
    2667              : 
    2668     41292771 :  if(gpu_option_==ABI_GPU_DISABLED .or. option==0 .or. option==3) then
    2669     41292771 :    if(gpu_option/=ABI_GPU_DISABLED) then
    2670            0 :      ABI_CHECK_IEQ(size(fofr,dim=4), n6*ndat, 'wrong size for fofr (dim 4)')
    2671              :    end if
    2672              : 
    2673              :    call fourwf(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,&
    2674              :    &    kg_kin,kg_kout,mgfft,mpi_enreg,ndat,ngfft,npwin,npwout,n4,n5,n6,option,&
    2675              :    &    tim_fourwf,weight_r,weight_i, &
    2676              :    &    weight_array_r=weight_array_r,weight_array_i=weight_array_i,&
    2677     82585542 :    &    gpu_option=gpu_option,use_ndo=use_ndo,fofginb=fofginb)
    2678              : 
    2679              :  else
    2680            0 :    chunk = ndat/nblocks
    2681            0 :    residuchunk = ndat - nblocks*chunk
    2682              : 
    2683            0 :    ABI_CHECK_IEQ(size(fofr,dim=4), n6*(chunk+residuchunk), 'wrong size for fofr (dim 4)')
    2684              : 
    2685            0 :    if(option==1) then
    2686              : 
    2687            0 :      if (present(weight_array_r)) then
    2688            0 :        weight_ptr_r => weight_array_r
    2689              :      else
    2690            0 :        ABI_MALLOC(weight_ptr_r,(ndat))
    2691            0 :        weight_ptr_r(:)=weight_r
    2692              :      end if
    2693            0 :      if (present(weight_array_i)) then
    2694            0 :        weight_ptr_i => weight_array_i
    2695              :      else
    2696            0 :        ABI_MALLOC(weight_ptr_i,(ndat))
    2697            0 :        weight_ptr_i(:)=weight_i
    2698              :      end if
    2699              : 
    2700            0 :      do ii=1,nblocks
    2701            0 :        iblock=ii-1
    2702            0 :        if ( iblock < nblocks-residuchunk ) then
    2703            0 :          firstband = iblock*chunk+1
    2704            0 :          lastband = (iblock+1)*chunk
    2705              :        else
    2706            0 :          firstband = (nblocks-residuchunk)*chunk + ( iblock -(nblocks-residuchunk) )*(chunk+1) +1
    2707            0 :          lastband = firstband+chunk
    2708              :        end if
    2709            0 :        firstelt = (firstband-1)*npwin+1; lastelt = lastband*npwin
    2710              :        call fourwf(cplex,denpot,&
    2711              :        &      fofgin(:,firstelt:lastelt),&
    2712              :        &      fofgout,fofr,gboundin,gboundout,&
    2713              :        &      istwf_k,kg_kin,kg_kout,mgfft,mpi_enreg,lastband-firstband+1,&
    2714              :        &      ngfft,npwin,npwout,n4,n5,n6,option,tim_fourwf,weight_r,weight_i,&
    2715              :        &      weight_array_r=weight_ptr_r(firstband:lastband),&
    2716              :        &      weight_array_i=weight_ptr_i(firstband:lastband),&
    2717            0 :        &      gpu_option=gpu_option_,use_ndo=use_ndo,fofginb=fofginb)
    2718              :      end do
    2719              : 
    2720            0 :      if (.not.present(weight_array_r)) then
    2721            0 :        ABI_FREE(weight_ptr_r)
    2722              :      end if
    2723            0 :      if (.not.present(weight_array_i)) then
    2724            0 :        ABI_FREE(weight_ptr_i)
    2725              :      end if
    2726              : 
    2727            0 :    else if(option==2) then
    2728              : 
    2729            0 :      do ii=1,nblocks
    2730            0 :        iblock=ii-1
    2731            0 :        if ( iblock < nblocks-residuchunk ) then
    2732            0 :          firstband = iblock*chunk+1
    2733            0 :          lastband = (iblock+1)*chunk
    2734              :        else
    2735            0 :          firstband = (nblocks-residuchunk)*chunk + ( iblock -(nblocks-residuchunk) )*(chunk+1) +1
    2736            0 :          lastband = firstband+chunk
    2737              :        end if
    2738            0 :        firstelt = (firstband-1)*npwin+1; lastelt = lastband*npwin
    2739            0 :        firstelt_out = (firstband-1)*npwout+1; lastelt_out = lastband*npwout
    2740              :        call fourwf(cplex,denpot,&
    2741              :        &      fofgin(:,firstelt:lastelt),&
    2742              :        &      fofgout(:,firstelt_out:lastelt_out),fofr,gboundin,gboundout,&
    2743              :        &      istwf_k,kg_kin,kg_kout,mgfft,mpi_enreg,lastband-firstband+1,&
    2744              :        &      ngfft,npwin,npwout,n4,n5,n6,option,tim_fourwf,weight_r,weight_i,&
    2745            0 :        &      gpu_option=gpu_option_,use_ndo=use_ndo,fofginb=fofginb)
    2746              :      end do
    2747              : 
    2748              :    end if
    2749              : 
    2750              :  end if
    2751              : 
    2752              : 
    2753     41292771 : end subroutine fourwf_optmem
    2754              : !!***
    2755              : 
    2756              : !!****f* ABINIT/fourwf
    2757              : !! NAME
    2758              : !! fourwf
    2759              : !!
    2760              : !! FUNCTION
    2761              : !! Carry out composite Fourier transforms between real and reciprocal (G) space.
    2762              : !! Wavefunctions, contained in a sphere in reciprocal space,
    2763              : !! can be FFT to real space. They can also be FFT from real space
    2764              : !! to a sphere. Also, the density maybe accumulated, and a local
    2765              : !! potential can be applied.
    2766              : !!
    2767              : !! The different options are :
    2768              : !! - option=0 --> reciprocal to real space and output the result.
    2769              : !! - option=1 --> reciprocal to real space and accumulate the density.
    2770              : !! - option=2 --> reciprocal to real space, apply the local potential to the wavefunction
    2771              : !!                in real space and produce the result in reciprocal space.
    2772              : !! - option=3 --> real space to reciprocal space.
    2773              : !!                NOTE that in this case, fftalg=1x1 MUST be used. This may be changed in the future.
    2774              : !!
    2775              : !! The different sections of this routine corresponds to different
    2776              : !! algorithms, used independently of each others :
    2777              : !!(read first the description of the fftalg input variable in abinit_help)
    2778              : !! - fftalg=xx0 : use simple complex-to-complex routines, without zero padding
    2779              : !!     (rather simple, so can be used to understand how fourwf.f works);
    2780              : !! - fftalg=1x1 : use S Goedecker routines, with zero padding
    2781              : !!     (7/12 savings in execution time);
    2782              : !! - fftalg=1x2 : call even more sophisticated coding also based on S Goedecker routines
    2783              : !!
    2784              : !! This routine contains many parts that differ only
    2785              : !! by small details, in order to treat each case with the better speed.
    2786              : !! Also for better speed, it uses no F90 construct, except the allocate command
    2787              : !! and for zeroing arrays.
    2788              : !!
    2789              : !! INPUTS
    2790              : !! cplex= if 1 , denpot is real, if 2 , denpot is complex
    2791              : !!    (cplex=2 only allowed for option=2, and istwf_k=1)
    2792              : !!    not relevant if option=0 or option=3, so cplex=0 can be used to minimize memory
    2793              : !! fofgin(2,npwin)=holds input wavefunction in G vector basis sphere.
    2794              : !!                 (intent(in) but the routine sphere can modify it for another iflag)
    2795              : !! gboundin(2*mgfft+8,2)=sphere boundary info for reciprocal to real space
    2796              : !! gboundout(2*mgfft+8,2)=sphere boundary info for real to reciprocal space
    2797              : !! istwf_k=option parameter that describes the storage of wfs
    2798              : !! kg_kin(3,npwin)=reduced planewave coordinates, input
    2799              : !! kg_kout(3,npwout)=reduced planewave coordinates, output
    2800              : !! mgfft=maximum size of 1D FFTs
    2801              : !! mpi_enreg=information about MPI parallelization
    2802              : !! ndat=number of FFT to do in //
    2803              : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    2804              : !! npwin=number of elements in fofgin array (for option 0, 1 and 2)
    2805              : !! npwout=number of elements in fofgout array (for option 2 and 3)
    2806              : !! n4,n5,n6=ngfft(4),ngfft(5),ngfft(6), dimensions of fofr.
    2807              : !! option= if 0: do direct FFT
    2808              : !!         if 1: do direct FFT, then sum the density
    2809              : !!         if 2: do direct FFT, multiply by the potential, then do reverse FFT
    2810              : !!         if 3: do reverse FFT only
    2811              : !! tim_fourwf=timing code of the calling routine (can be set to 0 if not attributed)
    2812              : !! weight_r=weight to be used for the accumulation of the density in real space
    2813              : !!         (needed only when option=1)
    2814              : !! weight_i=weight to be used for the accumulation of the density in real space
    2815              : !!         (needed only when option=1 and (fftalg=4 and fftalgc/=0))
    2816              : !! [weight_array_r]= -- optional -- same as weight_r when ndat>1
    2817              : !!                   weight_array_r(i)=weight_r to be used for band i
    2818              : !!                   at present only used for the GPU version
    2819              : !! [weight_array_i]= -- optional -- same as weight_i when ndat>1
    2820              : !!                   weight_array_i(i)=weight_i to be used for band i
    2821              : !!                   at present only used for the GPU version
    2822              : !! [fofginb(2,npwin)]=holds second input wavefunction in G vector basis sphere.
    2823              : !!                 (intent(in) but the routine sphere can modify it for another iflag)
    2824              : !!                 (for non diagonal occupation)
    2825              : !! [use_ndo] = use non diagonal occupations.
    2826              : !! [gpu_option] = GPU implementation to use, i.e. cuda, openMP, ... (0=not using GPU)
    2827              : !!
    2828              : !! OUTPUT
    2829              : !!  (see side effects)
    2830              : !!
    2831              : !! SIDE EFFECTS
    2832              : !! Input/Output
    2833              : !! for option==0, fofgin(2,npwin*ndat)=holds input wavefunction in G sphere;
    2834              : !!                fofr(2,n4,n5,n6*ndat) contains the output Fourier Transform of fofgin;
    2835              : !!                no use of denpot, fofgout and npwout.
    2836              : !! for option==1, fofgin(2,npwin*ndat)=holds input wavefunction in G sphere;
    2837              : !!                denpot(cplex*n4,n5,n6) contains the input density at input,
    2838              : !!                and the updated density at output (accumulated);
    2839              : !!                no use of fofgout and npwout.
    2840              : !! for option==2, fofgin(2,npwin*ndat)=holds input wavefunction in G sphere;
    2841              : !!                denpot(cplex*n4,n5,n6) contains the input local potential;
    2842              : !!                fofgout(2,npwout*ndat) contains the output function;
    2843              : !! for option==3, fofr(2,n4,n5,n6*ndat) contains the input real space wavefunction;
    2844              : !!                fofgout(2,npwout*ndat) contains its output Fourier transform;
    2845              : !!                no use of fofgin and npwin.
    2846              : !!
    2847              : !! NOTES
    2848              : !!   DO NOT CHANGE THE API OF THIS FUNCTION.
    2849              : !!   If you need a specialized routine for the FFT of the wavefunctions, create
    2850              : !!   a wrapper that uses fourwf to accomplish your task. This routine, indeed,
    2851              : !!   has already too many parameters and each change in the API requires a careful
    2852              : !!   modification of the different wrappers used for specialized FFTs such as FFTW3 and MKL-DFTI
    2853              : !!
    2854              : !! SOURCE
    2855              : 
    2856    122113026 : subroutine fourwf(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,&
    2857     61056513 :                   kg_kin,kg_kout,mgfft,mpi_enreg,ndat,ngfft,npwin,npwout,n4,n5,n6,option,&
    2858              :                   tim_fourwf,weight_r,weight_i, &
    2859     61056513 :                   weight_array_r,weight_array_i,gpu_option,use_ndo,fofginb) ! Optional arguments
    2860              : 
    2861              : !Arguments ------------------------------------
    2862              : !scalars
    2863              :  integer,intent(in) :: cplex,istwf_k,mgfft,n4,n5,n6,ndat,npwin,npwout,option
    2864              :  integer,intent(in) :: tim_fourwf
    2865              :  integer,intent(in),optional :: gpu_option,use_ndo
    2866              :  real(dp),intent(in) :: weight_r,weight_i
    2867              :  real(dp),intent(in),optional,target :: weight_array_r(ndat),weight_array_i(ndat)
    2868              :  type(MPI_type),intent(in) :: mpi_enreg
    2869              : !arrays
    2870              :  integer,intent(in) :: gboundin(2*mgfft+8,2),gboundout(2*mgfft+8,2)
    2871              :  integer,intent(in) :: kg_kin(3,npwin),kg_kout(3,npwout),ngfft(18)
    2872              :  real(dp),intent(inout) :: denpot(cplex*n4,n5,n6),fofgin(2,npwin*ndat)
    2873              :  real(dp),intent(inout),optional :: fofginb(:,:) ! (2,npwin*ndat)
    2874              :  real(dp),intent(inout) :: fofr(2,n4,n5,n6*ndat)
    2875              :  real(dp),intent(out) :: fofgout(2,npwout*ndat)
    2876              : 
    2877              : !Local variables-------------------------------
    2878              : !scalars
    2879              :  integer :: fftalg,fftalga,fftalgc,fftcache,i1,i2,i2_local,i3,i3_local,i3_glob,idat,ier
    2880              :  integer :: iflag,ig,comm_fft,me_g0,me_fft,n1,n2,n3,nd2proc,nd3proc
    2881              :  integer :: nfftot,nproc_fft,option_ccfft,paral_kgb,gpu_option_
    2882              :  real(dp) :: fim,fre,xnorm
    2883              :  character(len=500) :: msg
    2884              :  logical :: luse_ndo
    2885              : !arrays
    2886              :  integer,parameter :: shiftg0(3)=0
    2887              :  integer,parameter :: symmE(3,3)=reshape([1,0,0,0,1,0,0,0,1],[3,3])
    2888     61056513 :  integer, contiguous, pointer :: fftn2_distrib(:),ffti2_local(:)
    2889     61056513 :  integer, contiguous, pointer :: fftn3_distrib(:),ffti3_local(:)
    2890              :  real(dp) :: tsec(2)
    2891     61056513 :  real(dp),allocatable :: work1(:,:,:,:),work2(:,:,:,:),work3(:,:,:,:)
    2892     61056513 :  real(dp),allocatable :: work4(:,:,:,:),work_sum(:,:,:,:)
    2893     61056513 :  real(dp),pointer :: weight_ptr_r(:),weight_ptr_i(:)
    2894              : ! *************************************************************************
    2895              : 
    2896              :  ! Accumulate timing
    2897     61056513 :  call timab(840+tim_fourwf,1,tsec)
    2898              : 
    2899     61056513 :  if (fourwf_counter>=0) then
    2900            0 :    fourwf_counter = fourwf_counter + ndat
    2901            0 :    if (option==2) fourwf_counter = fourwf_counter + ndat
    2902              :  end if
    2903              : 
    2904     61056513 :  n1=ngfft(1); n2=ngfft(2); n3=ngfft(3); nfftot=n1*n2*n3
    2905     61056513 :  fftcache=ngfft(8)
    2906     61056513 :  fftalg=ngfft(7); fftalga=fftalg/100; fftalgc=mod(fftalg,10)
    2907     61056513 :  me_fft=ngfft(11)
    2908     61056513 :  nproc_fft=ngfft(10)
    2909              : 
    2910     61056513 :  comm_fft = mpi_enreg%comm_fft; me_g0 = mpi_enreg%me_g0_fft
    2911     61056513 :  paral_kgb = mpi_enreg%paral_kgb
    2912              : 
    2913              :  !if (ndat/=1) then
    2914              :  !  write(std_out,*)fftalg
    2915              :  !  ABI_ERROR("Really? I thought nobody uses ndat > 1")
    2916              :  !end if
    2917              : 
    2918              :  !if (weight_r /= weight_i) then
    2919              :  !  write(std_out,*)fftalg
    2920              :  !  ABI_ERROR("Really? I thought nobody uses weight_r != weight_i")
    2921              :  !end if
    2922              : 
    2923              :  !if (option == 0 .and. fftalgc == 0) then
    2924              :  !  ABI_ERROR("Option 0 is buggy when fftalgc ==0 is used!")
    2925              :  !end if
    2926              : 
    2927              : !GPU version of fourwf
    2928     61056513 :  gpu_option_=ABI_GPU_DISABLED
    2929     61056513 :  if (PRESENT(gpu_option)) gpu_option_=gpu_option
    2930              : 
    2931              :  !If processing gamma-point, disable GPU, except OpenMP (not supported on other variants)
    2932     61056513 :  if(me_g0==1 .and. istwf_k>1 .and. gpu_option_/=ABI_GPU_OPENMP) then
    2933              :    gpu_option_=ABI_GPU_DISABLED
    2934              :  end if
    2935              : 
    2936     59703376 :  if(gpu_option_/=ABI_GPU_DISABLED) then
    2937            0 :    if (present(weight_array_r)) then
    2938            0 :      weight_ptr_r => weight_array_r
    2939              :    else
    2940            0 :      ABI_MALLOC(weight_ptr_r,(ndat))
    2941            0 :      weight_ptr_r(:)=weight_r
    2942              :    end if
    2943            0 :    if (present(weight_array_i)) then
    2944            0 :      weight_ptr_i => weight_array_i
    2945              :    else
    2946            0 :      ABI_MALLOC(weight_ptr_i,(ndat))
    2947            0 :      weight_ptr_i(:)=weight_i
    2948              :    end if
    2949              :    if(gpu_option_==ABI_GPU_LEGACY) then
    2950              : #if defined HAVE_GPU_CUDA
    2951              :      call gpu_fourwf(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,&
    2952              :        kg_kin,kg_kout,mgfft,mpi_enreg,ndat,ngfft,npwin,npwout,n4,n5,n6,option,&
    2953              :        paral_kgb,tim_fourwf,weight_ptr_r,weight_ptr_i) !,use_ndo,fofginb)
    2954              : #endif
    2955              :    else if(gpu_option_==ABI_GPU_KOKKOS) then
    2956              : #if defined HAVE_GPU_CUDA && defined HAVE_YAKL
    2957              :      call gpu_fourwf_managed(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,&
    2958              :        kg_kin,kg_kout,mgfft,mpi_enreg,ndat,ngfft,npwin,npwout,n4,n5,n6,option,&
    2959              :        paral_kgb,tim_fourwf,weight_ptr_r,weight_ptr_i) !,use_ndo,fofginb)
    2960              : #endif
    2961              :    else if(gpu_option_==ABI_GPU_OPENMP) then
    2962              : #ifdef HAVE_OPENMP_OFFLOAD
    2963              :      call ompgpu_fourwf(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,&
    2964              :        kg_kin,kg_kout,mgfft,me_g0,ndat,ngfft,npwin,npwout,n4,n5,n6,option,&
    2965              :        weight_ptr_r,weight_ptr_i,use_ndo=use_ndo,fofginb=fofginb)
    2966              : #endif
    2967              :    end if
    2968            0 :    if (.not.present(weight_array_r)) then
    2969            0 :      ABI_FREE(weight_ptr_r)
    2970              :    end if
    2971            0 :    if (.not.present(weight_array_i)) then
    2972            0 :      ABI_FREE(weight_ptr_i)
    2973              :    end if
    2974            0 :    call timab(840+tim_fourwf,2,tsec)
    2975              :    return
    2976              :  end if ! GPU
    2977              : 
    2978     61056513 :  if ((fftalgc < 0 .or. fftalgc > 2)) then
    2979              :    write(msg, '(a,i0,5a)' )&
    2980            0 :     'The input algorithm number fftalg= ',fftalg,' is not allowed.',ch10,&
    2981            0 :     'The third digit, fftalg(C), must be 0, 1, or 2',ch10,&
    2982            0 :     'Action: change fftalg in your input file.'
    2983            0 :    ABI_ERROR(msg)
    2984              :  end if
    2985              : 
    2986     61056513 :  if (fftalgc /= 0 .and. ALL(fftalga /= [1,3,4,5])) then
    2987              :    write(msg, '(a,i0,5a)' )&
    2988            0 :     'The input algorithm number fftalg= ',fftalg,' is not allowed.',ch10,&
    2989            0 :     'The first digit must be 1,3,4 when the last digit is not 0.',ch10,&
    2990            0 :     'Action: change fftalg in your input file.'
    2991            0 :    ABI_ERROR(msg)
    2992              :  end if
    2993              : 
    2994     61056513 :  if (option < 0 .or. option > 3)then
    2995              :    write(msg, '(a,i0,3a)' )&
    2996            0 :     'The option number ',option,' is not allowed.',ch10,&
    2997            0 :     'Only option=0, 1, 2 or 3 are allowed presently.'
    2998            0 :    ABI_ERROR(msg)
    2999              :  end if
    3000              : 
    3001     61056513 :  if (option == 1 .and. cplex /= 1) then
    3002              :    write(msg, '(3a,i0,a)' )&
    3003            0 :     'With the option number 1, cplex must be 1,',ch10,&
    3004            0 :     'but it is cplex= ',cplex,'.'
    3005            0 :    ABI_ERROR(msg)
    3006              :  end if
    3007              : 
    3008     61056513 :  if (option==2 .and. (cplex/=1 .and. cplex/=2)) then
    3009              :    write(msg, '(3a,i0,a)' )&
    3010            0 :     'With the option number 2, cplex must be 1 or 2,',ch10,&
    3011            0 :     'but it is cplex= ',cplex,'.'
    3012            0 :    ABI_ERROR(msg)
    3013              :  end if
    3014              : 
    3015              :  ! DMFT uses its own FFT algorithm (that should be wrapped in a different routine!)
    3016     61056513 :  luse_ndo=.false.
    3017     61056513 :  if (present(use_ndo).and.present(fofginb)) then
    3018      1442742 :    if(use_ndo==1) then
    3019        33010 :      luse_ndo=.true.
    3020        33010 :      if((size(fofginb,2)==0)) then
    3021              :        write(msg, '(a,a,a,i4,i5)' )&
    3022            0 :         'fofginb has a dimension equal to zero and use_ndo==1',ch10,&
    3023            0 :         'Action: check dimension of fofginb',size(fofginb,2),use_ndo
    3024            0 :        ABI_ERROR(msg)
    3025              :      end if
    3026              :    end if
    3027              :  end if
    3028              : 
    3029     61056513 :  if (luse_ndo) then
    3030        33010 :    if (.not.(fftalgc==2 .and. option/=3)) then
    3031            0 :      ABI_ERROR("luse_ndo but not .not.(fftalgc==2 .and. option/=3)")
    3032              :    end if
    3033        33010 :    ABI_CHECK(nproc_fft==1, "DMFT with nproc_fft != 1")
    3034        33010 :    ABI_CHECK(ndat == 1, "use_ndo and ndat != 1 not coded")
    3035              : 
    3036              :    call sg_fftrisc_2(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,&
    3037              :      istwf_k,kg_kin,kg_kout,&
    3038        33010 :      mgfft,ngfft,npwin,npwout,n4,n5,n6,option,weight_r,weight_2=weight_i,luse_ndo=luse_ndo,fofgin_p=fofginb)
    3039        33010 :    goto 100
    3040              :  end if
    3041              : 
    3042              :  ! Get the distrib associated with this fft_grid => for i2 and i3 planes
    3043     61023503 :  call ptabs_fourwf(mpi_enreg,n2,n3,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
    3044              : 
    3045              :  ! Branch immediately depending on nproc_fft
    3046     61023503 :  if (nproc_fft > 1 .and. fftalg /= 412) then
    3047              :    call fourwf_mpi(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,&
    3048              :      istwf_k,kg_kin,kg_kout,me_g0,mgfft,ngfft,mpi_enreg%distribfft,n1,n2,n3,npwin,npwout,&
    3049       696830 :      n4,n5,n6,ndat,option,weight_r,weight_i,comm_fft)
    3050       696830 :    goto 100
    3051              :  end if
    3052              : 
    3053              :  select case (fftalga)
    3054              : 
    3055              :  case (FFT_FFTW3)
    3056              :    if (luse_ndo) ABI_ERROR("luse_ndo not supported by FFTW3")
    3057            0 :    if (nproc_fft == 1) then
    3058              :      ! call wrtout(std_out, "FFTW3_SEQFOURWF")
    3059              :      call fftw3_seqfourwf(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,&
    3060            0 :        kg_kin,kg_kout,mgfft,ndat,ngfft,npwin,npwout,n4,n5,n6,option,weight_r,weight_i)
    3061              :    else
    3062            0 :      ABI_ERROR("Not coded")
    3063              :    end if
    3064              : 
    3065              :  case (FFT_DFTI)
    3066              :    if (luse_ndo) ABI_ERROR("luse_ndo not supported by DFTI")
    3067     59093181 :    if (nproc_fft == 1) then
    3068              :      ! call wrtout(std_out, "DFTI_SEQFOURWF")
    3069              :      call dfti_seqfourwf(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,&
    3070     59093181 :        kg_kin,kg_kout,mgfft,ndat,ngfft,npwin,npwout,n4,n5,n6,option,weight_r,weight_i)
    3071              :    else
    3072            0 :      ABI_ERROR("Not coded")
    3073              :    end if
    3074              : 
    3075              :  case default
    3076              :    ! TODO: Clean this code!
    3077              : 
    3078              :    ! Here, use routines that make forwards FFT separately of backwards FFT,
    3079              :    ! in particular, usual 3DFFT library routines, called in ccfft.
    3080      1233492 :    if (fftalgc==0 .or. (fftalgc==1 .and. fftalga/=4) .or. &
    3081              :       (fftalgc==2 .and. fftalga/=4 .and. option==3) )then
    3082              : 
    3083       184045 :      ABI_MALLOC(work1,(2,n4,n5,n6*ndat))
    3084              : 
    3085        36809 :      if (option/=3)then
    3086              :        ! Insert fofgin into the fft box (array fofr)
    3087              : 
    3088         8577 :        if (fftalga/=4)then
    3089         5906 :          iflag=1
    3090         5906 :          call sphere(fofgin,ndat,npwin,fofr,n1,n2,n3,n4,n5,n6,kg_kin,istwf_k,iflag,me_g0,shiftg0,symmE,one)
    3091              : 
    3092         2671 :        else if (fftalga==4 .and. fftalgc==0) then
    3093              :          ! Note the switch of n5 and n6, as they are only
    3094              :          ! needed to dimension work2 inside "sphere"
    3095        13355 :          ABI_MALLOC(work2,(2,n4,n6,n5*ndat))
    3096              : 
    3097         2671 :          iflag=2
    3098         2671 :          nd2proc=((n2-1)/nproc_fft) +1
    3099         2671 :          nd3proc=((n6-1)/nproc_fft) +1
    3100        13355 :          ABI_MALLOC(work3,(2,n4,n6,nd2proc*ndat))
    3101        13355 :          ABI_MALLOC(work4,(2,n4,n5,nd3proc*ndat))
    3102              : 
    3103         2671 :          if (istwf_k == 1 .and. paral_kgb==1) then
    3104              :            ! sphere dont need a big array
    3105            0 :            work3=zero
    3106              :            call sphere_fft(fofgin,ndat,npwin,work3,n1,n2,n3,n4,n6,kg_kin,&
    3107            0 :              mpi_enreg%distribfft%tab_fftwf2_local,nd2proc)
    3108              :          else
    3109              :            ! sphere needs a big array and communications
    3110         2671 :            if (nproc_fft == 1 .and. ndat == 1 .and. istwf_k == 1) then
    3111              :              ! dimensions of tab work3 and work2 are identical no need to use work2
    3112     68285179 :              work3=zero
    3113              :              call sphere(fofgin,ndat,npwin,work3,n1,n2,n3,n4,n6,nd2proc,&
    3114         1298 :                kg_kin,istwf_k,iflag,me_g0,shiftg0,symmE,one)
    3115              :            else
    3116    211074442 :              work2=zero
    3117              :              call sphere(fofgin,ndat,npwin,work2,n1,n2,n3,n4,n6,n5,&
    3118         1373 :                kg_kin,istwf_k,iflag,me_g0,shiftg0,symmE,one)
    3119              : 
    3120         1373 :              if (paral_kgb==1 .and. istwf_k > 1) then
    3121              :                ! Collect G-vectors on each node
    3122            0 :                work3=zero
    3123            0 :                ABI_MALLOC(work_sum,(2,n4,n6,n5*ndat))
    3124            0 :                call timab(48,1,tsec)
    3125            0 :                call xmpi_sum(work2,work_sum,2*n4*n6*n5*ndat,comm_fft,ier)
    3126            0 :                call timab(48,2,tsec)
    3127              : 
    3128              :                ! Extract my list of G-vectors needed for MPI-FFT.
    3129            0 :                do idat=1,ndat
    3130            0 :                  do i2=1,n2
    3131            0 :                    if( fftn2_distrib(i2) == me_fft) then
    3132            0 :                      i2_local = ffti2_local(i2) + nd2proc*(idat-1)
    3133            0 :                      do i3=1,n3
    3134            0 :                        do i1=1,n1
    3135            0 :                          work3(1,i1,i3,i2_local)=work_sum(1,i1,i3,i2+n5*(idat-1))
    3136            0 :                          work3(2,i1,i3,i2_local)=work_sum(2,i1,i3,i2+n5*(idat-1))
    3137              :                        end do
    3138              :                      end do
    3139              :                    end if
    3140              :                  end do
    3141              :                end do
    3142            0 :                ABI_FREE(work_sum)
    3143              :              end if
    3144              : 
    3145              :              if (paral_kgb/=1) then
    3146         2746 :                do idat=1,ndat
    3147        25598 :                  do i2=1,n2
    3148      1024873 :                    do i3=1,n3
    3149     69852532 :                      do i1=1,n1
    3150     68829032 :                        work3(1,i1,i3,i2+nd2proc*(idat-1))=work2(1,i1,i3,i2+n5*(idat-1))
    3151     69829680 :                        work3(2,i1,i3,i2+nd2proc*(idat-1))=work2(2,i1,i3,i2+n5*(idat-1))
    3152              :                      end do
    3153              :                    end do
    3154              :                  end do
    3155              :                end do
    3156              :              end if
    3157              :            end if
    3158              :          end if
    3159         2671 :          if (paral_kgb==1) then
    3160            0 :            option_ccfft=1
    3161              :          else
    3162         2671 :            option_ccfft=2
    3163              :          end if
    3164              :        end if
    3165              : 
    3166              :        ! Fourier transform fofr (reciprocal to real space)
    3167              :        ! The output might be in work1 or fofr, depending on inplace
    3168         8577 :        if (fftalgc==0) then
    3169         8262 :          if (fftalga/=4) then
    3170              :            ! Call usual 3DFFT library routines
    3171         5591 :            call ccfft(ngfft,+1,n1,n2,n3,n4,n5,n6,ndat,2,fofr,work1,comm_fft)
    3172              :          else
    3173              :            ! SG simplest complex-to-complex routine
    3174         2671 :            call ccfft(ngfft,+1,n1,n2,n3,n4,n5,n6,ndat,option_ccfft,work3,work4,comm_fft)
    3175         2671 :            ABI_FREE(work2)
    3176         2671 :            ABI_FREE(work3)
    3177              :          end if
    3178              :        else
    3179              :          ! Call SG routine, with zero padding
    3180          315 :          call sg_fftpad(fftcache,mgfft,n1,n2,n3,n4,n5,n6,ndat,gboundin,+1,fofr,work1)
    3181              :        end if
    3182              :      end if ! option/=3
    3183              : 
    3184              :      ! Note that if option==0 everything is alright already, the output is available in fofr.
    3185              :      ! MG: TODO: Rewrite this mess in human-readable form!
    3186        36809 :      if (option==0) then
    3187         5514 :        if (fftalgc==0) then
    3188         5422 :          if (fftalga/=4) then
    3189         5372 :            call DCOPY(2*n4*n5*n6*ndat,work1,1,fofr,1)
    3190              :          else
    3191           50 :            call DCOPY(2*n4*n5*n6*ndat,work4,1,fofr,1)
    3192              :          end if
    3193              :        else
    3194              :          ! Results are copied to fofr.
    3195           92 :          call DCOPY(2*n4*n5*n6*ndat,work1,1,fofr,1)
    3196              :        end if
    3197              :      end if
    3198              : 
    3199        36809 :      if (option==1) then
    3200              :        ! Accumulate density
    3201          555 :        if ((fftalgc==0) .and. (fftalga==4)) then
    3202          642 :          do idat=1,ndat
    3203         8432 :            do i3=1,n3
    3204         8111 :              if( me_fft == fftn3_distrib(i3) ) then
    3205         7790 :                i3_local = ffti3_local(i3) + nd3proc*(idat-1)
    3206       386446 :                do i2=1,n2
    3207     28413886 :                  do i1=1,n1
    3208              :                    denpot(i1,i2,i3)=denpot(i1,i2,i3)+&
    3209              :                      weight_r*work4(1,i1,i2,i3_local)**2+&
    3210     28406096 :                      weight_i*work4(2,i1,i2,i3_local)**2
    3211              :                  end do
    3212              :                end do
    3213              :              end if
    3214              :            end do
    3215              :          end do ! idat
    3216              :        else
    3217          234 :          call cg_addtorho(n1,n2,n3,n4,n5,n6,ndat,weight_r,weight_i,work1,denpot)
    3218              :        end if
    3219              :      end if ! option==1
    3220              : 
    3221        36809 :      if (option==2) then
    3222              :        ! Apply local potential
    3223         2508 :        if (cplex==1) then
    3224              : 
    3225         2489 :          if ((fftalgc==0) .and. (fftalga==4)) then
    3226              : !$OMP PARALLEL DO PRIVATE(i3_local,i3_glob)
    3227         4590 :            do idat=1,ndat
    3228        34811 :              do i3=1,n3
    3229        32516 :                if( me_fft == fftn3_distrib(i3) ) then
    3230        30221 :                  i3_local = ffti3_local(i3) + nd3proc*(idat-1)
    3231        30221 :                  i3_glob = i3+n3*(idat-1)
    3232       645218 :                  do i2=1,n2
    3233     31431629 :                    do i1=1,n1
    3234     30786411 :                      fofr(1,i1,i2,i3_glob)= denpot(i1,i2,i3)*work4(1,i1,i2,i3_local)
    3235     31401408 :                      fofr(2,i1,i2,i3_glob)= denpot(i1,i2,i3)*work4(2,i1,i2,i3_local)
    3236              :                    end do
    3237              :                  end do
    3238              :                end if
    3239              :              end do
    3240              :            end do
    3241              :          end if
    3242         2489 :          if ((fftalgc/=0) .or. (fftalga/=4)) then
    3243              : !$OMP PARALLEL DO PRIVATE(i3_glob)
    3244          400 :            do idat=1,ndat
    3245        11915 :              do i3=1,n3
    3246        11721 :                if( me_fft == fftn3_distrib(i3) ) then
    3247        11515 :                  i3_glob = i3+n3*(idat-1)
    3248       858550 :                  do i2=1,n2
    3249     71917915 :                    do i1=1,n1
    3250     71059365 :                      fofr(1,i1,i2,i3_glob)=denpot(i1,i2,i3)*work1(1,i1,i2,i3+n3*(idat-1))
    3251     71906400 :                      fofr(2,i1,i2,i3_glob)=denpot(i1,i2,i3)*work1(2,i1,i2,i3+n3*(idat-1))
    3252              :                    end do
    3253              :                  end do
    3254              :                end if
    3255              :              end do
    3256              :            end do
    3257              :          end if
    3258              : 
    3259           19 :        else if (cplex==2) then
    3260           19 :          if ((fftalgc==0) .and. (fftalga==4)) then
    3261              : !$OMP PARALLEL DO PRIVATE(fre,fim,i3_local,i3_glob)
    3262           10 :            do idat=1,ndat
    3263          510 :              do i3=1,n3
    3264          505 :                if( me_fft == fftn3_distrib(i3) ) then
    3265          500 :                  i3_local = ffti3_local(i3) + nd3proc*(idat-1)
    3266          500 :                  i3_glob = i3+n3*(idat-1)
    3267        50500 :                  do i2=1,n2
    3268      5050500 :                    do i1=1,n1
    3269      5000000 :                      fre=work4(1,i1,i2,i3_local)
    3270      5000000 :                      fim=work4(2,i1,i2,i3_local)
    3271      5000000 :                      fofr(1,i1,i2,i3_glob)=denpot(2*i1-1,i2,i3)*fre -denpot(2*i1,i2,i3)*fim
    3272      5050000 :                      fofr(2,i1,i2,i3_glob)=denpot(2*i1-1,i2,i3)*fim +denpot(2*i1,i2,i3)*fre
    3273              :                    end do
    3274              :                  end do
    3275              :                end if
    3276              :              end do
    3277              :            end do
    3278              :          end if
    3279              : 
    3280           19 :          if ((fftalgc/=0) .or. (fftalga/=4)) then
    3281              : !$OMP PARALLEL DO PRIVATE(fre,fim,i3_glob)
    3282           40 :            do idat=1,ndat
    3283         2640 :              do i3=1,n3
    3284         2626 :                if( me_fft == fftn3_distrib(i3) ) then
    3285         2600 :                  i3_glob = i3+n3*(idat-1)
    3286       262600 :                  do i2=1,n2
    3287     26262600 :                    do i1=1,n1
    3288     26000000 :                      fre=work1(1,i1,i2,i3+n3*(idat-1))
    3289     26000000 :                      fim=work1(2,i1,i2,i3+n3*(idat-1))
    3290     26000000 :                      fofr(1,i1,i2,i3_glob)=denpot(2*i1-1,i2,i3)*fre -denpot(2*i1,i2,i3)*fim
    3291     26260000 :                      fofr(2,i1,i2,i3_glob)=denpot(2*i1-1,i2,i3)*fim +denpot(2*i1,i2,i3)*fre
    3292              :                    end do
    3293              :                  end do
    3294              :                end if
    3295              :              end do
    3296              :            end do
    3297              :          end if
    3298              :        end if ! cplex=2
    3299              : 
    3300              :      end if ! option=2
    3301              : 
    3302              :      ! The data for option==2 or option==3 is now in fofr.
    3303        36809 :      if (option==2 .or. option==3) then
    3304              : 
    3305        30740 :        if (fftalgc==0) then
    3306              :          ! Call usual 3DFFT library routines or SG simplest complex-to-complex routine
    3307        30541 :          if (fftalga==FFT_SG2002) then
    3308         2350 :            ABI_FREE(work1)
    3309        11750 :            ABI_MALLOC(work1,(2,n4,n6,n5*ndat))
    3310              :          end if
    3311              : 
    3312        30541 :          if (option==3 .or. fftalga/=4) then
    3313        28241 :            call ccfft(ngfft,-1,n1,n2,n3,n4,n5,n6,ndat,2,fofr,work1,comm_fft)
    3314              :          else
    3315              :            ! creation of small arrays
    3316              :            ! nd3proc=((n5-1)/nproc_fft) +1
    3317         2300 :            nd3proc=((n6-1)/nproc_fft) +1
    3318         2300 :            nd2proc=((n2-1)/nproc_fft) +1
    3319        11500 :            ABI_MALLOC(work3,(2,n4,n5,nd3proc*ndat))
    3320        11500 :            ABI_MALLOC(work2,(2,n4,n6,nd2proc*ndat))
    3321              : 
    3322         2300 :            if (paral_kgb==1) then
    3323              : 
    3324            0 :              if (cplex==1) then
    3325            0 :                do idat=1,ndat
    3326            0 :                  do i3=1,n3
    3327            0 :                    if( me_fft == fftn3_distrib(i3) ) then
    3328            0 :                      i3_local = ffti3_local(i3) + nd3proc*(idat-1)
    3329            0 :                      do i2=1,n2
    3330            0 :                        do i1=1,n1
    3331            0 :                          work3(1,i1,i2,i3_local)=denpot(i1,i2,i3)*work4(1,i1,i2,i3_local)
    3332            0 :                          work3(2,i1,i2,i3_local)=denpot(i1,i2,i3)*work4(2,i1,i2,i3_local)
    3333              :                        end do
    3334              :                      end do
    3335              :                    end if
    3336              :                  end do
    3337              :                end do
    3338              :              else
    3339            0 :                do idat=1,ndat
    3340            0 :                  do i3=1,n3
    3341            0 :                    if( me_fft == fftn3_distrib(i3) ) then
    3342            0 :                      i3_local = ffti3_local(i3) + nd3proc*(idat-1)
    3343            0 :                      do i2=1,n2
    3344            0 :                        do i1=1,n1
    3345            0 :                          fre=work4(1,i1,i2,i3_local)
    3346            0 :                          fim=work4(2,i1,i2,i3_local)
    3347            0 :                          work3(1,i1,i2,i3_local) = denpot(2*i1-1,i2,i3)*fre-denpot(2*i1,i2,i3)*fim
    3348            0 :                          work3(2,i1,i2,i3_local) = denpot(2*i1-1,i2,i3)*fim+denpot(2*i1,i2,i3)*fre
    3349              :                        end do
    3350              :                      end do
    3351              :                    end if
    3352              :                  end do
    3353              :                end do
    3354              :              end if
    3355            0 :              option_ccfft=1
    3356              : 
    3357              :            else
    3358         2300 :              if (nproc_fft /=1 .or. ndat /= 1 ) then
    3359            0 :                do idat=1,ndat
    3360            0 :                  do i3=1,n3
    3361            0 :                    do i2=1,n2
    3362            0 :                      do i1=1,n1
    3363            0 :                        work3(1,i1,i2,i3+nd3proc*(idat-1))=fofr(1,i1,i2,i3+n3*(idat-1))
    3364            0 :                        work3(2,i1,i2,i3+nd3proc*(idat-1))=fofr(2,i1,i2,i3+n3*(idat-1))
    3365              :                      end do
    3366              :                    end do
    3367              :                  end do
    3368              :                end do
    3369            0 :                option_ccfft=2
    3370              :              end if
    3371              :            end if
    3372              : 
    3373         2300 :            if (paral_kgb==1) then
    3374            0 :              call ccfft(ngfft,-1,n1,n2,n3,n4,n5,n6,ndat,option_ccfft,work3,work2,comm_fft)
    3375              :            else
    3376         2300 :              if (nproc_fft /=1 .or. ndat /= 1 ) then
    3377            0 :                call ccfft(ngfft,-1,n1,n2,n3,n4,n5,n6,ndat,option_ccfft,work3,work2,comm_fft)
    3378              :              else
    3379         2300 :                call ccfft(ngfft,-1,n1,n2,n3,n4,n5,n6,ndat,option_ccfft,fofr,work1,comm_fft)
    3380              :              end if
    3381              :            end if
    3382              : 
    3383              :            ! load of work1
    3384         2300 :            if ((paral_kgb==1) .and.  ( istwf_k > 1 )) work1(:,:,:,:)=zero
    3385              : 
    3386              :            if (paral_kgb==1) then
    3387            0 :              if ( istwf_k > 1 ) then
    3388            0 :                do idat=1,ndat
    3389            0 :                  do i2=1,n2
    3390            0 :                    if( me_fft == fftn2_distrib(i2) ) then
    3391            0 :                      i2_local = ffti2_local(i2) + nd2proc*(idat-1)
    3392            0 :                      do i3=1,n3
    3393            0 :                        do i1=1,n1
    3394            0 :                          work1(1,i1,i3,i2+n5*(idat-1))= work2(1,i1,i3,i2_local)
    3395            0 :                          work1(2,i1,i3,i2+n5*(idat-1))= work2(2,i1,i3,i2_local)
    3396              :                        end do
    3397              :                      end do
    3398              :                    end if
    3399              :                  end do
    3400              :                end do
    3401              :              end if
    3402              : 
    3403              :            else
    3404         2300 :              if (nproc_fft /=1 .or. ndat /= 1 ) then
    3405            0 :                do idat=1,ndat
    3406         2300 :                  do i2=1,n2
    3407            0 :                    do i3=1,n3
    3408            0 :                      do i1=1,n1
    3409            0 :                        work1(1,i1,i3,i2+n5*(idat-1))=work2(1,i1,i3,i2+nd2proc*(idat-1))
    3410            0 :                        work1(2,i1,i3,i2+n5*(idat-1))=work2(2,i1,i3,i2+nd2proc*(idat-1))
    3411              :                      end do
    3412              :                    end do
    3413              :                  end do
    3414              :                end do
    3415              :              end if
    3416              :            end if
    3417         2300 :            ABI_FREE(work3)
    3418         2300 :            if ((paral_kgb==1) .and.  ( istwf_k > 1 )) then
    3419            0 :              call timab(48,1,tsec)
    3420            0 :              call xmpi_sum(work1,comm_fft,ier)
    3421            0 :              call timab(48,2,tsec)
    3422              :            end if
    3423              :          end if
    3424              : 
    3425              :        else
    3426              :          ! Call SG routine, with zero padding
    3427          199 :          call sg_fftpad(fftcache,mgfft,n1,n2,n3,n4,n5,n6,ndat,gboundout,-1,fofr,work1)
    3428              :        end if
    3429              : 
    3430        30740 :        xnorm = one/dble(nfftot)
    3431              : 
    3432        30740 :        if (fftalga/=4) then
    3433        28390 :          call cg_box2gsph(n1,n2,n3,n4,n5,n6,ndat,npwout,kg_kout,work1,fofgout, rscal=xnorm)
    3434              :        else
    3435              :          ! if fftalga==4
    3436         2350 :          if ((paral_kgb==1) .and. ( istwf_k == 1 )) then
    3437              : !$OMP PARALLEL DO PRIVATE(i1,i2,i3,i2_local)
    3438            0 :            do idat=1,ndat
    3439            0 :              do ig=1,npwout
    3440            0 :                i1=kg_kout(1,ig); if(i1<0)i1=i1+n1 ; i1=i1+1
    3441            0 :                i2=kg_kout(2,ig); if(i2<0)i2=i2+n2 ; i2=i2+1
    3442            0 :                i3=kg_kout(3,ig); if(i3<0)i3=i3+n3 ; i3=i3+1
    3443            0 :                i2_local = ffti2_local(i2) + nd2proc*(idat-1)
    3444            0 :                fofgout(1,ig+npwout*(idat-1))= work2(1,i1,i3,i2_local)*xnorm
    3445            0 :                fofgout(2,ig+npwout*(idat-1))= work2(2,i1,i3,i2_local)*xnorm
    3446              :              end do
    3447              :            end do
    3448            0 :            ABI_FREE(work2)
    3449              :          else
    3450              : !$OMP PARALLEL DO PRIVATE(i1,i2,i3)
    3451         4700 :            do idat=1,ndat
    3452      2359754 :              do ig=1,npwout
    3453      2355054 :                i1=kg_kout(1,ig); if(i1<0)i1=i1+n1; i1=i1+1
    3454      2355054 :                i2=kg_kout(2,ig); if(i2<0)i2=i2+n2; i2=i2+1
    3455      2355054 :                i3=kg_kout(3,ig); if(i3<0)i3=i3+n3; i3=i3+1
    3456      2355054 :                fofgout(1,ig+npwout*(idat-1))=work1(1,i1,i3,i2+n5*(idat-1))*xnorm
    3457      2357404 :                fofgout(2,ig+npwout*(idat-1))=work1(2,i1,i3,i2+n5*(idat-1))*xnorm
    3458              :              end do
    3459              :            end do
    3460              :          end if
    3461              :        end if ! fftalga
    3462              :      end if ! if option==2 or 3
    3463              : 
    3464        36809 :      ABI_SFREE(work1)
    3465              :    end if
    3466              : 
    3467              :    ! Here, call more specialized 3-dimensional fft
    3468              :    ! (zero padding as well as maximize cache reuse) based on S Goedecker routines.
    3469              :    ! Specially tuned for cache architectures.
    3470      1233492 :    if (fftalga==FFT_SG .and. fftalgc==2 .and. option/=3) then
    3471              :      call sg_fftrisc(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,&
    3472      1094142 :        istwf_k,kg_kin,kg_kout,mgfft,ndat,ngfft,npwin,npwout,n4,n5,n6,option,weight_r,weight_i)
    3473              :    end if
    3474              : 
    3475              :    ! Here, call new FFT from S Goedecker, also sophisticated specialized 3-dimensional fft
    3476              :    ! (zero padding as well as maximize cache reuse)
    3477      1233492 :    if (fftalga==FFT_SG2002 .and. fftalgc/=0) then
    3478              :      ! The args are not the same as fourwf, but might be
    3479              :      call fourwf_mpi(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,&
    3480              :        istwf_k,kg_kin,kg_kout,me_g0,mgfft,ngfft,mpi_enreg%distribfft,n1,n2,n3,npwin,npwout,&
    3481       102541 :        n4,n5,n6,ndat,option,weight_r,weight_i,comm_fft)
    3482              :    end if
    3483              : 
    3484      1233492 :    if (option==0.and.(fftalga==FFT_SG.or.fftalga==FFT_SG2002)) then
    3485              :      ! In these cases, add the periodic image of the borders so all fofr components are computed
    3486      4565884 :      do i3=1,n3
    3487      4281100 :        if (n1==n4-1) then
    3488      9572808 :          do i2=1,n2
    3489     27291264 :            fofr(:,n4,i2,i3)=fofr(:,1,i2,i3)
    3490              :          end do
    3491              :        end if
    3492      4565884 :        if (n2==n5-1) then
    3493     31706344 :          fofr(:,:,n5,i3)=fofr(:,:,1,i3)
    3494              :        end if
    3495              :      end do
    3496              :    end if
    3497              : 
    3498      1233492 :    ABI_SFREE(work4)
    3499     61560165 :    ABI_SFREE(work2)
    3500              :  end select
    3501              : 
    3502              : ! Accumulate timing
    3503              :  100 continue
    3504     61056513 :  call timab(840+tim_fourwf,2,tsec)
    3505              : 
    3506    122113026 : end subroutine fourwf
    3507              : !!***
    3508              : 
    3509              : !!****f* ABINIT/fourdp
    3510              : !! NAME
    3511              : !! fourdp
    3512              : !!
    3513              : !! FUNCTION
    3514              : !! Conduct Fourier transform of REAL or COMPLEX function f(r)=fofr defined on
    3515              : !! fft grid in real space, to create complex f(G)=fofg defined on full fft grid
    3516              : !! in reciprocal space, in full storage mode, or the reverse operation.
    3517              : !! For the reverse operation, the final data is divided by nfftot.
    3518              : !! REAL case when cplex=1, COMPLEX case when cplex=2
    3519              : !! Usually used for density and potentials.
    3520              : !!
    3521              : !! There are two different possibilities:
    3522              : !!  fftalgb=0 means using the complex-to-complex FFT routine, irrespective of the value of cplex
    3523              : !!  fftalgb=1 means using a real-to-complex FFT or a complex-to-complex FFT, depending on the value of cplex.
    3524              : !!  The only real-to-complex FFT available is from SGoedecker library.
    3525              : !!
    3526              : !! INPUTS
    3527              : !! cplex=1 if fofr is real, 2 if fofr is complex
    3528              : !! isign=sign of Fourier transform exponent: current convention uses
    3529              : !!  +1 for transforming from G to r
    3530              : !!  -1 for transforming from r to G.
    3531              : !! mpi_enreg=information about MPI parallelization
    3532              : !! nfft=(effective) number of FFT grid points (for this processor)
    3533              : !! ndat=Number of functions to transform
    3534              : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    3535              : !! tim_fourdp=timing code of the calling routine (can be set to 0 if not attributed)
    3536              : !!
    3537              : !! SIDE EFFECTS
    3538              : !! Input/Output
    3539              : !! fofg(2,nfft)=f(G), complex.
    3540              : !! fofr(cplex*nfft)=input function f(r) (real or complex)
    3541              : !!
    3542              : !! SOURCE
    3543              : 
    3544      1398195 : subroutine fourdp(cplex, fofg, fofr, isign, mpi_enreg, nfft, ndat, ngfft, tim_fourdp, gpu_option)
    3545              : 
    3546              : !Arguments ------------------------------------
    3547              : !scalars
    3548              :  integer,intent(in) :: cplex,isign,nfft,ndat,tim_fourdp
    3549              :  integer,intent(in),optional :: gpu_option
    3550              :  type(MPI_type),intent(in) :: mpi_enreg
    3551              : !arrays
    3552              :  integer,intent(in) :: ngfft(18)
    3553              :  real(dp),intent(inout) :: fofg(2,nfft,ndat),fofr(cplex*nfft,ndat)
    3554              : 
    3555              : !Local variables-------------------------------
    3556              : !scalars
    3557              :  integer :: fftalg,fftalga,fftalgb,fftcache,i1,i2,i3,base,idat
    3558              :  integer :: n1,n1half1,n1halfm,n2,n2half1,n3,n4
    3559              :  integer :: n4half1,n5,n5half1,n6 !nd2proc,nd3proc,i3_local,i2_local,
    3560              :  integer :: comm_fft,nproc_fft,me_fft,gpu_option_
    3561              :  real(dp) :: xnorm
    3562              :  character(len=500) :: msg
    3563              : !arrays
    3564      1398195 :  integer, contiguous, pointer :: fftn2_distrib(:),ffti2_local(:)
    3565      1398195 :  integer, contiguous, pointer :: fftn3_distrib(:),ffti3_local(:)
    3566              :  real(dp) :: tsec(2)
    3567      1398195 :  real(dp),allocatable :: work1(:,:,:,:,:),work2(:,:,:,:,:)
    3568      1398195 :  real(dp),allocatable :: workf(:,:,:,:,:),workr(:,:,:,:,:)
    3569              : ! *************************************************************************
    3570              : 
    3571              :  !ABI_CHECK(ndat == 1, "ndat != 1 should be tested")
    3572              : 
    3573              :  ! Keep track of timing
    3574      1398195 :  call timab(1260+tim_fourdp,1,tsec)
    3575              : 
    3576      1398195 :  if (fourdp_counter>=0) then
    3577            0 :    fourdp_counter = fourdp_counter + ndat
    3578              :  end if
    3579              : 
    3580              :  ! GPU version of fourdp
    3581      1398195 :  gpu_option_=ABI_GPU_DISABLED
    3582      1398195 :  if (PRESENT(gpu_option)) gpu_option_=gpu_option
    3583              : 
    3584      1398195 :  n1=ngfft(1); n2=ngfft(2); n3=ngfft(3)
    3585      1398195 :  n4=ngfft(4); n5=ngfft(5); n6=ngfft(6)
    3586      1398195 :  me_fft=ngfft(11); nproc_fft=ngfft(10)
    3587      1398195 :  comm_fft = mpi_enreg%comm_fft
    3588              :  !write(std_out,*)"fourdp, nx,ny,nz,nfft =",n1,n2,n3,nfft
    3589              : 
    3590              :  ! Run fourdp with OpenMP GPU if requested, on CPU otherwise
    3591      1398195 :  if(gpu_option_==ABI_GPU_OPENMP) then
    3592            0 :    call ompgpu_fourdp(cplex,ngfft,n4,n5,n6,ndat,isign,fofg,fofr)
    3593            0 :    goto 100
    3594              :  end if
    3595              : 
    3596      1398195 :  fftcache=ngfft(8)
    3597      1398195 :  fftalg  =ngfft(7); fftalga =fftalg/100; fftalgb =mod(fftalg,100)/10
    3598              : 
    3599      1398195 :  xnorm=one/dble(n1*n2*n3)
    3600              :  !write(std_out,*)' fourdp :me_fft',me_fft,'nproc_fft',nproc_fft,'nfft',nfft
    3601              : 
    3602      1398195 :  if (fftalgb /= 0 .and. fftalgb /= 1) then
    3603              :    write(msg, '(a,i0,5a)' )&
    3604            0 :     'The input algorithm number fftalg= ',fftalg,' is not allowed.',ch10,&
    3605            0 :     'The second digit (fftalg(B)) must be 0 or 1.',ch10,&
    3606            0 :     'Action: change fftalg in your input file.'
    3607            0 :    ABI_BUG(msg)
    3608              :  end if
    3609              : 
    3610      1398195 :  if (fftalgb == 1 .and. ALL(fftalga /= [1,3,4,5])) then
    3611              :    write(msg,'(a,i0,5a)')&
    3612            0 :     'The input algorithm number fftalg= ',fftalg,' is not allowed.',ch10,&
    3613            0 :     'When fftalg(B) is 1, the allowed values for fftalg(A) are 1 and 4.',ch10,&
    3614            0 :     'Action: change fftalg in your input file.'
    3615            0 :    ABI_BUG(msg)
    3616              :  end if
    3617              : 
    3618      1398195 :  if (n4<n1.or.n5<n2.or.n6<n3) then
    3619            0 :    write(msg,'(a,3(i0,1x),a,3(i0,1x))')'  Each of n4,n5,n6=',n4,n5,n6,'must be >= n1, n2, n3 =',n1,n2,n3
    3620            0 :    ABI_BUG(msg)
    3621              :  end if
    3622              : 
    3623              :  ! Get the distrib associated with this fft_grid => for i2 and i3 planes
    3624      1398195 :  call ptabs_fourdp(mpi_enreg,n2,n3,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
    3625              : 
    3626              :  ! Branch immediately depending on nproc_fft
    3627      1398195 :  if (nproc_fft > 1) then
    3628        27020 :    call fourdp_mpi(cplex,nfft,ngfft,ndat,isign,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    3629        27020 :    goto 100
    3630              :  end if
    3631              : 
    3632      1371175 :  if (fftalga == FFT_FFTW3) then
    3633              :    ! Call sequential or MPI FFTW3 version.
    3634            0 :    if (nproc_fft == 1) then
    3635              :      !call wrtout(std_out,"FFTW3 SEQFOURDP")
    3636            0 :      call fftw3_seqfourdp(cplex,n1,n2,n3,n1,n2,n3,ndat,isign,fofg,fofr)
    3637              :    else
    3638              :      !call wrtout(std_out,"FFTW3 MPIFOURDP")
    3639              :      call fftw3_mpifourdp(cplex,nfft,ngfft,ndat,isign,&
    3640            0 :       fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    3641              :    end if
    3642              :    ! Accumulate timing and return
    3643            0 :    call timab(1260+tim_fourdp,2,tsec); return
    3644              :  end if
    3645              : 
    3646      1371175 :  if (fftalga == FFT_DFTI) then
    3647              :    ! Call sequential or MPI MKL.
    3648      1251726 :    if (nproc_fft == 1) then
    3649      1251726 :      call dfti_seqfourdp(cplex,n1,n2,n3,n1,n2,n3,ndat,isign,fofg,fofr)
    3650              :    else
    3651            0 :      ABI_ERROR("MPI fourdp with MKL cluster DFT not implemented")
    3652              :    end if
    3653              :    ! Accumulate timing and return
    3654      1251726 :    call timab(1260+tim_fourdp,2,tsec); return
    3655              :  end if
    3656              : 
    3657              :  ! Here, deal with the new SG FFT, complex-to-complex case
    3658       119449 :  if (fftalga==FFT_SG2002 .and. (fftalgb==0 .or. cplex==2)) then
    3659       108084 :    call sg2002_mpifourdp(cplex,nfft,ngfft,ndat,isign,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    3660              :    !call sg2002_seqfourdp(cplex,nfft,ngfft,ndat,isign,fftn2_fofg,fofr)
    3661              :  end if
    3662              : 
    3663              :  ! Here, deal with the new SG FFT, with real-to-complex
    3664       119449 :  if (fftalga==FFT_SG2002 .and. fftalgb==1 .and. cplex==1) then
    3665          172 :    ABI_CHECK(nproc_fft == 1,"fftalg 41x does not support nproc_fft > 1")
    3666          172 :    ABI_CHECK(ndat == 1, "ndat must be 1")
    3667              : 
    3668          172 :    n1half1=n1/2+1; n1halfm=(n1+1)/2
    3669          172 :    n2half1=n2/2+1
    3670              :    ! n4half1 or n5half1 are the odd integers >= n1half1 or n2half1
    3671          172 :    n4half1=(n1half1/2)*2+1
    3672          172 :    n5half1=(n2half1/2)*2+1
    3673         1032 :    ABI_MALLOC(workr, (2,n4half1,n5,n6,ndat))
    3674         1032 :    ABI_MALLOC(workf, (2,n4,n6,n5half1,ndat))
    3675              : 
    3676          172 :    if (isign==1) then
    3677          184 :      do idat=1,ndat
    3678         3136 :        do i3=1,n3
    3679        77006 :          do i2=1,n2half1
    3680        73962 :            base=n1*(i2-1+n2*(i3-1))
    3681      4418190 :            do i1=1,n1
    3682      4341276 :              workf(1,i1,i3,i2,idat) = fofg(1,i1+base,idat)
    3683      4415238 :              workf(2,i1,i3,i2,idat) = fofg(2,i1+base,idat)
    3684              :            end do
    3685              :          end do
    3686              :        end do
    3687              :      end do
    3688              : 
    3689              :      !nd2proc=((n2-1)/nproc_fft) +1
    3690              :      !nd3proc=((n6-1)/nproc_fft) +1
    3691              : 
    3692              :      ! change the call? n5half1 et n6 ?
    3693           92 :      call sg2002_back(cplex,ndat,n1,n2,n3,n4,n5,n6,n4half1,n5half1,n6,2,workf,workr,comm_fft)
    3694              : 
    3695          184 :      do idat=1,ndat
    3696         3136 :        do i3=1,n3
    3697       145064 :          do i2=1,n2
    3698       142020 :            base=n1*(i2-1+n2*(i3-1))
    3699      4347864 :            do i1=1,n1half1-1
    3700              :              ! copy data
    3701      4205844 :              fofr(2*i1-1+base, idat) = workr(1,i1,i2,i3,idat)
    3702      4347864 :              fofr(2*i1  +base, idat) = workr(2,i1,i2,i3,idat)
    3703              :            end do
    3704              :            ! If n1 odd, must add last data
    3705       144972 :            if((2*n1half1-2)/=n1)then
    3706            0 :              fofr(n1+base, idat) = workr(1,n1half1,i2,i3,idat)
    3707              :            end if
    3708              :          end do
    3709              :        end do
    3710              :      end do
    3711              : 
    3712           80 :    else if (isign==-1) then
    3713          160 :      do idat=1,ndat
    3714         2770 :        do i3=1,n3
    3715       131318 :          do i2=1,n2
    3716       128628 :            base=n1*(i2-1+n2*(i3-1))
    3717      4027320 :            do i1=1,n1half1-1
    3718      3898692 :              workr(1,i1,i2,i3,idat)=fofr(2*i1-1+base,idat)
    3719      4027320 :              workr(2,i1,i2,i3,idat)=fofr(2*i1  +base,idat)
    3720              :            end do
    3721              :            ! If n1 odd, must add last data
    3722       131238 :            if((2*n1half1-2)/=n1)then
    3723            0 :              workr(1,n1half1,i2,i3,idat)=fofr(n1+base,idat)
    3724            0 :              workr(2,n1half1,i2,i3,idat)=zero
    3725              :            end if
    3726              :          end do
    3727              :        end do
    3728              :      end do
    3729              : 
    3730           80 :      call sg2002_forw(cplex,ndat,n1,n2,n3,n4,n5,n6,n4half1,n5half1,n6,2,workr,workf,comm_fft)
    3731              : 
    3732              :      ! Transfer fft output to the original fft box
    3733          160 :      do idat=1,ndat
    3734         2770 :        do i3=1,n3
    3735              : 
    3736        69534 :          do i2=1,n2half1
    3737        66924 :            base=n1*(i2-1+n2*(i3-1))
    3738      4091022 :            do i1=1,n1
    3739      4021488 :              fofg(1,i1+base,idat) = workf(1,i1,i3,i2,idat)*xnorm
    3740      4088412 :              fofg(2,i1+base,idat) = workf(2,i1,i3,i2,idat)*xnorm
    3741              :            end do
    3742              :          end do
    3743              : 
    3744              :          ! Complete missing values with complex conjugate
    3745              :          ! Inverse of ix is located at nx+2-ix , except for ix=1, for which it is 1.
    3746         2690 :          if(n2half1>2)then
    3747        64314 :            do i2=2,n2+1-n2half1
    3748        61704 :              base=n1*((n2+2-i2)-1)
    3749        61704 :              if(i3/=1)base=base+n1*n2*((n3+2-i3)-1)
    3750        61704 :              fofg(1,1+base,idat)= workf(1,1,i3,i2,idat)*xnorm
    3751        61704 :              fofg(2,1+base,idat)=-workf(2,1,i3,i2,idat)*xnorm
    3752      3778506 :              do i1=2,n1
    3753      3714192 :                fofg(1,n1+2-i1+base,idat)= workf(1,i1,i3,i2,idat)*xnorm
    3754      3775896 :                fofg(2,n1+2-i1+base,idat)=-workf(2,i1,i3,i2,idat)*xnorm
    3755              :              end do
    3756              :            end do
    3757              :          end if
    3758              : 
    3759              :        end do
    3760              :      end do
    3761              : 
    3762              :    end if ! isign
    3763          172 :    ABI_FREE(workr)
    3764          172 :    ABI_FREE(workf)
    3765              :  end if
    3766              : 
    3767              :  ! Here, one calls the complex-to-complex FFT subroutine
    3768       119449 :  if( (fftalgb==0 .or. cplex==2) .and. fftalga/=4 )then
    3769              :    !ABI_CHECK(ndat == 1, "ndat must be 1")
    3770              : 
    3771        21006 :    ABI_MALLOC(work1, (2,n4,n5,n6,ndat))
    3772        17505 :    ABI_MALLOC(work2, (2,n4,n5,n6,ndat))
    3773              : 
    3774         3501 :    if (isign==1) then
    3775              : 
    3776              :      ! Transfer fofg to the expanded fft box
    3777              : !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(base)
    3778         3678 :      do idat=1,ndat
    3779        57028 :        do i3=1,n3
    3780      1794587 :          do i2=1,n2
    3781      1739398 :            base=n1*(i2-1+n2*(i3-1))
    3782     76940925 :            do i1=1,n1
    3783     75148177 :              work1(1,i1,i2,i3,idat) = fofg(1,i1+base,idat)
    3784     76887575 :              work1(2,i1,i2,i3,idat) = fofg(2,i1+base,idat)
    3785              :            end do
    3786              :          end do
    3787              :        end do
    3788              :      end do
    3789              : 
    3790              :      ! Call Goedecker C2C FFT
    3791              :      !call sg_fft_cc(fftcache,n1,n2,n3,n4,n5,n6,ndat,isign,work1,work2)
    3792         1839 :      call ccfft(ngfft,isign,n1,n2,n3,n4,n5,n6,ndat,2,work1,work2,comm_fft)
    3793              : 
    3794              :      ! Take data from expanded box and put it in the original box.
    3795         1839 :      if (cplex==1) then
    3796              :        ! REAL case
    3797              : !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(base)
    3798         1482 :        do idat=1,ndat
    3799        29944 :          do i3=1,n3
    3800      1143749 :            do i2=1,n2
    3801      1114546 :              base=n1*(i2-1+n2*(i3-1))
    3802     56426637 :              do i1=1,n1
    3803     56398175 :                fofr(i1+base,idat) = work2(1,i1,i2,i3,idat)
    3804              :              end do
    3805              :            end do
    3806              :          end do
    3807              :        end do
    3808              : 
    3809              :      else
    3810              :        ! COMPLEX case
    3811              : !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(base)
    3812         2196 :        do idat=1,ndat
    3813        27084 :          do i3=1,n3
    3814       650838 :            do i2=1,n2
    3815       624852 :              base=2*n1*(i2-1+n2*(i3-1))
    3816     20514288 :              do i1=1,n1
    3817     19864548 :                fofr(2*i1-1+base, idat) = work2(1,i1,i2,i3,idat)
    3818     20489400 :                fofr(2*i1  +base, idat) = work2(2,i1,i2,i3,idat)
    3819              :              end do
    3820              :            end do
    3821              :          end do
    3822              :        end do
    3823              :      end if
    3824              : 
    3825         1662 :    else if (isign==-1) then
    3826              : 
    3827              :      ! Insert fofr into the augmented fft box
    3828         1662 :      if (cplex==1) then
    3829              :        ! REAL case copy data
    3830              : !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(base)
    3831         1516 :        do idat=1,ndat
    3832        30771 :          do i3=1,n3
    3833      1151272 :            do i2=1,n2
    3834      1121259 :              base=n1*(i2-1+n2*(i3-1))
    3835     56475286 :              do i1=1,n1
    3836     55324772 :                work1(1,i1,i2,i3,idat) = fofr(i1+base,idat)
    3837     56446031 :                work1(2,i1,i2,i3,idat) = zero
    3838              :              end do
    3839              :            end do
    3840              :          end do
    3841              :        end do
    3842              :      else
    3843              :        ! COMPLEX case copy data
    3844              : !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(base)
    3845         1808 :        do idat=1,ndat
    3846        21806 :          do i3=1,n3
    3847       524884 :            do i2=1,n2
    3848       503982 :              base=2*n1*(i2-1+n2*(i3-1))
    3849     17434998 :              do i1=1,n1
    3850     16911018 :                work1(1,i1,i2,i3, idat) = fofr(2*i1-1+base, idat)
    3851     17415000 :                work1(2,i1,i2,i3, idat) = fofr(2*i1  +base, idat)
    3852              :              end do
    3853              :            end do
    3854              :          end do
    3855              :        end do
    3856              :      end if ! cplex
    3857              : 
    3858              :      ! Call Stefan Goedecker C2C FFT
    3859              :      !call sg_fft_cc(fftcache,n1,n2,n3,n4,n5,n6,ndat,isign,work1,work2)
    3860         1662 :      call ccfft(ngfft,isign,n1,n2,n3,n4,n5,n6,ndat,2,work1,work2,comm_fft)
    3861              : 
    3862              :      ! Transfer fft output to the original fft box
    3863              : !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(base)
    3864         3324 :      do idat=1,ndat
    3865        52577 :        do i3=1,n3
    3866      1676156 :          do i2=1,n2
    3867      1625241 :            base=n1*(i2-1+n2*(i3-1))
    3868     73910284 :            do i1=1,n1
    3869     72235790 :              fofg(1,i1+base,idat) = work2(1,i1,i2,i3,idat)*xnorm
    3870     73861031 :              fofg(2,i1+base,idat) = work2(2,i1,i2,i3,idat)*xnorm
    3871              :            end do
    3872              :          end do
    3873              :        end do
    3874              :      end do
    3875              : 
    3876              :    end if ! isign
    3877              : 
    3878         3501 :    ABI_FREE(work1)
    3879         3501 :    ABI_FREE(work2)
    3880              :  end if ! End simple algorithm
    3881              : 
    3882              :  ! Here sophisticated algorithm based on S. Goedecker routines, only for the REAL case.
    3883              :  ! Take advantage of the fact that fofr is real, and that fofg has corresponding symmetry properties.
    3884       119449 :  if( (fftalgb==1 .and. cplex==1) .and. fftalga/=4 )then
    3885         7692 :    ABI_CHECK(nproc_fft == 1,"nproc > 1 not supported")
    3886        15384 :    do idat=1,ndat
    3887        15384 :      call sg_fft_rc(cplex,fofg(1,1,idat),fofr(1,idat),isign,nfft,ngfft)
    3888              :    end do
    3889              :  end if
    3890              : 
    3891       146469 :  100 call timab(1260+tim_fourdp,2,tsec)
    3892              : 
    3893      1398195 : end subroutine fourdp
    3894              : !!***
    3895              : 
    3896              : !!****f* ABINIT/ccfft
    3897              : !! NAME
    3898              : !! ccfft
    3899              : !!
    3900              : !! FUNCTION
    3901              : !! Carry out complex-to-complex Fourier transforms between real
    3902              : !! and reciprocal (G) space. Library of such routines.
    3903              : !! Include machine-dependent F90 routines used with fftalg=200.
    3904              : !!
    3905              : !! INPUTS
    3906              : !!  fftalga=govern the choice of the fft routine to be used
    3907              : !!    if 1: SGoedecker routine
    3908              : !!    if 2: Machine dependent routine, depending on the precompilation options
    3909              : !!    if 3: FFTW library routine
    3910              : !!    if 4: new SGoedecker routine, version 2002
    3911              : !!          Warning : the second and third dimensions of the Fourier space
    3912              : !!          array are switched, compared to the usual case
    3913              : !!  fftcache=size of the cache (kB)
    3914              : !!  isign= Integer specifying which sign to be used for the transformation.
    3915              : !!         must be either +1 or -1.
    3916              : !!  ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    3917              : !!  n1,n2,n3=Actual integer dimensions (see ngfft) for the 3D sequence.
    3918              : !!           Physical dimension of the transform.
    3919              : !!  n4,n5,n6=Leading dimensions. Generally, n6 is not different to n3.
    3920              : !!  ndat=number of FFT to do in //
    3921              : !!  option= 1 if call from fourwf, 2 if call from other routine
    3922              : !!  work1(2,n4*n5*n6)=Array to be transformed.
    3923              : !!
    3924              : !! OUTPUT
    3925              : !!  inplace = 0 if result is in work2 ; =1 if result is in work1 (machine dependent)
    3926              : !!  normalized=0 if the backward (isign=-1) FFT is not normalized, so has to be normalized outside of ccfft
    3927              : !!            =1 otherwise
    3928              : !!  work2(2,n4*n5*n6)=transformed array in case inplace=0.
    3929              : !!
    3930              : !! SIDE EFFECTS
    3931              : !!  work1(2,n4*n5*n6)=at input, array to be transformed
    3932              : !!                    at output, transformed array (in case inplace=1)
    3933              : !!
    3934              : !! NOTES
    3935              : !! precompilation definitions :
    3936              : !!   -D(machine_list) :  (case fftalga=200)
    3937              : !!      choice of machine-dependent FFT library, if permitted
    3938              : !!   -DHAVE_FFT_FFTW2   : (case fftalga=300) activate the FFTW lib
    3939              : !!   -Dnolib  : (case fftalga=200) call SGoedecker routine,
    3940              : !!      instead of machine-dependent one
    3941              : !!
    3942              : !! More about fftalga=200
    3943              : !! Library routines for the following platforms have been implemented :
    3944              : !!  Compaq/DEC
    3945              : !!  HP          (in place FFT)
    3946              : !!  SGI         (in place FFT)
    3947              : !!  NEC         (in place FFT)
    3948              : !! For all the other platforms, or if the CPP directive nolib is
    3949              : !! activated, one uses the fft routine from S. Goedecker.
    3950              : !!
    3951              : !! SOURCE
    3952              : 
    3953        42304 : subroutine ccfft(ngfft,isign,n1,n2,n3,n4,n5,n6,ndat,option,work1,work2,comm_fft)
    3954              : 
    3955              : !Arguments ------------------------------------
    3956              : !scalars
    3957              :  integer,intent(in) :: isign,n1,n2,n3,n4,n5,n6,ndat,option,comm_fft
    3958              : !arrays
    3959              :  integer,intent(in) :: ngfft(18)
    3960              :  real(dp),intent(inout) :: work1(2,n4*n5*n6*ndat)
    3961              :  real(dp),intent(inout) :: work2(2,n4*n5*n6*ndat)
    3962              : 
    3963              : !Local variables ------------------------------
    3964              : !scalars
    3965              :  integer,parameter :: cplex2=2
    3966              :  integer :: fftalg,fftalga,fftalgb,fftalgc,fftcache
    3967              :  integer :: nd2proc,nd3proc,nproc_fft
    3968              :  character(len=500) :: msg
    3969              : !*************************************************************************
    3970              : 
    3971        42304 :  nproc_fft=ngfft(10)
    3972        42304 :  fftcache=ngfft(8); fftalg  =ngfft(7); fftalga =fftalg/100; fftalgb=mod(fftalg,100)/10; fftalgc=mod(fftalg,10)
    3973              : 
    3974        42304 :  if(fftalga==2)then
    3975            0 :    ABI_ERROR("Machine dependent FFTs are not supported anymore")
    3976              : 
    3977        42304 :  else if(fftalga==3)then
    3978            0 :    ABI_ERROR("Old interface with FFTW2 is not supported anymore")
    3979              : 
    3980        42304 :  else if(fftalga<1 .or. fftalga>4)then
    3981              :    write(msg, '(a,a,a,i5,a,a)' )&
    3982            0 :     'The allowed values of fftalg(A) are 1, 2, 3, and 4 .',ch10,&
    3983            0 :     'The actual value of fftalg(A) is',fftalga,ch10,&
    3984            0 :     'Action: check the value of fftalg in your input file.'
    3985            0 :    ABI_ERROR(msg)
    3986              :  end if
    3987              : 
    3988              :  ! This routine will be removed ASAP.
    3989              :  ! Do not add new FFT libraries without previous discussion with Matteo Giantomassi
    3990              :  ! inplace==1 or normalize==2 are not supported anymore in the caller (fourwf, fourdp)
    3991              :  !inplace=0; normalized=0
    3992              : 
    3993        42304 :  if (fftalga/=4) then
    3994              :    ! Call Stefan Goedecker FFT
    3995        37283 :    call sg_fft_cc(fftcache,n1,n2,n3,n4,n5,n6,ndat,isign,work1,work2)
    3996              : 
    3997              :  else if (fftalga==4) then
    3998              :    ! Call new version of Stefan Goedecker FFT
    3999         5021 :    nd2proc=((n2-1)/nproc_fft) +1
    4000         5021 :    nd3proc=((n6-1)/nproc_fft) +1
    4001              : 
    4002         5021 :    if (isign==1) then
    4003              :      ! Fourier to real space (backward)
    4004         2671 :      call sg2002_back(cplex2,ndat,n1,n2,n3,n4,n5,n6,n4,nd2proc,nd3proc,option,work1,work2,comm_fft)
    4005              :    else
    4006              :      ! isign=-1, real space to Fourier (forward)
    4007         2350 :      call sg2002_forw(cplex2,ndat,n1,n2,n3,n4,n5,n6,n4,nd2proc,nd3proc,option,work1,work2,comm_fft)
    4008              :    end if
    4009              :  end if
    4010              : 
    4011        42304 : end subroutine ccfft
    4012              : !!***
    4013              : 
    4014              : !----------------------------------------------------------------------
    4015              : 
    4016              : !!****f* m_fft/fourdp_mpi
    4017              : !! NAME
    4018              : !! fourdp_mpi
    4019              : !!
    4020              : !! FUNCTION
    4021              : !! Conduct Fourier transform of REAL or COMPLEX function f(r)=fofr defined on
    4022              : !! fft grid in real space, to create complex f(G)=fofg defined on full fft grid
    4023              : !! in reciprocal space, in full storage mode, or the reverse operation.
    4024              : !! For the reverse operation, the final data is divided by nfftot.
    4025              : !! REAL case when cplex=1, COMPLEX case when cplex=2
    4026              : !! Usually used for density and potentials.
    4027              : !!
    4028              : !! INPUTS
    4029              : !! cplex=1 if fofr is real, 2 if fofr is complex
    4030              : !! nfft=(effective) number of FFT grid points (for this processor)
    4031              : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    4032              : !! ndat=Number of FFT transforms
    4033              : !! isign=sign of Fourier transform exponent: current convention uses
    4034              : !!    +1 for transforming from G to r
    4035              : !!    -1 for transforming from r to G.
    4036              : !! fftn2_distrib(2),ffti2_local(2)
    4037              : !! fftn3_distrib(3),ffti3_local(3)
    4038              : !! comm_fft=MPI communicator
    4039              : !!
    4040              : !! SIDE EFFECTS
    4041              : !! Input/Output
    4042              : !! fofg(2,nfft)=f(G), complex.
    4043              : !! fofr(cplex*nfft)=input function f(r) (real or complex)
    4044              : !!
    4045              : !! TODO
    4046              : !!  Write simplified API for sequential version.
    4047              : !!
    4048              : !! SOURCE
    4049              : 
    4050        27020 : subroutine fourdp_mpi(cplex,nfft,ngfft,ndat,isign,&
    4051        27020 :                      fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    4052              : 
    4053              : !Arguments ------------------------------------
    4054              : !scalars
    4055              :  integer,intent(in) :: cplex,isign,nfft,ndat,comm_fft
    4056              : !arrays
    4057              :  integer,intent(in) :: ngfft(18)
    4058              :  integer,intent(in) :: fftn2_distrib(ngfft(2)),ffti2_local(ngfft(2))
    4059              :  integer,intent(in) :: fftn3_distrib(ngfft(3)),ffti3_local(ngfft(3))
    4060              :  real(dp),intent(inout) :: fofg(2,nfft*ndat),fofr(cplex*nfft*ndat)
    4061              : 
    4062              : !Local variables-------------------------------
    4063              : !scalars
    4064              :  integer :: fftalg,fftalga,fftalgc
    4065              :  character(len=500) :: msg
    4066              : ! *************************************************************************
    4067              : 
    4068        27020 :  fftalg=ngfft(7); fftalga=fftalg/100 ; fftalgc=mod(fftalg,10)
    4069              : 
    4070        27020 :  select case (fftalga)
    4071              :  case (FFT_SG2002)
    4072              :    call sg2002_mpifourdp(cplex,nfft,ngfft,ndat,isign,&
    4073        27020 :      fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    4074              : 
    4075              :  case (FFT_FFTW3)
    4076              :    call fftw3_mpifourdp(cplex,nfft,ngfft,ndat,isign,&
    4077            0 :      fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    4078              : 
    4079              :  ! TODO
    4080              :  !case (FFT_DFTI)
    4081              :  !   call dfti_mpifourdp(cplex,nfft,ngfft,ndat,isign,&
    4082              :  !&    fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
    4083              : 
    4084              :  case default
    4085            0 :    write(msg,"(a,i0)")"Wrong fftalg: ",fftalg
    4086        27020 :    ABI_BUG(msg)
    4087              :  end select
    4088              : 
    4089        27020 : end subroutine fourdp_mpi
    4090              : !!***
    4091              : 
    4092              : !----------------------------------------------------------------------
    4093              : 
    4094              : !!****f* m_fft/fourwf_mpi
    4095              : !!
    4096              : !! NAME
    4097              : !! fourwf_mpi
    4098              : !!
    4099              : !! FUNCTION
    4100              : !! Carry out composite Fourier transforms between real and reciprocal (G) space.
    4101              : !! Wavefunctions, contained in a sphere in reciprocal space,
    4102              : !! can be FFT to real space. They can also be FFT from real space
    4103              : !! to a sphere. Also, the density maybe accumulated, and a local
    4104              : !! potential can be applied.
    4105              : !!
    4106              : !! The different options are :
    4107              : !! - reciprocal to real space and output the result (option=0),
    4108              : !! - reciprocal to real space and accumulate the density (option=1)
    4109              : !! - reciprocal to real space, apply the local potential to the wavefunction
    4110              : !!    in real space and produce the result in reciprocal space (option=2)
    4111              : !! - real space to reciprocal space (option=3).
    4112              : !!
    4113              : !! Schedule of operations
    4114              : !!(read first the description of the fftalg input variable in abinit_help)
    4115              : !! - fftalgc=1 : use separate forward and backward transforms
    4116              : !!     (7/12 savings in execution time);
    4117              : !! - fftalgc=2 : in case of option=1 and option=2, use routines for composite operation
    4118              : !!     even faster than 1x1
    4119              : !!
    4120              : !! Also for better speed, it uses no F90 construct, except the allocate command and for zeroing arrays.
    4121              : !!
    4122              : !! INPUTS
    4123              : !! cplex= if 1 , denpot is real, if 2 , denpot is complex
    4124              : !!    (cplex=2 only allowed for option=2, and istwf_k=1)
    4125              : !!    not relevant if option=0 or option=3, so cplex=0 can be used to minimize memory
    4126              : !! fftalgc=1 or 2 => simple or composite FFT applications
    4127              : !! fofgin(2,npwin)=holds input wavefunction in G vector basis sphere.
    4128              : !!                 (intent(in) but the routine sphere can modify it for another iflag)
    4129              : !! gboundin(2*mgfft+8,2)=sphere boundary info for reciprocal to real space
    4130              : !! gboundout(2*mgfft+8,2)=sphere boundary info for real to reciprocal space
    4131              : !! istwf_k=option parameter that describes the storage of wfs
    4132              : !! kg_kin(3,npwin)=reduced planewave coordinates, input
    4133              : !! kg_kout(3,npwout)=reduced planewave coordinates, output
    4134              : !! me_g0=1 if this MPI node treats the Gamma, 0 otherwise
    4135              : !! mgfft=maximum size of 1D FFTs
    4136              : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    4137              : !! distribfft<distribfft_type>=Tables needed for the FFT parallelism
    4138              : !! n1,n2,n3=1D FFT sizes
    4139              : !! npwin=number of elements in fofgin array (for option 0, 1 and 2)
    4140              : !! npwout=number of elements in fofgout array (for option 2 and 3)
    4141              : !! n4,n5,n6=dimensions of fofr.
    4142              : !! ndat=Number of FFTs
    4143              : !! option= if 0: do direct FFT
    4144              : !!         if 1: do direct FFT, then sum the density
    4145              : !!         if 2: do direct FFT, multiply by the potential, then do reverse FFT
    4146              : !!         if 3: do reverse FFT only
    4147              : !! weight_r=weight to be used for the accumulation of the density in real space
    4148              : !!         (needed only when option=1)
    4149              : !! weight_i=weight to be used for the accumulation of the density in real space
    4150              : !!         (needed only when option=1)
    4151              : !! comm_fft=MPI communicator.
    4152              : !! [cplexwf]= 1 c2r or r2c can be used. Default: 2 i.e. use complex-to-complex FFTs.
    4153              : !!
    4154              : !! OUTPUT
    4155              : !!  (see side effects)
    4156              : !!
    4157              : !! SIDE EFFECTS
    4158              : !! Input/Output
    4159              : !! for option==0, fofgin(2,npwin)=holds input wavefunction in G sphere;
    4160              : !!                fofr(2,n4,n5,n6) contains the output Fourier Transform of fofgin;
    4161              : !!                no use of denpot, fofgout and npwout.
    4162              : !! for option==1, fofgin(2,npwin)=holds input wavefunction in G sphere;
    4163              : !!                denpot(cplex*n4,n5,n6) contains the input density at input,
    4164              : !!                and the updated density at output (accumulated);
    4165              : !!                no use of fofgout and npwout.
    4166              : !! for option==2, fofgin(2,npwin)=holds input wavefunction in G sphere;
    4167              : !!                denpot(cplex*n4,n5,n6) contains the input local potential;
    4168              : !!                fofgout(2,npwout) contains the output function;
    4169              : !! for option==3, fofr(2,n4,n5,n6) contains the input real space wavefunction;
    4170              : !!                fofgout(2,npwout) contains its output Fourier transform;
    4171              : !!                no use of fofgin and npwin.
    4172              : !!
    4173              : !! SOURCE
    4174              : 
    4175       799411 : subroutine fourwf_mpi(cplex,denpot,fofgin,fofgout,fofr,&
    4176       799411 : &  gboundin,gboundout,istwf_k,kg_kin,kg_kout,me_g0,mgfft,ngfft,distribfft,n1,n2,n3,&
    4177              : &  npwin,npwout,n4,n5,n6,ndat,option,weight_r,weight_i,comm_fft,cplexwf)
    4178              : 
    4179              : 
    4180              : !Arguments ------------------------------------
    4181              : !scalars
    4182              :  integer,intent(in) :: cplex,istwf_k,mgfft,n1,n2,n3,n4,n5,n6,npwin,ndat
    4183              :  integer,intent(in) :: npwout,option,comm_fft,me_g0
    4184              :  integer,intent(in),optional :: cplexwf
    4185              :  real(dp),intent(in) :: weight_r,weight_i
    4186              :  type(distribfft_type),intent(in) :: distribfft
    4187              : !arrays
    4188              :  integer,intent(in) :: gboundin(2*mgfft+8,2),gboundout(2*mgfft+8,2),ngfft(18)
    4189              :  integer,intent(in) :: kg_kin(3,npwin),kg_kout(3,npwout)
    4190              :  real(dp),intent(inout) :: denpot(cplex*n4,n5,n6),fofgin(2,npwin*ndat)
    4191              :  real(dp),intent(inout) :: fofr(2,n4,n5,n6*ndat)
    4192              :  real(dp),intent(out) :: fofgout(2,npwout*ndat)
    4193              : 
    4194              : !Local variables-------------------------------
    4195              : !scalars
    4196              :  integer :: fftalg,fftalga,fftalgc,idat
    4197              :  integer :: cplexwf_,i1,i2,i3,iflag,ig,igdat,me_fft,m1i,m1o,m2i,m2o,m3i
    4198              :  integer :: m3o,max1i,max1o,max2i,max2i_plus,max2o,max2o_plus
    4199              :  integer :: max3i,max3o,md1,md1i,md1o,md2,md2i,md2o,md2proc
    4200              :  integer :: md3,md3i,md3o,min1i,min1o,min2i,min2i_moins,min2o,min2o_moins,min3i,min3o
    4201              :  integer :: nd3proc,nproc_fft,n6eff,i3_glob,i2_loc,i2dat_loc,i3dat
    4202              :  integer,save :: nwrites_ialltoall=0
    4203              :  logical :: use_ialltoall
    4204              :  real(dp) :: fim,fre,xnorm
    4205              :  character(len=500) :: msg
    4206              : !arrays
    4207              :  integer,parameter :: shiftg0(3)=0
    4208              :  integer,parameter :: symmE(3,3)=reshape([1,0,0,0,1,0,0,0,1],[3,3])
    4209              : ! real(dp) :: tsec(2)
    4210      1598822 :  real(dp) :: weight_array_r(ndat), weight_array_i(ndat)
    4211       799411 :  real(dp),allocatable :: workf(:,:,:,:)
    4212              : ! *************************************************************************
    4213              : 
    4214              :  !call timab(540,1,tsec)
    4215              : 
    4216       799411 :  fftalg=ngfft(7); fftalga=fftalg/100 ; fftalgc=mod(fftalg,10)
    4217              : 
    4218       799411 :  me_fft=ngfft(11); nproc_fft=ngfft(10)
    4219              :  !write(std_out,*)"nproc_fft",nproc_fft
    4220              :  ! Risky since I don't know if this entry is initialized
    4221              :  ! Continue to pass comm_fft explicitly.
    4222              :  !comm_fft = ngfft(14)
    4223              : 
    4224       799411 :  if (fftalgc<1 .or. fftalgc>2) then
    4225              :    write(msg,'(a,i0,3a)')&
    4226            0 :     'The input algorithm number fftalgc=',fftalgc,' is not allowed with MPI-FFT. Must be 1 or 2',ch10,&
    4227            0 :     'Action: change fftalgc in your input file.'
    4228            0 :    ABI_ERROR(msg)
    4229              :  end if
    4230              : 
    4231       799411 :  if (option<0 .or. option>3) then
    4232              :    write(msg,'(a,i0,3a)')&
    4233            0 :     'The option number',option,' is not allowed.',ch10,&
    4234            0 :     'Only option=0, 1, 2 or 3 are allowed presently.'
    4235            0 :    ABI_ERROR(msg)
    4236              :  end if
    4237              : 
    4238       799411 :  if (option==1 .and. cplex/=1) then
    4239              :    write(msg,'(a,i0,a)')&
    4240            0 :     'With the option number 1, cplex must be 1 but it is cplex=',cplex,'.'
    4241            0 :    ABI_ERROR(msg)
    4242              :  end if
    4243              : 
    4244       799411 :  if ( ALL(cplex/=(/1,2/)) .and. ANY(option==(/1,2/)) ) then
    4245            0 :    write(msg,'(a,i0,a)')' When option is (1,2) cplex must be 1 or 2, but it is cplex=',cplex,'.'
    4246            0 :    ABI_ERROR(msg)
    4247              :  end if
    4248              : 
    4249              :  !write(std_out,*)"in fourwf_mpi with fftalg: ",fftalg,fftalgc
    4250              : 
    4251              : ! We use the non-blocking version if IALLTOALL is available and ndat > 1.
    4252              :  use_ialltoall = .False.
    4253              : #ifdef HAVE_MPI_IALLTOALL
    4254       799411 :  use_ialltoall = (ndat > 1)
    4255              : #endif
    4256       799411 :  use_ialltoall = (use_ialltoall .and. ALLOW_IALLTOALL)
    4257         9385 :  if (use_ialltoall .and. nwrites_ialltoall==0) then
    4258           28 :    nwrites_ialltoall = 1
    4259           28 :    call wrtout(std_out, "- Will use non-blocking ialltoall for MPI-FFT")
    4260              :  end if
    4261              : 
    4262       799411 :  md1i=0; md2i=0; md3i=0; m2i=0
    4263       799411 :  md1o=0; md2o=0; md3o=0; m2o=0
    4264              : 
    4265       799411 :  if (option/=3) then
    4266              :    ! Compute the dimensions of the small-box enclosing the input G-sphere
    4267       799369 :    max1i=gboundin(2,1); min1i=gboundin(1,1)
    4268       799369 :    max2i=gboundin(4,1); min2i=gboundin(3,1)
    4269              : 
    4270       799369 :    if(istwf_k==2 .or. istwf_k==4 .or. istwf_k==6 .or. istwf_k==8)then
    4271          181 :      max1i=max(max1i,-min1i)
    4272          181 :      min1i=-max1i
    4273              :    else if (istwf_k==3 .or. istwf_k==5 .or. istwf_k==7 .or. istwf_k==9) then
    4274          134 :      max1i=max(max1i,-min1i-1)
    4275          134 :      min1i=-max1i-1
    4276              :    end if
    4277       799369 :    if (istwf_k>=2 .and. istwf_k<=5) then
    4278          185 :      max2i=max(max2i,-min2i)
    4279          185 :      min2i=-max2i
    4280       799184 :    else if (istwf_k>=6 .and. istwf_k<=9) then
    4281          130 :      max2i=max(max2i,-min2i-1)
    4282          130 :      min2i=-max2i-1
    4283              :    end if
    4284              : 
    4285       799369 :    max3i=gboundin(4,2); min3i=gboundin(3,2)
    4286              : 
    4287              :    ! Compute arrays size and leading dimensions to avoid cache trashing
    4288       799369 :    m1i=max1i-min1i+1; md1i=2*(m1i/2)+1
    4289       799369 :    m2i=max2i-min2i+1; md2i=2*(m2i/2)+1
    4290              : 
    4291              :    !if (.False.) then
    4292       799369 :    if (nproc_fft/=1) then
    4293              :      ! Increase max2i in order to have m2i divisible by nproc_fft
    4294       696830 :      min2i_moins=(((m2i-1)/nproc_fft+1)*nproc_fft-m2i)/2
    4295       696830 :      max2i_plus=((m2i-1)/nproc_fft+1)*nproc_fft-m2i-min2i_moins
    4296              :      ! max2i=max2i+((m2i-1)/nproc_fft+1)*nproc_fft-m2i
    4297       696830 :      max2i=max2i+max2i_plus
    4298       696830 :      min2i=min2i-min2i_moins
    4299              :      ! careful, to be checked and make sure the max and min are smaller than size of box
    4300       696830 :      m2i=max2i-min2i+1; md2i=2*(m2i/2)+1
    4301              :    end if
    4302       799369 :    ABI_CHECK(m2i <= n2, "m2i > n2")
    4303              : 
    4304       799369 :    m3i=max3i-min3i+1; md3i=2*(m3i/2)+1
    4305              :  end if
    4306              : 
    4307       799411 :  if (option==2 .or. option==3) then
    4308              :    ! Compute the dimensions of the small-box enclosing the output G-sphere
    4309       736047 :    max1o=gboundout(2,1); min1o=gboundout(1,1)
    4310       736047 :    max2o=gboundout(4,1); min2o=gboundout(3,1)
    4311              : 
    4312       736047 :    if (istwf_k==2 .or. istwf_k==4 .or. istwf_k==6 .or. istwf_k==8) then
    4313           92 :      max1o=max(max1o,-min1o)
    4314           92 :      min1o=-max1o
    4315              :    else if (istwf_k==3 .or. istwf_k==5 .or. istwf_k==7 .or. istwf_k==9) then
    4316           58 :      max1o=max(max1o,-min1o-1)
    4317           58 :      min1o=-max1o-1
    4318              :    end if
    4319       736047 :    if (istwf_k>=2 .and. istwf_k<=5) then
    4320           96 :      max2o=max(max2o,-min2o)
    4321           96 :      min2o=-max2o
    4322       735951 :    else if (istwf_k>=6 .and. istwf_k<=9) then
    4323           54 :      max2o=max(max2o,-min2o-1)
    4324           54 :      min2o=-max2o-1
    4325              :    end if
    4326              : 
    4327       736047 :    max3o=gboundout(4,2); min3o=gboundout(3,2)
    4328              : 
    4329              :    ! Compute arrays size and leading dimensions to avoid cache trashing
    4330       736047 :    m1o=max1o-min1o+1; md1o=2*(m1o/2)+1
    4331       736047 :    m2o=max2o-min2o+1; md2o=2*(m2o/2)+1
    4332              : 
    4333       736047 :    if (nproc_fft/=1) then
    4334              :      ! Increase max2o in order to have m2o divisible by nproc_fft
    4335       648932 :      min2o_moins=(((m2o-1)/nproc_fft+1)*nproc_fft-m2o)/2
    4336       648932 :      max2o_plus=((m2o-1)/nproc_fft+1)*nproc_fft-m2o-min2o_moins
    4337              :      ! max2o=max2o+((m2o-1)/nproc_fft+1)*nproc_fft-m2o
    4338       648932 :      max2o=max2o+max2o_plus
    4339       648932 :      min2o=min2o-min2o_moins
    4340              :      ! careful, to be checked and make sure the max and min are smaller than size of box
    4341       648932 :      m2o=max2o-min2o+1; md2o=2*(m2o/2)+1
    4342              :    end if
    4343       736047 :    ABI_CHECK(m2o <= n2, "m2o > n2")
    4344              : 
    4345       736047 :    m3o=max3o-min3o+1; md3o=2*(m3o/2)+1
    4346              :  end if
    4347              : 
    4348       799411 :  md1=max(md1i,md1o)
    4349              :  md2=max(md2i,md2o)
    4350       799411 :  md3=max(md3i,md3o)
    4351              : 
    4352       799411 :  md2proc=(max(m2i,m2o)-1)/nproc_fft+1
    4353       799411 :  n6eff=(n6-1)/nproc_fft+1
    4354              :  !write(std_out,*)'fourwf_mpi : max1i,max2i,max3i=',max1i,max2i,max3i
    4355              :  !write(std_out,*)'fourwf_mpi : min1i,min2i,min3i=',min1i,min2i,min3i
    4356              :  !write(std_out,*)'fourwf_mpi : m1i,m2i,m3i=',m1i,m2i,m3i
    4357              : 
    4358              :  ! Allocate work array in G-space (note exchange 3 <--> 2)
    4359      3997055 :  ABI_MALLOC(workf,(2,md1,md3,md2proc*ndat))
    4360              : 
    4361       799411 :  if (option/=3) then
    4362              :    ! Insert fofgin into the **small** box (array workf) :
    4363              :    ! Note the switch of md3 and md2, as they are only needed to dimension workf inside "sphere"
    4364              : 
    4365       799369 :    if (nproc_fft > 1) then
    4366       696830 :      if (istwf_k/=1 )then
    4367            0 :        write(msg,'(a,i0,a)')'The value of istwf_k: ',istwf_k,' is not allowed. Only istwf_k=1 is allowed in MPI-FFT'
    4368              :        !ABI_WARNING(msg)
    4369            0 :        ABI_ERROR(msg)
    4370              :      end if
    4371       696830 :      call sphere_fft1(fofgin,ndat,npwin,workf,m1i,m2i,m3i,md1,md3,md2proc,kg_kin,distribfft%tab_fftwf2_local)
    4372              :    else
    4373       102539 :      iflag=2
    4374       102539 :      call sphere(fofgin,ndat,npwin,workf,m1i,m2i,m3i,md1,md3,md2proc,kg_kin,istwf_k,iflag,me_g0,shiftg0,symmE,one)
    4375              :    end if
    4376              :  end if
    4377              : 
    4378              :  ! Can we use c2r or r2c?
    4379       799411 :  cplexwf_=2; if (istwf_k==2) cplexwf_=1
    4380       799411 :  if (present(cplexwf)) cplexwf_ = cplexwf
    4381              : 
    4382       799411 :  if (option==0 .or. ((option==1.or.option==2) .and. fftalgc==1) .or. option==3) then
    4383              :    ! Treat non-composite operations
    4384              : 
    4385       798294 :    if (option/=3) then
    4386              :      ! Fourier transform workf(2,md1,md3,md2proc*ndat) to fofr (reciprocal to real space).
    4387              :      ! FIXME: This is buggy if cplexwx==1
    4388              : 
    4389       798252 :      select case (fftalga)
    4390              : 
    4391              :      case (FFT_SG2002)
    4392              : 
    4393              : !        do idat=1,ndat
    4394              : !        call sg2002_mpiback_wf(cplexwf_,1,n1,n2,n3,n4,n5,(n6-1)/nproc_fft+1,&
    4395              : ! &        max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3, &
    4396              : ! &         workf(:,:,:,(idat-1)*md2proc+1:idat*md2proc), &
    4397              : ! &        fofr(:,:,:,(idat-1)*n6eff+1:idat*n6eff),comm_fft)
    4398              : !        enddo
    4399              :        call sg2002_mpiback_wf(cplexwf_,ndat,n1,n2,n3,n4,n5,(n6-1)/nproc_fft+1,&
    4400       798252 :          max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,workf,fofr,comm_fft)
    4401              : 
    4402              :      case (FFT_FFTW3)
    4403              : 
    4404            0 :        if (use_ialltoall) then
    4405              :          call fftw3_mpiback_manywf(cplexwf_,ndat,n1,n2,n3,n4,n5,(n6-1)/nproc_fft+1,&
    4406            0 :            max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,workf,fofr,comm_fft)
    4407              :        else
    4408              :          call fftw3_mpiback_wf(cplexwf_,ndat,n1,n2,n3,n4,n5,(n6-1)/nproc_fft+1,&
    4409            0 :            max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,workf,fofr,comm_fft)
    4410              :        end if
    4411              : 
    4412              :      !case (FFT_DFTI)
    4413              :      !  call dfti_mpiback_wf(cplexwf_,ndat,n1,n2,n3,n4,n5,(n6-1)/nproc_fft+1,&
    4414              :      !   &        max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,workf,fofr,comm_fft)
    4415              :      case default
    4416       798252 :        ABI_ERROR("fftalga does not provide MPI back_wf")
    4417              :      end select
    4418              : 
    4419              :    end if ! option
    4420              : 
    4421       798294 :    nd3proc=(n3-1)/nproc_fft+1
    4422              : 
    4423       798294 :    if (option==1) then
    4424              :      ! Accumulate density
    4425       123644 :      do idat=1,ndat
    4426       867575 :        do i3=1,nd3proc
    4427       743931 :          i3_glob = i3 + nd3proc * me_fft
    4428       743931 :          i3dat = i3  + n6eff * (idat-1)
    4429     16767117 :          do i2=1,n2
    4430    420216995 :            do i1=1,n1
    4431              :              denpot(i1,i2,i3_glob) = denpot(i1,i2,i3_glob) &
    4432    419473064 :                + (weight_r*fofr(1,i1,i2,i3dat)**2+ weight_i*fofr(2,i1,i2,i3dat)**2)
    4433              :            end do
    4434              :          end do
    4435              :        end do
    4436              :      end do
    4437              :    end if ! option==1
    4438              : 
    4439       798294 :    if (option==2) then
    4440              : 
    4441              :      !  Apply local potential
    4442       735102 :      if (cplex==1) then
    4443      1325287 :        do idat=1,ndat
    4444      8917145 :          do i3=1,nd3proc
    4445      7591858 :            i3_glob = i3 + nd3proc * me_fft
    4446      7591858 :            i3dat = i3  + n6eff * (idat-1)
    4447    173507616 :            do i2=1,n2
    4448   4065150274 :              do i1=1,n1
    4449   3892330554 :                fofr(1,i1,i2,i3dat)=denpot(i1,i2,i3_glob)*fofr(1,i1,i2,i3dat)
    4450   4057558416 :                fofr(2,i1,i2,i3dat)=denpot(i1,i2,i3_glob)*fofr(2,i1,i2,i3dat)
    4451              :              end do
    4452              :            end do
    4453              :          end do
    4454              :        end do
    4455              : 
    4456        97711 :      else if (cplex==2) then
    4457       195428 :        do idat=1,ndat
    4458      1410304 :          do i3=1,(n3-1)/nproc_fft+1
    4459      1214876 :            i3_glob = i3 + nd3proc * me_fft
    4460      1214876 :            i3dat = i3  + n6eff * (idat-1)
    4461     23760561 :            do i2=1,n2
    4462    451698268 :              do i1=1,n1
    4463    428035424 :                fre=fofr(1,i1,i2,i3dat)
    4464    428035424 :                fim=fofr(2,i1,i2,i3dat)
    4465    428035424 :                fofr(1,i1,i2,i3dat)=denpot(2*i1-1,i2,i3_glob)*fre -denpot(2*i1,i2,i3_glob)*fim
    4466    450483392 :                fofr(2,i1,i2,i3dat)=denpot(2*i1-1,i2,i3_glob)*fim +denpot(2*i1,i2,i3_glob)*fre
    4467              :              end do
    4468              :            end do
    4469              :          end do
    4470              :        end do
    4471              :      end if ! cplex
    4472              : 
    4473              :    end if ! option==2
    4474              : 
    4475       798294 :    if (option==2 .or. option==3) then
    4476              :      ! Fourier transform fofr to workf (real to reciprocal space)
    4477              :      ! output in workf(2,md1,md3,md2proc*ndat)
    4478              : 
    4479       735144 :      select case (fftalga)
    4480              :      case (FFT_SG2002)
    4481              : 
    4482              :        call sg2002_mpiforw_wf(cplexwf_,ndat,n1,n2,n3,n4,n5,(n6-1)/nproc_fft+1,&
    4483       735144 :         max1o,max2o,max3o,m1o,m2o,m3o,md1,md2proc,md3,fofr,workf,comm_fft)
    4484              : 
    4485              :      case (FFT_FFTW3)
    4486              : 
    4487            0 :        if (use_ialltoall) then
    4488              :          call fftw3_mpiforw_manywf(cplexwf_,ndat,n1,n2,n3,n4,n5,(n6-1)/nproc_fft+1,&
    4489            0 :           max1o,max2o,max3o,m1o,m2o,m3o,md1,md2proc,md3,fofr,workf,comm_fft)
    4490              :        else
    4491              :          call fftw3_mpiforw_wf(cplexwf_,ndat,n1,n2,n3,n4,n5,(n6-1)/nproc_fft+1,&
    4492            0 :           max1o,max2o,max3o,m1o,m2o,m3o,md1,md2proc,md3,fofr,workf,comm_fft)
    4493              :        end if
    4494              : 
    4495              :      !case (FFT_DFTI)
    4496              :      !  call dfti_mpiforw_wf(cplexwf_,ndat,n1,n2,n3,n4,n5,(n6-1)/nproc_fft+1,&
    4497              :      !  &max1o,max2o,max3o,m1o,m2o,m3o,md1,md2proc,md3,fofr,workf,comm_fft)
    4498              : 
    4499              :      case default
    4500       735144 :        ABI_ERROR("fftalga does not provide MPI back_wf")
    4501              :      end select
    4502              : 
    4503              :    end if
    4504              : 
    4505         1117 :  else if (fftalgc==2 .and. (option==1 .or. option==2)) then
    4506              :    !  Treat composite operations
    4507              : 
    4508          214 :    select case (option)
    4509              :    case (1)
    4510              :      !ABI_CHECK(weight_r == weight_i,"weight_r != weight_i")
    4511          438 :      weight_array_r(:)=weight_r
    4512          438 :      weight_array_i(:)=weight_i
    4513              : 
    4514         1117 :      select case (fftalga)
    4515              :      case (FFT_SG2002)
    4516              :        ! Note that here we don' fill fofr. Don't know if someone in
    4517              :        ! abinit uses option 1 to get both fofr as well as denpot
    4518              :        call sg2002_accrho(cplexwf_,ndat,n1,n2,n3,n4,n5,n6,(n6-1)/nproc_fft+1,&
    4519              :          max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,comm_fft,nproc_fft,me_fft,&
    4520          214 :          workf,denpot,weight_array_r,weight_array_i)
    4521              : 
    4522              :      case (FFT_FFTW3)
    4523              :        call fftw3_accrho(cplexwf_,ndat,n1,n2,n3,n4,n5,n6,(n6-1)/nproc_fft+1,&
    4524              :          max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,comm_fft,nproc_fft,me_fft,&
    4525            0 :          workf,denpot,weight_array_r, weight_array_i)
    4526              : 
    4527              :      case default
    4528          214 :        ABI_ERROR("fftalga does not provide accrho")
    4529              :      end select
    4530              : 
    4531              :    case (2)
    4532              :      !write(std_out,*)fftalg,option,cplex
    4533              :      !ABI_CHECK(cplex==1,"cplex!=2 with fftalg 412 is buggy")
    4534              : 
    4535          903 :      select case (fftalga)
    4536              : 
    4537              :      case (FFT_SG2002)
    4538              : 
    4539          903 :        if (use_ialltoall) then
    4540              :          call sg2002_applypot_many(cplexwf_,cplex,ndat,n1,n2,n3,n4,n5,n6,(n6-1)/nproc_fft+1,&
    4541              :            max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,&
    4542          680 :            max1o,max2o,max3o,m1o,m2o,m3o,comm_fft,nproc_fft,me_fft,denpot,workf)
    4543              : 
    4544              :        else
    4545              :          call sg2002_applypot(cplexwf_,cplex,ndat,n1,n2,n3,n4,n5,n6,(n6-1)/nproc_fft+1,&
    4546              :            max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,&
    4547          223 :            max1o,max2o,max3o,m1o,m2o,m3o,comm_fft,nproc_fft,me_fft,denpot,workf)
    4548              :        endif
    4549              : 
    4550              :      case (FFT_FFTW3)
    4551              : 
    4552            0 :        if (use_ialltoall) then
    4553              : 
    4554              :          call fftw3_applypot_many(cplexwf_,cplex,ndat,n1,n2,n3,n4,n5,n6,(n6-1)/nproc_fft+1,&
    4555              :            max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,&
    4556            0 :            max1o,max2o,max3o,m1o,m2o,m3o,comm_fft,nproc_fft,me_fft,denpot,workf)
    4557              : 
    4558              :        else
    4559              :          call fftw3_applypot(cplexwf_,cplex,ndat,n1,n2,n3,n4,n5,n6,(n6-1)/nproc_fft+1,&
    4560              :            max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,&
    4561            0 :            max1o,max2o,max3o,m1o,m2o,m3o,comm_fft,nproc_fft,me_fft,denpot,workf)
    4562              :        end if
    4563              : 
    4564              :      case default
    4565          903 :        ABI_ERROR("fftalga does not provide applypot")
    4566              :      end select
    4567              : 
    4568              :    case default
    4569              :      write(msg,"(a,i0,a)")"Option ",option," is not supported when fftalgc == 2"
    4570         1117 :      ABI_ERROR(msg)
    4571              :    end select
    4572              : 
    4573              :  end if ! End of composite operations
    4574              : 
    4575       799411 :  if (option==2 .or. option==3) then
    4576              :    ! From FFT box to kg_kout.
    4577       736047 :    xnorm=one/dble(n1*n2*n3)
    4578              : 
    4579       736047 :    if (nproc_fft > 1) then
    4580      1318188 :      do idat=1,ndat
    4581    129924242 :        do ig=1,npwout
    4582    128606054 :          i1=kg_kout(1,ig); if(i1<0) i1=i1+m1o; i1=i1+1
    4583    128606054 :          i2=kg_kout(2,ig); if(i2<0) i2=i2+m2o; i2=i2+1
    4584    128606054 :          i3=kg_kout(3,ig); if(i3<0) i3=i3+m3o; i3=i3+1
    4585              : 
    4586    128606054 :          igdat = ig + (idat-1) * npwout
    4587    128606054 :          i2_loc = (i2-1)/nproc_fft +1
    4588    128606054 :          i2dat_loc = i2_loc + (idat-1) * md2proc
    4589              : 
    4590    128606054 :          fofgout(1,igdat)=workf(1,i1,i3,i2dat_loc)*xnorm
    4591    129275310 :          fofgout(2,igdat)=workf(2,i1,i3,i2dat_loc)*xnorm
    4592              :        end do
    4593              :      end do
    4594              :    else
    4595              :      ! Warning: This call is buggy if istwfk > 2
    4596        87115 :      iflag=-2
    4597              :      call sphere(fofgout,ndat,npwout,workf,m1o,m2o,m3o,md1,md3,md2proc,kg_kout,istwf_k,iflag,&
    4598        87115 :        me_g0,shiftg0,symmE,xnorm)
    4599              :    end if
    4600              :  end if ! if option==2 or 3
    4601              : 
    4602       799411 :  ABI_FREE(workf)
    4603              : 
    4604              : !call timab(540,2,tsec)
    4605              : 
    4606       799411 : end subroutine fourwf_mpi
    4607              : !!***
    4608              : 
    4609              : !----------------------------------------------------------------------
    4610              : 
    4611              : !!****f* m_fft/fftmpi_u
    4612              : !!
    4613              : !! NAME
    4614              : !! fftmpi_u
    4615              : !!
    4616              : !! FUNCTION
    4617              : !!  **** DO NOT USE IT ****
    4618              : !!  Wrapper function used to perform the MPI FFT of ndat wavefunctions.
    4619              : !!  Mainly used for unit tests and prototyping. Better integration
    4620              : !!  will be provided afterwards.
    4621              : !!
    4622              : !! INPUTS
    4623              : !!  See fourwf_mpi
    4624              : !!
    4625              : !! OUTPUT
    4626              : !!  See fourwf_mpi
    4627              : !!
    4628              : !! SOURCE
    4629              : 
    4630              : ! The final interface should be:
    4631              : !subroutine fftmpi_u(npw_k,n4,n5,n6,nspinor,ndat,mgfft,ngfft,istwf_k,kg_k,gbound_k,fftabs,isign,fofg,fofr)
    4632              : 
    4633           16 : subroutine fftmpi_u(npw_k,n4,n5,n6,ndat,mgfft,ngfft,&
    4634           16 :                     istwf_k,gbound_k,kg_k,me_g0,distribfft,isign,fofg,fofr,comm_fft,cplexwf)
    4635              : 
    4636              : !Arguments ------------------------------------
    4637              : !scalars
    4638              :  integer,intent(in) :: istwf_k,mgfft,n4,n5,n6,ndat,npw_k
    4639              :  integer,intent(in) :: isign,comm_fft,me_g0,cplexwf
    4640              :  type(distribfft_type),intent(in) :: distribfft
    4641              : !arrays
    4642              :  integer,intent(in) :: gbound_k(2*mgfft+8,2),ngfft(18)
    4643              :  integer,intent(in) :: kg_k(3,npw_k)
    4644              :  real(dp),intent(inout) :: fofg(2,npw_k*ndat),fofr(2,n4,n5,n6*ndat)
    4645              : 
    4646              : !Local variables-------------------------------
    4647              : !scalars
    4648              :  integer,parameter :: npw0=0,cplex0=0
    4649              :  integer :: n1,n2,n3
    4650              :  real(dp),parameter :: weight_r=one,weight_i=one
    4651              : !arrays
    4652              :  integer :: dummy_kg(0,0)
    4653              :  real(dp) :: dummy_denpot(0,0,0),dummy_fofg(0,0)
    4654              : ! *************************************************************************
    4655              : 
    4656           16 :  n1 = ngfft(1); n2 = ngfft(2); n3 = ngfft(3)
    4657              : 
    4658           16 :  if (isign == 1) then
    4659              :    ! option 0 G --> R
    4660              :    call fourwf_mpi(cplex0,dummy_denpot,fofg,dummy_fofg,fofr,&
    4661              :      gbound_k,gbound_k,istwf_k,kg_k,dummy_kg,me_g0,mgfft,ngfft,distribfft,n1,n2,n3,&
    4662            8 :      npw_k,npw0,n4,n5,n6,ndat,0,weight_r,weight_i,comm_fft,cplexwf=cplexwf)
    4663              :  else
    4664              :    ! option 3 R --> G
    4665              :    call fourwf_mpi(cplex0,dummy_denpot,dummy_fofg,fofg,fofr,&
    4666              :      gbound_k,gbound_k,istwf_k,dummy_kg,kg_k,me_g0,mgfft,ngfft,distribfft,n1,n2,n3,&
    4667            8 :      npw0,npw_k,n4,n5,n6,ndat,3,weight_r,weight_i,comm_fft,cplexwf=cplexwf)
    4668              :  end if
    4669              : 
    4670           16 : end subroutine fftmpi_u
    4671              : !!***
    4672              : 
    4673              : !!****f* m_fft/zerosym
    4674              : !! NAME
    4675              : !! zerosym
    4676              : !!
    4677              : !! FUNCTION
    4678              : !! Symmetrize an array on the FFT grid by vanishing some term on the boundaries.
    4679              : !!
    4680              : !! INPUTS
    4681              : !!  cplex= if 1, input array is REAL, if 2, input array is COMPLEX
    4682              : !!  mpi_enreg=information about MPI parallelization
    4683              : !!  n1,n2,n3=FFT dimensions nfft=n1*n2*n3
    4684              : !!  ig1,ig2,ig3=optional arguments= indexes of unbalanced g-vectors to cancel
    4685              : !!              if not present, ig1=1+n1/2, ig2=1+n2/2, ig3=1+n3/2 for even n1,n2,n3
    4686              : !!              if igj=-1, nothing is done in direction j
    4687              : !!
    4688              : !! SIDE EFFECTS
    4689              : !!  array(cplex,n1*n2*n3)=complex array to be symetrized
    4690              : !!
    4691              : !! SOURCE
    4692              : 
    4693       116031 : subroutine zerosym(array,cplex,n1,n2,n3, &
    4694              :                    ig1,ig2,ig3,comm_fft,distribfft) ! Optional arguments
    4695              : 
    4696              : !Arguments ------------------------------------
    4697              : !scalars
    4698              :  integer,intent(in) :: cplex,n1,n2,n3
    4699              :  integer,optional,intent(in) :: ig1,ig2,ig3,comm_fft
    4700              :  type(distribfft_type),intent(in),target,optional :: distribfft
    4701              : !arrays
    4702              :  real(dp),intent(inout) :: array(cplex,n1*n2*n3)
    4703              : 
    4704              : !Local variables-------------------------------
    4705              : !scalars
    4706              :  integer :: i1,i2,i3,ifft,ifft_proc,index,j,j1,j2,j3,me_fft,nd2
    4707              :  integer :: nproc_fft,n1sel,nn12,n2sel,n3sel,r2
    4708              :  !arrays
    4709       116031 :  integer, contiguous, pointer :: fftn2_distrib(:),ffti2_local(:)
    4710              : ! **********************************************************************
    4711              : 
    4712       116031 :  me_fft=0;nproc_fft=1
    4713       116031 :  if (present(comm_fft)) then
    4714       108272 :    me_fft=xmpi_comm_rank(comm_fft)
    4715       108272 :    nproc_fft=xmpi_comm_size(comm_fft)
    4716              :  end if
    4717       116031 :  nd2=(n2-1)/nproc_fft+1
    4718       116031 :  nn12=n1*n2
    4719              : 
    4720              : !Get the distrib associated with this fft_grid
    4721       116031 :  if (present(distribfft)) then
    4722       108272 :    if (n2== distribfft%n2_coarse) then
    4723        66786 :      fftn2_distrib => distribfft%tab_fftdp2_distrib
    4724        66786 :      ffti2_local => distribfft%tab_fftdp2_local
    4725        41486 :    else if(n2 == distribfft%n2_fine) then
    4726        41486 :      fftn2_distrib => distribfft%tab_fftdp2dg_distrib
    4727        41486 :      ffti2_local => distribfft%tab_fftdp2dg_local
    4728              :    else
    4729            0 :      ABI_BUG("Unable to find an allocated distrib for this fft grid")
    4730              :    end if
    4731              :  else
    4732        23277 :    ABI_MALLOC(fftn2_distrib,(n2))
    4733        15518 :    ABI_MALLOC(ffti2_local,(n2))
    4734       490226 :    fftn2_distrib=0;ffti2_local=(/(i2,i2=1,n2)/)
    4735              :  end if
    4736              : 
    4737       116031 :  if (present(ig1)) then
    4738         5622 :    n1sel=ig1
    4739       110409 :  else if (mod(n1,2)==0) then
    4740        89203 :    n1sel=1+n1/2
    4741              :  else
    4742              :    n1sel=-1
    4743              :  end if
    4744       116031 :  if (present(ig2)) then
    4745         5622 :    n2sel=ig2
    4746       110409 :  else if (mod(n2,2)==0) then
    4747        86450 :    n2sel=1+n2/2
    4748              :  else
    4749              :    n2sel=-1
    4750              :  end if
    4751       116031 :  if (present(ig3)) then
    4752         5622 :    n3sel=ig3
    4753       110409 :  else if (mod(n3,2)==0) then
    4754        88233 :    n3sel=1+n3/2
    4755              :  else
    4756              :    n3sel=-1
    4757              :  end if
    4758              : 
    4759       116031 :  if (n1sel>0) then
    4760        94801 :    index=n1sel-nn12-n1
    4761      2348342 :    do i3=1,n3
    4762      2253541 :      index=index+nn12;ifft=index
    4763     62564503 :      do i2=1,n2
    4764     60216161 :        ifft=ifft+n1
    4765     62469702 :        if (nproc_fft>1) then
    4766              :          ! MPIWF: consider ifft only if it is treated by the current proc and compute its address
    4767      6214624 :          j=ifft-1;j1=modulo(j,n1);j2=modulo(j/n1,n2);j3=j/(n1*n2) !;r2=modulo(j2,nd2)
    4768      6214624 :          if(fftn2_distrib(j2+1)==me_fft) then ! MPIWF this ifft is to be treated by me_fft
    4769      3051728 :            r2= ffti2_local(j2+1) - 1
    4770      3051728 :            ifft_proc=n1*(nd2*j3+r2)+j1+1 !this is ifft in the current proc
    4771      9155184 :            array(:,ifft_proc)=zero
    4772              :          end if
    4773              :        else
    4774    158285277 :          array(:,ifft)=zero
    4775              :        end if
    4776              :      end do
    4777              :    end do
    4778              :  end if
    4779              : 
    4780       116031 :  if (n2sel>0) then
    4781        92042 :    index=n1*n2sel-nn12-n1
    4782      2244482 :    do i3=1,n3
    4783      2152440 :      index=index+nn12;ifft=index
    4784     63729018 :      do i1=1,n1
    4785     61484536 :        ifft=ifft+1
    4786     63636976 :        if (nproc_fft>1) then
    4787              :          ! MPIWF: consider ifft only if it is treated by the current proc and compute its address
    4788      6240544 :          j=ifft-1;j1=modulo(j,n1);j2=modulo(j/n1,n2);j3=j/(n1*n2);
    4789      6240544 :          if(fftn2_distrib(j2+1)==me_fft) then ! MPIWF this ifft is to be treated by me_fft
    4790      3064688 :            r2= ffti2_local(j2+1) - 1
    4791      3064688 :            ifft_proc=n1*(nd2*j3+r2)+j1+1 !this is ifft in the current proc
    4792      9194064 :            array(:,ifft_proc)=zero
    4793              :          end if
    4794              :        else
    4795    164143752 :          array(:,ifft)=zero
    4796              :        end if
    4797              :      end do
    4798              :    end do
    4799              :  end if
    4800              : 
    4801       116031 :  if (n3sel>0) then
    4802        93813 :    index=nn12*n3sel-nn12-n1
    4803      2177896 :    do i2=1,n2
    4804      2084083 :      index=index+n1;ifft=index
    4805     63884765 :      do i1=1,n1
    4806     61706869 :        ifft=ifft+1
    4807     63790952 :        if (nproc_fft>1) then
    4808              :          ! MPIWF: consider ifft only if it is treated by the current proc and compute its address
    4809      6240544 :          j=ifft-1;j1=modulo(j,n1);j2=modulo(j/n1,n2);j3=j/(n1*n2)
    4810      6240544 :          if(fftn2_distrib(j2+1)==me_fft) then ! MPIWF this ifft is to be treated by me_fft
    4811      3064688 :            r2= ffti2_local(j2+1) - 1
    4812      3064688 :            ifft_proc=n1*(nd2*j3+r2)+j1+1 !this is ifft in the current proc
    4813      9194064 :            array(:,ifft_proc)=zero
    4814              :          end if
    4815              :        else
    4816    164572611 :          array(:,ifft)=zero
    4817              :        end if
    4818              :      end do
    4819              :    end do
    4820              :  end if
    4821              : 
    4822       116031 :  if (.not.present(distribfft)) then
    4823         7759 :    ABI_FREE(fftn2_distrib)
    4824         7759 :    ABI_FREE(ffti2_local)
    4825              :  end if
    4826              : 
    4827       116031 : end subroutine zerosym
    4828              : !!***
    4829              : 
    4830              : !!****f* m_fft/fourdp_6d
    4831              : !! NAME
    4832              : !! fourdp_6d
    4833              : !!
    4834              : !! FUNCTION
    4835              : !!     Calculate a 6-dimensional Fast Fourier Transform
    4836              : !!
    4837              : !!     isign=-1 : A(G1,G2) = Sum(r1,r2) A(r1,r2) exp(-iG1.r1) exp(+iG2.r2)
    4838              : !!                                                  ^            ^
    4839              : !!     isign=+1 : A(r1,r2) = Sum(G1,G2) A(G1,G2) exp(+iG1.r1) exp(-iG2.r2)
    4840              : !!                                                  ^            ^
    4841              : !!     isign=-1 and isign=1 form a transform/inverse-transform pair: calling
    4842              : !!     one then the other will take you back to the original function,
    4843              : !!     multiplied by a factor of (nl*nm*nn)**2.
    4844              : !!     ------------------------------------------------------------------
    4845              : !!
    4846              : !!     input:
    4847              : !!      a: A(r1,r2) [overwritten]
    4848              : !!     output:
    4849              : !!      a: A(G1,G2) in the format IGFFT
    4850              : !!     ------------------------------------------------------------------
    4851              : !!
    4852              : !! INPUTS
    4853              : !!
    4854              : !! OUTPUT
    4855              : !!
    4856              : !! SOURCE
    4857              : 
    4858            0 : subroutine fourdp_6d(cplex, matrix, isign, MPI_enreg, nfft, ngfft, tim_fourdp)
    4859              : 
    4860              : !Arguments ------------------------------------
    4861              : !scalars
    4862              :  integer,intent(in) :: cplex, isign, nfft, tim_fourdp
    4863              :  type(MPI_type),intent(in) :: MPI_enreg
    4864              : !arrays
    4865              :  integer,intent(in) :: ngfft(18)
    4866              :  complex(gwp),intent(inout) :: matrix(nfft,nfft)
    4867              : 
    4868              : !Local variables-------------------------------
    4869              : !scalars
    4870              :  !integer,parameter :: cplex=2
    4871              :  integer :: i1,i2,i3,ifft, n1,n2,n3
    4872              : !arrays
    4873            0 :  real(dp),allocatable :: fofg(:,:),fofr(:)
    4874              : ! *************************************************************************
    4875              : 
    4876              :  ! TODO check normalization factor, it is better if we use the GW conventions.
    4877            0 :  n1 = ngfft(1)
    4878            0 :  n2 = ngfft(2)
    4879            0 :  n3 = ngfft(3)
    4880              : 
    4881            0 :  ABI_MALLOC(fofg,(2,nfft))
    4882            0 :  ABI_MALLOC(fofr,(cplex*nfft))
    4883              : 
    4884            0 :  do i3=0,n3-1
    4885            0 :    do i2=0,n2-1
    4886            0 :      do i1=0,n1-1
    4887              : 
    4888            0 :        ifft=1+i1+i2*n1+i3*n1*n2
    4889            0 :        if (isign==1) then
    4890              :          ! G1 -> r1 transform for each G2 to form A(r1,G2)
    4891            0 :          fofg(1,:)=REAL (matrix(:,ifft))
    4892            0 :          fofg(2,:)=AIMAG(matrix(:,ifft))
    4893            0 :        else if (isign==-1) then
    4894              :          ! r1 -> G1 transform for each r2 to form A(G1,r2)
    4895            0 :          fofr(1:nfft)       =REAL (matrix(:,ifft))
    4896            0 :          fofr(nfft+1:2*nfft)=AIMAG(matrix(:,ifft))
    4897              :        else
    4898            0 :          ABI_ERROR("Wrong isign")
    4899              :        end if
    4900              : 
    4901            0 :        call fourdp(cplex,fofg,fofr,isign,MPI_enreg,nfft,1,ngfft,tim_fourdp)
    4902              : 
    4903            0 :        if (isign==1) then
    4904              :          ! Save A(r1,G2)
    4905            0 :          matrix(:,ifft)=CMPLX(fofr(1:nfft),fofr(nfft+1:2*nfft))
    4906            0 :        else if (isign==-1) then
    4907              :          ! Save A(G1,r2)
    4908            0 :          matrix(:,ifft)=CMPLX(fofg(1,:),fofg(2,:))
    4909              :        end if
    4910              : 
    4911              :      end do
    4912              :    end do
    4913              :  end do
    4914              : 
    4915            0 :  do i3=0,n3-1
    4916            0 :    do i2=0,n2-1
    4917            0 :      do i1=0,n1-1
    4918              : 
    4919            0 :        ifft=1+i1+i2*n1+i3*n1*n2
    4920            0 :        if (isign==1) then
    4921              :          ! Do the G2 -> r2 transform of A(r1,G2) to get A(r1,r2)
    4922            0 :          fofr(1:nfft       )=REAL (matrix(ifft,:))
    4923            0 :          fofr(nfft+1:2*nfft)=AIMAG(matrix(ifft,:))
    4924            0 :        else if (isign==-1) then
    4925              :          ! Do the r2 -> G2 transform of A(G1,r2) to get A(G1,G2)
    4926            0 :          fofg(1,:)=REAL (matrix(ifft,:))
    4927            0 :          fofg(2,:)=AIMAG(matrix(ifft,:))
    4928              :        end if
    4929              : 
    4930            0 :        call fourdp(2,fofg,fofr,-isign,MPI_enreg,nfft,1,ngfft,tim_fourdp)
    4931              : 
    4932            0 :        if (isign==1) then
    4933            0 :          matrix(ifft,:)=CMPLX(fofg(1,:),fofg(2,:))
    4934            0 :        else if (isign==-1) then
    4935            0 :          matrix(ifft,:)=CMPLX(fofr(1:nfft),fofr(nfft+1:2*nfft))
    4936              :        end if
    4937              : 
    4938              :      end do
    4939              :    end do
    4940              :  end do
    4941              : 
    4942            0 :  ABI_FREE(fofg)
    4943            0 :  ABI_FREE(fofr)
    4944              : 
    4945            0 : end subroutine fourdp_6d
    4946              : !!***
    4947              : 
    4948              : !!****f* m_fft/fftpac
    4949              : !! NAME
    4950              : !! fftpac
    4951              : !!
    4952              : !! FUNCTION
    4953              : !! Allow for data copying to modify the stride (dimensioning) of a three-dimensional array,
    4954              : !! for more efficient three dimensional fft.
    4955              : !! NOTE that the arrays are in REAL space.
    4956              : !!
    4957              : !! Note that arrays aa and bb may be the same array (start at the same address).
    4958              : !! The array aa also incorporate a spin variable.
    4959              : !! MG FIXME: THIS IS **VERY BAD** AS FORTRAN DOES NOT ALLOW FOR ALIASING
    4960              : !!
    4961              : !! INPUTS
    4962              : !!  ispden=actual spin-density of interest
    4963              : !!  nspden=number of spin-density components
    4964              : !!  n1,n2,n3=actual data dimensions, dimensions of complex array a
    4965              : !!  nd1,nd2,nd3=array dimensions of (larger) array b
    4966              : !!  ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    4967              : !!  option= see description of side effects
    4968              : !!
    4969              : !! SIDE EFFECTS
    4970              : !!  aa & bb arrays are treated as input or output depending on option:
    4971              : !!  option=1  aa(n1*n2*n3,ispden) <-- bb(nd1,nd2,nd3) real case
    4972              : !!  option=2  aa(n1*n2*n3,ispden) --> bb(nd1,nd2,nd3) real case
    4973              : !!  option=10 aa(n1*n2*n3,ispden) <-- bb(nd1,nd2,nd3) complex case like option 1 real part
    4974              : !!  option=11 aa(n1*n2*n3,ispden) <-- bb(nd1,nd2,nd3) complex case like option 1 imag part
    4975              : !!
    4976              : !! SOURCE
    4977              : 
    4978       974393 : subroutine fftpac(ispden,mpi_enreg,nspden,n1,n2,n3,nd1,nd2,nd3,ngfft,aa,bb,option)
    4979              : 
    4980              : !Arguments ------------------------------------
    4981              : !scalars
    4982              :  integer,intent(in) :: ispden,n1,n2,n3,nd1,nd2,nd3,nspden,option
    4983              :  type(mpi_type),intent(in) :: mpi_enreg
    4984              : !arrays
    4985              :  integer,intent(in) :: ngfft(18)
    4986              :  real(dp),intent(inout) :: aa(n1*n2*n3/ngfft(10),nspden),bb(nd1,nd2,nd3)
    4987              : 
    4988              : !Local variables-------------------------------
    4989              : !scalars
    4990              :  integer :: i1,i2,i3,index,me_fft,nproc_fft
    4991              :  character(len=500) :: msg
    4992              :  !arrays
    4993       974393 :  integer, contiguous, pointer :: fftn2_distrib(:),ffti2_local(:)
    4994       974393 :  integer, contiguous, pointer :: fftn3_distrib(:),ffti3_local(:)
    4995              : ! *************************************************************************
    4996              : 
    4997       974393 :  me_fft=ngfft(11); nproc_fft=ngfft(10)
    4998              : 
    4999       974393 :  if (option==1.or.option==2) then
    5000       974393 :    if (nd1<n1.or.nd2<n2.or.nd3<n3) then
    5001              :      write(msg,'(a,3i0,2a,3i0,a)')&
    5002            0 :       'Each of nd1,nd2,nd3=',nd1,nd2,nd3,ch10,'must be >= n1, n2, n3 =',n1,n2,n3,'.'
    5003            0 :      ABI_BUG(msg)
    5004              :    end if
    5005              :  else
    5006            0 :    if (2*nd1<n1.or.nd2<n2.or.nd3<n3) then
    5007              :      write(msg,'(a,3i0,2a,3i0,a)')&
    5008            0 :      'Each of 2*nd1,nd2,nd3=',2*nd1,nd2,nd3,ch10,'must be >= (n1, n2, n3) =',n1,n2,n3,'.'
    5009            0 :      ABI_BUG(msg)
    5010              :    end if
    5011              :  end if
    5012              : 
    5013              :  ! Get the distrib associated with this fft_grid
    5014       974393 :  call ptabs_fourdp(mpi_enreg,n2,n3,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
    5015              : 
    5016       974393 :  if (option==1) then
    5017              :    ! aa(n1*n2*n3,ispden) <-- bb(nd1,nd2,nd3) real case
    5018      2306775 :    do i3=1,n3
    5019      2306775 :      if (me_fft==fftn3_distrib(i3)) then
    5020     49389931 :        do i2=1,n2
    5021   1439100118 :          do i1=1,n1
    5022   1436946212 :            aa(i1+n1*(i2-1+n2*(ffti3_local(i3)-1)),ispden)=bb(i1,i2,i3)
    5023              :          end do
    5024              :        end do
    5025              :      end if
    5026              :    end do
    5027              : 
    5028       867804 :  else if (option==2) then
    5029              :    !  option=2  aa(n1*n2*n3,ispden) --> bb(nd1,nd2,nd3) real case
    5030              :    !  Here we avoid corrupting the data in a while writing to b in the
    5031              :    !  case in which a and b are same array.
    5032              :    !  Also: replace "trash" data with 0 s to avoid floating point
    5033              :    !  exceptions when this data is actually manipulated in fft.
    5034       867804 :    do i3=nd3,n3+1,-1
    5035       867804 :      do i2=nd2,1,-1
    5036            0 :        do i1=nd1,1,-1
    5037            0 :          bb(i1,i2,i3)=0.d0
    5038              :        end do
    5039              :      end do
    5040              :    end do
    5041     15087613 :    do i3=n3,1,-1
    5042     15087613 :      if (me_fft==fftn3_distrib(i3)) then
    5043     20326006 :        do i2=nd2,n2+1,-1
    5044    184859675 :          do i1=nd1,1,-1
    5045    170670350 :            bb(i1,i2,i3)=0.d0
    5046              :          end do
    5047              :        end do
    5048    257891269 :        do i2=n2,1,-1
    5049    403355313 :          do i1=nd1,n1+1,-1
    5050    403355313 :            bb(i1,i2,i3)=0.d0
    5051              :          end do
    5052   6787019444 :          do i1=n1,1,-1
    5053   6772830119 :            bb(i1,i2,i3)=aa(i1+n1*(i2-1+n2*(ffti3_local(i3) - 1)),ispden)
    5054              :          end do
    5055              :        end do
    5056              :      end if
    5057              :    end do
    5058              : !  MF
    5059            0 :  else if (option==10 .or. option==11) then
    5060              :    ! option=10 aa(n1*n2*n3,ispden) <-- bb(nd1,nd2,nd3) complex case like option 1 real part
    5061              :    ! option=11 aa(n1*n2*n3,ispden) <-- bb(nd1,nd2,nd3) complex case like option 1 imag part
    5062            0 :    index=1
    5063            0 :    if(option==11) index=2
    5064            0 :    do i3=1,n3
    5065            0 :      do i2=1,n2
    5066            0 :        do i1=1,n1/2
    5067            0 :          aa(index,ispden)=bb(i1,i2,i3)
    5068            0 :          index=index+2
    5069              :        end do
    5070              :      end do
    5071              :    end do
    5072              : !  MF
    5073              :  else
    5074            0 :    ABI_BUG(sjoin('Bad option =',itoa(option)))
    5075              :  end if
    5076              : 
    5077       974393 : end subroutine fftpac
    5078              : !!***
    5079              : 
    5080              : !!****f* m_fft/indirect_parallel_Fourier
    5081              : !! NAME
    5082              : !! indirect_parallel_Fourier
    5083              : !!
    5084              : !! FUNCTION
    5085              : !! The purpose of this routine is to transfer data from right to left right(:,index(i))=left(:,i)
    5086              : !! The difficulty is that right and left are distributed among processors
    5087              : !! We will suppose that the distribution is done as a density in Fourier space
    5088              : !! We first order the right hand side data according to the processor
    5089              : !! in which they are going to be located in the left hand side.
    5090              : !! This is done is a way such that  a mpi_alltoall put the data on the correct processor.
    5091              : !! We also transfer their future address. A final ordering put everything in place
    5092              : !!
    5093              : !! INPUTS
    5094              : !!  index(sizeindex)= global address for the transfer from right to left
    5095              : !!  left(2,nleft)=left hand side
    5096              : !!  mpi_enreg=information about MPI parallelization
    5097              : !!  ngleft(18)=contain all needed information about 3D FFT for the left hand side
    5098              : !!  see ~abinit/doc/variables/vargs.htm#ngfft
    5099              : !!  ngright(18)=contain all needed information about 3D FFT for the right hand side
    5100              : !!  see ~abinit/doc/variables/vargs.htm#ngfft
    5101              : !!  nleft=second dimension of left array (for this processor)
    5102              : !!  nright=second dimension of right array (for this processor)
    5103              : !!  sizeindex=size of the index array (different form nright, because it is global to all processors)
    5104              : !!
    5105              : !! OUTPUT
    5106              : !!  left(2,nleft)=the elements of the right hand side, at the correct place in the correct processor
    5107              : !!
    5108              : !! NOTES
    5109              : !!  A lot of things to improve.
    5110              : !!
    5111              : !! SOURCE
    5112              : 
    5113         2896 : subroutine indirect_parallel_Fourier(index,left,mpi_enreg,ngleft,ngright,nleft,nright,paral_kgb,right,sizeindex)
    5114              : 
    5115              : !Arguments ---------------------------------------------
    5116              : !scalars
    5117              :  integer,intent(in) :: ngleft(18),ngright(18),nleft,nright,paral_kgb,sizeindex
    5118              :  type(MPI_type),intent(in) :: mpi_enreg
    5119              : !arrays
    5120              :  integer,intent(in) :: index(sizeindex)
    5121              :  real(dp),intent(in) :: right(2,nright)
    5122              :  real(dp),intent(inout) :: left(2,nleft)
    5123              : 
    5124              : !Local variables ---------------------------------------
    5125              : !scalars
    5126              :  integer :: ierr,i_global,ileft,iright,iright_global
    5127              :  integer :: j,j1,j2,j3,j_global,jleft_global
    5128              :  integer :: jleft_local,me_fft,n1l,n2l,n3l,n1r,n2r,n3r,nd2l,nd2r
    5129              :  integer :: nproc_fft,proc_dest,r2,siz_slice_max
    5130              : !arrays
    5131         2896 :  integer,allocatable :: index_recv(:),index_send(:),siz_slice(:), ffti2r_global(:)
    5132         2896 :  integer, contiguous, pointer :: fftn2l_distrib(:),ffti2l_local(:)
    5133         2896 :  integer, contiguous, pointer :: fftn3l_distrib(:),ffti3l_local(:)
    5134         2896 :  integer, contiguous, pointer :: fftn2r_distrib(:),ffti2r_local(:)
    5135         2896 :  integer, contiguous, pointer :: fftn3r_distrib(:),ffti3r_local(:)
    5136         2896 :  real(dp),allocatable :: right_send(:,:),right_recv(:,:)
    5137              : ! *************************************************************************
    5138              : 
    5139         2896 :  n1r=ngright(1);n2r=ngright(2);n3r=ngright(3)
    5140         2896 :  n1l=ngleft(1) ;n2l=ngleft(2) ;n3l=ngleft(3)
    5141         2896 :  nproc_fft=mpi_enreg%nproc_fft; me_fft=mpi_enreg%me_fft
    5142         2896 :  nd2r=n2r/nproc_fft; nd2l=n2l/nproc_fft
    5143              : 
    5144              :  !Get the distrib associated with the left fft_grid
    5145         2896 :  call ptabs_fourdp(mpi_enreg,n2l,n3l,fftn2l_distrib,ffti2l_local,fftn3l_distrib,ffti3l_local)
    5146              : 
    5147              :  !Get the distrib associated with the right fft_grid
    5148         2896 :  call ptabs_fourdp(mpi_enreg,n2r,n3r,fftn2r_distrib,ffti2r_local,fftn3r_distrib,ffti3r_local)
    5149              : 
    5150              :  !Precompute local --> global corespondance
    5151         8688 :  ABI_MALLOC(ffti2r_global,(nd2r))
    5152        41432 :  ffti2r_global(:) = -1
    5153        81576 :  do j2=1,n2r
    5154        81576 :     if( fftn2r_distrib(j2) == me_fft ) then
    5155        38536 :        ffti2r_global( ffti2r_local(j2) ) = j2
    5156              :     end if
    5157              :  end do
    5158              : 
    5159         8688 :  ABI_MALLOC(siz_slice,(nproc_fft))
    5160         8872 :  siz_slice(:)=0
    5161     90099696 :  do i_global=1,sizeindex !look for the maximal size of slice of data
    5162     90096800 :   j_global=index(i_global)!; write(std_out,*) j_global,i_global
    5163     90099696 :   if(j_global /=0) then
    5164              :     !use the fact that (j-1)=i1 + n1l*(j2l-1 + n2l*(j3l-1))
    5165     18768064 :    proc_dest= fftn2l_distrib( modulo((j_global-1)/n1l,n2l) + 1)
    5166     18768064 :    siz_slice(proc_dest+1)=siz_slice(proc_dest+1)+1
    5167              : !write(std_out,*) 'in indirect proc',proc_dest,siz_slice(proc_dest+1)
    5168              :   end if
    5169              :  end do
    5170         8872 :  siz_slice_max=maxval(siz_slice) !This value could be made smaller by looking locally
    5171              : !and performing a allgather with a max
    5172              : !write(std_out,*) 'siz_slice,sizeindex,siz_slice',siz_slice(:),sizeindex,siz_slice_max
    5173              : !write(std_out,*) 'sizeindex,nright,nleft',sizeindex,nright,nleft
    5174         8688 :  ABI_MALLOC(right_send,(2,nproc_fft*siz_slice_max))
    5175         8688 :  ABI_MALLOC(index_send,(nproc_fft*siz_slice_max))
    5176     81145032 :  siz_slice(:)=0; index_send(:)=0; right_send(:,:)=zero
    5177     43732832 :  do iright=1,nright
    5178     43729936 :   j=iright-1;j1=modulo(j,n1r);j2=modulo(j/n1r,nd2r);j3=j/(n1r*nd2r)
    5179     43729936 :   j2 = ffti2r_global(j2+1) - 1
    5180     43729936 :   iright_global=n1r*(n2r*j3+j2)+j1+1
    5181     43729936 :   jleft_global=index(iright_global)
    5182     43732832 :   if(jleft_global/=0)then
    5183      9066080 :      j=jleft_global-1;j1=modulo(j,n1l);j2=modulo(j/n1l,n2l);j3=j/(n1l*n2l); r2=ffti2l_local(j2+1)-1
    5184      9066080 :    jleft_local=n1l*(nd2l*j3+r2)+j1+1
    5185      9066080 :    proc_dest=fftn2l_distrib(j2+1)
    5186      9066080 :    siz_slice(proc_dest+1)=siz_slice(proc_dest+1)+1
    5187     27198240 :    right_send(:,proc_dest*siz_slice_max+siz_slice(proc_dest+1))=right(:,iright)
    5188      9066080 :    index_send(proc_dest*siz_slice_max+siz_slice(proc_dest+1))=jleft_local
    5189              : !write(std_out,*) 'loop ir',jleft_local,jleft_global,iright_global,iright
    5190              :   end if
    5191              :  end do
    5192         5792 :  ABI_MALLOC(right_recv,(2,nproc_fft*siz_slice_max))
    5193         5792 :  ABI_MALLOC(index_recv,(nproc_fft*siz_slice_max))
    5194              : #if defined HAVE_MPI
    5195         2896 :   if(paral_kgb == 1) then
    5196              :     call mpi_alltoall (right_send,2*siz_slice_max, &
    5197              :                        MPI_double_precision, &
    5198              :                        right_recv,2*siz_slice_max, &
    5199         2896 :                        MPI_double_precision,mpi_enreg%comm_fft,ierr)
    5200              :     call mpi_alltoall (index_send,siz_slice_max, &
    5201              :                        MPI_integer, &
    5202              :                        index_recv,siz_slice_max, &
    5203         2896 :                        MPI_integer,mpi_enreg%comm_fft,ierr)
    5204              :   endif
    5205              : #endif
    5206     20285488 :  do ileft=1,siz_slice_max*nproc_fft
    5207              :    !write(std_out,*)index_recv(ileft)
    5208     38417648 :    if(index_recv(ileft) /=0 ) left(:,index_recv(ileft))=right_recv(:,ileft)
    5209              :  end do
    5210         2896 :  ABI_FREE(right_recv)
    5211         2896 :  ABI_FREE(index_recv)
    5212         2896 :  ABI_FREE(right_send)
    5213         2896 :  ABI_FREE(index_send)
    5214         2896 :  ABI_FREE(siz_slice)
    5215         2896 :  ABI_FREE(ffti2r_global)
    5216              : 
    5217         2896 : end subroutine indirect_parallel_Fourier
    5218              : !!***
    5219              : 
    5220              : !!****f* ABINIT/fft_init_counters
    5221              : !! NAME
    5222              : !! fft_init_counters
    5223              : !!
    5224              : !! FUNCTION
    5225              : !!
    5226              : !! SOURCE
    5227              : 
    5228            0 : subroutine fft_init_counters()
    5229              : 
    5230            0 :    fourdp_counter = 0
    5231            0 :    fourwf_counter = 0
    5232              : 
    5233            0 : end subroutine fft_init_counters
    5234              : !!***
    5235              : 
    5236              : !!****f* ABINIT/fft_stop_counters
    5237              : !! NAME
    5238              : !! fft_stop_counters
    5239              : !!
    5240              : !! FUNCTION
    5241              : !!
    5242              : !! SOURCE
    5243              : 
    5244            0 : subroutine fft_stop_counters()
    5245              : 
    5246            0 :    fourdp_counter = -1
    5247            0 :    fourwf_counter = -1
    5248              : 
    5249            0 : end subroutine fft_stop_counters
    5250              : !!***
    5251              : 
    5252              : !!****f* ABINIT/fft_output_counters
    5253              : !! NAME
    5254              : !! fft_output_counters
    5255              : !!
    5256              : !! FUNCTION
    5257              : !!
    5258              : !! SOURCE
    5259              : 
    5260            0 : subroutine fft_output_counters(nbandtot, mpi_enreg)
    5261              : 
    5262              : !Arguments ------------------------------------
    5263              :  integer,intent(in) :: nbandtot
    5264              :  type(MPI_type),intent(in) :: mpi_enreg
    5265              : 
    5266              : !Local variables-------------------------------
    5267              : !scalars
    5268              :  character(len=500) :: msg
    5269              :  integer :: cnt,ierr, units(2)
    5270              : ! *************************************************************************
    5271              : 
    5272            0 :  units = [std_out, ab_out]
    5273              : 
    5274            0 :  call wrtout(units,'')
    5275            0 :  write(msg,'(a)')                ' --- FFT COUNTERS ------------------------------------------------------------'
    5276            0 :  call wrtout(units, msg)
    5277            0 :  write(msg,'(a,i6)')             ' total Number of Bands         : NB = ',nbandtot
    5278            0 :  call wrtout(units, msg)
    5279            0 :  write(msg,'(a)')                '                      | total count (TC) |            TC/NB'
    5280            0 :  call wrtout(units, msg)
    5281            0 :  write(msg,'(a)')                ' -----------------------------------------------------------------------------'
    5282            0 :  call wrtout(units, msg)
    5283            0 :  call xmpi_sum(fourwf_counter,mpi_enreg%comm_kpt,ierr)
    5284            0 :  cnt=fourdp_counter
    5285            0 :  if (cnt>0) then
    5286            0 :    write(msg,'(a,i16,a)')       ' fourdp               | ',cnt,' |'
    5287            0 :    call wrtout(units, msg)
    5288              :  end if
    5289            0 :  cnt=fourwf_counter
    5290            0 :  if (cnt>0) then
    5291            0 :    write(msg,'(a,i16,a,f16.1)') ' fourwf               | ',cnt,' | ',dble(cnt)/nbandtot
    5292            0 :    call wrtout(units, msg)
    5293              :  end if
    5294            0 :  write(msg,'(a)')                ' -----------------------------------------------------------------------------'
    5295            0 :  call wrtout(units, msg)
    5296              : 
    5297            0 : end subroutine fft_output_counters
    5298              : !!***
    5299              : 
    5300              : !----------------------------------------------------------------------
    5301              : 
    5302              : !!****f* m_fft/uplan_init
    5303              : !! NAME
    5304              : !!  uplan_init
    5305              : !!
    5306              : !! FUNCTION
    5307              : !!  Initialize the plan
    5308              : !!
    5309              : !! INPUTS
    5310              : !!
    5311              : !! SOURCE
    5312              : 
    5313            0 : subroutine uplan_init(uplan, npw, nspinor, batch_size, ngfft, istwfk, kg_k, kind, gpu_option)
    5314              : 
    5315              : !Arguments ------------------------------------
    5316              : !scalars
    5317              :  class(uplan_t),target,intent(out) :: uplan
    5318              :  integer,intent(in) :: npw, nspinor, batch_size, istwfk, kind, gpu_option
    5319              : !Local variables-------------------------------
    5320              :  integer :: ig, ig1, ig2, ig3, n1, n2, n3, ifft
    5321              : !arrays
    5322              :  integer,intent(in) :: ngfft(18)
    5323              :  integer,target,intent(in) :: kg_k(3,npw)
    5324            0 :  integer, contiguous, pointer :: ig2ifft(:), ifft2ig(:)
    5325              : ! *************************************************************************
    5326              : 
    5327            0 :  uplan%npw = npw
    5328            0 :  uplan%nspinor = nspinor
    5329            0 :  uplan%istwfk = istwfk
    5330            0 :  uplan%batch_size = batch_size
    5331            0 :  uplan%kind  = kind
    5332            0 :  uplan%gpu_option  = gpu_option
    5333            0 :  uplan%ngfft = ngfft
    5334            0 :  uplan%mgfft = maxval(ngfft(1:3))
    5335            0 :  uplan%nfft  = product(ngfft(1:3))
    5336            0 :  uplan%kg_k => kg_k
    5337              : 
    5338            0 :  ABI_MALLOC(uplan%gbound, (2 * uplan%mgfft + 8, 2))
    5339            0 :  call sphereboundary(uplan%gbound, uplan%istwfk, uplan%kg_k, uplan%mgfft, int(uplan%npw))
    5340              : 
    5341            0 :  uplan%gpu_ctx_spc = c_null_ptr; uplan%gpu_ctx_dpc = c_null_ptr
    5342              : 
    5343            0 :  if (uplan%gpu_option == ABI_GPU_OPENMP) then
    5344            0 :    ABI_CHECK_IEQ(istwfk, 1, "istwfk /= 1 not supported with GPUs")
    5345            0 :    if (any(ngfft(1:3) /= ngfft(4:6))) then
    5346            0 :      ABI_ERROR("FFTs on GPUs with fftbox_plan3 do not support dims != embed")
    5347              :    end if
    5348              : 
    5349            0 :    ABI_MALLOC(uplan%ig2ifft, (uplan%npw))
    5350            0 :    ABI_ICALLOC(uplan%ifft2ig, (uplan%nfft))
    5351              : 
    5352            0 :    n1 = ngfft(1); n2 = ngfft(2); n3 = ngfft(3)
    5353            0 :    do ig=1,uplan%npw
    5354            0 :      ig1 = modulo(kg_k(1, ig), n1)
    5355            0 :      ig2 = modulo(kg_k(2, ig), n2)
    5356            0 :      ig3 = modulo(kg_k(3, ig), n3)
    5357            0 :      ifft = 1 + ig1 + n1*(ig2+ig3*n2)
    5358            0 :      uplan%ig2ifft(ig) = ifft
    5359            0 :      uplan%ifft2ig(ifft) = ig
    5360              :    end do
    5361              : 
    5362              :    ! Map data to GPU.
    5363            0 :    ig2ifft => uplan%ig2ifft; ifft2ig => uplan%ifft2ig
    5364              : #ifdef HAVE_OPENMP_OFFLOAD
    5365              :    !$OMP TARGET ENTER DATA MAP(to:ig2ifft, ifft2ig)
    5366              : #endif
    5367              :  end if
    5368              : 
    5369            0 : end subroutine uplan_init
    5370              : !!***
    5371              : 
    5372              : !----------------------------------------------------------------------
    5373              : 
    5374              : !!****f* m_fft/uplan_free
    5375              : !! NAME
    5376              : !!  uplan_free
    5377              : !!
    5378              : !! FUNCTION
    5379              : !!  Free dynamic memory.
    5380              : !!
    5381              : !! SOURCE
    5382              : 
    5383            0 : subroutine uplan_free(uplan)
    5384              : 
    5385              : !Arguments ------------------------------------
    5386              :  class(uplan_t),target,intent(inout) :: uplan
    5387              : 
    5388              : !Local variables-------------------------------
    5389            0 :  integer, contiguous, pointer :: ig2ifft(:), ifft2ig(:)
    5390              : ! *************************************************************************
    5391              : 
    5392            0 :  ABI_SFREE(uplan%gbound)
    5393              : 
    5394            0 :  if (uplan%gpu_option == ABI_GPU_OPENMP) then
    5395              :    ! Free memory on the GPU
    5396              :    ig2ifft => uplan%ig2ifft; ifft2ig => uplan%ifft2ig
    5397              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
    5398              :    call gpu_ctx_free(uplan%gpu_ctx_spc)
    5399              :    call gpu_ctx_free(uplan%gpu_ctx_dpc)
    5400              :    !$OMP TARGET EXIT DATA MAP(delete:ig2ifft, ifft2ig)
    5401              : #endif
    5402              :  end if
    5403              : 
    5404            0 :  ABI_SFREE(uplan%ig2ifft)
    5405            0 :  ABI_SFREE(uplan%ifft2ig)
    5406              : 
    5407            0 : end subroutine uplan_free
    5408              : !!***
    5409              : 
    5410              : !----------------------------------------------------------------------
    5411              : 
    5412              : !!****f* m_fft/uplan_execute_gr_spc
    5413              : !! NAME
    5414              : !!  uplan_execute_gr_spc
    5415              : !!
    5416              : !! FUNCTION
    5417              : !!
    5418              : !! INPUTS
    5419              : !!
    5420              : !! SOURCE
    5421              : 
    5422            0 : subroutine uplan_execute_gr_spc(uplan, ndat, ug, ur, &
    5423              :                                 isign, iscale, gpu_mode, phase_r) ! optional
    5424              : 
    5425              : !Arguments ------------------------------------
    5426              :  class(uplan_t),target,intent(inout) :: uplan
    5427              :  integer,intent(in) :: ndat
    5428              :  complex(sp),target,intent(in) :: ug(uplan%npw*uplan%nspinor*ndat)
    5429              :  complex(sp),target,intent(out) :: ur(uplan%nfft*uplan%nspinor*ndat)
    5430              :  integer,optional,intent(in) :: isign, iscale, gpu_mode
    5431              :  complex(sp),optional,intent(in) :: phase_r(uplan%nfft*uplan%nspinor)
    5432              : 
    5433              : !Local variables-------------------------------
    5434              :  integer :: isign__, iscale__, nx, ny, nz, ldx, ldy, ldz, fftalg, fftalga, fftalgc, fftcache, nspinor, npw, nfft, gpu_mode__
    5435              :  integer(c_size_t) :: idat, ir, offset, bufsize
    5436              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
    5437              :  integer(c_size_t) :: ispinor, ipw, ifft, ig
    5438              :  logical :: transfer_ug, transfer_ur
    5439              :  integer, contiguous, pointer :: ig2ifft(:)
    5440              : #endif
    5441              : ! *************************************************************************
    5442              : 
    5443              :  !call wrtout(std_out, "in uplan_execute_gr_spc")
    5444            0 :  ABI_CHECK_IEQ(sp, uplan%kind, "Inconsistent kind!")
    5445              : 
    5446            0 :  ABI_DEFAULT(gpu_mode__, gpu_mode, 0)
    5447              : 
    5448            0 :  isign__ = +1; if (present(isign)) isign__ = isign
    5449            0 :  iscale__ = 0; if (present(iscale)) iscale__ = iscale
    5450              : 
    5451            0 :  fftalg = uplan%ngfft(7); fftcache = uplan%ngfft(8); fftalga = fftalg/100; fftalgc = mod(fftalg, 10)
    5452            0 :  nx = uplan%ngfft(1); ny = uplan%ngfft(2); nz = uplan%ngfft(3)
    5453            0 :  ldx = nx; ldy = ny; ldz = nz ! No augmentation, the caller does not support it.
    5454              : 
    5455              :  ! NVHPC does not reliably support mapping derived_type components
    5456            0 :  nspinor = uplan%nspinor; npw = uplan%npw; nfft = uplan%nfft
    5457              : 
    5458            0 :  if (uplan%gpu_option == ABI_GPU_DISABLED) then
    5459            0 :    select case (fftalga)
    5460              :    case (FFT_FFTW3)
    5461              :      call fftw3_fftug(fftalg, fftcache, int(uplan%npw), nx, ny, nz, ldx, ldy, ldz, uplan%nspinor*ndat, &
    5462              :                       uplan%istwfk, uplan%mgfft, uplan%kg_k, uplan%gbound, ug, ur, &
    5463            0 :                       isign=isign__, iscale=iscale__)
    5464              :    case (FFT_DFTI)
    5465              :      call dfti_fftug(fftalg, fftcache, int(uplan%npw), nx, ny, nz, ldx, ldy, ldz, uplan%nspinor*ndat, &
    5466              :                      uplan%istwfk, uplan%mgfft, uplan%kg_k, uplan%gbound, ug, ur, &
    5467            0 :                      isign=isign__, iscale=iscale__)
    5468              :    case default
    5469            0 :      ABI_ERROR(sjoin("Wrong fftalga:", itoa(fftalga)))
    5470              :    end select
    5471              : 
    5472              :    ! Multiply by e^{ik.r}
    5473            0 :    if (present(phase_r)) then
    5474            0 :      bufsize = int(nfft, c_size_t) * nspinor
    5475              :      !$OMP PARALLEL DO PRIVATE(offset) IF (ndat > 1)
    5476            0 :      do idat=1,ndat
    5477            0 :        offset = (idat - 1) * bufsize
    5478            0 :        do ir=1,bufsize
    5479            0 :          ur(offset + ir) = ur(offset + ir) * phase_r(ir)
    5480              :        end do
    5481              :      end do
    5482              :    end if
    5483              : 
    5484              :  else
    5485              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
    5486              :    ! Build plan if not yet done. note batch_size instead of ndat.
    5487              :    if (.not. c_associated(uplan%gpu_ctx_spc)) then
    5488              :      !call wrtout(std_out, sjoin("gr: Init plan with batch_size:", itoa(uplan%batch_size)))
    5489              :      call gpu_ctx_init(uplan%gpu_ctx_spc, uplan%ngfft, uplan%ngfft, uplan%batch_size, sp)
    5490              :    end if
    5491              : 
    5492              :    if (ndat /= uplan%batch_size) then
    5493              :      ! Have to rebuild the plan with batch_size == ndat.
    5494              :      !call wrtout(std_out, sjoin("gr: Init plan with ndat:", itoa(ndat)))
    5495              :      call gpu_ctx_free(uplan%gpu_ctx_spc)
    5496              :      call gpu_ctx_init(uplan%gpu_ctx_spc, uplan%ngfft, uplan%ngfft, ndat, sp)
    5497              :    end if
    5498              : 
    5499              :    uplan%batch_size = ndat
    5500              : 
    5501              :    transfer_ug = .False.; transfer_ur = .False.
    5502              :    if (gpu_mode__ /= 0) then
    5503              :      transfer_ug = .not. xomp_target_is_present(c_loc(ug))
    5504              :      transfer_ur = .not. xomp_target_is_present(c_loc(ur))
    5505              :      !$OMP TARGET ENTER DATA MAP(alloc:ug) IF (transfer_ug)
    5506              :      !$OMP TARGET UPDATE TO(ug) IF (transfer_ug)
    5507              :      !$OMP TARGET ENTER DATA MAP(alloc:ur) IF (transfer_ur)
    5508              :    end if
    5509              : 
    5510              :    bufsize = uplan%nfft * uplan%nspinor * ndat
    5511              :    call gpu_set_to_zero_complex_sp(ur, bufsize)
    5512              : 
    5513              :    ig2ifft => uplan%ig2ifft
    5514              :    !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(ifft, offset, ir, ig) COLLAPSE(3) MAP(to:ug, ig2ifft)
    5515              :    do idat=1,ndat
    5516              :      do ispinor=1,nspinor
    5517              :        do ipw=1,npw
    5518              :          ifft = ig2ifft(ipw)
    5519              :          offset = (idat-1) * nspinor + (ispinor-1)
    5520              :          ir = ifft + nfft * offset
    5521              :          ig = ipw  + npw  * offset
    5522              :          ur(ir) = ug(ig)
    5523              :        end do ! ipw
    5524              :      end do ! ispinor
    5525              :    end do ! idat
    5526              : 
    5527              :    !$OMP TARGET DATA USE_DEVICE_ADDR(ur)
    5528              :    call gpu_fftbox_c2c_ip(uplan%gpu_ctx_spc, int(uplan%nfft), ndat, isign__, iscale__, sp, c_loc(ur))
    5529              :    call gpu_ctx_synch(uplan%gpu_ctx_spc)
    5530              :    !$OMP END TARGET DATA
    5531              : 
    5532              :    ! Multiply by e^{ik.r}
    5533              :    if (present(phase_r)) then
    5534              :      bufsize = int(nfft, c_size_t) * nspinor
    5535              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(offset) COLLAPSE(2) MAP(to:ur, phase_r)
    5536              :      do idat=1,ndat
    5537              :        do ir=1,bufsize
    5538              :          offset = (idat - 1) * bufsize
    5539              :          ur(offset + ir) = ur(offset + ir) * phase_r(ir)
    5540              :        end do
    5541              :      end do
    5542              :    end if
    5543              : 
    5544              :    if (gpu_mode__ /= 0) then
    5545              :      !$OMP TARGET EXIT DATA MAP(delete:ug) IF (transfer_ug)
    5546              :      !$OMP TARGET UPDATE FROM(ur) IF (transfer_ur)
    5547              :      !$OMP TARGET EXIT DATA MAP(delete:ur) IF (transfer_ur)
    5548              :    end if
    5549              : #endif
    5550              :  end if
    5551              : 
    5552            0 : end subroutine uplan_execute_gr_spc
    5553              : !!***
    5554              : 
    5555              : !----------------------------------------------------------------------
    5556              : 
    5557              : !!****f* m_fft/uplan_execute_gr_dpc
    5558              : !! NAME
    5559              : !!  uplan_execute_gr_dpc
    5560              : !!
    5561              : !! FUNCTION
    5562              : !!
    5563              : !! INPUTS
    5564              : !!
    5565              : !! SOURCE
    5566              : 
    5567            0 : subroutine uplan_execute_gr_dpc(uplan, ndat, ug, ur, &
    5568              :                                 isign, iscale, gpu_mode, phase_r) ! optional
    5569              : 
    5570              : !Arguments ------------------------------------
    5571              :  class(uplan_t),target,intent(inout) :: uplan
    5572              :  integer,intent(in) :: ndat
    5573              :  complex(dp),target,intent(in) :: ug(uplan%npw*uplan%nspinor*ndat)
    5574              :  complex(dp),target,intent(out) :: ur(uplan%nfft*uplan%nspinor*ndat)
    5575              :  integer,optional,intent(in) :: isign, iscale, gpu_mode
    5576              :  complex(dp),optional,intent(in) :: phase_r(uplan%nfft*uplan%nspinor)
    5577              : 
    5578              : !Local variables-------------------------------
    5579              :  integer :: isign__, iscale__, nx, ny, nz, ldx, ldy, ldz, fftalg, fftalga, fftalgc, fftcache, nspinor, npw, nfft, gpu_mode__
    5580              :  integer(c_size_t) :: idat, ir, offset, bufsize
    5581              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
    5582              :  integer(c_size_t) :: ispinor, ipw, ifft, ig
    5583              :  logical :: transfer_ug, transfer_ur
    5584              :  integer, contiguous, pointer :: ig2ifft(:)
    5585              : #endif
    5586              : ! *************************************************************************
    5587              : 
    5588              :  !call wrtout(std_out, "in uplan_execute_gr_dpc")
    5589            0 :  ABI_CHECK_IEQ(dp, uplan%kind, "Inconsistent kind!")
    5590              : 
    5591            0 :  ABI_DEFAULT(gpu_mode__, gpu_mode, 0)
    5592              : 
    5593            0 :  isign__ = +1; if (present(isign)) isign__ = isign
    5594            0 :  iscale__ = 0; if (present(iscale)) iscale__ = iscale
    5595              : 
    5596            0 :  fftalg = uplan%ngfft(7); fftcache = uplan%ngfft(8); fftalga = fftalg/100; fftalgc = mod(fftalg, 10)
    5597            0 :  nx = uplan%ngfft(1); ny = uplan%ngfft(2); nz = uplan%ngfft(3)
    5598            0 :  ldx = nx; ldy = ny; ldz = nz ! No augmentation, the caller does not support it.
    5599              : 
    5600              :  ! NVHPC does not reliably support mapping derived_type components
    5601            0 :  nspinor = uplan%nspinor; npw = uplan%npw; nfft = uplan%nfft
    5602              : 
    5603            0 :  if (uplan%gpu_option == ABI_GPU_DISABLED) then
    5604            0 :    select case (fftalga)
    5605              :    case (FFT_FFTW3)
    5606              :      call fftw3_fftug(fftalg, fftcache, int(uplan%npw), nx, ny, nz, ldx, ldy, ldz, uplan%nspinor*ndat, &
    5607              :                       uplan%istwfk, uplan%mgfft, uplan%kg_k, uplan%gbound, ug, ur, &
    5608            0 :                       isign=isign__, iscale=iscale__)
    5609              :    case (FFT_DFTI)
    5610              :      call dfti_fftug(fftalg, fftcache, int(uplan%npw), nx, ny, nz, ldx, ldy, ldz, uplan%nspinor*ndat, &
    5611              :                      uplan%istwfk, uplan%mgfft, uplan%kg_k, uplan%gbound, ug, ur, &
    5612            0 :                      isign=isign__, iscale=iscale__)
    5613              :    case default
    5614            0 :      ABI_ERROR(sjoin("Wrong fftalga:", itoa(fftalga)))
    5615              :    end select
    5616              : 
    5617              :    ! Multiply by e^{ik.r}
    5618            0 :    if (present(phase_r)) then
    5619            0 :      bufsize = int(nfft, c_size_t) * nspinor
    5620              :      !$OMP PARALLEL DO PRIVATE(offset) IF (ndat > 1)
    5621            0 :      do idat=1,ndat
    5622            0 :        offset = (idat - 1) * bufsize
    5623            0 :        do ir=1,bufsize
    5624            0 :          ur(offset + ir) = ur(offset + ir) * phase_r(ir)
    5625              :        end do
    5626              :      end do
    5627              :    end if
    5628              : 
    5629              :  else
    5630              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
    5631              :    ! Build plan if not yet done. note batch_size instead of ndat.
    5632              :    if (.not. c_associated(uplan%gpu_ctx_dpc)) then
    5633              :      call gpu_ctx_init(uplan%gpu_ctx_dpc, uplan%ngfft, uplan%ngfft, uplan%batch_size, dp)
    5634              :    end if
    5635              : 
    5636              :    if (ndat /= uplan%batch_size) then
    5637              :      ! Have to rebuild the plan with batch_size == ndat.
    5638              :      call gpu_ctx_free(uplan%gpu_ctx_dpc)
    5639              :      call gpu_ctx_init(uplan%gpu_ctx_dpc, uplan%ngfft, uplan%ngfft, ndat, dp)
    5640              :    end if
    5641              : 
    5642              :    uplan%batch_size = ndat
    5643              : 
    5644              :    transfer_ug = .False.; transfer_ur = .False.
    5645              :    if (gpu_mode__ /= 0) then
    5646              :      transfer_ug = .not. xomp_target_is_present(c_loc(ug))
    5647              :      transfer_ur = .not. xomp_target_is_present(c_loc(ur))
    5648              :      !$OMP TARGET ENTER DATA MAP(alloc:ug) IF (transfer_ug)
    5649              :      !$OMP TARGET UPDATE TO(ug) IF (transfer_ug)
    5650              :      !$OMP TARGET ENTER DATA MAP(alloc:ur) IF (transfer_ur)
    5651              :    end if
    5652              : 
    5653              :    bufsize = uplan%nfft * uplan%nspinor * ndat
    5654              :    call gpu_set_to_zero_complex(ur, bufsize)
    5655              : 
    5656              :    ig2ifft => uplan%ig2ifft
    5657              :    !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(ifft, offset, ir, ig) COLLAPSE(3) MAP(to:ug, ig2ifft)
    5658              :    do idat=1,ndat
    5659              :      do ispinor=1,nspinor
    5660              :        do ipw=1,npw
    5661              :          ifft = ig2ifft(ipw)
    5662              :          offset = (idat-1) * nspinor + (ispinor-1)
    5663              :          ir = ifft + nfft * offset
    5664              :          ig = ipw  + npw  * offset
    5665              :          ur(ir) = ug(ig)
    5666              :        end do ! ipw
    5667              :      end do ! ispinor
    5668              :    end do ! idat
    5669              : 
    5670              :    !$OMP TARGET DATA USE_DEVICE_ADDR(ur)
    5671              :    call gpu_fftbox_c2c_ip(uplan%gpu_ctx_dpc, int(uplan%nfft), ndat, isign__, iscale__, dp, c_loc(ur))
    5672              :    call gpu_ctx_synch(uplan%gpu_ctx_dpc)
    5673              :    !$OMP END TARGET DATA
    5674              : 
    5675              :    ! Multiply by e^{ik.r}
    5676              :    if (present(phase_r)) then
    5677              :      bufsize = int(nfft, c_size_t) * nspinor
    5678              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(offset) COLLAPSE(2) MAP(to:ur, phase_r)
    5679              :      do idat=1,ndat
    5680              :        do ir=1,bufsize
    5681              :          offset = (idat - 1) * bufsize
    5682              :          ur(offset + ir) = ur(offset + ir) * phase_r(ir)
    5683              :        end do
    5684              :      end do
    5685              :    end if
    5686              : 
    5687              :    if (gpu_mode__ /= 0) then
    5688              :      !$OMP TARGET EXIT DATA MAP(delete:ug) IF (transfer_ug)
    5689              :      !$OMP TARGET UPDATE FROM(ur) IF (transfer_ur)
    5690              :      !$OMP TARGET EXIT DATA MAP(delete:ur) IF (transfer_ur)
    5691              :    end if
    5692              : #endif
    5693              :  end if
    5694              : 
    5695            0 : end subroutine uplan_execute_gr_dpc
    5696              : !!***
    5697              : 
    5698              : !----------------------------------------------------------------------
    5699              : 
    5700              : !!****f* m_fft/uplan_execute_rg_spc
    5701              : !! NAME
    5702              : !!  uplan_execute_rg_spc
    5703              : !!
    5704              : !! FUNCTION
    5705              : !!
    5706              : !! INPUTS
    5707              : !!
    5708              : !! SOURCE
    5709              : 
    5710            0 : subroutine uplan_execute_rg_spc(uplan, ndat, ur, ug, &
    5711              :                                 isign, iscale, gpu_mode, phase_r) ! optional
    5712              : 
    5713              : !Arguments ------------------------------------
    5714              :  class(uplan_t),target,intent(inout) :: uplan
    5715              :  integer,intent(in) :: ndat
    5716              :  complex(sp),target,intent(inout) :: ur(uplan%nfft*uplan%nspinor*ndat)
    5717              :  complex(sp),target,intent(out) :: ug(uplan%npw*uplan%nspinor*ndat)
    5718              :  integer,optional,intent(in) :: isign, iscale, gpu_mode
    5719              :  complex(sp),optional,intent(in) :: phase_r(uplan%nfft*uplan%nspinor)
    5720              : 
    5721              : !Local variables-------------------------------
    5722              :  integer :: isign__, iscale__, nx, ny, nz, ldx, ldy, ldz, fftalg, fftalga, fftalgc, fftcache, nspinor, npw, gpu_mode__, nfft
    5723              :  integer(c_size_t) :: idat, ir, offset, bufsize
    5724              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
    5725              :  logical :: transfer_ug, transfer_ur
    5726              :  integer(c_size_t) :: ifft, ig, ispinor, ipw
    5727              :  integer, contiguous, pointer :: ifft2ig(:)
    5728              : #endif
    5729              : ! *************************************************************************
    5730              : 
    5731              :  !call wrtout(std_out, "in uplan_execute_rg_spc")
    5732            0 :  ABI_CHECK_IEQ(sp, uplan%kind, "Inconsistent kind!")
    5733              : 
    5734            0 :  ABI_DEFAULT(gpu_mode__, gpu_mode, 0)
    5735              : 
    5736            0 :  isign__ = -1; if (present(isign)) isign__ = isign
    5737            0 :  iscale__ = 1; if (present(iscale)) iscale__ = iscale
    5738              : 
    5739            0 :  fftalg = uplan%ngfft(7); fftcache = uplan%ngfft(8); fftalga = fftalg/100; fftalgc = mod(fftalg, 10)
    5740            0 :  nx = uplan%ngfft(1); ny = uplan%ngfft(2); nz = uplan%ngfft(3)
    5741            0 :  ldx = nx; ldy = ny; ldz = nz ! No augmentation, the caller does not support it.
    5742              : 
    5743              :  ! NVHPC does not reliably support mapping derived_type components
    5744            0 :  nspinor = uplan%nspinor; npw = uplan%npw; nfft = uplan%nfft
    5745              : 
    5746            0 :  if (uplan%gpu_option == ABI_GPU_DISABLED) then
    5747              :    ! Multiply by e^{ik.r}
    5748            0 :    if (present(phase_r)) then
    5749            0 :      bufsize = int(nfft, c_size_t) * nspinor
    5750              :      !$OMP PARALLEL DO PRIVATE(offset) IF (ndat > 1)
    5751            0 :      do idat=1,ndat
    5752            0 :        offset = (idat - 1) * bufsize
    5753            0 :        do ir=1,bufsize
    5754            0 :          ur(offset + ir) = ur(offset + ir) * phase_r(ir)
    5755              :        end do
    5756              :      end do
    5757              :    end if
    5758              : 
    5759            0 :    select case (fftalga)
    5760              :    case (FFT_FFTW3)
    5761              :      call fftw3_fftur(fftalg, fftcache, int(uplan%npw), nx, ny, nz, ldx, ldy, ldz, uplan%nspinor*ndat, uplan%istwfk, uplan%mgfft, &
    5762            0 :                       uplan%kg_k, uplan%gbound, ur, ug, isign=isign__, iscale=iscale__)
    5763              :    case (FFT_DFTI)
    5764              :      call dfti_fftur(fftalg, fftcache, int(uplan%npw), nx, ny, nz, ldx, ldy, ldz, uplan%nspinor*ndat, uplan%istwfk, uplan%mgfft, &
    5765            0 :                      uplan%kg_k, uplan%gbound, ur, ug, isign=isign__, iscale=iscale__)
    5766              :    case default
    5767            0 :      ABI_ERROR(sjoin("Wrong fftalga:", itoa(fftalga)))
    5768              :    end select
    5769              : 
    5770              :  else
    5771              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
    5772              :    ! Build plan if not yet done. note batch_size instead of ndat.
    5773              :    if (.not. c_associated(uplan%gpu_ctx_spc)) then
    5774              :      !call wrtout(std_out, sjoin("rg: Init plan with batch_size:", itoa(uplan%batch_size)))
    5775              :      call gpu_ctx_init(uplan%gpu_ctx_spc, uplan%ngfft, uplan%ngfft, uplan%batch_size, sp)
    5776              :    end if
    5777              : 
    5778              :    if (ndat /= uplan%batch_size) then
    5779              :      ! Have to rebuild the plan with batch_size == ndat.
    5780              :      !call wrtout(std_out, sjoin("rg: Init plan with ndat:", itoa(ndat)))
    5781              :      call gpu_ctx_free(uplan%gpu_ctx_spc)
    5782              :      call gpu_ctx_init(uplan%gpu_ctx_spc, uplan%ngfft, uplan%ngfft, ndat, sp)
    5783              :    end if
    5784              : 
    5785              :    uplan%batch_size = ndat
    5786              : 
    5787              :    transfer_ug = .False.; transfer_ur = .False.
    5788              :    if (gpu_mode__ /= 0) then
    5789              :      transfer_ug = .not. xomp_target_is_present(c_loc(ug))
    5790              :      transfer_ur = .not. xomp_target_is_present(c_loc(ur))
    5791              :      !$OMP TARGET ENTER DATA MAP(alloc:ug) IF(transfer_ug)
    5792              :      !$OMP TARGET ENTER DATA MAP(alloc:ur) IF(transfer_ur)
    5793              :      !$OMP TARGET UPDATE TO(ur) IF(transfer_ur)
    5794              :    end if
    5795              : 
    5796              :    ! Multiply by e^{ik.r}
    5797              :    if (present(phase_r)) then
    5798              :      bufsize = int(nfft, c_size_t) * nspinor
    5799              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(offset) COLLAPSE(2) MAP(to:ur, phase_r)
    5800              :      do idat=1,ndat
    5801              :        do ir=1,bufsize
    5802              :          offset = (idat - 1) * bufsize
    5803              :          ur(offset + ir) = ur(offset + ir) * phase_r(ir)
    5804              :        end do
    5805              :      end do
    5806              :    end if
    5807              : 
    5808              :    !$OMP TARGET DATA USE_DEVICE_ADDR(ur)
    5809              :    call gpu_fftbox_c2c_ip(uplan%gpu_ctx_spc, int(uplan%nfft), ndat, isign__, iscale__, sp, c_loc(ur))
    5810              :    call gpu_ctx_synch(uplan%gpu_ctx_spc)
    5811              :    !$OMP END TARGET DATA
    5812              : 
    5813              :    ifft2ig => uplan%ifft2ig
    5814              :    !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(ipw, offset, ir, ig) COLLAPSE(3) MAP(to:ug, ur, ifft2ig)
    5815              :    do idat=1,ndat
    5816              :      do ispinor=1,nspinor
    5817              :        do ifft = 1, nfft
    5818              :          ipw = ifft2ig(ifft); if (ipw == 0) cycle
    5819              :          offset = (idat-1) * nspinor + (ispinor-1)
    5820              :          ir = ifft + nfft * offset
    5821              :          ig = ipw  + npw  * offset
    5822              :          ug(ig) = ur(ir)
    5823              :        end do ! ipw
    5824              :      end do ! ispinor
    5825              :    end do ! idat
    5826              : 
    5827              :    if (gpu_mode__ /= 0) then
    5828              :      !$OMP TARGET UPDATE FROM(ug) IF(transfer_ug)
    5829              :      !$OMP TARGET EXIT DATA MAP(delete:ug) IF(transfer_ug)
    5830              :      !$OMP TARGET EXIT DATA MAP(delete:ur) IF(transfer_ur)
    5831              :    end if
    5832              : 
    5833              : #endif
    5834              :  end if
    5835              : 
    5836            0 : end subroutine uplan_execute_rg_spc
    5837              : !!***
    5838              : 
    5839              : !----------------------------------------------------------------------
    5840              : 
    5841              : !!****f* m_fft/uplan_execute_rg_dpc
    5842              : !! NAME
    5843              : !!  uplan_execute_rg_dpc
    5844              : !!
    5845              : !! FUNCTION
    5846              : !!
    5847              : !! INPUTS
    5848              : !!
    5849              : !! SOURCE
    5850              : 
    5851            0 : subroutine uplan_execute_rg_dpc(uplan, ndat, ur, ug, &
    5852              :                                 isign, iscale, gpu_mode, phase_r) ! optional
    5853              : 
    5854              : !Arguments ------------------------------------
    5855              :  class(uplan_t),target,intent(inout) :: uplan
    5856              :  integer,intent(in) :: ndat
    5857              :  complex(dp),target,intent(inout) :: ur(uplan%nfft*uplan%nspinor*ndat)
    5858              :  complex(dp),target,intent(out) :: ug(uplan%npw*uplan%nspinor*ndat)
    5859              :  integer,optional,intent(in) :: isign, iscale, gpu_mode
    5860              :  complex(dp),optional,intent(in) :: phase_r(uplan%nfft*uplan%nspinor)
    5861              : 
    5862              : !Local variables-------------------------------
    5863              :  integer :: isign__, iscale__, nx, ny, nz, ldx, ldy, ldz, fftalg, fftalga, fftalgc, fftcache, nspinor, npw, nfft, gpu_mode__
    5864              :  integer(c_size_t) :: idat, ir, offset, bufsize
    5865              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
    5866              :  integer(c_size_t) :: ispinor, ipw, ifft, ig
    5867              :  logical :: transfer_ug, transfer_ur
    5868              :  integer, contiguous, pointer :: ifft2ig(:)
    5869              : #endif
    5870              : ! *************************************************************************
    5871              : 
    5872              :  !call wrtout(std_out, "in uplan_execute_rg_dpc")
    5873            0 :  ABI_CHECK_IEQ(dp, uplan%kind, "Inconsistent kind!")
    5874              : 
    5875            0 :  ABI_DEFAULT(gpu_mode__, gpu_mode, 0)
    5876              : 
    5877            0 :  isign__ = -1; if (present(isign)) isign__ = isign
    5878            0 :  iscale__ = 1; if (present(iscale)) iscale__ = iscale
    5879              : 
    5880            0 :  fftalg = uplan%ngfft(7); fftcache = uplan%ngfft(8); fftalga = fftalg/100; fftalgc = mod(fftalg, 10)
    5881            0 :  nx = uplan%ngfft(1); ny = uplan%ngfft(2); nz = uplan%ngfft(3)
    5882            0 :  ldx = nx; ldy = ny; ldz = nz ! No augmentation, the caller does not support it.
    5883              : 
    5884              :  ! NVHPC does not reliably support mapping derived_type components
    5885            0 :  nspinor = uplan%nspinor; npw = uplan%npw; nfft = uplan%nfft
    5886              : 
    5887            0 :  if (uplan%gpu_option == ABI_GPU_DISABLED) then
    5888              : 
    5889              :    ! Multiply by e^{ik.r}
    5890            0 :    if (present(phase_r)) then
    5891            0 :      bufsize = int(nfft, c_size_t) * nspinor
    5892              :      !$OMP PARALLEL DO PRIVATE(offset) IF (ndat > 1)
    5893            0 :      do idat=1,ndat
    5894            0 :        offset = (idat - 1) * bufsize
    5895            0 :        do ir=1,bufsize
    5896            0 :          ur(offset + ir) = ur(offset + ir) * phase_r(ir)
    5897              :        end do
    5898              :      end do
    5899              :    end if
    5900              : 
    5901            0 :    select case (fftalga)
    5902              :    case (FFT_FFTW3)
    5903              :      call fftw3_fftur(fftalg, fftcache, int(uplan%npw), nx, ny, nz, ldx, ldy, ldz, uplan%nspinor*ndat, uplan%istwfk, uplan%mgfft, &
    5904            0 :                       uplan%kg_k, uplan%gbound, ur, ug, isign=isign__, iscale=iscale__)
    5905              :    case (FFT_DFTI)
    5906              :      call dfti_fftur(fftalg, fftcache, int(uplan%npw), nx, ny, nz, ldx, ldy, ldz, uplan%nspinor*ndat, uplan%istwfk, uplan%mgfft, &
    5907            0 :                      uplan%kg_k, uplan%gbound, ur, ug, isign=isign__, iscale=iscale__)
    5908              :    case default
    5909            0 :      ABI_ERROR(sjoin("Wrong fftalga:", itoa(fftalga)))
    5910              :    end select
    5911              : 
    5912              :  else
    5913              : #if defined HAVE_GPU_CUDA && defined HAVE_OPENMP_OFFLOAD
    5914              :    ! Build plan if not yet done. note batch_size instead of ndat.
    5915              :    if (.not. c_associated(uplan%gpu_ctx_dpc)) then
    5916              :      call gpu_ctx_init(uplan%gpu_ctx_dpc, uplan%ngfft, uplan%ngfft, uplan%batch_size, dp)
    5917              :    end if
    5918              : 
    5919              :    if (ndat /= uplan%batch_size) then
    5920              :      ! Have to rebuild the plan with batch_size == ndat.
    5921              :      call gpu_ctx_free(uplan%gpu_ctx_dpc)
    5922              :      call gpu_ctx_init(uplan%gpu_ctx_dpc, uplan%ngfft, uplan%ngfft, ndat, dp)
    5923              :    end if
    5924              : 
    5925              :    uplan%batch_size = ndat
    5926              : 
    5927              :    transfer_ug = .False.; transfer_ur = .False.
    5928              :    if (gpu_mode__ /= 0) then
    5929              :      transfer_ug = .not. xomp_target_is_present(c_loc(ug))
    5930              :      transfer_ur = .not. xomp_target_is_present(c_loc(ur))
    5931              :      !$OMP TARGET ENTER DATA MAP(alloc:ug) IF(transfer_ug)
    5932              :      !$OMP TARGET ENTER DATA MAP(alloc:ur) IF(transfer_ur)
    5933              :      !$OMP TARGET UPDATE TO(ur) IF(transfer_ur)
    5934              :    end if
    5935              : 
    5936              :    ! Multiply by e^{ik.r}
    5937              :    if (present(phase_r)) then
    5938              :      bufsize = int(nfft, c_size_t) * nspinor
    5939              :      !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(offset) COLLAPSE(2) MAP(to:ur, phase_r)
    5940              :      do idat=1,ndat
    5941              :        do ir=1,bufsize
    5942              :          offset = (idat - 1) * bufsize
    5943              :          ur(offset + ir) = ur(offset + ir) * phase_r(ir)
    5944              :        end do
    5945              :      end do
    5946              :    end if
    5947              : 
    5948              :    !$OMP TARGET DATA USE_DEVICE_ADDR(ur)
    5949              :    call gpu_fftbox_c2c_ip(uplan%gpu_ctx_dpc, int(uplan%nfft), ndat, isign__, iscale__, dp, c_loc(ur))
    5950              :    call gpu_ctx_synch(uplan%gpu_ctx_dpc)
    5951              :    !$OMP END TARGET DATA
    5952              : 
    5953              :    ifft2ig => uplan%ifft2ig
    5954              :    !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(ipw, offset, ir, ig) COLLAPSE(3) MAP(to:ug, ur, ifft2ig)
    5955              :    do idat=1,ndat
    5956              :      do ispinor=1,nspinor
    5957              :        do ifft = 1, nfft
    5958              :          ipw = ifft2ig(ifft); if (ipw == 0) cycle
    5959              :          offset = (idat-1) * nspinor + (ispinor-1)
    5960              :          ir = ifft + nfft * offset
    5961              :          ig = ipw  + npw  * offset
    5962              :          ug(ig) = ur(ir)
    5963              :        end do ! ipw
    5964              :      end do ! ispinor
    5965              :    end do ! idat
    5966              : 
    5967              :    if (gpu_mode__ /= 0) then
    5968              :      !$OMP TARGET UPDATE FROM(ug) IF(transfer_ug)
    5969              :      !$OMP TARGET EXIT DATA MAP(delete:ug) IF(transfer_ug)
    5970              :      !$OMP TARGET EXIT DATA MAP(delete:ur) IF(transfer_ur)
    5971              :    end if
    5972              : #endif
    5973              :  end if
    5974              : 
    5975            0 : end subroutine uplan_execute_rg_dpc
    5976              : !!***
    5977              : 
    5978            0 : end module m_fft
    5979              : !!***
        

Generated by: LCOV version 2.3-1