mirror of https://gitlab.com/QEF/q-e.git
3007 lines
96 KiB
Fortran
3007 lines
96 KiB
Fortran
!
|
|
! Copyright (C) 2004-2009 Quantum ESPRESSO group
|
|
! This file is distributed under the terms of the
|
|
! GNU General Public License. See the file `License'
|
|
! in the root directory of the present distribution,
|
|
! or http://www.gnu.org/copyleft/gpl.txt .
|
|
!
|
|
!
|
|
!----------------------------------------------------------------------------
|
|
MODULE realus
|
|
!----------------------------------------------------------------------------
|
|
!
|
|
USE kinds, ONLY : DP
|
|
!
|
|
! ... module originally written by Antonio Suriano and Stefano de Gironcoli
|
|
! ... modified by Carlo Sbraccia
|
|
! ... modified by O. Baris Malcioglu (2008)
|
|
! ... modified by P. Umari and G. Stenuit (2009)
|
|
! ... TODO : Write the k points part
|
|
INTEGER, ALLOCATABLE :: box(:,:), maxbox(:)
|
|
REAL(DP), ALLOCATABLE :: qsave(:)
|
|
REAL(DP), ALLOCATABLE :: boxrad(:)
|
|
REAL(DP), ALLOCATABLE :: boxdist(:,:), xyz(:,:,:)
|
|
REAL(DP), ALLOCATABLE :: spher(:,:,:)
|
|
! Beta function in real space
|
|
INTEGER, ALLOCATABLE :: box_beta(:,:), maxbox_beta(:)
|
|
REAL(DP), ALLOCATABLE :: betasave(:,:,:)
|
|
REAL(DP), ALLOCATABLE :: boxrad_beta(:)
|
|
REAL(DP), ALLOCATABLE :: boxdist_beta(:,:), xyz_beta(:,:,:)
|
|
REAL(DP), ALLOCATABLE :: spher_beta(:,:,:)
|
|
!General
|
|
!LOGICAL :: tnlr ! old hidden variable, should be removed soon
|
|
LOGICAL :: real_space ! When this flag is true, real space versions of the corresponding
|
|
! calculations are performed
|
|
INTEGER :: real_space_debug ! remove this, for debugging purposes
|
|
INTEGER :: initialisation_level ! init_realspace_vars sets this to 3 qpointlist adds 5
|
|
! betapointlist adds 7 so the value should be 15 if the
|
|
! real space routine is initalised properly
|
|
|
|
INTEGER, ALLOCATABLE :: &
|
|
igk_k(:,:),& ! The g<->k correspondance for each k point
|
|
npw_k(:) ! number of plane waves at each k point
|
|
! They are (used many times, it is much better to hold them in memory
|
|
|
|
!REAL(DP), ALLOCATABLE :: psic_rs(:) !In order to prevent mixup, a redundant copy of psic`
|
|
!
|
|
COMPLEX(DP), ALLOCATABLE :: tg_psic(:)
|
|
COMPLEX(DP), ALLOCATABLE :: psic_temp(:),tg_psic_temp(:) !Copies of psic and tg_psic
|
|
COMPLEX(DP), ALLOCATABLE :: tg_vrs(:) !task groups linear V memory
|
|
COMPLEX(DP), ALLOCATABLE :: psic_box_temp(:),tg_psic_box_temp(:)
|
|
!
|
|
CONTAINS
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE read_rs_status( dirname, ierr )
|
|
!------------------------------------------------------------------------
|
|
!
|
|
! This subroutine reads the real space control flags from a pwscf punch card
|
|
! OBM 2009
|
|
!
|
|
USE iotk_module
|
|
USE io_global, ONLY : ionode,ionode_id
|
|
USE io_files, ONLY : iunpun, xmlpun
|
|
USE mp, ONLY : mp_bcast
|
|
USE mp_global, ONLY : intra_image_comm
|
|
USE control_flags, ONLY : tqr
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
CHARACTER(len=*), INTENT(in) :: dirname
|
|
INTEGER, INTENT(out) :: ierr
|
|
!
|
|
!
|
|
IF ( ionode ) THEN
|
|
!
|
|
! ... look for an empty unit
|
|
!
|
|
CALL iotk_free_unit( iunpun, ierr )
|
|
!
|
|
CALL errore( 'realus->read_rs_status', 'no free units to read real space flags', ierr )
|
|
!
|
|
CALL iotk_open_read( iunpun, FILE = trim( dirname ) // '/' // &
|
|
& trim( xmlpun ), IERR = ierr )
|
|
!
|
|
ENDIF
|
|
!
|
|
CALL mp_bcast( ierr, ionode_id, intra_image_comm )
|
|
!
|
|
IF ( ierr > 0 ) RETURN
|
|
!
|
|
IF ( ionode ) THEN
|
|
CALL iotk_scan_begin( iunpun, "CONTROL" )
|
|
!
|
|
CALL iotk_scan_dat( iunpun, "Q_REAL_SPACE", tqr )
|
|
CALL iotk_scan_dat( iunpun, "BETA_REAL_SPACE", real_space )
|
|
!
|
|
CALL iotk_scan_end( iunpun, "CONTROL" )
|
|
!
|
|
CALL iotk_close_read( iunpun )
|
|
ENDIF
|
|
CALL mp_bcast( tqr, ionode_id, intra_image_comm )
|
|
CALL mp_bcast( real_space, ionode_id, intra_image_comm )
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE read_rs_status
|
|
!----------------------------------------------------------------------------
|
|
SUBROUTINE init_realspace_vars()
|
|
!---------------------------------------------------------------------------
|
|
!This subroutine should be called to allocate/reset real space related variables.
|
|
!---------------------------------------------------------------------------
|
|
USE wvfct, ONLY : npwx,npw, igk, g2kin, ecutwfc
|
|
USE klist, ONLY : nks, xk
|
|
USE gvect, ONLY : ngm, g
|
|
USE cell_base, ONLY : tpiba2
|
|
USE control_flags, ONLY : tqr
|
|
USE fft_base, ONLY : dffts
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE io_global, ONLY : stdout
|
|
|
|
|
|
IMPLICIT NONE
|
|
|
|
INTEGER :: ik
|
|
|
|
!print *, "<<<<<init_realspace_vars>>>>>>>"
|
|
|
|
IF ( allocated( igk_k ) ) DEALLOCATE( igk_k )
|
|
IF ( allocated( npw_k ) ) DEALLOCATE( npw_k )
|
|
|
|
ALLOCATE(igk_k(npwx,nks))
|
|
ALLOCATE(npw_k(nks))
|
|
!allocate (psic_temp(size(psic)))
|
|
!real space, allocation for task group fft work arrays
|
|
IF( dffts%have_task_groups ) THEN
|
|
!
|
|
IF (allocated( tg_psic ) ) DEALLOCATE( tg_psic )
|
|
!
|
|
ALLOCATE( tg_psic( dffts%tg_nnr * dffts%nogrp ) )
|
|
!ALLOCATE( tg_psic_temp( dffts%tg_nnr * dffts%nogrp ) )
|
|
ALLOCATE( tg_vrs( dffts%tg_nnr * dffts%nogrp ) )
|
|
|
|
!
|
|
ENDIF
|
|
!allocate (psic_rs( nrxx))
|
|
!at this point I can not decide if I should preserve a redundant copy of the real space psi, or transform it whenever required,
|
|
DO ik=1,nks
|
|
!
|
|
CALL gk_sort( xk(1,ik), ngm, g, ( ecutwfc / tpiba2 ), npw, igk, g2kin )
|
|
!
|
|
npw_k(ik) = npw
|
|
!
|
|
igk_k(:,ik) = igk(:)
|
|
!
|
|
!
|
|
ENDDO
|
|
|
|
!tqr = .true.
|
|
initialisation_level = initialisation_level + 7
|
|
IF (real_space_debug > 20 .and. real_space_debug < 30) THEN
|
|
real_space=.false.
|
|
IF (tqr) THEN
|
|
tqr = .false.
|
|
WRITE(stdout,'("Debug level forced tqr to be set false")')
|
|
ELSE
|
|
WRITE(stdout,'("tqr was already set false")')
|
|
ENDIF
|
|
real_space_debug=real_space_debug-20
|
|
ENDIF
|
|
!print *, "Real space = ", real_space
|
|
!print *, "Real space debug ", real_space_debug
|
|
|
|
|
|
END SUBROUTINE init_realspace_vars
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE deallocatenewdreal()
|
|
!------------------------------------------------------------------------
|
|
!
|
|
IF ( allocated( box ) ) DEALLOCATE( box )
|
|
IF ( allocated( maxbox ) ) DEALLOCATE( maxbox )
|
|
IF ( allocated( qsave ) ) DEALLOCATE( qsave )
|
|
IF ( allocated( boxrad ) ) DEALLOCATE( boxrad )
|
|
!
|
|
END SUBROUTINE deallocatenewdreal
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE qpointlist()
|
|
!------------------------------------------------------------------------
|
|
!
|
|
! ... This subroutine is the driver routine of the box system in this
|
|
! ... implementation of US in real space.
|
|
! ... All the variables common in the module are computed and stored for
|
|
! ... reusing.
|
|
! ... This routine has to be called every time the atoms are moved and of
|
|
! ... course at the beginning.
|
|
! ... A set of spherical boxes are computed for each atom.
|
|
! ... In boxradius there are the radii of the boxes.
|
|
! ... In maxbox the upper limit of leading index, namely the number of
|
|
! ... points of the fine mesh contained in each box.
|
|
! ... In xyz there are the coordinates of the points with origin in the
|
|
! ... centre of atom.
|
|
! ... In boxdist the distance from the centre.
|
|
! ... In spher the spherical harmonics computed for each box
|
|
! ... In qsave the q value interpolated in these boxes.
|
|
!
|
|
! ... Most of time is spent here; the calling routines are faster.
|
|
!
|
|
USE constants, ONLY : pi, fpi, eps8, eps16
|
|
USE ions_base, ONLY : nat, nsp, ityp, tau
|
|
USE cell_base, ONLY : at, bg, omega, alat
|
|
USE uspp, ONLY : okvan, indv, nhtol, nhtolm, ap, nhtoj, lpx, lpl
|
|
USE uspp_param, ONLY : upf, lmaxq, nh, nhm
|
|
USE atom, ONLY : rgrid
|
|
USE fft_base, ONLY : dfftp
|
|
USE mp_global, ONLY : me_pool
|
|
USE splinelib, ONLY : spline, splint
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER :: qsdim, ia, mbia, iqs, iqsia
|
|
INTEGER :: indm, idimension, &
|
|
ih, jh, ijh, lllnbnt, lllmbnt
|
|
INTEGER :: roughestimate, goodestimate, lamx2, l, nt
|
|
INTEGER, ALLOCATABLE :: buffpoints(:,:)
|
|
REAL(DP), ALLOCATABLE :: buffdist(:,:)
|
|
REAL(DP) :: distsq, qtot_int, first, second
|
|
INTEGER :: idx0, idx, ir
|
|
INTEGER :: i, j, k, ipol, lm, nb, mb, ijv, ilast
|
|
REAL(DP) :: posi(3)
|
|
REAL(DP), ALLOCATABLE :: rl(:,:), rl2(:), d1y(:), d2y(:)
|
|
REAL(DP), ALLOCATABLE :: tempspher(:,:), qtot(:,:,:), &
|
|
xsp(:), ysp(:), wsp(:)
|
|
REAL(DP) :: mbr, mbx, mby, mbz, dmbx, dmby, dmbz, aux
|
|
REAL(DP) :: inv_nr1, inv_nr2, inv_nr3, tau_ia(3), boxradsq_ia
|
|
!
|
|
!
|
|
initialisation_level = 3
|
|
IF ( .not. okvan ) RETURN
|
|
!
|
|
CALL start_clock( 'realus' )
|
|
!
|
|
! ... qsave is deallocated here to free the memory for the buffers
|
|
!
|
|
IF ( allocated( qsave ) ) DEALLOCATE( qsave )
|
|
!
|
|
IF ( .not. allocated( boxrad ) ) THEN
|
|
!
|
|
! ... here we calculate the radius of each spherical box ( one
|
|
! ... for each non-local projector )
|
|
!
|
|
ALLOCATE( boxrad( nsp ) )
|
|
!
|
|
boxrad(:) = 0.D0
|
|
!
|
|
DO nt = 1, nsp
|
|
IF ( .not. upf(nt)%tvanp ) CYCLE
|
|
DO ijv = 1, upf(nt)%nbeta*(upf(nt)%nbeta+1)/2
|
|
DO indm = upf(nt)%mesh,1,-1
|
|
!
|
|
IF( upf(nt)%q_with_l ) THEN
|
|
aux = sum(abs( upf(nt)%qfuncl(indm,ijv,:) ))
|
|
ELSE
|
|
aux = abs( upf(nt)%qfunc(indm,ijv) )
|
|
ENDIF
|
|
IF ( aux > eps16 ) THEN
|
|
!
|
|
boxrad(nt) = max( rgrid(nt)%r(indm), boxrad(nt) )
|
|
!
|
|
exit
|
|
!
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
boxrad(:) = boxrad(:) / alat
|
|
!
|
|
ENDIF
|
|
!
|
|
! ... a rough estimate for the number of grid-points per box
|
|
! ... is provided here
|
|
!
|
|
mbr = maxval( boxrad(:) )
|
|
!
|
|
mbx = mbr*sqrt( bg(1,1)**2 + bg(1,2)**2 + bg(1,3)**2 )
|
|
mby = mbr*sqrt( bg(2,1)**2 + bg(2,2)**2 + bg(2,3)**2 )
|
|
mbz = mbr*sqrt( bg(3,1)**2 + bg(3,2)**2 + bg(3,3)**2 )
|
|
!
|
|
dmbx = 2*anint( mbx*dfftp%nr1x ) + 2
|
|
dmby = 2*anint( mby*dfftp%nr2x ) + 2
|
|
dmbz = 2*anint( mbz*dfftp%nr3x ) + 2
|
|
!
|
|
roughestimate = anint( dble( dmbx*dmby*dmbz ) * pi / 6.D0 )
|
|
!
|
|
CALL start_clock( 'realus:boxes' )
|
|
!
|
|
ALLOCATE( buffpoints( roughestimate, nat ) )
|
|
ALLOCATE( buffdist( roughestimate, nat ) )
|
|
!
|
|
ALLOCATE( xyz( 3, roughestimate, nat ) )
|
|
!
|
|
buffpoints(:,:) = 0
|
|
buffdist(:,:) = 0.D0
|
|
!
|
|
IF ( .not.allocated( maxbox ) ) ALLOCATE( maxbox( nat ) )
|
|
!
|
|
maxbox(:) = 0
|
|
!
|
|
! ... now we find the points
|
|
!
|
|
#if defined (__PARA)
|
|
idx0 = dfftp%nr1x*dfftp%nr2x * sum ( dfftp%npp(1:me_pool) )
|
|
#else
|
|
idx0 = 0
|
|
#endif
|
|
!
|
|
inv_nr1 = 1.D0 / dble( dfftp%nr1 )
|
|
inv_nr2 = 1.D0 / dble( dfftp%nr2 )
|
|
inv_nr3 = 1.D0 / dble( dfftp%nr3 )
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
nt = ityp(ia)
|
|
!
|
|
IF ( .not. upf(nt)%tvanp ) CYCLE
|
|
!
|
|
boxradsq_ia = boxrad(nt)**2
|
|
!
|
|
tau_ia(1) = tau(1,ia)
|
|
tau_ia(2) = tau(2,ia)
|
|
tau_ia(3) = tau(3,ia)
|
|
!
|
|
DO ir = 1, dfftp%nnr
|
|
!
|
|
! ... three dimensional indices (i,j,k)
|
|
!
|
|
idx = idx0 + ir - 1
|
|
k = idx / (dfftp%nr1x*dfftp%nr2x)
|
|
idx = idx - (dfftp%nr1x*dfftp%nr2x)*k
|
|
j = idx / dfftp%nr1x
|
|
idx = idx - dfftp%nr1x*j
|
|
i = idx
|
|
!
|
|
! ... do not include points outside the physical range!
|
|
!
|
|
IF ( i >= dfftp%nr1 .or. j >= dfftp%nr2 .or. k >= dfftp%nr3 ) CYCLE
|
|
!
|
|
DO ipol = 1, 3
|
|
posi(ipol) = dble( i )*inv_nr1*at(ipol,1) + &
|
|
dble( j )*inv_nr2*at(ipol,2) + &
|
|
dble( k )*inv_nr3*at(ipol,3)
|
|
ENDDO
|
|
!
|
|
posi(:) = posi(:) - tau_ia(:)
|
|
!
|
|
! ... minimum image convenction
|
|
!
|
|
CALL cryst_to_cart( 1, posi, bg, -1 )
|
|
!
|
|
posi(:) = posi(:) - anint( posi(:) )
|
|
!
|
|
CALL cryst_to_cart( 1, posi, at, 1 )
|
|
!
|
|
distsq = posi(1)**2 + posi(2)**2 + posi(3)**2
|
|
!
|
|
IF ( distsq < boxradsq_ia ) THEN
|
|
!
|
|
mbia = maxbox(ia) + 1
|
|
!
|
|
maxbox(ia) = mbia
|
|
buffpoints(mbia,ia) = ir
|
|
buffdist(mbia,ia) = sqrt( distsq )*alat
|
|
xyz(:,mbia,ia) = posi(:)*alat
|
|
!
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
goodestimate = maxval( maxbox )
|
|
!
|
|
IF ( goodestimate > roughestimate ) &
|
|
CALL errore( 'qpointlist', 'rough-estimate is too rough', 2 )
|
|
!
|
|
! ... now store them in a more convenient place
|
|
!
|
|
IF ( allocated( box ) ) DEALLOCATE( box )
|
|
IF ( allocated( boxdist ) ) DEALLOCATE( boxdist )
|
|
!
|
|
ALLOCATE( box( goodestimate, nat ) )
|
|
ALLOCATE( boxdist( goodestimate, nat ) )
|
|
!
|
|
box(:,:) = buffpoints(1:goodestimate,:)
|
|
boxdist(:,:) = buffdist(1:goodestimate,:)
|
|
!
|
|
DEALLOCATE( buffpoints )
|
|
DEALLOCATE( buffdist )
|
|
!
|
|
CALL stop_clock( 'realus:boxes' )
|
|
CALL start_clock( 'realus:spher' )
|
|
!
|
|
! ... now it computes the spherical harmonics
|
|
!
|
|
lamx2 = lmaxq*lmaxq
|
|
!
|
|
IF ( allocated( spher ) ) DEALLOCATE( spher )
|
|
!
|
|
ALLOCATE( spher( goodestimate, lamx2, nat ) )
|
|
!
|
|
spher(:,:,:) = 0.D0
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
nt = ityp(ia)
|
|
!
|
|
IF ( .not. upf(nt)%tvanp ) CYCLE
|
|
!
|
|
idimension = maxbox(ia)
|
|
!
|
|
ALLOCATE( rl( 3, idimension ), rl2( idimension ) )
|
|
!
|
|
DO ir = 1, idimension
|
|
!
|
|
rl(:,ir) = xyz(:,ir,ia)
|
|
!
|
|
rl2(ir) = rl(1,ir)**2 + rl(2,ir)**2 + rl(3,ir)**2
|
|
!
|
|
ENDDO
|
|
!
|
|
ALLOCATE( tempspher( idimension, lamx2 ) )
|
|
!
|
|
CALL ylmr2( lamx2, idimension, rl, rl2, tempspher )
|
|
!
|
|
spher(1:idimension,:,ia) = tempspher(:,:)
|
|
!
|
|
DEALLOCATE( rl, rl2, tempspher )
|
|
!
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( xyz )
|
|
!
|
|
CALL stop_clock( 'realus:spher' )
|
|
CALL start_clock( 'realus:qsave' )
|
|
!
|
|
! ... let's do the main work
|
|
!
|
|
qsdim = 0
|
|
DO ia = 1, nat
|
|
mbia = maxbox(ia)
|
|
IF ( mbia == 0 ) CYCLE
|
|
nt = ityp(ia)
|
|
IF ( .not. upf(nt)%tvanp ) CYCLE
|
|
DO ih = 1, nh(nt)
|
|
DO jh = ih, nh(nt)
|
|
qsdim = qsdim + mbia
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
!
|
|
ALLOCATE( qsave( qsdim ) )
|
|
!
|
|
qsave(:) = 0.D0
|
|
!
|
|
! ... the source is inspired by init_us_1
|
|
!
|
|
! ... we perform two steps: first we compute for each l the qtot
|
|
! ... (radial q), then we interpolate it in our mesh, and then we
|
|
! ... add it to qsave with the correct spherical harmonics
|
|
!
|
|
! ... Q is read from pseudo and it is divided into two parts:
|
|
! ... in the inner radius a polinomial representation is known and so
|
|
! ... strictly speaking we do not use interpolation but just compute
|
|
! ... the correct value
|
|
!
|
|
iqs = 0
|
|
iqsia = 0
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
mbia = maxbox(ia)
|
|
!
|
|
IF ( mbia == 0 ) CYCLE
|
|
!
|
|
nt = ityp(ia)
|
|
!
|
|
IF ( .not. upf(nt)%tvanp ) CYCLE
|
|
!
|
|
ALLOCATE( qtot( upf(nt)%kkbeta, upf(nt)%nbeta, upf(nt)%nbeta ) )
|
|
!
|
|
! ... variables used for spline interpolation
|
|
!
|
|
ALLOCATE( xsp( upf(nt)%kkbeta ), ysp( upf(nt)%kkbeta ), &
|
|
wsp( upf(nt)%kkbeta ) )
|
|
!
|
|
! ... the radii in x
|
|
!
|
|
xsp(:) = rgrid(nt)%r(1:upf(nt)%kkbeta)
|
|
!
|
|
DO l = 0, upf(nt)%nqlc - 1
|
|
!
|
|
! ... first we build for each nb,mb,l the total Q(|r|) function
|
|
! ... note that l is the true (combined) angular momentum
|
|
! ... and that the arrays have dimensions 1..l+1
|
|
!
|
|
DO nb = 1, upf(nt)%nbeta
|
|
DO mb = nb, upf(nt)%nbeta
|
|
ijv = mb * (mb-1) /2 + nb
|
|
!
|
|
lllnbnt = upf(nt)%lll(nb)
|
|
lllmbnt = upf(nt)%lll(mb)
|
|
!
|
|
IF ( .not. ( l >= abs( lllnbnt - lllmbnt ) .and. &
|
|
l <= lllnbnt + lllmbnt .and. &
|
|
mod( l + lllnbnt + lllmbnt, 2 ) == 0 ) ) CYCLE
|
|
!
|
|
IF( upf(nt)%q_with_l ) THEN
|
|
qtot(1:upf(nt)%kkbeta,nb,mb) = &
|
|
upf(nt)%qfuncl(1:upf(nt)%kkbeta,ijv,l) &
|
|
/ rgrid(nt)%r(1:upf(nt)%kkbeta)**2
|
|
ELSE
|
|
DO ir = 1, upf(nt)%kkbeta
|
|
IF ( rgrid(nt)%r(ir) >= upf(nt)%rinner(l+1) ) THEN
|
|
qtot(ir,nb,mb) = upf(nt)%qfunc(ir,ijv) / &
|
|
rgrid(nt)%r(ir)**2
|
|
ELSE
|
|
ilast = ir
|
|
ENDIF
|
|
ENDDO
|
|
ENDIF
|
|
!
|
|
IF ( upf(nt)%rinner(l+1) > 0.D0 ) &
|
|
CALL setqfcorr( upf(nt)%qfcoef(1:,l+1,nb,mb), &
|
|
qtot(1,nb,mb), rgrid(nt)%r, upf(nt)%nqf, l, ilast )
|
|
!
|
|
! ... we save the values in y
|
|
!
|
|
ysp(:) = qtot(1:upf(nt)%kkbeta,nb,mb)
|
|
!
|
|
IF ( upf(nt)%nqf > 0 ) THEN
|
|
!
|
|
! ... compute the first derivative in first point
|
|
!
|
|
CALL setqfcorrptfirst( upf(nt)%qfcoef(1:,l+1,nb,mb), &
|
|
first, rgrid(nt)%r(1), upf(nt)%nqf, l )
|
|
!
|
|
! ... compute the second derivative in first point
|
|
!
|
|
CALL setqfcorrptsecond( upf(nt)%qfcoef(1:,l+1,nb,mb), &
|
|
second, rgrid(nt)%r(1), upf(nt)%nqf, l )
|
|
ELSE
|
|
!
|
|
! ... if we don't have the analitical coefficients, try to do
|
|
! ... the same numerically (note that setting first=0.d0 and
|
|
! ... second=0.d0 makes almost no difference)
|
|
!
|
|
ALLOCATE( d1y(upf(nt)%kkbeta), d2y(upf(nt)%kkbeta) )
|
|
CALL radial_gradient(ysp(1:upf(nt)%kkbeta), d1y, &
|
|
rgrid(nt)%r, upf(nt)%kkbeta, 1)
|
|
CALL radial_gradient(d1y, d2y, rgrid(nt)%r, upf(nt)%kkbeta, 1)
|
|
!
|
|
first = d1y(1) ! first derivative in first point
|
|
second =d2y(1) ! second derivative in first point
|
|
DEALLOCATE( d1y, d2y )
|
|
ENDIF
|
|
!
|
|
! ... call spline
|
|
!
|
|
CALL spline( xsp, ysp, first, second, wsp )
|
|
!
|
|
DO ir = 1, maxbox(ia)
|
|
!
|
|
IF ( boxdist(ir,ia) < upf(nt)%rinner(l+1) ) THEN
|
|
!
|
|
! ... if in the inner radius just compute the
|
|
! ... polynomial
|
|
!
|
|
CALL setqfcorrpt( upf(nt)%qfcoef(1:,l+1,nb,mb), &
|
|
qtot_int, boxdist(ir,ia), upf(nt)%nqf, l )
|
|
!
|
|
ELSE
|
|
!
|
|
! ... spline interpolation
|
|
!
|
|
qtot_int = splint( xsp, ysp, wsp, boxdist(ir,ia) )
|
|
!
|
|
ENDIF
|
|
!
|
|
ijh = 0
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
DO jh = ih, nh(nt)
|
|
!
|
|
iqs = iqsia + ijh*mbia + ir
|
|
ijh = ijh + 1
|
|
!
|
|
IF ( .not.( nb == indv(ih,nt) .and. &
|
|
mb == indv(jh,nt) ) ) CYCLE
|
|
!
|
|
DO lm = l*l+1, (l+1)*(l+1)
|
|
!
|
|
qsave(iqs) = qsave(iqs) + &
|
|
qtot_int*spher(ir,lm,ia)*&
|
|
ap(lm,nhtolm(ih,nt),nhtolm(jh,nt))
|
|
!
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
iqsia = iqs
|
|
!
|
|
DEALLOCATE( qtot )
|
|
DEALLOCATE( xsp )
|
|
DEALLOCATE( ysp )
|
|
DEALLOCATE( wsp )
|
|
!
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( boxdist )
|
|
DEALLOCATE( spher )
|
|
!
|
|
CALL stop_clock( 'realus:qsave' )
|
|
CALL stop_clock( 'realus' )
|
|
!
|
|
END SUBROUTINE qpointlist
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE betapointlist()
|
|
!------------------------------------------------------------------------
|
|
!
|
|
! ... This subroutine is the driver routine of the box system in this
|
|
! ... implementation of US in real space.
|
|
! ... All the variables common in the module are computed and stored for
|
|
! ... reusing.
|
|
! ... This routine has to be called every time the atoms are moved and of
|
|
! ... course at the beginning.
|
|
! ... A set of spherical boxes are computed for each atom.
|
|
! ... In boxradius there are the radii of the boxes.
|
|
! ... In maxbox the upper limit of leading index, namely the number of
|
|
! ... points of the fine mesh contained in each box.
|
|
! ... In xyz there are the coordinates of the points with origin in the
|
|
! ... centre of atom.
|
|
! ... In boxdist the distance from the centre.
|
|
! ... In spher the spherical harmonics computed for each box
|
|
! ... In qsave the q value interpolated in these boxes.
|
|
!
|
|
! ... Most of time is spent here; the calling routines are faster.
|
|
!
|
|
! The source inspired by qsave
|
|
!
|
|
USE constants, ONLY : pi, eps8, eps16
|
|
USE ions_base, ONLY : nat, nsp, ityp, tau
|
|
USE cell_base, ONLY : at, bg, omega, alat
|
|
USE uspp, ONLY : okvan, indv, nhtol, nhtolm, ap
|
|
USE uspp_param, ONLY : upf, lmaxq, nh, nhm
|
|
USE atom, ONLY : rgrid
|
|
!USE pffts, ONLY : npps
|
|
USE fft_base, ONLY : dffts
|
|
USE mp_global, ONLY : me_pool
|
|
USE splinelib, ONLY : spline, splint
|
|
USE ions_base, ONLY : ntyp => nsp
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER :: betasdim, ia, it, mbia, iqs
|
|
INTEGER :: indm, inbrx, idimension, &
|
|
ilm, ih, jh, iih, ijh
|
|
INTEGER :: roughestimate, goodestimate, lamx2, l, nt
|
|
INTEGER, ALLOCATABLE :: buffpoints(:,:)
|
|
REAL(DP), ALLOCATABLE :: buffdist(:,:)
|
|
REAL(DP) :: distsq, qtot_int, first, second
|
|
INTEGER :: index0, index, indproc, ir
|
|
INTEGER :: i, j, k, i0, j0, k0, ipol, lm, nb, mb, ijv, ilast
|
|
REAL(DP) :: posi(3)
|
|
REAL(DP), ALLOCATABLE :: rl(:,:), rl2(:)
|
|
REAL(DP), ALLOCATABLE :: tempspher(:,:), qtot(:,:,:), &
|
|
xsp(:), ysp(:), wsp(:), d1y(:), d2y(:)
|
|
REAL(DP) :: mbr, mbx, mby, mbz, dmbx, dmby, dmbz
|
|
REAL(DP) :: inv_nr1s, inv_nr2s, inv_nr3s, tau_ia(3), boxradsq_ia
|
|
!Delete Delete
|
|
CHARACTER(len=256) :: filename
|
|
CHARACTER(len=256) :: tmp
|
|
!Delete Delete
|
|
!
|
|
!
|
|
initialisation_level = initialisation_level + 5
|
|
IF ( .not. okvan ) RETURN
|
|
!
|
|
!print *, "<<<betapointlist>>>"
|
|
!
|
|
CALL start_clock( 'betapointlist' )
|
|
!
|
|
! ... betasave is deallocated here to free the memory for the buffers
|
|
!
|
|
IF ( allocated( betasave ) ) DEALLOCATE( betasave )
|
|
!
|
|
IF ( .not. allocated( boxrad_beta ) ) THEN
|
|
!
|
|
! ... here we calculate the radius of each spherical box ( one
|
|
! ... for each non-local projector )
|
|
!
|
|
ALLOCATE( boxrad_beta( nsp ) )
|
|
!
|
|
boxrad_beta(:) = 0.D0
|
|
!
|
|
DO it = 1, nsp
|
|
DO inbrx = 1, upf(it)%nbeta
|
|
DO indm = upf(it)%kkbeta, 1, -1
|
|
!
|
|
IF ( abs( upf(it)%beta(indm,inbrx) ) > 0.d0 ) THEN
|
|
!
|
|
boxrad_beta(it) = max( rgrid(it)%r(indm), boxrad_beta(it) )
|
|
!
|
|
CYCLE
|
|
!
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
boxrad_beta(:) = boxrad_beta(:) / alat
|
|
!
|
|
ENDIF
|
|
!
|
|
! ... a rough estimate for the number of grid-points per box
|
|
! ... is provided here
|
|
!
|
|
mbr = maxval( boxrad_beta(:) )
|
|
!
|
|
mbx = mbr*sqrt( bg(1,1)**2 + bg(1,2)**2 + bg(1,3)**2 )
|
|
mby = mbr*sqrt( bg(2,1)**2 + bg(2,2)**2 + bg(2,3)**2 )
|
|
mbz = mbr*sqrt( bg(3,1)**2 + bg(3,2)**2 + bg(3,3)**2 )
|
|
!
|
|
dmbx = 2*anint( mbx*dffts%nr1x ) + 2
|
|
dmby = 2*anint( mby*dffts%nr2x ) + 2
|
|
dmbz = 2*anint( mbz*dffts%nr3x ) + 2
|
|
!
|
|
roughestimate = anint( dble( dmbx*dmby*dmbz ) * pi / 6.D0 )
|
|
!
|
|
CALL start_clock( 'realus:boxes' )
|
|
!
|
|
ALLOCATE( buffpoints( roughestimate, nat ) )
|
|
ALLOCATE( buffdist( roughestimate, nat ) )
|
|
!
|
|
ALLOCATE( xyz_beta( 3, roughestimate, nat ) )
|
|
!
|
|
buffpoints(:,:) = 0
|
|
buffdist(:,:) = 0.D0
|
|
!
|
|
IF ( .not.allocated( maxbox_beta ) ) ALLOCATE( maxbox_beta( nat ) )
|
|
!
|
|
maxbox_beta(:) = 0
|
|
!
|
|
! ... now we find the points
|
|
!
|
|
! The beta functions are treated on smooth grid
|
|
#if defined (__PARA)
|
|
index0 = dffts%nr1x*dffts%nr2x * sum ( dffts%npp(1:me_pool) )
|
|
#else
|
|
index0 = 0
|
|
#endif
|
|
!
|
|
inv_nr1s = 1.D0 / dble( dffts%nr1 )
|
|
inv_nr2s = 1.D0 / dble( dffts%nr2 )
|
|
inv_nr3s = 1.D0 / dble( dffts%nr3 )
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
IF ( .not. upf(ityp(ia))%tvanp ) CYCLE
|
|
!
|
|
boxradsq_ia = boxrad_beta(ityp(ia))**2
|
|
!
|
|
tau_ia(1) = tau(1,ia)
|
|
tau_ia(2) = tau(2,ia)
|
|
tau_ia(3) = tau(3,ia)
|
|
!
|
|
DO ir = 1, dffts%nnr
|
|
!
|
|
! ... three dimensional indexes
|
|
!
|
|
index = index0 + ir - 1
|
|
k = index / (dffts%nr1x*dffts%nr2x)
|
|
index = index - (dffts%nr1x*dffts%nr2x)*k
|
|
j = index / dffts%nr1x
|
|
index = index - dffts%nr1x*j
|
|
i = index
|
|
!
|
|
DO ipol = 1, 3
|
|
posi(ipol) = dble( i )*inv_nr1s*at(ipol,1) + &
|
|
dble( j )*inv_nr2s*at(ipol,2) + &
|
|
dble( k )*inv_nr3s*at(ipol,3)
|
|
ENDDO
|
|
!
|
|
posi(:) = posi(:) - tau_ia(:)
|
|
!
|
|
! ... minimum image convenction
|
|
!
|
|
CALL cryst_to_cart( 1, posi, bg, -1 )
|
|
!
|
|
posi(:) = posi(:) - anint( posi(:) )
|
|
!
|
|
CALL cryst_to_cart( 1, posi, at, 1 )
|
|
!
|
|
distsq = posi(1)**2 + posi(2)**2 + posi(3)**2
|
|
!
|
|
IF ( distsq < boxradsq_ia ) THEN
|
|
!
|
|
mbia = maxbox_beta(ia) + 1
|
|
!
|
|
maxbox_beta(ia) = mbia
|
|
buffpoints(mbia,ia) = ir
|
|
buffdist(mbia,ia) = sqrt( distsq )*alat
|
|
xyz_beta(:,mbia,ia) = posi(:)*alat
|
|
!
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
goodestimate = maxval( maxbox_beta )
|
|
!
|
|
IF ( goodestimate > roughestimate ) &
|
|
CALL errore( 'betapointlist', 'rough-estimate is too rough', 2 )
|
|
!
|
|
! ... now store them in a more convenient place
|
|
!
|
|
IF ( allocated( box_beta ) ) DEALLOCATE( box_beta )
|
|
IF ( allocated( boxdist_beta ) ) DEALLOCATE( boxdist_beta )
|
|
!
|
|
ALLOCATE( box_beta ( goodestimate, nat ) )
|
|
ALLOCATE( boxdist_beta( goodestimate, nat ) )
|
|
!
|
|
box_beta(:,:) = buffpoints(1:goodestimate,:)
|
|
boxdist_beta(:,:) = buffdist(1:goodestimate,:)
|
|
!
|
|
DEALLOCATE( buffpoints )
|
|
DEALLOCATE( buffdist )
|
|
!
|
|
CALL stop_clock( 'realus:boxes' )
|
|
CALL start_clock( 'realus:spher' )
|
|
!
|
|
! ... now it computes the spherical harmonics
|
|
!
|
|
lamx2 = lmaxq*lmaxq
|
|
!
|
|
IF ( allocated( spher_beta ) ) DEALLOCATE( spher_beta )
|
|
!
|
|
ALLOCATE( spher_beta( goodestimate, lamx2, nat ) )
|
|
!
|
|
spher_beta(:,:,:) = 0.D0
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
IF ( .not. upf(ityp(ia))%tvanp ) CYCLE
|
|
!
|
|
idimension = maxbox_beta(ia)
|
|
!
|
|
ALLOCATE( rl( 3, idimension ), rl2( idimension ) )
|
|
!
|
|
DO ir = 1, idimension
|
|
!
|
|
rl(:,ir) = xyz_beta(:,ir,ia)
|
|
!
|
|
rl2(ir) = rl(1,ir)**2 + rl(2,ir)**2 + rl(3,ir)**2
|
|
!
|
|
ENDDO
|
|
!
|
|
ALLOCATE( tempspher( idimension, lamx2 ) )
|
|
!
|
|
CALL ylmr2( lamx2, idimension, rl, rl2, tempspher )
|
|
!
|
|
spher_beta(1:idimension,:,ia) = tempspher(:,:)
|
|
!
|
|
DEALLOCATE( rl, rl2, tempspher )
|
|
!
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( xyz_beta )
|
|
!
|
|
CALL stop_clock( 'realus:spher' )
|
|
CALL start_clock( 'realus:qsave' )
|
|
!
|
|
! ... let's do the main work
|
|
!
|
|
betasdim = 0
|
|
DO ia = 1, nat
|
|
mbia = maxbox_beta(ia)
|
|
IF ( mbia == 0 ) CYCLE
|
|
nt = ityp(ia)
|
|
IF ( .not. upf(nt)%tvanp ) CYCLE
|
|
DO ih = 1, nh(nt)
|
|
betasdim = betasdim + mbia
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
ALLOCATE( betasave( nat, nhm, goodestimate ) )
|
|
!
|
|
betasave = 0.D0
|
|
! Box is set, Y_lm is known in the box, now the calculation can commence
|
|
! Reminder: In real space
|
|
! |Beta_lm(r)>=f_l(r).Y_lm(r)
|
|
! In q space (calculated in init_us_1 and then init_us_2 )
|
|
! |Beta_lm(q)>= (4pi/omega).Y_lm(q).f_l(q).(i^l).S(q)
|
|
! Where
|
|
! f_l(q)=\int_0 ^\infty dr r^2 f_l (r) j_l(q.r)
|
|
!
|
|
! We know f_l(r) and Y_lm(r) for certain points,
|
|
! basically we interpolate the known values to new mesh using splint
|
|
! iqs = 0
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
mbia = maxbox_beta(ia)
|
|
!
|
|
IF ( mbia == 0 ) CYCLE
|
|
!
|
|
nt = ityp(ia)
|
|
!
|
|
IF ( .not. upf(nt)%tvanp ) CYCLE
|
|
!
|
|
ALLOCATE( qtot( upf(nt)%kkbeta, upf(nt)%nbeta, upf(nt)%nbeta ) )
|
|
!
|
|
! ... variables used for spline interpolation
|
|
!
|
|
ALLOCATE( xsp( upf(nt)%kkbeta ), ysp( upf(nt)%kkbeta ), wsp( upf(nt)%kkbeta ) )
|
|
!
|
|
! ... the radii in x
|
|
!
|
|
xsp(:) = rgrid(nt)%r(1:upf(nt)%kkbeta)
|
|
!
|
|
DO ih = 1, nh (nt)
|
|
!
|
|
lm = nhtolm(ih, nt)
|
|
nb = indv(ih, nt)
|
|
!
|
|
!OBM rgrid(nt)%r(1) == 0, attempting correction
|
|
! In the UPF file format, beta field is r*|beta>
|
|
IF (rgrid(nt)%r(1)==0) THEN
|
|
ysp(2:) = upf(nt)%beta(2:upf(nt)%kkbeta,nb) / rgrid(nt)%r(2:upf(nt)%kkbeta)
|
|
ysp(1)=0.d0
|
|
ELSE
|
|
ysp(:) = upf(nt)%beta(1:upf(nt)%kkbeta,nb) / rgrid(nt)%r(1:upf(nt)%kkbeta)
|
|
ENDIF
|
|
|
|
ALLOCATE( d1y(upf(nt)%kkbeta), d2y(upf(nt)%kkbeta) )
|
|
CALL radial_gradient(ysp(1:upf(nt)%kkbeta), d1y, &
|
|
rgrid(nt)%r, upf(nt)%kkbeta, 1)
|
|
CALL radial_gradient(d1y, d2y, rgrid(nt)%r, upf(nt)%kkbeta, 1)
|
|
|
|
first = d1y(1) ! first derivative in first point
|
|
second =d2y(1) ! second derivative in first point
|
|
DEALLOCATE( d1y, d2y )
|
|
|
|
|
|
CALL spline( xsp, ysp, first, second, wsp )
|
|
|
|
|
|
DO ir = 1, mbia
|
|
!
|
|
! ... spline interpolation
|
|
!
|
|
qtot_int = splint( xsp, ysp, wsp, boxdist_beta(ir,ia) ) !the value of f_l(r) in point ir in atom ia
|
|
!
|
|
!iqs = iqs + 1
|
|
!
|
|
betasave(ia,ih,ir) = qtot_int*spher_beta(ir,lm,ia) !spher_beta is the Y_lm in point ir for atom ia
|
|
!
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( qtot )
|
|
DEALLOCATE( xsp )
|
|
DEALLOCATE( ysp )
|
|
DEALLOCATE( wsp )
|
|
!
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( boxdist_beta )
|
|
DEALLOCATE( spher_beta )
|
|
!
|
|
CALL stop_clock( 'realus:qsave' )
|
|
CALL stop_clock( 'betapointlist' )
|
|
!
|
|
END SUBROUTINE betapointlist
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE newq_r(vr,deeq,skip_vltot)
|
|
!
|
|
! This routine computes the integral of the perturbed potential with
|
|
! the Q function in real space
|
|
!
|
|
USE cell_base, ONLY : omega
|
|
USE grid_dimensions, ONLY : nr1, nr2, nr3, nrxx
|
|
USE lsda_mod, ONLY : nspin
|
|
USE ions_base, ONLY : nat, ityp
|
|
USE uspp_param, ONLY : upf, nh, nhm
|
|
USE control_flags, ONLY : tqr
|
|
USE noncollin_module, ONLY : nspin_mag
|
|
USE scf, ONLY : vltot
|
|
USE mp_global, ONLY : intra_pool_comm
|
|
USE mp, ONLY : mp_sum
|
|
|
|
IMPLICIT NONE
|
|
!
|
|
! Input: potential , output: contribution to integral
|
|
REAL(kind=dp), INTENT(in) :: vr(nrxx,nspin)
|
|
REAL(kind=dp), INTENT(out) :: deeq( nhm, nhm, nat, nspin )
|
|
LOGICAL, INTENT(in) :: skip_vltot !If .false. vltot is added to vr when necessary
|
|
!Internal
|
|
REAL(DP), ALLOCATABLE :: aux(:)
|
|
!
|
|
INTEGER :: ia, ih, jh, is, ir, nt
|
|
INTEGER :: mbia, nht, nhnt, iqs
|
|
!
|
|
IF (tqr .and. .not. allocated(maxbox)) THEN
|
|
CALL qpointlist()
|
|
ENDIF
|
|
|
|
deeq(:,:,:,:) = 0.D0
|
|
!
|
|
ALLOCATE( aux( nrxx ) )
|
|
!
|
|
DO is = 1, nspin_mag
|
|
!
|
|
IF ( (nspin_mag == 4 .and. is /= 1) .or. skip_vltot ) THEN
|
|
aux(:) = vr(:,is)
|
|
ELSE
|
|
aux(:) = vltot(:) + vr(:,is)
|
|
ENDIF
|
|
!
|
|
iqs = 0
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
mbia = maxbox(ia)
|
|
!
|
|
IF ( mbia == 0 ) CYCLE
|
|
!
|
|
nt = ityp(ia)
|
|
!
|
|
IF ( .not. upf(nt)%tvanp ) CYCLE
|
|
!
|
|
nhnt = nh(nt)
|
|
!
|
|
DO ih = 1, nhnt
|
|
DO jh = ih, nhnt
|
|
DO ir = 1, mbia
|
|
iqs = iqs + 1
|
|
deeq(ih,jh,ia,is)= deeq(ih,jh,ia,is) + &
|
|
qsave(iqs)*aux(box(ir,ia))
|
|
ENDDO
|
|
deeq(jh,ih,ia,is) = deeq(ih,jh,ia,is)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
deeq(:,:,:,:) = deeq(:,:,:,:)*omega/(nr1*nr2*nr3)
|
|
!
|
|
DEALLOCATE( aux )
|
|
!
|
|
CALL mp_sum( deeq(:,:,:,1:nspin_mag) , intra_pool_comm )
|
|
END SUBROUTINE newq_r
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE newd_r()
|
|
!------------------------------------------------------------------------
|
|
!
|
|
! ... this subroutine is the version of newd in real space
|
|
!
|
|
USE ions_base, ONLY : nat, ityp
|
|
USE lsda_mod, ONLY : nspin
|
|
USE scf, ONLY : v
|
|
USE uspp, ONLY : okvan, deeq, deeq_nc, dvan, dvan_so
|
|
USE uspp_param, ONLY : upf, nh, nhm
|
|
USE noncollin_module, ONLY : noncolin, nspin_mag
|
|
USE spin_orb, ONLY : domag, lspinorb
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER :: ia, ih, jh, is, ir, nt
|
|
INTEGER :: mbia, nht, nhnt, iqs
|
|
!
|
|
IF ( .not. okvan ) THEN
|
|
!
|
|
! ... no ultrasoft potentials: use bare coefficients for projectors
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
nt = ityp(ia)
|
|
nht = nh(nt)
|
|
!
|
|
IF ( lspinorb ) THEN
|
|
!
|
|
deeq_nc(1:nht,1:nht,ia,1:nspin) = dvan_so(1:nht,1:nht,1:nspin,nt)
|
|
!
|
|
ELSEIF ( noncolin ) THEN
|
|
!
|
|
deeq_nc(1:nht,1:nht,ia,1) = dvan(1:nht,1:nht,nt)
|
|
deeq_nc(1:nht,1:nht,ia,2) = ( 0.D0, 0.D0 )
|
|
deeq_nc(1:nht,1:nht,ia,3) = ( 0.D0, 0.D0 )
|
|
deeq_nc(1:nht,1:nht,ia,4) = dvan(1:nht,1:nht,nt)
|
|
!
|
|
ELSE
|
|
!
|
|
DO is = 1, nspin
|
|
!
|
|
deeq(1:nht,1:nht,ia,is) = dvan(1:nht,1:nht,nt)
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
!
|
|
! ... early return
|
|
!
|
|
RETURN
|
|
!
|
|
ENDIF
|
|
!
|
|
CALL start_clock( 'newd' )
|
|
!
|
|
CALL newq_r(v%of_r,deeq,.false.)
|
|
IF (noncolin) call add_paw_to_deeq(deeq)
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
nt = ityp(ia)
|
|
!
|
|
IF ( noncolin ) THEN
|
|
!
|
|
IF ( upf(nt)%has_so ) THEN
|
|
CALL newd_so( ia )
|
|
ELSE
|
|
CALL newd_nc( ia )
|
|
ENDIF
|
|
!
|
|
ELSE
|
|
!
|
|
nhnt = nh(nt)
|
|
!
|
|
DO is = 1, nspin_mag
|
|
DO ih = 1, nhnt
|
|
DO jh = ih, nhnt
|
|
deeq(ih,jh,ia,is) = deeq(ih,jh,ia,is) + dvan(ih,jh,nt)
|
|
deeq(jh,ih,ia,is) = deeq(ih,jh,ia,is)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
ENDIF
|
|
ENDDO
|
|
!
|
|
CALL stop_clock( 'newd' )
|
|
!
|
|
RETURN
|
|
!
|
|
CONTAINS
|
|
!
|
|
!--------------------------------------------------------------------
|
|
SUBROUTINE newd_so( ia )
|
|
!--------------------------------------------------------------------
|
|
!
|
|
USE spin_orb, ONLY : fcoef, domag, lspinorb
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in) :: ia
|
|
INTEGER :: ijs, is1, is2, kh, lh
|
|
!
|
|
!
|
|
nt = ityp(ia)
|
|
ijs = 0
|
|
!
|
|
DO is1 = 1, 2
|
|
DO is2 = 1, 2
|
|
!
|
|
ijs = ijs + 1
|
|
!
|
|
IF ( domag ) THEN
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
DO jh = 1, nh(nt)
|
|
!
|
|
deeq_nc(ih,jh,ia,ijs) = dvan_so(ih,jh,ijs,nt)
|
|
!
|
|
DO kh = 1, nh(nt)
|
|
DO lh = 1, nh(nt)
|
|
!
|
|
deeq_nc(ih,jh,ia,ijs) = deeq_nc(ih,jh,ia,ijs) + &
|
|
deeq (kh,lh,ia,1)* &
|
|
(fcoef(ih,kh,is1,1,nt)*fcoef(lh,jh,1,is2,nt) + &
|
|
fcoef(ih,kh,is1,2,nt)*fcoef(lh,jh,2,is2,nt)) + &
|
|
deeq (kh,lh,ia,2)* &
|
|
(fcoef(ih,kh,is1,1,nt)*fcoef(lh,jh,2,is2,nt) + &
|
|
fcoef(ih,kh,is1,2,nt)*fcoef(lh,jh,1,is2,nt)) + &
|
|
(0.D0,-1.D0)*deeq (kh,lh,ia,3)* &
|
|
(fcoef(ih,kh,is1,1,nt)*fcoef(lh,jh,2,is2,nt) - &
|
|
fcoef(ih,kh,is1,2,nt)*fcoef(lh,jh,1,is2,nt)) + &
|
|
deeq (kh,lh,ia,4)* &
|
|
(fcoef(ih,kh,is1,1,nt)*fcoef(lh,jh,1,is2,nt) - &
|
|
fcoef(ih,kh,is1,2,nt)*fcoef(lh,jh,2,is2,nt))
|
|
!
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
ELSE
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
DO jh = 1, nh(nt)
|
|
!
|
|
deeq_nc(ih,jh,ia,ijs) = dvan_so(ih,jh,ijs,nt)
|
|
!
|
|
DO kh = 1, nh(nt)
|
|
DO lh = 1, nh(nt)
|
|
!
|
|
deeq_nc(ih,jh,ia,ijs) = deeq_nc(ih,jh,ia,ijs) + &
|
|
deeq (kh,lh,ia,1)* &
|
|
(fcoef(ih,kh,is1,1,nt)*fcoef(lh,jh,1,is2,nt) + &
|
|
fcoef(ih,kh,is1,2,nt)*fcoef(lh,jh,2,is2,nt) )
|
|
!
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE newd_so
|
|
!
|
|
!--------------------------------------------------------------------
|
|
SUBROUTINE newd_nc( ia )
|
|
!--------------------------------------------------------------------
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in) :: ia
|
|
!
|
|
nt = ityp(ia)
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
DO jh = 1, nh(nt)
|
|
!
|
|
IF ( lspinorb ) THEN
|
|
!
|
|
deeq_nc(ih,jh,ia,1) = dvan_so(ih,jh,1,nt) + &
|
|
deeq(ih,jh,ia,1) + deeq(ih,jh,ia,4)
|
|
deeq_nc(ih,jh,ia,4) = dvan_so(ih,jh,4,nt) + &
|
|
deeq(ih,jh,ia,1) - deeq(ih,jh,ia,4)
|
|
!
|
|
ELSE
|
|
!
|
|
deeq_nc(ih,jh,ia,1) = dvan(ih,jh,nt) + &
|
|
deeq(ih,jh,ia,1) + deeq(ih,jh,ia,4)
|
|
deeq_nc(ih,jh,ia,4) = dvan(ih,jh,nt) + &
|
|
deeq(ih,jh,ia,1) - deeq(ih,jh,ia,4)
|
|
!
|
|
ENDIF
|
|
!
|
|
deeq_nc(ih,jh,ia,2) = deeq(ih,jh,ia,2) - &
|
|
( 0.D0, 1.D0 ) * deeq(ih,jh,ia,3)
|
|
!
|
|
deeq_nc(ih,jh,ia,3) = deeq(ih,jh,ia,2) + &
|
|
( 0.D0, 1.D0 ) * deeq(ih,jh,ia,3)
|
|
!
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE newd_nc
|
|
!
|
|
END SUBROUTINE newd_r
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE setqfcorr( qfcoef, rho, r, nqf, ltot, mesh )
|
|
!-----------------------------------------------------------------------
|
|
!
|
|
! ... This routine compute the first part of the Q function up to rinner.
|
|
! ... On output it contains Q
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in):: nqf, ltot, mesh
|
|
! input: the number of coefficients
|
|
! input: the angular momentum
|
|
! input: the number of mesh point
|
|
REAL(DP), INTENT(in) :: r(mesh), qfcoef(nqf)
|
|
! input: the radial mesh
|
|
! input: the coefficients of Q
|
|
REAL(DP), INTENT(out) :: rho(mesh)
|
|
! output: the function to be computed
|
|
!
|
|
INTEGER :: ir, i
|
|
REAL(DP) :: rr
|
|
!
|
|
DO ir = 1, mesh
|
|
!
|
|
rr = r(ir)**2
|
|
!
|
|
rho(ir) = qfcoef(1)
|
|
!
|
|
DO i = 2, nqf
|
|
rho(ir) = rho(ir) + qfcoef(i)*rr**(i-1)
|
|
ENDDO
|
|
!
|
|
rho(ir) = rho(ir)*r(ir)**ltot
|
|
!
|
|
ENDDO
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE setqfcorr
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE setqfcorrpt( qfcoef, rho, r, nqf, ltot )
|
|
!------------------------------------------------------------------------
|
|
!
|
|
! ... This routine compute the first part of the Q function at the
|
|
! ... point r. On output it contains Q
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in):: nqf, ltot
|
|
! input: the number of coefficients
|
|
! input: the angular momentum
|
|
REAL(DP), INTENT(in) :: r, qfcoef(nqf)
|
|
! input: the radial mesh
|
|
! input: the coefficients of Q
|
|
REAL(DP), INTENT(out) :: rho
|
|
! output: the function to be computed
|
|
!
|
|
INTEGER :: i
|
|
REAL(DP) :: rr
|
|
!
|
|
rr = r*r
|
|
!
|
|
rho = qfcoef(1)
|
|
!
|
|
DO i = 2, nqf
|
|
rho = rho + qfcoef(i)*rr**(i-1)
|
|
ENDDO
|
|
!
|
|
rho = rho*r**ltot
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE setqfcorrpt
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE setqfcorrptfirst( qfcoef, rho, r, nqf, ltot )
|
|
!------------------------------------------------------------------------
|
|
!
|
|
! ... On output it contains Q' (probably wrong)
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in) :: nqf, ltot
|
|
! input: the number of coefficients
|
|
! input: the angular momentum
|
|
REAL(DP), INTENT(in) :: r, qfcoef(nqf)
|
|
! input: the radial mesh
|
|
! input: the coefficients of Q
|
|
REAL(DP), INTENT(out) :: rho
|
|
! output: the function to be computed
|
|
!
|
|
INTEGER :: i
|
|
REAL(DP) :: rr
|
|
!
|
|
rr = r*r
|
|
!
|
|
rho = 0.D0
|
|
!
|
|
DO i = max( 1, 2-ltot ), nqf
|
|
rho = rho + qfcoef(i)*rr**(i-2+ltot)*(i-1+ltot)
|
|
ENDDO
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE setqfcorrptfirst
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE setqfcorrptsecond( qfcoef, rho, r, nqf, ltot )
|
|
!------------------------------------------------------------------------
|
|
!
|
|
! ... On output it contains Q
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in) :: nqf, ltot
|
|
! input: the number of coefficients
|
|
! input: the angular momentum
|
|
REAL(DP), INTENT(in) :: r, qfcoef(nqf)
|
|
! input: the radial mesh
|
|
! input: the coefficients of Q
|
|
REAL(DP), INTENT(out) :: rho
|
|
! output: the function to be computed
|
|
!
|
|
INTEGER :: i
|
|
REAL(DP) :: rr
|
|
!
|
|
rr = r*r
|
|
!
|
|
rho = 0.D0
|
|
!
|
|
DO i = max( 3-ltot, 1 ), nqf
|
|
rho = rho + qfcoef(i)*rr**(i-3+ltot)*(i-1+ltot)*(i-2+ltot)
|
|
ENDDO
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE setqfcorrptsecond
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE addusdens_r(rho_1,rescale)
|
|
!------------------------------------------------------------------------
|
|
!
|
|
! ... This routine adds to the charge density the part which is due to
|
|
! ... the US augmentation.
|
|
!
|
|
USE ions_base, ONLY : nat, ityp
|
|
USE cell_base, ONLY : omega
|
|
USE lsda_mod, ONLY : nspin
|
|
!USE scf, ONLY : rho
|
|
USE klist, ONLY : nelec
|
|
USE grid_dimensions, ONLY : nr1, nr2, nr3, nrxx
|
|
USE uspp, ONLY : okvan, becsum
|
|
USE uspp_param, ONLY : upf, nh
|
|
USE noncollin_module, ONLY : noncolin, nspin_mag, nspin_lsda
|
|
USE spin_orb, ONLY : domag
|
|
USE mp_global, ONLY : intra_pool_comm, inter_pool_comm
|
|
USE mp, ONLY : mp_sum
|
|
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
REAL(kind=dp), INTENT(inout) :: rho_1(nrxx,nspin_mag) !The charge density to be augmented
|
|
LOGICAL, INTENT(in) :: rescale !If this is the ground charge density, enable rescaling
|
|
!
|
|
INTEGER :: ia, nt, ir, irb, ih, jh, ijh, is, mbia, nhnt, iqs
|
|
CHARACTER(len=80) :: msg
|
|
REAL(DP) :: charge
|
|
REAL(DP) :: tolerance
|
|
!
|
|
!
|
|
IF ( .not. okvan ) RETURN
|
|
tolerance = 1.D-4
|
|
IF ( real_space ) tolerance = 1.D-2 !Charge loss in real_space case is even worse.
|
|
!Final verdict: Mixing of Real Space paradigm and !Q space paradigm results in fast but not so
|
|
! accurate code. Not giving up though, I think
|
|
! I can still increase the accuracy a bit...
|
|
!
|
|
CALL start_clock( 'addusdens' )
|
|
!
|
|
DO is = 1, nspin_mag
|
|
!
|
|
iqs = 0
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
mbia = maxbox(ia)
|
|
!
|
|
IF ( mbia == 0 ) CYCLE
|
|
!
|
|
nt = ityp(ia)
|
|
!
|
|
IF ( .not. upf(nt)%tvanp ) CYCLE
|
|
!
|
|
nhnt = nh(nt)
|
|
!
|
|
ijh = 0
|
|
!
|
|
DO ih = 1, nhnt
|
|
DO jh = ih, nhnt
|
|
!
|
|
ijh = ijh + 1
|
|
!
|
|
DO ir = 1, mbia
|
|
!
|
|
irb = box(ir,ia)
|
|
iqs = iqs + 1
|
|
!
|
|
rho_1(irb,is) = rho_1(irb,is) + qsave(iqs)*becsum(ijh,ia,is)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
!
|
|
! ... check the integral of the total charge
|
|
|
|
IF (rescale) THEN
|
|
!OBM, RHO IS NOT NECESSARILY GROUND STATE CHARGE DENSITY, thus rescaling is optional
|
|
charge = sum( rho_1(:,1:nspin_lsda) )*omega / ( nr1*nr2*nr3 )
|
|
|
|
CALL mp_sum( charge , intra_pool_comm )
|
|
CALL mp_sum( charge , inter_pool_comm )
|
|
|
|
IF ( abs( charge - nelec ) / charge > tolerance ) THEN
|
|
!
|
|
! ... the error on the charge is too large
|
|
!
|
|
WRITE (msg,'("expected ",f13.8,", found ",f13.8)') &
|
|
nelec, charge
|
|
CALL errore( 'addusdens_r', &
|
|
trim(msg)//': wrong charge, increase ecutrho', 1 )
|
|
!
|
|
ELSE
|
|
!
|
|
! ... rescale the density to impose the correct number of electrons
|
|
!
|
|
rho_1(:,:) = rho_1(:,:) / charge * nelec
|
|
!
|
|
ENDIF
|
|
ENDIF
|
|
!
|
|
CALL stop_clock( 'addusdens' )
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE addusdens_r
|
|
!--------------------------------------------------------------------------
|
|
SUBROUTINE calbec_rs_gamma ( ibnd, m, becp_r )
|
|
|
|
!--------------------------------------------------------------------------
|
|
!
|
|
! Subroutine written by Dario Rocca Stefano de Gironcoli, modified by O. Baris Malcioglu
|
|
!
|
|
! Calculates becp_r in real space
|
|
! Requires BETASAVE (the beta functions at real space) calculated by betapointlist() (added to realus)
|
|
! ibnd is an index that runs over the number of bands, which is given by m
|
|
! So you have to call this subroutine inside a cycle with index ibnd
|
|
! In this cycle you have to perform a Fourier transform of the orbital
|
|
! corresponding to ibnd, namely you have to transform the orbital to
|
|
! real space and store it in the global variable psic.
|
|
! Remember that in the gamma_only case you
|
|
! perform two fast Fourier transform at the same time, and so you have
|
|
! that the real part correspond to ibnd, and the imaginary part to ibnd+1
|
|
!
|
|
! WARNING: For the sake of speed, there are no checks performed in this routine, check beforehand!
|
|
USE kinds, ONLY : DP
|
|
USE cell_base, ONLY : omega
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE ions_base, ONLY : nat, ntyp => nsp, ityp
|
|
USE smooth_grid_dimensions,ONLY : nr1s, nr2s, nr3s
|
|
USE uspp_param, ONLY : nh, nhm
|
|
USE fft_base, ONLY : tg_gather, dffts
|
|
USE mp_global, ONLY : me_pool, intra_pool_comm
|
|
USE mp, ONLY : mp_sum
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in) :: ibnd, m
|
|
INTEGER :: iqs, iqsp, ikb, nt, ia, ih, mbia
|
|
REAL(DP) :: fac
|
|
REAL(DP), ALLOCATABLE, DIMENSION(:) :: wr, wi
|
|
REAL(DP) :: bcr, bci
|
|
REAL(DP), DIMENSION(:,:), INTENT(out) :: becp_r
|
|
!COMPLEX(DP), allocatable, dimension(:) :: bt
|
|
!integer :: ir, k
|
|
!
|
|
REAL(DP), EXTERNAL :: ddot
|
|
!
|
|
!
|
|
CALL start_clock( 'calbec_rs' )
|
|
!
|
|
IF( ( dffts%have_task_groups ) .and. ( m >= dffts%nogrp ) ) THEN
|
|
|
|
CALL errore( 'calbec_rs_gamma', 'task_groups not implemented', 1 )
|
|
|
|
ELSE !non task groups part starts here
|
|
|
|
fac = sqrt(omega) / (nr1s*nr2s*nr3s)
|
|
!
|
|
becp_r(:,ibnd)=0.d0
|
|
IF ( ibnd+1 .le. m ) becp_r(:,ibnd+1)=0.d0
|
|
! Clearly for an odd number of bands for ibnd=nbnd=m you don't have
|
|
! anymore bands, and so the imaginary part equal zero
|
|
!
|
|
!
|
|
iqs = 1
|
|
ikb = 0
|
|
!
|
|
DO nt = 1, ntyp
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
IF ( ityp(ia) == nt ) THEN
|
|
!
|
|
mbia = maxbox_beta(ia)
|
|
|
|
! maxbox_beta contains the maximum number of real space points necessary
|
|
! to describe the beta function corresponding to the atom ia
|
|
! Namely this is the number of grid points for which beta is
|
|
! different from zero
|
|
!
|
|
ALLOCATE( wr(mbia), wi(mbia) )
|
|
! just working arrays
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
! nh is the number of beta functions, or something similar
|
|
!
|
|
ikb = ikb + 1
|
|
iqsp = iqs+mbia-1
|
|
wr(:) = dble ( psic( box_beta(1:mbia,ia) ) )
|
|
wi(:) = aimag( psic( box_beta(1:mbia,ia) ) )
|
|
!print *, "betasave check", betasave(ia,ih,:)
|
|
! box_beta contains explictly the points of the real space grid in
|
|
! which the beta functions are differet from zero. Remember
|
|
! that dble(psic) corresponds to ibnd, and aimag(psic) to ibnd+1:
|
|
! this is the standard way to perform fourier transform in pwscf
|
|
! in the gamma_only case
|
|
bcr = ddot( mbia, betasave(ia,ih,:), 1, wr(:) , 1 )
|
|
bci = ddot( mbia, betasave(ia,ih,:), 1, wi(:) , 1 )
|
|
! in the previous two lines the real space integral is performed, using
|
|
! few points of the real space mesh only
|
|
becp_r(ikb,ibnd) = fac * bcr
|
|
IF ( ibnd+1 .le. m ) becp_r(ikb,ibnd+1) = fac * bci
|
|
! It is necessary to multiply by fac which to obtain the integral in real
|
|
! space
|
|
!print *, becp_r(ikb,ibnd)
|
|
iqs = iqsp + 1
|
|
!
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( wr, wi )
|
|
!
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
!
|
|
!
|
|
ENDIF
|
|
CALL mp_sum( becp_r( :, ibnd ), intra_pool_comm )
|
|
IF ( ibnd+1 .le. m ) CALL mp_sum( becp_r( :, ibnd+1 ), intra_pool_comm )
|
|
CALL stop_clock( 'calbec_rs' )
|
|
!
|
|
RETURN
|
|
|
|
END SUBROUTINE calbec_rs_gamma
|
|
!
|
|
SUBROUTINE calbec_rs_k ( ibnd, m )
|
|
!--------------------------------------------------------------------------
|
|
! The k_point generalised version of calbec_rs_gamma. Basically same as above, but becp is used instead
|
|
! of becp_r, skipping the gamma point reduction
|
|
! derived from above by OBM 051108
|
|
USE kinds, ONLY : DP
|
|
USE cell_base, ONLY : omega
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE ions_base, ONLY : nat, ntyp => nsp, ityp
|
|
USE smooth_grid_dimensions,ONLY : nr1s, nr2s, nr3s
|
|
USE uspp_param, ONLY : nh, nhm
|
|
USE becmod, ONLY : bec_type, becp
|
|
USE fft_base, ONLY : tg_gather, dffts
|
|
USE mp_global, ONLY : me_pool
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in) :: ibnd, m
|
|
INTEGER :: iqs, iqsp, ikb, nt, ia, ih, mbia
|
|
REAL(DP) :: fac
|
|
REAL(DP), ALLOCATABLE, DIMENSION(:) :: wr, wi
|
|
REAL(DP) :: bcr, bci
|
|
!COMPLEX(DP), allocatable, dimension(:) :: bt
|
|
!integer :: ir, k
|
|
!
|
|
REAL(DP), EXTERNAL :: ddot
|
|
!
|
|
!
|
|
CALL start_clock( 'calbec_rs' )
|
|
!
|
|
IF( ( dffts%have_task_groups ) .and. ( m >= dffts%nogrp ) ) THEN
|
|
|
|
CALL errore( 'calbec_rs_k', 'task_groups not implemented', 1 )
|
|
|
|
ELSE !non task groups part starts here
|
|
|
|
fac = sqrt(omega) / (nr1s*nr2s*nr3s)
|
|
!
|
|
becp%k(:,ibnd)=0.d0
|
|
iqs = 1
|
|
ikb = 0
|
|
!
|
|
DO nt = 1, ntyp
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
IF ( ityp(ia) == nt ) THEN
|
|
!
|
|
mbia = maxbox_beta(ia)
|
|
ALLOCATE( wr(mbia), wi(mbia) )
|
|
DO ih = 1, nh(nt)
|
|
! nh is the number of beta functions, or something similar
|
|
!
|
|
ikb = ikb + 1
|
|
iqsp = iqs+mbia-1
|
|
wr(:) = dble ( psic( box_beta(1:mbia,ia) ) )
|
|
wi(:) = aimag( psic( box_beta(1:mbia,ia) ) )
|
|
bcr = ddot( mbia, betasave(ia,ih,:), 1, wr(:) , 1 )
|
|
bci = ddot( mbia, betasave(ia,ih,:), 1, wi(:) , 1 )
|
|
becp%k(ikb,ibnd) = fac * cmplx( bcr, bci,kind=DP)
|
|
iqs = iqsp + 1
|
|
!
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( wr, wi )
|
|
!
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
!
|
|
!
|
|
ENDIF
|
|
CALL stop_clock( 'calbec_rs' )
|
|
!
|
|
RETURN
|
|
|
|
END SUBROUTINE calbec_rs_k
|
|
!--------------------------------------------------------------------------
|
|
SUBROUTINE s_psir_gamma ( ibnd, m )
|
|
!--------------------------------------------------------------------------
|
|
!
|
|
! ... This routine applies the S matrix to m wavefunctions psi in real space (in psic),
|
|
! ... and puts the results again in psic for backtransforming.
|
|
! ... Requires becp%r (calbecr in REAL SPACE) and betasave (from betapointlist in realus)
|
|
! Subroutine written by Dario Rocca, modified by O. Baris Malcioglu
|
|
! WARNING ! for the sake of speed, no checks performed in this subroutine
|
|
|
|
USE kinds, ONLY : DP
|
|
USE cell_base, ONLY : omega
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE ions_base, ONLY : nat, ntyp => nsp, ityp
|
|
USE uspp_param, ONLY : nh
|
|
USE lsda_mod, ONLY : current_spin
|
|
USE uspp, ONLY : qq
|
|
USE becmod, ONLY : bec_type, becp
|
|
USE fft_base, ONLY : tg_gather, dffts
|
|
USE mp_global, ONLY : me_pool
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in) :: ibnd, m
|
|
!
|
|
INTEGER :: ih, jh, iqs, jqs, ikb, jkb, nt, ia, ir, mbia
|
|
REAL(DP) :: fac
|
|
REAL(DP), ALLOCATABLE, DIMENSION(:) :: w1, w2, bcr, bci
|
|
!
|
|
REAL(DP), EXTERNAL :: ddot
|
|
!
|
|
|
|
|
|
|
|
CALL start_clock( 's_psir' )
|
|
IF( ( dffts%have_task_groups ) .and. ( m >= dffts%nogrp ) ) THEN
|
|
|
|
CALL errore( 's_psir_gamma', 'task_groups not implemented', 1 )
|
|
|
|
ELSE !non task groups part starts here
|
|
|
|
!
|
|
fac = sqrt(omega)
|
|
!
|
|
ikb = 0
|
|
iqs = 0
|
|
jqs = 0
|
|
!
|
|
DO nt = 1, ntyp
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
IF ( ityp(ia) == nt ) THEN
|
|
!
|
|
mbia = maxbox_beta(ia)
|
|
!print *, "mbia=",mbia
|
|
ALLOCATE( w1(nh(nt)), w2(nh(nt)) )
|
|
w1 = 0.D0
|
|
w2 = 0.D0
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
!
|
|
DO jh = 1, nh(nt)
|
|
!
|
|
jkb = ikb + jh
|
|
w1(ih) = w1(ih) + qq(ih,jh,nt) * becp%r(jkb, ibnd)
|
|
IF ( ibnd+1 .le. m ) w2(ih) = w2(ih) + qq(ih,jh,nt) * becp%r(jkb, ibnd+1)
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
!
|
|
w1 = w1 * fac
|
|
w2 = w2 * fac
|
|
ikb = ikb + nh(nt)
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
!
|
|
DO ir = 1, mbia
|
|
!
|
|
iqs = jqs + ir
|
|
psic( box_beta(ir,ia) ) = psic( box_beta(ir,ia) ) + betasave(ia,ih,ir)*cmplx( w1(ih), w2(ih) ,kind=DP)
|
|
!
|
|
ENDDO
|
|
!
|
|
jqs = iqs
|
|
!
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( w1, w2 )
|
|
!
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDIF
|
|
CALL stop_clock( 's_psir' )
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE s_psir_gamma
|
|
!
|
|
SUBROUTINE s_psir_k ( ibnd, m )
|
|
!--------------------------------------------------------------------------
|
|
! Same as s_psir_gamma but for generalised k point scheme i.e.:
|
|
! 1) Only one band is considered at a time
|
|
! 2) Becp is a complex entity now
|
|
! Derived from s_psir_gamma by OBM 061108
|
|
USE kinds, ONLY : DP
|
|
USE cell_base, ONLY : omega
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE ions_base, ONLY : nat, ntyp => nsp, ityp
|
|
USE uspp_param, ONLY : nh
|
|
USE lsda_mod, ONLY : current_spin
|
|
USE uspp, ONLY : qq
|
|
USE becmod, ONLY : bec_type, becp
|
|
USE fft_base, ONLY : tg_gather, dffts
|
|
USE mp_global, ONLY : me_pool
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in) :: ibnd, m
|
|
!
|
|
INTEGER :: ih, jh, iqs, jqs, ikb, jkb, nt, ia, ir, mbia
|
|
REAL(DP) :: fac
|
|
REAL(DP), ALLOCATABLE, DIMENSION(:) :: bcr, bci
|
|
COMPLEX(DP) , ALLOCATABLE, DIMENSION(:) :: w1
|
|
!
|
|
REAL(DP), EXTERNAL :: ddot
|
|
!
|
|
|
|
|
|
|
|
CALL start_clock( 's_psir' )
|
|
IF( ( dffts%have_task_groups ) .and. ( m >= dffts%nogrp ) ) THEN
|
|
|
|
CALL errore( 's_psir_k', 'task_groups not implemented', 1 )
|
|
|
|
ELSE !non task groups part starts here
|
|
|
|
!
|
|
fac = sqrt(omega)
|
|
!
|
|
ikb = 0
|
|
iqs = 0
|
|
jqs = 0
|
|
!
|
|
DO nt = 1, ntyp
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
IF ( ityp(ia) == nt ) THEN
|
|
!
|
|
mbia = maxbox_beta(ia)
|
|
ALLOCATE( w1(nh(nt)) )
|
|
w1 = 0.D0
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
!
|
|
DO jh = 1, nh(nt)
|
|
!
|
|
jkb = ikb + jh
|
|
w1(ih) = w1(ih) + qq(ih,jh,nt) * becp%k(jkb, ibnd)
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
!
|
|
w1 = w1 * fac
|
|
ikb = ikb + nh(nt)
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
!
|
|
DO ir = 1, mbia
|
|
!
|
|
iqs = jqs + ir
|
|
psic( box_beta(ir,ia) ) = psic( box_beta(ir,ia) ) + betasave(ia,ih,ir)*w1(ih)
|
|
!
|
|
ENDDO
|
|
!
|
|
jqs = iqs
|
|
!
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( w1 )
|
|
!
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDIF
|
|
CALL stop_clock( 's_psir' )
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE s_psir_k
|
|
!
|
|
SUBROUTINE add_vuspsir_gamma ( ibnd, m )
|
|
!--------------------------------------------------------------------------
|
|
!
|
|
! This routine applies the Ultra-Soft Hamiltonian to a
|
|
! vector transformed in real space contained in psic.
|
|
! ibnd is an index that runs over the number of bands, which is given by m
|
|
! Requires the products of psi with all beta functions
|
|
! in array becp%r(nkb,m) (calculated by calbecr in REAL SPACE)
|
|
! Subroutine written by Dario Rocca, modified by O. Baris Malcioglu
|
|
! WARNING ! for the sake of speed, no checks performed in this subroutine
|
|
|
|
USE kinds, ONLY : DP
|
|
USE cell_base, ONLY : omega
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE ions_base, ONLY : nat, ntyp => nsp, ityp
|
|
USE uspp_param, ONLY : nh
|
|
USE lsda_mod, ONLY : current_spin
|
|
USE uspp, ONLY : deeq
|
|
USE becmod, ONLY : bec_type, becp
|
|
USE fft_base, ONLY : tg_gather, dffts
|
|
USE mp_global, ONLY : me_pool
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in) :: ibnd, m
|
|
!
|
|
INTEGER :: ih, jh, iqs, jqs, ikb, jkb, nt, ia, ir, mbia
|
|
REAL(DP) :: fac
|
|
REAL(DP), ALLOCATABLE, DIMENSION(:) :: w1, w2, bcr, bci
|
|
!
|
|
REAL(DP), EXTERNAL :: ddot
|
|
!
|
|
CALL start_clock( 'add_vuspsir' )
|
|
|
|
IF( ( dffts%have_task_groups ) .and. ( m >= dffts%nogrp ) ) THEN
|
|
|
|
CALL errore( 'add_vuspsir_gamma', 'task_groups not implemented', 1 )
|
|
|
|
ELSE !non task groups part starts here
|
|
|
|
!
|
|
fac = sqrt(omega)
|
|
!
|
|
ikb = 0
|
|
iqs = 0
|
|
jqs = 0
|
|
!
|
|
DO nt = 1, ntyp
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
IF ( ityp(ia) == nt ) THEN
|
|
!
|
|
mbia = maxbox_beta(ia)
|
|
ALLOCATE( w1(nh(nt)), w2(nh(nt)) )
|
|
w1 = 0.D0
|
|
w2 = 0.D0
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
!
|
|
DO jh = 1, nh(nt)
|
|
!
|
|
jkb = ikb + jh
|
|
!
|
|
w1(ih) = w1(ih) + deeq(ih,jh,ia,current_spin) * becp%r(jkb,ibnd)
|
|
IF ( ibnd+1 .le. m ) w2(ih) = w2(ih) + deeq(ih,jh,ia,current_spin) * becp%r(jkb,ibnd+1)
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
!
|
|
w1 = w1 * fac
|
|
w2 = w2 * fac
|
|
ikb = ikb + nh(nt)
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
!
|
|
DO ir = 1, mbia
|
|
!
|
|
iqs = jqs + ir
|
|
psic( box_beta(ir,ia) ) = psic( box_beta(ir,ia) ) + betasave(ia,ih,ir)*cmplx( w1(ih), w2(ih) ,kind=DP)
|
|
!
|
|
ENDDO
|
|
!
|
|
jqs = iqs
|
|
!
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( w1, w2 )
|
|
!
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDIF
|
|
CALL stop_clock( 'add_vuspsir' )
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE add_vuspsir_gamma
|
|
!
|
|
SUBROUTINE add_vuspsir_k ( ibnd, m )
|
|
!--------------------------------------------------------------------------
|
|
!
|
|
! This routine applies the Ultra-Soft Hamiltonian to a
|
|
! vector transformed in real space contained in psic.
|
|
! ibnd is an index that runs over the number of bands, which is given by m
|
|
! Requires the products of psi with all beta functions
|
|
! in array becp(nkb,m) (calculated by calbecr in REAL SPACE)
|
|
! Subroutine written by Stefano de Gironcoli, modified by O. Baris Malcioglu
|
|
! WARNING ! for the sake of speed, no checks performed in this subroutine
|
|
!
|
|
USE kinds, ONLY : DP
|
|
USE cell_base, ONLY : omega
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE ions_base, ONLY : nat, ntyp => nsp, ityp
|
|
USE uspp_param, ONLY : nh
|
|
USE lsda_mod, ONLY : current_spin
|
|
USE uspp, ONLY : deeq
|
|
USE becmod, ONLY : bec_type, becp
|
|
USE fft_base, ONLY : tg_gather, dffts
|
|
USE mp_global, ONLY : me_pool
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(in) :: ibnd, m
|
|
!
|
|
INTEGER :: ih, jh, iqs, jqs, ikb, jkb, nt, ia, ir, mbia
|
|
REAL(DP) :: fac
|
|
REAL(DP), ALLOCATABLE, DIMENSION(:) :: bcr, bci
|
|
!
|
|
COMPLEX(DP), ALLOCATABLE, DIMENSION(:) :: w1
|
|
!
|
|
REAL(DP), EXTERNAL :: ddot
|
|
!
|
|
CALL start_clock( 'add_vuspsir' )
|
|
|
|
IF( ( dffts%have_task_groups ) .and. ( m >= dffts%nogrp ) ) THEN
|
|
|
|
CALL errore( 'add_vuspsir_k', 'task_groups not implemented', 1 )
|
|
|
|
ELSE !non task groups part starts here
|
|
|
|
!
|
|
fac = sqrt(omega)
|
|
!
|
|
ikb = 0
|
|
iqs = 0
|
|
jqs = 0
|
|
!
|
|
DO nt = 1, ntyp
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
IF ( ityp(ia) == nt ) THEN
|
|
!
|
|
mbia = maxbox_beta(ia)
|
|
ALLOCATE( w1(nh(nt)) )
|
|
w1 = (0.d0, 0d0)
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
!
|
|
DO jh = 1, nh(nt)
|
|
!
|
|
jkb = ikb + jh
|
|
!
|
|
w1(ih) = w1(ih) + deeq(ih,jh,ia,current_spin) * becp%k(jkb,ibnd)
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
!
|
|
w1 = w1 * fac
|
|
ikb = ikb + nh(nt)
|
|
!
|
|
DO ih = 1, nh(nt)
|
|
!
|
|
DO ir = 1, mbia
|
|
!
|
|
iqs = jqs + ir
|
|
psic( box_beta(ir,ia) ) = psic( box_beta(ir,ia) ) + betasave(ia,ih,ir)*w1(ih)
|
|
!
|
|
ENDDO
|
|
!
|
|
jqs = iqs
|
|
!
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( w1)
|
|
!
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDDO
|
|
ENDIF
|
|
CALL stop_clock( 'add_vuspsir' )
|
|
RETURN
|
|
!
|
|
END SUBROUTINE add_vuspsir_k
|
|
|
|
!--------------------------------------------------------------------------
|
|
SUBROUTINE fft_orbital_gamma (orbital, ibnd, nbnd, conserved)
|
|
!--------------------------------------------------------------------------
|
|
!
|
|
! OBM 241008
|
|
! This driver subroutine transforms the given orbital using fft and puts the result in psic
|
|
! Warning! In order to be fast, no checks on the supplied data are performed!
|
|
! orbital: the orbital to be transformed
|
|
! ibnd: band index
|
|
! nbnd: total number of bands
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE gvecs, ONLY : nls,nlsm,doublegrid
|
|
USE kinds, ONLY : DP
|
|
USE fft_base, ONLY : dffts, tg_gather
|
|
USE fft_interfaces,ONLY : invfft
|
|
USE mp_global, ONLY : me_pool
|
|
|
|
IMPLICIT NONE
|
|
|
|
INTEGER, INTENT(in) :: ibnd,& ! Current index of the band currently being transformed
|
|
nbnd ! Total number of bands you want to transform
|
|
|
|
COMPLEX(DP),INTENT(in) :: orbital(:,:)
|
|
LOGICAL, OPTIONAL :: conserved !if this flag is true, the orbital is stored in temporary memory
|
|
|
|
!integer :: ig
|
|
|
|
!Internal temporary variables
|
|
COMPLEX(DP) :: fp, fm,alpha
|
|
|
|
INTEGER :: i, j, incr, ierr, idx, ioff, nsiz
|
|
LOGICAL :: use_tg
|
|
|
|
COMPLEX(DP), ALLOCATABLE :: psic_temp2(:)
|
|
|
|
!Task groups
|
|
!COMPLEX(DP), ALLOCATABLE :: tg_psic(:)
|
|
INTEGER :: recv_cnt( dffts%nogrp ), recv_displ( dffts%nogrp )
|
|
INTEGER :: v_siz
|
|
|
|
!The new task group version based on vloc_psi
|
|
!print *, "->Real space"
|
|
CALL start_clock( 'fft_orbital' )
|
|
!
|
|
! The following is dirty trick to prevent usage of task groups if
|
|
! the number of bands is smaller than the number of task groups
|
|
!
|
|
use_tg = dffts%have_task_groups
|
|
dffts%have_task_groups = ( dffts%have_task_groups ) .and. ( nbnd >= dffts%nogrp )
|
|
|
|
IF( dffts%have_task_groups ) THEN
|
|
!
|
|
|
|
tg_psic = (0.d0, 0.d0)
|
|
ioff = 0
|
|
!
|
|
DO idx = 1, 2*dffts%nogrp, 2
|
|
|
|
IF( idx + ibnd - 1 < nbnd ) THEN
|
|
DO j = 1, npw_k(1)
|
|
tg_psic(nls (igk_k(j,1))+ioff) = orbital(j,idx+ibnd-1) +&
|
|
(0.0d0,1.d0) * orbital(j,idx+ibnd)
|
|
tg_psic(nlsm(igk_k(j,1))+ioff) =conjg(orbital(j,idx+ibnd-1) -&
|
|
(0.0d0,1.d0) * orbital(j,idx+ibnd) )
|
|
ENDDO
|
|
ELSEIF( idx + ibnd - 1 == nbnd ) THEN
|
|
DO j = 1, npw_k(1)
|
|
tg_psic(nls (igk_k(j,1))+ioff) = orbital(j,idx+ibnd-1)
|
|
tg_psic(nlsm(igk_k(j,1))+ioff) = conjg( orbital(j,idx+ibnd-1))
|
|
ENDDO
|
|
ENDIF
|
|
|
|
ioff = ioff + dffts%tg_nnr
|
|
|
|
ENDDO
|
|
!
|
|
!
|
|
CALL invfft ('Wave', tg_psic, dffts)
|
|
!
|
|
!
|
|
IF (present(conserved)) THEN
|
|
IF (conserved .eqv. .true.) THEN
|
|
IF (.not. allocated(tg_psic_temp)) ALLOCATE( tg_psic_temp( dffts%tg_nnr * dffts%nogrp ) )
|
|
tg_psic_temp=tg_psic
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ELSE !Task groups not used
|
|
!
|
|
psic(:) = (0.d0, 0.d0)
|
|
|
|
! alpha=(0.d0,1.d0)
|
|
! if (ibnd .eq. nbnd) alpha=(0.d0,0.d0)
|
|
!
|
|
! allocate (psic_temp2(npw_k(1)))
|
|
! call zcopy(npw_k(1),orbital(:, ibnd),1,psic_temp2,1)
|
|
! call zaxpy(npw_k(1),alpha,orbital(:, ibnd+1),1,psic_temp2,1)
|
|
! psic (nls (igk_k(:,1)))=psic_temp2(:)
|
|
! call zaxpy(npw_k(1),(-2.d0,0.d0)*alpha,orbital(:, ibnd+1),1,psic_temp2,1)
|
|
! psic (nlsm (igk_k(:,1)))=conjg(psic_temp2(:))
|
|
! deallocate(psic_temp2)
|
|
|
|
|
|
IF (ibnd < nbnd) THEN
|
|
! two ffts at the same time
|
|
!print *,"alpha=",alpha
|
|
DO j = 1, npw_k(1)
|
|
psic (nls (igk_k(j,1))) = orbital(j, ibnd) + (0.0d0,1.d0)*orbital(j, ibnd+1)
|
|
psic (nlsm(igk_k(j,1))) = conjg(orbital(j, ibnd) - (0.0d0,1.d0)*orbital(j, ibnd+1))
|
|
!print *, nls (igk_k(j,1))
|
|
ENDDO
|
|
!CALL errore( 'fft_orbital_gamma', 'bye bye', 1 )
|
|
ELSE
|
|
DO j = 1, npw_k(1)
|
|
psic (nls (igk_k(j,1))) = orbital(j, ibnd)
|
|
psic (nlsm(igk_k(j,1))) = conjg(orbital(j, ibnd))
|
|
ENDDO
|
|
ENDIF
|
|
!
|
|
!
|
|
CALL invfft ('Wave', psic, dffts)
|
|
!
|
|
!
|
|
IF (present(conserved)) THEN
|
|
IF (conserved .eqv. .true.) THEN
|
|
IF (.not. allocated(psic_temp) ) ALLOCATE (psic_temp(size(psic)))
|
|
CALL zcopy(size(psic),psic,1,psic_temp,1)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
dffts%have_task_groups = use_tg
|
|
|
|
!if (.not. allocated(psic)) CALL errore( 'fft_orbital_gamma', 'psic not allocated', 2 )
|
|
! OLD VERSION ! Based on an algorithm found somewhere in the TDDFT codes, generalised to k points
|
|
!
|
|
! psic(:) =(0.0d0,0.0d0)
|
|
! if(ibnd<nbnd) then
|
|
! do ig=1,npw_k(1)
|
|
! !
|
|
! psic(nls(igk_k(ig,1)))=orbital(ig,ibnd)+&
|
|
! (0.0d0,1.0d0)*orbital(ig,ibnd+1)
|
|
! psic(nlsm(igk_k(ig,1)))=conjg(orbital(ig,ibnd)-&
|
|
! (0.0d0,1.0d0)*orbital(ig,ibnd+1))
|
|
! !
|
|
! enddo
|
|
! else
|
|
! do ig=1,npw_k(1)
|
|
! !
|
|
! psic(nls(igk_k(ig,1)))=orbital(ig,ibnd)
|
|
! psic(nlsm(igk_k(ig,1)))=conjg(orbital(ig,ibnd))
|
|
! !
|
|
! enddo
|
|
! endif
|
|
! !
|
|
! CALL invfft ('Wave', psic, dffts)
|
|
CALL stop_clock( 'fft_orbital' )
|
|
|
|
END SUBROUTINE fft_orbital_gamma
|
|
!
|
|
!
|
|
!--------------------------------------------------------------------------
|
|
SUBROUTINE bfft_orbital_gamma (orbital, ibnd, nbnd,conserved)
|
|
!--------------------------------------------------------------------------
|
|
!
|
|
! OBM 241008
|
|
! This driver subroutine -back- transforms the given orbital using fft using the already existent data
|
|
! in psic. Warning! This subroutine does not reset the orbital, use carefully!
|
|
! Warning 2! In order to be fast, no checks on the supplied data are performed!
|
|
! Variables:
|
|
! orbital: the orbital to be transformed
|
|
! ibnd: band index
|
|
! nbnd: total number of bands
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE gvecs, ONLY : nls,nlsm,doublegrid
|
|
USE kinds, ONLY : DP
|
|
USE fft_base, ONLY : dffts, tg_gather
|
|
USE fft_interfaces,ONLY : fwfft
|
|
USE mp_global, ONLY : me_pool
|
|
|
|
IMPLICIT NONE
|
|
|
|
INTEGER, INTENT(in) :: ibnd,& ! Current index of the band currently being transformed
|
|
nbnd ! Total number of bands you want to transform
|
|
|
|
COMPLEX(DP),INTENT(out) :: orbital(:,:)
|
|
|
|
!integer :: ig
|
|
|
|
LOGICAL, OPTIONAL :: conserved !if this flag is true, the orbital is stored in temporary memory
|
|
|
|
!Internal temporary variables
|
|
COMPLEX(DP) :: fp, fm
|
|
INTEGER :: i, j, incr, ierr, idx, ioff, nsiz
|
|
LOGICAL :: use_tg
|
|
|
|
!Task groups
|
|
INTEGER :: recv_cnt( dffts%nogrp ), recv_displ( dffts%nogrp )
|
|
INTEGER :: v_siz
|
|
!print *, "->fourier space"
|
|
CALL start_clock( 'bfft_orbital' )
|
|
!New task_groups versions
|
|
use_tg = dffts%have_task_groups
|
|
dffts%have_task_groups = ( dffts%have_task_groups ) .and. ( nbnd >= dffts%nogrp )
|
|
IF( dffts%have_task_groups ) THEN
|
|
!
|
|
CALL fwfft ('Wave', tg_psic, dffts )
|
|
!
|
|
ioff = 0
|
|
!
|
|
DO idx = 1, 2*dffts%nogrp, 2
|
|
!
|
|
IF( idx + ibnd - 1 < nbnd ) THEN
|
|
DO j = 1, npw_k(1)
|
|
fp= ( tg_psic( nls(igk_k(j,1)) + ioff ) + &
|
|
tg_psic( nlsm(igk_k(j,1)) + ioff ) ) * 0.5d0
|
|
fm= ( tg_psic( nls(igk_k(j,1)) + ioff ) - &
|
|
tg_psic( nlsm(igk_k(j,1)) + ioff ) ) * 0.5d0
|
|
orbital (j, ibnd+idx-1) = cmplx( dble(fp), aimag(fm),kind=DP)
|
|
orbital (j, ibnd+idx ) = cmplx(aimag(fp),- dble(fm),kind=DP)
|
|
ENDDO
|
|
ELSEIF( idx + ibnd - 1 == nbnd ) THEN
|
|
DO j = 1, npw_k(1)
|
|
orbital (j, ibnd+idx-1) = tg_psic( nls(igk_k(j,1)) + ioff )
|
|
ENDDO
|
|
ENDIF
|
|
!
|
|
ioff = ioff + dffts%nr3x * dffts%nsw( me_pool + 1 )
|
|
!
|
|
ENDDO
|
|
!
|
|
IF (present(conserved)) THEN
|
|
IF (conserved .eqv. .true.) THEN
|
|
IF (allocated(tg_psic_temp)) DEALLOCATE( tg_psic_temp )
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ELSE !Non task_groups version
|
|
!larger memory slightly faster
|
|
CALL fwfft ('Wave', psic, dffts)
|
|
|
|
|
|
IF (ibnd < nbnd) THEN
|
|
|
|
! two ffts at the same time
|
|
DO j = 1, npw_k(1)
|
|
fp = (psic (nls(igk_k(j,1))) + psic (nlsm(igk_k(j,1))))*0.5d0
|
|
fm = (psic (nls(igk_k(j,1))) - psic (nlsm(igk_k(j,1))))*0.5d0
|
|
orbital( j, ibnd) = cmplx( dble(fp), aimag(fm),kind=DP)
|
|
orbital( j, ibnd+1) = cmplx(aimag(fp),- dble(fm),kind=DP)
|
|
ENDDO
|
|
ELSE
|
|
DO j = 1, npw_k(1)
|
|
orbital(j, ibnd) = psic (nls(igk_k(j,1)))
|
|
ENDDO
|
|
ENDIF
|
|
IF (present(conserved)) THEN
|
|
IF (conserved .eqv. .true.) THEN
|
|
IF (allocated(psic_temp) ) DEALLOCATE(psic_temp)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
dffts%have_task_groups = use_tg
|
|
!! OLD VERSION Based on the algorithm found in lr_apply_liovillian
|
|
!!print * ,"a"
|
|
!CALL fwfft ('Wave', psic, dffts)
|
|
!!
|
|
!!print *, "b"
|
|
!if (ibnd<nbnd) then
|
|
! !
|
|
! do ig=1,npw_k(1)
|
|
! !
|
|
! fp=(psic(nls(igk_k(ig,1)))&
|
|
! +psic(nlsm(igk_k(ig,1))))*(0.50d0,0.0d0)
|
|
! !
|
|
! fm=(psic(nls(igk_k(ig,1)))&
|
|
! -psic(nlsm(igk_k(ig,1))))*(0.50d0,0.0d0)
|
|
! !
|
|
! orbital(ig,ibnd)=CMPLX(dble(fp),aimag(fm),dp)
|
|
! !
|
|
! orbital(ig,ibnd+1)=CMPLX(aimag(fp),-dble(fm),dp)
|
|
! !
|
|
! enddo
|
|
! !
|
|
!else
|
|
! !
|
|
! do ig=1,npw_k(1)
|
|
! !
|
|
! orbital(ig,ibnd)=psic(nls(igk_k(ig,1)))
|
|
! !
|
|
! enddo
|
|
! !
|
|
!endif
|
|
!print * , "c"
|
|
!
|
|
!
|
|
CALL stop_clock( 'bfft_orbital' )
|
|
|
|
END SUBROUTINE bfft_orbital_gamma
|
|
!
|
|
!--------------------------------------------------------------------------
|
|
SUBROUTINE fft_orbital_k (orbital, ibnd, nbnd,conserved)
|
|
!--------------------------------------------------------------------------
|
|
!
|
|
! OBM 110908
|
|
! This subroutine transforms the given orbital using fft and puts the result in psic
|
|
! Warning! In order to be fast, no checks on the supplied data are performed!
|
|
! orbital: the orbital to be transformed
|
|
! ibnd: band index
|
|
! nbnd: total number of bands
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE gvecs, ONLY : nls,nlsm,doublegrid
|
|
USE kinds, ONLY : DP
|
|
USE fft_base, ONLY : dffts
|
|
USE fft_interfaces,ONLY : invfft
|
|
USE mp_global, ONLY : me_pool
|
|
USE wvfct, ONLY : igk
|
|
|
|
IMPLICIT NONE
|
|
|
|
INTEGER, INTENT(in) :: ibnd,& ! Current index of the band currently being transformed
|
|
nbnd ! Total number of bands you want to transform
|
|
|
|
COMPLEX(DP),INTENT(in) :: orbital(:,:)
|
|
LOGICAL, OPTIONAL :: conserved !if this flag is true, the orbital is stored in temporary memory
|
|
|
|
! Internal variables
|
|
INTEGER :: j, ioff, idx
|
|
LOGICAL :: use_tg
|
|
|
|
CALL start_clock( 'fft_orbital' )
|
|
use_tg = dffts%have_task_groups
|
|
dffts%have_task_groups = ( dffts%have_task_groups ) .and. ( nbnd >= dffts%nogrp )
|
|
|
|
IF( dffts%have_task_groups ) THEN
|
|
!
|
|
tg_psic = ( 0.D0, 0.D0 )
|
|
ioff = 0
|
|
!
|
|
DO idx = 1, dffts%nogrp
|
|
!
|
|
IF( idx + ibnd - 1 <= nbnd ) THEN
|
|
!DO j = 1, size(orbital,1)
|
|
tg_psic( nls( igk(:) ) + ioff ) = orbital(:,idx+ibnd-1)
|
|
!END DO
|
|
ENDIF
|
|
|
|
ioff = ioff + dffts%tg_nnr
|
|
|
|
ENDDO
|
|
!
|
|
CALL invfft ('Wave', tg_psic, dffts)
|
|
IF (present(conserved)) THEN
|
|
IF (conserved .eqv. .true.) THEN
|
|
IF (.not. allocated(tg_psic_temp)) ALLOCATE( tg_psic_temp( dffts%tg_nnr * dffts%nogrp ) )
|
|
tg_psic_temp=tg_psic
|
|
ENDIF
|
|
ENDIF
|
|
!
|
|
ELSE !non task_groups version
|
|
!
|
|
psic(1:dffts%nnr) = ( 0.D0, 0.D0 )
|
|
!
|
|
psic(nls(igk(:))) = orbital(:,ibnd)
|
|
!
|
|
CALL invfft ('Wave', psic, dffts)
|
|
IF (present(conserved)) THEN
|
|
IF (conserved .eqv. .true.) THEN
|
|
IF (.not. allocated(psic_temp) ) ALLOCATE (psic_temp(size(psic)))
|
|
psic_temp=psic
|
|
ENDIF
|
|
ENDIF
|
|
!
|
|
ENDIF
|
|
dffts%have_task_groups = use_tg
|
|
CALL stop_clock( 'fft_orbital' )
|
|
END SUBROUTINE fft_orbital_k
|
|
!--------------------------------------------------------------------------
|
|
SUBROUTINE bfft_orbital_k (orbital, ibnd, nbnd,conserved)
|
|
!--------------------------------------------------------------------------
|
|
!
|
|
! OBM 110908
|
|
! This subroutine transforms the given orbital using fft and puts the result in psic
|
|
! Warning! In order to be fast, no checks on the supplied data are performed!
|
|
! orbital: the orbital to be transformed
|
|
! ibnd: band index
|
|
! nbnd: total number of bands
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE gvecs, ONLY : nls,nlsm,doublegrid
|
|
USE kinds, ONLY : DP
|
|
USE fft_base, ONLY : dffts
|
|
USE fft_interfaces,ONLY : fwfft
|
|
USE mp_global, ONLY : me_pool
|
|
USE wvfct, ONLY : igk
|
|
|
|
IMPLICIT NONE
|
|
|
|
INTEGER, INTENT(in) :: ibnd,& ! Current index of the band currently being transformed
|
|
nbnd ! Total number of bands you want to transform
|
|
|
|
COMPLEX(DP),INTENT(out) :: orbital(:,:)
|
|
LOGICAL, OPTIONAL :: conserved !if this flag is true, the orbital is stored in temporary memory
|
|
|
|
! Internal variables
|
|
INTEGER :: j, ioff, idx
|
|
LOGICAL :: use_tg
|
|
|
|
CALL start_clock( 'bfft_orbital' )
|
|
use_tg = dffts%have_task_groups
|
|
dffts%have_task_groups = ( dffts%have_task_groups ) .and. ( nbnd >= dffts%nogrp )
|
|
|
|
IF( dffts%have_task_groups ) THEN
|
|
!
|
|
CALL fwfft ('Wave', tg_psic, dffts)
|
|
!
|
|
ioff = 0
|
|
!
|
|
DO idx = 1, dffts%nogrp
|
|
!
|
|
IF( idx + ibnd - 1 <= nbnd ) THEN
|
|
orbital (:, ibnd+idx-1) = tg_psic( nls(igk(:)) + ioff )
|
|
ENDIF
|
|
!
|
|
ioff = ioff + dffts%nr3x * dffts%nsw( me_pool + 1 )
|
|
!
|
|
ENDDO
|
|
IF (present(conserved)) THEN
|
|
IF (conserved .eqv. .true.) THEN
|
|
IF (allocated(tg_psic_temp)) DEALLOCATE( tg_psic_temp )
|
|
ENDIF
|
|
ENDIF
|
|
!
|
|
ELSE !non task groups version
|
|
!
|
|
CALL fwfft ('Wave', psic, dffts)
|
|
!
|
|
orbital(:,ibnd) = psic(nls(igk(:)))
|
|
!
|
|
IF (present(conserved)) THEN
|
|
IF (conserved .eqv. .true.) THEN
|
|
IF (allocated(psic_temp) ) DEALLOCATE(psic_temp)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
dffts%have_task_groups = use_tg
|
|
CALL stop_clock( 'bfft_orbital' )
|
|
END SUBROUTINE bfft_orbital_k
|
|
!--------------------------------------------------------------------------
|
|
SUBROUTINE v_loc_psir (ibnd, nbnd)
|
|
!--------------------------------------------------------------------------
|
|
! Basically the same thing as v_loc but without implicit fft
|
|
! modified for real space implementation
|
|
! OBM 241008
|
|
!
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE gvecs, ONLY : nls,nlsm,doublegrid
|
|
USE kinds, ONLY : DP
|
|
USE fft_base, ONLY : dffts, tg_gather
|
|
USE mp_global, ONLY : me_pool
|
|
USE scf, ONLY : vrs
|
|
USE lsda_mod, ONLY : current_spin
|
|
|
|
|
|
IMPLICIT NONE
|
|
|
|
INTEGER, INTENT(in) :: ibnd,& ! Current index of the band currently being transformed
|
|
nbnd ! Total number of bands you want to transform
|
|
|
|
|
|
!Internal temporary variables
|
|
COMPLEX(DP) :: fp, fm
|
|
INTEGER :: i, j, incr, ierr, idx, ioff, nsiz
|
|
|
|
!Task groups
|
|
REAL(DP), ALLOCATABLE :: tg_v(:)
|
|
INTEGER :: recv_cnt( dffts%nogrp ), recv_displ( dffts%nogrp )
|
|
INTEGER :: v_siz
|
|
CALL start_clock( 'v_loc_psir' )
|
|
|
|
IF( dffts%have_task_groups .and. nbnd >= dffts%nogrp ) THEN
|
|
IF (ibnd == 1 ) THEN
|
|
CALL tg_gather( dffts, vrs(:,current_spin), tg_v ) !if ibnd==1 this is a new calculation, and tg_v should be distributed.
|
|
ENDIF
|
|
!
|
|
DO j = 1, dffts%nr1x*dffts%nr2x*dffts%tg_npp( me_pool + 1 )
|
|
tg_psic (j) = tg_psic (j) + tg_psic_temp (j) * tg_v(j)
|
|
ENDDO
|
|
!
|
|
DEALLOCATE( tg_v )
|
|
ELSE
|
|
! product with the potential v on the smooth grid
|
|
!
|
|
DO j = 1, dffts%nnr
|
|
psic (j) = psic (j) + psic_temp (j) * vrs(j,current_spin)
|
|
ENDDO
|
|
ENDIF
|
|
CALL stop_clock( 'v_loc_psir' )
|
|
END SUBROUTINE v_loc_psir
|
|
!--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
! NOW start the part added by GWW team
|
|
|
|
!
|
|
SUBROUTINE adduspos_gamma_r(iw,jw,r_ij,ik,becp_iw,becp_jw)
|
|
!----------------------------------------------------------------------
|
|
!
|
|
! This routine adds the US term < Psi_iw|r><r|Psi_jw>
|
|
! to the array r_ij
|
|
! this is a GAMMA only routine (i.e. r_ij is real)
|
|
!
|
|
USE kinds, ONLY : DP
|
|
USE ions_base, ONLY : nat, ntyp => nsp, ityp
|
|
USE grid_dimensions, ONLY : nrxx
|
|
USE gvect, ONLY : ngm, nl, nlm, gg, g
|
|
USE lsda_mod, ONLY : lsda, nspin, current_spin, isk
|
|
USE uspp, ONLY : okvan, becsum, nkb
|
|
USE uspp_param, ONLY : upf, lmaxq, nh
|
|
USE wvfct, ONLY : wg
|
|
USE control_flags, ONLY : gamma_only
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE io_global, ONLY : stdout
|
|
USE cell_base, ONLY : omega
|
|
!
|
|
USE mp_global, ONLY : intra_pool_comm
|
|
USE mp, ONLY : mp_sum
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
!
|
|
INTEGER, INTENT(in) :: iw,jw!the states indices
|
|
REAL(kind=DP), INTENT(inout) :: r_ij(nrxx)!where to add the us term
|
|
INTEGER, INTENT(in) :: ik!spin index for spin polarized calculations NOT IMPLEMENTED YET
|
|
REAL(kind=DP), INTENT(in) :: becp_iw( nkb)!overlap of wfcs with us projectors
|
|
REAL(kind=DP), INTENT(in) :: becp_jw( nkb)!overlap of wfcs with us projectors
|
|
|
|
! here the local variables
|
|
!
|
|
|
|
INTEGER :: na, nt, nhnt, ir, ih, jh, is , ia, mbia, irb, iqs, sizeqsave
|
|
INTEGER :: ikb, jkb, ijkb0, np
|
|
! counters
|
|
|
|
! work space for rho(G,nspin)
|
|
! Fourier transform of q
|
|
|
|
IF (.not.okvan) RETURN
|
|
IF( .not.gamma_only) THEN
|
|
WRITE(stdout,*) ' adduspos_gamma_r is a gamma ONLY routine'
|
|
STOP
|
|
ENDIF
|
|
|
|
ijkb0 = 0
|
|
DO is=1,nspin
|
|
!
|
|
DO np = 1, ntyp
|
|
!
|
|
iqs = 0
|
|
!
|
|
IF ( upf(np)%tvanp ) THEN
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
mbia = maxbox(ia)
|
|
nt = ityp(ia)
|
|
nhnt = nh(nt)
|
|
!
|
|
IF ( ityp(ia) /= np ) iqs=iqs+(nhnt+1)*nhnt*mbia/2
|
|
IF ( ityp(ia) /= np ) CYCLE
|
|
!
|
|
DO ih = 1, nhnt
|
|
!
|
|
ikb = ijkb0 + ih
|
|
!
|
|
DO jh = ih, nhnt
|
|
!
|
|
jkb = ijkb0 + jh
|
|
!
|
|
DO ir = 1, mbia
|
|
!
|
|
irb = box(ir,ia)
|
|
iqs = iqs + 1
|
|
!
|
|
r_ij(irb) = r_ij(irb) + qsave(iqs)*becp_iw(ikb)*becp_jw(jkb)*omega
|
|
!
|
|
IF ( ih /= jh ) THEN
|
|
r_ij(irb) = r_ij(irb) + qsave(iqs)*becp_iw(jkb)*becp_jw(ikb)*omega
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ijkb0 = ijkb0 + nhnt
|
|
!
|
|
ENDDO
|
|
!
|
|
ELSE
|
|
!
|
|
DO na = 1, nat
|
|
!
|
|
IF ( ityp(na) == np ) ijkb0 = ijkb0 + nh(np)
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE adduspos_gamma_r
|
|
!
|
|
SUBROUTINE adduspos_r(r_ij,becp_iw,becp_jw)
|
|
!----------------------------------------------------------------------
|
|
!
|
|
! This routine adds the US term < Psi_iw|r><r|Psi_jw>
|
|
! to the array r_ij
|
|
|
|
|
|
USE kinds, ONLY : DP
|
|
USE ions_base, ONLY : nat, ntyp => nsp, ityp
|
|
USE grid_dimensions, ONLY : nrxx
|
|
USE gvect, ONLY : ngm, nl, nlm, gg, g
|
|
USE lsda_mod, ONLY : lsda, nspin, current_spin, isk
|
|
USE uspp, ONLY : okvan, becsum, nkb
|
|
USE uspp_param, ONLY : upf, lmaxq, nh
|
|
USE wvfct, ONLY : wg
|
|
USE control_flags, ONLY : gamma_only
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE cell_base, ONLY : omega
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
COMPLEX(kind=DP), INTENT(inout) :: r_ij(nrxx)!where to add the us term
|
|
COMPLEX(kind=DP), INTENT(in) :: becp_iw( nkb)!overlap of wfcs with us projectors
|
|
COMPLEX(kind=DP), INTENT(in) :: becp_jw( nkb)!overlap of wfcs with us projectors
|
|
|
|
! here the local variables
|
|
!
|
|
INTEGER :: na, ia, nt, nhnt, ir, ih, jh, is, mbia, irb, iqs
|
|
INTEGER :: ikb, jkb, ijkb0, np
|
|
! counters
|
|
|
|
! work space for rho(G,nspin)
|
|
! Fourier transform of q
|
|
|
|
IF (.not.okvan) RETURN
|
|
|
|
ijkb0 = 0
|
|
DO is=1,nspin
|
|
!
|
|
DO np = 1, ntyp
|
|
!
|
|
iqs = 0
|
|
!
|
|
IF ( upf(np)%tvanp ) THEN
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
mbia = maxbox(ia)
|
|
nt = ityp(ia)
|
|
nhnt = nh(nt)
|
|
!
|
|
IF ( ityp(ia) /= np ) iqs=iqs+(nhnt+1)*nhnt*mbia/2
|
|
IF ( ityp(ia) /= np ) CYCLE
|
|
!
|
|
DO ih = 1, nhnt
|
|
!
|
|
ikb = ijkb0 + ih
|
|
DO jh = ih, nhnt
|
|
!
|
|
jkb = ijkb0 + jh
|
|
!
|
|
DO ir = 1, mbia
|
|
!
|
|
irb = box(ir,ia)
|
|
iqs = iqs + 1
|
|
!
|
|
r_ij(irb) = r_ij(irb) + qsave(iqs)*conjg(becp_iw(ikb))*becp_jw(jkb)*omega
|
|
!
|
|
IF ( ih /= jh ) THEN
|
|
r_ij(irb) = r_ij(irb) + qsave(iqs)*conjg(becp_iw(jkb))*becp_jw(ikb)*omega
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ijkb0 = ijkb0 + nhnt
|
|
!
|
|
ENDDO
|
|
!
|
|
ELSE
|
|
!
|
|
DO na = 1, nat
|
|
!
|
|
IF ( ityp(na) == np ) ijkb0 = ijkb0 + nh(np)
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
RETURN
|
|
END SUBROUTINE adduspos_r
|
|
!
|
|
SUBROUTINE adduspos_real(sca,qq_op,becp_iw,becp_jw)
|
|
!----------------------------------------------------------------------
|
|
!
|
|
! This routine adds the US term < Psi_iw|r><r|Psi_jw>
|
|
! to the array r_ij
|
|
|
|
|
|
USE kinds, ONLY : DP
|
|
USE ions_base, ONLY : nat, ntyp => nsp, ityp
|
|
USE gvect, ONLY : ngm, nl, nlm, gg, g
|
|
USE lsda_mod, ONLY : lsda, nspin, current_spin, isk
|
|
USE uspp, ONLY : okvan, becsum, nkb, qq
|
|
USE uspp_param, ONLY : upf, lmaxq, nh, nhm
|
|
USE wvfct, ONLY : wg
|
|
USE control_flags, ONLY : gamma_only
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE cell_base, ONLY : omega
|
|
!
|
|
USE mp_global, ONLY : intra_pool_comm
|
|
USE mp, ONLY : mp_sum
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
REAL(kind=DP), INTENT(inout) :: sca!where to add the us term
|
|
REAL(kind=DP), INTENT(in) :: becp_iw( nkb)!overlap of wfcs with us projectors
|
|
REAL(kind=DP), INTENT(in) :: becp_jw( nkb)!overlap of wfcs with us projectors
|
|
REAL(kind=DP), INTENT(in) :: qq_op(nhm, nhm,nat)!US augmentation charges
|
|
|
|
! here the local variables
|
|
!
|
|
|
|
INTEGER :: na, ia, nhnt, nt, ir, ih, jh, is, mbia
|
|
INTEGER :: ikb, jkb, ijkb0, np
|
|
! counters
|
|
|
|
! work space for rho(G,nspin)
|
|
! Fourier transform of q
|
|
|
|
IF (.not.okvan) RETURN
|
|
|
|
ijkb0 = 0
|
|
DO is=1,nspin
|
|
!
|
|
DO np = 1, ntyp
|
|
!
|
|
IF ( upf(np)%tvanp ) THEN
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
IF ( ityp(ia) /= np ) CYCLE
|
|
!
|
|
mbia = maxbox(ia)
|
|
nt = ityp(ia)
|
|
nhnt = nh(nt)
|
|
!
|
|
DO ih = 1, nhnt
|
|
!
|
|
ikb = ijkb0 + ih
|
|
DO jh = ih, nhnt
|
|
!
|
|
jkb = ijkb0 + jh
|
|
!
|
|
sca = sca + qq_op(ih,jh,ia) * becp_iw(ikb)*becp_jw(jkb)
|
|
!
|
|
IF ( ih /= jh ) THEN
|
|
sca = sca + qq_op(jh,ih,ia) * becp_iw(ikb)*becp_jw(jkb)
|
|
ENDIF
|
|
!
|
|
ENDDO
|
|
ENDDO
|
|
ijkb0 = ijkb0 + nhnt
|
|
!
|
|
ENDDO
|
|
!
|
|
ELSE
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
IF ( ityp(ia) == np ) ijkb0 = ijkb0 + nh(np)
|
|
!
|
|
ENDDO
|
|
!
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE adduspos_real
|
|
!
|
|
SUBROUTINE augmentation_qq(op,qq_op)
|
|
!----------------------------------------------------------------------
|
|
!
|
|
! this routine calculates the augmentaion charghe qq=\int q_ij(r)*op(r)
|
|
!
|
|
USE kinds, ONLY : DP
|
|
USE ions_base, ONLY : nat, ntyp => nsp, ityp
|
|
USE grid_dimensions, ONLY : nr1, nr2, nr3, nrxx
|
|
USE gvect, ONLY : ngm, nl, nlm, gg, g
|
|
USE lsda_mod, ONLY : lsda, nspin, current_spin, isk
|
|
USE uspp, ONLY : okvan, becsum, nkb, qq
|
|
USE uspp_param, ONLY : upf, lmaxq, nh, nhm
|
|
USE wvfct, ONLY : wg
|
|
USE control_flags, ONLY : gamma_only
|
|
USE wavefunctions_module, ONLY : psic
|
|
USE cell_base, ONLY : omega
|
|
! USE mp, ONLY : mp_sum
|
|
USE mp, ONLY : mp_sum
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER :: is, ia, nhnt, na, nt, ih, jh, ir, mbia, irb, iqs
|
|
REAL(kind=DP) :: sca
|
|
REAL(kind=DP), INTENT(out) :: qq_op(nhm, nhm,nat)!US augmentation charges to be calculated
|
|
REAL(kind=DP), INTENT(in) :: op(nrxx)!operator
|
|
|
|
qq_op(:,:,:)=0.d0
|
|
DO is=1,nspin
|
|
!
|
|
iqs = 0
|
|
!
|
|
DO ia = 1, nat
|
|
!
|
|
mbia = maxbox(ia)
|
|
!
|
|
nt = ityp(ia)
|
|
!
|
|
IF ( .not. upf(nt)%tvanp ) CYCLE
|
|
!
|
|
nhnt = nh(nt)
|
|
!
|
|
DO ih = 1, nhnt
|
|
!
|
|
DO jh = ih, nhnt
|
|
!
|
|
sca = 0.d0
|
|
DO ir = 1, mbia
|
|
!
|
|
irb = box(ir,ia)
|
|
iqs = iqs + 1
|
|
!
|
|
sca=sca+op(irb)*qsave(iqs)
|
|
ENDDO
|
|
!!!! call mp_sum(sca , intra_pool_comm)
|
|
CALL mp_sum(sca)
|
|
sca=sca/dble(nr1*nr2*nr3)
|
|
qq_op(ih,jh,ia)=sca
|
|
qq_op(jh,ih,ia)=sca
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE augmentation_qq
|
|
!
|
|
END MODULE realus
|