9
1
mirror of https://github.com/QuantumPackage/qp2.git synced 2024-06-02 02:35:18 +02:00
qp2/src/scf_utils/roothaan_hall_scf.irp.f

374 lines
11 KiB
Fortran
Raw Normal View History

2019-01-25 11:39:31 +01:00
subroutine Roothaan_Hall_SCF
BEGIN_DOC
! Roothaan-Hall algorithm for SCF Hartree-Fock calculation
END_DOC
implicit none
double precision :: energy_SCF,energy_SCF_previous,Delta_energy_SCF
double precision :: max_error_DIIS,max_error_DIIS_alpha,max_error_DIIS_beta
double precision, allocatable :: Fock_matrix_DIIS(:,:,:),error_matrix_DIIS(:,:,:)
integer :: iteration_SCF,dim_DIIS,index_dim_DIIS
2023-04-21 15:11:50 +02:00
logical :: converged
integer :: i,j,m
2019-01-25 11:39:31 +01:00
logical, external :: qp_stop
double precision, allocatable :: mo_coef_save(:,:), S(:,:)
2019-01-25 11:39:31 +01:00
PROVIDE ao_md5 mo_occ level_shift
allocate(mo_coef_save(ao_num,mo_num), &
Fock_matrix_DIIS (ao_num,ao_num,max_dim_DIIS), &
error_matrix_DIIS(ao_num,ao_num,max_dim_DIIS) &
)
2021-03-01 13:15:21 +01:00
Fock_matrix_DIIS = 0.d0
error_matrix_DIIS = 0.d0
mo_coef_save = 0.d0
2019-01-25 11:39:31 +01:00
call write_time(6)
print*,'Energy of the guess = ',SCF_energy
write(6,'(A4, 1X, A16, 1X, A16, 1X, A16, 1X, A16)') &
'====','================','================','================','================'
write(6,'(A4, 1X, A16, 1X, A16, 1X, A16, 1X, A16)') &
' N ', 'Energy ', 'Energy diff ', 'DIIS error ', 'Level shift '
write(6,'(A4, 1X, A16, 1X, A16, 1X, A16, 1X, A16)') &
'====','================','================','================','================'
! Initialize energies and density matrices
energy_SCF_previous = SCF_energy
Delta_energy_SCF = 1.d0
iteration_SCF = 0
dim_DIIS = 0
max_error_DIIS = 1.d0
!
! Start of main SCF loop
!
PROVIDE FPS_SPF_matrix_AO Fock_matrix_AO
2023-04-21 15:11:50 +02:00
converged = .False.
do while ( .not.converged .and. (iteration_SCF < n_it_SCF_max) )
2019-01-25 11:39:31 +01:00
! Increment cycle number
iteration_SCF += 1
if(frozen_orb_scf)then
call initialize_mo_coef_begin_iteration
endif
! Current size of the DIIS space
dim_DIIS = min(dim_DIIS+1,max_dim_DIIS)
2020-11-11 16:27:22 +01:00
if ( (scf_algorithm == 'DIIS').and.(dabs(Delta_energy_SCF) > 1.d-6) ) then
2019-01-25 11:39:31 +01:00
! Store Fock and error matrices at each iteration
do j=1,ao_num
do i=1,ao_num
index_dim_DIIS = mod(dim_DIIS-1,max_dim_DIIS)+1
Fock_matrix_DIIS (i,j,index_dim_DIIS) = Fock_matrix_AO(i,j)
error_matrix_DIIS(i,j,index_dim_DIIS) = FPS_SPF_matrix_AO(i,j)
enddo
enddo
! Compute the extrapolated Fock matrix
call extrapolate_Fock_matrix( &
error_matrix_DIIS,Fock_matrix_DIIS, &
Fock_matrix_AO,size(Fock_matrix_AO,1), &
iteration_SCF,dim_DIIS &
)
Fock_matrix_AO_alpha = Fock_matrix_AO*0.5d0
Fock_matrix_AO_beta = Fock_matrix_AO*0.5d0
TOUCH Fock_matrix_AO_alpha Fock_matrix_AO_beta
endif
MO_coef = eigenvectors_Fock_matrix_MO
if(frozen_orb_scf)then
call reorder_core_orb
call initialize_mo_coef_begin_iteration
endif
TOUCH MO_coef
! Calculate error vectors
max_error_DIIS = maxval(Abs(FPS_SPF_Matrix_MO))
! SCF energy
energy_SCF = SCF_energy
Delta_Energy_SCF = energy_SCF - energy_SCF_previous
if ( (SCF_algorithm == 'DIIS').and.(Delta_Energy_SCF > 0.d0) ) then
Fock_matrix_AO(1:ao_num,1:ao_num) = Fock_matrix_DIIS (1:ao_num,1:ao_num,index_dim_DIIS)
Fock_matrix_AO_alpha = Fock_matrix_AO*0.5d0
Fock_matrix_AO_beta = Fock_matrix_AO*0.5d0
TOUCH Fock_matrix_AO_alpha Fock_matrix_AO_beta
endif
double precision :: level_shift_save
level_shift_save = level_shift
mo_coef_save(1:ao_num,1:mo_num) = mo_coef(1:ao_num,1:mo_num)
do while (Delta_energy_SCF > 0.d0)
mo_coef(1:ao_num,1:mo_num) = mo_coef_save
if (level_shift <= .1d0) then
level_shift = 1.d0
else
level_shift = level_shift * 3.0d0
endif
TOUCH mo_coef level_shift
mo_coef(1:ao_num,1:mo_num) = eigenvectors_Fock_matrix_MO(1:ao_num,1:mo_num)
if(frozen_orb_scf)then
call reorder_core_orb
call initialize_mo_coef_begin_iteration
endif
TOUCH mo_coef
Delta_Energy_SCF = SCF_energy - energy_SCF_previous
energy_SCF = SCF_energy
if (level_shift-level_shift_save > 40.d0) then
level_shift = level_shift_save * 4.d0
SOFT_TOUCH level_shift
exit
endif
dim_DIIS=0
enddo
level_shift = level_shift * 0.5d0
SOFT_TOUCH level_shift
energy_SCF_previous = energy_SCF
2023-04-21 15:11:50 +02:00
converged = ( (max_error_DIIS <= threshold_DIIS_nonzero) .and. &
(dabs(Delta_energy_SCF) <= thresh_SCF) )
2019-01-25 11:39:31 +01:00
! Print results at the end of each iteration
write(6,'(I4, 1X, F16.10, 1X, F16.10, 1X, F16.10, 1X, F16.10, 1X, I3)') &
iteration_SCF, energy_SCF, Delta_energy_SCF, max_error_DIIS, level_shift, dim_DIIS
2023-04-21 15:11:50 +02:00
! Write data in JSON file
2023-04-21 18:06:37 +02:00
call lock_io
2023-04-21 15:11:50 +02:00
if (iteration_SCF == 1) then
2023-04-24 00:50:07 +02:00
write(json_unit, json_dict_uopen_fmt)
2023-04-21 15:11:50 +02:00
else
2023-04-24 00:50:07 +02:00
write(json_unit, json_dict_close_uopen_fmt)
2023-04-21 15:11:50 +02:00
endif
write(json_unit, json_int_fmt) 'iteration', iteration_SCF
write(json_unit, json_real_fmt) 'energy', energy_SCF
write(json_unit, json_real_fmt) 'delta_energy_SCF', Delta_energy_SCF
write(json_unit, json_real_fmt) 'max_error_DIIS', max_error_DIIS
write(json_unit, json_real_fmt) 'level_shift', level_shift
write(json_unit, json_int_fmt) 'dim_DIIS', dim_DIIS
2023-04-21 18:06:37 +02:00
call unlock_io
2023-04-21 15:11:50 +02:00
2019-01-25 11:39:31 +01:00
if (Delta_energy_SCF < 0.d0) then
call save_mos
2023-04-21 15:11:50 +02:00
write(json_unit, json_true_fmt) 'saved'
else
write(json_unit, json_false_fmt) 'saved'
2019-01-25 11:39:31 +01:00
endif
2023-04-21 15:11:50 +02:00
2023-04-21 18:06:37 +02:00
call lock_io
2023-04-21 15:11:50 +02:00
if (converged) then
write(json_unit, json_true_fmtx) 'converged'
else
write(json_unit, json_false_fmtx) 'converged'
endif
2023-04-21 18:06:37 +02:00
call unlock_io
2023-04-21 15:11:50 +02:00
2019-01-25 11:39:31 +01:00
if (qp_stop()) exit
enddo
2023-04-24 00:50:07 +02:00
write(json_unit, json_dict_close_fmtx)
2019-01-25 11:39:31 +01:00
if (iteration_SCF < n_it_SCF_max) then
2020-11-11 10:26:36 +01:00
mo_label = 'Canonical'
2019-01-25 11:39:31 +01:00
endif
!
! End of Main SCF loop
!
write(6,'(A4, 1X, A16, 1X, A16, 1X, A16, 1X, A16)') &
'====','================','================','================','================'
write(6,*)
2023-04-21 15:11:50 +02:00
if (converged) then
write(6,*) 'SCF converged'
2023-08-30 15:21:21 +02:00
call sleep(1) ! When too fast, the MOs aren't saved.
2023-04-21 15:11:50 +02:00
endif
2019-01-25 11:39:31 +01:00
if(.not.frozen_orb_scf)then
2020-11-11 10:26:36 +01:00
call mo_as_eigvectors_of_mo_matrix(Fock_matrix_mo,size(Fock_matrix_mo,1), &
size(Fock_matrix_mo,2),mo_label,1,.true.)
2020-11-11 16:27:22 +01:00
call restore_symmetry(ao_num, mo_num, mo_coef, size(mo_coef,1), 1.d-10)
2020-11-11 01:12:52 +01:00
call orthonormalize_mos
2019-01-25 11:39:31 +01:00
endif
! Identify degenerate MOs and force them on the axes
allocate(S(ao_num,ao_num))
i=1
do while (i<mo_num)
j=i
m=1
do while ( (j<mo_num).and.(fock_matrix_diag_mo(j+1)-fock_matrix_diag_mo(i) < 1.d-8) )
j += 1
m += 1
enddo
if (m>1) then
call dgemm('N','T',ao_num,ao_num,m,1.d0,mo_coef(1,i),size(mo_coef,1),mo_coef(1,i),size(mo_coef,1),0.d0,S,size(S,1))
call pivoted_cholesky( S, m, -1.d0, ao_num, mo_coef(1,i))
endif
i = j+1
enddo
call save_mos
2019-01-25 11:39:31 +01:00
call write_double(6, Energy_SCF, 'SCF energy')
call write_time(6)
end
2019-01-29 15:40:00 +01:00
subroutine extrapolate_Fock_matrix( &
error_matrix_DIIS,Fock_matrix_DIIS, &
Fock_matrix_AO_,size_Fock_matrix_AO, &
iteration_SCF,dim_DIIS &
)
2019-01-25 11:39:31 +01:00
BEGIN_DOC
! Compute the extrapolated Fock matrix using the DIIS procedure
END_DOC
implicit none
2020-08-31 23:04:34 +02:00
integer,intent(inout) :: dim_DIIS
2020-08-31 11:37:00 +02:00
double precision,intent(in) :: Fock_matrix_DIIS(ao_num,ao_num,dim_DIIS),error_matrix_DIIS(ao_num,ao_num,dim_DIIS)
2019-01-25 11:39:31 +01:00
integer,intent(in) :: iteration_SCF, size_Fock_matrix_AO
double precision,intent(inout):: Fock_matrix_AO_(size_Fock_matrix_AO,ao_num)
double precision,allocatable :: B_matrix_DIIS(:,:),X_vector_DIIS(:)
double precision,allocatable :: C_vector_DIIS(:)
double precision,allocatable :: scratch(:,:)
2021-03-22 09:25:36 +01:00
integer :: i,j,k,l,i_DIIS,j_DIIS
2020-05-25 18:11:27 +02:00
double precision :: rcond, ferr, berr
integer, allocatable :: iwork(:)
integer :: lwork
2020-05-26 11:00:35 +02:00
if (dim_DIIS < 1) then
2020-05-25 18:11:27 +02:00
return
endif
2019-01-25 11:39:31 +01:00
allocate( &
B_matrix_DIIS(dim_DIIS+1,dim_DIIS+1), &
X_vector_DIIS(dim_DIIS+1), &
C_vector_DIIS(dim_DIIS+1), &
scratch(ao_num,ao_num) &
)
2021-03-21 10:26:03 +01:00
! Compute the matrices B and X
2020-08-31 11:37:00 +02:00
B_matrix_DIIS(:,:) = 0.d0
2019-01-25 11:39:31 +01:00
do j=1,dim_DIIS
2020-09-02 17:09:19 +02:00
j_DIIS = min(dim_DIIS,mod(iteration_SCF-j,max_dim_DIIS)+1)
2019-01-25 11:39:31 +01:00
2021-03-22 09:25:36 +01:00
do i=1,dim_DIIS
2020-08-31 11:37:00 +02:00
i_DIIS = min(dim_DIIS,mod(iteration_SCF-i,max_dim_DIIS)+1)
2019-01-25 11:39:31 +01:00
2021-03-21 10:26:03 +01:00
! Compute product of two errors vectors
2021-03-22 09:25:36 +01:00
do l=1,ao_num
do k=1,ao_num
B_matrix_DIIS(i,j) = B_matrix_DIIS(i,j) + &
error_matrix_DIIS(k,l,i_DIIS) * error_matrix_DIIS(k,l,j_DIIS)
enddo
2019-01-25 11:39:31 +01:00
enddo
2021-03-22 09:25:36 +01:00
2019-01-25 11:39:31 +01:00
enddo
enddo
! Pad B matrix and build the X matrix
2020-08-31 11:37:00 +02:00
C_vector_DIIS(:) = 0.d0
2019-01-25 11:39:31 +01:00
do i=1,dim_DIIS
B_matrix_DIIS(i,dim_DIIS+1) = -1.d0
B_matrix_DIIS(dim_DIIS+1,i) = -1.d0
enddo
C_vector_DIIS(dim_DIIS+1) = -1.d0
2020-05-25 18:11:27 +02:00
deallocate(scratch)
2019-01-25 11:39:31 +01:00
2020-05-25 18:11:27 +02:00
! Estimate condition number of B
double precision :: anorm
2019-01-25 11:39:31 +01:00
integer :: info
integer,allocatable :: ipiv(:)
double precision, allocatable :: AF(:,:)
2020-05-25 18:11:27 +02:00
double precision, external :: dlange
2019-01-25 11:39:31 +01:00
2020-05-25 18:11:27 +02:00
lwork = max((dim_DIIS+1)**2, (dim_DIIS+1)*5)
allocate(AF(dim_DIIS+1,dim_DIIS+1))
allocate(ipiv(2*(dim_DIIS+1)), iwork(2*(dim_DIIS+1)) )
2019-01-25 11:39:31 +01:00
allocate(scratch(lwork,1))
2020-08-31 11:37:00 +02:00
scratch(:,1) = 0.d0
2019-01-25 11:39:31 +01:00
2020-05-25 18:11:27 +02:00
anorm = dlange('1', dim_DIIS+1, dim_DIIS+1, B_matrix_DIIS, &
2020-08-31 11:37:00 +02:00
size(B_matrix_DIIS,1), scratch(1,1))
2020-05-25 18:11:27 +02:00
AF(:,:) = B_matrix_DIIS(:,:)
call dgetrf(dim_DIIS+1,dim_DIIS+1,AF,size(AF,1),ipiv,info)
if (info /= 0) then
dim_DIIS = 0
return
endif
call dgecon( '1', dim_DIIS+1, AF, &
size(AF,1), anorm, rcond, scratch, iwork, info )
if (info /= 0) then
dim_DIIS = 0
return
endif
2020-05-25 23:34:51 +02:00
if (rcond < 1.d-14) then
2020-05-25 18:11:27 +02:00
dim_DIIS = 0
return
endif
! Solve the linear system C = B.X
2020-05-25 23:27:38 +02:00
X_vector_DIIS = C_vector_DIIS
call dgesv ( dim_DIIS+1 , 1, B_matrix_DIIS, size(B_matrix_DIIS,1), &
ipiv , X_vector_DIIS , size(X_vector_DIIS,1), info)
2020-05-25 23:32:23 +02:00
deallocate(scratch,AF,iwork)
if(info < 0) then
stop 'bug in DIIS'
endif
2019-01-25 11:39:31 +01:00
! Compute extrapolated Fock matrix
2020-05-25 18:11:27 +02:00
!$OMP PARALLEL DO PRIVATE(i,j,k) DEFAULT(SHARED) if (ao_num > 200)
do j=1,ao_num
do i=1,ao_num
Fock_matrix_AO_(i,j) = 0.d0
enddo
do k=1,dim_DIIS
2020-11-11 10:26:36 +01:00
if (dabs(X_vector_DIIS(k)) < 1.d-10) cycle
2020-05-25 18:11:27 +02:00
do i=1,ao_num
2021-03-01 13:15:21 +01:00
! FPE here
2020-05-25 18:11:27 +02:00
Fock_matrix_AO_(i,j) = Fock_matrix_AO_(i,j) + &
X_vector_DIIS(k)*Fock_matrix_DIIS(i,j,dim_DIIS-k+1)
2019-01-25 11:39:31 +01:00
enddo
2020-05-25 18:11:27 +02:00
enddo
enddo
!$OMP END PARALLEL DO
2019-01-25 11:39:31 +01:00
end