mirror of https://gitlab.com/QEF/q-e.git
367 lines
10 KiB
Fortran
367 lines
10 KiB
Fortran
!
|
|
! Copyright (C) 2001-2003 PWSCF 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 .
|
|
!
|
|
#include "machine.h"
|
|
!
|
|
!----------------------------------------------------------------------------
|
|
SUBROUTINE move_ions()
|
|
!----------------------------------------------------------------------------
|
|
!
|
|
! ... This routine moves the ions according to the requested scheme:
|
|
!
|
|
! ... iswitch = 1 bfgs minimizations or conjugate gradient
|
|
! ... iswitch = 2 constrained bfgs minimization:
|
|
! ... the user must supply the routine 'constrain' which
|
|
! ... defines the constraint equation and the gradient
|
|
! ... the constraint function gv(tau), dgv(i,tau) such
|
|
! ... that:
|
|
!
|
|
! ... gv({tau}) - target = 0,
|
|
!
|
|
! ... and
|
|
!
|
|
! ... D gv( {tau} )
|
|
! ... dgv(i,na) = ---------------.
|
|
! ... D tau(i,na)
|
|
!
|
|
! ... iswitch = 3 molecular dynamics, (verlet of vcsmd)
|
|
! ... iswitch = 4 molecular dynamics with one constraint,
|
|
! ... the same conventions as iswitch = 2
|
|
!
|
|
USE io_global, ONLY : stdout
|
|
USE io_files, ONLY : tmp_dir
|
|
USE bfgs_module, ONLY : lbfgs_ndim, new_bfgs => bfgs, lin_bfgs
|
|
USE kinds, ONLY : DP
|
|
USE brilz, ONLY : alat, at, bg
|
|
USE basis, ONLY : nat, ityp, tau, atm
|
|
USE gvect, ONLY : nr1, nr2, nr3
|
|
USE klist, ONLY : nelec
|
|
USE symme, ONLY : s, ftau, nsym, irt
|
|
USE ener, ONLY : etot
|
|
USE force_mod, ONLY : force
|
|
USE control_flags, ONLY : tr2, upscale, iswitch, lbfgs, loldbfgs, &
|
|
conv_ions
|
|
USE relax, ONLY : epse, epsf, starting_scf_threshold
|
|
USE cellmd, ONLY : lmovecell, calc
|
|
#if defined (__PARA)
|
|
USE para, ONLY : me, mypool
|
|
USE io_global, ONLY : ionode_id
|
|
USE mp, ONLY : mp_bcast
|
|
#endif
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
REAL(KIND=DP) :: dummy, gv
|
|
REAL(KIND=DP), ALLOCATABLE :: dgv(:,:)
|
|
REAL(KIND=DP) :: dgv2, theta0
|
|
! auxiliar variable :
|
|
! gv=0 defines the constrain
|
|
! the gradient of gv
|
|
! its square modulus
|
|
! the value of the one-dimensional const
|
|
REAL(KIND=DP) :: energy_error, gradient_error
|
|
LOGICAL :: step_accepted
|
|
REAL(KIND=DP), ALLOCATABLE :: pos(:), gradient(:)
|
|
!
|
|
!
|
|
conv_ions = .FALSE.
|
|
!
|
|
IF ( iswitch == 2 .OR. iswitch == 4 ) THEN
|
|
!
|
|
ALLOCATE( dgv(3,nat) )
|
|
!
|
|
! ... gv is the function which define the constrain, now first of all we
|
|
! ... find the constrain theta0 such that gv=0, and find the gradient of
|
|
! ... gv, dgv
|
|
!
|
|
dummy = 0.D0
|
|
!
|
|
CALL constrain( theta0, gv, dgv, dgv2, dummy, nat, tau, alat )
|
|
!
|
|
! ... find the constrained forces
|
|
!
|
|
CALL new_force( dgv, dgv2 )
|
|
!
|
|
DEALLOCATE( dgv )
|
|
!
|
|
END IF
|
|
!
|
|
! ... do the minimization / dynamics step
|
|
!
|
|
IF ( lmovecell .AND. ( iswitch == 2 .OR. iswitch == 4 ) ) &
|
|
CALL errore( 'move_ions', &
|
|
& 'variable cell and constrain not implemented', 1 )
|
|
!
|
|
! ... BFGS algorithm is used to minimize ionic configuration
|
|
!
|
|
IF ( lbfgs ) THEN
|
|
!
|
|
! ... the new bfgs procedure is used
|
|
!
|
|
#if defined (__PARA)
|
|
!
|
|
! ... only one node does the calculation in the parallel case
|
|
!
|
|
IF ( me == 1 .AND. mypool == 1 ) THEN
|
|
#endif
|
|
!
|
|
ALLOCATE( pos( 3 * nat ) )
|
|
ALLOCATE( gradient( 3 * nat ) )
|
|
!
|
|
pos = RESHAPE( SOURCE = tau, SHAPE = (/ 3 * nat /) ) * alat
|
|
gradient = - RESHAPE( SOURCE = force, SHAPE = (/ 3 * nat /) )
|
|
!
|
|
IF ( lbfgs_ndim == 1 ) THEN
|
|
!
|
|
CALL new_bfgs( pos, etot, gradient, tmp_dir, stdout, epse, &
|
|
epsf, energy_error, gradient_error, step_accepted, &
|
|
conv_ions )
|
|
!
|
|
ELSE
|
|
!
|
|
CALL lin_bfgs( pos, etot, gradient, tmp_dir, stdout, epse, &
|
|
epsf, energy_error, gradient_error, step_accepted, &
|
|
conv_ions )
|
|
!
|
|
END IF
|
|
!
|
|
IF ( .NOT. conv_ions ) THEN
|
|
!
|
|
! ... if a new bfgs step is done, new thresholds are computed
|
|
!
|
|
IF ( step_accepted ) THEN
|
|
!
|
|
tr2 = starting_scf_threshold * &
|
|
MIN( 1.D0, ( energy_error / ( epse * upscale ) ), &
|
|
( gradient_error / ( epsf * upscale ) ) )
|
|
tr2 = MAX( ( starting_scf_threshold / upscale ), tr2 )
|
|
!
|
|
END IF
|
|
!
|
|
WRITE( stdout, '(5X,"new conv_thr",T30,"= ",F18.10,/)' ) tr2
|
|
!
|
|
END IF
|
|
!
|
|
tau = RESHAPE( SOURCE = pos, SHAPE = (/ 3 , nat /) ) / alat
|
|
force = - RESHAPE( SOURCE = gradient, SHAPE = (/ 3 , nat /) )
|
|
!
|
|
CALL output_tau(conv_ions)
|
|
!
|
|
DEALLOCATE( pos )
|
|
DEALLOCATE( gradient )
|
|
#if defined (__PARA)
|
|
!
|
|
END IF
|
|
!
|
|
! ... broadcast calculated quantities to all nodes
|
|
!
|
|
CALL mp_bcast( tau, ionode_id )
|
|
CALL mp_bcast( force, ionode_id )
|
|
CALL mp_bcast( tr2, ionode_id )
|
|
CALL mp_bcast( conv_ions, ionode_id )
|
|
#endif
|
|
!
|
|
ELSE IF ( loldbfgs ) THEN
|
|
!
|
|
! ... the old bfgs scheme is used
|
|
!
|
|
CALL bfgs()
|
|
!
|
|
END IF
|
|
!
|
|
! ... molecular dynamics schemes are used
|
|
!
|
|
IF ( iswitch == 3 .OR.iswitch == 4 ) THEN
|
|
!
|
|
IF ( calc == ' ' ) CALL dynamics() ! verlet dynamics
|
|
IF ( calc /= ' ' ) CALL vcsmd() ! variable cell shape md
|
|
!
|
|
END IF
|
|
!
|
|
IF ( iswitch > 4 .OR. iswitch <= 0 ) THEN
|
|
!
|
|
CALL errore( 'move_ions', 'iswitch value not implemented or wrong', 1 )
|
|
!
|
|
END IF
|
|
!
|
|
! ... check if the new positions satisfy the constrain equation, in
|
|
! ... the CP case this is done inside the routine "cp"
|
|
!
|
|
IF ( iswitch == 2 .OR. iswitch == 4 ) &
|
|
CALL check_constrain( alat, tau, atm, ityp, theta0, nat )
|
|
!
|
|
! ... before leaving check that the new positions still transform
|
|
! ... according to the symmetry of the system.
|
|
!
|
|
CALL checkallsym( nsym, s, nat, tau, ityp, at, bg, nr1, nr2, nr3, irt, ftau )
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE move_ions
|
|
!
|
|
!
|
|
!----------------------------------------------------------------------------
|
|
SUBROUTINE new_force( dg, dg2 )
|
|
!----------------------------------------------------------------------------
|
|
!
|
|
! find the lagrange multiplier lambda for the problem with one const
|
|
!
|
|
! force*dg
|
|
! lambda = - --------,
|
|
! |dg|^2
|
|
!
|
|
! and redefine the forces:
|
|
!
|
|
! force = force + lambda*dg
|
|
!
|
|
! where dg is the gradient of the constraint function
|
|
!
|
|
USE io_global, ONLY : stdout
|
|
USE kinds, ONLY : DP
|
|
USE basis, ONLY : nat
|
|
USE brilz, ONLY : at, bg
|
|
USE force_mod, ONLY : force
|
|
USE symme, ONLY : s, nsym, irt
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER :: na, i, ipol
|
|
REAL(KIND=DP) :: dg(3, nat), lambda, dg2, sum
|
|
REAL(KIND=DP) :: DDOT
|
|
EXTERNAL DDOT
|
|
!
|
|
!
|
|
lambda = 0.D0
|
|
!
|
|
IF ( dg2 /= 0.D0 ) THEN
|
|
!
|
|
lambda = - DDOT( 3 * nat, force, 1, dg, 1 ) / dg2
|
|
!
|
|
CALL DAXPY( 3 * nat, lambda, dg, 1, force, 1)
|
|
!
|
|
IF ( DDOT( 3 * nat, force, 1, dg, 1 )**2 > 1.D-30 ) THEN
|
|
!
|
|
CALL errore( 'new_force', 'force is not orthogonal to constrain', - 1 )
|
|
PRINT *, DDOT( 3 * nat, force, 1, dg, 1 )**2
|
|
!
|
|
END IF
|
|
!
|
|
DO ipol = 1, 3
|
|
sum = 0.D0
|
|
DO na = 1, nat
|
|
sum = sum + force(ipol,na)
|
|
END DO
|
|
!
|
|
! ... impose total force = 0
|
|
!
|
|
DO na = 1, nat
|
|
force(ipol,na) = force(ipol,na) - sum / nat
|
|
END DO
|
|
END DO
|
|
!
|
|
! ... resymmetrize (should not be needed, but...)
|
|
!
|
|
IF ( nsym > 1 ) THEN
|
|
!
|
|
DO na = 1, nat
|
|
CALL trnvect( force(1,na), at, bg, - 1 )
|
|
END DO
|
|
!
|
|
CALL symvect( nat, force, nsym, s, irt )
|
|
!
|
|
DO na = 1, nat
|
|
CALL trnvect( force(1,na), at, bg, 1 )
|
|
END DO
|
|
!
|
|
END IF
|
|
!
|
|
WRITE( stdout, '(/5x,"Constrained forces")')
|
|
!
|
|
DO na = 1, nat
|
|
WRITE( stdout, '(3F14.8)') ( force(i,na) , i = 1, 3 )
|
|
END DO
|
|
!
|
|
END IF
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE new_force
|
|
!
|
|
!
|
|
!---------------------------------------------------------------------
|
|
SUBROUTINE check_constrain( alat, tau, atm, ityp, theta0, nat )
|
|
!---------------------------------------------------------------------
|
|
!
|
|
! update tau so that the constraint equation g=0 is satisfied,
|
|
! use the recursion formula:
|
|
!
|
|
! g(tau)
|
|
! tau' = tau - ------------ * dg(tau)
|
|
! |dg(tau)|^2
|
|
!
|
|
! in normal cases the constraint equation should be always satisfied
|
|
! the very first iteration.
|
|
!
|
|
USE io_global, ONLY : stdout
|
|
USE kinds, ONLY : DP
|
|
USE constants, ONLY : eps16
|
|
!
|
|
IMPLICIT NONE
|
|
!
|
|
INTEGER :: ityp(:), nat, na, i
|
|
CHARACTER(LEN=3) :: atm(:)
|
|
REAL(KIND=DP) :: tau(3,nat)
|
|
REAL(KIND=DP), ALLOCATABLE :: dg(:,:)
|
|
REAL(KIND=DP) :: alat, dg2, g, theta0, dummy, eps
|
|
INTEGER, PARAMETER :: maxiter = 250
|
|
!
|
|
!
|
|
ALLOCATE( dg(3,nat) )
|
|
!
|
|
CALL constrain( dummy, g, dg, dg2, theta0, nat, tau, alat )
|
|
!
|
|
WRITE( stdout, '(5X,"G = ",1PE9.2," iteration # ",I3)' ) g, 0
|
|
!
|
|
DO i = 1, maxiter
|
|
!
|
|
! ... check if g=0
|
|
!
|
|
IF ( ABS( g ) < eps16 ) GO TO 14
|
|
!
|
|
! ... if g<>0 find new tau = tau - g*dg/dg2 and check again
|
|
!
|
|
CALL DAXPY( 3 * nat, - g / dg2, dg, 1, tau, 1 )
|
|
!
|
|
CALL constrain( dummy, g, dg, dg2, theta0, nat, tau, alat )
|
|
!
|
|
WRITE( stdout, '(5X,"G = ",1PE9.2," iteration # ",I3)' ) g, i
|
|
!
|
|
END DO
|
|
!
|
|
CALL errore( 'new_dtau', 'g=0 is not satisfied g=', - 1 )
|
|
!
|
|
14 CONTINUE
|
|
!
|
|
WRITE( stdout, '(5X,"Number of step(s): ",I3)') i - 1
|
|
!
|
|
! ... if the atomic positions have been corrected write them on output
|
|
!
|
|
IF ( i > 1 ) THEN
|
|
!
|
|
WRITE( stdout, '(/5X,"Corrected atomic positions:",/)')
|
|
DO na = 1, nat
|
|
WRITE( stdout,'(A3,3X,3F14.9)') atm(ityp(na)), ( tau(i,na), i = 1, 3 )
|
|
END DO
|
|
!
|
|
END IF
|
|
!
|
|
DEALLOCATE( dg )
|
|
!
|
|
RETURN
|
|
!
|
|
END SUBROUTINE check_constrain
|