quantum-espresso/Modules/solvation_lauerism.f90

428 lines
13 KiB
Fortran

!
! Copyright (C) 2016 National Institute of Advanced Industrial Science and Technology (AIST)
! [ This code is written by Satomichi Nishihara. ]
!
! 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 .
!
!---------------------------------------------------------------------------
SUBROUTINE solvation_lauerism(rismt, charge, ireference, ierr)
!---------------------------------------------------------------------------
!
! ... setup charge density, solvation potential and solvation energy for DFT,
! ... which are derived from Laue-RISM.
! ...
! ... outside of the unit-cell, charge density is approximated as
!
! ----
! rho(gxy,z) > q(v) * rho(v) * h(v; gxy,z)
! ----
! v
!
! ... Variables:
! ... charge: total charge of solvent system
! ... ireference: reference position of solvation potential
!
USE cell_base, ONLY : at, alat
USE constants, ONLY : eps8
USE err_rism, ONLY : IERR_RISM_NULL, IERR_RISM_INCORRECT_DATA_TYPE
USE io_global, ONLY : stdout
USE kinds, ONLY : DP
USE lauefft, ONLY : fw_lauefft_2xy
USE mp, ONLY : mp_sum
USE rism, ONLY : rism_type, ITYPE_LAUERISM
USE solvmol, ONLY : get_nuniq_in_solVs, solVs, iuniq_to_nsite, &
& iuniq_to_isite, isite_to_isolV, isite_to_iatom
!
IMPLICIT NONE
!
TYPE(rism_type), INTENT(INOUT) :: rismt
REAL(DP), INTENT(IN) :: charge
INTEGER, INTENT(IN) :: ireference
INTEGER, INTENT(OUT) :: ierr
!
INTEGER :: nq
INTEGER :: iq
INTEGER :: iiq
INTEGER :: iv
INTEGER :: nv
INTEGER :: isolV
INTEGER :: iatom
INTEGER :: irz
INTEGER :: iirz
INTEGER :: igxy
INTEGER :: jgxy
INTEGER :: kgxy
INTEGER :: izright_tail
INTEGER :: izleft_tail
REAL(DP) :: rhov1
REAL(DP) :: rhov2
REAL(DP) :: qv
REAL(DP) :: ntmp
REAL(DP) :: dz
REAL(DP) :: area_xy
REAL(DP) :: vol, dvol
REAL(DP) :: voltmp
REAL(DP) :: fac1
REAL(DP) :: fac2
REAL(DP) :: charge0
REAL(DP) :: chgtmp
REAL(DP) :: rhog0
REAL(DP) :: vsol0
REAL(DP), ALLOCATABLE :: wei(:)
COMPLEX(DP), ALLOCATABLE :: ggz(:,:)
!
REAL(DP), PARAMETER :: RHO_THR = 1.0E-16_DP
REAL(DP), PARAMETER :: RHO_SMEAR = 1.0_DP ! in bohr
REAL(DP), PARAMETER :: WEI_THR = 1.0E-32_DP
COMPLEX(DP), PARAMETER :: C_ZERO = CMPLX(0.0_DP, 0.0_DP, kind=DP)
!
! ... number of sites in solvents
nq = get_nuniq_in_solVs()
!
! ... check data type
IF (rismt%itype /= ITYPE_LAUERISM) THEN
ierr = IERR_RISM_INCORRECT_DATA_TYPE
RETURN
END IF
!
IF (rismt%mp_site%nsite < nq) THEN
ierr = IERR_RISM_INCORRECT_DATA_TYPE
RETURN
END IF
!
IF (rismt%nrzs < rismt%dfft%nr3) THEN
ierr = IERR_RISM_INCORRECT_DATA_TYPE
RETURN
END IF
!
IF (rismt%nrzl < rismt%lfft%nrz) THEN
ierr = IERR_RISM_INCORRECT_DATA_TYPE
RETURN
END IF
!
IF (rismt%nr < rismt%dfft%nnr) THEN
ierr = IERR_RISM_INCORRECT_DATA_TYPE
RETURN
END IF
!
! ... allocate memory
IF(rismt%lfft%nrz > 0) THEN
ALLOCATE(wei(rismt%lfft%nrz))
END IF
IF (rismt%nrzs * rismt%ngxy * rismt%nsite > 0) THEN
ALLOCATE(ggz(rismt%nrzs * rismt%ngxy, rismt%nsite))
END IF
!
! ... set variables
dz = rismt%lfft%zstep * alat
area_xy = ABS(at(1, 1) * at(2, 2) - at(1, 2) * at(2, 1)) * alat * alat
dvol = area_xy * dz
!
! ... gr -> ggz
DO iq = rismt%mp_site%isite_start, rismt%mp_site%isite_end
iiq = iq - rismt%mp_site%isite_start + 1
IF (rismt%nrzs * rismt%ngxy > 0) THEN
ggz(:, iiq) = C_ZERO
END IF
!
IF (rismt%nr > 0 .AND. (rismt%nrzs * rismt%ngxy) > 0) THEN
CALL fw_lauefft_2xy(rismt%lfft, rismt%gr(:, iiq), ggz(:, iiq), rismt%nrzs, 1)
END IF
END DO
!
! ... make nsol, qsol
DO iq = rismt%mp_site%isite_start, rismt%mp_site%isite_end
iiq = iq - rismt%mp_site%isite_start + 1
iv = iuniq_to_isite(1, iq)
nv = iuniq_to_nsite(iq)
isolV = isite_to_isolV(iv)
iatom = isite_to_iatom(iv)
rhov1 = DBLE(nv) * solVs(isolV)%density
rhov2 = DBLE(nv) * solVs(isolV)%subdensity
qv = solVs(isolV)%charge(iatom)
!
rismt%nsol(iiq) = 0.0_DP
rismt%qsol(iiq) = 0.0_DP
!
IF (rismt%lfft%gxystart > 1) THEN
fac1 = rhov1 * dvol
fac2 = rhov2 * dvol
!
ntmp = 0.0_DP
!$omp parallel do default(shared) private(irz) reduction(+:ntmp)
DO irz = 1, (rismt%lfft%izleft_start - 1)
ntmp = ntmp + fac2 * (DBLE(rismt%hsgz(irz, iiq) + rismt%hlgz(irz, iiq)) + 1.0_DP)
END DO
!$omp end parallel do
rismt%nsol(iiq) = rismt%nsol(iiq) + ntmp
rismt%qsol(iiq) = rismt%qsol(iiq) + qv * ntmp
!
ntmp = 0.0_DP
!$omp parallel do default(shared) private(irz, iirz) reduction(+:ntmp)
DO irz = rismt%lfft%izleft_start, rismt%lfft%izleft_gedge
iirz = irz - rismt%lfft%izcell_start + 1
ntmp = ntmp + fac2 * DBLE(ggz(iirz, iiq))
END DO
!$omp end parallel do
rismt%nsol(iiq) = rismt%nsol(iiq) + ntmp
rismt%qsol(iiq) = rismt%qsol(iiq) + qv * ntmp
!
ntmp = 0.0_DP
!$omp parallel do default(shared) private(irz, iirz) reduction(+:ntmp)
DO irz = rismt%lfft%izright_gedge, rismt%lfft%izright_end
iirz = irz - rismt%lfft%izcell_start + 1
ntmp = ntmp + fac1 * DBLE(ggz(iirz, iiq))
END DO
!$omp end parallel do
rismt%nsol(iiq) = rismt%nsol(iiq) + ntmp
rismt%qsol(iiq) = rismt%qsol(iiq) + qv * ntmp
!
ntmp = 0.0_DP
!$omp parallel do default(shared) private(irz) reduction(+:ntmp)
DO irz = (rismt%lfft%izright_end + 1), rismt%lfft%nrz
ntmp = ntmp + fac1 * (DBLE(rismt%hsgz(irz, iiq) + rismt%hlgz(irz, iiq)) + 1.0_DP)
END DO
!$omp end parallel do
rismt%nsol(iiq) = rismt%nsol(iiq) + ntmp
rismt%qsol(iiq) = rismt%qsol(iiq) + qv * ntmp
!
END IF
END DO
!
IF (rismt%nsite > 0) THEN
CALL mp_sum(rismt%nsol, rismt%mp_site%intra_sitg_comm)
CALL mp_sum(rismt%qsol, rismt%mp_site%intra_sitg_comm)
END IF
!
! ... make qtot
rismt%qtot = 0.0_DP
DO iq = rismt%mp_site%isite_start, rismt%mp_site%isite_end
iiq = iq - rismt%mp_site%isite_start + 1
rismt%qtot = rismt%qtot + rismt%qsol(iiq)
END DO
!
CALL mp_sum(rismt%qtot, rismt%mp_site%inter_sitg_comm)
!
! ... make rhog (which is Laue-rep.)
IF (rismt%nrzl * rismt%ngxy > 0) THEN
rismt%rhog(:) = C_ZERO
END IF
!
DO iq = rismt%mp_site%isite_start, rismt%mp_site%isite_end
iiq = iq - rismt%mp_site%isite_start + 1
iv = iuniq_to_isite(1, iq)
nv = iuniq_to_nsite(iq)
isolV = isite_to_isolV(iv)
iatom = isite_to_iatom(iv)
rhov1 = DBLE(nv) * solVs(isolV)%density
rhov2 = DBLE(nv) * solVs(isolV)%subdensity
qv = solVs(isolV)%charge(iatom)
!
DO igxy = 1, rismt%ngxy
jgxy = (igxy - 1) * rismt%nrzl
kgxy = (igxy - 1) * rismt%nrzs
!
!$omp parallel do default(shared) private(irz)
DO irz = 1, (rismt%lfft%izleft_start - 1)
rismt%rhog(irz + jgxy) = rismt%rhog(irz + jgxy) &
& + qv * rhov2 * (rismt%hsgz(irz + jgxy, iiq) + rismt%hlgz(irz + jgxy, iiq))
END DO
!$omp end parallel do
!
!$omp parallel do default(shared) private(irz, iirz)
DO irz = rismt%lfft%izleft_start, rismt%lfft%izleft_gedge
iirz = irz - rismt%lfft%izcell_start + 1
rismt%rhog(irz + jgxy) = rismt%rhog(irz + jgxy) &
& + qv * rhov2 * ggz(iirz + kgxy, iiq)
END DO
!$omp end parallel do
!
!$omp parallel do default(shared) private(irz, iirz)
DO irz = rismt%lfft%izright_gedge, rismt%lfft%izright_end
iirz = irz - rismt%lfft%izcell_start + 1
rismt%rhog(irz + jgxy) = rismt%rhog(irz + jgxy) &
& + qv * rhov1 * ggz(iirz + kgxy, iiq)
END DO
!$omp end parallel do
!
!$omp parallel do default(shared) private(irz)
DO irz = (rismt%lfft%izright_end + 1), rismt%lfft%nrz
rismt%rhog(irz + jgxy) = rismt%rhog(irz + jgxy) &
& + qv * rhov1 * (rismt%hsgz(irz + jgxy, iiq) + rismt%hlgz(irz + jgxy, iiq))
END DO
!$omp end parallel do
!
END DO
END DO
!
IF (rismt%nrzl * rismt%ngxy > 0) THEN
CALL mp_sum(rismt%rhog, rismt%mp_site%inter_sitg_comm)
END IF
!
! ... detect truncating positions
izright_tail = 0
izleft_tail = 0
!
IF (rismt%lfft%gxystart > 1) THEN
izleft_tail = 1
DO irz = 1, rismt%lfft%izleft_gedge
IF (ABS(rismt%rhog(irz)) > RHO_THR) THEN
izleft_tail = irz
EXIT
END IF
END DO
!
izright_tail = rismt%lfft%nrz
DO irz = rismt%lfft%izright_gedge, rismt%lfft%nrz
iirz = rismt%lfft%nrz + rismt%lfft%izright_gedge - irz
IF (ABS(rismt%rhog(iirz)) > RHO_THR) THEN
izright_tail = iirz
EXIT
END IF
END DO
!
END IF
!
CALL mp_sum(izright_tail, rismt%mp_site%intra_sitg_comm)
CALL mp_sum(izleft_tail, rismt%mp_site%intra_sitg_comm)
!
! ... calculate weight
IF(rismt%lfft%nrz > 0) THEN
wei = 0.0_DP
END IF
!
!$omp parallel do default(shared) private(irz)
DO irz = 1, rismt%lfft%izleft_gedge
wei(irz) = 0.5_DP * erfc(DBLE(izleft_tail - irz ) * dz / RHO_SMEAR)
IF (wei(irz) < WEI_THR) THEN
wei(irz) = 0.0_DP
END IF
END DO
!$omp end parallel do
!
!$omp parallel do default(shared) private(irz)
DO irz = rismt%lfft%izright_gedge, rismt%lfft%nrz
wei(irz) = 0.5_DP * erfc(DBLE(irz - izright_tail) * dz / RHO_SMEAR)
IF (wei(irz) < WEI_THR) THEN
wei(irz) = 0.0_DP
END IF
END DO
!$omp end parallel do
!
! ... evaluate volume
vol = 0.0_DP
!
IF (rismt%lfft%gxystart > 1) THEN
!
voltmp = 0.0_DP
!$omp parallel do default(shared) private(irz) reduction(+:voltmp)
DO irz = 1, rismt%lfft%izleft_gedge
voltmp = voltmp + dvol * wei(irz)
END DO
!$omp end parallel do
vol = vol + voltmp
!
voltmp = 0.0_DP
!$omp parallel do default(shared) private(irz) reduction(+:voltmp)
DO irz = rismt%lfft%izright_gedge, rismt%lfft%nrz
voltmp = voltmp + dvol * wei(irz)
END DO
!$omp end parallel do
vol = vol + voltmp
!
END IF
!
CALL mp_sum(vol, rismt%mp_site%intra_sitg_comm)
!
! ... evaluate total charge
charge0 = 0.0_DP
!
IF (rismt%lfft%gxystart > 1) THEN
!
chgtmp = 0.0_DP
!$omp parallel do default(shared) private(irz) reduction(+:chgtmp)
DO irz = 1, rismt%lfft%izleft_gedge
chgtmp = chgtmp + dvol * wei(irz) * rismt%rhog(irz)
END DO
!$omp end parallel do
charge0 = charge0 + chgtmp
!
chgtmp = 0.0_DP
!$omp parallel do default(shared) private(irz) reduction(+:chgtmp)
DO irz = rismt%lfft%izright_gedge, rismt%lfft%nrz
chgtmp = chgtmp + dvol * wei(irz) * rismt%rhog(irz)
END DO
!$omp end parallel do
charge0 = charge0 + chgtmp
!
END IF
!
CALL mp_sum(charge0, rismt%mp_site%intra_sitg_comm)
!
! ... renormalize rhog
IF (rismt%lfft%gxystart > 1) THEN
IF (ABS(vol) <= eps8) THEN ! will not be occurred
CALL errore('solvation_lauerism', 'vol is zero', 1)
END IF
rhog0 = (charge - charge0) / vol
!
!$omp parallel do default(shared) private(irz)
DO irz = 1, rismt%lfft%izleft_gedge
rismt%rhog(irz) = (rismt%rhog(irz) + CMPLX(rhog0, 0.0_DP, kind=DP)) * wei(irz)
END DO
!$omp end parallel do
!
!$omp parallel do default(shared) private(irz)
DO irz = rismt%lfft%izright_gedge, rismt%lfft%nrz
rismt%rhog(irz) = (rismt%rhog(irz) + CMPLX(rhog0, 0.0_DP, kind=DP)) * wei(irz)
END DO
!$omp end parallel do
!
END IF
!
WRITE(stdout, '(/,5X,"solvent charge ",F10.5, &
& ", renormalised to ",F10.5)') charge0, charge
!
! ... make vpot
CALL solvation_esm_potential(rismt, ireference, vsol0, ierr)
IF (ierr /= IERR_RISM_NULL) THEN
RETURN
END IF
!
! ... make rhog_pbc and vpot_pbc
CALL solvation_pbc(rismt, ierr)
IF (ierr /= IERR_RISM_NULL) THEN
RETURN
END IF
!
! ... make esol
rismt%esol = 0.0_DP
!
DO iq = rismt%mp_site%isite_start, rismt%mp_site%isite_end
iiq = iq - rismt%mp_site%isite_start + 1
! this version only supports G.F.
!rismt%esol = rismt%esol + rismt%usol(iiq)
rismt%esol = rismt%esol + rismt%usol_GF(iiq)
END DO
!
CALL mp_sum(rismt%esol, rismt%mp_site%inter_sitg_comm)
!
! ... make vsol (reference level shifting)
rismt%vsol = vsol0
!
! ... deallocate memory
IF(rismt%lfft%nrz > 0) THEN
DEALLOCATE(wei)
END IF
IF (rismt%nrzs * rismt%ngxy * rismt%nsite > 0) THEN
DEALLOCATE(ggz)
END IF
!
! ... normally done
ierr = IERR_RISM_NULL
!
END SUBROUTINE solvation_lauerism