LCOV - code coverage report
Current view: top level - src/66_nonlocal - m_opernlb_ylm_mv.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 90 0
Test Date: 2026-09-20 18:56:22 Functions: 0.0 % 1 0

            Line data    Source code
       1              : !!****m* ABINIT/m_opernlb_ylm_mv
       2              : !! NAME
       3              : !!  m_opernlb_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_opernlb_ylm_mv
      22              : 
      23              :  use defs_basis
      24              :  use m_abicore
      25              :  use m_errors
      26              : #if defined HAVE_OPENMP
      27              :  use OMP_LIB
      28              : #endif
      29              : 
      30              :  implicit none
      31              : 
      32              :  private
      33              : !!***
      34              : 
      35              :  public :: opernlb_ylm_mv
      36              :  integer,public,save :: opernlb_mv_counter = -1
      37              :  integer,public,save :: opernlb_mv_dgemv_counter = -1
      38              : !!***
      39              : 
      40              : contains
      41              : !!***
      42              : 
      43              : !!****f* ABINIT/opernlb_ylm_mv
      44              : !! NAME
      45              : !! opernlb_ylm_mv
      46              : !!
      47              : !! FUNCTION
      48              : !! "matrix-vector" alternative implementation of "opernlrb_ylm".
      49              : !!
      50              : !! * Operate with the non-local part of the hamiltonian,
      51              : !!   from projected scalars to reciprocal space.
      52              : !! * Operate with the non-local projectors and the overlap matrix,
      53              : !!   from projected scalars to reciprocal space.
      54              : !!
      55              : !!   The input is gxfac (gxfac_sij):
      56              : !!   gxfac(lmn) = Sum_l'm'n' D_l'm'n'.<p_l'm'n|c> (or S_l'm'n' for gxfac_sij)
      57              : !!   and here we compute :
      58              : !!   Sum_lmn <g|p_lmn> gxfac(lmn) = 4pi/sqrt(vol) exp(-2pi.i.g.R) Sum_lmn (-i)^l f_nl(g).Y_lm(g) gxfac(lmn)
      59              : !!   Here this is done in 3 steps:
      60              : !!   (1) compute for every lmn : gxfac_(lmn) = 4pi/sqrt(vol).(-i)^l.gxfac(lmn)
      61              : !!   (2) compute for every g   : scal(g)     = Sum_lmn f_nl(g).Y_lm(g).gxfac_(lmn)
      62              : !!   (3) compute for every g   : vect(g)     = exp(-2pi.i.g.R).scal(g)
      63              : !!
      64              : !!   Step (2) is a real-matrix/complex-vector multiplication, here two options are possible:
      65              : !!   - case nloalg(1)=2 : compute the real and imaginary parts separately using two calls of DGMEV
      66              : !!   - 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"
      67              : !!
      68              : !!   Depending on the achitecture and the available blas library, one option could be more interesting than an other...
      69              : !!
      70              : !! INPUTS
      71              : !!  choice=chooses possible output (see below)
      72              : !!  cplex=1 if <p_lmn|c> scalars are real (equivalent to istwfk>1)
      73              : !!        2 if <p_lmn|c> scalars are complex
      74              : !!  cplex_fac=1 if gxfac scalars are real, 2 if gxfac scalars are complex
      75              : !!  dimffnl=second dimension of ffnl
      76              : !!  ffnl(npw,dimffnl,nlmn)= nonlocal quantities containing nonlocal form factors
      77              : !!  gxfac(cplex_fac,nlmn,nincat,nspinor)= reduced projected scalars related to Vnl (NL operator)
      78              : !!  gxfac_sij(cplex,nlmn,nincat,nspinor*(paw_opt/3))= reduced projected scalars related to Sij (overlap)
      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              : !!  matblk=dimension of the array ph3d
      82              : !!  nincat=number of atoms in the subset here treated
      83              : !!  nlmn=number of (l,m,n) numbers for current type of atom
      84              : !!  nloalg(3)=governs the choice of the algorithm for non-local operator.
      85              : !!  npw=number of plane waves in reciprocal space
      86              : !!  nspinor=number of spinorial components of the wavefunctions (on current proc)
      87              : !!  paw_opt= define the nonlocal operator concerned with:
      88              : !!           paw_opt=0 : Norm-conserving Vnl (use of Kleinman-Bylander ener.)
      89              : !!           paw_opt=1 : PAW nonlocal part of H (use of Dij coeffs)
      90              : !!           paw_opt=2 : PAW: (Vnl-lambda.Sij) (Sij=overlap matrix)
      91              : !!           paw_opt=3 : PAW overlap matrix (Sij)
      92              : !!           paw_opt=4 : both PAW nonlocal part of H (Dij) and overlap matrix (Sij)
      93              : !!  ph3d(2,npw,matblk)=three-dimensional phase factors
      94              : !!  ucvol=unit cell volume (bohr^3)
      95              : !!
      96              : !! OUTPUT
      97              : !!  (see side effects)
      98              : !!
      99              : !! SIDE EFFECTS
     100              : !! --if (paw_opt=0)
     101              : !!    vectout(2,npwout*my_nspinor*ndat)=result of the aplication of the concerned operator
     102              : !!                or one of its derivatives to the input vect.
     103              : !! --if (paw_opt=0, 1 or 4)
     104              : !!    vect(2,npwout*nspinor)=result of the aplication of the concerned operator
     105              : !!                or one of its derivatives to the input vect.:
     106              : !!      if (choice=1)  <G|V_nonlocal|vect_in>
     107              : !!  if (paw_opt=2)
     108              : !!    vect(2,npwout*nspinor)=final vector in reciprocal space:
     109              : !!      if (choice=1)  <G|V_nonlocal-lamdba.(I+S)|vect_in> (note: not including <G|I|c>)
     110              : !! --if (paw_opt=3 or 4)
     111              : !!    svect(2,npwout*nspinor)=result of the aplication of Sij (overlap matrix)
     112              : !!                  or one of its derivatives to the input vect.:
     113              : !!      if (choice=1)  <G|I+S|vect_in> (note: not including <G|I|c>)
     114              : !!
     115              : !! NOTES
     116              : !! 1-No openMP available for now
     117              : !! 2-Operate for one type of atom, and within this given type of atom,
     118              : !!   for a subset of at most nincat atoms.
     119              : !! 3-projector derivatives (abs(choice)>1) are not implemented yet
     120              : !!
     121              : !! SOURCE
     122              : 
     123            0 : subroutine opernlb_ylm_mv(choice,cplex,cplex_fac,&
     124            0 : &                      dimffnl,ffnl,gxfac,gxfac_sij,&
     125            0 : &                      ia3,indlmn,matblk,nincat,nlmn,nloalg,npw,&
     126            0 : &                      nspinor,paw_opt,ph3d,svect,ucvol,vect)
     127              : 
     128              : !Arguments ------------------------------------
     129              : !scalars
     130              :  integer,intent(in) :: choice,cplex,cplex_fac,dimffnl,ia3,matblk,nincat
     131              :  integer,intent(in) :: nlmn,npw,nspinor,paw_opt
     132              :  real(dp),intent(in) :: ucvol
     133              : !arrays
     134              :  integer,intent(in) ::  indlmn(6,nlmn),nloalg(3)
     135              :  real(dp),intent(in),target :: ffnl(npw,dimffnl,nlmn)
     136              :  real(dp),intent(in) :: gxfac(cplex_fac,nlmn,nincat,nspinor)
     137              :  real(dp),intent(in) :: gxfac_sij(cplex,nlmn,nincat,nspinor*(paw_opt/3))
     138              :  real(dp),intent(in) :: ph3d(2,npw,matblk)
     139              :  real(dp),intent(inout) :: svect(:,:),vect(:,:)
     140              : !Local variables-------------------------------
     141              : !Arrays
     142              : !scalars
     143              :  logical :: use_dgemv
     144              :  integer :: ia,iaph3d
     145              :  integer :: il,ilmn,ipw,jpw,ipwshft,ispinor
     146              :  real(dp) :: buffer_r,buffer_i,wt
     147              : !arrays
     148              : ! real(dp) :: tsec(2)
     149            0 :  real(dp) :: gxfac_(nlmn,2),gxfacs_(nlmn,2)
     150            0 :  real(dp),allocatable :: scalr(:),scali(:)
     151            0 :  real(dp),pointer :: ffnl_loc(:,:)
     152              :  complex(dp) :: ctmp, cil(4)
     153              : 
     154              : ! *************************************************************************
     155              : 
     156              :  DBG_ENTER("COLL")
     157              : 
     158              : !Some checks
     159              : ! nthreads=1
     160              : !#if defined HAVE_OPENMP
     161              : ! nthreads=OMP_GET_NUM_THREADS()
     162              : !#endif
     163              : ! if (nthreads>1) then
     164              : !   ABI_ERROR('Only nthreads=1 is available for now.')
     165              : ! end if
     166              : 
     167            0 :  if (abs(choice)>1) then
     168            0 :    ABI_ERROR('Only abs(choice)<=1 is available for now.')
     169              :  end if
     170            0 :  if (nloalg(1)<2.or.nloalg(1)>10) then
     171            0 :    ABI_ERROR('nloalg(1) should be between 2 or 10.')
     172              :  end if
     173              : 
     174            0 :  use_dgemv = nloalg(1)==2.or.nloalg(1)==6.or.nloalg(1)==10
     175              :  if (use_dgemv) then
     176            0 :    if(opernlb_mv_dgemv_counter>=0) then
     177            0 :      opernlb_mv_dgemv_counter = opernlb_mv_dgemv_counter + 1
     178            0 :      if (paw_opt==4) opernlb_mv_dgemv_counter = opernlb_mv_dgemv_counter + 1
     179              :    end if
     180              :  else
     181            0 :    if(opernlb_mv_counter>=0) then
     182            0 :      opernlb_mv_counter = opernlb_mv_counter + 1
     183            0 :      if (paw_opt==4) opernlb_mv_counter = opernlb_mv_counter + 1
     184              :    end if
     185              :  end if
     186              : 
     187              : !Inits
     188            0 :  wt=four_pi/sqrt(ucvol)
     189              : 
     190            0 :  ffnl_loc => ffnl(:,1,:)
     191              : 
     192              : 
     193            0 :  ABI_MALLOC(scalr,(npw))
     194            0 :  ABI_MALLOC(scali,(npw))
     195              : 
     196              : !$OMP PARALLEL PRIVATE(buffer_r,buffer_i,cil,il,ilmn,ipw,jpw,ctmp), &
     197              : !$OMP PRIVATE(ispinor,ipwshft,ia,iaph3d,gxfac_,gxfacs_)
     198              : 
     199              : ! (-i)^l
     200            0 :  cil(1) = ( 1.0_DP, 0.0_DP) * wt
     201            0 :  cil(2) = ( 0.0_DP,-1.0_DP) * wt
     202            0 :  cil(3) = (-1.0_DP, 0.0_DP) * wt
     203            0 :  cil(4) = ( 0.0_DP, 1.0_DP) * wt
     204              : 
     205              : ! if (paw_opt/=3) then
     206              : !   ABI_MALLOC(gxfac_,(nlmn,2))
     207              : ! end if
     208              : ! if (paw_opt>=3) then
     209              : !   ABI_MALLOC(gxfacs_,(nlmn,2))
     210              : ! end if
     211              : 
     212              : !Loop on spinorial components
     213            0 :  do ispinor=1,nspinor
     214            0 :    ipwshft=(ispinor-1)*npw
     215              : 
     216              : !  Loop on atoms (blocking)
     217            0 :    do ia=1,nincat
     218            0 :      iaph3d=ia;if (nloalg(2)>0) iaph3d=ia+ia3-1
     219              : !    Step (1) : scale gxfac with 4pi/sqr(omega).(-i)^l
     220            0 :      if (paw_opt/=3) then
     221            0 :        if (cplex_fac==2) then
     222            0 :          do ilmn=1,nlmn
     223            0 :            il=mod(indlmn(1,ilmn),4)+1
     224            0 :            ctmp = cil(il) * cmplx( gxfac(1,ilmn,ia,ispinor), gxfac(2,ilmn,ia,ispinor), kind=DP )
     225            0 :            gxfac_(ilmn,1) =  real(ctmp)
     226            0 :            gxfac_(ilmn,2) = aimag(ctmp)
     227              :          end do
     228            0 :        else if (cplex_fac==1) then
     229            0 :          do ilmn=1,nlmn
     230            0 :            il=mod(indlmn(1,ilmn),4)+1
     231            0 :            ctmp = cil(il) * gxfac(1,ilmn,ia,ispinor)
     232            0 :            gxfac_(ilmn,1) =  real(ctmp)
     233            0 :            gxfac_(ilmn,2) = aimag(ctmp)
     234              :          end do
     235              :        else
     236            0 :          ABI_BUG('Error : should not be possible to be here')
     237              :        end if
     238              :      end if
     239              : 
     240              : !    Step (1) bis: Scale gxfac_sij with 4pi/sqr(omega).(-i)^l
     241            0 :      if (paw_opt>=3) then
     242            0 :        if (cplex==2) then
     243            0 :          do ilmn=1,nlmn
     244            0 :            il=mod(indlmn(1,ilmn),4)+1
     245            0 :            ctmp = cil(il) * cmplx( gxfac_sij(1,ilmn,ia,ispinor), gxfac_sij(2,ilmn,ia,ispinor), kind=DP )
     246            0 :            gxfacs_(ilmn,1) =  real(ctmp)
     247            0 :            gxfacs_(ilmn,2) = aimag(ctmp)
     248              :          end do
     249            0 :        else if (cplex==1) then
     250            0 :          do ilmn=1,nlmn
     251            0 :            il=mod(indlmn(1,ilmn),4)+1
     252            0 :            ctmp = cil(il) * gxfac_sij(1,ilmn,ia,ispinor)
     253            0 :            gxfacs_(ilmn,1) =  real(ctmp)
     254            0 :            gxfacs_(ilmn,2) = aimag(ctmp)
     255              :          end do
     256              :        else
     257            0 :          ABI_BUG('Error : should not be possible to be here')
     258              :        end if
     259              :      end if
     260              : 
     261              : !    Compute <g|Vnl|c> (or derivatives) for each plane wave:
     262            0 :      if (paw_opt/=3) then
     263              : 
     264              : !      Step (2) scal(g) = Sum_lmn f_nl(g).Y_lm(g).gxfac_(lmn)
     265            0 :        if (use_dgemv) then
     266            0 :          call DGEMV('N',npw,nlmn,1.0_DP,ffnl_loc,npw,gxfac_(:,1),1,0.0_DP,scalr,1)
     267            0 :          call DGEMV('N',npw,nlmn,1.0_DP,ffnl_loc,npw,gxfac_(:,2),1,0.0_DP,scali,1)
     268              :        else
     269              : !         scalr(:) = zero
     270              : !         scali(:) = zero
     271              : !         do ilmn=1,nlmn
     272              : !           do ipw=1,npw
     273              : !             scalr(ipw) = scalr(ipw) + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,1)
     274              : !             scali(ipw) = scali(ipw) + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,2)
     275              : !           end do
     276              : !         end do
     277              : !$OMP DO
     278            0 :          do ipw=1,npw
     279              :            buffer_r = zero
     280              :            buffer_i = zero
     281            0 :            do ilmn=1,nlmn
     282            0 :              buffer_r = buffer_r + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,1)
     283            0 :              buffer_i = buffer_i + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,2)
     284              : !             scalr(ipw) = scalr(ipw) + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,1)
     285              : !             scali(ipw) = scali(ipw) + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,2)
     286              :            end do
     287            0 :            scalr(ipw) = buffer_r
     288            0 :            scali(ipw) = buffer_i
     289              :          end do
     290              : !$OMP END DO
     291              :        end if
     292              : 
     293              : !      Step (3) : vect(g) = exp(-2pi.i.g.R).scal(g)
     294              : !$OMP DO
     295            0 :        do ipw=1,npw
     296            0 :          jpw=ipw+ipwshft
     297            0 :          vect(1,jpw)=vect(1,jpw)+scalr(ipw)*ph3d(1,ipw,iaph3d)+scali(ipw)*ph3d(2,ipw,iaph3d)
     298            0 :          vect(2,jpw)=vect(2,jpw)-scalr(ipw)*ph3d(2,ipw,iaph3d)+scali(ipw)*ph3d(1,ipw,iaph3d)
     299              :        end do
     300              : !$OMP END DO
     301              : 
     302              :      end if
     303              : 
     304              : !    Compute <g|S|c> (or derivatives) for each plane wave:
     305            0 :      if (paw_opt>=3) then
     306              : 
     307              : !      Step (2) (bis) scal(g) = Sum_lmn f_nl(g).Y_lm(g).gxfacs_(lmn)
     308            0 :        if (nloalg(1)==3) then
     309              : !         scalr(:) = zero
     310              : !         scali(:) = zero
     311              : !         do ilmn=1,nlmn
     312              : !           do ipw=1,npw
     313              : !             scalr(ipw) = scalr(ipw) + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,1)
     314              : !             scali(ipw) = scali(ipw) + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,2)
     315              : !           end do
     316              : !         end do
     317              : !$OMP DO
     318            0 :          do ipw=1,npw
     319              :            buffer_r = zero
     320              :            buffer_i = zero
     321            0 :            do ilmn=1,nlmn
     322            0 :              buffer_r = buffer_r + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,1)
     323            0 :              buffer_i = buffer_i + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,2)
     324              : !             scalr(ipw) = scalr(ipw) + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,1)
     325              : !             scali(ipw) = scali(ipw) + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,2)
     326              :            end do
     327            0 :            scalr(ipw) = buffer_r
     328            0 :            scali(ipw) = buffer_i
     329              :          end do
     330              : !$OMP END DO
     331            0 :        else if (nloalg(1)==2) then
     332            0 :          call DGEMV('N',npw,nlmn,1.0_DP,ffnl_loc,npw,gxfacs_(:,1),1,0.0_DP,scalr,1)
     333            0 :          call DGEMV('N',npw,nlmn,1.0_DP,ffnl_loc,npw,gxfacs_(:,2),1,0.0_DP,scali,1)
     334              :        end if
     335              : 
     336              : !      Step (3) (bis) : svect(g) = exp(-2pi.i.g.R).scal(g)
     337              : !$OMP DO
     338            0 :        do ipw=1,npw
     339            0 :          jpw=ipw+ipwshft
     340            0 :          svect(1,jpw)=svect(1,jpw)+scalr(ipw)*ph3d(1,ipw,iaph3d)+scali(ipw)*ph3d(2,ipw,iaph3d)
     341            0 :          svect(2,jpw)=svect(2,jpw)-scalr(ipw)*ph3d(2,ipw,iaph3d)+scali(ipw)*ph3d(1,ipw,iaph3d)
     342              :        end do
     343              : !$OMP END DO
     344              : 
     345              :      end if
     346              : 
     347              : !    End loop on atoms
     348              :    end do
     349              :  end do !  End loop on spinors
     350              : ! if (paw_opt/=3) then
     351              : !   ABI_FREE(gxfac_)
     352              : ! end if
     353              : ! if (paw_opt>=3) then
     354              : !   ABI_FREE(gxfacs_)
     355              : ! end if
     356              : !$OMP END PARALLEL
     357              : 
     358            0 :  ABI_FREE(scalr)
     359            0 :  ABI_FREE(scali)
     360              : 
     361              : 
     362              :  DBG_EXIT("COLL")
     363              : 
     364            0 : end subroutine opernlb_ylm_mv
     365              : !!***
     366              : 
     367              : end module m_opernlb_ylm_mv
     368              : !!***
        

Generated by: LCOV version 2.3-1