LCOV - code coverage report
Current view: top level - src/66_nonlocal - m_opernla_ylm_mv.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 67 0
Test Date: 2026-11-09 13:21:34 Functions: 0.0 % 1 0
Branches: 0.0 % 102 0

             Branch data     Line data    Source code
       1                 :             : !!****m* ABINIT/m_opernla_ylm_mv
       2                 :             : !! NAME
       3                 :             : !!  m_opernla_ylm_mv
       4                 :             : !!
       5                 :             : !! FUNCTION
       6                 :             : !!
       7                 :             : !! COPYRIGHT
       8                 :             : !!  Copyright (C) 2021-2026 ABINIT group (LB,MT)
       9                 :             : !!  This file is distributed under the terms of the
      10                 :             : !!  GNU General Public License, see ~abinit/COPYING
      11                 :             : !!  or http://www.gnu.org/copyleft/gpl.txt .
      12                 :             : !!
      13                 :             : !! SOURCE
      14                 :             : 
      15                 :             : #if defined HAVE_CONFIG_H
      16                 :             : #include "config.h"
      17                 :             : #endif
      18                 :             : 
      19                 :             : #include "abi_common.h"
      20                 :             : 
      21                 :             : module m_opernla_ylm_mv
      22                 :             : 
      23                 :             :  use defs_basis
      24                 :             :  use m_abicore
      25                 :             :  use m_errors
      26                 :             :  use m_xmpi
      27                 :             : #if defined HAVE_OPENMP
      28                 :             :  use OMP_LIB
      29                 :             : #endif
      30                 :             : 
      31                 :             :  use defs_abitypes, only : MPI_type
      32                 :             :  use m_time,        only : timab
      33                 :             : 
      34                 :             :  implicit none
      35                 :             : 
      36                 :             :  private
      37                 :             : !!***
      38                 :             : 
      39                 :             :  public :: opernla_ylm_mv
      40                 :             :  integer,public,save :: opernla_mv_counter = -1
      41                 :             :  integer,public,save :: opernla_mv_dgemv_counter = -1
      42                 :             : !!***
      43                 :             : !!***
      44                 :             : 
      45                 :             : contains
      46                 :             : !!***
      47                 :             : 
      48                 :             : !!****f* ABINIT/opernla_ylm_mv
      49                 :             : !! NAME
      50                 :             : !! opernla_ylm_mv
      51                 :             : !!
      52                 :             : !! FUNCTION
      53                 :             : !! "matrix-vector" alternative implementation of "opernla_ylm".
      54                 :             : !!
      55                 :             : !! For a given wave-function |c>, get all projected scalars
      56                 :             : !! <p_lmn|c> where |p_lmn> are non-local projectors
      57                 :             : !!   With:
      58                 :             : !!   <p_lmn|c>=4pi/sqrt(vol) (i)^l Sum_g[c(g).f_nl(g).Y_lm(g).exp(2pi.i.g.R)]
      59                 :             : !!
      60                 :             : !! Here this is done in 3 steps:
      61                 :             : !! (1) compute for every g   : scal(g)   = c(g).exp(2pi.i.g.R)
      62                 :             : !! (2) compute for every lmn : scal(lmn) = Sum_g[scal(g).f_nl(g).Y_lm(g)]
      63                 :             : !! (3) compute for every lmn : <p_lmn|c> = 4pi/sqrt(vol).(i)^l.scal(lmn)
      64                 :             : !!
      65                 :             : !! Step (2) is a real-matrix/complex-vector multiplication, here two options are possible:
      66                 :             : !! - case nloalg(1)=2 : compute the real and imaginary parts separately using two calls of DGMEV
      67                 :             : !! - case nloalg(1)=3 : in order to read the matrix only once, we compute both real and imaginary parts at the same time "by hand"
      68                 :             : !!
      69                 :             : !! Depending on the achitecture and the available blas library, one option could be more interesting than an other...
      70                 :             : !!
      71                 :             : !! INPUTS
      72                 :             : !!  choice=chooses possible output:
      73                 :             : !!         if choice>=0: compute projected scalars
      74                 :             : !!         if choice<0: same as choice>0 but use already computed projected scalars
      75                 :             : !!  cplex=1 if <p_lmn|c> scalars are real (equivalent to istwfk>1)
      76                 :             : !!        2 if <p_lmn|c> scalars are complex
      77                 :             : !!  dimffnl=second dimension of ffnl
      78                 :             : !!  ffnl(npw,dimffnl,nlmn)= nonlocal quantities containing nonlocal form factors
      79                 :             : !!  ia3=gives the number of the first atom in the subset presently treated
      80                 :             : !!  indlmn(6,nlmn)= array giving l,m,n,lm,ln,s for i=lmn
      81                 :             : !!  istwf_k=option parameter that describes the storage of wfs
      82                 :             : !!  matblk=dimension of the array ph3d
      83                 :             : !!  mpi_enreg=information about MPI parallelization
      84                 :             : !!  nincat=number of atoms in the subset here treated
      85                 :             : !!  nlmn=number of (l,m,n) numbers for current type of atom
      86                 :             : !!  nloalg(3)=governs the choice of the algorithm for non-local operator.
      87                 :             : !!  npw=number of plane waves in reciprocal space
      88                 :             : !!  nspinor=number of spinorial components of the wavefunctions (on current proc)
      89                 :             : !!  ph3d(2,npw,matblk)=three-dimensional phase factors
      90                 :             : !!  ucvol=unit cell volume (bohr^3)
      91                 :             : !!  vect(2,npw*my_nspinor)=starting vector in reciprocal space
      92                 :             : !!
      93                 :             : !! OUTPUT
      94                 :             : !!  gx(cplex,nlmn,nincat,nspinor)= projected scalars
      95                 :             : !!
      96                 :             : !! SIDE EFFECTS
      97                 :             : !!
      98                 :             : !! NOTES
      99                 :             : !! 1-Not available yet for openMP
     100                 :             : !! 2-Operate for one type of atom, and within this given type of atom,
     101                 :             : !!   for a subset of at most nincat atoms.
     102                 :             : !! 3-projector derivatives (abs(choice)>1) are not implemented yet
     103                 :             : !!
     104                 :             : !! SOURCE
     105                 :             : 
     106                 :           0 : subroutine opernla_ylm_mv(choice,cplex,dimffnl,ffnl,gx,&
     107                 :           0 : &       ia3,indlmn,istwf_k,matblk,mpi_enreg,nincat,nlmn,&
     108         [ #  # ]:           0 : &       nloalg,npw,nspinor,ph3d,ucvol,vect)
     109                 :             : 
     110                 :             : !Arguments ------------------------------------
     111                 :             : !scalars
     112                 :             :  integer,intent(in) :: choice,cplex,dimffnl,ia3,istwf_k,matblk
     113                 :             :  integer,intent(in) :: nincat,nlmn,npw,nspinor
     114                 :             :  real(dp),intent(in) :: ucvol
     115                 :             :  type(MPI_type),intent(in) :: mpi_enreg
     116                 :             : !arrays
     117                 :             :  integer,intent(in) :: indlmn(6,nlmn),nloalg(3)
     118                 :             :  real(dp),intent(in),target :: ffnl(npw,dimffnl,nlmn)
     119                 :             :  real(dp),intent(in) :: ph3d(2,npw,matblk)
     120                 :             :  real(dp),intent(in) :: vect(:,:)
     121                 :             :  real(dp),intent(out) :: gx(cplex,nlmn,nincat,nspinor)
     122                 :             : 
     123                 :             : !Local variables-------------------------------
     124                 :             : !scalars
     125                 :             :  logical :: use_dgemv
     126                 :             :  integer :: ia,iaph3d,ierr,il,ilmn,ipw,ipw0,ipwshft,ispinor,jpw
     127                 :             :  real(dp) :: wt
     128                 :             : !arrays
     129                 :             :  real(dp) :: buffer_r,buffer_i,tsec(2)
     130                 :           0 :  real(dp),pointer :: ffnl_loc(:,:)
     131                 :           0 :  real(dp),allocatable :: scali(:),scalr(:)
     132                 :           0 :  real(dp),allocatable :: scalr_lmn(:),scali_lmn(:)
     133                 :             :  complex(dp) :: ctmp,cil(4)
     134                 :             : ! *************************************************************************
     135                 :             : 
     136                 :           0 :  if (choice==-1) return
     137                 :             : 
     138                 :             : !Some checks
     139         [ #  # ]:           0 :  if (abs(choice)>1) then
     140                 :           0 :    ABI_ERROR('Only abs(choice)<=1 is available for now.')
     141                 :             :  end if
     142         [ #  # ]:           0 :  if (nloalg(1)<2.or.nloalg(1)>10) then
     143                 :           0 :    ABI_ERROR('nloalg(1) should be between 2 and 10.')
     144                 :             :  end if
     145                 :             : ! nthreads=1
     146                 :             : !#if defined HAVE_OPENMP
     147                 :             : ! nthreads=OMP_GET_NUM_THREADS()
     148                 :             : !#endif
     149                 :             : ! if (nthreads>1) then
     150                 :             : !   ABI_ERROR('Only nthreads=1 is available for now.')
     151                 :             : ! end if
     152                 :             : 
     153         [ #  # ]:           0 :  use_dgemv = nloalg(1)==2.or.nloalg(1)==5.or.nloalg(1)==7
     154                 :             :  if (choice>=0.or.abs(choice)>1) then
     155         [ #  # ]:           0 :    if (use_dgemv) then
     156         [ #  # ]:           0 :      if(opernla_mv_dgemv_counter>=0) opernla_mv_dgemv_counter = opernla_mv_dgemv_counter + 1
     157                 :             :    else
     158         [ #  # ]:           0 :      if(opernla_mv_counter>=0) opernla_mv_counter = opernla_mv_counter + 1
     159                 :             :    end if
     160                 :             :  end if
     161                 :             : 
     162                 :             : !Useful variables
     163         [ #  # ]:           0 :  wt=four_pi/sqrt(ucvol);if (cplex==1) wt=2.d0*wt
     164   [ #  #  #  # ]:           0 :  ipw0=1;if (istwf_k==2.and.mpi_enreg%me_g0_fft==1) ipw0=2
     165                 :             : 
     166                 :             : !Allocate work space
     167   [ #  #  #  #  :           0 :  ABI_MALLOC(scalr,(npw))
          #  #  #  #  #  
                #  #  # ]
     168   [ #  #  #  #  :           0 :  ABI_MALLOC(scali,(npw))
             #  #  #  # ]
     169   [ #  #  #  #  :           0 :  ABI_MALLOC(scalr_lmn,(nlmn))
          #  #  #  #  #  
                #  #  # ]
     170   [ #  #  #  #  :           0 :  ABI_MALLOC(scali_lmn,(nlmn))
             #  #  #  # ]
     171                 :             : 
     172                 :           0 :  ffnl_loc => ffnl(:,1,:)
     173                 :             : 
     174                 :             : ! i^l
     175                 :           0 :  cil(1) = ( 1.0_DP, 0.0_DP) * wt
     176                 :           0 :  cil(2) = ( 0.0_DP, 1.0_DP) * wt
     177                 :           0 :  cil(3) = (-1.0_DP, 0.0_DP) * wt
     178                 :           0 :  cil(4) = ( 0.0_DP,-1.0_DP) * wt
     179                 :             : 
     180                 :             :  ! FIXME OpenMP parallelism is still flawed here so forcing NUM_THREADS=1 here
     181                 :             :  ! Bug reproducible with v9[71] and bounds checks enabled
     182                 :             : !$OMP PARALLEL PRIVATE(il,ilmn,ipw,jpw), &
     183                 :             : !$OMP PRIVATE(ispinor,ipwshft,ia,iaph3d) &
     184                 :             : !$OMP NUM_THREADS(1)
     185                 :             : 
     186                 :             : !Loop on spinorial components
     187         [ #  # ]:           0 :  do ispinor =1,nspinor
     188                 :           0 :    ipwshft=(ispinor-1)*npw
     189                 :             : 
     190                 :             : !  Loop on atoms (blocking)
     191         [ #  # ]:           0 :    do ia=1,nincat
     192         [ #  # ]:           0 :      iaph3d=ia;if (nloalg(2)>0) iaph3d=ia+ia3-1
     193                 :             : !    Step (1) : Compute scal(g) = c(g).exp(2pi.i.g.R)
     194                 :             : !$OMP DO
     195         [ #  # ]:           0 :      do ipw=ipw0,npw
     196                 :           0 :        jpw=ipw+ipwshft
     197                 :           0 :        scalr(ipw)=(vect(1,jpw)*ph3d(1,ipw,iaph3d)-vect(2,jpw)*ph3d(2,ipw,iaph3d))
     198                 :           0 :        scali(ipw)=(vect(2,jpw)*ph3d(1,ipw,iaph3d)+vect(1,jpw)*ph3d(2,ipw,iaph3d))
     199                 :             :      end do
     200                 :             : !$OMP END DO
     201                 :             : 
     202                 :             : !$OMP SINGLE
     203         [ #  # ]:           0 :      if (ipw0==2) then
     204                 :           0 :        scalr(1)=half*vect(1,1+ipwshft)*ph3d(1,1,iaph3d)
     205                 :           0 :        scali(1)=half*vect(1,1+ipwshft)*ph3d(2,1,iaph3d)
     206                 :             :      end if
     207                 :             : !$OMP END SINGLE
     208                 :             : 
     209                 :             : !    --------------------------------------------------------------------
     210                 :             : !    ALL CHOICES:
     211                 :             : !    Accumulate Gx
     212                 :             : !    --------------------------------------------------------------------
     213                 :             : 
     214         [ #  # ]:           0 :      if (choice>=0) then
     215                 :             : 
     216                 :             : !      Step (2) : Compute scal(lmn) = Sum_g[scal(g).f_nl(g).Y_lm(g)]
     217         [ #  # ]:           0 :        if (use_dgemv) then
     218         [ #  # ]:           0 :          call DGEMV('T',npw,nlmn,1.0_DP,ffnl_loc,npw,scalr,1,0.0_DP,scalr_lmn,1)
     219         [ #  # ]:           0 :          call DGEMV('T',npw,nlmn,1.0_DP,ffnl_loc,npw,scali,1,0.0_DP,scali_lmn,1)
     220                 :             :        else
     221         [ #  # ]:           0 :          do ilmn=1,nlmn
     222                 :             : !           do ipw=1,npw
     223                 :             : !             scalr_lmn(ilmn) = scalr_lmn(ilmn) + scalr(ipw) * ffnl_loc(ipw,ilmn)
     224                 :             : !             scali_lmn(ilmn) = scali_lmn(ilmn) + scali(ipw) * ffnl_loc(ipw,ilmn)
     225                 :             : !           end do
     226                 :             : !$OMP SINGLE
     227                 :             :            buffer_r = 0.0_DP
     228                 :             :            buffer_i = 0.0_DP
     229                 :             : !$OMP END SINGLE
     230                 :             : !$OMP DO REDUCTION(+:buffer_r,buffer_i)
     231         [ #  # ]:           0 :            do ipw=1,npw
     232                 :           0 :              buffer_r = buffer_r + scalr(ipw) * ffnl_loc(ipw,ilmn)
     233                 :           0 :              buffer_i = buffer_i + scali(ipw) * ffnl_loc(ipw,ilmn)
     234                 :             :            end do
     235                 :             : !$OMP END DO
     236                 :             : !$OMP SINGLE
     237                 :           0 :            scalr_lmn(ilmn) = buffer_r
     238                 :           0 :            scali_lmn(ilmn) = buffer_i
     239                 :             : !$OMP END SINGLE
     240                 :             :          end do
     241                 :             :        end if
     242                 :             : !      Step (3) : Compute gx(lmn) = 4pi/sqrt(vol) (i)^l scal(lmn)
     243                 :             : !$OMP SINGLE
     244         [ #  # ]:           0 :        if (cplex==2) then
     245         [ #  # ]:           0 :          do ilmn=1,nlmn
     246                 :           0 :            il=mod(indlmn(1,ilmn),4)+1
     247                 :           0 :            ctmp = cil(il) * cmplx(scalr_lmn(ilmn),scali_lmn(ilmn),kind=DP)
     248                 :           0 :            gx(1,ilmn,ia,ispinor) = real(ctmp)
     249                 :           0 :            gx(2,ilmn,ia,ispinor) = aimag(ctmp)
     250                 :             :          end do
     251                 :             :        else
     252         [ #  # ]:           0 :          do ilmn=1,nlmn
     253                 :           0 :            il=mod(indlmn(1,ilmn),4)+1
     254                 :           0 :            ctmp = cil(il) * cmplx(scalr_lmn(ilmn),scali_lmn(ilmn),kind=DP)
     255                 :           0 :            gx(1,ilmn,ia,ispinor) = real(ctmp)
     256                 :             :          end do
     257                 :             :        end if
     258                 :             : !$OMP END SINGLE
     259                 :             : 
     260                 :             :      end if
     261                 :             : 
     262                 :             :    end do ! End loop on atoms
     263                 :             : 
     264                 :             :  end do !  End loop on spinorial components
     265                 :             : !$OMP END PARALLEL
     266                 :             : 
     267                 :             : !Deallocate temporary space
     268         [ #  # ]:           0 :  ABI_FREE(scalr)
     269         [ #  # ]:           0 :  ABI_FREE(scali)
     270         [ #  # ]:           0 :  ABI_FREE(scalr_lmn)
     271         [ #  # ]:           0 :  ABI_FREE(scali_lmn)
     272                 :             : 
     273                 :             : !Has to reduce arrays in case of FFT parallelization
     274         [ #  # ]:           0 :  if (mpi_enreg%nproc_fft>1) then
     275                 :           0 :    call timab(48,1,tsec)
     276         [ #  # ]:           0 :    if (choice>=0) then
     277                 :           0 :      call xmpi_sum(gx,mpi_enreg%comm_fft,ierr)
     278                 :             :    end if
     279                 :           0 :    call timab(48,2,tsec)
     280                 :             :  end if
     281                 :             : 
     282         [ #  # ]:           0 : end subroutine opernla_ylm_mv
     283                 :             : !!***
     284                 :             : 
     285                 :             : end module m_opernla_ylm_mv
     286                 :             : !!***
        

Generated by: LCOV version 2.3-1