2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
! Copyright (C) 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 .
|
|
|
|
!
|
|
|
|
!----------------------------------------------------------------------------
|
|
|
|
MODULE basic_algebra_routines
|
|
|
|
!----------------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
USE parameters, ONLY : DP
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
INTERFACE OPERATOR( .dot. )
|
|
|
|
!
|
|
|
|
MODULE PROCEDURE internal_dot_product
|
|
|
|
!
|
|
|
|
END INTERFACE
|
|
|
|
!
|
2003-11-24 23:35:36 +08:00
|
|
|
INTERFACE OPERATOR( * )
|
|
|
|
!
|
|
|
|
MODULE PROCEDURE matrix_times_vector, vector_times_matrix
|
|
|
|
!
|
|
|
|
END INTERFACE
|
|
|
|
!
|
|
|
|
CONTAINS
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
PURE FUNCTION internal_dot_product( vector1, vector2 )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL (KIND=DP), INTENT(IN) :: vector1(:), vector2(:)
|
|
|
|
REAL (KIND=DP) :: internal_dot_product
|
|
|
|
!
|
|
|
|
!
|
|
|
|
internal_dot_product = DOT_PRODUCT( vector1 , vector2 )
|
|
|
|
!
|
|
|
|
END FUNCTION internal_dot_product
|
|
|
|
!
|
|
|
|
!
|
2003-11-26 17:44:49 +08:00
|
|
|
!-----------------------------------------------------------------------
|
2003-11-26 02:19:16 +08:00
|
|
|
PURE FUNCTION norm( vector )
|
2003-11-24 23:35:36 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL (KIND=DP), INTENT(IN) :: vector(:)
|
|
|
|
REAL (KIND=DP) :: norm
|
|
|
|
!
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
norm = SQRT( vector .dot. vector )
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
END FUNCTION norm
|
|
|
|
!
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
2003-11-26 02:19:16 +08:00
|
|
|
PURE FUNCTION matrix_times_vector( matrix , vector )
|
2003-11-24 23:35:36 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL (KIND=DP), INTENT(IN) :: vector(:)
|
|
|
|
REAL (KIND=DP), INTENT(IN) :: matrix(:,:)
|
|
|
|
REAL (KIND=DP) :: matrix_times_vector(SIZE( vector ))
|
2003-11-26 17:44:49 +08:00
|
|
|
INTEGER :: i, dim
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
!
|
|
|
|
dim = SIZE( vector )
|
|
|
|
!
|
|
|
|
DO i = 1, dim
|
|
|
|
!
|
2003-11-26 17:44:49 +08:00
|
|
|
matrix_times_vector(i) = matrix(i,:) .dot. vector(:)
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
END FUNCTION matrix_times_vector
|
|
|
|
!
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
2003-11-26 02:19:16 +08:00
|
|
|
PURE FUNCTION vector_times_matrix( vector , matrix )
|
2003-11-24 23:35:36 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL (KIND=DP), INTENT(IN) :: vector(:)
|
|
|
|
REAL (KIND=DP), INTENT(IN) :: matrix(:,:)
|
|
|
|
REAL (KIND=DP) :: vector_times_matrix(SIZE( vector ))
|
2003-11-26 17:44:49 +08:00
|
|
|
INTEGER :: i, dim
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
!
|
|
|
|
dim = SIZE( vector )
|
|
|
|
!
|
|
|
|
DO i = 1, dim
|
|
|
|
!
|
2003-11-26 17:44:49 +08:00
|
|
|
vector_times_matrix(i) = vector(:) .dot. matrix(:,i)
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
END FUNCTION vector_times_matrix
|
|
|
|
!
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
2003-11-26 02:19:16 +08:00
|
|
|
PURE FUNCTION matrix( vector1 , vector2 )
|
2003-11-24 23:35:36 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL (KIND=DP), INTENT(IN) :: vector1(:), vector2(:)
|
|
|
|
REAL (KIND=DP) :: matrix(SIZE( vector1 ),SIZE( vector2 ))
|
|
|
|
INTEGER :: i, j
|
|
|
|
!
|
|
|
|
!
|
|
|
|
DO i = 1, SIZE( vector1 )
|
|
|
|
!
|
|
|
|
DO j = 1, SIZE( vector2 )
|
|
|
|
!
|
|
|
|
matrix(i,j) = vector1(i) * vector2(j)
|
|
|
|
!
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
END FUNCTION matrix
|
2003-11-26 02:19:16 +08:00
|
|
|
!
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
PURE FUNCTION identity( dim )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
INTEGER, INTENT(IN) :: dim
|
|
|
|
REAL(KIND=DP) :: identity(dim,dim)
|
|
|
|
INTEGER :: i
|
|
|
|
!
|
|
|
|
!
|
2003-11-26 17:44:49 +08:00
|
|
|
identity = 0.D0
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
DO i = 1, dim
|
|
|
|
!
|
|
|
|
identity(i,i) = 1.D0
|
|
|
|
!
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
END FUNCTION identity
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
END MODULE basic_algebra_routines
|
|
|
|
!
|
|
|
|
!
|
|
|
|
!----------------------------------------------------------------------------
|
|
|
|
MODULE bfgs_module
|
|
|
|
!----------------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
! ... ionic relaxation through Broyden-Fletcher-Goldfarb-Shanno
|
|
|
|
! ... minimization and a "trust radius" line search based on
|
|
|
|
! ... Wolfe conditions
|
|
|
|
!
|
|
|
|
! ... references :
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
! ... 1) R. Fletcher, Practical Methods of Optimization, John Wiley and Sons,
|
|
|
|
! ... Chichester, 2nd edn, 1987.
|
|
|
|
! ... 2) Salomon R. Billeter, Alexander J. Turner, Walter Thiel,
|
2003-11-24 23:35:36 +08:00
|
|
|
! ... Phys. Chem. Chem. Phys. 2, 2177 (2000)
|
2003-11-26 02:19:16 +08:00
|
|
|
! ... 3) Salomon R. Billeter, Alessandro Curioni, Wanda Andreoni,
|
2003-11-24 23:35:36 +08:00
|
|
|
! ... Comput. Mat. Science 27, 437, (2003)
|
|
|
|
!
|
|
|
|
!
|
|
|
|
USE parameters, ONLY : DP
|
|
|
|
!
|
|
|
|
USE basic_algebra_routines
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
PRIVATE
|
|
|
|
!
|
|
|
|
PUBLIC :: bfgs
|
|
|
|
!
|
|
|
|
REAL(KIND=DP), ALLOCATABLE :: &
|
2003-11-27 01:22:24 +08:00
|
|
|
pos_old(:), &! old positions
|
|
|
|
inverse_hessian(:,:), &! inverse of the hessian matrix (updated via
|
|
|
|
! BFGS formula)
|
|
|
|
bfgs_step(:), &! bfgs direction
|
|
|
|
bfgs_step_old(:), &! old bfgs direction
|
|
|
|
gradient_old(:) ! old gradient
|
2003-11-24 23:35:36 +08:00
|
|
|
REAL(KIND=DP) :: &
|
2003-11-27 01:22:24 +08:00
|
|
|
trust_radius, &! displacement along the bfgs direction
|
|
|
|
trust_radius_old, &! old displacement along the bfgs direction
|
|
|
|
energy_old ! old energy
|
2003-11-26 02:19:16 +08:00
|
|
|
INTEGER :: &
|
2003-11-27 01:22:24 +08:00
|
|
|
iteration ! bfgs iteration
|
2003-11-24 23:35:36 +08:00
|
|
|
REAL(KIND=DP), PARAMETER :: &
|
2003-11-27 01:22:24 +08:00
|
|
|
trust_radius_max = 0.5D0, &! maximum allowed displacement
|
|
|
|
trust_radius_min = 1.D-5, &! minimum allowed displacement
|
|
|
|
trust_radius_ini = 0.5D0, &! initial displacement
|
|
|
|
trust_radius_end = 1.D-7 ! bfgs stops when trust_radius is less than
|
|
|
|
! this value
|
2003-11-24 23:35:36 +08:00
|
|
|
INTEGER, PARAMETER :: &
|
2003-11-27 01:22:24 +08:00
|
|
|
iunbfgs = 4 ! iunit for bfgs IO
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
CONTAINS
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
SUBROUTINE bfgs( pos, energy, gradient, scratch, stdout, energy_thr, &
|
|
|
|
gradient_thr, energy_error, gradient_error, &
|
|
|
|
step_accepted, conv_bfgs )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL(KIND=DP), INTENT(INOUT) :: pos(:)
|
|
|
|
REAL(KIND=DP), INTENT(INOUT) :: energy
|
|
|
|
REAL(KIND=DP), INTENT(INOUT) :: gradient(:)
|
|
|
|
CHARACTER (LEN=*), INTENT(IN) :: scratch
|
|
|
|
INTEGER, INTENT(IN) :: stdout
|
|
|
|
REAL(KIND=DP), INTENT(IN) :: energy_thr, gradient_thr
|
|
|
|
REAL(KIND=DP), INTENT(OUT) :: energy_error, gradient_error
|
|
|
|
LOGICAL, INTENT(OUT) :: step_accepted, conv_bfgs
|
|
|
|
INTEGER :: dim, i
|
|
|
|
LOGICAL :: lwolfe
|
|
|
|
!
|
|
|
|
!
|
|
|
|
dim = SIZE( pos )
|
|
|
|
!
|
|
|
|
ALLOCATE( pos_old( dim ) )
|
|
|
|
ALLOCATE( inverse_hessian( dim, dim ) )
|
|
|
|
ALLOCATE( bfgs_step( dim ) )
|
|
|
|
ALLOCATE( bfgs_step_old( dim ) )
|
|
|
|
ALLOCATE( gradient_old( dim ) )
|
|
|
|
!
|
|
|
|
CALL read_bfgs_file( scratch, dim )
|
|
|
|
!
|
|
|
|
conv_bfgs = ( ( energy_old - energy ) < energy_thr )
|
|
|
|
!
|
|
|
|
energy_error = ABS( energy_old - energy )
|
|
|
|
gradient_error = 0.D0
|
|
|
|
!
|
|
|
|
DO i = 1, dim
|
|
|
|
!
|
|
|
|
conv_bfgs = ( conv_bfgs .AND. ( ABS( gradient(i) ) < gradient_thr ) )
|
|
|
|
!
|
|
|
|
gradient_error = MAX( gradient_error, ABS( gradient(i) ) )
|
|
|
|
!
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
IF ( conv_bfgs ) THEN
|
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
CALL terminate_bfgs( energy, stdout, scratch )
|
2003-11-26 02:19:16 +08:00
|
|
|
!
|
2003-11-24 23:35:36 +08:00
|
|
|
RETURN
|
|
|
|
!
|
|
|
|
END IF
|
|
|
|
!
|
|
|
|
iteration = iteration + 1
|
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
WRITE( stdout, '(/,5X,"iteration = ",I3)' ) iteration
|
2003-11-24 23:35:36 +08:00
|
|
|
WRITE( stdout, '(5X,"energy new = ",F14.10)' ) energy
|
|
|
|
WRITE( stdout, '(5X,"energy old = ",F14.10)' ) energy_old
|
|
|
|
!
|
|
|
|
IF ( energy > energy_old ) THEN
|
2003-11-27 01:22:24 +08:00
|
|
|
!
|
|
|
|
! ... the previous step is rejected
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
step_accepted = .FALSE.
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
WRITE( stdout, '(/,5X,"CASE: energy_new > energy_old",/)' )
|
2003-11-27 01:22:24 +08:00
|
|
|
WRITE( stdout, '(/,5X,"gradient .dot. bfgs_step > 0.D0 : ",L1,/)' ) &
|
|
|
|
( ( gradient .dot. bfgs_step_old ) > 0.D0 )
|
|
|
|
!
|
|
|
|
! ... the old trust radius is reduced by a factor 2
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
trust_radius = 0.5D0 * trust_radius_old
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
WRITE( stdout, '(5X,"trust_radius = ",F14.10)' ) trust_radius
|
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
IF ( trust_radius < trust_radius_min ) THEN
|
|
|
|
!
|
|
|
|
! ... the history is resetted
|
|
|
|
!
|
|
|
|
WRITE( stdout, '(/,5X,"resetting bfgs history",/)' )
|
|
|
|
!
|
|
|
|
inverse_hessian = identity(dim)
|
|
|
|
!
|
|
|
|
bfgs_step = - inverse_hessian * gradient
|
|
|
|
!
|
|
|
|
trust_radius = trust_radius_ini
|
|
|
|
!
|
|
|
|
ELSE
|
|
|
|
!
|
|
|
|
! ... values saved of the previous step are restored
|
|
|
|
!
|
|
|
|
pos = pos_old
|
|
|
|
energy = energy_old
|
|
|
|
gradient = gradient_old
|
|
|
|
!
|
|
|
|
! ... old bfgs direction (normalized) is recovered
|
|
|
|
!
|
|
|
|
bfgs_step = bfgs_step_old / trust_radius_old
|
|
|
|
!
|
|
|
|
END IF
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
ELSE
|
2003-11-27 01:22:24 +08:00
|
|
|
!
|
|
|
|
! ... a new bfgs step is done
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
step_accepted = .TRUE.
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
WRITE( stdout, '(/,5X,"CASE: energy_new < energy_old",/)' )
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
CALL check_wolfe_conditions( lwolfe, energy, gradient )
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
WRITE( stdout, '(5X,"lwolfe = ",L1)' ) lwolfe
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
CALL update_inverse_hessian( gradient, dim )
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
! ... bfgs direction (not normalized)
|
|
|
|
!
|
2003-11-24 23:35:36 +08:00
|
|
|
bfgs_step = - inverse_hessian * gradient
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
IF ( ( gradient .dot. bfgs_step ) > 0.D0 ) THEN
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
! ... bfgs direction is reversed if not downhill
|
|
|
|
!
|
2003-11-24 23:35:36 +08:00
|
|
|
bfgs_step = - bfgs_step
|
|
|
|
!
|
|
|
|
WRITE( stdout, '(/,5X,"search direction reversed")' )
|
|
|
|
!
|
|
|
|
END IF
|
2003-11-27 01:22:24 +08:00
|
|
|
!
|
|
|
|
! ... the new trust radius is computed
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
CALL compute_trust_radius( lwolfe, energy, gradient, dim, &
|
|
|
|
stdout, conv_bfgs )
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
! ... if trust_radius < trust_radius_end convergence is achieved
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
IF ( conv_bfgs ) THEN
|
|
|
|
!
|
|
|
|
CALL terminate_bfgs( energy, stdout, scratch )
|
|
|
|
!
|
|
|
|
RETURN
|
|
|
|
!
|
|
|
|
END IF
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
WRITE( stdout, '(5X,"trust_radius = ",F14.10)' ) trust_radius
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
END IF
|
|
|
|
!
|
|
|
|
! ... actual positions are stored
|
|
|
|
!
|
|
|
|
pos_old = pos
|
|
|
|
!
|
|
|
|
! ... bfgs step
|
|
|
|
!
|
|
|
|
bfgs_step = trust_radius * bfgs_step / norm( bfgs_step )
|
|
|
|
!
|
|
|
|
! ... positions are updated
|
|
|
|
!
|
|
|
|
pos = pos + bfgs_step
|
|
|
|
!
|
|
|
|
CALL write_bfgs_file( energy, gradient, scratch )
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
DEALLOCATE( pos_old )
|
|
|
|
DEALLOCATE( inverse_hessian )
|
|
|
|
DEALLOCATE( bfgs_step )
|
|
|
|
DEALLOCATE( bfgs_step_old )
|
|
|
|
DEALLOCATE( gradient_old )
|
|
|
|
!
|
|
|
|
END SUBROUTINE bfgs
|
|
|
|
!
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
SUBROUTINE read_bfgs_file( scratch, dim )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
USE io_files, ONLY : prefix
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
CHARACTER (LEN=*), INTENT(IN) :: scratch
|
|
|
|
INTEGER, INTENT(IN) :: dim
|
|
|
|
CHARACTER (LEN=256) :: bfgs_file
|
|
|
|
LOGICAL :: file_exists
|
|
|
|
!
|
|
|
|
!
|
|
|
|
bfgs_file = TRIM( scratch ) // TRIM( prefix ) //'.bfgs'
|
|
|
|
!
|
|
|
|
INQUIRE( FILE = TRIM( bfgs_file ) , EXIST = file_exists )
|
|
|
|
!
|
|
|
|
IF ( file_exists ) THEN
|
2003-11-27 01:22:24 +08:00
|
|
|
!
|
|
|
|
! ... bfgs is restarted from file
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
OPEN( UNIT = iunbfgs, FILE = TRIM( bfgs_file ), &
|
|
|
|
STATUS = 'UNKNOWN', ACTION = 'READ' )
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
READ( iunbfgs, * ) iteration
|
2003-11-24 23:35:36 +08:00
|
|
|
READ( iunbfgs, * ) pos_old
|
|
|
|
READ( iunbfgs, * ) energy_old
|
|
|
|
READ( iunbfgs, * ) gradient_old
|
|
|
|
READ( iunbfgs, * ) bfgs_step_old
|
|
|
|
READ( iunbfgs, * ) trust_radius_old
|
|
|
|
READ( iunbfgs, * ) inverse_hessian
|
|
|
|
!
|
|
|
|
CLOSE( UNIT = iunbfgs )
|
|
|
|
!
|
|
|
|
ELSE
|
2003-11-27 01:22:24 +08:00
|
|
|
!
|
|
|
|
! ... bfgs initialization
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
iteration = 0
|
|
|
|
pos_old = 0.D0
|
|
|
|
energy_old = 0.D0
|
|
|
|
gradient_old = 0.D0
|
|
|
|
bfgs_step_old = 0.D0
|
|
|
|
trust_radius_old = trust_radius_ini
|
2003-11-26 17:44:49 +08:00
|
|
|
inverse_hessian = identity(dim)
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
END IF
|
|
|
|
!
|
|
|
|
END SUBROUTINE read_bfgs_file
|
|
|
|
!
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
SUBROUTINE write_bfgs_file( energy, gradient, scratch )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
USE io_files, ONLY : prefix
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL(KIND=DP), INTENT(IN) :: energy
|
|
|
|
REAL(KIND=DP), INTENT(IN) :: gradient(:)
|
|
|
|
CHARACTER (LEN=*), INTENT(IN) :: scratch
|
|
|
|
!
|
|
|
|
!
|
|
|
|
OPEN( UNIT = iunbfgs, FILE = TRIM( scratch )//TRIM( prefix )//'.bfgs', &
|
|
|
|
STATUS = 'UNKNOWN', ACTION = 'WRITE' )
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
WRITE( iunbfgs, * ) iteration
|
2003-11-24 23:35:36 +08:00
|
|
|
WRITE( iunbfgs, * ) pos_old
|
|
|
|
WRITE( iunbfgs, * ) energy
|
|
|
|
WRITE( iunbfgs, * ) gradient
|
|
|
|
WRITE( iunbfgs, * ) bfgs_step
|
|
|
|
WRITE( iunbfgs, * ) trust_radius
|
|
|
|
WRITE( iunbfgs, * ) inverse_hessian
|
|
|
|
!
|
|
|
|
CLOSE( UNIT = iunbfgs )
|
|
|
|
!
|
|
|
|
END SUBROUTINE write_bfgs_file
|
|
|
|
!
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
2003-11-26 02:19:16 +08:00
|
|
|
SUBROUTINE update_inverse_hessian( gradient, dim )
|
2003-11-24 23:35:36 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
USE constants, ONLY : eps16
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
2003-11-26 17:44:49 +08:00
|
|
|
REAL(KIND=DP), INTENT(IN) :: gradient(:)
|
|
|
|
INTEGER, INTENT(IN) :: dim
|
|
|
|
REAL(KIND=DP) :: gamma(dim)
|
|
|
|
REAL(KIND=DP) :: sdotgamma
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
!
|
|
|
|
gamma = gradient - gradient_old
|
|
|
|
!
|
2003-11-26 02:19:16 +08:00
|
|
|
sdotgamma = bfgs_step_old .dot. gamma
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
IF ( ABS( sdotgamma ) < eps16 ) THEN
|
|
|
|
!
|
|
|
|
inverse_hessian = inverse_hessian
|
|
|
|
!
|
|
|
|
ELSE
|
|
|
|
!
|
2003-11-26 17:44:49 +08:00
|
|
|
inverse_hessian = inverse_hessian + ( identity(dim) + &
|
|
|
|
( gamma .dot. ( inverse_hessian * gamma ) ) / sdotgamma ) * &
|
|
|
|
matrix( bfgs_step_old, bfgs_step_old ) / sdotgamma - &
|
|
|
|
( matrix( bfgs_step_old, ( gamma * inverse_hessian ) ) + &
|
|
|
|
matrix( ( inverse_hessian * gamma ), bfgs_step_old ) ) / sdotgamma
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
END IF
|
|
|
|
!
|
|
|
|
END SUBROUTINE update_inverse_hessian
|
|
|
|
!
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
SUBROUTINE check_wolfe_conditions( lwolfe, energy, gradient )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL(KIND=DP), INTENT(IN) :: energy
|
|
|
|
REAL(KIND=DP), INTENT(IN) :: gradient(:)
|
|
|
|
REAL(KIND=DP), PARAMETER :: w_1 = 1.0D-4
|
|
|
|
REAL(KIND=DP), PARAMETER :: w_2 = 0.9D0
|
|
|
|
!
|
|
|
|
LOGICAL, INTENT(OUT) :: lwolfe
|
|
|
|
!
|
|
|
|
lwolfe = ( energy - energy_old ) < &
|
2003-11-26 02:19:16 +08:00
|
|
|
w_1 * ( gradient_old .dot. bfgs_step_old )
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
lwolfe = lwolfe .AND. &
|
2003-11-26 02:19:16 +08:00
|
|
|
( ( gradient .dot. bfgs_step_old ) > &
|
|
|
|
w_2 * ( gradient_old .dot. bfgs_step_old ) )
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
END SUBROUTINE check_wolfe_conditions
|
|
|
|
!
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
2003-11-27 01:22:24 +08:00
|
|
|
SUBROUTINE compute_trust_radius( lwolfe, energy, gradient, dim, &
|
|
|
|
stdout, conv_bfgs )
|
2003-11-24 23:35:36 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
LOGICAL, INTENT(IN) :: lwolfe
|
|
|
|
REAL(KIND=DP), INTENT(IN) :: energy
|
|
|
|
REAL(KIND=DP), INTENT(IN) :: gradient(:)
|
|
|
|
INTEGER, INTENT(IN) :: dim
|
|
|
|
INTEGER, INTENT(IN) :: stdout
|
|
|
|
LOGICAL, INTENT(OUT) :: conv_bfgs
|
|
|
|
REAL(KIND=DP) :: a
|
|
|
|
LOGICAL :: ltest
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
!
|
|
|
|
ltest = ( energy - energy_old ) < &
|
2003-11-26 02:19:16 +08:00
|
|
|
1.0D-4 * ( gradient_old .dot. bfgs_step_old )
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
ltest = ltest .AND. ( norm( bfgs_step ) > trust_radius_old )
|
|
|
|
!
|
|
|
|
IF ( ltest ) THEN
|
|
|
|
!
|
|
|
|
a = 1.25D0
|
|
|
|
!
|
|
|
|
ELSE
|
|
|
|
!
|
|
|
|
a = 1.D0
|
|
|
|
!
|
|
|
|
END IF
|
|
|
|
!
|
|
|
|
IF ( lwolfe ) THEN
|
|
|
|
!
|
|
|
|
trust_radius = MIN( trust_radius_max, 2.D0 * a * trust_radius_old )
|
|
|
|
!
|
|
|
|
ELSE
|
|
|
|
!
|
|
|
|
trust_radius = MIN( trust_radius_max, a * trust_radius_old, &
|
|
|
|
norm( bfgs_step ) )
|
|
|
|
!
|
|
|
|
END IF
|
|
|
|
!
|
|
|
|
IF ( trust_radius < trust_radius_end ) THEN
|
|
|
|
!
|
|
|
|
conv_bfgs = .TRUE.
|
|
|
|
!
|
|
|
|
ELSE IF ( trust_radius < trust_radius_min ) THEN
|
2003-11-27 01:22:24 +08:00
|
|
|
!
|
|
|
|
! ... the history is resetted
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
|
|
|
WRITE( stdout, '(/,5X,"resetting bfgs history",/)' )
|
|
|
|
!
|
2003-11-26 17:44:49 +08:00
|
|
|
inverse_hessian = identity(dim)
|
2003-11-24 23:35:36 +08:00
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
bfgs_step = - inverse_hessian * gradient
|
|
|
|
!
|
|
|
|
trust_radius = trust_radius_ini
|
|
|
|
!
|
2003-11-24 23:35:36 +08:00
|
|
|
END IF
|
|
|
|
!
|
|
|
|
END SUBROUTINE compute_trust_radius
|
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
SUBROUTINE terminate_bfgs( energy, stdout, scratch )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
USE io_files, ONLY : prefix
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL(KIND=DP), INTENT(IN) :: energy
|
|
|
|
INTEGER, INTENT(IN) :: stdout
|
|
|
|
CHARACTER (LEN=*), INTENT(IN) :: scratch
|
|
|
|
!
|
|
|
|
!
|
|
|
|
WRITE( stdout, '(/,5X,"bfgs converged in ",I3," iterations")' ) &
|
|
|
|
iteration
|
|
|
|
WRITE( stdout, '(/,5X,"Final energy: ",F14.10," ryd"/)' ) energy
|
|
|
|
!
|
2003-11-27 23:31:36 +08:00
|
|
|
WRITE( stdout, '(/,5X,"Saving the approssimate hessian")' )
|
|
|
|
!
|
|
|
|
OPEN( UNIT = iunbfgs, FILE = TRIM( scratch )//TRIM( prefix )//'.hess', &
|
|
|
|
STATUS = 'UNKNOWN', ACTION = 'WRITE' )
|
|
|
|
!
|
|
|
|
WRITE( iunbfgs, * ) SHAPE( inverse_hessian )
|
|
|
|
WRITE( iunbfgs, * ) inverse_hessian
|
|
|
|
!
|
|
|
|
CLOSE( UNIT = iunbfgs )
|
|
|
|
!
|
2003-11-27 01:22:24 +08:00
|
|
|
OPEN( UNIT = iunbfgs, &
|
|
|
|
FILE = TRIM( scratch )//TRIM( prefix )//'.bfgs' )
|
|
|
|
CLOSE( UNIT = iunbfgs, STATUS = 'DELETE' )
|
|
|
|
!
|
|
|
|
DEALLOCATE( pos_old )
|
|
|
|
DEALLOCATE( inverse_hessian )
|
|
|
|
DEALLOCATE( bfgs_step )
|
|
|
|
DEALLOCATE( bfgs_step_old )
|
|
|
|
DEALLOCATE( gradient_old )
|
|
|
|
!
|
|
|
|
END SUBROUTINE terminate_bfgs
|
|
|
|
!
|
2003-11-24 23:35:36 +08:00
|
|
|
END MODULE bfgs_module
|