Skip to content

Commit

Permalink
Add density check and condition number test information
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmaryewski committed Nov 13, 2024
1 parent 3f08723 commit 4c2a165
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 23 deletions.
2 changes: 1 addition & 1 deletion common/lib/accuracy.F90
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
!! Not all routines use the string length specifications to set their character string lengths.
module common_accuracy

use, intrinsic :: iso_fortran_env, only : real64
use, intrinsic :: iso_fortran_env, only : real64, real128

implicit none
private
Expand Down
22 changes: 21 additions & 1 deletion slateratom/lib/diagonalizations.f90
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ subroutine diagonalize_overlap(max_l, num_alpha, poly_order, ss)
!! eigenvalues of overlap matrices
real(dp), allocatable :: eigenvalues(:)

!> auxiliary variables
!! auxiliary variables
integer :: ll, diagsize, ii
real(dp) :: e_min, e_max, cond_num

do ll = 0, max_l

Expand All @@ -57,11 +58,30 @@ subroutine diagonalize_overlap(max_l, num_alpha, poly_order, ss)
stop
end if

if (ll == 0) then
e_min = minval(eigenvalues)
e_max = maxval(eigenvalues)
end if

if (minval(eigenvalues) < e_min) then
e_min = minval(eigenvalues)
end if

if (maxval(eigenvalues) > e_max) then
e_max = maxval(eigenvalues)
end if

deallocate(overlap, eigenvalues)

end do

cond_num = abs(e_max / e_min)
write(*, '(A,E16.8)') 'Condition number is ', cond_num
! 16 is due to double precision
write(*, '(A,I2)') 'Expect convergence only up to approx. 1e-', 16 - int(anint(log10(cond_num)))
write(*,*) ' '


end subroutine diagonalize_overlap


Expand Down
10 changes: 7 additions & 3 deletions slateratom/lib/globals.f90
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ module globals
real(dp) :: commutator_max

!> density matrix supervector
real(dp), allocatable :: pp(:,:,:,:)
real(dp), allocatable :: pp(:,:,:,:), pp_old(:,:,:,:)

!> density matrix max difference
real(dp) :: pp_diff

!> fock matrix supervector
real(dp), allocatable :: ff(:,:,:,:)
Expand Down Expand Up @@ -180,8 +183,8 @@ module globals
!> true, if zero-order regular approximation for relativistic effects is desired
logical :: tZora

!> true, if SCF cycle reached convergency on a quantity
logical :: tCommutatorConverged, tEnergyConverged, tEigenspectrumConverged
!> true, if SCF cycle reached convergency on a given quantity
logical :: tCommutatorConverged, tEnergyConverged, tEigenspectrumConverged, tDensityConverged

!> identifier of mixer
integer :: mixnr
Expand Down Expand Up @@ -262,6 +265,7 @@ subroutine allocate_globals()
! fourth index of cof is the eigenvalue index, see densmatrix build
allocate(cof(2, 0:max_l, problemsize, problemsize))
allocate(pp(2, 0:max_l, problemsize, problemsize))
allocate(pp_old(2, 0:max_l, problemsize, problemsize))

weight(:) = 0.0_dp
abcissa(:) = 0.0_dp
Expand Down
53 changes: 45 additions & 8 deletions slateratom/lib/utilities.f90
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ module utilities
private

public :: check_electron_number, check_convergence_energy, check_convergence_commutator,&
& check_convergence_eigenspectrum, compute_commutator, check_convergence_pot
& check_convergence_eigenspectrum, compute_commutator, check_convergence_pot,&
& check_convergence_density
public :: vector_length, fak, zeroOutCpotOfEmptyDensitySpinChannels


Expand Down Expand Up @@ -164,7 +165,37 @@ subroutine compute_commutator(max_l, num_alpha, poly_order, ff, pp, ss, commutat
end subroutine


!> Checks convergence by computing energy change from the last SCF iteration.
!> Checks convergence by computing max. density change from the last SCF iteration.
pure subroutine check_convergence_density(pp_old, pp_new, scftol, iScf, res, tConverged)

!> old and new energy to compare
real(dp), intent(in) :: pp_old(:,:,:,:), pp_new(:,:,:,:)

!> scf tolerance, i.e. convergence criteria
real(dp), intent(in) :: scftol

!> current SCF step
integer, intent(in) :: iScf

!> obtained maximum change in energy
real(dp), intent(out) :: res

!> true, if SCF converged
logical, intent(out) :: tConverged

res = 0.0_dp

res = maxval(abs(pp_new - pp_old))
tConverged = res < scftol

if (iScf < 3) then
tConverged = .false.
end if

end subroutine check_convergence_density


!> Checks convergence by computing energy change from the last SCF iteration.
pure subroutine check_convergence_energy(energy_old, energy_new, scftol, iScf, change,&
& tConverged)

Expand Down Expand Up @@ -197,7 +228,7 @@ end subroutine check_convergence_energy

!> Checks convergence by evaluating change in the occupied part of the eigenspectrum
pure subroutine check_convergence_eigenspectrum(max_l, num_alpha, poly_order, eigval_new,&
& eigval_old, occ, scftol, iScf, change, tConverged)
& eigval_old, occ, scftol, iScf, res, tConverged)

!> maximum angular momentum
integer, intent(in) :: max_l
Expand All @@ -221,7 +252,7 @@ pure subroutine check_convergence_eigenspectrum(max_l, num_alpha, poly_order, ei
integer, intent(in) :: iScf

!> obtained change
real(dp), intent(out) :: change
real(dp), intent(out) :: res

!> true, if SCF converged
logical, intent(out) :: tConverged
Expand All @@ -232,22 +263,28 @@ pure subroutine check_convergence_eigenspectrum(max_l, num_alpha, poly_order, ei
! Occupation
real(dp) :: occ_ii

change = 0.0_dp
! Difference
real(dp) :: e_diff

! Frobenius norm, but only occupied states contribute
! Max. difference, only occupied orbitals contribute
res = 0.0_dp
do iSpin = 1, 2
do ll = 0, max_l
diagsize = num_alpha(ll) * poly_order(ll)
do ii = 1, diagsize
occ_ii = abs(occ(iSpin, ll, ii))
if (occ_ii > 1e-16) then
change = change + (eigval_new(iSpin, ll, ii) - eigval_old(iSpin, ll, ii))**2
! change = change + (eigval_new(iSpin, ll, ii) - eigval_old(iSpin, ll, ii))**2
e_diff = abs(eigval_new(iSpin, ll, ii) - eigval_old(iSpin, ll, ii))
if (e_diff > res) then
res = e_diff
end if
end if
end do
end do
end do

tConverged = change < scftol
tConverged = res < scftol

if (iScf < 3) then
tConverged = .false.
Expand Down
20 changes: 10 additions & 10 deletions slateratom/prog/main.f90
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ program HFAtom
use dft, only : check_accuracy, density_grid
use utilities, only : check_electron_number, check_convergence_energy,&
& check_convergence_commutator, check_convergence_eigenspectrum,&
& compute_commutator, check_convergence_pot
& compute_commutator, check_convergence_density
use zora_routines, only : scaled_zora
use cmdargs, only : parse_command_arguments
use common_poisson, only : TBeckeGridParams
Expand Down Expand Up @@ -82,8 +82,7 @@ program HFAtom
! WARNING: too high number of grid points somehow
! manages to break the Broyden mixer!
if (xcFunctional%isMGGA(xcnr)) then
! num_mesh_points = num_mesh_points + 2000
num_mesh_points = num_mesh_points + 500
num_mesh_points = num_mesh_points + 1000
end if

call echo_input(nuc, max_l, occ_shells, maxiter, scftol, poly_order, num_alpha, alpha, conf_r0,&
Expand Down Expand Up @@ -146,18 +145,20 @@ program HFAtom
& poly_order, problemsize, xcnr, num_mesh_points, weight, abcissa, vxc, vtau, alpha, pot_old,&
& pot_new, tZora, ff, commutator, camAlpha, camBeta)

pp_old(:,:,:,:) = pp

! self-consistency cycles
write(*,*) 'Energies in Hartree'
write(*,*)
write(*,*) ' Iter | Total energy | HF-X energy | XC energy | max(abs([F,PS])) &
& | Delta (Total energy) | Delta (spectrum)'
write(*,*) ' Iter | Total energy | P | [F,PS] | E | lambda'
write(*,*) '-------------------------------------------------------------------------------------&
& ------------------------------------------'
&--------------------'
lpScf: do iScf = 1, maxiter

pot_old(:,:,:,:) = pot_new
total_ene_old = total_ene
eigval_old(:,:,:) = eigval
pp_old(:,:,:,:) = pp

! diagonalize
call diagonalize(max_l, num_alpha, poly_order, ff, ss, cof, eigval)
Expand Down Expand Up @@ -190,16 +191,14 @@ program HFAtom

call check_convergence_commutator(commutator, scftol, iScf, commutator_max,&
& tCommutatorConverged)
! For debugging:
! call check_convergence_pot(pot_old, pot_new, max_l, problemsize, scftol, iScf,&
! & commutator_max, tCommutatorConverged)
call check_convergence_density(pp_old, pp, scftol, iScf, pp_diff, tDensityConverged)
call check_convergence_energy(total_ene_old, total_ene, scftol, iScf, total_ene_diff,&
& tEnergyConverged)
call check_convergence_eigenspectrum(max_l, num_alpha, poly_order, eigval, eigval_old, occ,&
& scftol, iScf, eigval_diff, tEigenspectrumConverged)

! Print SCF loop information
write(*, '(I4,2X,3(1X,F16.9),7X,E16.9,8X,E16.9,8X,E16.9)') iScf, total_ene, exchange_energy, x_en_2,&
write(*, '(I4,5X,E16.9,4X,E16.9,4X,E16.9,4X,E16.9,4X,E16.9)') iScf, total_ene, pp_diff,&
& commutator_max, total_ene_diff, eigval_diff

! if self-consistency is reached, exit loop
Expand Down Expand Up @@ -246,6 +245,7 @@ program HFAtom
end if

write(*, '(A,E20.12)') '[F,PS] converged to', commutator_max
write(*, '(A,E20.12)') 'Density matrix converged to', pp_diff
write(*, '(A)') ' '

if (tZora) then
Expand Down

0 comments on commit 4c2a165

Please sign in to comment.