mirror of https://gitlab.com/QEF/q-e.git
469 lines
14 KiB
Fortran
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
|