LCOV - code coverage report
Current view: top level - src/66_wfs - m_invovl.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 90.2 % 307 277
Test Date: 2026-11-10 12:08:57 Functions: 63.6 % 11 7
Branches: 61.3 % 814 499

             Branch data     Line data    Source code
       1                 :             : !!****m* ABINIT/m_invovl
       2                 :             : !! NAME
       3                 :             : !!  m_invovl
       4                 :             : !!
       5                 :             : !! FUNCTION
       6                 :             : !!  Provides functions to invert the overlap matrix S. Used by Chebyshev in PAW
       7                 :             : !!  See paper by A. Levitt and M. Torrent for details
       8                 :             : !!  S = 1 + projs * s_projs * projs'
       9                 :             : !!  S^-1 = 1 + projs * inv_s_projs * projs', with
      10                 :             : !!  inv_s_projs = - (s_projs^-1 + projs'*projs)^-1
      11                 :             : !!
      12                 :             : !! COPYRIGHT
      13                 :             : !! Copyright (C) 2013-2026 ABINIT group (AL)
      14                 :             : !! This file is distributed under the terms of the
      15                 :             : !! GNU General Public License, see ~abinit/COPYING
      16                 :             : !! or http://www.gnu.org/copyleft/gpl.txt .
      17                 :             : !!
      18                 :             : !! SOURCE
      19                 :             : 
      20                 :             : #if defined HAVE_CONFIG_H
      21                 :             : #include "config.h"
      22                 :             : #endif
      23                 :             : 
      24                 :             : #include "abi_common.h"
      25                 :             : 
      26                 :             : ! nvtx related macro definition
      27                 :             : #include "nvtx_macros.h"
      28                 :             : 
      29                 :             : MODULE m_invovl
      30                 :             : 
      31                 :             :  use defs_basis
      32                 :             :  use m_errors
      33                 :             :  use m_xmpi
      34                 :             :  use m_xomp
      35                 :             :  use m_abicore
      36                 :             :  use m_abi_linalg
      37                 :             : 
      38                 :             :  use defs_abitypes, only : mpi_type
      39                 :             :  use m_time,        only : timab
      40                 :             :  use m_hamiltonian, only : gs_hamiltonian_type
      41                 :             :  use m_bandfft_kpt, only : bandfft_kpt_get_ikpt
      42                 :             :  use m_pawcprj,     only : pawcprj_type, pawcprj_alloc, pawcprj_free, pawcprj_axpby
      43                 :             :  use m_gemm_nonlop_projectors, only : gemm_nonlop_use_gemm
      44                 :             :  use m_nonlop,      only : nonlop
      45                 :             :  use m_prep_kgb,    only : prep_nonlop
      46                 :             : 
      47                 :             : #ifdef HAVE_FC_ISO_C_BINDING
      48                 :             : ! FIXME Don't know what's wrong with GCC when OpenMP GPU Offload is enabled here...
      49                 :             : #ifdef FC_GNU
      50                 :             :  use, intrinsic :: iso_c_binding, only : c_int32_t, c_int64_t, c_float, c_double, c_size_t, c_loc
      51                 :             : #else
      52                 :             :  use, intrinsic :: iso_c_binding, only : c_ptr, c_int32_t, c_int64_t, c_float, c_double, c_size_t, c_loc
      53                 :             : #endif
      54                 :             : #endif
      55                 :             : 
      56                 :             : #if defined(HAVE_GPU_MARKERS)
      57                 :             :  use m_nvtx_data
      58                 :             : #endif
      59                 :             : 
      60                 :             : #ifdef HAVE_GPU
      61                 :             :   use m_gpu_toolbox
      62                 :             : #endif
      63                 :             : 
      64                 :             : #ifdef HAVE_KOKKOS
      65                 :             :  use m_manage_kokkos, only : add_array_kokkos
      66                 :             : #endif
      67                 :             : 
      68                 :             :  implicit none
      69                 :             : 
      70                 :             :  private
      71                 :             : 
      72                 :             : !public procedures.
      73                 :             :  public :: init_invovl
      74                 :             :  public :: make_invovl
      75                 :             :  public :: apply_invovl
      76                 :             :  public :: destroy_invovl
      77                 :             : 
      78                 :             :  ! Those routines are here to assess memory requirements
      79                 :             :  public :: invovl_ompgpu_work_mem
      80                 :             :  public :: invovl_ompgpu_static_mem
      81                 :             : !!***
      82                 :             : 
      83                 :             : !!****t* m_invovl/invovl_kpt_type
      84                 :             : !! NAME
      85                 :             : !! invovl_kpt_type
      86                 :             : !!
      87                 :             : !! FUNCTION
      88                 :             : !! Contains information needed to invert the overlap matrix S
      89                 :             : !!
      90                 :             : !! SOURCE
      91                 :             : 
      92                 :             : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
      93                 :             : 
      94                 :             :  type, public :: invovl_kpt_type
      95                 :             : 
      96                 :             :    integer(kind=c_int32_t) :: nprojs
      97                 :             :    !  total number of projectors
      98                 :             :    !    nlmn for a specific atom = count(indlmn(3,:,itypat)>0)
      99                 :             :    !  A value of -1 means that the following arrays are not allocated
     100                 :             : 
     101                 :             :    real(kind=c_double), allocatable :: gram_projs(:,:,:)
     102                 :             :    ! gram_projs(cplx, nprojs, nprojs)
     103                 :             :    ! projs' * projs
     104                 :             : 
     105                 :             :    real(kind=c_double), allocatable :: inv_sij(:,:,:,:)
     106                 :             :    ! inv_sij(cplx, lmnmax, lmnmax, ntypat)
     107                 :             :    ! inverse of ham%sij
     108                 :             : 
     109                 :             :    real(kind=c_double), allocatable :: inv_s_approx(:,:,:,:)
     110                 :             :    ! inv_s_approx(cplx, lmnmax, lmnmax, ntypat)
     111                 :             :    ! preconditionner
     112                 :             : 
     113                 :             :  end type invovl_kpt_type
     114                 :             : 
     115                 :             :  !> companion type to invovl_kpt_type to pass data to gpu/cuda
     116                 :             :  type, bind(c), public :: invovl_kpt_gpu_type
     117                 :             : 
     118                 :             :    integer(kind=c_int32_t) :: nprojs
     119                 :             :    !  total number of projectors
     120                 :             :    !    nlmn for a specific atom = count(indlmn(3,:,itypat)>0)
     121                 :             :    !  A value of -1 means that the following arrays are not allocated
     122                 :             : 
     123                 :             :    type(c_ptr) :: gram_projs
     124                 :             :    ! gram_projs(cplx, nprojs, nprojs)
     125                 :             :    ! projs' * projs
     126                 :             : 
     127                 :             :    integer(kind=c_int32_t) :: gram_projs_dim(3)
     128                 :             : 
     129                 :             :    type(c_ptr) :: inv_sij
     130                 :             :    ! inv_sij(cplx, lmnmax, lmnmax, ntypat)
     131                 :             :    ! inverse of ham%sij
     132                 :             : 
     133                 :             :    integer(kind=c_int32_t) :: inv_sij_dim(4)
     134                 :             : 
     135                 :             :    type(c_ptr) :: inv_s_approx
     136                 :             :    ! inv_s_approx(cplx, lmnmax, lmnmax, ntypat)
     137                 :             :    ! preconditionner
     138                 :             : 
     139                 :             :    integer(kind=c_int32_t) :: inv_s_approx_dim(4)
     140                 :             : 
     141                 :             :  end type invovl_kpt_gpu_type
     142                 :             : 
     143                 :             : #else
     144                 :             : 
     145                 :             : type, public :: invovl_kpt_type
     146                 :             : 
     147                 :             :    integer :: nprojs
     148                 :             :    !  total number of projectors
     149                 :             :    !    nlmn for a specific atom = count(indlmn(3,:,itypat)>0)
     150                 :             :    !  A value of -1 means that the following arrays are not allocated
     151                 :             : 
     152                 :             :    real(dp), allocatable :: gram_projs(:,:,:)
     153                 :             :    ! gram_projs(cplx, nprojs, nprojs)
     154                 :             :    ! projs' * projs
     155                 :             : 
     156                 :             :    real(dp), allocatable :: inv_sij(:,:,:,:)
     157                 :             :    ! inv_sij(cplx, lmnmax, lmnmax, ntypat)
     158                 :             :    ! inverse of ham%sij
     159                 :             : 
     160                 :             :    real(dp), allocatable :: inv_s_approx(:,:,:,:)
     161                 :             :    ! inv_s_approx(cplx, lmnmax, lmnmax, ntypat)
     162                 :             :    ! preconditionner
     163                 :             : 
     164                 :             : end type invovl_kpt_type
     165                 :             : 
     166                 :             : #endif
     167                 :             : 
     168                 :             : !!***
     169                 :             : 
     170                 :             :   integer, parameter :: tim_nonlop = 13
     171                 :             : 
     172                 :             :   integer, parameter :: &
     173                 :             :     & timer_apply_inv_ovl_opernla = 1630, &
     174                 :             :     & timer_apply_inv_ovl_opernlb = 1631, &
     175                 :             :     & timer_apply_inv_ovl_inv_s   = 1632
     176                 :             : 
     177                 :             :  type(invovl_kpt_type), public,save,allocatable, target :: invovl_kpt(:)
     178                 :             : #ifdef HAVE_OPENMP_OFFLOAD
     179                 :             :  real(dp), ABI_CONTIGUOUS pointer :: current_gram_projs(:,:,:)
     180                 :             :  real(dp), ABI_CONTIGUOUS pointer :: current_inv_sij(:,:,:,:)
     181                 :             :  real(dp), ABI_CONTIGUOUS pointer :: current_inv_s_approx(:,:,:,:)
     182                 :             :  real(dp),allocatable, target :: proj_ompgpu(:,:,:)
     183                 :             :  real(dp),allocatable, target :: sm1proj_ompgpu(:,:,:)
     184                 :             :  real(dp),allocatable, target :: PtPsm1proj_ompgpu(:,:,:)
     185                 :             :  !Module variable keeping track of which K-point data is so=tored on GPU
     186                 :             :  integer, save :: current_ikpt_in_gpu=-1
     187                 :             :  integer, save :: gpu_initialized=0
     188                 :             :  integer, save :: mod__cplx=0, mod__nprojs=0
     189                 :             : #endif
     190                 :             : 
     191                 :             : #if defined(HAVE_GPU_CUDA)
     192                 :             : 
     193                 :             :  !> this interface is only useful when gpu is enabled
     194                 :             :  !! these functions are defined in 46_manage_gpu/gpu_apply_invovl_inner.cu
     195                 :             :  !! these functions are entry point for calling cuda implemented functions
     196                 :             :  interface
     197                 :             : 
     198                 :             :    !> allocate GPU workspace for apply_invovl
     199                 :             :    subroutine f_gpu_apply_invovl_inner_alloc(proj_dim, ntypat, realloc) bind(c, name='gpu_apply_invovl_inner_alloc')
     200                 :             :      use, intrinsic :: iso_c_binding
     201                 :             :      integer(kind=c_int32_t),        intent(in) :: proj_dim(3)
     202                 :             :      integer(kind=c_int32_t), value, intent(in) :: ntypat
     203                 :             :      integer(kind=c_int32_t), value, intent(in) :: realloc
     204                 :             :    end subroutine f_gpu_apply_invovl_inner_alloc
     205                 :             : 
     206                 :             :    !> deallocate GPU workspace for apply_invovl
     207                 :             :    subroutine f_gpu_apply_invovl_inner_dealloc() bind(c, name='gpu_apply_invovl_inner_dealloc')
     208                 :             :    end subroutine f_gpu_apply_invovl_inner_dealloc
     209                 :             : 
     210                 :             :    !> allocate GPU workspace for make_invovl (sij and s_approx)
     211                 :             :    subroutine f_gpu_apply_invovl_matrix_alloc(cplx, nprojs, lmnmax, ntypat, realloc) bind(c, name='gpu_apply_invovl_matrix_alloc')
     212                 :             :      use, intrinsic :: iso_c_binding
     213                 :             :      integer(kind=c_int32_t), value, intent(in) :: cplx
     214                 :             :      integer(kind=c_int32_t), value, intent(in) :: nprojs
     215                 :             :      integer(kind=c_int32_t), value, intent(in) :: ntypat
     216                 :             :      integer(kind=c_int32_t), value, intent(in) :: lmnmax
     217                 :             :      integer(kind=c_int32_t), value, intent(in) :: realloc
     218                 :             :    end subroutine f_gpu_apply_invovl_matrix_alloc
     219                 :             : 
     220                 :             :    !> deallocate GPU workspace for make_invovl (sij and s_approx)
     221                 :             :    subroutine f_gpu_apply_invovl_matrix_dealloc() bind(c, name='gpu_apply_invovl_matrix_dealloc')
     222                 :             :    end subroutine f_gpu_apply_invovl_matrix_dealloc
     223                 :             : 
     224                 :             :    !> init data for GPU
     225                 :             :    subroutine f_gpu_init_invovl_data(indlmn_dim, indlmn_ptr) bind(c, name='init_invovl_data')
     226                 :             :      use, intrinsic :: iso_c_binding
     227                 :             :      integer(kind=c_int32_t),        intent(in)    :: indlmn_dim(3)
     228                 :             :      type(c_ptr)            , value                :: indlmn_ptr
     229                 :             :    end subroutine f_gpu_init_invovl_data
     230                 :             : 
     231                 :             :    !> upload inverse overlap matrices
     232                 :             :    subroutine f_upload_inverse_overlap(invovl_gpu, cplx, nprojs, lmnmax, ntypat) bind(c, name='upload_inverse_overlap')
     233                 :             :      use, intrinsic :: iso_c_binding
     234                 :             :      import invovl_kpt_gpu_type
     235                 :             :      type(invovl_kpt_gpu_type), value, intent(in) :: invovl_gpu
     236                 :             :      integer(kind=c_int32_t),   value, intent(in) :: cplx
     237                 :             :      integer(kind=c_int32_t),   value, intent(in) :: nprojs
     238                 :             :      integer(kind=c_int32_t),   value, intent(in) :: lmnmax
     239                 :             :      integer(kind=c_int32_t),   value, intent(in) :: ntypat
     240                 :             :    end subroutine f_upload_inverse_overlap
     241                 :             : 
     242                 :             :    !> solve_inner on GPU
     243                 :             :    subroutine f_solve_inner_gpu(proj_dim, proj_ptr, sm1proj_ptr, ptp_sm1proj_ptr, &
     244                 :             :      & nattyp_dim, nattyp_ptr, ntypat, lmnmax, cplx, block_sliced) bind(c, name='solve_inner_gpu')
     245                 :             : 
     246                 :             :      use, intrinsic :: iso_c_binding
     247                 :             :      integer(kind=c_int32_t),        intent(in) :: proj_dim(3)
     248                 :             :      type(c_ptr)            , value             :: proj_ptr
     249                 :             :      type(c_ptr)            , value             :: sm1proj_ptr
     250                 :             :      type(c_ptr)            , value             :: ptp_sm1proj_ptr
     251                 :             :      integer(kind=c_int32_t), value, intent(in) :: nattyp_dim
     252                 :             :      type(c_ptr)            , value             :: nattyp_ptr
     253                 :             :      integer(kind=c_int32_t), value, intent(in) :: ntypat
     254                 :             :      integer(kind=c_int32_t), value, intent(in) :: lmnmax
     255                 :             :      integer(kind=c_int32_t), value, intent(in) :: cplx
     256                 :             :      integer(kind=c_int32_t), value, intent(in) :: block_sliced
     257                 :             :    end subroutine f_solve_inner_gpu
     258                 :             : 
     259                 :             :  end interface
     260                 :             : 
     261                 :             : #endif
     262                 :             : 
     263                 :             : CONTAINS
     264                 :             : 
     265                 :             : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
     266                 :             : !!****f* m_invovl/make_invovl_kpt_gpu
     267                 :             : !! NAME
     268                 :             : !! make_invovl_kpt
     269                 :             : !!
     270                 :             : !! FUNCTION
     271                 :             : !! Create a invovl_pkt_gpu_type from a cpu counter part for cuda interoperability
     272                 :             : !! SOURCE
     273                 :             :   function make_invovl_kpt_gpu(invovl) result(invovl_gpu)
     274                 :             :     type(invovl_kpt_type), intent(inout),target :: invovl
     275                 :             :     type(invovl_kpt_gpu_type)                   :: invovl_gpu
     276                 :             : 
     277                 :             :     invovl_gpu%nprojs = invovl%nprojs
     278                 :             : 
     279                 :             :     invovl_gpu%gram_projs = c_loc(invovl%gram_projs(1,1,1))
     280                 :             :     invovl_gpu%gram_projs_dim = (/ &
     281                 :             :       & size(invovl%gram_projs,1), &
     282                 :             :       & size(invovl%gram_projs,2), &
     283                 :             :       & size(invovl%gram_projs,3)  &
     284                 :             :       & /)
     285                 :             : 
     286                 :             :     invovl_gpu%inv_sij = c_loc(invovl%inv_sij(1,1,1,1))
     287                 :             :     invovl_gpu%inv_sij_dim = (/ &
     288                 :             :       & size(invovl%inv_sij,1), &
     289                 :             :       & size(invovl%inv_sij,2), &
     290                 :             :       & size(invovl%inv_sij,3), &
     291                 :             :       & size(invovl%inv_sij,4)  &
     292                 :             :       & /)
     293                 :             : 
     294                 :             :     invovl_gpu%inv_s_approx = c_loc(invovl%inv_s_approx(1,1,1,1))
     295                 :             :     invovl_gpu%inv_s_approx_dim = (/ &
     296                 :             :       & size(invovl%inv_s_approx,1), &
     297                 :             :       & size(invovl%inv_s_approx,2), &
     298                 :             :       & size(invovl%inv_s_approx,3), &
     299                 :             :       & size(invovl%inv_s_approx,4)  &
     300                 :             :       & /)
     301                 :             : 
     302                 :             :   end function make_invovl_kpt_gpu
     303                 :             : !!***
     304                 :             : #endif
     305                 :             : 
     306                 :             : #ifdef HAVE_OPENMP_OFFLOAD
     307                 :             : 
     308                 :             :  subroutine alloc_ompgpu_buffers(cplx,nprojs,nspinor,ndat)
     309                 :             :   integer,intent(in) :: cplx,nprojs,nspinor,ndat
     310                 :             : 
     311                 :             :   if(gpu_initialized == 0 .or. mod__cplx/=cplx .or. mod__nprojs/=nprojs) then
     312                 :             : 
     313                 :             :     if(gpu_initialized==1) then
     314                 :             :       ABI_FREE(proj_ompgpu)
     315                 :             :       ABI_FREE(sm1proj_ompgpu)
     316                 :             :       ABI_FREE(PtPsm1proj_ompgpu)
     317                 :             :     end if
     318                 :             : 
     319                 :             :     ABI_MALLOC(proj_ompgpu,       (cplx,nprojs,nspinor*ndat))
     320                 :             :     ABI_MALLOC(sm1proj_ompgpu,    (cplx,nprojs,nspinor*ndat))
     321                 :             :     ABI_MALLOC(PtPsm1proj_ompgpu, (cplx,nprojs,nspinor*ndat))
     322                 :             : 
     323                 :             :     mod__cplx=cplx; mod__nprojs=nprojs
     324                 :             : 
     325                 :             :     !FIXME Smater buffer management ?
     326                 :             :     !!$OMP TARGET ENTER DATA MAP(alloc:proj_ompgpu,sm1proj_ompgpu,PtPsm1proj_ompgpu)
     327                 :             :     gpu_initialized=1
     328                 :             :   end if
     329                 :             : 
     330                 :             :  end subroutine alloc_ompgpu_buffers
     331                 :             : 
     332                 :             :  subroutine refresh_invovl_ompgpu_kpt(ikpt)
     333                 :             :   integer,intent(in) :: ikpt
     334                 :             : 
     335                 :             : ! *************************************************************************
     336                 :             : 
     337                 :             :   if(ikpt < 0) then
     338                 :             :     ABI_BUG("Requested GPU upload of a negative K-point index !")
     339                 :             :   end if
     340                 :             : 
     341                 :             :   if(current_ikpt_in_gpu /= -1) then
     342                 :             :     !$OMP TARGET EXIT DATA MAP(delete:current_gram_projs)
     343                 :             :     !$OMP TARGET EXIT DATA MAP(delete:current_inv_sij)
     344                 :             :     !$OMP TARGET EXIT DATA MAP(delete:current_inv_s_approx)
     345                 :             :   end if
     346                 :             : 
     347                 :             :   current_gram_projs   => invovl_kpt(ikpt)%gram_projs
     348                 :             :   current_inv_sij      => invovl_kpt(ikpt)%inv_sij
     349                 :             :   current_inv_s_approx => invovl_kpt(ikpt)%inv_s_approx
     350                 :             : 
     351                 :             :   !$OMP TARGET ENTER DATA MAP(to:current_gram_projs)
     352                 :             :   !$OMP TARGET ENTER DATA MAP(to:current_inv_sij)
     353                 :             :   !$OMP TARGET ENTER DATA MAP(to:current_inv_s_approx)
     354                 :             :   current_ikpt_in_gpu=ikpt
     355                 :             : 
     356                 :             :  end subroutine refresh_invovl_ompgpu_kpt
     357                 :             : #endif
     358                 :             : 
     359                 :             : !!****f* m_invovl/init_invovl
     360                 :             : !! NAME
     361                 :             : !! init_invovl
     362                 :             : !!
     363                 :             : !! FUNCTION
     364                 :             : !! Initalization of the invovl_kpt array
     365                 :             : !!
     366                 :             : !! INPUTS
     367                 :             : !! nkpt= number of k-points
     368                 :             : !!
     369                 :             : !! SOURCE
     370                 :             : 
     371                 :         109 :  subroutine init_invovl(nkpt)
     372                 :             : 
     373                 :             :   integer, intent(in) :: nkpt
     374                 :             :   integer :: ikpt
     375                 :             : 
     376                 :             : ! *************************************************************************
     377                 :             : 
     378   [ -  +  +  -  :        1633 :   ABI_MALLOC(invovl_kpt, (nkpt))
          +  -  +  -  -  
          +  -  +  -  +  
                   +  + ]
     379                 :             :   ! TODO add cycling if kpt parallelism
     380         [ +  + ]:        1415 :   do ikpt=1,nkpt
     381                 :        1415 :     invovl_kpt(ikpt)%nprojs = -1
     382                 :             :   end do
     383                 :             : 
     384                 :         109 :  end subroutine init_invovl
     385                 :             : !!***
     386                 :             : 
     387                 :             : !!****f* m_invovl/destroy_invovl_ikpt
     388                 :             : !! NAME
     389                 :             : !! destroy_invovl_ikpt
     390                 :             : !!
     391                 :             : !! FUNCTION
     392                 :             : !! Destruction of the ikpt-th member of invovl array
     393                 :             : !!
     394                 :             : !! INPUTS
     395                 :             : !! ikpt= index of k-point
     396                 :             : !!
     397                 :             : !! SOURCE
     398                 :       16611 :  subroutine destroy_invovl_ikpt(ikpt, gpu_option)
     399                 :             : 
     400                 :             :    integer, intent(in) :: ikpt
     401                 :             :    integer, intent(in) :: gpu_option
     402                 :             : 
     403                 :             : ! *************************************************************************
     404                 :             : 
     405                 :             :   if(gpu_option==ABI_GPU_OPENMP) then
     406                 :             : #ifdef HAVE_OPENMP_OFFLOAD
     407                 :             :     if(gpu_initialized==1 .and. current_ikpt_in_gpu == ikpt) then
     408                 :             :       !$OMP TARGET EXIT DATA MAP(delete:current_gram_projs)
     409                 :             :       !$OMP TARGET EXIT DATA MAP(delete:current_inv_sij)
     410                 :             :       !$OMP TARGET EXIT DATA MAP(delete:current_inv_s_approx)
     411                 :             :       nullify(current_gram_projs)
     412                 :             :       nullify(current_inv_sij)
     413                 :             :       nullify(current_inv_s_approx)
     414                 :             :       current_ikpt_in_gpu = -1
     415                 :             :       !FIXME Smater buffer management ?
     416                 :             :       !!$OMP TARGET EXIT DATA MAP(delete:proj_ompgpu,sm1proj_ompgpu,PtPsm1proj_ompgpu)
     417                 :             :       ABI_FREE(proj_ompgpu)
     418                 :             :       ABI_FREE(sm1proj_ompgpu)
     419                 :             :       ABI_FREE(PtPsm1proj_ompgpu)
     420                 :             :       gpu_initialized = 0
     421                 :             :     end if
     422                 :             : #endif
     423                 :             :   end if
     424                 :             : 
     425         [ -  + ]:       16611 :   ABI_FREE(invovl_kpt(ikpt)%gram_projs)
     426         [ -  + ]:       16611 :   ABI_FREE(invovl_kpt(ikpt)%inv_sij)
     427         [ -  + ]:       16611 :   ABI_FREE(invovl_kpt(ikpt)%inv_s_approx)
     428                 :       16611 :   invovl_kpt(ikpt)%nprojs = -1
     429                 :             : 
     430                 :             : #if defined(HAVE_GPU_CUDA) && defined(HAVE_FC_ISO_C_BINDING)
     431                 :             :   if (gpu_option == ABI_GPU_LEGACY .or. gpu_option == ABI_GPU_KOKKOS) then
     432                 :             :     call f_gpu_apply_invovl_inner_dealloc()
     433                 :             :     call f_gpu_apply_invovl_matrix_dealloc()
     434                 :             :   end if
     435                 :             : #endif
     436                 :             : 
     437                 :       16611 :  end subroutine destroy_invovl_ikpt
     438                 :             : !!***
     439                 :             : 
     440                 :             : !!****f* m_invovl/destroy_invovl
     441                 :             : !! NAME
     442                 :             : !! destroy_invovl
     443                 :             : !!
     444                 :             : !! FUNCTION
     445                 :             : !! Destruction of the invovl_kpt array
     446                 :             : !!
     447                 :             : !! INPUTS
     448                 :             : !! nkpt= number of k-points
     449                 :             : !!
     450                 :             : !! SOURCE
     451                 :         108 :  subroutine destroy_invovl(nkpt, gpu_option)
     452                 :             : 
     453                 :             :    integer, intent(in) :: nkpt
     454                 :             :    integer, intent(in) :: gpu_option
     455                 :             :    integer :: ikpt
     456                 :             : 
     457                 :             : ! *************************************************************************
     458                 :             : 
     459                 :             :   ! TODO add cycling if kpt parallelism
     460         [ +  + ]:        1386 :   do ikpt=1,nkpt
     461         [ +  + ]:        1278 :     if(invovl_kpt(ikpt)%nprojs == -1) then
     462                 :             :       ! write(0, *) 'ERROR invovl_kpt is unallocated'
     463                 :             :       cycle
     464                 :             :     end if
     465                 :        1386 :     call destroy_invovl_ikpt(ikpt, gpu_option)
     466                 :             :   end do
     467                 :             : 
     468   [ +  -  +  +  :        1386 :   ABI_FREE(invovl_kpt)
          -  +  -  +  -  
                +  -  + ]
     469                 :             : 
     470                 :         108 :  end subroutine destroy_invovl
     471                 :             : !!***
     472                 :             : 
     473                 :             : !!****f* m_invovl/make_invovl
     474                 :             : !! NAME
     475                 :             : !! make_invovl
     476                 :             : !!
     477                 :             : !! FUNCTION
     478                 :             : !! Builds of the invovl structure
     479                 :             : !!
     480                 :             : !! INPUTS
     481                 :             : !!
     482                 :             : !! SOURCE
     483                 :             : 
     484                 :       16639 : subroutine make_invovl(ham, dimffnl, ffnl, ph3d, mpi_enreg)
     485                 :             : 
     486                 :             :  use m_abi_linalg
     487                 :             : 
     488                 :             :  type(gs_hamiltonian_type),intent(in), target :: ham
     489                 :             :  integer, intent(in) :: dimffnl
     490                 :             :  real(dp),intent(in) :: ffnl(ham%npw_k,dimffnl,ham%lmnmax,ham%ntypat)
     491                 :             :  real(dp),intent(in) :: ph3d(2,ham%npw_k,ham%matblk)
     492                 :             :  type(mpi_type) :: mpi_enreg
     493                 :             : 
     494                 :       33278 :  real(dp) :: atom_projs(2, ham%npw_k, ham%lmnmax)
     495                 :       33278 :  real(dp) :: temp(ham%npw_k)
     496                 :       16639 :  complex(dp), allocatable :: work(:)
     497                 :       16639 :  real(dp), allocatable,target :: projs(:,:,:)
     498                 :       16639 :  real(dp), allocatable :: gram_proj(:,:,:)
     499                 :       16639 :  integer, allocatable :: ipiv(:)
     500                 :             : 
     501                 :             :  integer :: itypat, ilmn, nlmn, jlmn, ia, iaph3d, shift
     502                 :             :  integer :: il, ilm, jlm, ipw, info, ierr, cplx
     503                 :             :  integer :: ikpt_this_proc,cplex_dij
     504                 :             :  logical :: parity
     505                 :             :  real(dp) :: tsec(2)
     506                 :             : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
     507                 :             :  character(len=500) :: message
     508                 :             : #endif
     509                 :             :  character :: blas_transpose
     510                 :             : 
     511                 :             :  type(invovl_kpt_type), pointer :: invovl
     512                 :             : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
     513                 :             :  type(invovl_kpt_gpu_type) :: invovl_gpu
     514                 :             : #endif
     515                 :       33278 :  integer :: array_nprojs_pp(mpi_enreg%nproc_fft)
     516                 :             :  integer :: iproc, slice_size
     517                 :       16639 :  real(dp), allocatable :: gramwork(:,:,:)
     518                 :             : #ifdef HAVE_OPENMP_OFFLOAD
     519                 :             :  real(dp), ABI_CONTIGUOUS pointer :: invovl_gram_projs(:,:,:)
     520                 :             : #endif
     521                 :             : 
     522                 :             :  integer, parameter :: timer_mkinvovl = 1620, timer_mkinvovl_build_d = 1621, timer_mkinvovl_build_ptp = 1622
     523                 :             : 
     524                 :             : ! *************************************************************************
     525                 :             : 
     526                 :             :  !! S = 1 + PDP', so
     527                 :             :  !! S^-1 = 1 + P inv_s_projs P', with
     528                 :             :  !! inv_s_projs = - (D^-1 + P'*P)^-1
     529                 :             : 
     530                 :             :  ABI_NVTX_START_RANGE(NVTX_MAKE_INVOVL)
     531                 :             : 
     532         [ +  + ]:       16639 :  if(ham%istwf_k == 1) then
     533                 :       16511 :    cplx = 2
     534                 :       16511 :    blas_transpose = 'c'
     535                 :             :  else
     536                 :         128 :    cplx = 1
     537                 :         128 :    blas_transpose = 't'
     538                 :             :  end if
     539                 :             : 
     540                 :       16639 :  ikpt_this_proc=bandfft_kpt_get_ikpt()
     541                 :       16639 :  invovl => invovl_kpt(ikpt_this_proc)
     542                 :             : 
     543         [ +  + ]:       16639 :  if(invovl%nprojs /= -1) then
     544                 :             :    ! We have been here before, cleanup before remaking
     545                 :       15736 :    call destroy_invovl_ikpt(ikpt_this_proc, ham%gpu_option)
     546                 :             :  end if
     547                 :             : 
     548                 :       16639 :  iaph3d = 1
     549                 :             : 
     550                 :       16639 :  call timab(timer_mkinvovl,1,tsec)
     551                 :       16639 :  call timab(timer_mkinvovl_build_d,1,tsec)
     552                 :             : 
     553                 :             :  ! build nprojs
     554                 :       16639 :  invovl%nprojs = 0
     555         [ +  + ]:       33736 :  do itypat=1,ham%ntypat
     556   [ +  +  +  + ]:      170882 :    invovl%nprojs = invovl%nprojs + count(ham%indlmn(3,:,itypat)>0)*ham%nattyp(itypat)
     557                 :             :  end do
     558                 :             : 
     559   [ -  +  +  -  :       66556 :  ABI_MALLOC(projs, (2, ham%npw_k, invovl%nprojs))
          -  +  +  -  +  
          -  +  -  -  +  
                   -  + ]
     560   [ -  +  +  -  :       99834 :  ABI_MALLOC(invovl%inv_sij, (cplx, ham%lmnmax, ham%lmnmax, ham%ntypat))
          -  +  +  -  -  
          +  +  -  -  +  
          +  -  +  -  +  
          -  -  +  -  +  
                   -  + ]
     561   [ -  +  +  -  :       99834 :  ABI_MALLOC(invovl%inv_s_approx, (cplx, ham%lmnmax, ham%lmnmax, ham%ntypat))
          -  +  +  -  -  
          +  +  -  -  +  
          +  -  +  -  +  
          -  -  +  -  +  
                   -  + ]
     562                 :             :  ! workspace for inversion
     563   [ -  +  +  -  :       49917 :  ABI_MALLOC(ipiv, (ham%lmnmax))
          +  -  +  -  -  
                +  -  + ]
     564   [ +  -  -  +  :       49917 :  ABI_MALLOC(work, (64*ham%lmnmax))
          +  -  +  -  +  
             -  -  +  -  
                      + ]
     565                 :             : 
     566   [ +  +  +  +  :   132942015 :  projs = zero
                   +  + ]
     567   [ +  +  +  +  :     3465982 :  invovl%inv_sij = zero
             +  +  +  + ]
     568   [ +  +  +  +  :     3465982 :  invovl%inv_s_approx = zero
             +  +  +  + ]
     569                 :             : 
     570                 :             :  shift = 0
     571         [ +  + ]:       33736 :  do itypat = 1, ham%ntypat
     572   [ +  +  +  + ]:      154243 :    nlmn = count(ham%indlmn(3,:,itypat)>0)
     573         [ +  + ]:       17097 :    if (size(ham%sij(:,itypat))==ham%lmnmax*(ham%lmnmax+1)/2) then
     574                 :             :      cplex_dij = 1
     575         [ -  + ]:         176 :    else if (size(ham%sij(:,itypat))==ham%lmnmax*(ham%lmnmax+1)) then
     576                 :             :      cplex_dij = 2
     577                 :             :    else
     578                 :           0 :      ABI_ERROR('sij size not recognize')
     579                 :             :    end if
     580                 :             :    !! unpack ham%sij into inv_sij
     581         [ +  + ]:      154223 :    do jlmn = 1, nlmn
     582         [ +  + ]:      137126 :      if (cplex_dij==1) then
     583                 :      135718 :        invovl%inv_sij(1, jlmn, jlmn, itypat) = ham%sij(jlmn*(jlmn-1)/2 + jlmn, itypat)
     584                 :             :      else
     585                 :        1408 :        invovl%inv_sij(1, jlmn, jlmn, itypat) = ham%sij(jlmn*(jlmn-1) + 2*jlmn-1, itypat)
     586                 :             :      end if
     587         [ +  + ]:      637314 :      do ilmn = 1, jlmn-1
     588         [ +  + ]:      620217 :        if (cplex_dij==1) then
     589                 :      478163 :          invovl%inv_sij(1, ilmn, jlmn, itypat) = ham%sij(jlmn*(jlmn-1)/2 + ilmn, itypat)
     590                 :      478163 :          invovl%inv_sij(1, jlmn, ilmn, itypat) = ham%sij(jlmn*(jlmn-1)/2 + ilmn, itypat)
     591                 :             :        else
     592                 :        4928 :          invovl%inv_sij(1, ilmn, jlmn, itypat) = ham%sij(jlmn*(jlmn-1) + 2*ilmn-1, itypat)
     593                 :        4928 :          invovl%inv_sij(1, jlmn, ilmn, itypat) = ham%sij(jlmn*(jlmn-1) + 2*ilmn-1, itypat)
     594                 :             : 
     595                 :             :        end if
     596                 :             :      end do
     597                 :             :    end do
     598                 :             : 
     599                 :             :    ! Invert sij
     600         [ +  + ]:       17097 :    if(cplx == 2) then
     601                 :       16841 :      call ZHETRF('U', nlmn, invovl%inv_sij(:,:,:,itypat), ham%lmnmax, ipiv, work, (64*nlmn), info)
     602                 :       16841 :      call ZHETRI('U', nlmn, invovl%inv_sij(:,:,:,itypat), ham%lmnmax, ipiv, work, info)
     603                 :             :    else
     604                 :         256 :      call DSYTRF('U', nlmn, invovl%inv_sij(:,:,:,itypat), ham%lmnmax, ipiv, work, (64*nlmn), info)
     605                 :         256 :      call DSYTRI('U', nlmn, invovl%inv_sij(:,:,:,itypat), ham%lmnmax, ipiv, work, info)
     606                 :             :    end if
     607                 :             :    ! complete the matrix
     608         [ +  + ]:      154223 :    do ilm=1, nlmn
     609         [ +  + ]:      637314 :      do jlm=1, ilm-1
     610                 :      620217 :        invovl%inv_sij(1,ilm,jlm,itypat) =  invovl%inv_sij(1,jlm,ilm,itypat)
     611                 :             :      end do
     612                 :             :    end do
     613                 :             : 
     614                 :             :    !! loop on atoms to build atom_projs and fill projs, s_projs
     615         [ +  + ]:       67339 :    do ia = 1, ham%nattyp(itypat)
     616                 :             : 
     617                 :             :      !! build atom_projs, from opernlb
     618                 :             :      !! P = 4pi/sqrt(ucvol)* conj(diag(ph3d)) * ffnl * diag(parity), with parity = (-i)^l
     619   [ +  +  +  +  :   133024979 :      atom_projs(:,:,:) = zero
                   +  + ]
     620                 :             : 
     621                 :             :      ! start from 4pi/sqrt(ucvol)*ffnl
     622                 :             :      ! atom_projs(1, :, 1:nlmn) = four_pi/sqrt(ham%ucvol) * ffnl(:, 1, 1:nlmn)
     623                 :             :      ! TODO vectorize (DCOPY with stride)
     624         [ +  + ]:     5074316 :      do ipw=1, ham%npw_k
     625         [ +  + ]:    49291890 :        atom_projs(1,ipw, 1:nlmn) = four_pi/sqrt(ham%ucvol) * ffnl(ipw, 1, 1:nlmn, itypat)
     626                 :             :      end do
     627                 :             : 
     628                 :             :      ! multiply by (-i)^l
     629         [ +  + ]:      306257 :      do ilmn=1,nlmn
     630                 :      272654 :        il=mod(ham%indlmn(1,ilmn, itypat),4);
     631                 :      272654 :        parity=(mod(il,2)==0)
     632         [ +  + ]:      272654 :        if (il>1) then
     633                 :             :          ! multiply by -1
     634   [ +  +  +  + ]:    11679440 :          atom_projs(:,:,ilmn) = -atom_projs(:,:,ilmn)
     635                 :             :        end if
     636         [ +  + ]:      306257 :        if(.not. parity) then
     637                 :             :          ! multiply by -i
     638         [ +  + ]:    30445896 :          temp = atom_projs(2,:,ilmn)
     639         [ +  + ]:    30445896 :          atom_projs(2,:,ilmn) = -atom_projs(1,:,ilmn)
     640         [ +  + ]:    30445896 :          atom_projs(1,:,ilmn) =  temp
     641                 :             :        end if
     642                 :             :      end do
     643                 :             : 
     644                 :             :      ! multiply by conj(ph3d)
     645         [ +  + ]:      306257 :      do ilmn=1,nlmn
     646         [ +  + ]:    44490228 :        temp = atom_projs(1, :, ilmn)
     647         [ +  + ]:    44490228 :        atom_projs(1, :, ilmn) = atom_projs(1, :, ilmn) * ph3d(1, :, iaph3d) + atom_projs(2, :, ilmn) * ph3d(2, :, iaph3d)
     648         [ +  + ]:    44523831 :        atom_projs(2, :, ilmn) = atom_projs(2, :, ilmn) * ph3d(1, :, iaph3d) - temp                   * ph3d(2, :, iaph3d)
     649                 :             :      end do
     650                 :             : 
     651                 :             :      ! me_g0 trick
     652   [ +  +  +  + ]:       33603 :      if(ham%istwf_k == 2 .and. mpi_enreg%me_g0 == 1) then
     653         [ +  + ]:         126 :        atom_projs(1,1,:) = atom_projs(1,1,:) / sqrt2
     654         [ +  + ]:         126 :        atom_projs(2,1,:) = zero
     655                 :             :      end if
     656         [ +  + ]:       33603 :      if(ham%istwf_k > 1) then
     657   [ +  +  +  +  :      198240 :        atom_projs(:,:,:) = atom_projs(:,:,:) * sqrt2
                   +  + ]
     658                 :             :      end if
     659                 :             : 
     660                 :             : 
     661                 :             :      !! atom_projs and typat_s_projs are built, copy them to projs and inv_s_projs
     662   [ +  +  +  +  :   132958979 :      projs(:, :, shift+1:shift+nlmn) = atom_projs(:, :, 1:nlmn)
                   +  + ]
     663                 :       33603 :      shift = shift + nlmn
     664                 :             : 
     665                 :             :      ! build inv_s_approx = (D^-1+PtP)^-1 restricted to a single atom block
     666                 :             :      ! can be optimized (real, build directly from ffnl)
     667         [ +  + ]:       33603 :      if(ia == 1) then
     668                 :             :        ! D^-1
     669   [ +  +  +  + ]:     1257487 :        invovl%inv_s_approx(1, :, :, itypat) = invovl%inv_sij(1, :, :, itypat)
     670                 :             :        ! + PtP
     671   [ -  +  +  -  :       85445 :        ABI_MALLOC(gram_proj, (cplx, nlmn, nlmn))
          -  +  +  -  -  
          +  +  -  +  -  
          +  -  -  +  -  
                +  -  + ]
     672                 :             :        call abi_xgemm(blas_transpose,'N', nlmn, nlmn, (3-cplx)*ham%npw_k, cone, atom_projs(:,:,1), (3-cplx)*ham%npw_k, &
     673                 :       17089 : &                     atom_projs(:,:,1), (3-cplx)*ham%npw_k, czero, gram_proj(:,:,1), nlmn,x_cplx=cplx)
     674                 :       17089 :        call xmpi_sum(gram_proj,mpi_enreg%comm_bandspinorfft,ierr)
     675   [ +  +  +  +  :     3446155 :        invovl%inv_s_approx(:,1:nlmn,1:nlmn,itypat) = invovl%inv_s_approx(:,1:nlmn,1:nlmn,itypat) + gram_proj(:,:,:)
                   +  + ]
     676         [ -  + ]:       17089 :        ABI_FREE(gram_proj)
     677                 :             :        ! ^-1
     678         [ +  + ]:       17089 :        if(cplx == 2) then
     679                 :       16833 :          call ZHETRF('U', nlmn, invovl%inv_s_approx(:,:,:,itypat), ham%lmnmax, ipiv, work, (64*nlmn), info)
     680                 :       16833 :          call ZHETRI('U', nlmn, invovl%inv_s_approx(:,:,:,itypat), ham%lmnmax, ipiv, work, info)
     681                 :             :        else
     682                 :         256 :          call DSYTRF('U', nlmn, invovl%inv_s_approx(:,:,:,itypat), ham%lmnmax, ipiv, work, (64*nlmn), info)
     683                 :         256 :          call DSYTRI('U', nlmn, invovl%inv_s_approx(:,:,:,itypat), ham%lmnmax, ipiv, work, info)
     684                 :             :        end if
     685                 :             :        ! complete lower triangle of matrix
     686         [ +  + ]:      171240 :        do ilm=1, nlmn
     687         [ +  + ]:      637018 :          do jlm=1, ilm-1
     688                 :      482867 :            invovl%inv_s_approx(1, ilm, jlm, itypat) =  invovl%inv_s_approx(1, jlm, ilm, itypat)
     689         [ +  + ]:      619929 :            if(cplx == 2) then
     690                 :      475699 :              invovl%inv_s_approx(2, ilm, jlm, itypat) =  -invovl%inv_s_approx(2, jlm, ilm, itypat)
     691                 :             :            end if
     692                 :             :          end do
     693                 :             :        end do
     694                 :             :      end if
     695                 :             : 
     696                 :       50700 :      iaph3d = iaph3d + 1
     697                 :             :    end do
     698                 :             :  end do
     699         [ -  + ]:       16639 :  ABI_FREE(ipiv)
     700         [ -  + ]:       16639 :  ABI_FREE(work)
     701                 :             : 
     702                 :       16639 :  call timab(timer_mkinvovl_build_d, 2, tsec)
     703                 :       16639 :  call timab(timer_mkinvovl_build_ptp, 1, tsec)
     704                 :             : 
     705                 :             :  ! Compute P'P one column slice at a time (might be too big to fit in one proc)
     706         [ +  + ]:       16639 :  if(mpi_enreg%paral_kgb == 1) then
     707                 :             :    ! Split the work evenly the fft processors
     708         [ +  + ]:       13464 :    array_nprojs_pp(:) = invovl%nprojs / mpi_enreg%nproc_fft
     709                 :             :    ! not enough work, there's MOD(nprojs,mpi_enreg%nproc_fft) tasks left
     710                 :             :    ! assign them to the first ones
     711         [ -  + ]:        6728 :    array_nprojs_pp(1:MOD(invovl%nprojs,mpi_enreg%nproc_fft)) = array_nprojs_pp(1:MOD(invovl%nprojs,mpi_enreg%nproc_fft)) + 1
     712                 :             :  else
     713         [ +  + ]:       19822 :    array_nprojs_pp = invovl%nprojs
     714                 :             :  end if
     715   [ -  +  +  -  :       83195 :  ABI_MALLOC(invovl%gram_projs, (cplx,invovl%nprojs,array_nprojs_pp(mpi_enreg%me_fft+1)))
          -  +  +  -  -  
          +  +  -  +  -  
          +  -  -  +  -  
                +  -  + ]
     716                 :       16639 :  shift = 0
     717   [ -  +  -  - ]:       16639 :  if (ham%gpu_option==ABI_GPU_OPENMP .and. mpi_enreg%nproc_fft==1) then
     718                 :             : #ifdef HAVE_OPENMP_OFFLOAD
     719                 :             :    ! compute gram_projs in one GEMM, only one FFT proc expected in GPU mode
     720                 :             :    slice_size = array_nprojs_pp(1)
     721                 :             :    invovl_gram_projs   => invovl%gram_projs
     722                 :             :    !$OMP TARGET ENTER DATA MAP(alloc:invovl_gram_projs)
     723                 :             :    !$OMP TARGET ENTER DATA MAP(to:projs)
     724                 :             : 
     725                 :             :    call abi_xgemm(blas_transpose,'N', invovl%nprojs, slice_size, (3-cplx)*ham%npw_k, cone, &
     726                 :             :    &              projs, (3-cplx)*ham%npw_k, &
     727                 :             :    &              projs, (3-cplx)*ham%npw_k, czero, &
     728                 :             :    &              invovl_gram_projs, invovl%nprojs, &
     729                 :             :    &              x_cplx=cplx, gpu_option=ham%gpu_option)
     730                 :             :    call xmpi_sum(invovl%gram_projs,mpi_enreg%comm_band,ierr,use_omp_map=.true.)
     731                 :             :    !$OMP TARGET EXIT DATA MAP(from:invovl_gram_projs)
     732                 :             :    !$OMP TARGET EXIT DATA MAP(delete:projs)
     733                 :             : #endif
     734                 :             :  else
     735         [ +  + ]:       33286 :    do iproc = 1, mpi_enreg%nproc_fft
     736                 :             :      ! compute local contribution to slice iproc of gram_projs
     737                 :       16647 :      slice_size = array_nprojs_pp(iproc)
     738   [ -  +  +  -  :       83235 :      ABI_MALLOC(gramwork, (cplx,invovl%nprojs,slice_size))
          -  +  +  -  -  
          +  +  -  +  -  
          +  -  -  +  -  
                +  -  + ]
     739                 :             :      call abi_xgemm(blas_transpose,'N', invovl%nprojs, slice_size, (3-cplx)*ham%npw_k, cone,&
     740                 :             :      &              projs(:,:,1), (3-cplx)*ham%npw_k, &
     741                 :             :      &              projs(:, :, shift+1), (3-cplx)*ham%npw_k, czero, &
     742                 :             :      &              gramwork(:,:,1), invovl%nprojs,&
     743                 :       16647 :      &              x_cplx=cplx)
     744                 :       16647 :      shift = shift + slice_size
     745                 :             :      ! reduce on proc i
     746                 :       16647 :      call xmpi_sum_master(gramwork, iproc-1, mpi_enreg%comm_fft, ierr)
     747         [ +  + ]:       16647 :      if(iproc == mpi_enreg%me_fft+1) then
     748   [ +  -  +  -  :    21888376 :        invovl%gram_projs = gramwork
          +  -  -  +  -  
          -  -  -  -  -  
          -  -  +  +  +  
                +  +  + ]
     749                 :             :      end if
     750         [ -  + ]:       33286 :      ABI_FREE(gramwork)
     751                 :             :    end do
     752                 :       16639 :    call xmpi_sum(invovl%gram_projs,mpi_enreg%comm_band,ierr)
     753                 :             :  end if
     754                 :             : 
     755                 :       16639 :  call timab(timer_mkinvovl_build_ptp, 2, tsec)
     756                 :       16639 :  call timab(timer_mkinvovl,2,tsec)
     757                 :             : 
     758         [ -  + ]:       16639 :  ABI_FREE(projs)
     759                 :             : 
     760                 :             : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
     761                 :             : 
     762                 :             :  ! upload inverse overlap matrices (sij and s_approx) to GPU memory
     763                 :             :  if (ham%gpu_option==ABI_GPU_LEGACY .or. ham%gpu_option==ABI_GPU_KOKKOS) then
     764                 :             :    ! allocate memory for sij and s_approx on GPU
     765                 :             :    write(message,'(a,a,i12,a,a,i6,a,a,i6,a,a,es12.4,a)') &
     766                 :             :      & 'Allocate GPU memory for inverse overlap computations (sij and s_approx) : ',&
     767                 :             :      & 'nprojs=',invovl%nprojs,ch10,&
     768                 :             :      & 'nlmnax=',ham%lmnmax,ch10,&
     769                 :             :      & 'ntypat=',ham%ntypat,ch10,&
     770                 :             :      & 'gram_projs_gpu_size (GBytes)=',1e-9*cplx*invovl%nprojs*invovl%nprojs*dp,ch10
     771                 :             :    call wrtout(std_out,message,'COLL')
     772                 :             :    call f_gpu_apply_invovl_matrix_alloc(cplx, invovl%nprojs, ham%lmnmax, ham%ntypat, 0)
     773                 :             : 
     774                 :             :    invovl_gpu = make_invovl_kpt_gpu(invovl)
     775                 :             :    call f_upload_inverse_overlap(invovl_gpu, cplx, invovl%nprojs, ham%lmnmax, ham%ntypat)
     776                 :             :    write(message,*) 'Invovl uploaded to GPU memory'
     777                 :             :    call wrtout(std_out,message,'COLL')
     778                 :             :  end if
     779                 :             : 
     780                 :             : #endif
     781                 :             : 
     782                 :             : #ifdef HAVE_OPENMP_OFFLOAD
     783                 :             :  if (ham%gpu_option==ABI_GPU_OPENMP) then
     784                 :             :    call refresh_invovl_ompgpu_kpt(ikpt_this_proc)
     785                 :             :  end if
     786                 :             : #endif
     787                 :             : 
     788                 :             : ! LB-10/06/24: This message is too verbose on some cases (for example many k-points)
     789                 :             : ! write(message,*) 'Invovl built'
     790                 :             : ! call wrtout(std_out,message,'COLL')
     791                 :             : 
     792                 :             :  ABI_NVTX_END_RANGE()
     793                 :             : 
     794   [ -  +  -  + ]:       16639 : end subroutine make_invovl
     795                 :             : !!***
     796                 :             : 
     797                 :             : !!****f* m_invovl/apply_invovl
     798                 :             : !! NAME
     799                 :             : !! apply_invovl
     800                 :             : !!
     801                 :             : !! FUNCTION
     802                 :             : !! Applies the inverse of the overlap matrix to cwavef
     803                 :             : !!
     804                 :             : !! INPUTS
     805                 :             : !!
     806                 :             : !! SOURCE
     807                 :             : 
     808         [ -  + ]:      160806 : subroutine apply_invovl(ham, cwavef, sm1cwavef, cwaveprj, npw, ndat, mpi_enreg, nspinor, block_sliced)
     809                 :             : 
     810                 :             : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
     811                 :             :   use, intrinsic :: iso_c_binding
     812                 :             : #endif
     813                 :             : 
     814                 :             :   ! args
     815                 :             :   type(gs_hamiltonian_type), intent(in), target :: ham
     816                 :             :   integer, intent(in) :: npw, ndat
     817                 :             :   integer, intent(in) :: nspinor
     818                 :             :   integer, intent(in) :: block_sliced
     819                 :             :   real(dp), intent(inout), target :: cwavef(2, npw*nspinor*ndat) ! TODO should be in, fix nonlop
     820                 :             :   type(mpi_type) :: mpi_enreg
     821                 :             :   real(dp), intent(inout), target :: sm1cwavef(2, npw*nspinor*ndat)
     822                 :             :   type(pawcprj_type), intent(inout) :: cwaveprj(:,:)
     823                 :             : 
     824                 :      160806 :   real(dp),allocatable, target :: proj(:,:,:), sm1proj(:,:,:), PtPsm1proj(:,:,:)
     825                 :             : 
     826                 :             :   ! used to pass proj dimensions to cuda
     827                 :             :   integer(kind=c_int32_t) :: proj_dim(3)
     828                 :             :   integer(kind=c_int32_t) :: nattyp_dim
     829                 :             :   integer(kind=c_int32_t) :: indlmn_dim(3)
     830                 :             : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
     831                 :             :   integer(kind=c_int32_t) :: cwavef_size
     832                 :             : #endif
     833                 :             : 
     834                 :             :   integer :: idat, iatom, nlmn, shift
     835                 :             :   real(dp) :: tsec(2)
     836                 :             : 
     837                 :             :   integer :: choice, cpopt, paw_opt , cplx
     838                 :             :   character :: blas_transpose
     839                 :      160806 :   type(pawcprj_type),allocatable :: cwaveprj_in(:,:)
     840                 :             : 
     841                 :             :   integer :: ikpt_this_proc
     842                 :             :   ! dummies
     843                 :      321612 :   real(dp) :: enlout(ndat), lambda_block(1), gvnlxc(1,1)
     844                 :             :   integer, parameter :: nnlout = 0, idir = 0, signs = 2
     845                 :             : 
     846                 :             :   type(invovl_kpt_type), pointer :: invovl
     847                 :             : 
     848                 :             :   ! *************************************************************************
     849                 :             : 
     850                 :             :   if(ham%gpu_option==ABI_GPU_OPENMP) then
     851                 :             : #ifdef HAVE_OPENMP_OFFLOAD
     852                 :             :     call apply_invovl_ompgpu(ham, cwavef, sm1cwavef, cwaveprj, npw, ndat, mpi_enreg, nspinor, block_sliced)
     853                 :             :     return
     854                 :             : #endif
     855                 :             :   end if
     856                 :             : 
     857                 :             :   ABI_NVTX_START_RANGE(NVTX_INVOVL_PREP)
     858                 :      160806 :   ikpt_this_proc=bandfft_kpt_get_ikpt()
     859                 :      160806 :   invovl => invovl_kpt(ikpt_this_proc)
     860                 :             : 
     861         [ +  + ]:      160806 :   if(ham%istwf_k == 1) then
     862                 :      143995 :     cplx = 2
     863                 :      143995 :     blas_transpose = 'c'
     864                 :             :   else
     865                 :       16811 :     cplx = 1
     866                 :       16811 :     blas_transpose = 't'
     867                 :             :   end if
     868                 :             : 
     869   [ -  +  +  -  :      804030 :   ABI_MALLOC(proj,       (cplx,invovl%nprojs,nspinor*ndat))
          -  +  +  -  -  
          +  +  -  +  -  
          +  -  -  +  -  
                      + ]
     870   [ -  +  +  -  :      643224 :   ABI_MALLOC(sm1proj,    (cplx,invovl%nprojs,nspinor*ndat))
          -  +  +  -  -  
          +  +  -  -  +  
                   -  + ]
     871   [ -  +  +  -  :      643224 :   ABI_MALLOC(PtPsm1proj, (cplx,invovl%nprojs,nspinor*ndat))
          -  +  +  -  -  
          +  +  -  -  +  
                   -  + ]
     872   [ +  +  +  +  :    65308502 :   proj = zero
                   +  + ]
     873   [ +  +  +  +  :    65308502 :   sm1proj = zero
                   +  + ]
     874   [ +  +  +  +  :    65308502 :   PtPsm1proj = zero
                   +  + ]
     875                 :             : 
     876                 :      160806 :   proj_dim = (/ size(proj,1), size(proj,2), size(proj,3) /)
     877                 :             : 
     878                 :      160806 :   nattyp_dim = size(ham%nattyp)
     879                 :             : 
     880                 :      160806 :   indlmn_dim = (/ size(ham%indlmn,1), size(ham%indlmn,2), size(ham%indlmn,3) /)
     881                 :             : 
     882                 :             : #if defined(HAVE_GPU_CUDA) && defined(HAVE_FC_ISO_C_BINDING)
     883                 :             : 
     884                 :             :   !! memory allocation of data used in solve_inner_gpu
     885                 :             :   !! note : this is actually done only once
     886                 :             :   if (ham%gpu_option==ABI_GPU_LEGACY .or. ham%gpu_option==ABI_GPU_KOKKOS) then
     887                 :             : 
     888                 :             : #ifdef DEBUG_VERBOSE_GPU
     889                 :             :     if(xmpi_comm_rank(xmpi_world) == 0) then
     890                 :             :       call check_gpu_mem("gpu_apply_invovl_inner_alloc begin")
     891                 :             :     end if
     892                 :             : #endif
     893                 :             : 
     894                 :             :     ! make sure to use sizes from apply_invovl
     895                 :             :     call f_gpu_apply_invovl_inner_alloc(proj_dim, ham%ntypat, 0)
     896                 :             : 
     897                 :             : #ifdef DEBUG_VERBOSE_GPU
     898                 :             :     if(xmpi_comm_rank(xmpi_world) == 0) then
     899                 :             :       call check_gpu_mem("gpu_apply_invovl_inner_alloc end")
     900                 :             :     end if
     901                 :             : #endif
     902                 :             : 
     903                 :             :     ! TODO find a better place to put that initialization
     904                 :             :     call f_gpu_init_invovl_data(indlmn_dim, c_loc(ham%indlmn(1,1,1)))
     905                 :             : 
     906                 :             :   end if
     907                 :             : 
     908                 :             : #endif
     909                 :             : 
     910                 :             : 
     911                 :      160806 :   call timab(timer_apply_inv_ovl_opernla, 1, tsec)
     912                 :             : 
     913                 :             :   ! cwaveprj may be dummy or unused if gemm nonlop is turned on
     914   [ +  +  +  +  :      482418 :   if((.not. gemm_nonlop_use_gemm) .or. size(cwaveprj) > 1) then
                   +  + ]
     915   [ -  +  +  -  :     4200552 :     ABI_MALLOC(cwaveprj_in, (ham%natom,nspinor*ndat))
          -  +  +  -  +  
          -  +  -  -  +  
          -  +  -  +  +  
                +  +  + ]
     916                 :      160518 :     call pawcprj_alloc(cwaveprj_in,0,ham%dimcprj)
     917                 :             :   else
     918   [ -  +  -  +  :         864 :     ABI_MALLOC(cwaveprj_in, (1,1))
             +  +  +  + ]
     919                 :         288 :     call pawcprj_alloc(cwaveprj_in,0,(/1/))
     920                 :             :   end if
     921                 :             :   ABI_NVTX_END_RANGE()
     922                 :             : 
     923                 :             :   ! get the cprj
     924                 :             :   ABI_NVTX_START_RANGE(NVTX_INVOVL_NONLOP1)
     925                 :      160806 :   choice = 0 ! only compute cprj, nothing else
     926                 :      160806 :   cpopt = 0 ! compute and save cprj
     927                 :      160806 :   paw_opt = 3 ! S nonlocal operator
     928         [ +  + ]:      160806 :   if (mpi_enreg%paral_kgb==1) then
     929                 :             :     call prep_nonlop(choice,cpopt,cwaveprj_in,enlout,ham,idir,lambda_block,ndat,mpi_enreg,&
     930                 :             :       &                   nnlout,paw_opt,signs,sm1cwavef,tim_nonlop,cwavef,gvnlxc,&
     931                 :             :       &                   already_transposed=.true.,&
     932                 :             :       &                   gpu_option=ham%gpu_option,&
     933                 :       62460 :       &                   vectproj=proj)
     934                 :             :   else
     935                 :             :     call nonlop(choice,cpopt,cwaveprj_in,enlout,ham,idir,lambda_block,mpi_enreg,ndat,&
     936                 :       98346 :       &              nnlout,paw_opt,signs,sm1cwavef,tim_nonlop,cwavef,gvnlxc,vectproj=proj)
     937                 :             :   end if
     938                 :             :   ABI_NVTX_END_RANGE()
     939                 :             : 
     940                 :      160806 :   call timab(timer_apply_inv_ovl_opernla, 2, tsec)
     941                 :      160806 :   call timab(timer_apply_inv_ovl_inv_s, 1, tsec)
     942                 :             : 
     943                 :             :   ! If using GEMM nonlop, proj array is used directly instead of writing in cwaveprj_in content, so skip this copy
     944         [ +  + ]:      160806 :   if(.not. gemm_nonlop_use_gemm) then
     945                 :             :     ! copy cwaveprj_in to proj(:,:)
     946         [ +  + ]:     1288502 :     do idat=1, ndat*nspinor
     947                 :     1128272 :       shift = 0
     948         [ +  + ]:     3713526 :       do iatom = 1, ham%natom
     949                 :     2425024 :         nlmn = cwaveprj_in(iatom, idat)%nlmn
     950   [ +  +  +  + ]:    66317440 :         proj(1:cplx, shift+1:shift+nlmn, idat) = cwaveprj_in(iatom, idat)%cp(1:cplx, 1:nlmn)
     951                 :     3553296 :         shift = shift + nlmn
     952                 :             :       end do
     953                 :             :     end do
     954                 :             :   end if
     955                 :             : 
     956                 :             :   !multiply by S^1
     957                 :             :   ABI_NVTX_START_RANGE(NVTX_INVOVL_INNER)
     958                 :             :   ! TODO : when solve_inner_gpu is ready, update the following to activate GPU computation
     959         [ +  - ]:      160806 :   if (ham%gpu_option == ABI_GPU_LEGACY .or. ham%gpu_option==ABI_GPU_KOKKOS) then
     960                 :             : 
     961                 :             : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
     962                 :             : 
     963                 :             :     if (mpi_enreg%nproc_fft /= 1) then
     964                 :             :       ABI_ERROR("[66_wfs/m_invovl.F90:apply_invovl] nproc_fft must be 1, when GPU/CUDA is activated")
     965                 :             :     end if
     966                 :             : 
     967                 :             :     call f_solve_inner_gpu(proj_dim, c_loc(proj(1,1,1)), &
     968                 :             :       & c_loc(sm1proj(1,1,1)), c_loc(PtPsm1proj(1,1,1)), &
     969                 :             :       & nattyp_dim, c_loc(ham%nattyp(1)), ham%ntypat, &
     970                 :             :       & ham%lmnmax, cplx, block_sliced)
     971                 :             : 
     972                 :             : #endif
     973                 :             : 
     974                 :             :   else
     975                 :             : 
     976                 :      160806 :     call solve_inner(invovl, ham, cplx, mpi_enreg, proj, ndat*nspinor, sm1proj, PtPsm1proj, block_sliced)
     977   [ +  +  +  +  :    65308502 :     sm1proj = - sm1proj
                   +  + ]
     978   [ +  +  +  +  :    65308502 :     PtPsm1proj = - PtPsm1proj
                   +  + ]
     979                 :             :   end if
     980                 :             : 
     981                 :             :   ABI_NVTX_END_RANGE()
     982                 :             : 
     983                 :             :   ! If using GEMM nonlop, sm1proj array is used directly instead of reading cwaveprj content, so skip this copy
     984         [ +  + ]:      160806 :   if(.not. gemm_nonlop_use_gemm) then
     985                 :             :     ! copy sm1proj to cwaveprj(:,:)
     986         [ +  + ]:     1288502 :     do idat=1, ndat*nspinor
     987                 :     1128272 :       shift = 0
     988         [ +  + ]:     3713526 :       do iatom = 1, ham%natom
     989                 :     2425024 :         nlmn = cwaveprj(iatom, idat)%nlmn
     990   [ +  +  +  + ]:    66317440 :         cwaveprj(iatom, idat)%cp(1:cplx, 1:nlmn) = sm1proj(1:cplx, shift+1:shift+nlmn, idat)
     991                 :     3553296 :         shift = shift + nlmn
     992                 :             :       end do
     993                 :             :     end do
     994                 :             :   end if
     995                 :      160806 :   call timab(timer_apply_inv_ovl_inv_s, 2, tsec)
     996                 :      160806 :   call timab(timer_apply_inv_ovl_opernlb, 1, tsec)
     997                 :             : 
     998                 :             :   ! get the corresponding wf
     999                 :             :   ABI_NVTX_START_RANGE(NVTX_INVOVL_NONLOP2)
    1000                 :      160806 :   cpopt = 2 ! reuse cprj
    1001                 :      160806 :   choice = 7 ! get wf from cprj, without the application of S
    1002                 :             :   paw_opt = 3
    1003         [ +  + ]:      160806 :   if (mpi_enreg%paral_kgb==1) then
    1004                 :             :     call prep_nonlop(choice,cpopt,cwaveprj,enlout,ham,idir,lambda_block,ndat,mpi_enreg,nnlout,&
    1005                 :             :       &                   paw_opt,signs,sm1cwavef,tim_nonlop,cwavef,gvnlxc,already_transposed=.true.,&
    1006                 :       62460 :       &                   gpu_option=ham%gpu_option,vectproj=sm1proj)
    1007                 :             :   else
    1008                 :             :     call nonlop(choice,cpopt,cwaveprj,enlout,ham,idir,lambda_block,mpi_enreg,ndat,nnlout,paw_opt,&
    1009                 :       98346 :       &              signs,sm1cwavef,tim_nonlop,cwavef,gvnlxc,vectproj=sm1proj)
    1010                 :             :   end if
    1011                 :             :   ABI_NVTX_END_RANGE()
    1012                 :             : 
    1013                 :      160806 :   call timab(timer_apply_inv_ovl_opernlb, 2, tsec)
    1014                 :             : 
    1015                 :             :   ABI_NVTX_START_RANGE(NVTX_INVOVL_POST2)
    1016   [ +  +  +  + ]:      482418 :   if(size(cwaveprj) > 1) then
    1017                 :             :     ! copy PtPSm1proj to cwaveprj(:,:)
    1018         [ +  + ]:     1290518 :     do idat=1, ndat*nspinor
    1019                 :     1130000 :       shift = 0
    1020         [ +  + ]:     3718998 :       do iatom = 1, ham%natom
    1021                 :     2428480 :         nlmn = cwaveprj(iatom, idat)%nlmn
    1022   [ +  +  +  + ]:    66403840 :         cwaveprj(iatom, idat)%cp(1:cplx, 1:nlmn) = PtPsm1proj(1:cplx, shift+1:shift+nlmn, idat)
    1023                 :     3558480 :         shift = shift + nlmn
    1024                 :             :       end do
    1025                 :             :     end do
    1026                 :             :     !cwaveprj_in is empty if GEMM nonlop is being used, so populate it here
    1027         [ +  + ]:      160518 :     if(gemm_nonlop_use_gemm) then
    1028         [ +  + ]:        2016 :       do idat=1, ndat*nspinor
    1029                 :        1728 :         shift = 0
    1030         [ +  + ]:        5472 :         do iatom = 1, ham%natom
    1031                 :        3456 :           nlmn = cwaveprj_in(iatom, idat)%nlmn
    1032   [ +  +  +  + ]:       86400 :           cwaveprj_in(iatom, idat)%cp(1:cplx, 1:nlmn) = proj(1:cplx, shift+1:shift+nlmn, idat)
    1033                 :        5184 :           shift = shift + nlmn
    1034                 :             :         end do
    1035                 :             :       end do
    1036                 :             :     end if
    1037                 :      160518 :     call pawcprj_axpby(one, one, cwaveprj_in, cwaveprj)
    1038                 :             :   end if
    1039                 :      160806 :   call pawcprj_free(cwaveprj_in)
    1040   [ +  -  +  +  :     2589574 :   ABI_FREE(cwaveprj_in)
          -  +  -  +  -  
                      + ]
    1041                 :             : 
    1042         [ +  - ]:      160806 :   if (ham%gpu_option == ABI_GPU_LEGACY .or. ham%gpu_option==ABI_GPU_KOKKOS) then
    1043                 :             : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
    1044                 :             :     cwavef_size = 2*npw*nspinor*ndat
    1045                 :             :     call add_array_kokkos(c_loc(sm1cwavef), c_loc(cwavef), cwavef_size)
    1046                 :             : #endif
    1047                 :             :   else
    1048   [ +  +  +  + ]:   669394662 :     sm1cwavef = cwavef + sm1cwavef
    1049                 :             :   end if
    1050                 :             : 
    1051                 :             :   ABI_NVTX_END_RANGE()
    1052                 :             : 
    1053         [ -  + ]:      160806 :   ABI_FREE(proj)
    1054         [ -  + ]:      160806 :   ABI_FREE(sm1proj)
    1055         [ -  + ]:      160806 :   ABI_FREE(PtPsm1proj)
    1056                 :             : 
    1057   [ -  +  -  -  :      160806 : end subroutine apply_invovl
             -  -  -  - ]
    1058                 :             : !!***
    1059                 :             : 
    1060                 :             : !!****f* m_invovl/solve_inner
    1061                 :             : !! NAME
    1062                 :             : !! solve_inner
    1063                 :             : !!
    1064                 :             : !! FUNCTION
    1065                 :             : !! Helper function: iteratively solves the inner system
    1066                 :             : !!
    1067                 :             : !! INPUTS
    1068                 :             : !!
    1069                 :             : !! SOURCE
    1070                 :      160806 : subroutine solve_inner(invovl, ham, cplx, mpi_enreg, proj, ndat, sm1proj, PtPsm1proj, block_sliced)
    1071                 :             : 
    1072                 :             :  use m_abi_linalg
    1073                 :             : 
    1074                 :             :  integer,intent(in) :: ndat,cplx
    1075                 :             :  type(invovl_kpt_type), intent(in) :: invovl
    1076                 :             :  real(dp), intent(inout) :: proj(cplx, invovl%nprojs,ndat)
    1077                 :             :  real(dp), intent(inout) :: sm1proj(cplx, invovl%nprojs, ndat)
    1078                 :             :  real(dp), intent(inout) :: PtPsm1proj(cplx, invovl%nprojs, ndat)
    1079                 :      160806 :  real(dp), allocatable :: temp_proj(:,:,:)
    1080                 :             :  type(mpi_type), intent(in) :: mpi_enreg
    1081                 :             :  type(gs_hamiltonian_type),intent(in) :: ham
    1082                 :             :  integer, intent(in) :: block_sliced
    1083                 :             : 
    1084                 :      321612 :  integer :: array_nlmntot_pp(mpi_enreg%nproc_fft)
    1085                 :             :  integer :: nlmntot_this_proc, ibeg, iend, ierr, i, nprojs
    1086                 :      321612 :  real(dp) :: resid(cplx, invovl%nprojs,ndat), precondresid(cplx, invovl%nprojs,ndat)
    1087                 :      321612 :  real(dp) :: normprojs(ndat), errs(ndat), maxerr, previous_maxerr
    1088                 :             :  character(len=500) :: message
    1089                 :             : 
    1090                 :             :  real(dp), parameter :: precision = 1e-16 ! maximum relative error. TODO: use tolwfr ?
    1091                 :             :  real(dp) :: convergence_rate
    1092                 :             :  integer :: additional_steps_to_take
    1093                 :             : 
    1094                 :             : ! *************************************************************************
    1095                 :             : 
    1096                 :      160806 :  nprojs = invovl%nprojs
    1097   [ +  +  +  +  :    65308502 :  normprojs = SUM(SUM(proj**2, 1),1)
                   +  + ]
    1098                 :      160806 :  call xmpi_sum(normprojs, mpi_enreg%comm_fft, ierr)
    1099                 :             : 
    1100                 :             :  ! Compute work distribution : split nprojs evenly between the fft processors
    1101         [ +  + ]:      160806 :  if(mpi_enreg%paral_kgb == 1) then
    1102         [ +  + ]:      125208 :    array_nlmntot_pp(:) = nprojs / mpi_enreg%nproc_fft
    1103                 :             :    ! not enough work, there's MOD(nprojs,mpi_enreg%nproc_fft) tasks left
    1104                 :             :    ! assign them to the first ones
    1105         [ -  + ]:       62460 :    array_nlmntot_pp(1:MOD(nprojs,mpi_enreg%nproc_fft)) = array_nlmntot_pp(1:MOD(nprojs,mpi_enreg%nproc_fft)) + 1
    1106         [ +  + ]:       62604 :    ibeg = SUM(array_nlmntot_pp(1:mpi_enreg%me_fft)) + 1
    1107                 :       62460 :    iend = ibeg + array_nlmntot_pp(1+mpi_enreg%me_fft) - 1
    1108                 :       62460 :    nlmntot_this_proc = iend - ibeg + 1
    1109                 :             :  else
    1110                 :       98346 :    ibeg = 1
    1111                 :       98346 :    iend = nprojs
    1112                 :       98346 :    nlmntot_this_proc = nprojs
    1113                 :             :  end if
    1114                 :             : 
    1115   [ -  +  +  -  :      804030 :  ABI_MALLOC(temp_proj, (cplx, nlmntot_this_proc, ndat))
          -  +  +  -  -  
          +  +  -  +  -  
          +  -  -  +  -  
                      + ]
    1116                 :             : 
    1117                 :             :  ! first guess for sm1proj
    1118                 :      160806 :  call apply_block(ham, cplx, invovl%inv_s_approx, nprojs, ndat, proj, sm1proj, block_sliced)
    1119                 :             : 
    1120                 :             :  ! Iterative refinement
    1121                 :             :  ! TODO use a more efficient iterative algorithm than iterative refinement, use locking
    1122                 :      160806 :  additional_steps_to_take = -1
    1123         [ +  - ]:     1476115 :  do i=1, 30
    1124                 :             :    ! compute resid = proj - (D^-1 + PtP)sm1proj
    1125                 :     1476115 :    call apply_block(ham, cplx, invovl%inv_sij, nprojs, ndat, sm1proj, resid, block_sliced)
    1126   [ +  -  -  +  :   724585084 :    temp_proj = sm1proj(:,ibeg:iend,:)
          -  -  +  +  +  
                +  +  + ]
    1127                 :             : 
    1128                 :             :    ! compute matrix multiplication : PtPsm1proj(:,:,1) = invovl%gram * temp_proj(:,:,1)
    1129                 :             :    call abi_xgemm('N', 'N', nprojs, ndat, nlmntot_this_proc, cone, &
    1130                 :             :      & invovl%gram_projs(:,:,1), nprojs, &
    1131                 :             :      & temp_proj(:,:,1), nlmntot_this_proc, czero, &
    1132                 :             :      & PtPsm1proj(:,:,1), nprojs, &
    1133                 :     1476115 :      & x_cplx=cplx)
    1134                 :     1476115 :    call xmpi_sum(PtPsm1proj, mpi_enreg%comm_fft, ierr)
    1135   [ +  +  +  +  :   723593097 :    resid = proj - resid - Ptpsm1proj
                   +  + ]
    1136                 :             :    ! exit check
    1137   [ +  +  +  +  :   723593097 :    errs = SUM(SUM(resid**2, 1),1)
                   +  + ]
    1138                 :     1476115 :    call xmpi_sum(errs, mpi_enreg%comm_fft, ierr)
    1139                 :             : 
    1140   [ +  -  -  +  :    13553758 :    maxerr = sqrt(MAXVAL(errs/normprojs))
             -  -  +  + ]
    1141   [ +  +  +  + ]:     1476115 :    if(maxerr < precision .or. additional_steps_to_take == 1) then
    1142                 :             :      exit
    1143                 :             :      ! We might stall and never get to the specified precision because of machine errors.
    1144                 :             :      ! If we got to 1e-10, extrapolate convergence rate and determine the number of additional
    1145                 :             :      ! steps to take to reach precision
    1146   [ +  +  +  + ]:     1398471 :    else if(maxerr < 1e-10 .and. additional_steps_to_take == -1) then
    1147                 :      160806 :      convergence_rate = -LOG(1e-10) / i
    1148         [ -  + ]:      160806 :      additional_steps_to_take = CEILING(-LOG(precision/1e-10)/convergence_rate) + 1
    1149         [ +  + ]:     1237665 :    else if(additional_steps_to_take > 0) then
    1150         [ +  + ]:      525573 :      if(previous_maxerr<maxerr)exit
    1151                 :      442411 :      additional_steps_to_take = additional_steps_to_take - 1
    1152                 :             :    end if
    1153                 :     1315309 :    previous_maxerr=maxerr
    1154                 :             : 
    1155                 :             :    ! add preconditionned residual
    1156                 :     1315309 :    call apply_block(ham, cplx, invovl%inv_s_approx, nprojs, ndat, resid, precondresid, block_sliced)
    1157   [ +  +  +  +  :   658445401 :    sm1proj = sm1proj + precondresid
                   +  + ]
    1158                 :             :  end do
    1159                 :             : 
    1160   [ +  +  -  + ]:      160806 :  if(maxerr >= precision .and. maxerr >= 1e-10) then
    1161                 :           0 :    write(message, *) 'In invovl, max error was', maxerr, ' after 30 iterations'
    1162                 :           0 :    ABI_WARNING(message)
    1163                 :             :  else
    1164                 :             :    ! write(message,'(a,i2,a,es13.5)') 'Iterative solver in invovl finished in ', i, ' iterations, error', maxerr
    1165                 :             :    ! call wrtout(std_out,message,'COLL')
    1166                 :             :  end if
    1167                 :             : 
    1168         [ -  + ]:      160806 :  ABI_FREE(temp_proj)
    1169                 :             : 
    1170                 :      160806 : end subroutine solve_inner
    1171                 :             : !!***
    1172                 :             : 
    1173                 :             : !!****f* m_invovl/apply_block
    1174                 :             : !! NAME
    1175                 :             : !! apply_block
    1176                 :             : !!
    1177                 :             : !! FUNCTION
    1178                 :             : !! Helper function: applies a block-diagonal matrix mat(lmnmax, lmnmax, ntypat)
    1179                 :             : !!
    1180                 :             : !! INPUTS
    1181                 :             : !!
    1182                 :             : !! SOURCE
    1183                 :     2952230 : subroutine apply_block(ham, cplx, mat, nprojs, ndat, x, y, block_sliced)
    1184                 :             : 
    1185                 :             :   use m_abi_linalg
    1186                 :             : 
    1187                 :             :   integer,intent(in) :: ndat, nprojs, cplx
    1188                 :             :   real(dp), intent(inout), target :: x(cplx, nprojs, ndat), y(cplx, nprojs, ndat)
    1189                 :             :   type(gs_hamiltonian_type),intent(in) :: ham
    1190                 :             :   real(dp), intent(in) :: mat(cplx, ham%lmnmax, ham%lmnmax, ham%ntypat)
    1191                 :             :   integer, intent(in) :: block_sliced
    1192                 :             : 
    1193                 :             :   integer :: nlmn, shift, itypat, idat
    1194                 :     2952230 :   real(dp),pointer :: work_x(:,:),work_y(:,:)
    1195                 :             : 
    1196                 :             : ! *************************************************************************
    1197                 :             : 
    1198                 :     2952230 :   if (block_sliced == 1) then
    1199                 :             : 
    1200         [ +  + ]:    24155286 :      do idat = 1, ndat
    1201                 :    21203056 :         shift = 1
    1202         [ +  + ]:    52113246 :         do itypat=1, ham%ntypat
    1203   [ +  +  +  + ]:   271874380 :            nlmn = count(ham%indlmn(3,:,itypat)>0)
    1204                 :             :            !! apply mat to all atoms at once
    1205                 :             :            ! perform natom multiplications of size nlmn
    1206                 :             :            ! compute y = mat*x
    1207                 :    27957960 :            work_x => x(:, shift:shift+nlmn*ham%nattyp(itypat)-1, idat)
    1208                 :    27957960 :            work_y => y(:, shift:shift+nlmn*ham%nattyp(itypat)-1, idat)
    1209         [ +  + ]:    27957960 :            if(cplx == 2) then
    1210                 :             :               call ZHEMM('L','U', nlmn, ham%nattyp(itypat), cone, &
    1211                 :             :                    &  mat(:, :, :, itypat), ham%lmnmax, &
    1212                 :             :                    &  work_x, nlmn, czero, &
    1213   [ -  +  -  + ]:    25098432 :                    &  work_y, nlmn)
    1214                 :             :            else
    1215                 :             :               call DSYMM('L','U', nlmn, ham%nattyp(itypat), one, &
    1216                 :             :                    &  mat(:, :, :, itypat), ham%lmnmax, &
    1217                 :             :                    &  work_x, nlmn, zero, &
    1218   [ -  +  -  + ]:     2859528 :                    &  work_y, nlmn)
    1219                 :             :            end if
    1220                 :    49161016 :            shift = shift + nlmn*ham%nattyp(itypat)
    1221                 :             :         end do
    1222                 :             :      end do
    1223                 :             : 
    1224                 :             :   else ! block_sliced = 0
    1225                 :             : 
    1226                 :             :      shift = 1
    1227         [ #  # ]:           0 :      do itypat=1, ham%ntypat
    1228   [ #  #  #  # ]:           0 :         nlmn = count(ham%indlmn(3,:,itypat)>0)
    1229                 :             :         !! apply mat to all atoms at once, all idat at once
    1230                 :             :         ! perform natom multiplications of size nlmn
    1231                 :             :         ! be careful here matrix extracted from x and y are not memory contiguous
    1232                 :             :         ! ==> so in the GPU version we will need to adapt leading dimension
    1233         [ #  # ]:           0 :         if(cplx == 2) then
    1234                 :             :            call ZHEMM('L','U', nlmn, ham%nattyp(itypat)*ndat, cone, &
    1235                 :             :                 &  mat(:, :, :, itypat), ham%lmnmax, &
    1236                 :             :                 &  x(:, 1:nlmn*ham%nattyp(itypat), 1:ndat), nlmn, czero, &
    1237   [ #  #  #  #  :           0 :                 &  y(:, 1:shift+nlmn*ham%nattyp(itypat)-1, 1:ndat), nlmn)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1238                 :             :         else
    1239                 :             :            call DSYMM('L','U', nlmn, ham%nattyp(itypat)*ndat, one, &
    1240                 :             :                 &  mat(:, :, :, itypat), ham%lmnmax, &
    1241                 :             :                 &  x(:, shift:shift+nlmn*ham%nattyp(itypat)-1, 1:ndat), nlmn, zero, &
    1242   [ #  #  #  #  :           0 :                 &  y(:, shift:shift+nlmn*ham%nattyp(itypat)-1, 1:ndat), nlmn)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1243                 :             :         end if
    1244                 :           0 :         shift = shift + nlmn*ham%nattyp(itypat)
    1245                 :             :      end do
    1246                 :             : 
    1247                 :             :   end if
    1248                 :             : 
    1249         [ -  + ]:     2952230 : end subroutine apply_block
    1250                 :             : !!***
    1251                 :             : 
    1252                 :           0 :  function invovl_ompgpu_work_mem(ham, ndat) result(req_mem)
    1253                 :             : 
    1254                 :             :    type(gs_hamiltonian_type), intent(in) :: ham
    1255                 :             :    integer, intent(in) :: ndat
    1256                 :             :    integer :: nprojs, cplx, itypat
    1257                 :             :    integer(kind=c_size_t) :: req_mem
    1258                 :             : 
    1259                 :           0 :    nprojs = 0
    1260         [ #  # ]:           0 :    do itypat=1,ham%ntypat
    1261   [ #  #  #  # ]:           0 :      nprojs = nprojs + count(ham%indlmn(3,:,itypat)>0)*ham%nattyp(itypat)
    1262                 :             :    end do
    1263         [ #  # ]:           0 :    cplx = 2; if(ham%istwf_k == 2) cplx = 1
    1264                 :             : 
    1265                 :           0 :    req_mem = 0
    1266                 :           0 :    req_mem = req_mem + dp * cplx * int(nprojs, c_size_t) * int(ndat, c_size_t)  ! proj
    1267                 :             :    req_mem = req_mem + dp * cplx * int(nprojs, c_size_t) * int(ndat, c_size_t)  ! sm1proj
    1268                 :             :    req_mem = req_mem + dp * cplx * int(nprojs, c_size_t) * int(ndat, c_size_t)  ! PtPsm1proj
    1269                 :           0 :    req_mem = req_mem + dp * cplx * int(nprojs, c_size_t) * int(ndat, c_size_t)  ! resid (solve_inner)
    1270                 :           0 :    req_mem = req_mem + dp * cplx * int(nprojs, c_size_t) * int(ndat, c_size_t)  ! precondresid (solve_inner)
    1271                 :             : 
    1272                 :           0 :  end function invovl_ompgpu_work_mem
    1273                 :             : 
    1274                 :           0 :  function invovl_ompgpu_static_mem(ham) result(req_mem)
    1275                 :             : 
    1276                 :             :    type(gs_hamiltonian_type), intent(in) :: ham
    1277                 :             :    integer :: nprojs, cplx, itypat
    1278                 :             :    integer(kind=c_size_t) :: req_mem
    1279                 :             : 
    1280                 :           0 :    nprojs = 0
    1281         [ #  # ]:           0 :    do itypat=1,ham%ntypat
    1282   [ #  #  #  # ]:           0 :      nprojs = nprojs + count(ham%indlmn(3,:,itypat)>0)*ham%nattyp(itypat)
    1283                 :             :    end do
    1284         [ #  # ]:           0 :    cplx = 2; if(ham%istwf_k > 1) cplx = 1
    1285                 :             : 
    1286                 :           0 :    req_mem = 0
    1287                 :           0 :    req_mem = req_mem + dp * cplx * int(nprojs, c_size_t) * int(nprojs, c_size_t)                       ! gram_projs
    1288                 :             :    req_mem = req_mem + dp * cplx * int(ham%lmnmax, c_size_t) * &
    1289                 :           0 :    &         int(ham%lmnmax, c_size_t) * int(ham%ntypat, c_size_t)  ! inv_sij
    1290                 :             :    req_mem = req_mem + dp * cplx * int(ham%lmnmax, c_size_t) * &
    1291                 :           0 :    &         int(ham%lmnmax, c_size_t) * int(ham%ntypat, c_size_t)  ! inv_s_approx
    1292                 :             : 
    1293                 :           0 :  end function invovl_ompgpu_static_mem
    1294                 :             : 
    1295                 :             : #ifdef HAVE_OPENMP_OFFLOAD
    1296                 :             : !*******************************************************************************************************************************!
    1297                 :             : !                                               OpenMP GPU routines                                                             !
    1298                 :             : !*******************************************************************************************************************************!
    1299                 :             : 
    1300                 :             : !!****f* m_invovl/apply_invovl_ompgpu
    1301                 :             : !! NAME
    1302                 :             : !! apply_invovl_ompgpu
    1303                 :             : !!
    1304                 :             : !! FUNCTION
    1305                 :             : !! Applies the inverse of the overlap matrix to cwavef (OpenMP GPU implementation)
    1306                 :             : !!
    1307                 :             : !! INPUTS
    1308                 :             : !!
    1309                 :             : !! SOURCE
    1310                 :             : 
    1311                 :             : subroutine apply_invovl_ompgpu(ham, cwavef, sm1cwavef, cwaveprj, npw, ndat, mpi_enreg, nspinor, block_sliced)
    1312                 :             : 
    1313                 :             : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU)
    1314                 :             :   use, intrinsic :: iso_c_binding
    1315                 :             : #endif
    1316                 :             : 
    1317                 :             :   ! args
    1318                 :             :   type(gs_hamiltonian_type), intent(in), target :: ham
    1319                 :             :   integer, intent(in) :: npw, ndat
    1320                 :             :   integer, intent(in) :: nspinor
    1321                 :             :   integer, intent(in) :: block_sliced
    1322                 :             :   real(dp), intent(inout), target :: cwavef(2, npw*nspinor*ndat) ! TODO should be in, fix nonlop
    1323                 :             :   type(mpi_type) :: mpi_enreg
    1324                 :             :   real(dp), intent(inout), target :: sm1cwavef(2, npw*nspinor*ndat)
    1325                 :             :   type(pawcprj_type), intent(inout) :: cwaveprj(:,:)
    1326                 :             :   logical :: transfer_omp_args
    1327                 :             : 
    1328                 :             :   real(dp), ABI_CONTIGUOUS pointer :: proj(:,:,:),sm1proj(:,:,:),PtPsm1proj(:,:,:)
    1329                 :             : 
    1330                 :             :   integer :: idat, iatom, icplx, iproj, nprojs, nlmn, shift
    1331                 :             :   real(dp) :: tsec(2)
    1332                 :             : 
    1333                 :             :   integer :: choice, cpopt, paw_opt , cplx, old_me_g0
    1334                 :             :   type(pawcprj_type),allocatable :: cwaveprj_in(:,:)
    1335                 :             : 
    1336                 :             :   integer :: ikpt_this_proc
    1337                 :             :   ! dummies
    1338                 :             :   real(dp) :: enlout(ndat), lambda_block(1), gvnlxc(1,1)
    1339                 :             :   integer, parameter :: nnlout = 0, idir = 0, signs = 2
    1340                 :             : 
    1341                 :             :   type(invovl_kpt_type), pointer :: invovl
    1342                 :             : 
    1343                 :             :   ! *************************************************************************
    1344                 :             : 
    1345                 :             :   ikpt_this_proc=bandfft_kpt_get_ikpt()
    1346                 :             :   invovl => invovl_kpt(ikpt_this_proc)
    1347                 :             :   nprojs=invovl%nprojs
    1348                 :             :   if(ikpt_this_proc /= current_ikpt_in_gpu) call refresh_invovl_ompgpu_kpt(ikpt_this_proc)
    1349                 :             : 
    1350                 :             :   if(ham%istwf_k == 1) then
    1351                 :             :     cplx = 2
    1352                 :             :   else
    1353                 :             :     cplx = 1
    1354                 :             :   end if
    1355                 :             :   call alloc_ompgpu_buffers(cplx,nprojs,nspinor,ndat)
    1356                 :             :   proj => proj_ompgpu
    1357                 :             :   sm1proj => sm1proj_ompgpu
    1358                 :             :   PtPsm1proj => PtPsm1proj_ompgpu
    1359                 :             :   !$OMP TARGET ENTER DATA MAP(alloc:proj,sm1proj,PtPsm1proj)
    1360                 :             : 
    1361                 :             :   transfer_omp_args =  .not. ( xomp_target_is_present(c_loc(sm1cwavef)) &
    1362                 :             :    .and. xomp_target_is_present(c_loc(cwavef)))
    1363                 :             :   !$OMP TARGET ENTER DATA MAP(alloc:gvnlxc)
    1364                 :             :   if(transfer_omp_args) then
    1365                 :             :    !$OMP TARGET ENTER DATA MAP(alloc:sm1cwavef,cwavef)
    1366                 :             :    !$OMP TARGET UPDATE TO(sm1cwavef,cwavef)
    1367                 :             :   end if
    1368                 :             : 
    1369                 :             :   call timab(timer_apply_inv_ovl_opernla, 1, tsec)
    1370                 :             : 
    1371                 :             :   ! get the cprj
    1372                 :             :   ABI_NVTX_START_RANGE(NVTX_INVOVL_NONLOP1)
    1373                 :             :   choice = 0 ! only compute cprj, nothing else
    1374                 :             :   cpopt = 0 ! compute and save cprj
    1375                 :             :   paw_opt = 3 ! S nonlocal operator
    1376                 :             : 
    1377                 :             :   if(ham%istwf_k==2) then
    1378                 :             :     old_me_g0=mpi_enreg%me_g0
    1379                 :             :     if (mpi_enreg%me_fft==0) then
    1380                 :             :       mpi_enreg%me_g0=1
    1381                 :             :     else
    1382                 :             :       mpi_enreg%me_g0=0
    1383                 :             :     end if
    1384                 :             :   end if
    1385                 :             :   call nonlop(choice,cpopt,cwaveprj_in,enlout,ham,idir,lambda_block,mpi_enreg,ndat,nnlout,&
    1386                 :             :                 paw_opt,signs,sm1cwavef,tim_nonlop,cwavef,gvnlxc,vectproj=proj)
    1387                 :             :   ABI_NVTX_END_RANGE()
    1388                 :             : 
    1389                 :             :   call timab(timer_apply_inv_ovl_opernla, 2, tsec)
    1390                 :             :   call timab(timer_apply_inv_ovl_inv_s, 1, tsec)
    1391                 :             : 
    1392                 :             :   !multiply by S^1
    1393                 :             :   ABI_NVTX_START_RANGE(NVTX_INVOVL_INNER)
    1394                 :             :   call solve_inner_ompgpu(invovl, ham, cplx, mpi_enreg, proj, ndat*nspinor, sm1proj, PtPsm1proj, block_sliced)
    1395                 :             :   !$OMP TARGET TEAMS DISTRIBUTE MAP(to:sm1proj,PtPsm1proj)
    1396                 :             :   do idat  =1, ndat*nspinor
    1397                 :             :     !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(iproj,icplx)
    1398                 :             :     do iproj = 1, nprojs
    1399                 :             :       do icplx = 1, cplx
    1400                 :             :         sm1proj(icplx,iproj,idat) = - sm1proj(icplx,iproj,idat)
    1401                 :             :         PtPsm1proj(icplx,iproj,idat) = - PtPsm1proj(icplx,iproj,idat)
    1402                 :             :       end do
    1403                 :             :     end do
    1404                 :             :   end do
    1405                 :             : 
    1406                 :             :   ABI_NVTX_END_RANGE()
    1407                 :             : 
    1408                 :             :   call timab(timer_apply_inv_ovl_inv_s, 2, tsec)
    1409                 :             :   call timab(timer_apply_inv_ovl_opernlb, 1, tsec)
    1410                 :             : 
    1411                 :             :   ! get the corresponding wf
    1412                 :             :   ABI_NVTX_START_RANGE(NVTX_INVOVL_NONLOP2)
    1413                 :             :   cpopt = 2 ! reuse cprj
    1414                 :             :   choice = 7 ! get wf from cprj, without the application of S
    1415                 :             :   paw_opt = 3
    1416                 :             :   call nonlop(choice,cpopt,cwaveprj,enlout,ham,idir,lambda_block,mpi_enreg,ndat,nnlout,paw_opt,&
    1417                 :             :               signs,sm1cwavef,tim_nonlop,cwavef,gvnlxc,vectproj=sm1proj)
    1418                 :             :   ABI_NVTX_END_RANGE()
    1419                 :             : 
    1420                 :             :   call timab(timer_apply_inv_ovl_opernlb, 2, tsec)
    1421                 :             :   if (ham%istwf_k==2) mpi_enreg%me_g0=old_me_g0
    1422                 :             : 
    1423                 :             :   if(size(cwaveprj) > 1) then
    1424                 :             :     ABI_MALLOC(cwaveprj_in, (ham%natom,nspinor*ndat))
    1425                 :             :     call pawcprj_alloc(cwaveprj_in,0,ham%dimcprj)
    1426                 :             :     !$OMP TARGET UPDATE FROM(PtPsm1proj,proj)
    1427                 :             :     ! copy PtPsm1proj to cwaveprj(:,:)
    1428                 :             :     do idat=1, ndat*nspinor
    1429                 :             :       shift = 0
    1430                 :             :       do iatom = 1, ham%natom
    1431                 :             :         nlmn = cwaveprj(iatom, idat)%nlmn
    1432                 :             :         cwaveprj(iatom, idat)%cp(1:cplx, 1:nlmn) = PtPsm1proj(1:cplx, shift+1:shift+nlmn, idat)
    1433                 :             :         shift = shift + nlmn
    1434                 :             :       end do
    1435                 :             :     end do
    1436                 :             :     do idat=1, ndat*nspinor
    1437                 :             :       shift = 0
    1438                 :             :       do iatom = 1, ham%natom
    1439                 :             :         nlmn = cwaveprj_in(iatom, idat)%nlmn
    1440                 :             :         cwaveprj_in(iatom, idat)%cp(1:cplx, 1:nlmn) = proj(1:cplx, shift+1:shift+nlmn, idat)
    1441                 :             :         shift = shift + nlmn
    1442                 :             :       end do
    1443                 :             :     end do
    1444                 :             :     call pawcprj_axpby(one, one, cwaveprj_in, cwaveprj)
    1445                 :             :     call pawcprj_free(cwaveprj_in)
    1446                 :             :     ABI_FREE(cwaveprj_in)
    1447                 :             :   end if
    1448                 :             : 
    1449                 :             :   call abi_xaxpy(2*npw*nspinor*ndat, cone, cwavef, 1, sm1cwavef, 1, gpu_option=ABI_GPU_OPENMP)
    1450                 :             : 
    1451                 :             :   if(transfer_omp_args) then
    1452                 :             :     !$OMP TARGET UPDATE FROM(sm1cwavef,cwavef)
    1453                 :             :     !$OMP TARGET EXIT DATA MAP(delete:sm1cwavef,cwavef)
    1454                 :             :   end if
    1455                 :             : 
    1456                 :             :   !$OMP TARGET EXIT DATA MAP(delete:gvnlxc)
    1457                 :             :   !$OMP TARGET EXIT DATA MAP(delete:proj,sm1proj,PtPsm1proj)
    1458                 :             : 
    1459                 :             : end subroutine apply_invovl_ompgpu
    1460                 :             : !!***
    1461                 :             : 
    1462                 :             : !!****f* m_invovl/solve_inner_ompgpu
    1463                 :             : !! NAME
    1464                 :             : !! solve_inner_ompgpu
    1465                 :             : !!
    1466                 :             : !! FUNCTION
    1467                 :             : !! Helper function: iteratively solves the inner system (OpenMP GPU offload implementation)
    1468                 :             : !!
    1469                 :             : !! INPUTS
    1470                 :             : !!
    1471                 :             : !! SOURCE
    1472                 :             : subroutine solve_inner_ompgpu(invovl, ham, cplx, mpi_enreg, proj, ndat, sm1proj, PtPsm1proj, block_sliced)
    1473                 :             : 
    1474                 :             :  use m_abi_linalg
    1475                 :             : 
    1476                 :             :  integer,intent(in) :: ndat,cplx
    1477                 :             :  type(invovl_kpt_type), intent(in), target :: invovl
    1478                 :             :  real(dp), intent(inout) :: proj(cplx, invovl%nprojs,ndat)
    1479                 :             :  real(dp), intent(inout), target :: sm1proj(cplx, invovl%nprojs, ndat)
    1480                 :             :  real(dp), intent(inout), target :: PtPsm1proj(cplx, invovl%nprojs, ndat)
    1481                 :             :  type(mpi_type), intent(in) :: mpi_enreg
    1482                 :             :  type(gs_hamiltonian_type),intent(in) :: ham
    1483                 :             :  integer, intent(in) :: block_sliced
    1484                 :             : 
    1485                 :             :  integer :: array_nlmntot_pp(mpi_enreg%nproc_fft)
    1486                 :             :  integer :: nlmntot_this_proc, ibeg, iend, ierr, i, nprojs
    1487                 :             :  real(dp) :: resid(cplx, invovl%nprojs,ndat), precondresid(cplx, invovl%nprojs,ndat)
    1488                 :             :  real(dp) :: normprojs(ndat), errs(ndat), maxerr, previous_maxerr
    1489                 :             :  character(len=500) :: message
    1490                 :             : 
    1491                 :             :  real(dp), parameter :: precision = 1e-16 ! maximum relative error. TODO: use tolwfr ?
    1492                 :             :  real(dp) :: convergence_rate,sum_tmp
    1493                 :             :  integer :: additional_steps_to_take,idat,iproj,icplx
    1494                 :             :  integer :: Ptsize(3)
    1495                 :             : 
    1496                 :             : ! *************************************************************************
    1497                 :             : 
    1498                 :             :  Ptsize(1) = cplx
    1499                 :             :  Ptsize(2) = invovl%nprojs
    1500                 :             :  Ptsize(3) = ndat
    1501                 :             :  nprojs = invovl%nprojs
    1502                 :             : 
    1503                 :             :  !$OMP TARGET ENTER DATA MAP(alloc:errs,precondresid,resid,normprojs)
    1504                 :             : 
    1505                 :             :  !FIXME LLVM has trouble with performing team reduction (AOMP 15.0.2)
    1506                 :             : #ifdef FC_LLVM
    1507                 :             :  !$OMP TARGET UPDATE FROM(proj)
    1508                 :             : #else
    1509                 :             :  !$OMP TARGET TEAMS DISTRIBUTE MAP(to:normprojs,proj) PRIVATE(idat,sum_tmp)
    1510                 :             : #endif
    1511                 :             :  do idat = 1,ndat
    1512                 :             :   sum_tmp=0
    1513                 :             : #ifndef FC_LLVM
    1514                 :             :   !$OMP PARALLEL DO COLLAPSE(2) REDUCTION(+:sum_tmp) PRIVATE(iproj,icplx)
    1515                 :             : #endif
    1516                 :             :   do iproj = 1,nprojs
    1517                 :             :     do icplx = 1,cplx
    1518                 :             :       sum_tmp = sum_tmp + proj(icplx,iproj,idat)**2
    1519                 :             :     end do
    1520                 :             :   end do
    1521                 :             :   normprojs(idat)=sum_tmp
    1522                 :             :  end do
    1523                 :             : #ifndef FC_LLVM
    1524                 :             :  !$OMP TARGET UPDATE FROM(normprojs)
    1525                 :             : #endif
    1526                 :             : 
    1527                 :             :  ibeg = 1
    1528                 :             :  iend = nprojs
    1529                 :             :  nlmntot_this_proc = nprojs
    1530                 :             : 
    1531                 :             :  ! first guess for sm1proj
    1532                 :             :  call apply_block_ompgpu(ham, cplx, invovl%inv_s_approx, nprojs, ndat, proj, sm1proj, block_sliced)
    1533                 :             : 
    1534                 :             :  ! Iterative refinement
    1535                 :             :  ! TODO use a more efficient iterative algorithm than iterative refinement, use locking
    1536                 :             :  additional_steps_to_take = -1
    1537                 :             :  do i=1, 30
    1538                 :             : #ifdef FC_NVHPC
    1539                 :             :    ! Silly fix for NVHPC 25.1
    1540                 :             :    if(ndat == -42) write(100,*) ndat
    1541                 :             : #endif
    1542                 :             :    ! compute resid = proj - (D^-1 + PtP)sm1proj
    1543                 :             :    call apply_block_ompgpu(ham, cplx, invovl%inv_sij, nprojs, ndat, sm1proj, resid, block_sliced)
    1544                 :             : 
    1545                 :             :    ! compute matrix multiplication : PtPsm1proj(:,:,1) = invovl%gram * sm1proj(:,:,1)
    1546                 :             :    ABI_NVTX_START_RANGE(NVTX_INVOVL_INNER_GEMM)
    1547                 :             :    call abi_xgemm('N', 'N', nprojs, ndat, nlmntot_this_proc, cone, &
    1548                 :             :    &              current_gram_projs, nprojs,&
    1549                 :             :    &              sm1proj, nlmntot_this_proc, czero, &
    1550                 :             :    &              PtPsm1proj, nprojs, &
    1551                 :             :    &              x_cplx=cplx, gpu_option=ABI_GPU_OPENMP)
    1552                 :             : 
    1553                 :             :    !$OMP TARGET TEAMS DISTRIBUTE &
    1554                 :             :    !$OMP& PRIVATE(idat) MAP(to:proj,resid,PtPsm1proj)
    1555                 :             :    do idat =1, ndat
    1556                 :             :      !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(iproj,icplx)
    1557                 :             :      do iproj =1, nprojs
    1558                 :             :        do icplx = 1,cplx
    1559                 :             :          resid(icplx, iproj, idat) = proj(icplx, iproj, idat) - resid(icplx, iproj, idat) - PtPsm1proj(icplx, iproj, idat)
    1560                 :             :        end do
    1561                 :             :      end do
    1562                 :             :    end do
    1563                 :             : 
    1564                 :             :    ! exit check
    1565                 :             : #ifdef FC_LLVM
    1566                 :             :    !FIXME LLVM has trouble with performing team reduction (v16.0.0 from AMD ROCm 5.6.0)
    1567                 :             :    !$OMP TARGET UPDATE FROM(resid)
    1568                 :             :    errs = SUM(SUM(resid**2, 1),1)
    1569                 :             : #else
    1570                 :             :    !$OMP TARGET TEAMS DISTRIBUTE MAP(to:errs,resid) PRIVATE(idat,sum_tmp)
    1571                 :             :    do idat = 1,ndat
    1572                 :             :      sum_tmp=0
    1573                 :             :      !$OMP PARALLEL DO COLLAPSE(2) REDUCTION(+:sum_tmp) PRIVATE(iproj,icplx)
    1574                 :             :      do iproj = 1,nprojs
    1575                 :             :        do icplx = 1,cplx
    1576                 :             :          sum_tmp = sum_tmp + resid(icplx,iproj,idat)**2
    1577                 :             :        end do
    1578                 :             :      end do
    1579                 :             :      errs(idat)=sum_tmp
    1580                 :             :    end do
    1581                 :             :    !$OMP TARGET UPDATE FROM(errs)
    1582                 :             : #endif
    1583                 :             : 
    1584                 :             :    ABI_NVTX_END_RANGE()
    1585                 :             : 
    1586                 :             :    maxerr = sqrt(MAXVAL(errs/normprojs))
    1587                 :             :    if(maxerr < precision .or. additional_steps_to_take == 1) then
    1588                 :             :      exit
    1589                 :             :      ! We might stall and never get to the specified precision because of machine errors.
    1590                 :             :      ! If we got to 1e-10, extrapolate convergence rate and determine the number of additional
    1591                 :             :      ! steps to take to reach precision
    1592                 :             :    else if(maxerr < 1e-10 .and. additional_steps_to_take == -1) then
    1593                 :             :      convergence_rate = -LOG(1e-10) / i
    1594                 :             :      additional_steps_to_take = CEILING(-LOG(precision/1e-10)/convergence_rate) + 1
    1595                 :             :    else if(additional_steps_to_take > 0) then
    1596                 :             :      if(previous_maxerr<maxerr)exit
    1597                 :             :      additional_steps_to_take = additional_steps_to_take - 1
    1598                 :             :    end if
    1599                 :             :    previous_maxerr=maxerr
    1600                 :             : 
    1601                 :             :    ! add preconditionned residual
    1602                 :             :    call apply_block_ompgpu(ham, cplx, invovl%inv_s_approx, nprojs, ndat, resid, precondresid, block_sliced)
    1603                 :             : 
    1604                 :             :    !$OMP TARGET TEAMS DISTRIBUTE &
    1605                 :             :    !$OMP& PRIVATE(idat) MAP(to:sm1proj,precondresid)
    1606                 :             :    do idat =1, ndat
    1607                 :             :      !$OMP PARALLEL DO PRIVATE(iproj,icplx) COLLAPSE(2)
    1608                 :             :      do iproj =1, nprojs
    1609                 :             :        do icplx = 1,cplx
    1610                 :             :          sm1proj(icplx, iproj, idat) = sm1proj(icplx, iproj, idat) + precondresid(icplx, iproj, idat)
    1611                 :             :        end do
    1612                 :             :      end do
    1613                 :             :    end do
    1614                 :             :  end do
    1615                 :             :  !$OMP TARGET EXIT DATA MAP(delete:errs,resid,precondresid,normprojs)
    1616                 :             : 
    1617                 :             :  if(maxerr >= precision .and. maxerr >= 1e-10) then
    1618                 :             :    write(message, *) 'In invovl, max error was', maxerr, ' after 30 iterations'
    1619                 :             :    ABI_WARNING(message)
    1620                 :             :  else
    1621                 :             :    ! write(message,'(a,i2,a,es13.5)') 'Iterative solver in invovl finished in ', i, ' iterations, error', maxerr
    1622                 :             :    ! call wrtout(std_out,message,'COLL')
    1623                 :             :  end if
    1624                 :             : 
    1625                 :             : end subroutine solve_inner_ompgpu
    1626                 :             : !!***
    1627                 :             : 
    1628                 :             : !!****f* m_invovl/apply_block_ompgpu
    1629                 :             : !! NAME
    1630                 :             : !! apply_block_ompgpu
    1631                 :             : !!
    1632                 :             : !! FUNCTION
    1633                 :             : !! Helper function: applies a block-diagonal matrix mat(lmnmax, lmnmax, ntypat)
    1634                 :             : !!
    1635                 :             : !! INPUTS
    1636                 :             : !!
    1637                 :             : !! SOURCE
    1638                 :             : subroutine apply_block_ompgpu(ham, cplx, mat, nprojs, ndat, x, y, block_sliced)
    1639                 :             : 
    1640                 :             :   use m_abi_linalg
    1641                 :             : 
    1642                 :             :   integer,intent(in) :: ndat, nprojs, cplx
    1643                 :             :   real(dp), intent(inout), target :: x(cplx, nprojs, ndat), y(cplx, nprojs, ndat)
    1644                 :             :   type(gs_hamiltonian_type),intent(in) :: ham
    1645                 :             :   real(dp), intent(in), target :: mat(cplx, ham%lmnmax, ham%lmnmax, ham%ntypat)
    1646                 :             :   integer, intent(in) :: block_sliced
    1647                 :             : 
    1648                 :             :   integer :: nlmn, shift, itypat, idat
    1649                 :             :   real(dp), ABI_CONTIGUOUS pointer :: x_ptr(:, :, :), y_ptr(:, :, :), mat_ptr(:,:,:)
    1650                 :             : 
    1651                 :             : ! *************************************************************************
    1652                 :             : 
    1653                 :             :   if (block_sliced == 1) then
    1654                 :             : 
    1655                 :             :      do idat = 1, ndat
    1656                 :             :         shift = 1
    1657                 :             :         do itypat=1, ham%ntypat
    1658                 :             :            nlmn = count(ham%indlmn(3,:,itypat)>0)
    1659                 :             :            !! apply mat to all atoms at once
    1660                 :             :            ! perform natom multiplications of size nlmn
    1661                 :             :            ! compute y = mat*x
    1662                 :             :            if(cplx == 2) then
    1663                 :             :              !$OMP TARGET DATA USE_DEVICE_ADDR(mat,x,y)
    1664                 :             :              call abi_gpu_zhemm('L','U', nlmn, ham%nattyp(itypat), cone, &
    1665                 :             :                    c_loc(mat(:, :, :, itypat)), ham%lmnmax, &
    1666                 :             :                    c_loc(x(:, shift:shift+nlmn*ham%nattyp(itypat)-1, idat)), nlmn, czero, &
    1667                 :             :                    c_loc(y(:, shift:shift+nlmn*ham%nattyp(itypat)-1, idat)), nlmn)
    1668                 :             :              !$OMP END TARGET DATA
    1669                 :             :            else
    1670                 :             :              !$OMP TARGET DATA USE_DEVICE_ADDR(mat,x,y)
    1671                 :             :              call abi_gpu_xsymm(cplx, 'L','U', nlmn, ham%nattyp(itypat), cone, &
    1672                 :             :                    c_loc(mat(:, :, :, itypat)), ham%lmnmax, &
    1673                 :             :                    c_loc(x(:, shift:shift+nlmn*ham%nattyp(itypat)-1, idat)), nlmn, czero, &
    1674                 :             :                    c_loc(y(:, shift:shift+nlmn*ham%nattyp(itypat)-1, idat)), nlmn)
    1675                 :             :              !$OMP END TARGET DATA
    1676                 :             :            end if
    1677                 :             :            shift = shift + nlmn*ham%nattyp(itypat)
    1678                 :             :         end do
    1679                 :             :      end do
    1680                 :             : 
    1681                 :             :   else ! block_sliced = 0
    1682                 :             : 
    1683                 :             :     shift = 1
    1684                 :             :     do itypat=1, ham%ntypat
    1685                 :             :       nlmn = count(ham%indlmn(3,:,itypat)>0)
    1686                 :             :       x_ptr => x(:, shift:shift+nlmn*ham%nattyp(itypat)-1, :)
    1687                 :             :       y_ptr => y(:, shift:shift+nlmn*ham%nattyp(itypat)-1, :)
    1688                 :             :       mat_ptr => mat(:, :, :, itypat)
    1689                 :             :       !! apply mat to all atoms at once, all idat at once
    1690                 :             :       ! perform natom multiplications of size nlmn
    1691                 :             :       ! be careful here matrix extracted from x and y are not memory contiguous
    1692                 :             :       ! ==> so in the GPU version we will need to adapt leading dimension
    1693                 :             :       !$OMP TARGET DATA USE_DEVICE_ADDR(mat_ptr,x_ptr,y_ptr)
    1694                 :             :       call abi_gpu_xgemm_strided(cplx, 'N','N', &
    1695                 :             :               nlmn, ham%nattyp(itypat), nlmn, cone, &
    1696                 :             :               c_loc(mat_ptr), ham%lmnmax, 0, &
    1697                 :             :               c_loc(x_ptr), nlmn, nprojs, &
    1698                 :             :               czero, &
    1699                 :             :               c_loc(y_ptr), nlmn, nprojs, ndat)
    1700                 :             :       !$OMP END TARGET DATA
    1701                 :             :       shift = shift + nlmn*ham%nattyp(itypat)
    1702                 :             :     end do
    1703                 :             : 
    1704                 :             :   end if
    1705                 :             : 
    1706                 :             : end subroutine apply_block_ompgpu
    1707                 :             : !!***
    1708                 :             : #endif
    1709                 :             : 
    1710   [ #  #  #  #  :           0 : end MODULE m_invovl
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
    1711                 :             : !!***
        

Generated by: LCOV version 2.3-1