quantum-espresso/Modules/eqn_lauevoid.f90

577 lines
17 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 eqn_lauevoid(rismt, lboth, expand, ierr)
!---------------------------------------------------------------------------
!
! ... solve Laue-RISM equation from void-region, which is defined as
! ...
! ... /
! ... h1(gxy=0,z1) = | dz2 c2(gxy=0,z2) * x21(gxy=0,z2-z1)
! ... /void-region
! ...
! ... void-region is in right-hand side, left-hand side or between right- and left-hand side,
! ... where solvents does not exist and c2 is linear function.
! ... calculated total correlations are added to `hgz' or `hsgz'.
! ...
!
USE err_rism, ONLY : IERR_RISM_NULL, IERR_RISM_INCORRECT_DATA_TYPE
USE rism, ONLY : rism_type, ITYPE_LAUERISM
USE solvmol, ONLY : get_nuniq_in_solVs
!
IMPLICIT NONE
!
TYPE(rism_type), INTENT(INOUT) :: rismt
LOGICAL, INTENT(IN) :: lboth ! both-hands calculation, or not
LOGICAL, INTENT(IN) :: expand ! expand-cell(.TRUE.) or unit-cell(.FALSE.)
INTEGER, INTENT(OUT) :: ierr
!
INTEGER :: nq
!
! ... 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%lfft%xright .AND. rismt%lfft%xleft) THEN
!
! ... void-region is between right- and left-hand side
CALL eqn_lauevoid_between(rismt, lboth, expand)
!
ELSE
!
! ... void-region is right-hand side or left-hand side
CALL eqn_lauevoid_oneside(rismt, expand)
!
END IF
!
ierr = IERR_RISM_NULL
!
END SUBROUTINE eqn_lauevoid
!
!---------------------------------------------------------------------------
SUBROUTINE eqn_lauevoid_oneside(rismt, expand)
!---------------------------------------------------------------------------
!
! ... Laue-RISM equation from void-region of right-hand side or left-hand side.
!
USE cell_base, ONLY : alat
USE constants, ONLY : K_BOLTZMANN_RY
USE kinds, ONLY : DP
USE mp, ONLY : mp_sum
USE rism, ONLY : rism_type
USE solvmol, ONLY : solVs, get_nuniq_in_solVs, &
& iuniq_to_isite, isite_to_isolV, isite_to_iatom
!
IMPLICIT NONE
!
TYPE(rism_type), INTENT(INOUT) :: rismt
LOGICAL, INTENT(IN) :: expand ! expand-cell(.TRUE.) or unit-cell(.FALSE.)
!
INTEGER :: nq
INTEGER :: iq1, iq2
INTEGER :: iiq1, iiq2
INTEGER :: iv2
INTEGER :: isolV2
INTEGER :: iatom2
INTEGER :: iz
INTEGER :: izsta
INTEGER :: izend
INTEGER :: izsolv
INTEGER :: izvoid
INTEGER :: nzint
INTEGER :: izint
INTEGER :: izdelt
REAL(DP) :: beta
REAL(DP) :: qv2
REAL(DP) :: z
REAL(DP) :: zstep
REAL(DP) :: zoffs
REAL(DP) :: zedge
REAL(DP) :: voppo
REAL(DP) :: vsign
REAL(DP) :: cz
REAL(DP) :: dz
REAL(DP), ALLOCATABLE :: c2(:)
REAL(DP), ALLOCATABLE :: d2(:)
REAL(DP), ALLOCATABLE :: h1(:)
!
! ... number of sites in solvents
nq = get_nuniq_in_solVs()
!
! ... beta = 1 / (kB * T)
beta = 1.0_DP / K_BOLTZMANN_RY / rismt%temp
!
! ... set integral regions as index of long Z-stick (i.e. expanded cell)
IF (rismt%lfft%xright) THEN
IF (expand) THEN
izsta = rismt%lfft%izright_gedge
izend = rismt%lfft%nrz
ELSE
izsta = rismt%lfft%izright_start0
izend = rismt%lfft%izright_end0
END IF
!
izsolv = rismt%lfft%izright_start0
izvoid = izsolv - 1
!
IF (rismt%lfft%gxystart > 1) THEN
voppo = DBLE(rismt%vleft(1)) / alat
ELSE
voppo = 0.0_DP
END IF
!
vsign = -1.0_DP
!
ELSE !IF (rismt%lfft%xleft) THEN
IF (expand) THEN
izsta = 1
izend = rismt%lfft%izleft_gedge
ELSE
izsta = rismt%lfft%izleft_start0
izend = rismt%lfft%izleft_end0
END IF
!
izsolv = rismt%lfft%izleft_end0
izvoid = izsolv + 1
!
IF (rismt%lfft%gxystart > 1) THEN
voppo = DBLE(rismt%vright(1)) / alat
ELSE
voppo = 0.0_DP
END IF
!
vsign = +1.0_DP
END IF
!
! ... count integral points along Z
nzint = izend - izsta + 1
!
! ... properties about length (in a.u.)
zstep = alat * rismt%lfft%zstep
zoffs = alat * (rismt%lfft%zleft + rismt%lfft%zoffset)
zedge = zoffs + zstep * DBLE(izsolv - 1)
!
! ... allocate working memory
IF (rismt%nsite > 0) THEN
ALLOCATE(c2(rismt%nsite))
ALLOCATE(d2(rismt%nsite))
END IF
IF (nzint > 0) THEN
ALLOCATE(h1(nzint))
END IF
!
! ... calculate c2, d2
DO iq2 = rismt%mp_site%isite_start, rismt%mp_site%isite_end
iiq2 = iq2 - rismt%mp_site%isite_start + 1
iv2 = iuniq_to_isite(1, iq2)
isolV2 = isite_to_isolV(iv2)
iatom2 = isite_to_iatom(iv2)
qv2 = solVs(isolV2)%charge(iatom2)
!
IF (rismt%lfft%gxystart > 1) THEN
c2(iiq2) = rismt%csdg0(izsolv, iiq2) &
& - beta * qv2 * DBLE(rismt%vlgz(izsolv))
d2(iiq2) = -beta * qv2 * voppo
ELSE
c2(iiq2) = 0.0_DP
d2(iiq2) = 0.0_DP
END IF
END DO
!
IF (rismt%nsite > 0) THEN
CALL mp_sum(c2, rismt%mp_site%intra_sitg_comm)
CALL mp_sum(d2, rismt%mp_site%intra_sitg_comm)
END IF
!
! ... Laue-RISM equation of void-region
DO iq1 = 1, nq
IF (rismt%mp_site%isite_start <= iq1 .AND. iq1 <= rismt%mp_site%isite_end) THEN
iiq1 = iq1 - rismt%mp_site%isite_start + 1
ELSE
iiq1 = 0
END IF
!
IF (nzint > 0) THEN
h1 = 0.0_DP
END IF
!
DO iq2 = rismt%mp_site%isite_start, rismt%mp_site%isite_end
iiq2 = iq2 - rismt%mp_site%isite_start + 1
!
! ... h1(z1)
!$omp parallel do default(shared) private(iz, izint, izdelt, z, cz, dz)
DO iz = izsta, izend
izint = iz - izsta + 1
izdelt = ABS(iz - izvoid) + 1
!
IF (izdelt <= rismt%lfft%nrz) THEN
z = zoffs + zstep * DBLE(iz - 1)
cz = c2(iiq2) + d2(iiq2) * (z - zedge)
dz = d2(iiq2) * vsign
h1(izint) = h1(izint) &
& + cz * rismt%xgs0(izdelt, iiq2, iq1) &
& + dz * rismt%xgs1(izdelt, iiq2, iq1)
END IF
END DO
!$omp end parallel do
END DO
!
IF (nzint > 0) THEN
CALL mp_sum(h1, rismt%mp_site%inter_sitg_comm)
END IF
!
IF (iiq1 > 0) THEN
IF (expand) THEN
! ... add h1 -> hsgz
IF (rismt%lfft%gxystart > 1) THEN
!$omp parallel do default(shared) private(iz, izint)
DO iz = izsta, izend
izint = iz - izsta + 1
rismt%hsgz(iz, iiq1) = rismt%hsgz(iz, iiq1) + CMPLX(h1(izint), 0.0_DP, kind=DP)
END DO
!$omp end parallel do
END IF
!
ELSE
! ... add h1 -> hg0
!$omp parallel do default(shared) private(iz, izint)
DO iz = izsta, izend
izint = iz - izsta + 1
rismt%hg0(iz, iiq1) = rismt%hg0(iz, iiq1) + h1(izint)
END DO
!$omp end parallel do
END IF
END IF
!
END DO
!
! ... deallocate working memory
IF (rismt%nsite > 0) THEN
DEALLOCATE(c2)
DEALLOCATE(d2)
END IF
IF (nzint > 0) THEN
DEALLOCATE(h1)
END IF
!
END SUBROUTINE eqn_lauevoid_oneside
!
!---------------------------------------------------------------------------
SUBROUTINE eqn_lauevoid_between(rismt, lboth, expand)
!---------------------------------------------------------------------------
!
! ... Laue-RISM equation from void-region between right- and left-hand side.
!
USE cell_base, ONLY : alat
USE constants, ONLY : K_BOLTZMANN_RY
USE kinds, ONLY : DP
USE mp, ONLY : mp_sum
USE rism, ONLY : rism_type
USE solvmol, ONLY : solVs, get_nuniq_in_solVs, &
& iuniq_to_isite, isite_to_isolV, isite_to_iatom
!
IMPLICIT NONE
!
TYPE(rism_type), INTENT(INOUT) :: rismt
LOGICAL, INTENT(IN) :: lboth ! both-hands calculation, or not
LOGICAL, INTENT(IN) :: expand ! expand-cell(.TRUE.) or unit-cell(.FALSE.)
!
INTEGER :: nq
INTEGER :: iq1, iq2
INTEGER :: iiq1, iiq2
INTEGER :: iv2
INTEGER :: isolV2
INTEGER :: iatom2
INTEGER :: iz
INTEGER :: nzright
INTEGER :: izright_sta
INTEGER :: izright_end
INTEGER :: izright_solv
INTEGER :: izright_void
INTEGER :: nzleft
INTEGER :: izleft_sta
INTEGER :: izleft_end
INTEGER :: izleft_solv
INTEGER :: izleft_void
INTEGER :: izint
INTEGER :: izdelt1
INTEGER :: izdelt2
REAL(DP) :: beta
REAL(DP) :: qv2
REAL(DP) :: z
REAL(DP) :: zstep
REAL(DP) :: zoffs
REAL(DP) :: zright_edge
REAL(DP) :: zleft_edge
REAL(DP) :: c2, cz
REAL(DP) :: d2, dz
REAL(DP), ALLOCATABLE :: xg0(:)
REAL(DP), ALLOCATABLE :: xg1(:)
REAL(DP), ALLOCATABLE :: cright(:)
REAL(DP), ALLOCATABLE :: cleft(:)
REAL(DP), ALLOCATABLE :: hright(:)
REAL(DP), ALLOCATABLE :: hleft(:)
!
! ... has void-region ?
IF ((rismt%lfft%izright_start0 - rismt%lfft%izleft_end0) <= 1) THEN
RETURN
END IF
!
! ... number of sites in solvents
nq = get_nuniq_in_solVs()
!
! ... beta = 1 / (kB * T)
beta = 1.0_DP / K_BOLTZMANN_RY / rismt%temp
!
! ... set integral regions as index of long Z-stick (i.e. expanded cell)
IF (expand) THEN
izright_sta = rismt%lfft%izright_gedge
izright_end = rismt%lfft%nrz
izleft_sta = 1
izleft_end = rismt%lfft%izleft_gedge
ELSE
izright_sta = rismt%lfft%izright_start0
izright_end = rismt%lfft%izright_end0
izleft_sta = rismt%lfft%izleft_start0
izleft_end = rismt%lfft%izleft_end0
END IF
!
izright_solv = rismt%lfft%izright_start0
izright_void = izright_solv - 1
izleft_solv = rismt%lfft%izleft_end0
izleft_void = izleft_solv + 1
!
! ... count integral points along Z
nzright = izright_end - izright_sta + 1
nzleft = izleft_end - izleft_sta + 1
!
! ... properties about length (in a.u.)
zstep = alat * rismt%lfft%zstep
zoffs = alat * (rismt%lfft%zleft + rismt%lfft%zoffset)
!
zright_edge = zoffs + zstep * DBLE(izright_solv - 1)
zleft_edge = zoffs + zstep * DBLE(izleft_solv - 1)
!
! ... allocate working memory
IF (rismt%nrzl > 0) THEN
ALLOCATE(xg0(rismt%nrzl))
ALLOCATE(xg1(rismt%nrzl))
END IF
IF (rismt%nsite > 0) THEN
ALLOCATE(cright(rismt%nsite))
ALLOCATE(cleft( rismt%nsite))
END IF
IF (nzright > 0) THEN
ALLOCATE(hright(nzright))
END IF
IF (nzleft > 0) THEN
ALLOCATE(hleft(nzleft))
END IF
!
! ... calculate cright(z2), cleft(z2)
DO iq2 = rismt%mp_site%isite_start, rismt%mp_site%isite_end
iiq2 = iq2 - rismt%mp_site%isite_start + 1
iv2 = iuniq_to_isite(1, iq2)
isolV2 = isite_to_isolV(iv2)
iatom2 = isite_to_iatom(iv2)
qv2 = solVs(isolV2)%charge(iatom2)
!
IF (rismt%lfft%gxystart > 1) THEN
cright(iiq2) = rismt%csdg0(izright_solv, iiq2) &
& - beta * qv2 * DBLE(rismt%vlgz(izright_solv))
cleft( iiq2) = rismt%csdg0(izleft_solv, iiq2) &
& - beta * qv2 * DBLE(rismt%vlgz(izleft_solv))
ELSE
cright(iiq2) = 0.0_DP
cleft( iiq2) = 0.0_DP
END IF
END DO
!
IF (rismt%nsite > 0) THEN
CALL mp_sum(cright, rismt%mp_site%intra_sitg_comm)
CALL mp_sum(cleft, rismt%mp_site%intra_sitg_comm)
END IF
!
! ... Laue-RISM equation of void-region
DO iq1 = 1, nq
IF (rismt%mp_site%isite_start <= iq1 .AND. iq1 <= rismt%mp_site%isite_end) THEN
iiq1 = iq1 - rismt%mp_site%isite_start + 1
ELSE
iiq1 = 0
END IF
!
IF (nzright > 0) THEN
hright = 0.0_DP
END IF
IF (nzleft > 0) THEN
hleft = 0.0_DP
END IF
!
DO iq2 = rismt%mp_site%isite_start, rismt%mp_site%isite_end
iiq2 = iq2 - rismt%mp_site%isite_start + 1
!
d2 = (cright(iiq2) - cleft(iiq2)) / (zright_edge - zleft_edge)
!
! ... hleft(z1)
c2 = cleft(iiq2)
!
IF (.NOT. lboth) THEN
xg0 = rismt%xgs0(1:rismt%nrzl, iiq2, iq1)
xg1 = rismt%xgs1(1:rismt%nrzl, iiq2, iq1)
ELSE
xg0 = rismt%ygs0(1:rismt%nrzl, iiq2, iq1)
xg1 = rismt%ygs1(1:rismt%nrzl, iiq2, iq1)
END IF
!
!$omp parallel do default(shared) private(iz, izint, izdelt1, izdelt2, z, cz, dz)
DO iz = izleft_sta, izleft_end
izint = iz - izleft_sta + 1
izdelt1 = ABS(iz - izleft_void ) + 1
izdelt2 = ABS(iz - izright_solv) + 1
!
IF (izdelt1 <= rismt%lfft%nrz) THEN
z = zoffs + zstep * DBLE(iz - 1)
cz = c2 + d2 * (z - zleft_edge)
dz = d2
hleft(izint) = hleft(izint) &
& + cz * xg0(izdelt1) &
& + dz * xg1(izdelt1)
END IF
!
IF (izdelt2 <= rismt%lfft%nrz) THEN
z = zoffs + zstep * DBLE(iz - 1)
cz = c2 + d2 * (z - zleft_edge)
dz = d2
hleft(izint) = hleft(izint) &
& - cz * xg0(izdelt2) &
& - dz * xg1(izdelt2)
END IF
END DO
!$omp end parallel do
!
! ... hright(z1)
c2 = cright(iiq2)
!
xg0 = rismt%xgs0(1:rismt%nrzl, iiq2, iq1)
xg1 = rismt%xgs1(1:rismt%nrzl, iiq2, iq1)
!
!$omp parallel do default(shared) private(iz, izint, izdelt1, izdelt2, z, cz, dz)
DO iz = izright_sta, izright_end
izint = iz - izright_sta + 1
izdelt1 = ABS(iz - izright_void) + 1
izdelt2 = ABS(iz - izleft_solv ) + 1
!
IF (izdelt1 <= rismt%lfft%nrz) THEN
z = zoffs + zstep * DBLE(iz - 1)
cz = c2 + d2 * (z - zright_edge)
dz = -d2
hright(izint) = hright(izint) &
& + cz * xg0(izdelt1) &
& + dz * xg1(izdelt1)
END IF
!
IF (izdelt2 <= rismt%lfft%nrz) THEN
z = zoffs + zstep * DBLE(iz - 1)
cz = c2 + d2 * (z - zright_edge)
dz = -d2
hright(izint) = hright(izint) &
& - cz * xg0(izdelt2) &
& - dz * xg1(izdelt2)
END IF
END DO
!$omp end parallel do
END DO
!
IF (nzright > 0) THEN
CALL mp_sum(hright, rismt%mp_site%inter_sitg_comm)
END IF
IF (nzleft > 0) THEN
CALL mp_sum(hleft, rismt%mp_site%inter_sitg_comm)
END IF
!
IF (iiq1 > 0) THEN
IF (expand) THEN
IF (rismt%lfft%gxystart > 1) THEN
! ... add hleft -> hsgz
!$omp parallel do default(shared) private(iz, izint)
DO iz = izleft_sta, izleft_end
izint = iz - izleft_sta + 1
rismt%hsgz(iz, iiq1) = rismt%hsgz(iz, iiq1) + CMPLX(hleft(izint), 0.0_DP, kind=DP)
END DO
!$omp end parallel do
!
! ... add hright -> hsgz
!$omp parallel do default(shared) private(iz, izint)
DO iz = izright_sta, izright_end
izint = iz - izright_sta + 1
rismt%hsgz(iz, iiq1) = rismt%hsgz(iz, iiq1) + CMPLX(hright(izint), 0.0_DP, kind=DP)
END DO
!$omp end parallel do
END IF
!
ELSE
! ... add hleft -> hg0
!$omp parallel do default(shared) private(iz, izint)
DO iz = izleft_sta, izleft_end
izint = iz - izleft_sta + 1
rismt%hg0(iz, iiq1) = rismt%hg0(iz, iiq1) + hleft(izint)
END DO
!$omp end parallel do
!
! ... add hright -> hg0
!$omp parallel do default(shared) private(iz, izint)
DO iz = izright_sta, izright_end
izint = iz - izright_sta + 1
rismt%hg0(iz, iiq1) = rismt%hg0(iz, iiq1) + hright(izint)
END DO
!$omp end parallel do
END IF
END IF
!
END DO
!
! ... deallocate working memory
IF (rismt%nrzl > 0) THEN
DEALLOCATE(xg0)
DEALLOCATE(xg1)
END IF
IF (rismt%nsite > 0) THEN
DEALLOCATE(cright)
DEALLOCATE(cleft)
END IF
IF (nzright > 0) THEN
DEALLOCATE(hright)
END IF
IF (nzleft > 0) THEN
DEALLOCATE(hleft)
END IF
!
END SUBROUTINE eqn_lauevoid_between