10
0
mirror of https://github.com/LCPQ/quantum_package synced 2024-12-26 14:23:43 +01:00
quantum_package/src/Utils/LinearAlgebra.irp.f

676 lines
16 KiB
Fortran
Raw Normal View History

2015-11-27 10:15:46 +01:00
subroutine svd(A,LDA,U,LDU,D,Vt,LDVt,m,n)
implicit none
BEGIN_DOC
! Compute A = U.D.Vt
!
! LDx : leftmost dimension of x
!
! Dimsneion of A is m x n
!
END_DOC
integer, intent(in) :: LDA, LDU, LDVt, m, n
double precision, intent(in) :: A(LDA,n)
2016-10-18 19:29:50 +02:00
double precision, intent(out) :: U(LDU,m)
2015-11-27 10:15:46 +01:00
double precision,intent(out) :: Vt(LDVt,n)
2016-10-18 19:29:50 +02:00
double precision,intent(out) :: D(min(m,n))
2015-11-27 10:15:46 +01:00
double precision,allocatable :: work(:)
integer :: info, lwork, i, j, k
double precision,allocatable :: A_tmp(:,:)
allocate (A_tmp(LDA,n))
A_tmp = A
! Find optimal size for temp arrays
allocate(work(1))
lwork = -1
2016-10-18 19:29:50 +02:00
call dgesvd('A','A', m, n, A_tmp, LDA, &
2015-11-27 10:15:46 +01:00
D, U, LDU, Vt, LDVt, work, lwork, info)
2017-04-12 20:23:04 +02:00
lwork = int(work(1))
2015-11-27 10:15:46 +01:00
deallocate(work)
allocate(work(lwork))
2016-10-18 19:29:50 +02:00
call dgesvd('A','A', m, n, A_tmp, LDA, &
2015-11-27 10:15:46 +01:00
D, U, LDU, Vt, LDVt, work, lwork, info)
deallocate(work,A_tmp)
if (info /= 0) then
print *, info, ': SVD failed'
stop
endif
end
subroutine ortho_canonical(overlap,LDA,N,C,LDC,m)
implicit none
BEGIN_DOC
! Compute C_new=C_old.U.s^-1/2 canonical orthogonalization.
!
! overlap : overlap matrix
!
! LDA : leftmost dimension of overlap array
!
! N : Overlap matrix is NxN (array is (LDA,N) )
!
! C : Coefficients of the vectors to orthogonalize. On exit,
! orthogonal vectors
!
! LDC : leftmost dimension of C
!
! m : Coefficients matrix is MxN, ( array is (LDC,N) )
!
END_DOC
integer, intent(in) :: lda, ldc, n
integer, intent(out) :: m
double precision, intent(in) :: overlap(lda,n)
double precision, intent(inout) :: C(ldc,n)
double precision, allocatable :: U(:,:)
double precision, allocatable :: Vt(:,:)
double precision, allocatable :: D(:)
2017-09-13 16:50:45 +02:00
double precision, allocatable :: S(:,:)
2017-11-27 10:58:32 +01:00
!DIR$ ATTRIBUTES ALIGN : 64 :: U, Vt, D
integer :: info, i, j
2016-05-11 21:45:56 +02:00
if (n < 2) then
return
endif
2017-09-13 16:50:45 +02:00
allocate (U(ldc,n), Vt(lda,n), D(n), S(lda,n))
call svd(overlap,lda,U,ldc,D,Vt,lda,n,n)
2018-01-08 18:26:51 +01:00
D(:) = dsqrt(D(:))
m=n
do i=1,n
if ( D(i) >= 1.d-6 ) then
2018-01-08 18:26:51 +01:00
D(i) = 1.d0/D(i)
else
m = i-1
print *, 'Removed Linear dependencies below:', 1.d0/D(m)
exit
endif
enddo
do i=m+1,n
D(i) = 0.d0
enddo
do i=1,m
if ( D(i) >= 1.d5 ) then
print *, 'Warning: Basis set may have linear dependence problems'
endif
enddo
do j=1,n
do i=1,n
2017-09-13 16:50:45 +02:00
S(i,j) = U(i,j)*D(j)
enddo
2018-01-08 18:26:51 +01:00
enddo
do j=1,n
do i=1,n
U(i,j) = C(i,j)
enddo
enddo
2018-01-08 18:26:51 +01:00
call dgemm('N','N',n,n,n,1.d0,U,size(U,1),S,size(S,1),0.d0,C,size(C,1))
2017-09-13 16:50:45 +02:00
deallocate (U, Vt, D, S)
end
2015-11-27 10:15:46 +01:00
2016-10-18 19:29:50 +02:00
subroutine ortho_qr(A,LDA,m,n)
implicit none
BEGIN_DOC
! Orthogonalization using Q.R factorization
!
! A : matrix to orthogonalize
!
! LDA : leftmost dimension of A
!
! n : Number of rows of A
!
! m : Number of columns of A
!
END_DOC
integer, intent(in) :: m,n, LDA
double precision, intent(inout) :: A(LDA,n)
integer :: lwork, info
integer, allocatable :: jpvt(:)
double precision, allocatable :: tau(:), work(:)
allocate (jpvt(n), tau(n), work(1))
LWORK=-1
call dgeqrf( m, n, A, LDA, TAU, WORK, LWORK, INFO )
2017-04-12 20:23:04 +02:00
LWORK=2*int(WORK(1))
2016-10-18 19:29:50 +02:00
deallocate(WORK)
allocate(WORK(LWORK))
2017-03-25 11:56:08 +01:00
call dgeqrf(m, n, A, LDA, TAU, WORK, LWORK, INFO )
call dorgqr(m, n, n, A, LDA, tau, WORK, LWORK, INFO)
2016-10-18 19:29:50 +02:00
deallocate(WORK,jpvt,tau)
end
2016-11-16 10:17:37 +01:00
subroutine ortho_qr_unblocked(A,LDA,m,n)
implicit none
BEGIN_DOC
! Orthogonalization using Q.R factorization
!
! A : matrix to orthogonalize
!
! LDA : leftmost dimension of A
!
! n : Number of rows of A
!
! m : Number of columns of A
!
END_DOC
integer, intent(in) :: m,n, LDA
double precision, intent(inout) :: A(LDA,n)
integer :: info
integer, allocatable :: jpvt(:)
double precision, allocatable :: tau(:), work(:)
allocate (jpvt(n), tau(n), work(n))
call dgeqr2( m, n, A, LDA, TAU, WORK, INFO )
call dorg2r(m, n, n, A, LDA, tau, WORK, INFO)
deallocate(WORK,jpvt,tau)
end
subroutine ortho_lowdin(overlap,LDA,N,C,LDC,m)
implicit none
2014-04-07 20:01:30 +02:00
BEGIN_DOC
! Compute C_new=C_old.S^-1/2 orthogonalization.
!
! overlap : overlap matrix
!
! LDA : leftmost dimension of overlap array
!
! N : Overlap matrix is NxN (array is (LDA,N) )
!
! C : Coefficients of the vectors to orthogonalize. On exit,
! orthogonal vectors
!
! LDC : leftmost dimension of C
!
2017-06-02 14:20:59 +02:00
! M : Coefficients matrix is MxN, ( array is (LDC,N) )
!
2014-04-07 20:01:30 +02:00
END_DOC
integer, intent(in) :: LDA, ldc, n, m
double precision, intent(in) :: overlap(lda,n)
double precision, intent(inout) :: C(ldc,n)
double precision, allocatable :: U(:,:)
double precision, allocatable :: Vt(:,:)
double precision, allocatable :: D(:)
2017-09-13 16:50:45 +02:00
double precision, allocatable :: S(:,:)
2015-12-08 13:24:43 +01:00
integer :: info, i, j, k
2016-05-11 21:45:56 +02:00
if (n < 2) then
return
endif
2017-09-13 16:50:45 +02:00
allocate(U(ldc,n),Vt(lda,n),S(lda,n),D(n))
2016-10-18 19:29:50 +02:00
call svd(overlap,lda,U,ldc,D,Vt,lda,n,n)
2015-11-27 10:15:46 +01:00
!$OMP PARALLEL DEFAULT(NONE) &
2017-09-13 16:50:45 +02:00
!$OMP SHARED(S,U,D,Vt,n,C,m) &
!$OMP PRIVATE(i,j,k)
!$OMP DO
do i=1,n
if ( D(i) < 1.d-6 ) then
2015-11-30 20:57:41 +01:00
D(i) = 0.d0
else
D(i) = 1.d0/dsqrt(D(i))
endif
do j=1,n
2017-09-13 16:50:45 +02:00
S(j,i) = 0.d0
enddo
enddo
!$OMP END DO
do k=1,n
2015-12-08 15:43:36 +01:00
if (D(k) /= 0.d0) then
!$OMP DO
do j=1,n
do i=1,n
2017-09-13 16:50:45 +02:00
S(i,j) = S(i,j) + U(i,k)*D(k)*Vt(k,j)
2015-12-08 15:43:36 +01:00
enddo
enddo
2015-12-08 15:43:36 +01:00
!$OMP END DO NOWAIT
endif
enddo
!$OMP BARRIER
!$OMP DO
do j=1,n
do i=1,m
U(i,j) = C(i,j)
enddo
enddo
!$OMP END DO
!$OMP END PARALLEL
2017-09-13 16:50:45 +02:00
call dgemm('N','N',m,n,n,1.d0,U,size(U,1),S,size(S,1),0.d0,C,size(C,1))
2017-09-13 16:50:45 +02:00
deallocate(U,Vt,S,D)
end
2017-06-19 20:38:28 +02:00
subroutine get_inverse(A,LDA,m,C,LDC)
implicit none
BEGIN_DOC
! Returns the inverse of the square matrix A
END_DOC
integer, intent(in) :: m, LDA, LDC
double precision, intent(in) :: A(LDA,m)
double precision, intent(out) :: C(LDC,m)
integer :: info,lwork
integer, allocatable :: ipiv(:)
double precision,allocatable :: work(:)
2017-11-22 17:07:16 +01:00
allocate (ipiv(m), work(m*m))
2017-06-19 20:38:28 +02:00
lwork = size(work)
C(1:m,1:m) = A(1:m,1:m)
call dgetrf(m,m,C,size(C,1),ipiv,info)
if (info /= 0) then
print *, info
stop 'error in inverse (dgetrf)'
endif
call dgetri(m,C,size(C,1),ipiv,work,lwork,info)
if (info /= 0) then
print *, info
stop 'error in inverse (dgetri)'
endif
deallocate(ipiv,work)
end
subroutine get_pseudo_inverse(A,LDA,m,n,C,LDC)
implicit none
2014-04-07 20:01:30 +02:00
BEGIN_DOC
! Find C = A^-1
END_DOC
2017-06-19 20:38:28 +02:00
integer, intent(in) :: m,n, LDA, LDC
double precision, intent(in) :: A(LDA,n)
2017-06-19 20:38:28 +02:00
double precision, intent(out) :: C(LDC,m)
double precision, allocatable :: U(:,:), D(:), Vt(:,:), work(:), A_tmp(:,:)
integer :: info, lwork
integer :: i,j,k
allocate (D(n),U(m,n),Vt(n,n),work(1),A_tmp(m,n))
do j=1,n
do i=1,m
A_tmp(i,j) = A(i,j)
enddo
enddo
lwork = -1
call dgesvd('S','A', m, n, A_tmp, m,D,U,m,Vt,n,work,lwork,info)
if (info /= 0) then
print *, info, ': SVD failed'
stop
endif
2017-04-12 20:23:04 +02:00
lwork = int(work(1))
deallocate(work)
allocate(work(lwork))
call dgesvd('S','A', m, n, A_tmp, m,D,U,m,Vt,n,work,lwork,info)
if (info /= 0) then
2017-06-16 15:35:52 +02:00
print *, info, ':: SVD failed'
2014-04-07 20:01:30 +02:00
stop 1
endif
do i=1,n
2017-06-19 20:38:28 +02:00
if (D(i)/D(1) > 1.d-10) then
D(i) = 1.d0/D(i)
else
D(i) = 0.d0
endif
enddo
C = 0.d0
do i=1,m
do j=1,n
do k=1,n
2017-06-19 20:38:28 +02:00
C(j,i) = C(j,i) + U(i,k) * D(k) * Vt(k,j)
enddo
enddo
enddo
deallocate(U,D,Vt,work,A_tmp)
end
subroutine find_rotation(A,LDA,B,m,C,n)
implicit none
2014-04-07 20:01:30 +02:00
BEGIN_DOC
! Find A.C = B
END_DOC
integer, intent(in) :: m,n, LDA
double precision, intent(in) :: A(LDA,n), B(LDA,n)
double precision, intent(out) :: C(n,n)
double precision, allocatable :: A_inv(:,:)
allocate(A_inv(LDA,n))
2017-06-26 20:35:07 +02:00
call get_pseudo_inverse(A,LDA,m,n,A_inv,LDA)
integer :: i,j,k
call dgemm('N','N',n,n,m,1.d0,A_inv,n,B,LDA,0.d0,C,n)
deallocate(A_inv)
end
subroutine apply_rotation(A,LDA,R,LDR,B,LDB,m,n)
implicit none
2014-04-07 20:01:30 +02:00
BEGIN_DOC
! Apply the rotation found by find_rotation
END_DOC
2016-02-19 00:20:28 +01:00
integer, intent(in) :: m,n, LDA, LDB, LDR
double precision, intent(in) :: R(LDR,n)
double precision, intent(in) :: A(LDA,n)
double precision, intent(out) :: B(LDB,n)
call dgemm('N','N',m,n,n,1.d0,A,LDA,R,LDR,0.d0,B,LDB)
end
2014-06-25 14:58:58 +02:00
subroutine lapack_diagd(eigvalues,eigvectors,H,nmax,n)
implicit none
2014-04-07 20:01:30 +02:00
BEGIN_DOC
! Diagonalize matrix H
2014-05-19 18:35:56 +02:00
!
! H is untouched between input and ouptut
!
! eigevalues(i) = ith lowest eigenvalue of the H matrix
!
! eigvectors(i,j) = <i|psi_j> where i is the basis function and psi_j is the j th eigenvector
!
2014-04-07 20:01:30 +02:00
END_DOC
integer, intent(in) :: n,nmax
double precision, intent(out) :: eigvectors(nmax,n)
double precision, intent(out) :: eigvalues(n)
double precision, intent(in) :: H(nmax,n)
double precision,allocatable :: eigenvalues(:)
double precision,allocatable :: work(:)
integer ,allocatable :: iwork(:)
double precision,allocatable :: A(:,:)
integer :: lwork, info, i,j,l,k, liwork
allocate(A(nmax,n),eigenvalues(n))
! print*,'Diagonalization by jacobi'
! print*,'n = ',n
A=H
lwork = 2*n*n + 6*n+ 1
liwork = 5*n + 3
allocate (work(lwork),iwork(liwork))
lwork = -1
liwork = -1
call DSYEVD( 'V', 'U', n, A, nmax, eigenvalues, work, lwork, &
iwork, liwork, info )
if (info < 0) then
print *, irp_here, ': DSYEVD: the ',-info,'-th argument had an illegal value'
stop 2
endif
lwork = int( work( 1 ) )
liwork = iwork(1)
deallocate (work,iwork)
allocate (work(lwork),iwork(liwork))
call DSYEVD( 'V', 'U', n, A, nmax, eigenvalues, work, lwork, &
iwork, liwork, info )
deallocate(work,iwork)
if (info < 0) then
print *, irp_here, ': DSYEVD: the ',-info,'-th argument had an illegal value'
stop 2
else if( info > 0 ) then
write(*,*)'DSYEVD Failed'
stop 1
end if
eigvectors = 0.d0
eigvalues = 0.d0
do j = 1, n
eigvalues(j) = eigenvalues(j)
do i = 1, n
eigvectors(i,j) = A(i,j)
enddo
enddo
deallocate(A,eigenvalues)
end
2014-06-25 14:58:58 +02:00
subroutine lapack_diag(eigvalues,eigvectors,H,nmax,n)
implicit none
BEGIN_DOC
! Diagonalize matrix H
!
! H is untouched between input and ouptut
!
! eigevalues(i) = ith lowest eigenvalue of the H matrix
!
! eigvectors(i,j) = <i|psi_j> where i is the basis function and psi_j is the j th eigenvector
!
END_DOC
integer, intent(in) :: n,nmax
double precision, intent(out) :: eigvectors(nmax,n)
double precision, intent(out) :: eigvalues(n)
double precision, intent(in) :: H(nmax,n)
double precision,allocatable :: eigenvalues(:)
double precision,allocatable :: work(:)
double precision,allocatable :: A(:,:)
integer :: lwork, info, i,j,l,k, liwork
allocate(A(nmax,n),eigenvalues(n))
! print*,'Diagonalization by jacobi'
! print*,'n = ',n
A=H
lwork = 2*n*n + 6*n+ 1
allocate (work(lwork))
lwork = -1
call DSYEV( 'V', 'U', n, A, nmax, eigenvalues, work, lwork, &
info )
if (info < 0) then
print *, irp_here, ': DSYEV: the ',-info,'-th argument had an illegal value'
stop 2
endif
lwork = int( work( 1 ) )
deallocate (work)
allocate (work(lwork))
call DSYEV( 'V', 'U', n, A, nmax, eigenvalues, work, lwork, &
info )
deallocate(work)
if (info < 0) then
print *, irp_here, ': DSYEV: the ',-info,'-th argument had an illegal value'
stop 2
else if( info > 0 ) then
2016-11-16 22:08:43 +01:00
write(*,*)'DSYEV Failed : ', info
do i=1,n
do j=1,n
print *, H(i,j)
enddo
enddo
2014-06-25 14:58:58 +02:00
stop 1
end if
eigvectors = 0.d0
eigvalues = 0.d0
do j = 1, n
eigvalues(j) = eigenvalues(j)
do i = 1, n
eigvectors(i,j) = A(i,j)
enddo
enddo
deallocate(A,eigenvalues)
end
2014-10-06 15:49:16 +02:00
subroutine lapack_diag_s2(eigvalues,eigvectors,H,nmax,n)
implicit none
BEGIN_DOC
! Diagonalize matrix H
!
! H is untouched between input and ouptut
!
! eigevalues(i) = ith lowest eigenvalue of the H matrix
!
! eigvectors(i,j) = <i|psi_j> where i is the basis function and psi_j is the j th eigenvector
!
END_DOC
integer, intent(in) :: n,nmax
double precision, intent(out) :: eigvectors(nmax,n)
double precision, intent(out) :: eigvalues(n)
double precision, intent(in) :: H(nmax,n)
double precision,allocatable :: eigenvalues(:)
double precision,allocatable :: work(:)
double precision,allocatable :: A(:,:)
integer :: lwork, info, i,j,l,k, liwork
allocate(A(nmax,n),eigenvalues(n))
! print*,'Diagonalization by jacobi'
! print*,'n = ',n
A=H
lwork = 2*n*n + 6*n+ 1
allocate (work(lwork))
lwork = -1
call DSYEV( 'V', 'U', n, A, nmax, eigenvalues, work, lwork, &
info )
if (info < 0) then
print *, irp_here, ': DSYEV: the ',-info,'-th argument had an illegal value'
stop 2
endif
lwork = int( work( 1 ) )
deallocate (work)
allocate (work(lwork))
call DSYEV( 'V', 'U', n, A, nmax, eigenvalues, work, lwork, &
info )
deallocate(work)
if (info < 0) then
print *, irp_here, ': DSYEV: the ',-info,'-th argument had an illegal value'
stop 2
else if( info > 0 ) then
write(*,*)'DSYEV Failed'
stop 1
end if
eigvectors = 0.d0
eigvalues = 0.d0
do j = 1, n
eigvalues(j) = eigenvalues(j)
do i = 1, n
eigvectors(i,j) = A(i,j)
enddo
enddo
deallocate(A,eigenvalues)
end
2014-06-25 14:58:58 +02:00
subroutine lapack_partial_diag(eigvalues,eigvectors,H,nmax,n,n_st)
implicit none
BEGIN_DOC
! Diagonalize matrix H
!
! H is untouched between input and ouptut
!
! eigevalues(i) = ith lowest eigenvalue of the H matrix
!
! eigvectors(i,j) = <i|psi_j> where i is the basis function and psi_j is the j th eigenvector
!
END_DOC
integer, intent(in) :: n,nmax,n_st
double precision, intent(out) :: eigvectors(nmax,n)
double precision, intent(out) :: eigvalues(n)
double precision, intent(in) :: H(nmax,n)
double precision,allocatable :: work(:)
integer ,allocatable :: iwork(:), isuppz(:)
double precision,allocatable :: A(:,:)
integer :: lwork, info, i,j,l,k,m, liwork
allocate(A(nmax,n))
A=H
lwork = 2*n*n + 6*n+ 1
liwork = 5*n + 3
allocate (work(lwork),iwork(liwork),isuppz(2*N_st))
lwork = -1
liwork = -1
call DSYEVR( 'V', 'I', 'U', n, A, nmax, 0.d0, 0.d0, 1, n_st, 1.d-10, m, eigvalues, eigvectors, nmax, isuppz, work, lwork, &
iwork, liwork, info )
if (info < 0) then
print *, irp_here, ': DSYEVR: the ',-info,'-th argument had an illegal value'
stop 2
endif
lwork = int( work( 1 ) )
liwork = iwork(1)
deallocate (work,iwork)
allocate (work(lwork),iwork(liwork))
call DSYEVR( 'V', 'I', 'U', n, A, nmax, 0.d0, 0.d0, 1, n_st, 1.d-10, m, eigvalues, eigvectors, nmax, isuppz, work, lwork, &
iwork, liwork, info )
deallocate(work,iwork)
if (info < 0) then
print *, irp_here, ': DSYEVR: the ',-info,'-th argument had an illegal value'
stop 2
else if( info > 0 ) then
write(*,*)'DSYEVR Failed'
stop 1
end if
deallocate(A)
end
2014-10-03 15:24:04 +02:00
2015-01-07 17:59:31 +01:00
subroutine set_zero_extra_diag(i1,i2,matrix,lda,m)
implicit none
integer, intent(in) :: i1,i2,lda,m
double precision, intent(inout) :: matrix(lda,m)
integer :: i,j
do j=i1,i2
do i = 1,i1-1
matrix(i,j) = 0.d0
matrix(j,i) = 0.d0
enddo
enddo
2014-10-03 15:24:04 +02:00
2015-01-07 17:59:31 +01:00
do i = i2,i1
do j=i2+1,m
matrix(i,j) = 0.d0
matrix(j,i) = 0.d0
enddo
enddo
2014-10-03 15:24:04 +02:00
2014-10-03 16:40:18 +02:00
end
2015-04-09 21:46:28 +02:00
2016-11-02 16:01:01 +01:00
subroutine matrix_vector_product(u0,u1,matrix,sze,lda)
implicit none
BEGIN_DOC
! performs u1 += u0 * matrix
END_DOC
integer, intent(in) :: sze,lda
double precision, intent(in) :: u0(sze)
double precision, intent(inout) :: u1(sze)
double precision, intent(in) :: matrix(lda,sze)
integer :: i,j
integer :: incx,incy
incx = 1
incy = 1
call dsymv('U', sze, 1.d0, matrix, lda, u0, incx, 1.d0, u1, incy)
end