mirror of https://gitlab.com/QEF/q-e.git
2270 lines
92 KiB
Fortran
2270 lines
92 KiB
Fortran
!
|
|
! Copyright (C) 2007-2010 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 .
|
|
!
|
|
! NOTE ON PARALLELIZATION:
|
|
! this code is parallelized on atoms, i.e. each node computes potential, energy,
|
|
! newd coefficients, ddots and \int v \times n on a reduced number of atoms.
|
|
! The implementation assumes that divisions of atoms among the nodes is always
|
|
! done in the same way! By doing so we can avoid to allocate the potential for
|
|
! all the atoms on all the nodes, and (most important) we don't need to
|
|
! distribute the potential among the nodes after computing it.
|
|
!
|
|
MODULE paw_onecenter
|
|
!
|
|
USE kinds, ONLY : DP
|
|
USE paw_variables, ONLY : paw_info, rad, radial_grad_style, vs_rad
|
|
USE mp_global, ONLY : nproc_image, me_image, intra_image_comm
|
|
USE mp, ONLY : mp_sum
|
|
!
|
|
IMPLICIT NONE
|
|
|
|
! entry points:
|
|
PUBLIC :: PAW_potential ! prepare paw potential and store it,
|
|
! also computes energy if required
|
|
PUBLIC :: PAW_ddot ! error estimate for mix_rho
|
|
PUBLIC :: PAW_dpotential ! calculate change of the paw potential
|
|
! and derivatives of D^1-~D^1 coefficients
|
|
PUBLIC :: PAW_rho_lm ! uses becsum to generate one-center charges
|
|
! (all-electron and pseudo) on radial grid
|
|
!
|
|
INTEGER, SAVE :: paw_comm, me_paw, nproc_paw
|
|
!
|
|
INTEGER, SAVE :: nx_loc, ix_s, ix_e ! parallelization on the directions
|
|
!
|
|
PRIVATE
|
|
|
|
REAL(DP), ALLOCATABLE :: msmall_lm(:,:,:) ! magnetiz. due to small
|
|
! components expanded on Y_lm
|
|
REAL(DP), ALLOCATABLE :: g_lm(:,:,:) ! potential density as lm components
|
|
!
|
|
LOGICAL :: with_small_so = .FALSE.
|
|
!
|
|
! the following macro controls the use of several fine-grained clocks
|
|
! set it to 'if(.false.) CALL' (without quotes) in order to disable them,
|
|
! set it to 'CALL' to enable them.
|
|
!
|
|
LOGICAL, PARAMETER :: TIMING = .false.
|
|
!
|
|
INTEGER, EXTERNAL :: ldim_block
|
|
INTEGER, EXTERNAL :: gind_block
|
|
|
|
CONTAINS
|
|
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! Computes V_h and V_xc using the "density" becsum provided and then
|
|
!!!
|
|
!!! Update the descreening coefficients:
|
|
!!! D_ij = \int v_Hxc p_ij - \int vt_Hxc (pt_ij + augfun_ij)
|
|
!!!
|
|
!!! calculate the onecenter contribution to the energy
|
|
!!!
|
|
SUBROUTINE PAW_potential(becsum, d, energy, e_cmp)
|
|
USE atom, ONLY : g => rgrid
|
|
USE ions_base, ONLY : nat, ityp
|
|
USE lsda_mod, ONLY : nspin
|
|
USE uspp_param, ONLY : nh, nhm, upf
|
|
USE noncollin_module, ONLY : nspin_lsda, nspin_mag
|
|
USE mp, ONLY : mp_barrier, mp_comm_split, mp_comm_free, mp_size, mp_rank
|
|
|
|
REAL(DP), INTENT(IN) :: becsum(nhm*(nhm+1)/2,nat,nspin)! cross band occupations
|
|
REAL(DP), INTENT(OUT) :: d(nhm*(nhm+1)/2,nat,nspin) ! descreening coefficients (AE - PS)
|
|
REAL(DP), INTENT(OUT), OPTIONAL :: energy ! if present compute E[rho]
|
|
REAL(DP), INTENT(OUT), OPTIONAL :: e_cmp(nat, 2, 2) ! components of the energy
|
|
! {AE!PS}
|
|
INTEGER, PARAMETER :: AE = 1, PS = 2,& ! All-Electron and Pseudo
|
|
XC = 1, H = 2 ! XC and Hartree
|
|
REAL(DP), POINTER :: rho_core(:) ! pointer to AE/PS core charge density
|
|
TYPE(paw_info) :: i ! minimal info on atoms
|
|
INTEGER :: i_what ! counter on AE and PS
|
|
INTEGER :: is ! spin index
|
|
INTEGER :: lm ! counters on angmom and radial grid
|
|
INTEGER :: nb, mb, nmb ! augfun indexes
|
|
INTEGER :: ia,ia_s,ia_e ! atoms counters and indexes
|
|
INTEGER :: mykey ! my index in the atom group
|
|
INTEGER :: j, l2, kkbeta, imesh
|
|
!
|
|
REAL(DP), ALLOCATABLE :: v_lm(:,:,:) ! workspace: potential
|
|
REAL(DP), ALLOCATABLE :: rho_lm(:,:,:) ! density expanded on Y_lm
|
|
REAL(DP), ALLOCATABLE :: savedv_lm(:,:,:) ! workspace: potential
|
|
! fake cross band occupations to select only one pfunc at a time:
|
|
REAL(DP) :: becfake(nhm*(nhm+1)/2,nat,nspin)
|
|
REAL(DP) :: integral ! workspace
|
|
REAL(DP) :: energy_xc, energy_h, energy_tot
|
|
REAL(DP) :: sgn ! +1 for AE -1 for PS
|
|
|
|
CALL start_clock('PAW_pot')
|
|
! Some initialization
|
|
becfake(:,:,:) = 0._dp
|
|
d(:,:,:) = 0._dp
|
|
energy_tot = 0._dp
|
|
!
|
|
!
|
|
! Parallel: divide tasks among all the processor for this image
|
|
! (i.e. all the processors except for NEB and similar)
|
|
!
|
|
CALL block_distribute( nat, me_image, nproc_image, ia_s, ia_e, mykey )
|
|
!
|
|
! build the group of all the procs associated with the same atom
|
|
!
|
|
CALL mp_comm_split( intra_image_comm, ia_s - 1, me_image, paw_comm )
|
|
!
|
|
me_paw = mp_rank( paw_comm )
|
|
nproc_paw = mp_size( paw_comm )
|
|
|
|
!
|
|
atoms: DO ia = ia_s, ia_e
|
|
!
|
|
i%a = ia ! atom's index
|
|
i%t = ityp(ia) ! type of atom ia
|
|
i%m = g(i%t)%mesh ! radial mesh size for atom i%t
|
|
i%b = upf(i%t)%nbeta ! number of beta functions for i%t
|
|
i%l = upf(i%t)%lmax_rho+1 ! max ang.mom. in augmentation for ia
|
|
l2 = i%l**2
|
|
kkbeta = upf(i%t)%kkbeta
|
|
imesh = i%m
|
|
!
|
|
ifpaw: IF (upf(i%t)%tpawp) THEN
|
|
!
|
|
! parallelization over the direction. Here each processor chooses
|
|
! its directions
|
|
!
|
|
nx_loc = ldim_block( rad(i%t)%nx, nproc_paw, me_paw )
|
|
ix_s = gind_block( 1, rad(i%t)%nx, nproc_paw, me_paw )
|
|
ix_e = ix_s + nx_loc - 1
|
|
!
|
|
! Arrays are allocated inside the cycle to allow reduced
|
|
! memory usage as different atoms have different meshes
|
|
ALLOCATE(v_lm(i%m,l2,nspin))
|
|
ALLOCATE(savedv_lm(i%m,l2,nspin))
|
|
ALLOCATE(rho_lm(i%m,l2,nspin))
|
|
!
|
|
!
|
|
whattodo: DO i_what = AE, PS
|
|
! STEP: 1 [ build rho_lm (PAW_rho_lm) ]
|
|
i%ae=i_what
|
|
NULLIFY(rho_core)
|
|
IF (i_what == AE) THEN
|
|
! Compute rho spherical harmonics expansion from becsum and pfunc
|
|
CALL PAW_rho_lm(i, becsum, upf(i%t)%paw%pfunc, rho_lm)
|
|
with_small_so=upf(i%t)%has_so.AND.nspin_mag==4
|
|
IF (with_small_so) THEN
|
|
ALLOCATE(msmall_lm(i%m,l2,nspin))
|
|
ALLOCATE(g_lm(i%m,l2,nspin))
|
|
CALL PAW_rho_lm(i, becsum, upf(i%t)%paw%pfunc_rel, msmall_lm)
|
|
ENDIF
|
|
! used later for xc potential:
|
|
rho_core => upf(i%t)%paw%ae_rho_atc
|
|
! sign to sum up the enrgy
|
|
sgn = +1._dp
|
|
ELSE
|
|
CALL PAW_rho_lm(i, becsum, upf(i%t)%paw%ptfunc, rho_lm, upf(i%t)%qfuncl)
|
|
! optional argument for pseudo part (aug. charge) --> ^^^
|
|
rho_core => upf(i%t)%rho_atc ! as before
|
|
sgn = -1._dp ! as before
|
|
with_small_so=.FALSE.
|
|
ENDIF
|
|
! cleanup auxiliary potentials
|
|
savedv_lm(:,:,:) = 0._dp
|
|
|
|
! First compute the Hartree potential (it does not depend on spin...):
|
|
CALL PAW_h_potential(i, rho_lm, v_lm(:,:,1), energy)
|
|
!
|
|
!
|
|
! NOTE: optional variables works recursively: e.g. if energy is not present here
|
|
! it will not be present in PAW_h_potential too!
|
|
!IF (present(energy)) write(*,*) 'H',i%a,i_what,sgn*energy
|
|
IF (present(energy) .AND. mykey == 0 ) energy_tot = energy_tot + sgn*energy
|
|
IF (present(e_cmp) .AND. mykey == 0 ) e_cmp(ia, H, i_what) = energy
|
|
DO is = 1,nspin_lsda ! ... v_H has to be copied to all spin components
|
|
savedv_lm(:,:,is) = v_lm(:,:,1)
|
|
ENDDO
|
|
|
|
|
|
! Then the XC one:
|
|
CALL PAW_xc_potential(i, rho_lm, rho_core, v_lm, energy)
|
|
!IF (present(energy)) write(*,*) 'X',i%a,i_what,sgn*energy
|
|
IF (present(energy) .AND. mykey == 0 ) energy_tot = energy_tot + sgn*energy
|
|
IF (present(e_cmp) .AND. mykey == 0 ) e_cmp(ia, XC, i_what) = energy
|
|
savedv_lm(:,:,:) = savedv_lm(:,:,:) + v_lm(:,:,:)
|
|
!
|
|
spins: DO is = 1, nspin_mag
|
|
nmb = 0
|
|
! loop on all pfunc for this kind of pseudo
|
|
DO nb = 1, nh(i%t)
|
|
DO mb = nb, nh(i%t)
|
|
nmb = nmb+1 ! nmb = 1, nh*(nh+1)/2
|
|
!
|
|
! compute the density from a single pfunc
|
|
becfake(nmb,ia,is) = 1._dp
|
|
IF (i_what == AE) THEN
|
|
CALL PAW_rho_lm(i, becfake, upf(i%t)%paw%pfunc, rho_lm)
|
|
IF (with_small_so) &
|
|
CALL PAW_rho_lm(i, becfake, upf(i%t)%paw%pfunc_rel, &
|
|
msmall_lm)
|
|
ELSE
|
|
CALL PAW_rho_lm(i, becfake, upf(i%t)%paw%ptfunc, rho_lm, upf(i%t)%qfuncl)
|
|
! optional argument for pseudo part --> ^^^
|
|
ENDIF
|
|
!
|
|
! Now I multiply the rho_lm and the potential, I can use
|
|
! rho_lm itself as workspace
|
|
DO lm = 1, l2
|
|
DO j = 1, imesh
|
|
rho_lm(j,lm,is) = rho_lm(j,lm,is) * savedv_lm(j,lm,is)
|
|
END DO
|
|
! Integrate!
|
|
CALL simpson(kkbeta,rho_lm(1,lm,is),g(i%t)%rab(1),&
|
|
integral)
|
|
d(nmb,i%a,is) = d(nmb,i%a,is) + sgn * integral
|
|
IF (is>1.and.with_small_so.AND.i_what== AE ) THEN
|
|
DO j=1, imesh
|
|
msmall_lm(j,lm,is)=msmall_lm(j,lm,is)*&
|
|
g_lm(j,lm,is)
|
|
ENDDO
|
|
CALL simpson(kkbeta,msmall_lm(1,lm,is),&
|
|
g(i%t)%rab(1), integral)
|
|
d(nmb,i%a,is) = d(nmb,i%a,is) + sgn * integral
|
|
ENDIF
|
|
ENDDO
|
|
! restore becfake to zero
|
|
becfake(nmb,ia,is) = 0._dp
|
|
ENDDO ! mb
|
|
ENDDO ! nb
|
|
ENDDO spins
|
|
IF (with_small_so) THEN
|
|
DEALLOCATE ( msmall_lm )
|
|
DEALLOCATE ( g_lm )
|
|
END IF
|
|
ENDDO whattodo
|
|
! cleanup
|
|
DEALLOCATE(rho_lm)
|
|
DEALLOCATE(savedv_lm)
|
|
DEALLOCATE(v_lm)
|
|
!
|
|
ENDIF ifpaw
|
|
ENDDO atoms
|
|
#ifdef __PARA
|
|
! recollect D coeffs and total one-center energy
|
|
IF( mykey /= 0 ) energy_tot = 0.0d0
|
|
CALL mp_sum(energy_tot, intra_image_comm)
|
|
IF( mykey /= 0 ) d = 0.0d0
|
|
CALL mp_sum(d, intra_image_comm)
|
|
#endif
|
|
! put energy back in the output variable
|
|
IF ( present(energy) ) energy = energy_tot
|
|
!
|
|
CALL mp_comm_free( paw_comm )
|
|
!
|
|
CALL stop_clock('PAW_pot')
|
|
|
|
END SUBROUTINE PAW_potential
|
|
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! As rho_ddot in mix_rho for radial grids
|
|
!!
|
|
FUNCTION PAW_ddot(bec1,bec2)
|
|
USE constants, ONLY : pi
|
|
USE noncollin_module, ONLY : nspin_lsda
|
|
USE lsda_mod, ONLY : nspin
|
|
USE ions_base, ONLY : nat, ityp
|
|
USE atom, ONLY : g => rgrid
|
|
USE uspp_param, ONLY : nhm, upf
|
|
|
|
REAL(DP) :: PAW_ddot
|
|
|
|
REAL(DP), INTENT(IN) :: &
|
|
bec1(nhm*(nhm+1)/2,nat,nspin), &! cross band occupations (previous step)
|
|
bec2(nhm*(nhm+1)/2,nat,nspin) ! cross band occupations (next step)
|
|
|
|
INTEGER, PARAMETER :: AE = 1, PS = 2 ! All-Electron and Pseudo
|
|
INTEGER :: i_what ! counter on AE and PS
|
|
INTEGER :: ia,mykey,ia_s,ia_e
|
|
! atoms counters and indexes
|
|
INTEGER :: lm,k ! counters on angmom and radial grid
|
|
|
|
! hartree energy scalar fields expanded on Y_lm
|
|
REAL(DP), ALLOCATABLE :: rho_lm(:,:,:) ! radial density expanded on Y_lm
|
|
REAL(DP), ALLOCATABLE :: v_lm(:,:) ! hartree potential, summed on spins (from bec1)
|
|
!
|
|
REAL(DP) :: i_sign ! +1 for AE, -1 for PS
|
|
REAL(DP) :: integral ! workspace
|
|
TYPE(paw_info) :: i
|
|
|
|
CALL start_clock ('PAW_ddot')
|
|
! initialize
|
|
PAW_ddot = 0._dp
|
|
|
|
! Parallel: divide among processors for the same image
|
|
CALL block_distribute( nat, me_image, nproc_image, ia_s, ia_e, mykey )
|
|
!
|
|
atoms: DO ia = ia_s, ia_e
|
|
!
|
|
i%a = ia ! the index of the atom
|
|
i%t = ityp(ia) ! the type of atom ia
|
|
i%m = g(i%t)%mesh ! radial mesh size for atom ia
|
|
i%b = upf(i%t)%nbeta
|
|
i%l = upf(i%t)%lmax_rho+1
|
|
!
|
|
ifpaw: IF (upf(i%t)%tpawp) THEN
|
|
!
|
|
ALLOCATE(rho_lm(i%m,i%l**2,nspin))
|
|
ALLOCATE(v_lm(i%m,i%l**2))
|
|
!
|
|
whattodo: DO i_what = AE, PS
|
|
! Build rho from the occupations in bec1
|
|
IF (i_what == AE) THEN
|
|
CALL PAW_rho_lm(i, bec1, upf(i%t)%paw%pfunc, rho_lm)
|
|
i_sign = +1._dp
|
|
ELSE
|
|
CALL PAW_rho_lm(i, bec1, upf(i%t)%paw%ptfunc, rho_lm, upf(i%t)%qfuncl)
|
|
i_sign = -1._dp
|
|
ENDIF
|
|
!
|
|
! Compute the hartree potential from bec1
|
|
CALL PAW_h_potential(i, rho_lm, v_lm)
|
|
!
|
|
! Now a new rho is computed, this time from bec2
|
|
IF (i_what == AE) THEN
|
|
CALL PAW_rho_lm(i, bec2, upf(i%t)%paw%pfunc, rho_lm)
|
|
ELSE
|
|
CALL PAW_rho_lm(i, bec2, upf(i%t)%paw%ptfunc, rho_lm, upf(i%t)%qfuncl)
|
|
ENDIF
|
|
!
|
|
! Finally compute the integral
|
|
DO lm = 1, i%l**2
|
|
! I can use v_lm as workspace
|
|
DO k = 1, i%m
|
|
v_lm(k,lm) = v_lm(k,lm) * SUM(rho_lm(k,lm,1:nspin_lsda))
|
|
ENDDO
|
|
CALL simpson (upf(i%t)%kkbeta,v_lm(:,lm),g(i%t)%rab,integral)
|
|
!
|
|
! Sum all the energies in PAW_ddot
|
|
PAW_ddot = PAW_ddot + i_sign * integral * 0.5_DP
|
|
!
|
|
ENDDO
|
|
ENDDO whattodo
|
|
!
|
|
DEALLOCATE(v_lm)
|
|
DEALLOCATE(rho_lm)
|
|
!
|
|
ENDIF ifpaw
|
|
ENDDO atoms
|
|
|
|
#ifdef __PARA
|
|
IF( mykey /= 0 ) PAW_ddot = 0.0_dp
|
|
CALL mp_sum(PAW_ddot, intra_image_comm)
|
|
#endif
|
|
|
|
CALL stop_clock ('PAW_ddot')
|
|
|
|
|
|
END FUNCTION PAW_ddot
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! use the density produced by sum_rad_rho to compute xc potential and energy, as
|
|
!!! xc functional is not diagonal on angular momentum numerical integration is performed
|
|
SUBROUTINE PAW_xc_potential(i, rho_lm, rho_core, v_lm, energy)
|
|
USE noncollin_module, ONLY : nspin_mag
|
|
USE constants, ONLY : e2, eps12
|
|
USE uspp_param, ONLY : upf
|
|
USE lsda_mod, ONLY : nspin
|
|
USE atom, ONLY : g => rgrid
|
|
USE funct, ONLY : dft_is_gradient, evxc_t_vec, xc_spin
|
|
USE constants, ONLY : fpi ! REMOVE
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
REAL(DP), INTENT(IN) :: rho_lm(i%m,i%l**2,nspin)! charge density as lm components
|
|
REAL(DP), INTENT(IN) :: rho_core(i%m) ! core charge, radial and spherical
|
|
REAL(DP), INTENT(OUT) :: v_lm(i%m,i%l**2,nspin) ! potential density as lm components
|
|
REAL(DP),OPTIONAL,INTENT(OUT) :: energy ! XC energy (if required)
|
|
!
|
|
REAL(DP), ALLOCATABLE :: rho_loc(:,:) ! local density (workspace), up and down
|
|
REAL(DP) :: v_rad(i%m,rad(i%t)%nx,nspin) ! radial potential (to be integrated)
|
|
REAL(DP), ALLOCATABLE :: g_rad(:,:,:) ! radial potential
|
|
|
|
REAL(DP), ALLOCATABLE :: rho_rad(:,:) ! workspace (only one radial slice of rho)
|
|
!
|
|
REAL(DP), ALLOCATABLE :: msmall_rad(:,:) ! workspace
|
|
REAL(DP) :: hatr(3) ! aux, used to integrate energy
|
|
|
|
REAL(DP), ALLOCATABLE :: e_rad(:) ! aux, used to store radial slices of energy
|
|
REAL(DP), ALLOCATABLE :: e_of_tid(:) ! aux, for openmp parallel reduce
|
|
REAL(DP) :: e ! aux, used to integrate energy
|
|
!
|
|
INTEGER :: ix,k ! counters on directions and radial grid
|
|
INTEGER :: lsd ! switch for local spin density
|
|
|
|
REAL(DP) :: exc_ret, stmp
|
|
!
|
|
REAL(DP) :: arho, amag, zeta, ex, ec, vx(2), vc(2), vs
|
|
!
|
|
INTEGER :: ipol, kpol
|
|
|
|
INTEGER :: mytid, ntids
|
|
|
|
#ifdef __OPENMP
|
|
INTEGER, EXTERNAL :: omp_get_thread_num, omp_get_num_threads
|
|
#endif
|
|
|
|
if(TIMING) CALL start_clock ('PAW_xc_pot')
|
|
!
|
|
! true if using spin
|
|
lsd = 0
|
|
IF (nspin==2) lsd=1
|
|
!
|
|
!$omp parallel default(private), &
|
|
!$omp shared(i,rad,v_lm,rho_lm,rho_core,v_rad,ix_s,ix_e,energy,e_of_tid,nspin,g,lsd)
|
|
#ifdef __OPENMP
|
|
mytid = omp_get_thread_num()+1 ! take the thread ID
|
|
ntids = omp_get_num_threads() ! take the number of threads
|
|
#else
|
|
mytid = 1
|
|
ntids = 1
|
|
#endif
|
|
! This will hold the "true" charge density, without r**2 or other factors
|
|
ALLOCATE( rho_loc(i%m,nspin_mag) )
|
|
rho_loc = 0._dp
|
|
!
|
|
ALLOCATE( rho_rad(i%m,nspin_mag) )
|
|
IF (with_small_so) THEN
|
|
ALLOCATE(g_rad(i%m,rad(i%t)%nx,nspin))
|
|
g_rad = 0.0_DP
|
|
ENDIF
|
|
!
|
|
IF (present(energy)) THEN
|
|
!$omp single
|
|
energy = 0._dp
|
|
ALLOCATE(e_of_tid(ntids))
|
|
!$omp end single
|
|
ALLOCATE(e_rad(i%m))
|
|
e_of_tid(mytid) = 0._dp
|
|
ENDIF
|
|
!$omp workshare
|
|
v_rad = 0.0_dp
|
|
!!!not really needed IF (with_small_so) g_rad = 0.0_DP
|
|
!$omp end workshare
|
|
!$omp do
|
|
DO ix = ix_s, ix_e
|
|
!
|
|
! *** LDA (and LSDA) part (no gradient correction) ***
|
|
! convert _lm density to real density along ix
|
|
!
|
|
CALL PAW_lm2rad(i, ix, rho_lm, rho_rad, nspin_mag)
|
|
!
|
|
! compute the potential along ix
|
|
!
|
|
IF ( nspin_mag ==4 ) THEN
|
|
IF (with_small_so.AND.i%ae==1) CALL add_small_mag(i,ix,rho_rad)
|
|
DO k=1,i%m
|
|
rho_loc(k,1:nspin) = rho_rad(k,1:nspin)*g(i%t)%rm2(k)
|
|
arho = rho_loc(k,1)+rho_core(k)
|
|
amag = SQRT(rho_loc(k,2)**2+rho_loc(k,3)**2+rho_loc(k,4)**2)
|
|
arho = ABS( arho )
|
|
IF ( arho > eps12 ) THEN
|
|
zeta = amag / arho
|
|
IF ( ABS( zeta ) > 1.D0 ) zeta = SIGN( 1.D0, zeta )
|
|
CALL xc_spin( arho, zeta, ex, ec, vx(1), vx(2), vc(1), vc(2) )
|
|
IF (present(energy)) &
|
|
e_rad(k) = e2*(ex+ec)*(rho_rad(k,1)+rho_core(k)*g(i%t)%r2(k))
|
|
vs = e2*0.5D0*( vx(1) + vc(1) - vx(2) - vc(2) )
|
|
v_rad(k,ix,1) = e2*(0.5D0*( vx(1) + vc(1) + vx(2) + vc(2)))
|
|
IF ( amag > eps12 ) THEN
|
|
v_rad(k,ix,2:4) = vs * rho_loc(k,2:4) / amag
|
|
ELSE
|
|
v_rad(k,ix,2:4)=0.0_DP
|
|
ENDIF
|
|
ELSE
|
|
v_rad(k,ix,:)=0.0_DP
|
|
IF (present(energy)) e_rad(k)=0.0_DP
|
|
END IF
|
|
END DO
|
|
IF (with_small_so) CALL compute_g(i,ix,v_rad,g_rad)
|
|
ELSEIF (nspin==2) THEN
|
|
DO k = 1,i%m
|
|
rho_loc(k,1) = rho_rad(k,1)*g(i%t)%rm2(k)
|
|
rho_loc(k,2) = rho_rad(k,2)*g(i%t)%rm2(k)
|
|
ENDDO
|
|
ELSE
|
|
DO k = 1,i%m
|
|
rho_loc(k,1) = rho_rad(k,1)*g(i%t)%rm2(k)
|
|
ENDDO
|
|
END IF
|
|
!
|
|
! Integrate to obtain the energy
|
|
!
|
|
IF (present(energy)) THEN
|
|
IF (nspin_mag <= 2 ) THEN
|
|
CALL evxc_t_vec(rho_loc, rho_core, lsd, i%m, v_rad(:,ix,:), e_rad)
|
|
IF ( nspin_mag < 2 ) THEN
|
|
e_rad = e_rad * ( rho_rad(:,1) + rho_core*g(i%t)%r2 )
|
|
ELSE IF (nspin_mag == 2) THEN
|
|
e_rad = e_rad *(rho_rad(:,1)+rho_rad(:,2)+rho_core*g(i%t)%r2 )
|
|
END IF
|
|
END IF
|
|
! Integrate to obtain the energy
|
|
CALL simpson(i%m, e_rad, g(i%t)%rab, e)
|
|
e_of_tid(mytid) = e_of_tid(mytid) + e * rad(i%t)%ww(ix)
|
|
ELSE
|
|
IF (nspin_mag <= 2) &
|
|
CALL evxc_t_vec(rho_loc, rho_core, lsd, i%m, v_rad(:,ix,:))
|
|
ENDIF
|
|
ENDDO
|
|
!$omp end do nowait
|
|
|
|
IF(present(energy)) DEALLOCATE(e_rad)
|
|
|
|
DEALLOCATE( rho_rad )
|
|
DEALLOCATE( rho_loc )
|
|
|
|
!$omp end parallel
|
|
|
|
IF(present(energy)) THEN
|
|
energy = sum(e_of_tid)
|
|
DEALLOCATE(e_of_tid)
|
|
CALL mp_sum( energy, paw_comm )
|
|
END IF
|
|
|
|
! Recompose the sph. harm. expansion
|
|
CALL PAW_rad2lm(i, v_rad, v_lm, i%l, nspin_mag)
|
|
IF (with_small_so) THEN
|
|
CALL PAW_rad2lm(i, g_rad, g_lm, i%l, nspin_mag)
|
|
DEALLOCATE( g_rad )
|
|
END IF
|
|
|
|
! Add gradient correction, if necessary
|
|
IF( dft_is_gradient() ) &
|
|
CALL PAW_gcxc_potential( i, rho_lm, rho_core, v_lm, energy )
|
|
|
|
if(TIMING) CALL stop_clock ('PAW_xc_pot')
|
|
RETURN
|
|
|
|
END SUBROUTINE PAW_xc_potential
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! add gradient correction to v_xc, code mostly adapted from ../atomic/vxcgc.f90
|
|
!!! in order to support non-spherical charges (as Y_lm expansion)
|
|
!!! Note that the first derivative in vxcgc becames a gradient, while the second is a divergence.
|
|
!!! We also have to temporary store some additional Y_lm components in order not to loose
|
|
!!! precision during the calculation, even if only the ones up to lmax_rho (the maximum in the
|
|
!!! density of charge) matter when computing \int v * rho
|
|
SUBROUTINE PAW_gcxc_potential(i, rho_lm,rho_core, v_lm, energy)
|
|
USE lsda_mod, ONLY : nspin
|
|
USE noncollin_module, ONLY : noncolin, nspin_mag, nspin_gga
|
|
USE atom, ONLY : g => rgrid
|
|
USE constants, ONLY : sqrtpi, fpi,pi,e2, eps => eps12, eps2 => eps24
|
|
USE funct, ONLY : gcxc, gcx_spin_vec, gcc_spin, gcx_spin
|
|
USE mp, ONLY : mp_sum
|
|
!
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
REAL(DP), INTENT(IN) :: rho_lm(i%m,i%l**2,nspin) ! charge density as lm components
|
|
REAL(DP), INTENT(IN) :: rho_core(i%m) ! core charge, radial and spherical
|
|
REAL(DP), INTENT(INOUT) :: v_lm(i%m,i%l**2,nspin) ! potential to be updated
|
|
REAL(DP),OPTIONAL,INTENT(INOUT) :: energy ! if present, add GC to energy
|
|
|
|
REAL(DP),ALLOCATABLE :: rho_rad(:,:)! charge density sampled
|
|
REAL(DP),ALLOCATABLE :: grad(:,:,:) ! gradient
|
|
REAL(DP),ALLOCATABLE :: grad2(:,:) ! square modulus of gradient
|
|
! (first of charge, than of hamiltonian)
|
|
REAL(DP),ALLOCATABLE :: gc_rad(:,:,:) ! GC correction to V (radial samples)
|
|
REAL(DP),ALLOCATABLE :: gc_lm(:,:,:) ! GC correction to V (Y_lm expansion)
|
|
REAL(DP),ALLOCATABLE :: h_rad(:,:,:,:)! hamiltonian (vector field)
|
|
REAL(DP),ALLOCATABLE :: h_lm(:,:,:,:)! hamiltonian (vector field)
|
|
!!! ^^^^^^^^^^^^^^^^^^ expanded to higher lm than rho !!!
|
|
REAL(DP),ALLOCATABLE :: div_h(:,:,:) ! div(hamiltonian)
|
|
|
|
REAL(DP), ALLOCATABLE :: rhoout_lm(:,:,:) ! charge density as lm components
|
|
REAL(DP), ALLOCATABLE :: vout_lm(:,:,:) ! potential as lm components
|
|
REAL(DP), ALLOCATABLE :: segni_rad(:,:) ! sign of the magnetization
|
|
|
|
REAL(DP),ALLOCATABLE :: e_rad(:) ! aux, used to store energy
|
|
REAL(DP) :: e, e_gcxc ! aux, used to integrate energy
|
|
|
|
INTEGER :: k, ix, is, lm ! counters on spin and mesh
|
|
REAL(DP) :: sx,sc,v1x,v2x,v1c,v2c ! workspace
|
|
REAL(DP) :: v1xup, v1xdw, v2xup, v2xdw, v1cup, v1cdw ! workspace
|
|
REAL(DP) :: sgn, arho ! workspace
|
|
REAL(DP) :: rup, rdw, co2 ! workspace
|
|
REAL(DP) :: rh, zeta, grh2
|
|
REAL(DP), ALLOCATABLE :: rup_vec(:), rdw_vec(:)
|
|
REAL(DP), ALLOCATABLE :: sx_vec(:)
|
|
REAL(DP), ALLOCATABLE :: v1xup_vec(:), v1xdw_vec(:)
|
|
REAL(DP), ALLOCATABLE :: v2xup_vec(:), v2xdw_vec(:)
|
|
|
|
|
|
INTEGER :: mytid, ntids
|
|
#ifdef __OPENMP
|
|
INTEGER, EXTERNAL :: omp_get_thread_num, omp_get_num_threads
|
|
#endif
|
|
REAL(DP),ALLOCATABLE :: egcxc_of_tid(:)
|
|
|
|
|
|
if(TIMING) CALL start_clock ('PAW_gcxc_v')
|
|
|
|
|
|
e_gcxc = 0._dp
|
|
|
|
ALLOCATE( gc_rad(i%m,rad(i%t)%nx,nspin_gga) )! GC correction to V (radial samples)
|
|
ALLOCATE( gc_lm(i%m,i%l**2,nspin_gga) )! GC correction to V (Y_lm expansion)
|
|
ALLOCATE( h_rad(i%m,3,rad(i%t)%nx,nspin_gga))! hamiltonian (vector field)
|
|
ALLOCATE( h_lm(i%m,3,(i%l+rad(i%t)%ladd)**2,nspin_gga) )
|
|
!!! ^^^^^^^^^^^^^^^^^^ expanded to higher lm than rho !!!
|
|
ALLOCATE(div_h(i%m,i%l**2,nspin_gga))
|
|
ALLOCATE(rhoout_lm(i%m,i%l**2,nspin_gga)) ! charge density as lm components
|
|
ALLOCATE(vout_lm(i%m,i%l**2,nspin_gga)) ! potential as lm components
|
|
ALLOCATE(segni_rad(i%m,rad(i%t)%nx)) ! charge density as lm components
|
|
vout_lm=0.0_DP
|
|
|
|
!$omp parallel default(private) &
|
|
!$omp& shared(i,g,nspin,rad,e_gcxc,egcxc_of_tid,gc_rad,h_rad,rho_lm,rho_core,energy,ix_s,ix_e)
|
|
mytid = 1
|
|
ntids = 1
|
|
#ifdef __OPENMP
|
|
mytid = omp_get_thread_num()+1 ! take the thread ID
|
|
ntids = omp_get_num_threads() ! take the number of threads
|
|
#endif
|
|
ALLOCATE( rho_rad(i%m,nspin_gga))! charge density sampled
|
|
ALLOCATE( grad(i%m,3,nspin_gga) )! gradient
|
|
ALLOCATE( grad2(i%m,nspin_gga) )! square modulus of gradient
|
|
! (first of charge, than of hamiltonian)
|
|
!$omp workshare
|
|
gc_rad = 0.0d0
|
|
h_rad = 0.0d0
|
|
!$omp end workshare nowait
|
|
|
|
IF (present(energy)) THEN
|
|
!$omp single
|
|
allocate(egcxc_of_tid(ntids))
|
|
!$omp end single
|
|
egcxc_of_tid(mytid) = 0.0_dp
|
|
ALLOCATE(e_rad(i%m))
|
|
ENDIF
|
|
|
|
spin:&
|
|
!XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
IF ( nspin_mag == 1 ) THEN
|
|
!
|
|
! GGA case
|
|
!
|
|
!$omp do
|
|
DO ix = ix_s, ix_e
|
|
!
|
|
! WARNING: the next 2 calls are duplicated for spin==2
|
|
CALL PAW_lm2rad(i, ix, rho_lm, rho_rad, nspin_mag)
|
|
CALL PAW_gradient(i, ix, rho_lm, rho_rad, rho_core, grad2, grad)
|
|
|
|
DO k = 1, i%m
|
|
! arho is the absolute value of real charge, sgn is its sign
|
|
arho = rho_rad(k,1)*g(i%t)%rm2(k) + rho_core(k)
|
|
sgn = SIGN(1._dp,arho)
|
|
arho = ABS(arho)
|
|
|
|
! I am using grad(rho)**2 here, so its eps has to be eps**2
|
|
IF ( (arho>eps) .and. (grad2(k,1)>eps2) ) THEN
|
|
CALL gcxc(arho,grad2(k,1), sx,sc,v1x,v2x,v1c,v2c)
|
|
IF (present(energy)) &
|
|
e_rad(k) = sgn *e2* (sx+sc) * g(i%t)%r2(k)
|
|
gc_rad(k,ix,1) = (v1x+v1c)!*g(i%t)%rm2(k)
|
|
h_rad(k,:,ix,1) = (v2x+v2c)*grad(k,:,1)*g(i%t)%r2(k)
|
|
ELSE
|
|
IF (present(energy)) &
|
|
e_rad(k) = 0._dp
|
|
gc_rad(k,ix,1) = 0._dp
|
|
h_rad(k,:,ix,1) = 0._dp
|
|
ENDIF
|
|
ENDDO
|
|
!
|
|
! integrate energy (if required)
|
|
IF (present(energy)) THEN
|
|
CALL simpson(i%m, e_rad, g(i%t)%rab, e)
|
|
egcxc_of_tid(mytid) = egcxc_of_tid(mytid) + e * rad(i%t)%ww(ix)
|
|
ENDIF
|
|
ENDDO
|
|
!$omp end do
|
|
!XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
ELSEIF ( nspin_mag == 2 .OR. nspin_mag == 4 ) THEN
|
|
ALLOCATE( rup_vec(i%m) )
|
|
ALLOCATE( rdw_vec(i%m) )
|
|
ALLOCATE( sx_vec(i%m) )
|
|
ALLOCATE( v1xup_vec(i%m) )
|
|
ALLOCATE( v1xdw_vec(i%m) )
|
|
ALLOCATE( v2xup_vec(i%m) )
|
|
ALLOCATE( v2xdw_vec(i%m) )
|
|
|
|
! transform the noncollinear case into sigma-GGA case
|
|
IF (noncolin) THEN
|
|
CALL compute_rho_spin_lm(i, rho_lm, rhoout_lm, segni_rad)
|
|
ELSE
|
|
rhoout_lm=rho_lm
|
|
ENDIF
|
|
!
|
|
! this is the \sigma-GGA case
|
|
!
|
|
!$omp do
|
|
DO ix = ix_s, ix_e
|
|
!
|
|
CALL PAW_lm2rad(i, ix, rhoout_lm, rho_rad, nspin_gga)
|
|
CALL PAW_gradient(i, ix, rhoout_lm, rho_rad, rho_core, &
|
|
grad2, grad)
|
|
!
|
|
DO k = 1,i%m
|
|
!
|
|
! Prepare the necessary quantities
|
|
! rho_core is considered half spin up and half spin down:
|
|
co2 = rho_core(k)/2._dp
|
|
! than I build the real charge dividing by r**2
|
|
rup_vec(k) = rho_rad(k,1)*g(i%t)%rm2(k) + co2
|
|
rdw_vec(k) = rho_rad(k,2)*g(i%t)%rm2(k) + co2
|
|
END DO
|
|
! bang!
|
|
CALL gcx_spin_vec (rup_vec, rdw_vec, grad2(:,1), grad2(:,2), &
|
|
sx_vec, v1xup_vec, v1xdw_vec, v2xup_vec, v2xdw_vec, i%m)
|
|
DO k = 1,i%m
|
|
rh = rup_vec(k) + rdw_vec(k) ! total charge
|
|
IF ( rh > eps ) THEN
|
|
zeta = (rup_vec(k) - rdw_vec(k) ) / rh ! polarization
|
|
!
|
|
grh2 = (grad(k,1,1) + grad(k,1,2))**2 &
|
|
+ (grad(k,2,1) + grad(k,2,2))**2 &
|
|
+ (grad(k,3,1) + grad(k,3,2))**2
|
|
CALL gcc_spin (rh, zeta, grh2, sc, v1cup, v1cdw, v2c)
|
|
ELSE
|
|
sc = 0._dp
|
|
v1cup = 0._dp
|
|
v1cdw = 0._dp
|
|
v2c = 0._dp
|
|
ENDIF
|
|
IF (present(energy)) &
|
|
e_rad(k) = e2*(sx_vec(k)+sc)* g(i%t)%r2(k)
|
|
gc_rad(k,ix,1) = (v1xup_vec(k)+v1cup)!*g(i%t)%rm2(k)
|
|
gc_rad(k,ix,2) = (v1xdw_vec(k)+v1cdw)!*g(i%t)%rm2(k)
|
|
!
|
|
h_rad(k,:,ix,1) =( (v2xup_vec(k)+v2c)*grad(k,:,1)+v2c*grad(k,:,2) )*g(i%t)%r2(k)
|
|
h_rad(k,:,ix,2) =( (v2xdw_vec(k)+v2c)*grad(k,:,2)+v2c*grad(k,:,1) )*g(i%t)%r2(k)
|
|
ENDDO ! k
|
|
! integrate energy (if required)
|
|
! NOTE: this integration is duplicated for every spin, FIXME!
|
|
IF (present(energy)) THEN
|
|
CALL simpson(i%m, e_rad, g(i%t)%rab, e)
|
|
egcxc_of_tid(mytid) = egcxc_of_tid(mytid) + e * rad(i%t)%ww(ix)
|
|
ENDIF
|
|
ENDDO ! ix
|
|
!$omp end do nowait
|
|
DEALLOCATE( rup_vec )
|
|
DEALLOCATE( rdw_vec )
|
|
DEALLOCATE( sx_vec )
|
|
DEALLOCATE( v1xup_vec )
|
|
DEALLOCATE( v1xdw_vec )
|
|
DEALLOCATE( v2xup_vec )
|
|
DEALLOCATE( v2xdw_vec )
|
|
!XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
ELSE spin
|
|
!$omp master
|
|
CALL errore('PAW_gcxc_v', 'unknown spin number', 2)
|
|
!$omp end master
|
|
ENDIF spin
|
|
!
|
|
IF (present(energy)) THEN
|
|
DEALLOCATE(e_rad)
|
|
ENDIF
|
|
|
|
DEALLOCATE( rho_rad )
|
|
DEALLOCATE( grad )
|
|
DEALLOCATE( grad2 )
|
|
!$omp end parallel
|
|
!
|
|
!
|
|
IF (present(energy)) THEN
|
|
e_gcxc = sum(egcxc_of_tid)
|
|
CALL mp_sum( e_gcxc, paw_comm )
|
|
energy = energy + e_gcxc
|
|
ENDIF
|
|
!
|
|
IF (present(energy)) THEN
|
|
deallocate(egcxc_of_tid)
|
|
ENDIF
|
|
!
|
|
! convert the first part of the GC correction back to spherical harmonics
|
|
CALL PAW_rad2lm(i, gc_rad, gc_lm, i%l, nspin_gga)
|
|
!
|
|
! Note that the expansion into spherical harmonics of the derivative
|
|
! with respect to theta of the spherical harmonics, is very slow to
|
|
! converge and would require a huge angular momentum ladd.
|
|
! This derivative divided by sin_th is much faster to converge, so
|
|
! we divide here before calculating h_lm and keep into account for
|
|
! this factor sin_th in the expression of the divergence.
|
|
!
|
|
! ADC 30/04/2009.
|
|
!
|
|
DO ix = ix_s, ix_e
|
|
h_rad(1:i%m,3,ix,1:nspin_gga) = h_rad(1:i%m,3,ix,1:nspin_gga)/&
|
|
rad(i%t)%sin_th(ix)
|
|
ENDDO
|
|
! We need the gradient of h to calculate the last part of the exchange
|
|
! and correlation potential. First we have to convert H to its Y_lm expansion
|
|
CALL PAW_rad2lm3(i, h_rad, h_lm, i%l+rad(i%t)%ladd,nspin_gga)
|
|
!
|
|
! Compute div(H)
|
|
CALL PAW_divergence(i, h_lm, div_h, i%l+rad(i%t)%ladd, i%l)
|
|
! input max lm --^ ^-- output max lm
|
|
|
|
! Finally sum it back into v_xc
|
|
DO is = 1,nspin_gga
|
|
DO lm = 1,i%l**2
|
|
vout_lm(1:i%m,lm,is) = vout_lm(1:i%m,lm,is) + e2*(gc_lm(1:i%m,lm,is)-div_h(1:i%m,lm,is))
|
|
ENDDO
|
|
ENDDO
|
|
IF (nspin_mag == 4 ) THEN
|
|
CALL compute_pot_nonc(i,vout_lm,v_lm,segni_rad,rho_lm)
|
|
ELSE
|
|
v_lm(:,:,1:nspin_mag)=v_lm(:,:,1:nspin_mag)+vout_lm(:,:,1:nspin_mag)
|
|
ENDIF
|
|
|
|
DEALLOCATE( gc_rad )
|
|
DEALLOCATE( gc_lm )
|
|
DEALLOCATE( h_rad )
|
|
DEALLOCATE( h_lm )
|
|
DEALLOCATE( div_h )
|
|
DEALLOCATE(rhoout_lm)
|
|
DEALLOCATE(vout_lm)
|
|
DEALLOCATE(segni_rad)
|
|
|
|
!if(present(energy)) write(*,*) "gcxc -->", e_gcxc
|
|
if(TIMING) CALL stop_clock ('PAW_gcxc_v')
|
|
|
|
END SUBROUTINE PAW_gcxc_potential
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! compute divergence of a vector field (actutally the hamiltonian)
|
|
!!! it is assumed that: 1. the input function is multiplied by r**2;
|
|
!!! 2. the output function is multiplied by r**2 too
|
|
SUBROUTINE PAW_divergence(i, F_lm, div_F_lm, lmaxq_in, lmaxq_out)
|
|
USE constants, ONLY : sqrtpi, fpi, e2
|
|
USE noncollin_module, ONLY : nspin_gga
|
|
USE lsda_mod, ONLY : nspin
|
|
USE atom, ONLY : g => rgrid
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
INTEGER, INTENT(IN) :: lmaxq_in ! max angular momentum to derive
|
|
! (divergence is reliable up to lmaxq_in-2)
|
|
INTEGER, INTENT(IN) :: lmaxq_out ! max angular momentum to reconstruct for output
|
|
REAL(DP), INTENT(IN) :: F_lm(i%m,3,lmaxq_in**2,nspin_gga) ! Y_lm expansion of F
|
|
REAL(DP), INTENT(OUT):: div_F_lm(i%m,lmaxq_out**2,nspin_gga)! div(F)
|
|
!
|
|
REAL(DP) :: div_F_rad(i%m,rad(i%t)%nx,nspin_gga)! div(F) on rad. grid
|
|
REAL(DP) :: aux(i%m)!,aux2(i%m) ! workspace
|
|
! counters on: spin, angular momentum, radial grid point:
|
|
INTEGER :: is, lm, ix
|
|
|
|
if(TIMING) CALL start_clock ('PAW_div')
|
|
|
|
! This is the divergence in spherical coordinates:
|
|
! {1 \over r^2}{\partial ( r^2 A_r ) \over \partial r}
|
|
! + {1 \over r\sin\theta}{\partial \over \partial \theta} ( A_\theta\sin\theta )
|
|
! + {1 \over r\sin\theta}{\partial A_\phi \over \partial \phi}
|
|
!
|
|
! The derivative sum_LM d(Y_LM sin(theta) )/dtheta will be expanded as:
|
|
! sum_LM ( Y_lm cos(theta) + sin(theta) dY_lm/dtheta )
|
|
|
|
! The radial component of the divergence is computed last, for practical reasons
|
|
|
|
! CALL errore('PAW_divergence', 'More angular momentum components are needed (in input)'//&
|
|
! ' to provide the number you have requested (in output)', lmaxq_out-lmaxq_in+2)
|
|
|
|
! phi component
|
|
|
|
div_F_rad=0.0_DP
|
|
|
|
DO is = 1,nspin_gga
|
|
DO ix = ix_s,ix_e
|
|
aux(:) = 0._dp
|
|
! this derivative has no spherical component, so lm starts from 2
|
|
DO lm = 2,lmaxq_in**2
|
|
aux(1:i%m) = aux(1:i%m) + rad(i%t)%dylmp(ix,lm)* (F_lm(1:i%m,2,lm,is))! &
|
|
!* g(i%t)%rm1(1:i%m) !/sin_th(ix)
|
|
! as for PAW_gradient this is already present in dylmp --^
|
|
ENDDO
|
|
div_F_rad(1:i%m,ix,is) = aux(1:i%m)
|
|
ENDDO
|
|
ENDDO
|
|
|
|
! theta component
|
|
DO is = 1,nspin_gga
|
|
DO ix = ix_s,ix_e
|
|
aux(:) = 0._dp
|
|
! this derivative has a spherical component too!
|
|
DO lm = 1,lmaxq_in**2
|
|
aux(1:i%m) = aux(1:i%m) + F_lm(1:i%m,3,lm,is) &
|
|
* (rad(i%t)%dylmt(ix,lm)*rad(i%t)%sin_th(ix)&
|
|
+ 2.0_DP*rad(i%t)%ylm(ix,lm)*rad(i%t)%cos_th(ix))
|
|
! *( rad(i%t)%dylmt(ix,lm) &
|
|
! + rad(i%t)%ylm(ix,lm) * rad(i%t)%cotg_th(ix) )
|
|
ENDDO
|
|
div_F_rad(1:i%m,ix,is) = div_F_rad(1:i%m,ix,is)+aux(1:i%m)
|
|
ENDDO
|
|
ENDDO
|
|
|
|
! Convert what I have done so far to Y_lm
|
|
CALL PAW_rad2lm(i, div_F_rad, div_F_lm, lmaxq_out, nspin_gga)
|
|
! Multiply by 1/r**3: 1/r is for theta and phi componente only
|
|
! 1/r**2 is common to all the three components.
|
|
DO is = 1,nspin_gga
|
|
DO lm = 1,lmaxq_out**2
|
|
div_F_lm(1:i%m,lm,is) = div_F_lm(1:i%m,lm,is) * g(i%t)%rm3(1:i%m)
|
|
ENDDO
|
|
ENDDO
|
|
|
|
! Compute partial radial derivative d/dr
|
|
DO is = 1,nspin_gga
|
|
DO lm = 1,lmaxq_out**2
|
|
! Derive along \hat{r} (F already contains a r**2 factor, otherwise
|
|
! it may be better to expand (1/r**2) d(A*r**2)/dr = dA/dr + 2A/r)
|
|
CALL radial_gradient(F_lm(1:i%m,1,lm,is), aux, g(i%t)%r, i%m, radial_grad_style)
|
|
! Sum it in the divergence: it is already in the right Y_lm form
|
|
aux(1:i%m) = aux(1:i%m)*g(i%t)%rm2(1:i%m)
|
|
!
|
|
div_F_lm(1:i%m,lm,is) = div_F_lm(1:i%m,lm,is) + aux(1:i%m)
|
|
ENDDO
|
|
ENDDO
|
|
|
|
if(TIMING) CALL stop_clock ('PAW_div')
|
|
|
|
END SUBROUTINE PAW_divergence
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! build gradient of radial charge distribution from its spherical harmonics expansion
|
|
SUBROUTINE PAW_gradient(i, ix, rho_lm, rho_rad, rho_core, grho_rad2, grho_rad)
|
|
USE constants, ONLY : fpi
|
|
USE noncollin_module, ONLY : nspin_gga
|
|
USE lsda_mod, ONLY : nspin
|
|
USE atom, ONLY : g => rgrid
|
|
|
|
INTEGER, INTENT(IN) :: ix ! line of the dylm2 matrix to use actually it is
|
|
! one of the nx spherical integration directions
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
REAL(DP), INTENT(IN) :: rho_lm(i%m,i%l**2,nspin_gga)! Y_lm expansion of rho
|
|
REAL(DP), INTENT(IN) :: rho_rad(i%m,nspin_gga) ! radial density along direction ix
|
|
REAL(DP), INTENT(IN) :: rho_core(i%m) ! core density
|
|
REAL(DP), INTENT(OUT):: grho_rad2(i%m,nspin_gga) ! |grad(rho)|^2 on rad. grid
|
|
REAL(DP), OPTIONAL,INTENT(OUT):: grho_rad(i%m,3,nspin_gga) ! vector gradient (only for gcxc)
|
|
! r, theta and phi components ---^
|
|
!
|
|
REAL(DP) :: aux(i%m),aux2(i%m), fact ! workspace
|
|
INTEGER :: is, lm ! counters on: spin, angular momentum
|
|
|
|
if(TIMING) CALL start_clock ('PAW_grad')
|
|
! 1. build real charge density = rho/r**2 + rho_core
|
|
! 2. compute the partial derivative of rho_rad
|
|
fact=1.0_DP/DBLE(nspin_gga)
|
|
grho_rad2(:,:) = 0._dp
|
|
DO is = 1,nspin_gga
|
|
! build real charge density
|
|
aux(1:i%m) = rho_rad(1:i%m,is)*g(i%t)%rm2(1:i%m) &
|
|
+ rho_core(1:i%m)*fact
|
|
CALL radial_gradient(aux, aux2, g(i%t)%r, i%m, radial_grad_style)
|
|
! compute the square
|
|
grho_rad2(:,is) = aux2(:)**2
|
|
! store in vector gradient, if present:
|
|
IF (present(grho_rad)) grho_rad(:,1,is) = aux2(:)
|
|
ENDDO
|
|
|
|
spin: &
|
|
DO is = 1,nspin_gga
|
|
aux(:) = 0._dp
|
|
aux2(:) = 0._dp
|
|
! Spherical (lm=1) component (that would also include core correction) can be omitted
|
|
! as its contribution to non-radial derivative is zero
|
|
DO lm = 2,i%l**2
|
|
! 5. [ \sum_{lm} rho(r) (dY_{lm}/dphi /cos(theta)) ]**2
|
|
aux(1:i%m) = aux(1:i%m) + rad(i%t)%dylmp(ix,lm)* rho_lm(1:i%m,lm,is)
|
|
! 6. [ \sum_{lm} rho(r) (dY_{lm}/dtheta) ]**2
|
|
aux2(1:i%m) = aux2(1:i%m) + rad(i%t)%dylmt(ix,lm)* rho_lm(1:i%m,lm,is)
|
|
ENDDO
|
|
! Square and sum up these 2 components, the (1/r**2)**3 factor come from:
|
|
! a. 1/r**2 from the derivative in spherical coordinates
|
|
! b. (1/r**2)**2 from rho_lm being multiplied by r**2
|
|
! (as the derivative is orthogonal to r you can multiply after deriving)
|
|
grho_rad2(1:i%m,is) = grho_rad2(1:i%m,is)&
|
|
+ (aux(1:i%m)**2 + aux2(1:i%m)**2)&
|
|
* g(i%t)%rm2(1:i%m)**3
|
|
! Store vector components:
|
|
IF (present(grho_rad)) THEN
|
|
grho_rad(1:i%m,2,is) = aux(1:i%m) *g(i%t)%rm3(1:i%m) ! phi
|
|
grho_rad(1:i%m,3,is) = aux2(1:i%m) *g(i%t)%rm3(1:i%m) ! theta
|
|
ENDIF
|
|
ENDDO spin
|
|
|
|
if(TIMING) CALL stop_clock ('PAW_grad')
|
|
|
|
END SUBROUTINE PAW_gradient
|
|
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! computes H potential from rho, used by PAW_h_energy and PAW_ddot
|
|
SUBROUTINE PAW_h_potential(i, rho_lm, v_lm, energy)
|
|
USE constants, ONLY : fpi, e2
|
|
USE radial_grids, ONLY : hartree
|
|
USE uspp_param, ONLY : upf
|
|
USE noncollin_module, ONLY : nspin_lsda
|
|
USE ions_base, ONLY : ityp
|
|
USE lsda_mod, ONLY : nspin
|
|
USE atom, ONLY : g => rgrid
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
! charge density as lm components already summed on spin:
|
|
REAL(DP), INTENT(IN) :: rho_lm(i%m,i%l**2,nspin)
|
|
REAL(DP), INTENT(OUT) :: v_lm (i%m,i%l**2) ! potential as lm components
|
|
REAL(DP),INTENT(OUT),OPTIONAL :: energy ! if present, compute energy
|
|
!
|
|
REAL(DP) :: aux(i%m) ! workspace
|
|
REAL(DP) :: pref ! workspace
|
|
|
|
INTEGER :: lm,l ! counter on composite angmom lm = l**2 +m
|
|
INTEGER :: k ! counter on radial grid (only for energy)
|
|
REAL(DP) :: e ! workspace
|
|
|
|
if(TIMING) CALL start_clock ('PAW_h_pot')
|
|
|
|
! this loop computes the hartree potential using the following formula:
|
|
! l is the first argument in hartree subroutine
|
|
! r1 = min(r,r'); r2 = MAX(r,r')
|
|
! V_h(r) = \sum{lm} Y_{lm}(\hat{r})/(2l+1) \int dr' 4\pi r'^2 \rho^{lm}(r') (r1^l/r2^{l+1})
|
|
! done here --> ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ <-- input to the hartree subroutine
|
|
! output from the h.s. --> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
v_lm=0.0_DP
|
|
DO lm = 1, i%l**2
|
|
l = INT(sqrt(DBLE(lm-1))) ! l has to start from *zero*
|
|
pref = e2*fpi/DBLE(2*l+1)
|
|
DO k = 1, i%m
|
|
aux(k) = pref * SUM(rho_lm(k,lm,1:nspin_lsda))
|
|
ENDDO
|
|
!
|
|
CALL hartree(l, 2*l+2, i%m, g(i%t), aux(:), v_lm(:,lm))
|
|
ENDDO
|
|
|
|
! compute energy if required:
|
|
! E_h = \sum_lm \int v_lm(r) (rho_lm(r) r^2) dr
|
|
IF(present(energy)) THEN
|
|
energy = 0._dp
|
|
DO lm = 1, i%l**2
|
|
! I can use v_lm as workspace
|
|
DO k = 1, i%m
|
|
aux(k) = v_lm(k,lm) * SUM(rho_lm(k,lm,1:nspin_lsda))
|
|
ENDDO
|
|
CALL simpson (i%m, aux, g(i%t)%rab, e)
|
|
!
|
|
! Sum all the energies in PAW_ddot
|
|
energy = energy + e
|
|
!
|
|
ENDDO
|
|
! fix double counting
|
|
energy = energy/2._dp
|
|
ENDIF
|
|
|
|
if(TIMING) CALL stop_clock ('PAW_h_pot')
|
|
|
|
END SUBROUTINE PAW_h_potential
|
|
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! sum up pfuncs x occupation to build radial density's angular momentum components
|
|
SUBROUTINE PAW_rho_lm(i, becsum, pfunc, rho_lm, aug)
|
|
USE ions_base, ONLY : nat
|
|
USE lsda_mod, ONLY : nspin
|
|
USE noncollin_module, ONLY : nspin_mag
|
|
USE uspp_param, ONLY : upf, nh, nhm
|
|
USE uspp, ONLY : indv, ap, nhtolm,lpl,lpx
|
|
USE constants, ONLY : eps12
|
|
USE atom, ONLY : g => rgrid
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
REAL(DP), INTENT(IN) :: becsum(nhm*(nhm+1)/2,nat,nspin_mag)! cross band occupation
|
|
REAL(DP), INTENT(IN) :: pfunc(i%m,i%b,i%b) ! psi_i * psi_j
|
|
REAL(DP), INTENT(OUT) :: rho_lm(i%m,i%l**2,nspin_mag) ! AE charge density on rad. grid
|
|
REAL(DP), OPTIONAL,INTENT(IN) :: &
|
|
aug(i%m,i%b*(i%b+1)/2,0:2*upf(i%t)%lmax) ! augmentation functions (only for PS part)
|
|
|
|
REAL(DP) :: pref ! workspace (ap*becsum)
|
|
|
|
INTEGER :: ih,jh, & ! counters for pfunc ih,jh = 1, nh (CRYSTAL index)
|
|
nb,mb, & ! counters for pfunc nb,mb = 1, nbeta (ATOMIC index)
|
|
ijh,nmb, & ! composite "triangular" index for pfunc nmb = 1,nh*(nh+1)/2
|
|
lm,lp,l, & ! counters for angular momentum lm = l**2+m
|
|
ispin ! counter for spin (FIXME: may be unnecessary)
|
|
|
|
! This subroutine computes the angular momentum components of rho
|
|
! using the following formula:
|
|
! rho(\vec{r}) = \sum_{LM} Y_{LM} \sum_{i,j} (\hat{r}) a_{LM}^{(lm)_i(lm)_j} becsum_ij pfunc_ij(r)
|
|
! where a_{LM}^{(lm)_i(lm)_j} are the Clebsh-Gordan coefficients.
|
|
!
|
|
! actually different angular momentum components are stored separately:
|
|
! rho^{LM}(\vec{r}) = \sum_{i,j} (\hat{r}) a_{LM}^{(lm)_i(lm)_j} becsum_ij pfunc_ij(r)
|
|
!
|
|
! notice that pfunc's are already multiplied by r^2 and they are indexed on the atom
|
|
! (they only depends on l, not on m), the augmentation charge depend only on l
|
|
! but the becsum depend on both l and m.
|
|
|
|
if(TIMING) CALL start_clock ('PAW_rho_lm')
|
|
|
|
! initialize density
|
|
rho_lm(:,:,:) = 0._dp
|
|
|
|
spins: DO ispin = 1, nspin_mag
|
|
ijh = 0
|
|
! loop on all pfunc for this kind of pseudo
|
|
DO ih = 1, nh(i%t)
|
|
DO jh = ih, nh(i%t)
|
|
ijh = ijh+1
|
|
nb = indv(ih,i%t)
|
|
mb = indv(jh,i%t)
|
|
nmb = mb * (mb-1)/2 + nb ! mb has to be .ge. nb
|
|
!write(*,'(99i4)') nb,mb,nmb
|
|
IF (ABS(becsum(ijh,i%a,ispin)) < eps12) CYCLE
|
|
!
|
|
angular_momentum: &
|
|
DO lp = 1, lpx (nhtolm(jh,i%t), nhtolm(ih,i%t)) !lmaxq**2
|
|
! the lpl array contains the possible combination of LM,lm_j,lm_j that
|
|
! have non-zero a_{LM}^{(lm)_i(lm)_j} (it saves some loops)
|
|
lm = lpl (nhtolm(jh,i%t), nhtolm(ih,i%t), lp)
|
|
!
|
|
! becsum already contains a factor 2 for off-diagonal pfuncs
|
|
pref = becsum(ijh,i%a,ispin) * ap(lm, nhtolm(ih,i%t), nhtolm(jh,i%t))
|
|
!
|
|
rho_lm(1:i%m,lm,ispin) = rho_lm(1:i%m,lm,ispin) &
|
|
+pref * pfunc(1:i%m, nb, mb)
|
|
IF (present(aug)) THEN
|
|
! if I'm doing the pseudo part I have to add the augmentation charge
|
|
l = INT(SQRT(DBLE(lm-1))) ! l has to start from zero, lm = l**2 +m
|
|
rho_lm(1:i%m,lm,ispin) = rho_lm(1:i%m,lm,ispin) &
|
|
+pref * aug(1:i%m, nmb, l)
|
|
ENDIF ! augfun
|
|
ENDDO angular_momentum
|
|
ENDDO !mb
|
|
ENDDO !nb
|
|
ENDDO spins
|
|
|
|
if(TIMING) CALL stop_clock ('PAW_rho_lm')
|
|
|
|
END SUBROUTINE PAW_rho_lm
|
|
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! build radial charge distribution from its spherical harmonics expansion
|
|
SUBROUTINE PAW_lm2rad(i, ix, F_lm, F_rad, nspin)
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
INTEGER :: ix ! line of the ylm matrix to use
|
|
! actually it is one of the nx directions
|
|
INTEGER, INTENT(IN) :: nspin
|
|
REAL(DP), INTENT(IN) :: F_lm(i%m,i%l**2,nspin)! Y_lm expansion of rho
|
|
REAL(DP), INTENT(OUT) :: F_rad(i%m,nspin) ! charge density on rad. grid
|
|
!
|
|
INTEGER :: ispin, lm ! counters on angmom and spin
|
|
|
|
if(TIMING) CALL start_clock ('PAW_lm2rad')
|
|
F_rad(:,:) = 0._dp
|
|
! cycling on spin is a bit less general...
|
|
spins: DO ispin = 1,nspin
|
|
DO lm = 1, i%l**2
|
|
F_rad(:,ispin) = F_rad(:,ispin) +&
|
|
rad(i%t)%ylm(ix,lm)*F_lm(:,lm,ispin)
|
|
ENDDO ! lm
|
|
ENDDO spins
|
|
|
|
if(TIMING) CALL stop_clock ('PAW_lm2rad')
|
|
|
|
END SUBROUTINE PAW_lm2rad
|
|
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! computes F_lm(r) = \int d \Omega F(r,th,ph) Y_lm(th,ph)
|
|
SUBROUTINE PAW_rad2lm(i, F_rad, F_lm, lmax_loc, nspin)
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
INTEGER, INTENT(IN) :: nspin
|
|
INTEGER, INTENT(IN) :: lmax_loc ! in some cases I have to keep higher angular components
|
|
! than the default ones (=lmaxq =the ones present in rho)
|
|
REAL(DP), INTENT(OUT):: F_lm(i%m, lmax_loc**2, nspin) ! lm component of F up to lmax_loc
|
|
REAL(DP), INTENT(IN) :: F_rad(i%m, rad(i%t)%nx, nspin)! radial samples of F
|
|
!
|
|
INTEGER :: ix ! counter for integration
|
|
INTEGER :: lm ! counter for angmom
|
|
INTEGER :: ispin ! counter for spin
|
|
INTEGER :: j
|
|
|
|
if(TIMING) CALL start_clock ('PAW_rad2lm')
|
|
|
|
!$omp parallel default(shared), private(ispin,lm,ix,j)
|
|
DO ispin = 1,nspin
|
|
!$omp do
|
|
DO lm = 1,lmax_loc**2
|
|
F_lm(:,lm,ispin) = 0._dp
|
|
DO ix = ix_s, ix_e
|
|
DO j = 1, i%m
|
|
F_lm(j, lm, ispin) = F_lm(j, lm, ispin) + F_rad(j,ix,ispin)* rad(i%t)%wwylm(ix,lm)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$omp end do
|
|
ENDDO
|
|
!$omp end parallel
|
|
|
|
!
|
|
! This routine recollects the result within the paw communicator
|
|
!
|
|
CALL mp_sum( F_lm, paw_comm )
|
|
|
|
if(TIMING) CALL stop_clock ('PAW_rad2lm')
|
|
|
|
END SUBROUTINE PAW_rad2lm
|
|
!___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
|
|
!!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
|
!!! computes F_lm(r) = \int d \Omega F(r,th,ph) Y_lm(th,ph)
|
|
!!! duplicated version to work on vector fields, necessary for performance reasons
|
|
SUBROUTINE PAW_rad2lm3(i, F_rad, F_lm, lmax_loc, nspin)
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
INTEGER, INTENT(IN) :: lmax_loc ! in some cases I have to keep higher angular components
|
|
! than the default ones (=lmaxq =the ones present in rho)
|
|
REAL(DP), INTENT(OUT):: F_lm(i%m, 3, lmax_loc**2, nspin) ! lm component of F up to lmax_loc
|
|
REAL(DP), INTENT(IN) :: F_rad(i%m, 3, rad(i%t)%nx, nspin)! radial samples of F
|
|
!
|
|
REAL(DP) :: aux(i%m) ! optimization
|
|
|
|
INTEGER, INTENT(IN) :: nspin
|
|
INTEGER :: ix ! counter for integration
|
|
INTEGER :: lm ! counter for angmom
|
|
INTEGER :: ispin ! counter for spin
|
|
|
|
if(TIMING) CALL start_clock ('PAW_rad2lm3')
|
|
|
|
! Third try: 50% faster than blind implementation (60% with prefetch)
|
|
DO ispin = 1,nspin
|
|
DO lm = 1,lmax_loc**2
|
|
aux(:) = 0._dp
|
|
DO ix = ix_s, ix_e
|
|
aux(1:i%m) = aux(1:i%m) + F_rad(1:i%m,1,ix,ispin) * rad(i%t)%wwylm(ix,lm)
|
|
!CALL MM_PREFETCH( F_rad(1:i%m,1,MIN(ix+1,rad(i%t)%nx),ispin), 1 )
|
|
ENDDO
|
|
F_lm(1:i%m, 1, lm, ispin) = aux(1:i%m)
|
|
!
|
|
aux(:) = 0._dp
|
|
DO ix = ix_s, ix_e
|
|
aux(1:i%m) = aux(1:i%m) + F_rad(1:i%m,2,ix,ispin) * rad(i%t)%wwylm(ix,lm)
|
|
!CALL MM_PREFETCH( F_rad(1:i%m,2,MIN(ix+1,rad(i%t)%nx),ispin), 1 )
|
|
ENDDO
|
|
F_lm(1:i%m, 2, lm, ispin) = aux(1:i%m)
|
|
!
|
|
aux(:) = 0._dp
|
|
DO ix = ix_s, ix_e
|
|
aux(1:i%m) = aux(1:i%m) + F_rad(1:i%m,3,ix,ispin) * rad(i%t)%wwylm(ix,lm)
|
|
!CALL MM_PREFETCH( F_rad(1:i%m,3,MIN(ix+1,rad(i%t)%nx),ispin), 1 )
|
|
ENDDO
|
|
F_lm(1:i%m, 3, lm, ispin) = aux(1:i%m)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
! NB: this routine collects the result among the paw communicator
|
|
!
|
|
CALL mp_sum( F_lm, paw_comm )
|
|
|
|
if(TIMING) CALL stop_clock ('PAW_rad2lm3')
|
|
|
|
END SUBROUTINE PAW_rad2lm3
|
|
!
|
|
! Computes dV_h and dV_xc using the "change of density" dbecsum provided
|
|
! Update the change of the descreening coefficients:
|
|
! D_ij = \int dv_Hxc p_ij - \int dvt_Hxc (pt_ij + augfun_ij)
|
|
!
|
|
!
|
|
SUBROUTINE PAW_dpotential(dbecsum, becsum, int3, npe)
|
|
USE atom, ONLY : g => rgrid
|
|
USE ions_base, ONLY : nat, ityp
|
|
USE mp, ONLY : mp_comm_split, mp_comm_free, mp_size, mp_rank
|
|
USE noncollin_module, ONLY : nspin_lsda, nspin_mag
|
|
USE lsda_mod, ONLY : nspin
|
|
USE uspp_param, ONLY : nh, nhm, upf
|
|
|
|
INTEGER, INTENT(IN) :: npe ! number of perturbations
|
|
|
|
REAL(DP), INTENT(IN) :: becsum(nhm*(nhm+1)/2,nat,nspin_mag) ! cross band
|
|
! occupations
|
|
COMPLEX(DP), INTENT(IN) :: dbecsum(nhm*(nhm+1)/2,nat,nspin_mag,npe)!
|
|
|
|
COMPLEX(DP), INTENT(OUT) :: int3(nhm,nhm,npe,nat,nspin_mag) ! change of
|
|
!descreening coefficients (AE - PS)
|
|
INTEGER, PARAMETER :: AE = 1, PS = 2,& ! All-Electron and Pseudo
|
|
XC = 1, H = 2 ! XC and Hartree
|
|
REAL(DP), POINTER :: rho_core(:) ! pointer to AE/PS core charge density
|
|
TYPE(paw_info) :: i ! minimal info on atoms
|
|
INTEGER :: i_what ! counter on AE and PS
|
|
INTEGER :: is ! spin index
|
|
INTEGER :: lm ! counters on angmom and radial grid
|
|
INTEGER :: nb, mb, nmb ! augfun indexes
|
|
INTEGER :: ia,mykey,ia_s,ia_e ! atoms counters and indexes
|
|
!
|
|
REAL(DP), ALLOCATABLE :: rho_lm(:,:,:) ! density expanded on Y_lm
|
|
REAL(DP), ALLOCATABLE :: dv_lm(:,:,:) ! workspace: change of potential
|
|
REAL(DP), ALLOCATABLE :: drhor_lm(:,:,:,:) ! change of density expanded
|
|
! on Y_lm (real part)
|
|
REAL(DP), ALLOCATABLE :: drhoi_lm(:,:,:,:) ! change of density expanded
|
|
! on Y_lm (imaginary part)
|
|
REAL(DP), ALLOCATABLE :: savedvr_lm(:,:,:,:) ! workspace: potential
|
|
REAL(DP), ALLOCATABLE :: savedvi_lm(:,:,:,:) ! workspace: potential
|
|
REAL(DP), ALLOCATABLE :: aux_lm(:) ! auxiliary radial function
|
|
! fake cross band occupations to select only one pfunc at a time:
|
|
REAL(DP) :: becfake(nhm*(nhm+1)/2,nat,nspin_mag)
|
|
REAL(DP) :: integral_r ! workspace
|
|
REAL(DP) :: integral_i ! workspace
|
|
REAL(DP) :: sgn ! +1 for AE -1 for PS
|
|
COMPLEX(DP) :: sumd
|
|
INTEGER :: ipert
|
|
|
|
CALL start_clock('PAW_dpot')
|
|
! Some initialization
|
|
becfake(:,:,:) = 0._dp
|
|
int3 = (0.0_DP, 0.0_DP)
|
|
!
|
|
! Parallel: divide tasks among all the processor for this image
|
|
! (i.e. all the processors except for NEB and similar)
|
|
CALL block_distribute( nat, me_image, nproc_image, ia_s, ia_e, mykey )
|
|
! build the group of all the procs associated with the same atom
|
|
!
|
|
CALL mp_comm_split( intra_image_comm, ia_s - 1, me_image, paw_comm )
|
|
!
|
|
me_paw = mp_rank( paw_comm )
|
|
nproc_paw = mp_size( paw_comm )
|
|
!
|
|
|
|
atoms: DO ia = ia_s, ia_e
|
|
!
|
|
i%a = ia ! atom's index
|
|
i%t = ityp(ia) ! type of atom ia
|
|
i%m = g(i%t)%mesh ! radial mesh size for atom i%t
|
|
i%b = upf(i%t)%nbeta ! number of beta functions for i%t
|
|
i%l = upf(i%t)%lmax_rho+1 ! max ang.mom. in augmentation for ia
|
|
!
|
|
ifpaw: IF (upf(i%t)%tpawp) THEN
|
|
!
|
|
! Initialize parallelization over the directions
|
|
!
|
|
nx_loc = ldim_block( rad(i%t)%nx, nproc_paw, me_paw )
|
|
ix_s = gind_block( 1, rad(i%t)%nx, nproc_paw, me_paw )
|
|
ix_e = ix_s + nx_loc - 1
|
|
!
|
|
! Arrays are allocated inside the cycle to allow reduced
|
|
! memory usage as differnt atoms have different meshes
|
|
!
|
|
ALLOCATE(dv_lm(i%m,i%l**2,nspin_mag))
|
|
ALLOCATE(savedvr_lm(i%m,i%l**2,nspin_mag,npe))
|
|
ALLOCATE(savedvi_lm(i%m,i%l**2,nspin_mag,npe))
|
|
ALLOCATE(rho_lm(i%m,i%l**2,nspin_mag))
|
|
ALLOCATE(drhor_lm(i%m,i%l**2,nspin_mag,npe))
|
|
ALLOCATE(drhoi_lm(i%m,i%l**2,nspin_mag,npe))
|
|
ALLOCATE(aux_lm(i%m))
|
|
!
|
|
whattodo: DO i_what = AE, PS
|
|
NULLIFY(rho_core)
|
|
IF (i_what == AE) THEN
|
|
CALL PAW_rho_lm(i, becsum, upf(i%t)%paw%pfunc, rho_lm)
|
|
rho_core => upf(i%t)%paw%ae_rho_atc
|
|
sgn = +1._dp
|
|
ELSE
|
|
CALL PAW_rho_lm(i, becsum, upf(i%t)%paw%ptfunc, &
|
|
rho_lm, upf(i%t)%qfuncl)
|
|
rho_core => upf(i%t)%rho_atc
|
|
sgn = -1._dp
|
|
ENDIF
|
|
!
|
|
! Compute the change of the charge density. Complex because the
|
|
! displacements might be complex
|
|
!
|
|
DO ipert=1,npe
|
|
IF (i_what == AE) THEN
|
|
becfake(:,ia,:)=DBLE(dbecsum(:,ia,:,ipert))
|
|
CALL PAW_rho_lm(i, becfake, upf(i%t)%paw%pfunc, &
|
|
drhor_lm(1,1,1,ipert))
|
|
becfake(:,ia,:)=AIMAG(dbecsum(:,ia,:,ipert))
|
|
CALL PAW_rho_lm(i, becfake, upf(i%t)%paw%pfunc, &
|
|
drhoi_lm(1,1,1,ipert))
|
|
ELSE
|
|
becfake(:,ia,:)=DBLE(dbecsum(:,ia,:,ipert))
|
|
CALL PAW_rho_lm(i, becfake, upf(i%t)%paw%ptfunc, &
|
|
drhor_lm(1,1,1,ipert), upf(i%t)%qfuncl)
|
|
becfake(:,ia,:)=AIMAG(dbecsum(:,ia,:,ipert))
|
|
CALL PAW_rho_lm(i, becfake, upf(i%t)%paw%ptfunc, &
|
|
drhoi_lm(1,1,1,ipert), upf(i%t)%qfuncl)
|
|
END IF
|
|
END DO
|
|
|
|
savedvr_lm(:,:,:,:) = 0._dp
|
|
savedvi_lm(:,:,:,:) = 0._dp
|
|
|
|
DO ipert=1,npe
|
|
!
|
|
! Change of Hartree potential
|
|
!
|
|
CALL PAW_h_potential(i, drhor_lm(1,1,1,ipert), dv_lm(:,:,1))
|
|
DO is = 1,nspin_lsda
|
|
savedvr_lm(:,:,is,ipert) = dv_lm(:,:,1)
|
|
ENDDO
|
|
CALL PAW_h_potential(i, drhoi_lm(1,1,1,ipert), dv_lm(:,:,1))
|
|
DO is = 1,nspin_lsda
|
|
savedvi_lm(:,:,is,ipert) = dv_lm(:,:,1)
|
|
ENDDO
|
|
!
|
|
! Change of Exchange-correlation potential
|
|
!
|
|
CALL PAW_dxc_potential(i, drhor_lm(1,1,1,ipert), &
|
|
rho_lm, rho_core, dv_lm)
|
|
savedvr_lm(:,:,:,ipert) = savedvr_lm(:,:,:,ipert)+dv_lm(:,:,:)
|
|
|
|
CALL PAW_dxc_potential(i, drhoi_lm(1,1,1,ipert), &
|
|
rho_lm, rho_core, dv_lm)
|
|
savedvi_lm(:,:,:,ipert) = savedvi_lm(:,:,:,ipert)+dv_lm(:,:,:)
|
|
END DO
|
|
!
|
|
spins: DO is = 1, nspin_mag
|
|
nmb = 0
|
|
! loop on all pfunc for this kind of pseudo
|
|
becfake=0.0_DP
|
|
DO nb = 1, nh(i%t)
|
|
DO mb = nb, nh(i%t)
|
|
nmb = nmb+1
|
|
becfake(nmb,ia,is) = 1._dp
|
|
IF (i_what == AE) THEN
|
|
CALL PAW_rho_lm(i, becfake, upf(i%t)%paw%pfunc, rho_lm)
|
|
ELSE
|
|
CALL PAW_rho_lm(i, becfake, upf(i%t)%paw%ptfunc, &
|
|
rho_lm, upf(i%t)%qfuncl)
|
|
ENDIF
|
|
!
|
|
! Integrate the change of Hxc potential and the partial waves
|
|
! to find the change of the D coefficients: D^1-~D^1
|
|
!
|
|
DO ipert=1,npe
|
|
DO lm = 1,i%l**2
|
|
aux_lm(1:i%m)=rho_lm(1:i%m,lm,is)* &
|
|
savedvr_lm(1:i%m,lm,is,ipert)
|
|
CALL simpson (upf(i%t)%kkbeta,aux_lm, &
|
|
g(i%t)%rab,integral_r)
|
|
aux_lm(1:i%m)=rho_lm(1:i%m,lm,is)* &
|
|
savedvi_lm(1:i%m,lm,is,ipert)
|
|
CALL simpson (upf(i%t)%kkbeta,aux_lm, &
|
|
g(i%t)%rab,integral_i)
|
|
int3(nb,mb,ipert,i%a,is) = &
|
|
int3(nb,mb,ipert,i%a,is) &
|
|
+ sgn * CMPLX(integral_r, integral_i,kind=DP)
|
|
ENDDO
|
|
IF (nb /= mb) int3(mb,nb,ipert,i%a,is) = &
|
|
int3(nb,mb,ipert,i%a,is)
|
|
ENDDO
|
|
becfake(nmb,ia,is) = 0._dp
|
|
ENDDO ! mb
|
|
ENDDO ! nb
|
|
ENDDO spins
|
|
ENDDO whattodo
|
|
! cleanup
|
|
DEALLOCATE(rho_lm)
|
|
DEALLOCATE(drhor_lm)
|
|
DEALLOCATE(drhoi_lm)
|
|
DEALLOCATE(savedvr_lm)
|
|
DEALLOCATE(savedvi_lm)
|
|
DEALLOCATE(dv_lm)
|
|
DEALLOCATE(aux_lm)
|
|
!
|
|
ENDIF ifpaw
|
|
ENDDO atoms
|
|
|
|
#ifdef __PARA
|
|
IF( mykey /= 0 ) int3 = 0.0_dp
|
|
CALL mp_sum(int3, intra_image_comm)
|
|
#endif
|
|
|
|
CALL mp_comm_free( paw_comm )
|
|
|
|
CALL stop_clock('PAW_dpot')
|
|
|
|
END SUBROUTINE PAW_dpotential
|
|
|
|
SUBROUTINE PAW_dxc_potential(i, drho_lm, rho_lm, rho_core, v_lm)
|
|
!
|
|
! This routine computes the change of the exchange and correlation
|
|
! potential in the spherical basis. It receives as input the charge
|
|
! density and its variation.
|
|
!
|
|
USE spin_orb, ONLY : domag
|
|
USE noncollin_module, ONLY : nspin_mag
|
|
USE lsda_mod, ONLY : nspin
|
|
USE atom, ONLY : g => rgrid
|
|
USE funct, ONLY : dmxc, dmxc_spin, dmxc_nc, &
|
|
dft_is_gradient
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
REAL(DP), INTENT(IN) :: rho_lm(i%m,i%l**2,nspin_mag) ! charge density as
|
|
! lm components
|
|
REAL(DP), INTENT(IN) :: drho_lm(i%m,i%l**2,nspin_mag)! change of charge
|
|
! density as lm components
|
|
REAL(DP), INTENT(IN) :: rho_core(i%m) ! core charge, radial
|
|
! and spherical
|
|
REAL(DP), INTENT(OUT) :: v_lm(i%m,i%l**2,nspin_mag) ! potential density
|
|
! as lm components
|
|
REAL(DP), ALLOCATABLE :: dmuxc(:,:,:) ! fxc in the lsda case
|
|
REAL(DP), ALLOCATABLE :: v_rad(:,:,:) ! radial potential
|
|
! (to be integrated)
|
|
REAL(DP), ALLOCATABLE :: rho_rad(:,:) ! workspace (only one
|
|
! radial slice of rho)
|
|
REAL(DP) :: rho_loc(nspin_mag) ! workspace
|
|
|
|
REAL(DP) :: rhotot, rhoup, rhodw ! auxiliary
|
|
REAL(DP) :: auxdmuxc(nspin_mag,nspin_mag) ! auxiliary space
|
|
|
|
INTEGER :: is,js,ix,k ! counters on directions
|
|
! and radial grid
|
|
|
|
CALL start_clock ('PAW_dxc_pot')
|
|
ALLOCATE(dmuxc(i%m,nspin_mag,nspin_mag))
|
|
ALLOCATE(v_rad(i%m,rad(i%t)%nx,nspin_mag))
|
|
ALLOCATE(rho_rad(i%m,nspin_mag))
|
|
!
|
|
DO ix = ix_s, ix_e
|
|
!
|
|
! *** LDA (and LSDA) part (no gradient correction) ***
|
|
! convert _lm density to real density along ix
|
|
!
|
|
CALL PAW_lm2rad(i, ix, rho_lm, rho_rad, nspin_mag)
|
|
!
|
|
! Compute the fxc function on the radial mesh along ix
|
|
!
|
|
DO k = 1,i%m
|
|
rho_loc(1:nspin_mag) = rho_rad(k,1:nspin_mag)*g(i%t)%rm2(k)
|
|
IF (nspin_mag==4) THEN
|
|
rhotot = rho_loc(1) + rho_core (k)
|
|
CALL dmxc_nc (rhotot, rho_loc(2), rho_loc(3), rho_loc(4), auxdmuxc)
|
|
DO is=1,nspin_mag
|
|
DO js=1,nspin_mag
|
|
dmuxc(k,is,js)=auxdmuxc(is,js)
|
|
END DO
|
|
END DO
|
|
ELSEIF (nspin_mag==2) THEN
|
|
rhoup = rho_loc(1) + 0.5_DP * rho_core (k)
|
|
rhodw = rho_loc(2) + 0.5_DP * rho_core (k)
|
|
CALL dmxc_spin (rhoup, rhodw, dmuxc(k,1,1), dmuxc(k,2,1), &
|
|
dmuxc(k,1,2), dmuxc(k,2,2) )
|
|
ELSE
|
|
rhotot = rho_loc(1) + rho_core (k)
|
|
IF (rhotot.GT.1.d-30) v_rad (k,ix,1) = dmxc (rhotot)
|
|
IF (rhotot.LT. - 1.d-30) v_rad(k, ix, 1) = - dmxc ( - rhotot)
|
|
IF (rhotot.LT.1.d-30.AND.rhotot.GT.-1.d-30) v_rad(k,ix,1)=0.0_DP
|
|
ENDIF
|
|
ENDDO
|
|
!
|
|
! Compute the change of the charge on the radial mesh along ix
|
|
!
|
|
CALL PAW_lm2rad(i, ix, drho_lm, rho_rad, nspin_mag)
|
|
!
|
|
! fxc * dn
|
|
!
|
|
IF (nspin_mag==1) THEN
|
|
DO k = 1,i%m
|
|
v_rad(k,ix,1)=v_rad(k,ix,1)*rho_rad(k,1)*g(i%t)%rm2(k)
|
|
ENDDO
|
|
ELSE
|
|
DO k = 1,i%m
|
|
DO is=1,nspin_mag
|
|
v_rad(k,ix,is)=0.0_DP
|
|
DO js=1,nspin_mag
|
|
v_rad(k,ix,is)= v_rad(k,ix,is) + &
|
|
dmuxc(k,is,js)*rho_rad(k,js)*g(i%t)%rm2(k)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDIF
|
|
ENDDO
|
|
!
|
|
! Recompose the sph. harm. expansion
|
|
!
|
|
CALL PAW_rad2lm(i, v_rad, v_lm, i%l, nspin_mag)
|
|
!
|
|
! Add gradient correction, if necessary
|
|
!
|
|
IF( dft_is_gradient() ) &
|
|
CALL PAW_dgcxc_potential(i,rho_lm,rho_core,drho_lm,v_lm)
|
|
|
|
DEALLOCATE(rho_rad)
|
|
DEALLOCATE(v_rad)
|
|
DEALLOCATE(dmuxc)
|
|
|
|
CALL stop_clock ('PAW_dxc_pot')
|
|
|
|
RETURN
|
|
END SUBROUTINE PAW_dxc_potential
|
|
!
|
|
! add gradient correction to dvxc. Both unpolarized and
|
|
! spin polarized cases are supported.
|
|
!
|
|
SUBROUTINE PAW_dgcxc_potential(i,rho_lm,rho_core, drho_lm, v_lm)
|
|
|
|
USE noncollin_module, ONLY : nspin_mag, nspin_gga
|
|
USE lsda_mod, ONLY : nspin
|
|
USE atom, ONLY : g => rgrid
|
|
USE constants, ONLY : pi,e2, eps => eps12, eps2 => eps24
|
|
USE funct, ONLY : gcxc, gcx_spin, gcc_spin, dgcxc, &
|
|
dgcxc_spin
|
|
!
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
REAL(DP), INTENT(IN) :: rho_lm(i%m,i%l**2,nspin_mag) ! charge density as lm components
|
|
REAL(DP), INTENT(IN) :: drho_lm(i%m,i%l**2,nspin_mag) ! change of charge density as lm components
|
|
REAL(DP), INTENT(IN) :: rho_core(i%m) ! core charge, radial and spherical
|
|
REAL(DP), INTENT(INOUT) :: v_lm(i%m,i%l**2,nspin_mag) ! potential to be updated
|
|
REAL(DP) :: zero(i%m) ! dcore charge, not used
|
|
REAL(DP) :: rho_rad(i%m,nspin_gga)! charge density sampled
|
|
REAL(DP) :: drho_rad(i%m,nspin_gga)! charge density sampled
|
|
REAL(DP) :: grad(i%m,3,nspin_gga) ! gradient
|
|
REAL(DP) :: grad2(i%m,nspin_gga) ! square modulus of gradient
|
|
! (first of charge, than of hamiltonian)
|
|
REAL(DP) :: dgrad(i%m,3,nspin_gga) ! gradient
|
|
REAL(DP) :: dgrad2(i%m,nspin_gga) ! square modulus of gradient
|
|
! of dcharge
|
|
REAL(DP) :: gc_rad(i%m,rad(i%t)%nx,nspin_gga) ! GC correction to V (radial samples)
|
|
REAL(DP) :: gc_lm(i%m,i%l**2,nspin_gga) ! GC correction to V (Y_lm expansion)
|
|
REAL(DP) :: h_rad(i%m,3,rad(i%t)%nx,nspin_gga)! hamiltonian (vector field)
|
|
REAL(DP) :: h_lm(i%m,3,(i%l+rad(i%t)%ladd)**2,nspin_gga)! hamiltonian (vector field)
|
|
!!! ^^^^^^^^^^^^^^^^^^ expanded to higher lm than rho !!!
|
|
REAL(DP) :: vout_lm(i%m,i%l**2,nspin_gga) ! potential to be updated
|
|
REAL(DP) :: rhoout_lm(i%m,i%l**2,nspin_gga) ! change of charge density as lm components
|
|
REAL(DP) :: drhoout_lm(i%m,i%l**2,nspin_gga) ! change of charge density as lm components
|
|
REAL(DP) :: segni_rad(i%m, rad(i%t)%nx)
|
|
|
|
REAL(DP) :: div_h(i%m,i%l**2,nspin_gga) ! div(hamiltonian)
|
|
|
|
|
|
INTEGER :: k, ix, is, lm ! counters on spin and mesh
|
|
REAL(DP) :: sx,sc,v1x,v2x,v1c,v2c ! workspace
|
|
REAL(DP) :: v1xup, v1xdw, v2xup, v2xdw, v1cup, v1cdw ! workspace
|
|
REAL(DP) :: vrrx,vsrx,vssx,vrrc,vsrc,vssc ! workspace
|
|
REAL(DP) :: dvxc_rr, dvxc_sr, dvxc_ss, dvxc_s ! workspace
|
|
REAL(DP) :: vrrxup, vrrxdw, vrsxup, vrsxdw, vssxup, vssxdw, &
|
|
vrrcup, vrrcdw, vrscup, vrscdw, vrzcup, vrzcdw
|
|
REAL(DP) :: dsvxc_rr(2,2), dsvxc_sr(2,2), &
|
|
dsvxc_ss(2,2), dsvxc_s(2,2) ! workspace
|
|
REAL(DP) :: a(2,2,2), b(2,2,2,2), c(2,2,2)
|
|
REAL(DP) :: arho, s1 ! workspace
|
|
REAL(DP) :: rup, rdw, co2 ! workspace
|
|
REAL(DP) :: rh, zeta, grh2
|
|
REAL(DP) :: grho(3,2), ps(2,2), ps1(3,2,2), ps2(3,2,2,2)
|
|
INTEGER :: js, ls, ks, ipol
|
|
|
|
if(TIMING) CALL start_clock ('PAW_dgcxc_v')
|
|
|
|
zero=0.0_DP
|
|
gc_rad=0.0_DP
|
|
h_rad=0.0_DP
|
|
vout_lm=0.0_DP
|
|
IF ( nspin_mag == 1 ) THEN
|
|
!
|
|
! GGA case - no spin polarization
|
|
!
|
|
DO ix = ix_s, ix_e
|
|
!
|
|
CALL PAW_lm2rad(i, ix, rho_lm, rho_rad, nspin_mag)
|
|
CALL PAW_gradient(i, ix, rho_lm, rho_rad, rho_core, grad2, grad)
|
|
CALL PAW_lm2rad(i, ix, drho_lm, drho_rad, nspin_mag)
|
|
CALL PAW_gradient(i, ix, drho_lm, drho_rad, zero, dgrad2, dgrad)
|
|
DO k = 1, i%m
|
|
! arho is the absolute value of real charge, sgn is its sign
|
|
arho = rho_rad(k,1)*g(i%t)%rm2(k) + rho_core(k)
|
|
arho = ABS(arho)
|
|
s1 = grad (k, 1, 1) * dgrad(k, 1, 1) + &
|
|
grad (k, 2, 1) * dgrad(k, 2, 1) + &
|
|
grad (k, 3, 1) * dgrad(k, 3, 1)
|
|
|
|
! I am using grad(rho)**2 here, so its eps has to be eps**2
|
|
IF ( (arho>eps) .and. (grad2(k,1)>eps2) ) THEN
|
|
CALL gcxc(arho,grad2(k,1),sx,sc,v1x,v2x,v1c,v2c)
|
|
CALL dgcxc(arho,grad2(k,1),vrrx,vsrx,vssx,vrrc,vsrc,vssc)
|
|
dvxc_rr = vrrx + vrrc
|
|
dvxc_sr = vsrx + vsrc
|
|
dvxc_ss = vssx + vssc
|
|
dvxc_s = v2x + v2c
|
|
gc_rad(k,ix,1) = dvxc_rr*drho_rad(k, 1)*g(i%t)%rm2(k) &
|
|
+ dvxc_sr*s1
|
|
h_rad(k,:,ix,1) = ((dvxc_sr*drho_rad(k, 1)*g(i%t)%rm2(k) + &
|
|
dvxc_ss*s1)*grad(k,:, 1) + &
|
|
dvxc_s*dgrad(k,:,1))*g(i%t)%r2(k)
|
|
ELSE
|
|
gc_rad(k,ix,1) = 0._dp
|
|
h_rad(k,:,ix,1) = 0._dp
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ELSEIF ( nspin_mag == 2 .OR. nspin_mag == 4 ) THEN
|
|
!
|
|
! \sigma-GGA case - spin polarization
|
|
!
|
|
IF (nspin_mag==4) THEN
|
|
CALL compute_drho_spin_lm(i, rho_lm, drho_lm, rhoout_lm, &
|
|
drhoout_lm, segni_rad)
|
|
ELSE
|
|
rhoout_lm=rho_lm
|
|
drhoout_lm=drho_lm
|
|
ENDIF
|
|
|
|
DO ix = ix_s, ix_e
|
|
!
|
|
CALL PAW_lm2rad(i, ix, rhoout_lm, rho_rad, nspin_gga)
|
|
CALL PAW_gradient(i, ix, rhoout_lm, rho_rad, rho_core, &
|
|
grad2, grad)
|
|
CALL PAW_lm2rad(i, ix, drhoout_lm, drho_rad, nspin_gga)
|
|
CALL PAW_gradient(i, ix, drhoout_lm, drho_rad, zero, dgrad2, dgrad)
|
|
!
|
|
DO k = 1,i%m
|
|
!
|
|
! Prepare the necessary quantities
|
|
! rho_core is considered half spin up and half spin down:
|
|
co2 = rho_core(k)/DBLE(nspin_gga)
|
|
rup = rho_rad(k,1)*g(i%t)%rm2(k) + co2
|
|
rdw = rho_rad(k,2)*g(i%t)%rm2(k) + co2
|
|
CALL gcx_spin (rup, rdw, grad2(k,1), grad2(k,2), &
|
|
sx, v1xup, v1xdw, v2xup, v2xdw)
|
|
grho(:,:)=grad(k,:,:)
|
|
CALL dgcxc_spin (rup, rdw, grho (1,1), grho (1, 2), vrrxup, &
|
|
vrrxdw, vrsxup, vrsxdw, vssxup, vssxdw, &
|
|
vrrcup, vrrcdw, vrscup, vrscdw, vssc, vrzcup, vrzcdw)
|
|
|
|
rh = rup + rdw ! total charge
|
|
IF ( rh > eps ) THEN
|
|
zeta = (rup - rdw ) / rh ! polarization
|
|
!
|
|
grh2 = (grad(k,1,1) + grad(k,1,2))**2 &
|
|
+ (grad(k,2,1) + grad(k,2,2))**2 &
|
|
+ (grad(k,3,1) + grad(k,3,2))**2
|
|
CALL gcc_spin (rh, zeta, grh2, sc, v1cup, v1cdw, v2c)
|
|
dsvxc_rr (1, 1) = vrrxup + vrrcup + vrzcup *(1.d0 - zeta) / rh
|
|
dsvxc_rr (1, 2) = vrrcup - vrzcup * (1.d0 + zeta) / rh
|
|
dsvxc_rr (2, 1) = vrrcdw + vrzcdw * (1.d0 - zeta) / rh
|
|
dsvxc_rr (2, 2) = vrrxdw + vrrcdw - vrzcdw *(1.d0 + zeta) / rh
|
|
dsvxc_s (1, 1) = v2xup + v2c
|
|
dsvxc_s (1, 2) = v2c
|
|
dsvxc_s (2, 1) = v2c
|
|
dsvxc_s (2, 2) = v2xdw + v2c
|
|
ELSE
|
|
sc = 0._DP
|
|
v1cup = 0._DP
|
|
v1cdw = 0._DP
|
|
v2c = 0._DP
|
|
dsvxc_rr = 0._DP
|
|
dsvxc_s = 0._DP
|
|
ENDIF
|
|
dsvxc_sr (1, 1) = vrsxup + vrscup
|
|
dsvxc_sr (1, 2) = vrscup
|
|
dsvxc_sr (2, 1) = vrscdw
|
|
dsvxc_sr (2, 2) = vrsxdw + vrscdw
|
|
dsvxc_ss (1, 1) = vssxup + vssc
|
|
dsvxc_ss (1, 2) = vssc
|
|
dsvxc_ss (2, 1) = vssc
|
|
dsvxc_ss (2, 2) = vssxdw + vssc
|
|
ps (:,:) = (0._DP, 0._DP)
|
|
DO is = 1, nspin_gga
|
|
DO js = 1, nspin_gga
|
|
ps1(:, is, js)=drho_rad(k,is)*g(i%t)%rm2(k)*grad(k,:,js)
|
|
DO ipol=1,3
|
|
ps(is, js)=ps(is,js)+grad(k,ipol,is)*dgrad(k,ipol,js)
|
|
ENDDO
|
|
DO ks = 1, nspin_gga
|
|
IF (is == js .AND. js == ks) THEN
|
|
a (is, js, ks) = dsvxc_sr (is, is)
|
|
c (is, js, ks) = dsvxc_sr (is, is)
|
|
ELSE
|
|
IF (is == 1) THEN
|
|
a (is, js, ks) = dsvxc_sr (1, 2)
|
|
ELSE
|
|
a (is, js, ks) = dsvxc_sr (2, 1)
|
|
ENDIF
|
|
IF (js == 1) THEN
|
|
c (is, js, ks) = dsvxc_sr (1, 2)
|
|
ELSE
|
|
c (is, js, ks) = dsvxc_sr (2, 1)
|
|
ENDIF
|
|
ENDIF
|
|
ps2 (:, is, js, ks) = ps (is, js) * grad (k,:,ks)
|
|
DO ls = 1, nspin_gga
|
|
IF (is == js .AND. js == ks .AND. ks == ls) THEN
|
|
b (is, js, ks, ls) = dsvxc_ss (is, is)
|
|
ELSE
|
|
IF (is == 1) THEN
|
|
b (is, js, ks, ls) = dsvxc_ss (1, 2)
|
|
ELSE
|
|
b (is, js, ks, ls) = dsvxc_ss (2, 1)
|
|
ENDIF
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
DO is = 1, nspin_gga
|
|
DO js = 1, nspin_gga
|
|
gc_rad(k,ix,is) = gc_rad(k,ix,is)+ dsvxc_rr (is,js) &
|
|
*drho_rad(k, js)*g(i%t)%rm2(k)
|
|
h_rad(k,:,ix,is) = h_rad(k,:,ix,is) + &
|
|
dsvxc_s (is,js) * dgrad(k,:,js)
|
|
DO ks = 1, nspin_gga
|
|
gc_rad(k,ix,is) = gc_rad(k,ix,is)+a(is,js,ks)*ps(js,ks)
|
|
h_rad(k,:,ix,is) = h_rad(k,:,ix,is) + &
|
|
c (is, js, ks) * ps1 (:, js, ks)
|
|
DO ls = 1, nspin_gga
|
|
h_rad(k,:,ix,is) = h_rad(k,:,ix,is) + &
|
|
b (is, js, ks, ls) * ps2 (:, js, ks, ls)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
h_rad(k,:,ix,:)=h_rad(k,:,ix,:)*g(i%t)%r2(k)
|
|
ENDDO ! k
|
|
ENDDO ! ix
|
|
ELSE
|
|
CALL errore('PAW_gcxc_v', 'unknown spin number', 2)
|
|
ENDIF
|
|
!
|
|
! convert the first part of the GC correction back to spherical harmonics
|
|
CALL PAW_rad2lm(i, gc_rad, gc_lm, i%l, nspin_gga)
|
|
!
|
|
! We need the divergence of h to calculate the last part of the exchange
|
|
! and correlation potential. First we have to convert H to its Y_lm expansion
|
|
DO ix = ix_s, ix_e
|
|
h_rad(1:i%m,3,ix,1:nspin_gga)=h_rad(1:i%m,3,ix,1:nspin_gga)&
|
|
/rad(i%t)%sin_th(ix)
|
|
ENDDO
|
|
|
|
CALL PAW_rad2lm3(i, h_rad, h_lm, i%l+rad(i%t)%ladd, nspin_gga)
|
|
!
|
|
! Compute div(H)
|
|
CALL PAW_divergence(i, h_lm, div_h, i%l+rad(i%t)%ladd, i%l)
|
|
! input max lm --^ ^-- output max lm
|
|
! Finally sum it back into v_xc
|
|
DO is = 1,nspin_gga
|
|
DO lm = 1,i%l**2
|
|
vout_lm(1:i%m,lm,is) = vout_lm(1:i%m,lm,is) + &
|
|
e2*(gc_lm(1:i%m,lm,is)-div_h(1:i%m,lm,is))
|
|
ENDDO
|
|
ENDDO
|
|
!
|
|
! In the noncollinear case we have to calculate the four components of
|
|
! the potential
|
|
!
|
|
IF (nspin_mag == 4 ) THEN
|
|
CALL compute_dpot_nonc(i,vout_lm,v_lm,segni_rad,rho_lm,drho_lm)
|
|
ELSE
|
|
v_lm(:,:,1:nspin_mag)=v_lm(:,:,1:nspin_mag)+vout_lm(:,:,1:nspin_mag)
|
|
ENDIF
|
|
|
|
if(TIMING) CALL stop_clock ('PAW_dgcxc_v')
|
|
|
|
END SUBROUTINE PAW_dgcxc_potential
|
|
!
|
|
SUBROUTINE compute_rho_spin_lm(i,rho_lm,rhoout_lm,segni_rad)
|
|
!
|
|
! This subroutine diagonalizes the spin density matrix and gives
|
|
! the spin-up and spin-down components of the charge. In input
|
|
! the spin_density is decomposed into the lm components and in
|
|
! output the spin-up and spin-down densities are decomposed into
|
|
! the lm components. segni_rad is an output variable with the sign
|
|
! of the direction of the magnetization in each point.
|
|
!
|
|
USE kinds, ONLY : dp
|
|
USE constants, ONLY: eps12
|
|
USE lsda_mod, ONLY : nspin
|
|
USE noncollin_module, ONLY : ux, nspin_gga, nspin_mag
|
|
USE uspp_param, ONLY : upf
|
|
USE atom, ONLY : g => rgrid
|
|
USE io_global, ONLY : stdout
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i
|
|
|
|
REAL(DP), INTENT(IN) :: rho_lm(i%m, i%l**2, nspin)
|
|
! input: the four components of the charge
|
|
REAL(DP), INTENT(OUT) :: rhoout_lm(i%m, i%l**2, nspin_gga)
|
|
! output: the spin up and spin down charge
|
|
REAL(DP), INTENT(OUT) :: segni_rad(i%m, rad(i%t)%nx)
|
|
! output: keep track of the spin direction
|
|
|
|
REAL(DP) :: rho_rad(i%m, nspin) ! auxiliary: the charge+mag along a line
|
|
REAL(DP) :: msmall_rad(i%m, nspin) ! auxiliary: the charge+mag along a line
|
|
REAL(DP) :: rhoout_rad(i%m, rad(i%t)%nx, nspin_gga) ! auxiliary: rho up and down along a line
|
|
REAL(DP) :: mag ! modulus of the magnetization
|
|
REAL(DP) :: m(3), hatr(3)
|
|
|
|
INTEGER :: ix, k, ipol, kpol ! counter on mesh points
|
|
|
|
IF (nspin /= 4) CALL errore('compute_rho_spin_lm','called in the wrong case',1)
|
|
|
|
segni_rad=0.0_DP
|
|
|
|
DO ix = ix_s, ix_e
|
|
CALL PAW_lm2rad(i, ix, rho_lm, rho_rad, nspin)
|
|
IF (with_small_so) CALL add_small_mag(i,ix,rho_rad)
|
|
DO k=1, i%m
|
|
rho_rad(k, 1:nspin) = rho_rad(k, 1:nspin)*g(i%t)%rm2(k)
|
|
mag = sqrt( rho_rad(k,2)**2 + rho_rad(k,3)**2 + rho_rad(k,4)**2 )
|
|
!
|
|
! Choose rhoup and rhodw depending on the projection of the magnetization
|
|
! on the chosen direction
|
|
!
|
|
IF (mag.LT.eps12) THEN
|
|
segni_rad(k,ix)=1.0_DP
|
|
ELSE
|
|
DO ipol=1,3
|
|
m(ipol)=rho_rad(k,1+ipol)/mag
|
|
ENDDO
|
|
!
|
|
! The axis ux is chosen in the corresponding routine in real space.
|
|
!
|
|
segni_rad(k,ix)=SIGN(1.0_DP, m(1)*ux(1)+m(2)*ux(2)+m(3)*ux(3))
|
|
ENDIF
|
|
rhoout_rad(k, ix, 1)= 0.5d0*( rho_rad(k,1) + segni_rad(k,ix)*mag )* &
|
|
g(i%t)%r2(k)
|
|
rhoout_rad(k, ix, 2)= 0.5d0*( rho_rad(k,1) - segni_rad(k,ix)*mag )* &
|
|
g(i%t)%r2(k)
|
|
ENDDO
|
|
ENDDO
|
|
CALL PAW_rad2lm(i, rhoout_rad, rhoout_lm, i%l, nspin_gga)
|
|
|
|
#ifdef __PARA
|
|
CALL mp_sum( segni_rad, paw_comm )
|
|
#endif
|
|
|
|
RETURN
|
|
END SUBROUTINE compute_rho_spin_lm
|
|
!
|
|
SUBROUTINE compute_pot_nonc(i,vout_lm,v_lm,segni_rad,rho_lm)
|
|
!
|
|
! This subroutine receives the GGA potential for spin up and
|
|
! spin down and calculates the exchange and correlation potential and
|
|
! magnetic field.
|
|
!
|
|
USE kinds, ONLY : dp
|
|
USE constants, ONLY: eps12
|
|
USE lsda_mod, ONLY : nspin
|
|
USE noncollin_module, ONLY : nspin_gga, nspin_mag
|
|
USE uspp_param, ONLY : upf
|
|
USE atom, ONLY : g => rgrid
|
|
USE io_global, ONLY : stdout
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i
|
|
|
|
REAL(DP), INTENT(IN) :: rho_lm(i%m, i%l**2, nspin)
|
|
! input: the charge and magnetization densities
|
|
REAL(DP), INTENT(IN) :: vout_lm(i%m, i%l**2, nspin_gga)
|
|
! input: the spin up and spin down charges
|
|
REAL(DP), INTENT(IN) :: segni_rad(i%m, rad(i%t)%nx)
|
|
! input: keep track of the direction of the magnetization
|
|
REAL(DP), INTENT(OUT) :: v_lm(i%m, i%l**2, nspin)
|
|
! output: the xc potential and magnetic field
|
|
|
|
REAL(DP) :: vsave_lm(i%m, i%l**2, nspin) ! auxiliary: v_lm is updated
|
|
REAL(DP) :: gsave_lm(i%m, i%l**2, nspin) ! auxiliary: g_lm is updated
|
|
|
|
REAL(DP) :: vout_rad(i%m, nspin_gga) ! auxiliary: the potential along a line
|
|
|
|
REAL(DP) :: rho_rad(i%m, nspin) ! auxiliary: the charge+mag along a line
|
|
|
|
REAL(DP) :: msmall_rad(i%m, nspin) ! auxiliary: the mag of small components
|
|
! along a line
|
|
REAL(DP) :: v_rad(i%m, rad(i%t)%nx, nspin) ! auxiliary: rho up and down along a line
|
|
REAL(DP) :: g_rad(i%m, rad(i%t)%nx, nspin) ! auxiliary: rho up and down along a line
|
|
REAL(DP) :: mag ! modulus of the magnetization
|
|
|
|
REAL(DP) :: hatr(3) ! modulus of the magnetization
|
|
|
|
integer :: ix, k, ipol, kpol ! counter on mesh points
|
|
|
|
IF (nspin /= 4) CALL errore('compute_pot_nonc','called in the wrong case',1)
|
|
|
|
v_rad=0.0_DP
|
|
IF (upf(i%t)%has_so.and.i%ae==1) g_rad=0.0_DP
|
|
|
|
DO ix = ix_s, ix_e
|
|
CALL PAW_lm2rad(i, ix, vout_lm, vout_rad, nspin_gga)
|
|
CALL PAW_lm2rad(i, ix, rho_lm, rho_rad, nspin_mag)
|
|
IF (with_small_so) CALL add_small_mag(i,ix,rho_rad)
|
|
DO k=1, i%m
|
|
rho_rad(k, 1:nspin) = rho_rad(k, 1:nspin) * g(i%t)%rm2(k)
|
|
mag = sqrt( rho_rad(k,2)**2 + rho_rad(k,3)**2 + rho_rad(k,4)**2 )
|
|
v_rad(k, ix, 1) = 0.5_DP * ( vout_rad(k,1) + vout_rad(k,2) )
|
|
vs_rad(k,ix,i%a) = 0.5_DP * ( vout_rad(k,1) - vout_rad(k,2) )
|
|
!
|
|
! Choose rhoup and rhodw depending on the projection of the magnetization
|
|
! on the chosen direction
|
|
!
|
|
IF (mag.GT.eps12) THEN
|
|
DO ipol=2,4
|
|
v_rad(k, ix, ipol) = vs_rad(k,ix,i%a) * segni_rad(k,ix) * &
|
|
rho_rad(k,ipol) / mag
|
|
ENDDO
|
|
ENDIF
|
|
ENDDO
|
|
IF (with_small_so) CALL compute_g(i,ix,v_rad,g_rad)
|
|
ENDDO
|
|
|
|
CALL PAW_rad2lm(i, v_rad, vsave_lm, i%l, nspin)
|
|
|
|
v_lm=v_lm+vsave_lm
|
|
|
|
IF (with_small_so) THEN
|
|
CALL PAW_rad2lm(i, g_rad, gsave_lm, i%l, nspin)
|
|
g_lm=g_lm+gsave_lm
|
|
ENDIF
|
|
|
|
RETURN
|
|
END SUBROUTINE compute_pot_nonc
|
|
!
|
|
SUBROUTINE compute_drho_spin_lm(i, rho_lm, drho_lm, rhoout_lm, &
|
|
drhoout_lm, segni_rad)
|
|
!
|
|
! This routine receives as input the induced charge and magnetization
|
|
! densities and gives as output the spin up and spin down components of
|
|
! the induced densities
|
|
!
|
|
!
|
|
USE kinds, ONLY : dp
|
|
USE constants, ONLY : eps12
|
|
USE lsda_mod, ONLY : nspin
|
|
USE noncollin_module, ONLY : ux, nspin_gga
|
|
USE atom, ONLY : g => rgrid
|
|
USE io_global, ONLY : stdout
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i
|
|
|
|
REAL(DP), INTENT(IN) :: rho_lm(i%m, i%l**2, nspin)
|
|
! input: the four components of the charge
|
|
REAL(DP), INTENT(IN) :: drho_lm(i%m, i%l**2, nspin)
|
|
! input: the four components of the induced charge
|
|
REAL(DP), INTENT(OUT) :: rhoout_lm(i%m, i%l**2, nspin_gga)
|
|
! output: the spin up and spin down charge
|
|
REAL(DP), INTENT(OUT) :: drhoout_lm(i%m, i%l**2, nspin_gga)
|
|
! output: the induced spin-up and spin-down charge
|
|
REAL(DP), INTENT(OUT) :: segni_rad(i%m, rad(i%t)%nx)
|
|
! output: keep track of the magnetization direction
|
|
|
|
REAL(DP) :: rho_rad(i%m, nspin) ! auxiliary: the charge+mag along a line
|
|
REAL(DP) :: drho_rad(i%m, nspin) ! auxiliary: the induced ch+mag along a line
|
|
REAL(DP) :: rhoout_rad(i%m, rad(i%t)%nx, nspin_gga) ! auxiliary: rho up and down along a line
|
|
REAL(DP) :: drhoout_rad(i%m, rad(i%t)%nx, nspin_gga) ! auxiliary: the charge of the charge+mag along a line
|
|
REAL(DP) :: mag ! modulus of the magnetization
|
|
REAL(DP) :: prod
|
|
REAL(DP) :: m(3)
|
|
|
|
integer :: ix, k, ipol ! counter on mesh points
|
|
|
|
IF (nspin /= 4) CALL errore('compute_drho_spin_lm','called in the wrong case',1)
|
|
|
|
DO ix = ix_s, ix_e
|
|
CALL PAW_lm2rad(i, ix, rho_lm, rho_rad, nspin)
|
|
CALL PAW_lm2rad(i, ix, drho_lm, drho_rad, nspin)
|
|
!
|
|
! Qui manca il pezzo della small component
|
|
!
|
|
DO k=1, i%m
|
|
mag = sqrt( rho_rad(k,2)**2 + rho_rad(k,3)**2 + rho_rad(k,4)**2 )
|
|
!
|
|
! Choose rhoup and rhodw depending on the projection of the magnetization
|
|
! on the chosen direction
|
|
!
|
|
IF (mag*g(i%t)%rm2(k).LT.eps12) THEN
|
|
segni_rad(k,ix)=1.0_DP
|
|
ELSE
|
|
DO ipol=1,3
|
|
m(ipol)=rho_rad(k,1+ipol)/mag
|
|
ENDDO
|
|
!
|
|
! The axis ux is chosen in the corresponding routine in real space.
|
|
!
|
|
segni_rad(k,ix)=sign(1.0_DP, m(1)*ux(1)+m(2)*ux(2)+m(3)*ux(3))
|
|
ENDIF
|
|
rhoout_rad(k, ix, 1)= 0.5d0*( rho_rad(k,1) + segni_rad(k,ix)*mag )
|
|
rhoout_rad(k, ix, 2)= 0.5d0*( rho_rad(k,1) - segni_rad(k,ix)*mag )
|
|
drhoout_rad(k, ix, 1)= 0.5d0 * drho_rad(k,1)
|
|
drhoout_rad(k, ix, 2)= 0.5d0 * drho_rad(k,1)
|
|
IF (mag*g(i%t)%rm2(k)>eps12) THEN
|
|
prod=0.0_DP
|
|
DO ipol=1,3
|
|
prod=prod + m(ipol) * drho_rad(k,ipol+1)
|
|
ENDDO
|
|
prod=0.5_DP * prod
|
|
drhoout_rad(k, ix, 1)= drhoout_rad(k,ix,1) + segni_rad(k,ix) * prod
|
|
drhoout_rad(k, ix, 2)= drhoout_rad(k,ix,2) - segni_rad(k,ix) * prod
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
CALL PAW_rad2lm(i, rhoout_rad, rhoout_lm, i%l, nspin_gga)
|
|
CALL PAW_rad2lm(i, drhoout_rad, drhoout_lm, i%l, nspin_gga)
|
|
|
|
RETURN
|
|
END SUBROUTINE compute_drho_spin_lm
|
|
!
|
|
SUBROUTINE compute_dpot_nonc(i,vout_lm,v_lm,segni_rad,rho_lm,drho_lm)
|
|
!
|
|
! Anche qui manca ancora il pezzo dovuto alla small component.
|
|
! This subroutine receives the GGA potential for spin up and
|
|
! spin down and calculate the effective potential and the effective
|
|
! magnetic field.
|
|
!
|
|
USE kinds, ONLY : dp
|
|
USE constants, ONLY: eps12
|
|
USE lsda_mod, ONLY : nspin
|
|
USE noncollin_module, ONLY : nspin_gga
|
|
USE atom, ONLY : g => rgrid
|
|
USE io_global, ONLY : stdout
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i
|
|
|
|
REAL(DP), INTENT(IN) :: rho_lm(i%m, i%l**2, nspin)
|
|
! input: the four components of the charge
|
|
REAL(DP), INTENT(IN) :: drho_lm(i%m, i%l**2, nspin)
|
|
! input: the four components of the charge
|
|
REAL(DP), INTENT(IN) :: vout_lm(i%m, i%l**2, nspin_gga)
|
|
! output: the spin up and spin down charge
|
|
REAL(DP), INTENT(OUT) :: v_lm(i%m, i%l**2, nspin)
|
|
! output: the spin up and spin down charge
|
|
REAL(DP), INTENT(IN) :: segni_rad(i%m, rad(i%t)%nx)
|
|
! output: keep track of the spin direction
|
|
|
|
REAL(DP) :: vsave_lm(i%m, i%l**2, nspin) ! auxiliary: v_lm is not overwritten
|
|
|
|
REAL(DP) :: vout_rad(i%m, nspin_gga) ! auxiliary: the potential along a line
|
|
|
|
REAL(DP) :: rho_rad(i%m, nspin) ! auxiliary: the charge+mag along a line
|
|
|
|
REAL(DP) :: drho_rad(i%m, nspin) ! auxiliary: the d n along a line
|
|
|
|
REAL(DP) :: v_rad(i%m, rad(i%t)%nx, nspin) ! auxiliary: rho up and down along a line
|
|
REAL(DP) :: mag, dvs, term, term1 ! auxiliary
|
|
|
|
integer :: ix, k, ipol ! counter on mesh points
|
|
|
|
v_rad=0.0_DP
|
|
|
|
DO ix = ix_s, ix_e
|
|
CALL PAW_lm2rad(i, ix, vout_lm, vout_rad, nspin_gga)
|
|
CALL PAW_lm2rad(i, ix, rho_lm, rho_rad, nspin)
|
|
CALL PAW_lm2rad(i, ix, drho_lm, drho_rad, nspin)
|
|
DO k=1, i%m
|
|
!
|
|
! Core charge is not added because we need only the magnetization.
|
|
!
|
|
rho_rad(k, 1:nspin) =rho_rad(k, 1:nspin) * g(i%t)%rm2(k)
|
|
drho_rad(k, 1:nspin) =drho_rad(k, 1:nspin) * g(i%t)%rm2(k)
|
|
mag = sqrt( rho_rad(k,2)**2 + rho_rad(k,3)**2 + rho_rad(k,4)**2 )
|
|
v_rad(k, ix, 1) = 0.5_DP * ( vout_rad(k,1) + vout_rad(k,2) )
|
|
dvs = 0.5_DP * ( vout_rad(k,1) - vout_rad(k,2) )
|
|
!
|
|
! Choose rhoup and rhodw depending on the projection of the magnetization
|
|
! on the chosen direction
|
|
!
|
|
IF (mag.GT.eps12) THEN
|
|
!
|
|
! The axis ux is chosen in the corresponding routine in real space.
|
|
!
|
|
term=0.0_DP
|
|
DO ipol=2,4
|
|
term=term+rho_rad(k,ipol)*drho_rad(k,ipol)
|
|
ENDDO
|
|
DO ipol=2,4
|
|
term1 = term*rho_rad(k,ipol)/mag**2
|
|
v_rad(k, ix, ipol)= segni_rad(k,ix)*( dvs*rho_rad(k,ipol) + &
|
|
vs_rad(k,ix,i%a)*(drho_rad(k,ipol)-term1))/mag
|
|
ENDDO
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
|
|
CALL PAW_rad2lm(i, v_rad, vsave_lm, i%l, nspin)
|
|
|
|
v_lm=v_lm+vsave_lm
|
|
|
|
RETURN
|
|
END SUBROUTINE compute_dpot_nonc
|
|
!
|
|
SUBROUTINE add_small_mag(i, ix, rho_rad)
|
|
|
|
USE noncollin_module, ONLY : nspin_mag
|
|
!
|
|
! This subroutine computes the contribution of the small component to the
|
|
! magnetization in the noncollinear case and adds its to rho_rad.
|
|
! The calculation is done along the radial line ix.
|
|
!
|
|
! NB: Both the input and the output magnetizations are multiplied by
|
|
! r^2.
|
|
!
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
INTEGER, INTENT(IN) :: ix ! the line
|
|
REAL(DP), INTENT(INOUT) :: rho_rad(i%m,nspin_mag) ! the magnetization
|
|
|
|
REAL(DP) :: msmall_rad(i%m, nspin_mag) ! auxiliary: the mag of the small
|
|
! components along a line
|
|
REAL(DP) :: hatr(3)
|
|
INTEGER :: k, ipol, kpol
|
|
|
|
CALL PAW_lm2rad(i, ix, msmall_lm, msmall_rad, nspin_mag)
|
|
hatr(1)=rad(i%t)%sin_th(ix)*rad(i%t)%cos_phi(ix)
|
|
hatr(2)=rad(i%t)%sin_th(ix)*rad(i%t)%sin_phi(ix)
|
|
hatr(3)=rad(i%t)%cos_th(ix)
|
|
|
|
DO k=1,i%m
|
|
DO ipol=1,3
|
|
DO kpol=1,3
|
|
rho_rad(k,ipol+1) = rho_rad(k,ipol+1) - &
|
|
msmall_rad(k,kpol+1) * hatr(ipol) * hatr(kpol) * 2.0_DP
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
|
|
RETURN
|
|
END SUBROUTINE add_small_mag
|
|
!
|
|
SUBROUTINE compute_g(i, ix, v_rad, g_rad)
|
|
!
|
|
! This routine receives as input B_{xc} and calculates the function G
|
|
! described in Phys. Rev. B 82, 075116 (2010). The same routine can
|
|
! be used when v_rad contains the induced B_{xc}. In this case the
|
|
! output is the change of G.
|
|
!
|
|
USE noncollin_module, ONLY : nspin_mag
|
|
|
|
TYPE(paw_info), INTENT(IN) :: i ! atom's minimal info
|
|
INTEGER, INTENT(IN) :: ix ! the line
|
|
REAL(DP), INTENT(IN) :: v_rad(i%m,rad(i%t)%nx,nspin_mag) ! radial pot
|
|
REAL(DP), INTENT(INOUT) :: g_rad(i%m,rad(i%t)%nx,nspin_mag)
|
|
! radial potential (small comp)
|
|
|
|
REAL(DP) :: hatr(3)
|
|
|
|
INTEGER :: k, ipol, kpol
|
|
|
|
hatr(1)=rad(i%t)%sin_th(ix)*rad(i%t)%cos_phi(ix)
|
|
hatr(2)=rad(i%t)%sin_th(ix)*rad(i%t)%sin_phi(ix)
|
|
hatr(3)=rad(i%t)%cos_th(ix)
|
|
|
|
DO k=1, i%m
|
|
DO ipol=1,3
|
|
DO kpol=1,3
|
|
!
|
|
! v_rad contains -B_{xc} with the notation of the papers
|
|
!
|
|
g_rad(k,ix,ipol+1)=g_rad(k,ix,ipol+1) - &
|
|
v_rad(k,ix,kpol+1)*hatr(kpol)*hatr(ipol)*2.0_DP
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
|
|
RETURN
|
|
END SUBROUTINE compute_g
|
|
!
|
|
END MODULE paw_onecenter
|