quantum-espresso/Modules/solvavg.f90

584 lines
15 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 .
!
!--------------------------------------------------------------------------
MODULE solvavg
!--------------------------------------------------------------------------
!
! ... planar average of solvents.
!
USE constants, ONLY : BOHR_RADIUS_ANGS
USE cell_base, ONLY : at, alat
USE fft_types, ONLY : fft_type_descriptor, fft_index_to_3d
USE io_global, ONLY : ionode
USE kinds, ONLY : DP
USE lauefft, ONLY : lauefft_type
USE mp, ONLY : mp_sum
USE parallel_include
!
IMPLICIT NONE
SAVE
PRIVATE
!
! ... define constants
INTEGER, PARAMETER :: LEN_LABEL = 20
!
#if defined (__DEBUG_RISM)
INTEGER, PARAMETER :: MAX_NUM_DATA = 256
#else
INTEGER, PARAMETER :: MAX_NUM_DATA = 64
#endif
!
! ... related 3D-FFT
TYPE(fft_type_descriptor), POINTER :: dfft => NULL()
!
! ... related Laue-FFT
TYPE(lauefft_type), POINTER :: lfft => NULL()
!
! ... MPI-communicator
INTEGER :: intra_group_comm = MPI_COMM_NULL
!
! ... radial data, or not
LOGICAL :: radial = .FALSE.
!
! ... number of data
INTEGER :: ndata = 0
!
! ... labels of data
CHARACTER(LEN=LEN_LABEL), ALLOCATABLE :: label(:)
!
! ... data of planar average
REAL(DP), ALLOCATABLE :: rdata(:,:)
!
! ... public components
PUBLIC :: solvavg_size
PUBLIC :: solvavg_init
PUBLIC :: solvavg_clear
PUBLIC :: solvavg_put
PUBLIC :: solvavg_add
PUBLIC :: solvavg_print
!
! ... overload subroutines
INTERFACE solvavg_init
MODULE PROCEDURE solvavg_init_3d
MODULE PROCEDURE solvavg_init_laue
END INTERFACE
!
INTERFACE solvavg_put
MODULE PROCEDURE solvavg_put_real
MODULE PROCEDURE solvavg_put_laue
END INTERFACE
!
INTERFACE solvavg_add
MODULE PROCEDURE solvavg_add_real
MODULE PROCEDURE solvavg_add_laue
END INTERFACE
!
CONTAINS
!
!--------------------------------------------------------------------------
INTEGER FUNCTION solvavg_size()
!--------------------------------------------------------------------------
!
! ... get ndata
!
IMPLICIT NONE
!
solvavg_size = ndata
!
END FUNCTION solvavg_size
!
!--------------------------------------------------------------------------
SUBROUTINE solvavg_init_3d(dfft_, comm, is_radial)
!--------------------------------------------------------------------------
!
! ... initialize this module with 3D-FFT.
!
IMPLICIT NONE
!
TYPE(fft_type_descriptor), TARGET, INTENT(IN) :: dfft_
INTEGER, INTENT(IN) :: comm
LOGICAL, INTENT(IN) :: is_radial
!
dfft => dfft_
!
intra_group_comm = comm
!
radial = is_radial
!
ndata = 0
ALLOCATE(label( MAX_NUM_DATA))
ALLOCATE(rdata(dfft%nr3, MAX_NUM_DATA))
!
END SUBROUTINE solvavg_init_3d
!
!--------------------------------------------------------------------------
SUBROUTINE solvavg_init_laue(lfft_, comm, is_radial)
!--------------------------------------------------------------------------
!
! ... initialize this module with Laue-FFT.
!
IMPLICIT NONE
!
TYPE(lauefft_type), TARGET, INTENT(IN) :: lfft_
INTEGER, INTENT(IN) :: comm
LOGICAL, INTENT(IN) :: is_radial
!
lfft => lfft_
!
intra_group_comm = comm
!
radial = is_radial
!
ndata = 0
ALLOCATE(label( MAX_NUM_DATA))
ALLOCATE(rdata(lfft%nrz, MAX_NUM_DATA))
!
END SUBROUTINE solvavg_init_laue
!
!--------------------------------------------------------------------------
SUBROUTINE solvavg_clear()
!--------------------------------------------------------------------------
!
! ... finalize this module.
!
IMPLICIT NONE
!
IF (ASSOCIATED(dfft)) THEN
NULLIFY(dfft)
END IF
!
IF (ASSOCIATED(lfft)) THEN
NULLIFY(lfft)
END IF
!
intra_group_comm = MPI_COMM_NULL
!
ndata = 0
IF (ALLOCATED(label)) THEN
DEALLOCATE(label)
END IF
IF (ALLOCATED(rdata)) THEN
DEALLOCATE(rdata)
END IF
!
END SUBROUTINE solvavg_clear
!
!--------------------------------------------------------------------------
SUBROUTINE solvavg_put_real(title, integrate, zuv)
!--------------------------------------------------------------------------
!
! ... put solvent data as R-space.
!
IMPLICIT NONE
!
CHARACTER(LEN=*), INTENT(IN) :: title
LOGICAL, INTENT(IN) :: integrate
REAL(DP), INTENT(IN) :: zuv(:) !dimension(nnr)
!
IF (ndata < MAX_NUM_DATA) THEN
!
ndata = ndata + 1
label( ndata) = TRIM(title)
rdata(:, ndata) = 0.0_DP
!
CALL solvavg_add_real(ndata, integrate, zuv)
!
END IF
!
END SUBROUTINE solvavg_put_real
!
!--------------------------------------------------------------------------
SUBROUTINE solvavg_put_laue(title, integrate, zuv, nrz, expanded, igxy)
!--------------------------------------------------------------------------
!
! ... put solvent data as Laue-rep.
!
IMPLICIT NONE
!
CHARACTER(LEN=*), INTENT(IN) :: title
LOGICAL, INTENT(IN) :: integrate
COMPLEX(DP), INTENT(IN) :: zuv(:) !dimension(nrz*ngxy)
INTEGER, INTENT(IN) :: nrz
LOGICAL, INTENT(IN) :: expanded
INTEGER, OPTIONAL, INTENT(IN) :: igxy
!
IF (ndata < MAX_NUM_DATA) THEN
!
ndata = ndata + 1
label( ndata) = TRIM(title)
rdata(:, ndata) = 0.0_DP
!
IF (PRESENT(igxy)) THEN
CALL solvavg_add_laue(ndata, integrate, zuv, nrz, expanded, igxy)
ELSE
CALL solvavg_add_laue(ndata, integrate, zuv, nrz, expanded)
END IF
!
END IF
!
END SUBROUTINE solvavg_put_laue
!
!--------------------------------------------------------------------------
SUBROUTINE solvavg_add_real(idata, integrate, zuv)
!--------------------------------------------------------------------------
!
! ... add solvent data as R-space, at idata.
!
IMPLICIT NONE
!
INTEGER, INTENT(IN) :: idata
LOGICAL, INTENT(IN) :: integrate
REAL(DP), INTENT(IN) :: zuv(:) !dimension(nnr)
!
LOGICAL :: laue
INTEGER :: ir, nr
INTEGER :: i1, i2, i3
INTEGER :: n1, n2, n3
INTEGER :: nrz
INTEGER :: irz
INTEGER :: irz0
LOGICAL :: offrange
REAL(DP) :: area_xy
REAL(DP), ALLOCATABLE :: ztmp(:)
!
! ... check dfft, lfft
IF (.NOT. (ASSOCIATED(dfft) .OR. ASSOCIATED(lfft))) THEN
RETURN
END IF
!
laue = .FALSE.
IF (ASSOCIATED(lfft)) THEN
laue = .TRUE.
END IF
!
! ... FFT box
IF (laue) THEN
n1 = lfft%dfft%nr1
n2 = lfft%dfft%nr2
n3 = lfft%dfft%nr3
nr = lfft%dfft%nr1x * lfft%dfft%my_nr2p * lfft%dfft%my_nr3p
nrz = lfft%nrz
irz0 = lfft%izcell_start
ELSE
n1 = dfft%nr1
n2 = dfft%nr2
n3 = dfft%nr3
nr = dfft%nr1x * dfft%my_nr2p * dfft%my_nr3p
nrz = dfft%nr3
irz0 = 1
END IF
!
! ... allocate memory
ALLOCATE(ztmp(nrz))
!
ztmp = 0.0_DP
!
! ... calculate planar average
DO ir = 1, nr
!
IF (laue) THEN
CALL fft_index_to_3d(ir, lfft%dfft, i1, i2, i3, offrange)
ELSE
CALL fft_index_to_3d(ir, dfft, i1, i2, i3, offrange)
END IF
!
IF (offrange) THEN
CYCLE
END IF
!
IF (i3 >= (n3 - (n3 / 2))) THEN
irz = i3 - n3
ELSE
irz = i3
END IF
irz = irz + (n3 / 2)
irz = irz + irz0
!
ztmp(irz) = ztmp(irz) + zuv(ir)
!
END DO
!
CALL mp_sum(ztmp, intra_group_comm)
!
IF (integrate) THEN
area_xy = alat * alat * ABS(at(1, 1) * at(2, 2) - at(1, 2) * at(2, 1))
ztmp = ztmp * (area_xy / DBLE(n1 * n2))
ELSE
ztmp = ztmp / DBLE(n1 * n2)
END IF
!
! ... add to data
IF (1 <= idata .AND. idata <= ndata) THEN
DO irz = 1, nrz
rdata(irz, idata) = rdata(irz, idata) + ztmp(irz)
END DO
END IF
!
! ... deallocate memory
DEALLOCATE(ztmp)
!
END SUBROUTINE solvavg_add_real
!
!--------------------------------------------------------------------------
SUBROUTINE solvavg_add_laue(idata, integrate, zuv, nrz, expanded, igxy)
!--------------------------------------------------------------------------
!
! ... add solvent data as Laue-rep., at idata.
!
IMPLICIT NONE
!
INTEGER, INTENT(IN) :: idata
LOGICAL, INTENT(IN) :: integrate
COMPLEX(DP), INTENT(IN) :: zuv(:) !dimension(nrz*ngxy)
INTEGER, INTENT(IN) :: nrz
LOGICAL, INTENT(IN) :: expanded
INTEGER, OPTIONAL, INTENT(IN) :: igxy
!
INTEGER :: irz
INTEGER :: jgxy
REAL(DP) :: area_xy
REAL(DP) :: zr
REAL(DP) :: zi
COMPLEX(DP), ALLOCATABLE :: ztmp(:)
!
! ... check lfft
IF (.NOT. ASSOCIATED(lfft)) THEN
RETURN
END IF
!
! ... check nrz
IF (expanded) THEN
IF (nrz < lfft%nrz) THEN
RETURN
END IF
ELSE
IF (nrz < lfft%dfft%nr3) THEN
RETURN
END IF
END IF
!
! ... check igxy
IF (PRESENT(igxy)) THEN
jgxy = igxy
ELSE
jgxy = -1
END IF
!
! ... allocate memory
ALLOCATE(ztmp(lfft%nrz))
!
ztmp = CMPLX(0.0_DP, 0.0_DP, kind=DP)
!
IF (jgxy < 1) THEN
!
! ... in case Gxy = 0
IF (lfft%gxystart > 1) THEN
IF (expanded) THEN
DO irz = 1, lfft%nrz
ztmp(irz) = zuv(irz)
END DO
ELSE
DO irz = lfft%izcell_start, lfft%izcell_end
ztmp(irz) = zuv(irz - lfft%izcell_start + 1)
END DO
END IF
END IF
!
ELSE
!
! ... in case Gxy /= 0
IF (ionode .AND. (jgxy <= lfft%ngxy)) THEN
IF (expanded) THEN
DO irz = 1, lfft%nrz
ztmp(irz) = zuv(irz + nrz * (jgxy - 1))
END DO
ELSE
DO irz = lfft%izcell_start, lfft%izcell_end
ztmp(irz) = zuv(irz - lfft%izcell_start + 1 + nrz * (jgxy - 1))
END DO
END IF
END IF
!
END IF
!
CALL mp_sum(ztmp, intra_group_comm)
!
IF (integrate) THEN
area_xy = alat * alat * ABS(at(1, 1) * at(2, 2) - at(1, 2) * at(2, 1))
ztmp = ztmp * area_xy
END IF
!
! ... add to data
IF (1 <= idata .AND. idata <= ndata) THEN
DO irz = 1, lfft%nrz
zr = DBLE( ztmp(irz))
zi = AIMAG(ztmp(irz))
!rdata(irz, idata) = rdata(irz, idata) + SQRT(zr * zr + zi * zi)
rdata(irz, idata) = rdata(irz, idata) + zr
END DO
END IF
!
! ... deallocate memory
DEALLOCATE(ztmp)
!
END SUBROUTINE solvavg_add_laue
!
!--------------------------------------------------------------------------
SUBROUTINE solvavg_print(filename, comment, ierr)
!--------------------------------------------------------------------------
!
! ... print planar average of solvents.
!
IMPLICIT NONE
!
CHARACTER(LEN=*), INTENT(IN) :: filename
CHARACTER(LEN=*), INTENT(IN) :: comment
INTEGER, INTENT(OUT) :: ierr
!
INTEGER :: iun
!
ierr = 0
!
CALL open_file(iun, filename, ierr)
IF (ierr /= 0) THEN
RETURN
END IF
!
IF (ionode .AND. LEN_TRIM(comment) > 0) THEN
WRITE(iun, '("#",A)') TRIM(comment)
END IF
!
CALL write_data(iun)
!
CALL close_file(iun)
!
END SUBROUTINE solvavg_print
!
SUBROUTINE open_file(iun, filename, ierr)
IMPLICIT NONE
INTEGER, INTENT(OUT) :: iun
CHARACTER(LEN=*), INTENT(IN) :: filename
INTEGER, INTENT(OUT) :: ierr
!
INTEGER :: ios
!
INTEGER, EXTERNAL :: find_free_unit
!
iun = find_free_unit()
IF (ionode) THEN
OPEN(unit=iun, file=filename, status='unknown', form='formatted', action='write', iostat=ios)
ios = ABS(ios)
ELSE
ios = 0
END IF
!
CALL mp_sum(ios, intra_group_comm)
ierr = ios
END SUBROUTINE open_file
!
SUBROUTINE close_file(iun)
IMPLICIT NONE
INTEGER, INTENT(IN) :: iun
!
IF (ionode) THEN
CLOSE(unit=iun)
END IF
END SUBROUTINE close_file
!
SUBROUTINE write_data(iun)
IMPLICIT NONE
INTEGER, INTENT(IN) :: iun
!
LOGICAL :: laue
INTEGER :: idata
INTEGER :: irz
INTEGER :: nrz
REAL(DP) :: rz
REAL(DP) :: dz
REAL(DP) :: z0
REAL(DP) :: c
#if defined (__DEBUG_RISM)
INTEGER :: ilabel
INTEGER :: nlabel
#endif
CHARACTER(LEN=LEN_LABEL) :: label1
!
IF (.NOT. ionode) THEN
RETURN
END IF
!
! ... check dfft, lfft
IF (.NOT. (ASSOCIATED(dfft) .OR. ASSOCIATED(lfft))) THEN
RETURN
END IF
!
laue = .FALSE.
IF (ASSOCIATED(lfft)) THEN
laue = .TRUE.
END IF
!
! ... FFT box
IF (laue) THEN
nrz = lfft%nrz
dz = lfft%zstep
IF (.NOT. radial) THEN
z0 = lfft%zleft + lfft%zoffset
ELSE
z0 = 0.0_DP
END IF
ELSE
c = SQRT(at(1, 3) * at(1, 3) + at(2, 3) * at(2, 3) + at(3, 3) * at(3, 3))
nrz = dfft%nr3
dz = c / DBLE(dfft%nr3)
IF (.NOT. radial) THEN
z0 = -0.5_DP * c + dz * MOD(nrz, 2)
ELSE
z0 = 0.0_DP
END IF
END IF
!
! ... write labels
#if defined (__DEBUG_RISM)
WRITE(iun, '("#__z_(A) ")', advance='no')
#else
WRITE(iun, '("# z (A) ")', advance='no')
#endif
!
DO idata = 1, ndata
label1 = label(idata)
#if defined (__DEBUG_RISM)
nlabel = LEN_TRIM(label1)
DO ilabel = 1, nlabel
IF (label1(ilabel:ilabel) == ' ') THEN
label1(ilabel:ilabel) = '_'
END IF
END DO
#endif
WRITE(iun, '(2X,A20)', advance='no') label1
END DO
WRITE(iun, '()', advance='yes')
!
! ... write data
DO irz = 1, nrz
rz = z0 + dz * DBLE(irz - 1)
rz = rz * alat
rz = rz * BOHR_RADIUS_ANGS
WRITE(iun, '(F8.3)', advance='no') rz
!
DO idata = 1, ndata
WRITE(iun, '(E22.12e3)', advance='no') rdata(irz, idata)
END DO
WRITE(iun, '()', advance='yes')
END DO
!
END SUBROUTINE write_data
!
END MODULE solvavg