quantum-espresso/Modules/input_1drism.f90

469 lines
14 KiB
Fortran

!
! Copyright (C) 2015-2016 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 iosys_1drism(laue)
!-----------------------------------------------------------------------------
!
! ... Copy data read from input file (in subroutine "read_input_file") and
! ... stored in modules input_parameters into internal modules
! ... Note: this subroutine requires pseudo_dir(io_files), omega(cell_base),
! ... ecutrho(gvect), dual(gvecs).
!
USE cell_base, ONLY : alat, at, omega
USE constants, ONLY : pi, tpi, eps8, eps12
USE gvecs, ONLY : dual
USE gvect, ONLY : ecutrho
USE io_files, ONLY : molfile
USE kinds, ONLY : DP
USE molecule_const, ONLY : BOHRm3_TO_MOLCMm3, BOHRm3_TO_MOLLm1
USE read_solv_module, ONLY : read_solvents
USE rism, ONLY : CLOSURE_HNC, CLOSURE_KH
USE rism1d_facade, ONLY : nproc_sub, nproc_switch, starting_corr, niter, epsv, &
& bond_width, dielectric, molesize, &
& mdiis_size, mdiis_step, rism1t, rism1d_initialize, &
& rism1d_activate_right, rism1d_activate_left
USE solvmol, ONLY : nsolV_ => nsolV, solVs, get_nsite_in_solVs
!
! ... CONTROL namelist
!
USE input_parameters, ONLY : restart_mode
!
! ... RISM namelist
!
USE input_parameters, ONLY : nsolv, closure, starting1d, tempv, rmax1d, &
smear1d, rism1d_maxstep, rism1d_conv_thr, &
rism1d_bond_width, rism1d_dielectric, rism1d_molesize, &
rism1d_nproc, rism1d_nproc_switch, mdiis1d_size, mdiis1d_step, &
laue_expand_right, laue_expand_left, laue_both_hands
!
! ... SOLVENTS card
!
USE input_parameters, ONLY : solv_label, solv_mfile, solv_dens1, solv_dens2, solvents_unit
!
IMPLICIT NONE
!
LOGICAL, INTENT(IN) :: laue
!
INTEGER :: ngrid
INTEGER :: nsite
INTEGER :: isolV
INTEGER :: iatom
REAL(DP) :: z0
REAL(DP) :: zright
REAL(DP) :: zleft
CHARACTER(LEN=10), ALLOCATABLE :: slabel(:)
REAL(DP), ALLOCATABLE :: sdens1(:)
REAL(DP), ALLOCATABLE :: sdens2(:)
REAL(DP) :: tdens1
REAL(DP) :: tdens2
REAL(DP) :: rsol(3)
REAL(DP) :: qsol
REAL(DP) :: dsol(3)
REAL(DP) :: dtot
INTEGER :: ihand
INTEGER :: nhand
!
REAL(DP), PARAMETER :: RMAX1D_SCALE = 1.5_DP
REAL(DP), PARAMETER :: BOND_SCALE = 4.0_DP
INTEGER, PARAMETER :: MDIIS_SWITCH = 6
REAL(DP), PARAMETER :: MDIIS_STEP_DEF1 = 0.5_DP
REAL(DP), PARAMETER :: MDIIS_STEP_DEF2 = 0.1_DP
!
! ... allocate memory
ALLOCATE(slabel(nsolv))
ALLOCATE(sdens1(nsolv))
ALLOCATE(sdens2(nsolv))
!
! ... check starting condition.
IF (TRIM(restart_mode) == 'restart') THEN
IF (TRIM(starting1d) /= 'file' .AND. TRIM(starting1d) /= 'fix') THEN
CALL infomsg('input','WARNING: "starting1d" set to '//TRIM(starting1d)//' may spoil restart')
starting1d = 'file'
END IF
END IF
!
! ... check both-hand Laue-RISM w/ DRISM.
IF (laue .AND. laue_both_hands) THEN
IF (dielectric > 0.0_DP) THEN
CALL errore('iosys_1drism', 'Cannot use both-hand Laue-RISM with DRISM', 1)
END IF
END IF
!
! ... modify rmax1d
IF (laue) THEN
z0 = 0.5_DP * alat * at(3, 3)
zright = z0 + MAX(0.0_DP, laue_expand_right)
zleft = -z0 - MAX(0.0_DP, laue_expand_left )
rmax1d = MAX(rmax1d, RMAX1D_SCALE * (zright - zleft))
ENDIF
!
! ... modify rism1d_bond_width
IF (laue .AND. rism1d_bond_width <= 0.0_DP) THEN
rism1d_bond_width = BOND_SCALE / SQRT(ecutrho * 4.0_DP / dual)
ENDIF
!
! ... evaluate #grid
ngrid = number_of_grids(rmax1d)
!
! ... set from namelist. these data are already checked.
nsolV_ = nsolv
starting_corr = starting1d
nproc_sub = rism1d_nproc
nproc_switch = rism1d_nproc_switch
niter = rism1d_maxstep
epsv = rism1d_conv_thr
bond_width = rism1d_bond_width
dielectric = rism1d_dielectric
molesize = rism1d_molesize
mdiis_size = mdiis1d_size
mdiis_step = mdiis1d_step
!
! ... set from card
DO isolV = 1, nsolV_
slabel( isolV) = solv_label(isolV)
molfile(isolV) = solv_mfile(isolV)
sdens1( isolV) = solv_dens1(isolV)
sdens2( isolV) = solv_dens2(isolV)
END DO
!
! ... read solvents from molecule files
CALL read_solvents()
!
! ... set variables for solVs
tdens1 = 0.0_DP
tdens2 = 0.0_DP
!
DO isolV = 1, nsolV_
!
! ... name
IF (LEN_TRIM(slabel(isolV)) > 0) THEN
solVs(isolV)%name = slabel(isolv)
ELSE
CALL infomsg('iosys_1drism', &
& 'default molecular name(formula) from MOL file('//TRIM(molfile(isolV))//') is used')
END IF
IF (LEN_TRIM(solVs(isolV)%name) <= 0) THEN
CALL errore('iosys_1drism', 'invalid name', isolV)
END IF
!
! ... density
IF (sdens1(isolV) >= 0.0_DP) THEN
CALL convert_dens(TRIM(ADJUSTL(solvents_unit)), isolV, sdens1(isolV))
solVs(isolV)%density = sdens1(isolv)
ELSE
IF (laue .AND. laue_both_hands) THEN
CALL infomsg('iosys_1drism', &
& 'default density(right) from MOL file('//TRIM(molfile(isolV))//') is used')
ELSE
CALL infomsg('iosys_1drism', &
& 'default density from MOL file('//TRIM(molfile(isolV))//') is used')
END IF
END IF
!
IF (solVs(isolV)%density < 0.0_DP) THEN
IF (laue .AND. laue_both_hands) THEN
CALL errore('iosys_1drism', 'invalid density(right)', isolV)
ELSE
CALL errore('iosys_1drism', 'invalid density', isolV)
END IF
END IF
!
! ... subdensity
IF (laue .AND. laue_both_hands) THEN
IF (sdens2(isolV) >= 0.0_DP) THEN
CALL convert_dens(TRIM(ADJUSTL(solvents_unit)), isolV, sdens2(isolV))
solVs(isolV)%subdensity = sdens2(isolv)
ELSE
CALL infomsg('iosys_1drism', &
& 'default density(left) from MOL file('//TRIM(molfile(isolV))//') is used')
END IF
!
IF (solVs(isolV)%subdensity < 0.0_DP) THEN
CALL errore('iosys_1drism', 'invalid density(left)', isolV)
END IF
!
ELSE
solVs(isolV)%subdensity = solVs(isolV)%density
END IF
!
IF (solVs(isolV)%density <= 0.0_DP .AND. solVs(isolV)%subdensity <= 0.0_DP) THEN
CALL errore('iosys_1drism', 'solvent density is zero', isolV)
END IF
!
tdens1 = tdens1 + solVs(isolV)%density
tdens2 = tdens2 + solVs(isolV)%subdensity
!
! ... dipole moment, and rotation of coordinate, if DRISM
solVs(isolV)%dipole = 0.0_DP
solVs(isolV)%is_polar = .FALSE.
!
IF (dielectric > 0.0_DP) THEN
!
rsol = 0.0_DP
DO iatom = 1, solVs(isolV)%natom
rsol = rsol + solVs(isolV)%coord(:, iatom)
END DO
!
rsol = rsol / DBLE(solVs(isolV)%natom)
!
qsol = 0.0_DP
dsol = 0.0_DP
DO iatom = 1, solVs(isolV)%natom
qsol = qsol + solVs(isolV)%charge(iatom)
dsol = dsol + solVs(isolV)%charge(iatom) * (solVs(isolV)%coord(:, iatom) - rsol)
END DO
!
dtot = SQRT(dsol(1) * dsol(1) + dsol(2) * dsol(2) + dsol(3) * dsol(3))
!
IF (ABS(qsol) <= eps8 .AND. dtot > eps8) THEN
DO iatom = 1, solVs(isolV)%natom
solVs(isolV)%coord(:, iatom) = solVs(isolV)%coord(:, iatom) - rsol
END DO
!
CALL rotate_coord(isolV, dsol)
!
dsol = 0.0_DP
DO iatom = 1, solVs(isolV)%natom
dsol = dsol + solVs(isolV)%charge(iatom) * solVs(isolV)%coord(:, iatom)
END DO
!
IF (ABS(dsol(1)) > eps8 .OR. ABS(dsol(2)) > eps8 .OR. ABS(dtot - dsol(3)) > eps8) THEN
CALL errore('iosys_1drism', 'error in rotation of molecule', isolV)
END IF
!
solVs(isolV)%dipole = dsol(3)
solVs(isolV)%is_polar = .TRUE.
END IF
!
END IF
!
END DO
!
IF (tdens1 < eps8 .OR. tdens2 < eps8) THEN
CALL errore('iosys_1drism', 'all of solvent densities are zero', 1)
END IF
!
! ... modify rism1d_dielectric
IF (rism1d_dielectric > 0.0_DP) THEN
IF(.NOT. ANY(solVs(:)%is_polar)) THEN
rism1d_dielectric = -1.0_DP
dielectric = rism1d_dielectric
CALL infomsg('iosys_1drism', 'there are no polar solvents, DRISM is not used.')
END IF
END IF
!
! ... modify mdiis1d_step (this operation must be after read_solvents)
IF (mdiis1d_step < 0.0_DP) THEN
nsite = get_nsite_in_solVs()
IF (nsite <= MDIIS_SWITCH) THEN
mdiis1d_step = MDIIS_STEP_DEF1
ELSE
mdiis1d_step = MDIIS_STEP_DEF2
END IF
mdiis_step = mdiis1d_step
END IF
!
! ... initialize rism1d_facade
IF (laue .AND. laue_both_hands) THEN
nhand = 2
ELSE
nhand = 1
END IF
!
DO ihand = 1, nhand
IF (ihand == 1) THEN
CALL rism1d_activate_right()
ELSE
CALL rism1d_activate_left()
END IF
!
IF (TRIM(closure) == 'hnc') THEN
rism1t%closure = CLOSURE_HNC
ELSE IF (TRIM(closure) == 'kh') THEN
rism1t%closure = CLOSURE_KH
END IF
rism1t%temp = tempv
rism1t%tau = smear1d
END DO
!
CALL rism1d_initialize(ngrid, rmax1d, nhand > 1)
!
! ... deallocate memory
DEALLOCATE(slabel)
DEALLOCATE(sdens1)
DEALLOCATE(sdens2)
!
CONTAINS
!
SUBROUTINE convert_dens(dens_format, isolV, dens)
IMPLICIT NONE
CHARACTER(LEN=*), INTENT(IN) :: dens_format
INTEGER, INTENT(IN) :: isolV
REAL(DP), INTENT(INOUT) :: dens
!
SELECT CASE (dens_format)
CASE ('1/cell')
dens = dens / omega
!
CASE ('mol/L')
dens = dens / BOHRm3_TO_MOLLm1
!
CASE ('g/cm^3')
dens = (dens / solVs(isolV)%mass) / BOHRm3_TO_MOLCMm3
!
CASE DEFAULT
CALL errore('iosys_1drism', 'dens_format='// &
& TRIM(dens_format)//' not implemented', isolV)
!
END SELECT
END SUBROUTINE convert_dens
!
SUBROUTINE rotate_coord(isolV, ax)
IMPLICIT NONE
INTEGER, INTENT(IN) :: isolV
REAL(DP), INTENT(IN) :: ax(3)
!
INTEGER :: iatom
REAL(DP) :: er
REAL(DP) :: e0(3)
REAL(DP) :: e1(3), r1, s1
REAL(DP) :: e2(3), r2, s2
REAL(DP) :: e3(3), r3, s3
REAL(DP) :: cos0, sin0, tan0
REAL(DP) :: x, y, z
REAL(DP) :: xx, yy, xy
REAL(DP) :: phi
!
e3 = ax
er = SQRT(MAX(0.0_DP, e3(1) * e3(1) + e3(2) * e3(2) + e3(3) * e3(3)))
IF (er <= 0.0_DP) CALL errore('iosys_1drism', 'e3 = 0', isolV)
e3 = e3 / er
!
IF (ABS(e3(1)) > eps12 .OR. ABS(e3(2)) > eps12) THEN
!
e0(1) = 0.0_DP
e0(2) = 0.0_DP
e0(3) = 1.0_DP
!
cos0 = e0(1) * e3(1) + e0(2) * e3(2) + e0(3) * e3(3)
sin0 = -SQRT(MAX(0.0_DP, 1.0_DP - cos0 * cos0))
!
e1(1) = e0(2) * e3(3) - e0(3) * e3(2)
e1(2) = e0(3) * e3(1) - e0(1) * e3(3)
e1(3) = e0(1) * e3(2) - e0(2) * e3(1)
er = SQRT(MAX(0.0_DP, e1(1) * e1(1) + e1(2) * e1(2) + e1(3) * e1(3)))
IF (er <= 0.0_DP) CALL errore('iosys_1drism', 'e1 = 0', isolV)
e1 = e1 / er
!
e2(1) = e3(2) * e1(3) - e3(3) * e1(2)
e2(2) = e3(3) * e1(1) - e3(1) * e1(3)
e2(3) = e3(1) * e1(2) - e3(2) * e1(1)
er = SQRT(MAX(0.0_DP, e2(1) * e2(1) + e2(2) * e2(2) + e2(3) * e2(3)))
IF (er <= 0.0_DP) CALL errore('iosys_1drism', 'e2 = 0', isolV)
e2 = e2 / er
!
DO iatom = 1, solVs(isolV)%natom
!
x = solVs(isolV)%coord(1, iatom)
y = solVs(isolV)%coord(2, iatom)
z = solVs(isolV)%coord(3, iatom)
!
r1 = x * e1(1) + y * e1(2) + z * e1(3)
r2 = x * e2(1) + y * e2(2) + z * e2(3)
r3 = x * e3(1) + y * e3(2) + z * e3(3)
!
s1 = r1
s2 = r2 * cos0 - r3 * sin0
s3 = r2 * sin0 + r3 * cos0
!
x = s1 * e1(1) + s2 * e2(1) + s3 * e3(1)
y = s1 * e1(2) + s2 * e2(2) + s3 * e3(2)
z = s1 * e1(3) + s2 * e2(3) + s3 * e3(3)
!
solVs(isolV)%coord(1, iatom) = x
solVs(isolV)%coord(2, iatom) = y
solVs(isolV)%coord(3, iatom) = z
!
END DO
!
ELSE IF (e3(3) < 0.0_DP) THEN
!
DO iatom = 1, solVs(isolV)%natom
!
x = solVs(isolV)%coord(1, iatom)
y = solVs(isolV)%coord(2, iatom)
z = solVs(isolV)%coord(3, iatom)
!
solVs(isolV)%coord(1, iatom) = +x ! rotate with x-axis
solVs(isolV)%coord(2, iatom) = -y
solVs(isolV)%coord(3, iatom) = -z
!
END DO
!
END IF
!
xx = 0.0_DP
yy = 0.0_DP
xy = 0.0_DP
!
DO iatom = 1, solVs(isolV)%natom
!
x = solVs(isolV)%coord(1, iatom)
y = solVs(isolV)%coord(2, iatom)
!
xx = xx + x * x
yy = yy + y * y
xy = xy + x * y
!
END DO
!
IF (ABS(xx - yy) > eps12) THEN
tan0 = -2.0_DP * xy / (xx - yy)
phi = ATAN(tan0) / 2.0_DP
ELSE
phi = pi / 4.0_DP
END IF
!
cos0 = COS(phi)
sin0 = SIN(phi)
!
DO iatom = 1, solVs(isolV)%natom
!
x = solVs(isolV)%coord(1, iatom)
y = solVs(isolV)%coord(2, iatom)
!
solVs(isolV)%coord(1, iatom) = x * cos0 - y * sin0
solVs(isolV)%coord(2, iatom) = x * sin0 + y * cos0
!
END DO
!
END SUBROUTINE rotate_coord
!
FUNCTION number_of_grids(rmax) RESULT(nr)
IMPLICIT NONE
REAL(DP), INTENT(IN) :: rmax
INTEGER :: nr
!
REAL(DP) :: tpibr
REAL(DP) :: tpibr2
REAL(DP) :: ecutrism
REAL(DP) :: gcutrism
!
REAL(DP), PARAMETER :: ECUT_SCALE = 1.1_DP
!
tpibr = tpi / (2.0_DP * rmax)
tpibr2 = tpibr * tpibr
ecutrism = ECUT_SCALE * MAX(ecutrho, ecutrho * 4.0_DP / dual)
!
gcutrism = ecutrism / tpibr2
nr = INT(SQRT(gcutrism)) + 1
END FUNCTION number_of_grids
!
END SUBROUTINE iosys_1drism