Calculates a grid of points that fall inside of (and eventually on the surface of) the Wigner-Seitz supercell centered on the origin of the B lattice with primitive translations nmonkh(1)a_1+nmonkh(2)a_2+nmonkh(3)*a_3
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
logical, | intent(in) | :: | count_pts | Only count points and return |
subroutine hamiltonian_wigner_seitz(count_pts)
!================================================================================!
!! Calculates a grid of points that fall inside of (and eventually on the
!! surface of) the Wigner-Seitz supercell centered on the origin of the B
!! lattice with primitive translations nmonkh(1)*a_1+nmonkh(2)*a_2+nmonkh(3)*a_3
!================================================================================!
use w90_constants, only: eps7, eps8
use w90_io, only: io_error, io_stopwatch, stdout
use w90_parameters, only: iprint, mp_grid, real_metric, timing_level, &
ws_search_size, ws_distance_tol
! irvec(i,irpt) The irpt-th Wigner-Seitz grid point has components
! irvec(1:3,irpt) in the basis of the lattice vectors
! ndegen(irpt) Weight of the irpt-th point is 1/ndegen(irpt)
! nrpts number of Wigner-Seitz grid points
implicit none
logical, intent(in) :: count_pts
!! Only count points and return
integer :: ndiff(3)
real(kind=dp) :: tot, dist_min
real(kind=dp), allocatable :: dist(:)
integer :: n1, n2, n3, i1, i2, i3, icnt, i, j, ierr, dist_dim
if (timing_level > 1) call io_stopwatch('hamiltonian: wigner_seitz', 1)
dist_dim = 1
do i = 1, 3
dist_dim = dist_dim*((ws_search_size(i) + 1)*2 + 1)
end do
allocate (dist(dist_dim), stat=ierr)
if (ierr /= 0) call io_error('Error in allocating dist in hamiltonian_wigner_seitz')
! The Wannier functions live in a supercell of the real space unit cell
! this supercell is mp_grid unit cells long in each direction
!
! We loop over grid points r on a unit cell that is (2*ws_search_size+1)**3 times
! larger than this primitive supercell.
!
! One of these points is in the W-S cell if it is closer to R=0 than any of the
! other points, R (where R are the translation vectors of the supercell)
! In the end nrpts contains the total number of grid
! points that have been found in the Wigner-Seitz cell
nrpts = 0
! Loop over the lattice vectors of the primitive cell
! that live in a supercell which is (2*ws_search_size+1)**2
! larger than the Born-von Karman supercell.
! We need to find which among these live in the Wigner-Seitz cell
do n1 = -ws_search_size(1)*mp_grid(1), ws_search_size(1)*mp_grid(1)
do n2 = -ws_search_size(2)*mp_grid(2), ws_search_size(2)*mp_grid(2)
do n3 = -ws_search_size(3)*mp_grid(3), ws_search_size(3)*mp_grid(3)
! Loop over the lattice vectors R of the Born-von Karman supercell
! that contains all the points of the previous loop.
! There are (2*(ws_search_size+1)+1)**3 points R. R=0 corresponds to
! i1=i2=i3=0, or icnt=((2*(ws_search_size+1)+1)**3 + 1)/2
icnt = 0
do i1 = -ws_search_size(1) - 1, ws_search_size(1) + 1
do i2 = -ws_search_size(2) - 1, ws_search_size(2) + 1
do i3 = -ws_search_size(3) - 1, ws_search_size(3) + 1
icnt = icnt + 1
! Calculate distance squared |r-R|^2
ndiff(1) = n1 - i1*mp_grid(1)
ndiff(2) = n2 - i2*mp_grid(2)
ndiff(3) = n3 - i3*mp_grid(3)
dist(icnt) = 0.0_dp
do i = 1, 3
do j = 1, 3
dist(icnt) = dist(icnt) + real(ndiff(i), dp)*real_metric(i, j) &
*real(ndiff(j), dp)
enddo
enddo
enddo
enddo
enddo
! AAM: On first pass, we reference unallocated variables (ndegen,irvec)
dist_min = minval(dist)
if (abs(dist((dist_dim + 1)/2) - dist_min) .lt. ws_distance_tol**2) then
nrpts = nrpts + 1
if (.not. count_pts) then
ndegen(nrpts) = 0
do i = 1, dist_dim
if (abs(dist(i) - dist_min) .lt. ws_distance_tol**2) ndegen(nrpts) = ndegen(nrpts) + 1
end do
irvec(1, nrpts) = n1
irvec(2, nrpts) = n2
irvec(3, nrpts) = n3
!
! Record index of r=0
if (n1 == 0 .and. n2 == 0 .and. n3 == 0) rpt_origin = nrpts
endif
end if
!n3
enddo
!n2
enddo
!n1
enddo
!
deallocate (dist, stat=ierr)
if (ierr /= 0) call io_error('Error in deallocating dist hamiltonian_wigner_seitz')
if (count_pts) return
! Check the "sum rule"
tot = 0.0_dp
do i = 1, nrpts
tot = tot + 1.0_dp/real(ndegen(i), dp)
enddo
if (iprint >= 3 .and. on_root) then
write (stdout, '(1x,i4,a,/)') nrpts, ' lattice points in Wigner-Seitz supercell:'
do i = 1, nrpts
write (stdout, '(4x,a,3(i3,1x),a,i2)') ' vector ', irvec(1, i), irvec(2, i), &
irvec(3, i), ' degeneracy: ', ndegen(i)
enddo
write (stdout, '(1x,a,f12.3)') ' tot = ', tot
write (stdout, '(1x,a,i12)') ' mp_grid product = ', mp_grid(1)*mp_grid(2)*mp_grid(3)
endif
if (abs(tot - real(mp_grid(1)*mp_grid(2)*mp_grid(3), dp)) > eps8) then
call io_error('ERROR in hamiltonian_wigner_seitz: error in finding Wigner-Seitz points')
endif
if (timing_level > 1) call io_stopwatch('hamiltonian: wigner_seitz', 2)
return
end subroutine hamiltonian_wigner_seitz