00001
00002
00003
00004
00005
00006
00007
00008 module m_bvector
00009 implicit none
00010 contains
00011
00012 subroutine generate_bvectors(b1, b2, b3, nkb1, nkb2, nkb3, &
00013 nbmax, maxshell, verbosity, &
00014 nb, bvec_frac, bvec_cart, weight)
00015
00016
00017
00018 real(8), intent(in) :: b1(3), b2(3), b3(3)
00019 integer, intent(in) :: nkb1, nkb2, nkb3
00020 integer, intent(in) :: nbmax, maxshell
00021 integer, intent(in) :: verbosity
00022 integer, intent(out) :: nb
00023 real(8), intent(out) :: bvec_frac(3,nbmax), bvec_cart(3,nbmax)
00024 real(8), intent(out) :: weight(nbmax)
00025
00026 integer :: i, j, k, m, l
00027 integer :: nk, nbvec
00028 integer :: nmulti, nshell
00029 integer :: nbvec_now, nbvec_shell
00030 integer :: nrank, nmin, shift
00031 integer, allocatable :: multiplicity(:)
00032 integer, allocatable :: index_sort(:), index_k(:)
00033 integer, allocatable :: index_k_shell(:), index_k_tmp(:)
00034 logical :: is_new, is_fullrank, satisfy_orthogonal, success
00035 real(8), parameter :: tolerance = 1.0d-8
00036 real(8) :: kval(3), dist_tmp, sigma_tmp(6), bvec(3)
00037 real(8), parameter :: sigma_vec(6) = (/1.d0, 0.d0, 0.d0, 1.d0, 0.d0, 1.d0/)
00038 real(8), allocatable :: xk(:,:), xk_cart(:,:), dist_k(:)
00039 real(8), allocatable :: bvec_merged(:,:), bvec_shell(:,:)
00040 real(8), allocatable :: bvec_tmp(:,:), bvec_now(:,:)
00041 real(8), allocatable :: bbmat(:,:), weight_tmp(:)
00042 real(8), allocatable :: Umat(:,:), Sval(:), VTmat(:,:), Sinv(:,:)
00043
00044 if (verbosity > 0) then
00045 write(6,*) ' '
00046 write(6,*) '============================================='
00047 write(6,*) ' Auatomatic generation of b-vectors '
00048 write(6,*) '============================================='
00049 write(6,*) ' '
00050 endif
00051
00052 bvec_frac = 0.0d0
00053 bvec_cart = 0.0d0
00054 weight = 0.0d0
00055 nb = 0
00056
00057
00058
00059
00060 nk = nkb1 * nkb2 * nkb3 + 26
00061 allocate(xk(3, nk))
00062 m = 0
00063 do i = 1, nkb1
00064 kval(1) = dble(i-1) / dble(nkb1)
00065 if (kval(1) >= 0.5d0) then
00066 kval(1) = kval(1) - 1.0d0
00067 endif
00068 do j = 1, nkb2
00069 kval(2) = dble(j-1) / dble(nkb2)
00070 if (kval(2) >= 0.5d0) then
00071 kval(2) = kval(2) - 1.0d0
00072 endif
00073 do k = 1, nkb3
00074 kval(3) = dble(k-1) / dble(nkb3)
00075 if (kval(3) >= 0.5d0) then
00076 kval(3) = kval(3) - 1.0d0
00077 endif
00078 m = m + 1
00079 xk(1:3, m) = kval(1:3)
00080 enddo
00081 enddo
00082 enddo
00083
00084
00085
00086 do i = -1, 1
00087 do j = -1, 1
00088 do k = -1, 1
00089 if (i == 0 .and. j == 0 .and. k == 0) then
00090 cycle
00091 endif
00092 m = m + 1
00093 xk(1:3, m) = (/dble(i), dble(j), dble(k)/)
00094 enddo
00095 enddo
00096 enddo
00097
00098
00099
00100
00101 allocate(xk_cart(3, nk), dist_k(nk))
00102 allocate(index_sort(nk))
00103 do i = 1, nk
00104 xk_cart(:,i) = xk(1,i)*b1(:) + xk(2,i)*b2(:) + xk(3,i)*b3(:)
00105 dist_k(i) = sqrt(dot_product(xk_cart(:,i), xk_cart(:,i)))
00106 index_sort(i) = i
00107 enddo
00108
00109
00110
00111 call quicksort_double_arg(nk, dist_k, index_sort, 1, nk)
00112
00113
00114
00115
00116 allocate(multiplicity(maxshell+1))
00117 nmulti = 0
00118 dist_tmp = 0.0d0
00119 multiplicity = 0
00120 m = 1
00121 do i = 1, nk
00122 if (abs(dist_k(i) - dist_tmp) < tolerance) then
00123 nmulti = nmulti + 1
00124 else
00125 dist_tmp = dist_k(i)
00126 multiplicity(m) = nmulti
00127
00128 nmulti = 1
00129 m = m + 1
00130 if (m > maxshell + 1) then
00131 exit
00132 endif
00133 endif
00134 enddo
00135
00136 nshell = 0
00137 do i = 1, maxshell + 1
00138 if (multiplicity(i) > 0) then
00139 nshell = nshell + 1
00140 endif
00141 enddo
00142
00143 if (verbosity > 0) then
00144 write(6,*) " Shell Distance Multiplicity"
00145 write(6,*) " ------- ---------- ------------"
00146 m = 1
00147 do i = 1, nshell
00148 dist_tmp = dist_k(m)
00149
00150 if (dist_tmp > tolerance) then
00151 write(6,'(i5,F20.8,i18)') i - 1, dist_tmp, multiplicity(i)
00152 endif
00153 m = m + multiplicity(i)
00154 enddo
00155 write(6,*)
00156 endif
00157 deallocate(dist_k)
00158
00159
00160
00161
00162 allocate(index_k(nk))
00163 allocate(bvec_now(3,nk))
00164 nbvec_now = 0
00165 index_k = 0
00166 bvec_now = 0.0d0
00167
00168
00169
00170 do i = 2, nshell
00171
00172 nmulti = multiplicity(i)
00173
00174 allocate(bvec_shell(3, nmulti))
00175 allocate(bvec_tmp(3, nmulti))
00176 allocate(index_k_shell(nmulti))
00177 allocate(index_k_tmp(nmulti))
00178 bvec_shell = 0.0d0
00179 index_k_shell = 0
00180
00181 shift = sum(multiplicity(1:i-1))
00182 index_k_tmp(:) = index_sort(shift+1:shift+nmulti)
00183 bvec_tmp(:,1:nmulti) = xk_cart(:,index_k_tmp(1:nmulti))
00184
00185
00186
00187
00188 m = 0
00189 do j = 1, nmulti
00190
00191 is_new = .true.
00192
00193 bvec(:) = -bvec_tmp(:,j)
00194 do k = 1, m
00195 if (sqrt(dot_product(bvec_shell(:,k)-bvec(:), &
00196 bvec_shell(:,k)-bvec(:))) < tolerance) then
00197 is_new = .false.
00198 exit
00199 endif
00200 enddo
00201
00202 if (is_new) then
00203 m = m + 1
00204 bvec_shell(:,m) = bvec_tmp(:,j)
00205 index_k_shell(m) = index_k_tmp(j)
00206 endif
00207 enddo
00208 nbvec_shell = m
00209 nbvec = nbvec_now + nbvec_shell
00210 deallocate(index_k_tmp, bvec_tmp)
00211
00212
00213
00214 allocate(bvec_merged(3, nbvec))
00215 bvec_merged = 0.0d0
00216 bvec_merged(:,1:nbvec_now) = bvec_now(:,1:nbvec_now)
00217 bvec_merged(:,nbvec_now+1:nbvec) = bvec_shell(:,1:nbvec_shell)
00218
00219 if (verbosity > 0) then
00220 write(6,*)
00221 write(6,*) " ------------------------------------------------ "
00222 write(6,'(2x,a,i4)') " New shell index : ", i - 1
00223 write(6,*)
00224 write(6,'(2x,a,i4)') " Number of candidate b-vectors : ", nbvec
00225 write(6,*) " List of b-vectors (Cartesian) :"
00226 do j = 1, nbvec
00227 write(6,'(3F15.8)') bvec_merged(:,j)
00228 enddo
00229 endif
00230
00231
00232
00233 allocate(bbmat(6, nbvec))
00234 allocate(weight_tmp(nbvec))
00235
00236 m = 0
00237 do j = 1, 3
00238 do k = j, 3
00239 m = m + 1
00240 do l = 1, nbvec
00241 bbmat(m, l) = bvec_merged(j,l) * bvec_merged(k,l)
00242 enddo
00243 enddo
00244 enddo
00245
00246 nmin = min(6, nbvec)
00247 allocate(Sval(nmin), Umat(6, 6), VTmat(nbvec, nbvec))
00248
00249 call SVD(6, nbvec, nmin, bbmat, nrank, Sval, Umat, VTmat)
00250
00251 is_fullrank = (nrank == nmin)
00252
00253 if (is_fullrank) then
00254
00255
00256
00257 bvec_now(:,nbvec_now+1:nbvec) = bvec_shell(:,1:nbvec_shell)
00258 index_k(nbvec_now+1:nbvec) = index_k_shell(1:nbvec_shell)
00259 nbvec_now = nbvec
00260
00261 allocate(Sinv(6, nbvec))
00262 Sinv = 0.0d0
00263 do j = 1, nmin
00264 Sinv(j,j) = 1.0d0 / Sval(j)
00265 enddo
00266
00267 weight_tmp = matmul(transpose(matmul(matmul(Umat, Sinv), VTmat)), sigma_vec)
00268
00269 deallocate(Sinv)
00270
00271 if (verbosity > 0) then
00272 write(6,*)
00273 write(6,*) " Matrix is full-rank. This shell is"
00274 write(6,*) " linearly independent on the existing shells."
00275 write(*,*) " Weights of each b-vectors below:"
00276 do j = 1, nbvec
00277 write(6,'(3x, F15.8)') weight_tmp(j)*0.5d0
00278 enddo
00279 endif
00280
00281
00282
00283 m = 0
00284 do j = 1, 3
00285 do k = j, 3
00286 m = m + 1
00287 sigma_tmp(m) = 0.0d0
00288 do l = 1, nbvec
00289 sigma_tmp(m) = sigma_tmp(m) &
00290 + weight_tmp(l)*bvec_merged(j,l)*bvec_merged(k,l)
00291 enddo
00292 enddo
00293 enddo
00294
00295 sigma_tmp = sigma_tmp - sigma_vec
00296 if (sqrt(dot_product(sigma_tmp,sigma_tmp)) < tolerance) then
00297 satisfy_orthogonal = .true.
00298 else
00299 satisfy_orthogonal = .false.
00300 endif
00301 else
00302 if (verbosity > 0) then
00303 write(6,*)
00304 write(6,*) " Matrix is rank-deficient. This shell is"
00305 write(6,*) " linearly dependent on the existing shells."
00306 write(6,*) " Skipping this shell..."
00307 endif
00308 endif
00309
00310 deallocate(Sval, Umat, VTmat)
00311 deallocate(bbmat)
00312 deallocate(bvec_shell,bvec_merged)
00313 deallocate(index_k_shell)
00314
00315 success = .false.
00316 if (is_fullrank) then
00317 if (satisfy_orthogonal) then
00318
00319 success = .true.
00320
00321 if (verbosity > 0) then
00322 write(6,*)
00323 write(6,*) " Weighted orthogonality is satisfied."
00324 endif
00325
00326
00327
00328 nb = 2 * nbvec
00329 do j = 1, nbvec
00330 bvec_frac(:, 2*(j-1) + 1) = xk(:, index_k(j))
00331 bvec_frac(:, 2*j ) = -xk(:, index_k(j))
00332 bvec_cart(:, 2*(j-1) + 1) = xk_cart(:, index_k(j))
00333 bvec_cart(:, 2*j ) = -xk_cart(:, index_k(j))
00334 weight(2*(j-1) + 1) = weight_tmp(j)*0.5d0
00335 weight(2*j ) = weight_tmp(j)*0.5d0
00336 enddo
00337 else
00338 if (verbosity > 0) then
00339 write(6,*)
00340 write(6,*) " Weighted orthogonality is NOT satisfied."
00341 endif
00342 endif
00343 endif
00344
00345 deallocate(weight_tmp)
00346
00347 if (success) exit
00348 enddo
00349
00350 deallocate(xk, xk_cart, index_k, bvec_now)
00351
00352 if (success) then
00353 if (verbosity > 0) then
00354 write(6,*)
00355 write(6,*) " b-vectors are created successfully."
00356 write(6,*) ' '
00357 write(6,*) '============================================='
00358 write(6,*) ' Finish automatic generation '
00359 write(6,*) '============================================='
00360 write(6,*) ' '
00361 endif
00362 else
00363 stop ' Could not find b-vectors'
00364 endif
00365
00366 return
00367 end subroutine generate_bvectors
00368
00369
00370 subroutine SVD(m, n, k, A, nrank, S, U, VT)
00371
00372
00373
00374 implicit none
00375 integer, intent(in) :: m, n, k
00376 real(8), intent(in) :: A(m, n)
00377 integer, intent(out) :: nrank
00378 real(8), intent(out) :: S(k), U(m, m), VT(n, n)
00379
00380 integer :: i
00381 integer :: lwork, info
00382 real(8), allocatable :: work(:)
00383 real(8), allocatable :: Acopy(:,:)
00384
00385 lwork = max(3*k+max(m,n), 5*k)
00386 lwork = 2 * lwork
00387
00388 allocate(Acopy(m, n), work(lwork))
00389 Acopy = A
00390
00391 call dgesvd('A', 'A', m, n, Acopy, m, S, U, m, &
00392 VT, n, work, lwork, info)
00393
00394 nrank = 0
00395 do i = 1, k
00396 if (S(1) > 1.0d-12) then
00397 if (S(i) > S(1)*1.0d-8) then
00398 nrank = nrank + 1
00399 endif
00400 endif
00401 enddo
00402
00403 deallocate(Acopy, work)
00404
00405 return
00406 end subroutine SVD
00407
00408 recursive subroutine quicksort_double_arg(n, array, ind, first, last)
00409
00410
00411
00412 implicit none
00413 integer, intent(in) :: n, first, last
00414 integer, intent(inout) :: ind(n)
00415 real(8), intent(inout) :: array(n)
00416 integer :: i, j, ind_tmp
00417 real(8) :: tmp, pivot
00418 pivot= array((first+last)/2)
00419 i= first
00420 j= last
00421 do
00422 do while (array(i) < pivot)
00423 i = i + 1
00424 end do
00425 do while (pivot < array(j))
00426 j = j - 1
00427 end do
00428 if (i >= j) exit
00429
00430 tmp = array(i)
00431 array(i) = array(j)
00432 array(j) = tmp
00433 ind_tmp = ind(i)
00434 ind(i) = ind(j)
00435 ind(j) = ind_tmp
00436
00437 i= i + 1
00438 j= j - 1
00439 end do
00440 if (first < i - 1) call quicksort_double_arg(n, array, ind, first, i - 1)
00441 if (j + 1 < last) call quicksort_double_arg(n, array, ind, j + 1, last)
00442 end subroutine quicksort_double_arg
00443
00444 end module m_bvector