10
0
mirror of https://github.com/LCPQ/quantum_package synced 2024-06-25 22:52:15 +02:00
quantum_package/src/Davidson/diagonalization.irp.f

582 lines
16 KiB
Fortran
Raw Normal View History

2016-09-23 14:23:03 +02:00
subroutine davidson_diag(dets_in,u_in,energies,dim_in,sze,N_st,N_st_diag,Nint,iunit)
2015-04-20 16:45:06 +02:00
use bitmasks
implicit none
BEGIN_DOC
! Davidson diagonalization.
!
! dets_in : bitmasks corresponding to determinants
!
! u_in : guess coefficients on the various states. Overwritten
! on exit
!
! dim_in : leftmost dimension of u_in
!
! sze : Number of determinants
!
! N_st : Number of eigenstates
!
! iunit : Unit number for the I/O
!
! Initial guess vectors are not necessarily orthonormal
END_DOC
2016-09-23 14:23:03 +02:00
integer, intent(in) :: dim_in, sze, N_st, N_st_diag, Nint, iunit
2015-04-20 16:45:06 +02:00
integer(bit_kind), intent(in) :: dets_in(Nint,2,sze)
2016-09-23 14:23:03 +02:00
double precision, intent(inout) :: u_in(dim_in,N_st_diag)
2015-04-20 16:45:06 +02:00
double precision, intent(out) :: energies(N_st)
double precision, allocatable :: H_jj(:)
double precision :: diag_h_mat_elem
integer :: i
ASSERT (N_st > 0)
ASSERT (sze > 0)
ASSERT (Nint > 0)
ASSERT (Nint == N_int)
PROVIDE mo_bielec_integrals_in_map
allocate(H_jj(sze))
!$OMP PARALLEL DEFAULT(NONE) &
!$OMP SHARED(sze,H_jj,dets_in,Nint) &
!$OMP PRIVATE(i)
!$OMP DO SCHEDULE(guided)
do i=1,sze
H_jj(i) = diag_h_mat_elem(dets_in(1,1,i),Nint)
enddo
!$OMP END DO
!$OMP END PARALLEL
2016-09-23 14:23:03 +02:00
call davidson_diag_hjj(dets_in,u_in,H_jj,energies,dim_in,sze,N_st,N_st_diag,Nint,iunit)
2015-04-20 16:45:06 +02:00
deallocate (H_jj)
end
logical function det_inf(key1, key2, Nint)
use bitmasks
implicit none
2016-09-20 17:29:02 +02:00
BEGIN_DOC
! Ordering function for determinants
END_DOC
integer,intent(in) :: Nint
2016-02-19 00:20:28 +01:00
integer(bit_kind),intent(in) :: key1(Nint, 2), key2(Nint, 2)
integer :: i,j
det_inf = .false.
do i=1,2
do j=Nint,1,-1
if(key1(j,i) < key2(j,i)) then
det_inf = .true.
return
else if(key1(j,i) > key2(j,i)) then
return
end if
end do
end do
end function
subroutine tamiser(key, idx, no, n, Nint, N_key)
use bitmasks
implicit none
2015-11-13 17:36:29 +01:00
BEGIN_DOC
! Uncodumented : TODO
END_DOC
integer,intent(in) :: no, n, Nint, N_key
2015-11-13 17:36:29 +01:00
integer(bit_kind),intent(inout) :: key(Nint, 2, N_key)
integer,intent(inout) :: idx(N_key)
integer :: k,j,tmpidx
integer(bit_kind) :: tmp(Nint, 2)
logical :: det_inf
2015-11-13 17:36:29 +01:00
integer :: ni
k = no
j = 2*k
do while(j <= n)
if(j < n) then
2015-11-13 17:36:29 +01:00
if (det_inf(key(1,1,j), key(1,1,j+1), Nint)) then
j = j+1
endif
endif
2015-11-13 17:36:29 +01:00
if(det_inf(key(1,1,k), key(1,1,j), Nint)) then
do ni=1,Nint
tmp(ni,1) = key(ni,1,k)
tmp(ni,2) = key(ni,2,k)
key(ni,1,k) = key(ni,1,j)
key(ni,2,k) = key(ni,2,j)
key(ni,1,j) = tmp(ni,1)
key(ni,2,j) = tmp(ni,2)
enddo
tmpidx = idx(k)
idx(k) = idx(j)
idx(j) = tmpidx
k = j
j = k+k
else
return
endif
enddo
end subroutine
subroutine sort_dets_ba_v(key_in, key_out, idx, shortcut, version, N_key, Nint)
2015-10-23 15:58:43 +02:00
use bitmasks
implicit none
2015-11-17 23:57:55 +01:00
BEGIN_DOC
! Uncodumented : TODO
END_DOC
2015-11-13 17:36:29 +01:00
integer, intent(in) :: Nint, N_key
integer(bit_kind),intent(in) :: key_in(Nint,2,N_key)
integer(bit_kind),intent(out) :: key_out(Nint,N_key)
integer,intent(out) :: idx(N_key)
integer,intent(out) :: shortcut(0:N_key+1)
integer(bit_kind),intent(out) :: version(Nint,N_key+1)
2015-11-17 23:57:55 +01:00
integer(bit_kind), allocatable :: key(:,:,:)
2015-11-13 17:36:29 +01:00
integer :: i,ni
2015-10-23 15:58:43 +02:00
2015-11-17 23:57:55 +01:00
allocate ( key(Nint,2,N_key) )
2015-11-13 17:36:29 +01:00
do i=1,N_key
do ni=1,Nint
key(ni,1,i) = key_in(ni,2,i)
key(ni,2,i) = key_in(ni,1,i)
enddo
enddo
2015-10-23 15:58:43 +02:00
call sort_dets_ab_v(key, key_out, idx, shortcut, version, N_key, Nint)
2015-11-17 23:57:55 +01:00
deallocate ( key )
2015-10-23 15:58:43 +02:00
end subroutine
subroutine sort_dets_ab_v(key_in, key_out, idx, shortcut, version, N_key, Nint)
2015-10-23 15:58:43 +02:00
use bitmasks
implicit none
2015-11-13 17:36:29 +01:00
BEGIN_DOC
! Uncodumented : TODO
END_DOC
integer, intent(in) :: Nint, N_key
integer(bit_kind),intent(in) :: key_in(Nint,2,N_key)
integer(bit_kind),intent(out) :: key_out(Nint,N_key)
2015-10-23 15:58:43 +02:00
integer,intent(out) :: idx(N_key)
integer,intent(out) :: shortcut(0:N_key+1)
integer(bit_kind),intent(out) :: version(Nint,N_key+1)
2015-11-17 23:57:55 +01:00
integer(bit_kind), allocatable :: key(:,:,:)
2015-10-23 15:58:43 +02:00
integer(bit_kind) :: tmp(Nint, 2)
integer :: tmpidx,i,ni
2015-11-17 23:57:55 +01:00
allocate (key(Nint,2,N_key))
2015-10-23 15:58:43 +02:00
do i=1,N_key
2015-11-13 17:36:29 +01:00
do ni=1,Nint
key(ni,1,i) = key_in(ni,1,i)
key(ni,2,i) = key_in(ni,2,i)
enddo
2015-10-23 15:58:43 +02:00
idx(i) = i
end do
do i=N_key/2,1,-1
call tamiser(key, idx, i, N_key, Nint, N_key)
end do
do i=N_key,2,-1
2015-11-13 17:36:29 +01:00
do ni=1,Nint
tmp(ni,1) = key(ni,1,i)
tmp(ni,2) = key(ni,2,i)
key(ni,1,i) = key(ni,1,1)
key(ni,2,i) = key(ni,2,1)
key(ni,1,1) = tmp(ni,1)
key(ni,2,1) = tmp(ni,2)
enddo
2015-10-23 15:58:43 +02:00
tmpidx = idx(i)
idx(i) = idx(1)
idx(1) = tmpidx
call tamiser(key, idx, 1, i-1, Nint, N_key)
end do
shortcut(0) = 1
shortcut(1) = 1
2015-11-13 17:36:29 +01:00
do ni=1,Nint
version(ni,1) = key(ni,1,1)
enddo
2015-10-23 15:58:43 +02:00
do i=2,N_key
do ni=1,nint
if(key(ni,1,i) /= key(ni,1,i-1)) then
shortcut(0) = shortcut(0) + 1
shortcut(shortcut(0)) = i
version(:,shortcut(0)) = key(:,1,i)
exit
end if
end do
end do
shortcut(shortcut(0)+1) = N_key+1
2015-11-13 17:36:29 +01:00
do i=1,N_key
do ni=1,Nint
key_out(ni,i) = key(ni,2,i)
enddo
enddo
2015-11-17 23:57:55 +01:00
deallocate (key)
2015-10-23 15:58:43 +02:00
end subroutine
subroutine sort_dets_ab(key, idx, shortcut, N_key, Nint)
use bitmasks
implicit none
2015-11-13 17:36:29 +01:00
BEGIN_DOC
! Uncodumented : TODO
END_DOC
2016-02-19 00:20:28 +01:00
integer, intent(in) :: Nint, N_key
integer(bit_kind),intent(inout) :: key(Nint,2,N_key)
2016-05-26 13:52:48 +02:00
integer,intent(inout) :: idx(N_key)
integer,intent(inout) :: shortcut(0:N_key+1)
integer(bit_kind) :: tmp(Nint, 2)
integer :: tmpidx,i,ni
do i=1,N_key
idx(i) = i
end do
do i=N_key/2,1,-1
call tamiser(key, idx, i, N_key, Nint, N_key)
end do
do i=N_key,2,-1
2015-11-13 17:36:29 +01:00
do ni=1,Nint
tmp(ni,1) = key(ni,1,i)
tmp(ni,2) = key(ni,2,i)
key(ni,1,i) = key(ni,1,1)
key(ni,2,i) = key(ni,2,1)
key(ni,1,1) = tmp(ni,1)
key(ni,2,1) = tmp(ni,2)
enddo
tmpidx = idx(i)
idx(i) = idx(1)
idx(1) = tmpidx
call tamiser(key, idx, 1, i-1, Nint, N_key)
end do
shortcut(0) = 1
shortcut(1) = 1
do i=2,N_key
do ni=1,nint
if(key(ni,1,i) /= key(ni,1,i-1)) then
shortcut(0) = shortcut(0) + 1
shortcut(shortcut(0)) = i
exit
end if
end do
end do
shortcut(shortcut(0)+1) = N_key+1
end subroutine
2016-09-23 14:23:03 +02:00
subroutine davidson_diag_hjj(dets_in,u_in,H_jj,energies,dim_in,sze,N_st,N_st_diag,Nint,iunit)
2015-04-20 16:45:06 +02:00
use bitmasks
implicit none
BEGIN_DOC
! Davidson diagonalization with specific diagonal elements of the H matrix
!
! H_jj : specific diagonal H matrix elements to diagonalize de Davidson
!
! dets_in : bitmasks corresponding to determinants
!
! u_in : guess coefficients on the various states. Overwritten
! on exit
!
! dim_in : leftmost dimension of u_in
!
! sze : Number of determinants
!
! N_st : Number of eigenstates
2016-09-23 14:23:03 +02:00
!
! N_st_diag : Number of states in which H is diagonalized
2015-04-20 16:45:06 +02:00
!
! iunit : Unit for the I/O
!
! Initial guess vectors are not necessarily orthonormal
END_DOC
2016-09-23 14:23:03 +02:00
integer, intent(in) :: dim_in, sze, N_st, N_st_diag, Nint
2015-04-20 16:45:06 +02:00
integer(bit_kind), intent(in) :: dets_in(Nint,2,sze)
double precision, intent(in) :: H_jj(sze)
integer, intent(in) :: iunit
2016-09-23 14:23:03 +02:00
double precision, intent(inout) :: u_in(dim_in,N_st_diag)
double precision, intent(out) :: energies(N_st_diag)
2015-04-20 16:45:06 +02:00
2016-05-02 10:31:57 +02:00
integer :: sze_8
2015-04-20 16:45:06 +02:00
integer :: iter
integer :: i,j,k,l,m
logical :: converged
2016-09-23 14:23:03 +02:00
double precision, allocatable :: overlap(:,:)
2015-04-20 16:45:06 +02:00
double precision :: u_dot_v, u_dot_u
integer, allocatable :: kl_pairs(:,:)
integer :: k_pairs, kl
integer :: iter2
2016-09-17 01:54:44 +02:00
double precision, allocatable :: W(:,:,:), U(:,:,:), R(:,:)
2015-04-20 16:45:06 +02:00
double precision, allocatable :: y(:,:,:,:), h(:,:,:,:), lambda(:)
double precision :: diag_h_mat_elem
2016-09-23 14:23:03 +02:00
double precision, allocatable :: residual_norm(:)
2015-04-20 16:45:06 +02:00
character*(16384) :: write_buffer
double precision :: to_print(2,N_st)
double precision :: cpu, wall
2016-09-17 01:54:44 +02:00
!DIR$ ATTRIBUTES ALIGN : $IRP_ALIGN :: U, W, R, y, h, lambda
2016-09-23 14:23:03 +02:00
PROVIDE nuclear_repulsion
2015-04-20 16:45:06 +02:00
call write_time(iunit)
call wall_time(wall)
call cpu_time(cpu)
write(iunit,'(A)') ''
write(iunit,'(A)') 'Davidson Diagonalization'
write(iunit,'(A)') '------------------------'
write(iunit,'(A)') ''
call write_int(iunit,N_st,'Number of states')
2016-09-23 14:23:03 +02:00
call write_int(iunit,N_st_diag,'Number of states in diagonalization')
2015-04-20 16:45:06 +02:00
call write_int(iunit,sze,'Number of determinants')
write(iunit,'(A)') ''
write_buffer = '===== '
do i=1,N_st
write_buffer = trim(write_buffer)//' ================ ================'
enddo
write(iunit,'(A)') trim(write_buffer)
write_buffer = ' Iter'
do i=1,N_st
write_buffer = trim(write_buffer)//' Energy Residual'
enddo
write(iunit,'(A)') trim(write_buffer)
write_buffer = '===== '
do i=1,N_st
write_buffer = trim(write_buffer)//' ================ ================'
enddo
write(iunit,'(A)') trim(write_buffer)
2016-05-02 10:31:57 +02:00
integer, external :: align_double
sze_8 = align_double(sze)
2015-04-20 16:45:06 +02:00
allocate( &
2016-09-23 14:23:03 +02:00
kl_pairs(2,N_st_diag*(N_st_diag+1)/2), &
W(sze_8,N_st_diag,davidson_sze_max), &
U(sze_8,N_st_diag,davidson_sze_max), &
R(sze_8,N_st_diag), &
h(N_st_diag,davidson_sze_max,N_st_diag,davidson_sze_max), &
y(N_st_diag,davidson_sze_max,N_st_diag,davidson_sze_max), &
residual_norm(N_st_diag), &
overlap(N_st_diag,N_st_diag), &
lambda(N_st_diag*davidson_sze_max))
2015-04-20 16:45:06 +02:00
ASSERT (N_st > 0)
2016-09-23 14:23:03 +02:00
ASSERT (N_st_diag >= N_st)
2015-04-20 16:45:06 +02:00
ASSERT (sze > 0)
ASSERT (Nint > 0)
ASSERT (Nint == N_int)
! Davidson iterations
! ===================
converged = .False.
do while (.not.converged)
do k=1,N_st
do i=1,sze
U(i,k,1) = u_in(i,k)
enddo
enddo
2016-09-23 14:23:03 +02:00
do k=N_st+1,N_st_diag
do i=1,sze
call RANDOM_NUMBER(U(i,k,1))
U(i,k,1) = U(i,k,1) - 0.5d0
enddo
enddo
2015-04-20 16:45:06 +02:00
2016-09-23 14:23:03 +02:00
! Compute overlap matrix
call DGEMM('T','N', N_st_diag, N_st_diag, sze, &
1.d0, U(1,1,1), size(U,1), U(1,1,1), size(U,1), &
0.d0, overlap, size(overlap,1))
call ortho_lowdin(overlap,size(overlap,1),N_st_diag,U,size(U,1),sze)
2015-04-20 16:45:06 +02:00
do iter=1,davidson_sze_max-1
! Compute W_k = H |u_k>
! ----------------------
2016-09-23 14:23:03 +02:00
call H_u_0_nstates(W(1,1,iter),U(1,1,iter),H_jj,sze,dets_in,Nint,N_st_diag,sze_8)
2015-04-20 16:45:06 +02:00
2015-04-20 16:45:06 +02:00
! Compute h_kl = <u_k | W_l> = <u_k| H |u_l>
! -------------------------------------------
2016-09-23 14:23:03 +02:00
!$OMP PARALLEL PRIVATE(k,l,iter2) SHARED(h,U,W,sze,iter)
do l=1,N_st_diag
!$OMP DO
do k=1,N_st_diag
2015-04-20 16:45:06 +02:00
do iter2=1,iter-1
h(k,iter2,l,iter) = u_dot_v(U(1,k,iter2),W(1,l,iter),sze)
h(k,iter,l,iter2) = h(k,iter2,l,iter)
enddo
enddo
2016-09-23 14:23:03 +02:00
!$OMP END DO
enddo
do l=1,N_st_diag
!$OMP DO
2015-04-20 16:45:06 +02:00
do k=1,l
h(k,iter,l,iter) = u_dot_v(U(1,k,iter),W(1,l,iter),sze)
h(l,iter,k,iter) = h(k,iter,l,iter)
enddo
2016-09-23 14:23:03 +02:00
!$OMP END DO
2015-04-20 16:45:06 +02:00
enddo
2016-09-23 14:23:03 +02:00
!$OMP END PARALLEL
2015-04-20 16:45:06 +02:00
!DEBUG H MATRIX
!do i=1,iter
! print '(10(x,F16.10))', h(1,i,1,1:i)
!enddo
!print *, ''
!END
! Diagonalize h
! -------------
2016-09-23 14:23:03 +02:00
call lapack_diag(lambda,y,h,N_st_diag*davidson_sze_max,N_st_diag*iter)
2015-04-20 16:45:06 +02:00
! Express eigenvectors of h in the determinant basis
! --------------------------------------------------
2016-05-02 10:31:57 +02:00
!$OMP PARALLEL DEFAULT(NONE) &
2016-07-13 01:12:05 +02:00
!$OMP PRIVATE(k,i,l,iter2) &
2016-09-23 14:23:03 +02:00
!$OMP SHARED(U,W,R,y,iter,lambda,N_st_diag,sze,to_print, &
!$OMP residual_norm,nuclear_repulsion,N_st)
do k=1,N_st_diag
2016-05-02 10:31:57 +02:00
!$OMP DO
2015-04-20 16:45:06 +02:00
do i=1,sze
U(i,k,iter+1) = 0.d0
W(i,k,iter+1) = 0.d0
2016-07-13 01:12:05 +02:00
enddo
!$OMP END DO
do iter2=1,iter
2016-09-23 14:23:03 +02:00
do l=1,N_st_diag
2016-07-13 01:12:05 +02:00
!$OMP DO
do i=1,sze
2015-04-20 16:45:06 +02:00
U(i,k,iter+1) = U(i,k,iter+1) + U(i,l,iter2)*y(l,iter2,k,1)
W(i,k,iter+1) = W(i,k,iter+1) + W(i,l,iter2)*y(l,iter2,k,1)
enddo
2016-07-13 01:12:05 +02:00
!$OMP END DO NOWAIT
2015-04-20 16:45:06 +02:00
enddo
enddo
2016-07-13 01:12:05 +02:00
! Compute residual vector
! -----------------------
2015-04-20 16:45:06 +02:00
2016-07-13 01:12:05 +02:00
!$OMP DO
2015-04-20 16:45:06 +02:00
do i=1,sze
R(i,k) = lambda(k) * U(i,k,iter+1) - W(i,k,iter+1)
enddo
2016-07-13 01:12:05 +02:00
!$OMP END DO
!$OMP SINGLE
2016-09-23 14:23:03 +02:00
if (k <= N_st) then
residual_norm(k) = u_dot_u(R(1,k),sze)
to_print(1,k) = lambda(k) + nuclear_repulsion
to_print(2,k) = residual_norm(k)
endif
2016-07-13 01:12:05 +02:00
!$OMP END SINGLE
2015-04-20 16:45:06 +02:00
enddo
2016-07-13 01:12:05 +02:00
!$OMP END PARALLEL
2016-02-19 00:20:28 +01:00
write(iunit,'(X,I3,X,100(X,F16.10,X,E16.6))') iter, to_print(:,1:N_st)
2016-09-23 14:23:03 +02:00
call davidson_converged(lambda,residual_norm,wall,iter,cpu,N_st,converged)
2015-04-20 16:45:06 +02:00
if (converged) then
exit
endif
! Davidson step
! -------------
2016-09-23 14:23:03 +02:00
do k=1,N_st_diag
2015-04-20 16:45:06 +02:00
do i=1,sze
U(i,k,iter+1) = -1.d0/max(H_jj(i) - lambda(k),1.d-2) * R(i,k)
enddo
enddo
! Gram-Schmidt
! ------------
double precision :: c
2016-09-23 14:23:03 +02:00
do k=1,N_st_diag
2015-04-20 16:45:06 +02:00
do iter2=1,iter
2016-09-23 14:23:03 +02:00
do l=1,N_st_diag
2015-04-20 16:45:06 +02:00
c = u_dot_v(U(1,k,iter+1),U(1,l,iter2),sze)
do i=1,sze
U(i,k,iter+1) = U(i,k,iter+1) - c * U(i,l,iter2)
2015-04-20 16:45:06 +02:00
enddo
enddo
enddo
do l=1,k-1
c = u_dot_v(U(1,k,iter+1),U(1,l,iter+1),sze)
do i=1,sze
U(i,k,iter+1) = U(i,k,iter+1) - c * U(i,l,iter+1)
2015-04-20 16:45:06 +02:00
enddo
enddo
call normalize( U(1,k,iter+1), sze )
enddo
!DEBUG : CHECK OVERLAP
!print *, '==='
!do k=1,iter+1
! do l=1,k
! c = u_dot_v(U(1,1,k),U(1,1,l),sze)
! print *, k,l, c
! enddo
!enddo
!print *, '==='
!pause
!END DEBUG
enddo
if (.not.converged) then
iter = davidson_sze_max-1
endif
! Re-contract to u_in
! -----------
2016-09-23 14:23:03 +02:00
do k=1,N_st_diag
2015-04-20 16:45:06 +02:00
energies(k) = lambda(k)
do i=1,sze
u_in(i,k) = 0.d0
do iter2=1,iter
2016-09-23 14:23:03 +02:00
do l=1,N_st_diag
2015-04-20 16:45:06 +02:00
u_in(i,k) += U(i,l,iter2)*y(l,iter2,k,1)
enddo
enddo
enddo
enddo
enddo
write_buffer = '===== '
do i=1,N_st
write_buffer = trim(write_buffer)//' ================ ================'
enddo
write(iunit,'(A)') trim(write_buffer)
write(iunit,'(A)') ''
call write_time(iunit)
deallocate ( &
kl_pairs, &
2016-09-23 14:23:03 +02:00
W, residual_norm, &
U, overlap, &
2015-04-20 16:45:06 +02:00
R, &
h, &
y, &
lambda &
)
end