perform Pulay's direct inversion in the iterative subspace extrapolation:
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
integer(kind=ip), | intent(in) | :: | n | |||
integer(kind=ip), | intent(inout) | :: | nmat | |||
integer(kind=ip), | intent(in) | :: | ndiis | |||
real(kind=rp), | intent(inout), | dimension(n, ndiis) | :: | x | ||
real(kind=rp), | intent(inout), | dimension(n, ndiis) | :: | e | ||
real(kind=rp), | intent(inout), | dimension(ndiis+1, ndiis+1) | :: | b | ||
real(kind=rp), | intent(inout), | dimension(n) | :: | xnew |
subroutine diis(n,nmat,ndiis,x,e,b,xnew)
!! perform Pulay's direct inversion in the iterative subspace extrapolation:
use mod_memory, only: mallocate, mfree
implicit none
! TODO doc
integer(ip), intent(in) :: n, ndiis
integer(ip), intent(inout) :: nmat
real(rp), dimension(n, ndiis), intent(inout) :: x, e
real(rp), dimension(ndiis+1, ndiis+1), intent(inout) :: b
real(rp), dimension(n), intent(inout) :: xnew
integer(ip) :: nmat1, i, info
integer(ip) :: j, k
real(rp), allocatable :: bloc(:,:), cex(:)
integer(ip), allocatable :: ipiv(:)
if (nmat.ge.ndiis) then
do j = 2, nmat - 10
do k = 2, nmat - 10
b(j,k) = b(j+10,k+10)
end do
end do
do j = 1, nmat - 10
x(:,j) = x(:,j+10)
e(:,j) = e(:,j+10)
end do
nmat = nmat - 10
end if
nmat1 = nmat + 1
call mallocate('diis [bloc]', nmat1, nmat1, bloc)
call mallocate('diis [cex]', nmat1, cex)
call mallocate('diis [ipiv]', nmat1, ipiv)
call makeb(n, nmat, ndiis, e, b)
bloc = b(1:nmat1,1:nmat1)
cex = 0.0_rp
cex(1) = 1.0_rp
call dgesv(nmat1, 1, bloc, nmat1, ipiv, cex, nmat1, info)
if(info /= 0) then
! inversion failed. discard the previous points and restart.
nmat = 1
call mfree('diis [bloc]', bloc)
call mfree('diis [cex]', cex)
call mfree('diis [ipiv]', ipiv)
return
end if
xnew = 0.0_rp
do i = 1, nmat
xnew = xnew + cex(i+1)*x(:,i)
end do
nmat = nmat + 1
call mfree('diis [bloc]', bloc)
call mfree('diis [cex]', cex)
call mfree('diis [ipiv]', ipiv)
end subroutine diis