mirror of https://gitlab.com/QEF/q-e.git
388 lines
13 KiB
Fortran
388 lines
13 KiB
Fortran
!
|
|
! Copyright (C) 2002-2005 Quantum-ESPRESSO group
|
|
! 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 metadyn_base
|
|
!----------------------------------------------------------------------------
|
|
!
|
|
! ... this module contains the core methods used to implement meta-dynamics
|
|
!
|
|
! ... meta-dynamics is implemented following these two references:
|
|
!
|
|
! ... 1) A. Laio and M. Parrinello; PNAS 99, 12562 (2002);
|
|
! ... 2) C. Micheletti, A. Laio, and M Parrinello; PRL 92, 17061 (2004).
|
|
!
|
|
! ... code written by Carlo Sbraccia (2005)
|
|
!
|
|
USE kinds, ONLY : DP
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
CONTAINS
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE metadyn_init( progname, tau )
|
|
!------------------------------------------------------------------------
|
|
!
|
|
USE kinds, ONLY : DP
|
|
USE input_parameters, ONLY : restart_mode
|
|
USE constraints_module, ONLY : target
|
|
USE control_flags, ONLY : nstep, ndr
|
|
USE constants, ONLY : bohr_radius_angs
|
|
USE cell_base, ONLY : at, alat
|
|
USE metadyn_vars, ONLY : ncolvar, fe_grad, g_amplitude, fe_step, &
|
|
max_metadyn_iter, metadyn_history, &
|
|
metadyn_fmt, first_metadyn_iter, &
|
|
gaussian_pos
|
|
USE metadyn_io, ONLY : read_metadyn_restart
|
|
USE io_files, ONLY : tmp_dir, scradir, prefix, iunaxsf, &
|
|
iunmeta, delete_if_present
|
|
USE io_global, ONLY : stdout, ionode, ionode_id
|
|
USE mp, ONLY : mp_bcast
|
|
USE xml_io_base, ONLY : restart_dir
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
CHARACTER(LEN=*), INTENT(IN) :: progname
|
|
REAL(DP), INTENT(INOUT) :: tau(:,:)
|
|
!
|
|
INTEGER :: idum, i
|
|
REAL(DP) :: rdum
|
|
LOGICAL :: file_exists
|
|
CHARACTER(LEN=256) :: dirname
|
|
CHARACTER(LEN=4) :: c_ncolvar
|
|
CHARACTER(LEN=16) :: fe_step_fmt
|
|
!
|
|
CHARACTER(LEN=6), EXTERNAL :: int_to_char
|
|
!
|
|
!
|
|
c_ncolvar = int_to_char( ncolvar )
|
|
!
|
|
metadyn_fmt = '(I5,' // TRIM( c_ncolvar ) // '(2X,F10.5),2X,F14.8,' // &
|
|
& TRIM( c_ncolvar ) // '(2X,F10.5),' // &
|
|
& TRIM( c_ncolvar ) // '(2X,F10.7))'
|
|
!
|
|
IF ( nstep < 1 ) CALL errore( 'metadyn_init', 'nstep < 1', 1 )
|
|
!
|
|
max_metadyn_iter = nstep
|
|
!
|
|
IF ( restart_mode == 'from_scratch' ) THEN
|
|
!
|
|
IF ( ionode ) THEN
|
|
!
|
|
OPEN( UNIT = iunaxsf, &
|
|
FILE = TRIM( prefix ) // ".axsf", STATUS = 'UNKNOWN' )
|
|
!
|
|
WRITE( UNIT = iunaxsf, &
|
|
FMT = '(" ANIMSTEPS ",I5)' ) max_metadyn_iter
|
|
!
|
|
WRITE( UNIT = iunaxsf, FMT = '(" CRYSTAL ")' )
|
|
WRITE( UNIT = iunaxsf, FMT = '(" PRIMVEC ")' )
|
|
WRITE( UNIT = iunaxsf, FMT = '(3F14.10)' ) &
|
|
at(1,1) * alat * bohr_radius_angs, &
|
|
at(2,1) * alat * bohr_radius_angs, &
|
|
at(3,1) * alat * bohr_radius_angs
|
|
WRITE( UNIT = iunaxsf, FMT = '(3F14.10)' ) &
|
|
at(1,2) * alat * bohr_radius_angs, &
|
|
at(2,2) * alat * bohr_radius_angs, &
|
|
at(3,2) * alat * bohr_radius_angs
|
|
WRITE( UNIT = iunaxsf, FMT = '(3F14.10)' ) &
|
|
at(1,3) * alat * bohr_radius_angs, &
|
|
at(2,3) * alat * bohr_radius_angs, &
|
|
at(3,3) * alat * bohr_radius_angs
|
|
!
|
|
END IF
|
|
!
|
|
CALL delete_if_present( TRIM( prefix ) // '.metadyn' )
|
|
!
|
|
IF ( ionode ) THEN
|
|
!
|
|
OPEN( UNIT = iunmeta, &
|
|
FILE = TRIM( prefix ) // '.metadyn', STATUS = 'NEW' )
|
|
!
|
|
WRITE( iunmeta, '(2(2X,I5))' ) ncolvar, max_metadyn_iter
|
|
WRITE( iunmeta, '(2(2X,F12.8))' ) g_amplitude
|
|
!
|
|
fe_step_fmt = '(' // TRIM( c_ncolvar ) // '(2X,F12.8))'
|
|
!
|
|
WRITE( iunmeta, fe_step_fmt ) fe_step(:)
|
|
!
|
|
END IF
|
|
!
|
|
first_metadyn_iter = 0
|
|
!
|
|
ELSE
|
|
!
|
|
! ... restarting from file
|
|
!
|
|
IF ( progname == 'PW' ) THEN
|
|
!
|
|
dirname = TRIM( tmp_dir ) // TRIM( prefix ) // '.save'
|
|
!
|
|
ELSE IF ( progname == 'CP' ) THEN
|
|
!
|
|
dirname = restart_dir( scradir, ndr )
|
|
!
|
|
ELSE
|
|
!
|
|
CALL errore( 'metadyn_init', &
|
|
'wrong calling program: ' // TRIM( progname ), 1 )
|
|
!
|
|
END IF
|
|
!
|
|
CALL read_metadyn_restart( dirname, tau, alat )
|
|
!
|
|
IF ( ionode ) THEN
|
|
!
|
|
OPEN( UNIT = iunaxsf, FILE = TRIM( prefix ) // ".axsf", &
|
|
STATUS = 'UNKNOWN', ACTION = 'WRITE', POSITION = 'APPEND' )
|
|
OPEN( UNIT = iunmeta, FILE = TRIM( prefix ) // '.metadyn', &
|
|
STATUS = 'UNKNOWN', ACTION = 'WRITE', POSITION = 'APPEND' )
|
|
!
|
|
END IF
|
|
!
|
|
END IF
|
|
!
|
|
IF ( first_metadyn_iter == max_metadyn_iter ) THEN
|
|
!
|
|
WRITE( stdout, '(/,5X,"Simulation already completed",/)' )
|
|
!
|
|
CLOSE( UNIT = iunmeta, STATUS = 'KEEP' )
|
|
!
|
|
CALL stop_run( .FALSE. )
|
|
!
|
|
END IF
|
|
!
|
|
gaussian_pos(:) = target(1:ncolvar)
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE metadyn_init
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE add_gaussians( iter )
|
|
!------------------------------------------------------------------------
|
|
!
|
|
USE metadyn_vars, ONLY : ncolvar, metadyn_history, fe_grad, fe_step, &
|
|
dfe_acc, g_amplitude
|
|
USE basic_algebra_routines
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER, INTENT(IN) :: iter
|
|
!
|
|
INTEGER :: i
|
|
REAL(DP), ALLOCATABLE :: delta(:)
|
|
!
|
|
! ... history dependent term
|
|
!
|
|
IF ( iter == 1 ) RETURN
|
|
!
|
|
ALLOCATE( delta( ncolvar ) )
|
|
!
|
|
dfe_acc = 0.D0
|
|
!
|
|
DO i = 1, iter - 1
|
|
!
|
|
delta = metadyn_history(:,iter) - metadyn_history(:,i)
|
|
!
|
|
dfe_acc(:) = dfe_acc(:) + delta(:) / fe_step(:)**2 * &
|
|
EXP( - SUM( delta(:)**2 / ( 2.D0 * fe_step(:)**2 ) ) )
|
|
!
|
|
END DO
|
|
!
|
|
fe_grad(:) = fe_grad(:) - g_amplitude * dfe_acc(:)
|
|
!
|
|
DEALLOCATE( delta )
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE add_gaussians
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE add_domain_potential()
|
|
!------------------------------------------------------------------------
|
|
!
|
|
! ... a repulsive potential is added to confine the collective variables
|
|
! ... within the appropriate domain :
|
|
!
|
|
! ... V(s) = A * ( sigma / s )^12
|
|
!
|
|
! ... where A is the amplitude of the gaussians used for meta-dynamics
|
|
!
|
|
USE constraints_module, ONLY : target, constr_type, dmax
|
|
USE metadyn_vars, ONLY : ncolvar, fe_grad, g_amplitude
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER :: i
|
|
REAL(DP) :: A, s, inv_s
|
|
!
|
|
REAL(DP), PARAMETER :: coord_sigma = 0.050D0
|
|
REAL(DP), PARAMETER :: dist_sigma = 0.050D0
|
|
REAL(DP), PARAMETER :: stfac_sigma = 0.005D0
|
|
!
|
|
!
|
|
A = 12.D0 * g_amplitude
|
|
!
|
|
DO i = 1, ncolvar
|
|
!
|
|
SELECT CASE( constr_type(i) )
|
|
CASE( 1, 2 )
|
|
!
|
|
! ... coordination must always be larger than a minimum threshold
|
|
!
|
|
inv_s = 1.D0 / target(i)
|
|
!
|
|
fe_grad(i) = fe_grad(i) - A * inv_s * ( coord_sigma * inv_s )**11
|
|
!
|
|
CASE( 3 )
|
|
!
|
|
! ... a distance can never be larger than dmax ( check file
|
|
! ... constraints_module.f90 for its definition )
|
|
!
|
|
inv_s = 1.D0 / ( dmax - target(i) )
|
|
!
|
|
fe_grad(i) = fe_grad(i) - A * inv_s * ( dist_sigma * inv_s )**11
|
|
!
|
|
CASE( 6 )
|
|
!
|
|
! ... the square modulus of the structure factor is never negative
|
|
! ... or larger than one
|
|
!
|
|
inv_s = 1.D0 / target(i)
|
|
!
|
|
fe_grad(i) = fe_grad(i) - A * inv_s * ( stfac_sigma * inv_s )**11
|
|
!
|
|
inv_s = 1.D0 / ( 1.D0 - target(i) )
|
|
!
|
|
fe_grad(i) = fe_grad(i) - A * inv_s * ( stfac_sigma * inv_s )**11
|
|
!
|
|
END SELECT
|
|
!
|
|
END DO
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE add_domain_potential
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE evolve_collective_vars( norm_fe_grad )
|
|
!------------------------------------------------------------------------
|
|
!
|
|
! ... the collective variables are evolved taking care of the
|
|
! ... additional constraints imposed by the domain definition
|
|
!
|
|
USE constants, ONLY : eps32
|
|
USE constraints_module, ONLY : constr_type, target, dmax
|
|
USE metadyn_vars, ONLY : ncolvar, fe_grad, fe_step, new_target, &
|
|
to_target, shake_nstep, gaussian_pos, &
|
|
g_amplitude
|
|
USE random_numbers, ONLY : rndm
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
REAL(DP), INTENT(IN) :: norm_fe_grad
|
|
!
|
|
INTEGER :: i
|
|
REAL(DP) :: step
|
|
!
|
|
!
|
|
IF ( norm_fe_grad < eps32 ) &
|
|
CALL errore( 'evolve_collective_vars', 'norm( fe_grad ) = 0', 1 )
|
|
!
|
|
IF ( g_amplitude > 0.D0 ) fe_grad(:) = fe_grad(:) / norm_fe_grad
|
|
!
|
|
DO i = 1, ncolvar
|
|
!
|
|
gaussian_pos(i) = target(i) - fe_step(i) * fe_grad(i)
|
|
!
|
|
step = ( 1.D0 + 0.5D0*rndm() ) * fe_step(i)
|
|
!
|
|
new_target(i) = target(i) - step * fe_grad(i)
|
|
!
|
|
END DO
|
|
!
|
|
CALL impose_domain_constraints()
|
|
!
|
|
to_target(:) = ( new_target(:) - target(1:ncolvar) ) / DBLE( shake_nstep )
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE evolve_collective_vars
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE impose_domain_constraints()
|
|
!------------------------------------------------------------------------
|
|
!
|
|
USE constraints_module, ONLY : constr_type, dmax
|
|
USE metadyn_vars, ONLY : ncolvar, new_target
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER :: i
|
|
!
|
|
!
|
|
DO i = 1, ncolvar
|
|
!
|
|
SELECT CASE( constr_type(i) )
|
|
CASE( 1, 2 )
|
|
!
|
|
! ... coordination must always be larger than zero
|
|
!
|
|
new_target(i) = ABS( new_target(i) )
|
|
!
|
|
CASE( 3 )
|
|
!
|
|
! ... a distance can never be larger than dmax ( check file
|
|
! ... constraints_module.f90 for its definition )
|
|
!
|
|
IF ( new_target(i) > dmax ) &
|
|
new_target(i) = 2.D0 * dmax - new_target(i)
|
|
!
|
|
CASE( 6 )
|
|
!
|
|
! ... the square modulus of the structure factor is never
|
|
! ... negative or larger than one
|
|
!
|
|
new_target(i) = ABS( new_target(i) )
|
|
!
|
|
IF ( new_target(i) > 1.D0 ) new_target(i) = 2.D0 - new_target(i)
|
|
!
|
|
CASE( 7 )
|
|
!
|
|
! ... the spherical average of the structure factor must be within
|
|
! ... -1 and 1
|
|
!
|
|
IF ( new_target(i) > +1.D0 ) new_target(i) = +2.D0 - new_target(i)
|
|
IF ( new_target(i) < -1.D0 ) new_target(i) = -2.D0 - new_target(i)
|
|
!
|
|
END SELECT
|
|
!
|
|
END DO
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE impose_domain_constraints
|
|
!
|
|
!------------------------------------------------------------------------
|
|
SUBROUTINE set_target()
|
|
!------------------------------------------------------------------------
|
|
!
|
|
USE metadyn_vars, ONLY : ncolvar, to_target, to_new_target
|
|
USE constraints_module, ONLY : target
|
|
!
|
|
!
|
|
IF ( to_new_target ) &
|
|
target(1:ncolvar) = target(1:ncolvar) + to_target(:)
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE set_target
|
|
!
|
|
END MODULE metadyn_base
|