kmesh_shell_automatic Subroutine

private subroutine kmesh_shell_automatic(multi, dnn, bweight)

Uses

  • proc~~kmesh_shell_automatic~~UsesGraph proc~kmesh_shell_automatic kmesh_shell_automatic module~w90_constants w90_constants proc~kmesh_shell_automatic->module~w90_constants module~w90_io w90_io proc~kmesh_shell_automatic->module~w90_io module~w90_io->module~w90_constants

Find the correct set of shells to satisfy B1 The stratagy is: 1) Take the bvectors from the next shell 2) Reject them if they are parallel to exisiting b vectors 3) Test to see if we satisfy B1, if not add another shell and repeat

Arguments

Type IntentOptional AttributesName
integer, intent(in) :: multi(search_shells)
real(kind=dp), intent(in) :: dnn(search_shells)
real(kind=dp), intent(out) :: bweight(max_shells)

Calls

proc~~kmesh_shell_automatic~~CallsGraph proc~kmesh_shell_automatic kmesh_shell_automatic dgesvd dgesvd proc~kmesh_shell_automatic->dgesvd proc~io_error io_error proc~kmesh_shell_automatic->proc~io_error

Called by

proc~~kmesh_shell_automatic~~CalledByGraph proc~kmesh_shell_automatic kmesh_shell_automatic proc~kmesh_get kmesh_get proc~kmesh_get->proc~kmesh_shell_automatic proc~wannier_run wannier_run proc~wannier_run->proc~kmesh_get program~postw90 postw90 program~postw90->proc~kmesh_get

Contents

Source Code


Source Code

  subroutine kmesh_shell_automatic(multi, dnn, bweight)
    !==========================================================================
    !
    !! Find the correct set of shells to satisfy B1
    !!  The stratagy is:
    !!       1) Take the bvectors from the next shell
    !!       2) Reject them if they are parallel to exisiting b vectors
    !!       3) Test to see if we satisfy B1, if not add another shell and repeat
    !
    !==========================================================================

    use w90_constants, only: eps5, eps6
    use w90_io, only: io_error, stdout, io_stopwatch
    implicit none

    integer, intent(in) :: multi(search_shells)   ! the number of kpoints in the shell
    real(kind=dp), intent(in) :: dnn(search_shells) ! the bvectors
    real(kind=dp), intent(out) :: bweight(max_shells)
    real(kind=dp), allocatable     :: bvector(:, :, :) ! the bvectors

    real(kind=dp), dimension(:), allocatable :: singv, tmp1, tmp2, tmp3
    real(kind=dp), dimension(:, :), allocatable :: amat, umat, vmat, smat, tmp0
    integer, parameter :: lwork = max_shells*10
    real(kind=dp) :: work(lwork)
    real(kind=dp), parameter :: target(6) = (/1.0_dp, 1.0_dp, 1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp/)
    logical :: b1sat, lpar
    integer :: loop_i, loop_j, loop_bn, loop_b, loop_s, info, cur_shell, ierr
    real(kind=dp) :: delta

    integer :: loop, shell

    if (timing_level > 1) call io_stopwatch('kmesh: shell_automatic', 1)

    allocate (bvector(3, maxval(multi), max_shells), stat=ierr)
    if (ierr /= 0) call io_error('Error allocating bvector in kmesh_shell_automatic')
    bvector = 0.0_dp; bweight = 0.0_dp

    if (on_root) write (stdout, '(1x,a)') '| The b-vectors are chosen automatically                                     |'

    b1sat = .false.
    do shell = 1, search_shells
      cur_shell = num_shells + 1

      ! get the b vectors for the new shell
      call kmesh_get_bvectors(multi(shell), 1, dnn(shell), bvector(:, 1:multi(shell), cur_shell))

      if (iprint >= 3 .and. on_root) then
        write (stdout, '(1x,a8,1x,I2,a14,1x,I2,49x,a)') '| Shell:', shell, ' Multiplicity:', multi(shell), '|'
        do loop = 1, multi(shell)
          write (stdout, '(1x,a10,I2,1x,a1,4x,3f12.6,5x,a9,9x,a)') '| b-vector ', loop, ':', &
            bvector(:, loop, cur_shell)/lenconfac, '('//trim(length_unit)//'^-1)', '|'
        end do
      end if

      ! We check that the new shell is not parrallel to an existing shell (cosine=1)
      lpar = .false.
      if (num_shells > 0) then
        do loop_bn = 1, multi(shell)
          do loop_s = 1, num_shells
            do loop_b = 1, multi(shell_list(loop_s))
              delta = dot_product(bvector(:, loop_bn, cur_shell), bvector(:, loop_b, loop_s))/ &
                      sqrt(dot_product(bvector(:, loop_bn, cur_shell), bvector(:, loop_bn, cur_shell))* &
                           dot_product(bvector(:, loop_b, loop_s), bvector(:, loop_b, loop_s)))
              if (abs(abs(delta) - 1.0_dp) < eps6) lpar = .true.
            end do
          end do
        end do
      end if

      if (lpar) then
        if (iprint >= 3 .and. on_root) then
          write (stdout, '(1x,a)') '| This shell is linearly dependent on existing shells: Trying next shell     |'
        end if
        cycle
      end if

      num_shells = num_shells + 1
      shell_list(num_shells) = shell

      allocate (tmp0(max_shells, max_shells), stat=ierr)
      if (ierr /= 0) call io_error('Error allocating amat in kmesh_shell_automatic')
      allocate (tmp1(max_shells), stat=ierr)
      if (ierr /= 0) call io_error('Error allocating amat in kmesh_shell_automatic')
      allocate (tmp2(num_shells), stat=ierr)
      if (ierr /= 0) call io_error('Error allocating amat in kmesh_shell_automatic')
      allocate (tmp3(num_shells), stat=ierr)
      if (ierr /= 0) call io_error('Error allocating amat in kmesh_shell_automatic')
      allocate (amat(max_shells, num_shells), stat=ierr)
      if (ierr /= 0) call io_error('Error allocating amat in kmesh_shell_automatic')
      allocate (umat(max_shells, max_shells), stat=ierr)
      if (ierr /= 0) call io_error('Error allocating umat in kmesh_shell_automatic')
      allocate (vmat(num_shells, num_shells), stat=ierr)
      if (ierr /= 0) call io_error('Error allocating vmat in kmesh_shell_automatic')
      allocate (smat(num_shells, max_shells), stat=ierr)
      if (ierr /= 0) call io_error('Error allocating smat in kmesh_shell_automatic')
      allocate (singv(num_shells), stat=ierr)
      if (ierr /= 0) call io_error('Error allocating singv in kmesh_shell_automatic')
      amat(:, :) = 0.0_dp; umat(:, :) = 0.0_dp; vmat(:, :) = 0.0_dp; smat(:, :) = 0.0_dp; singv(:) = 0.0_dp

      amat = 0.0_dp
      do loop_s = 1, num_shells
        do loop_b = 1, multi(shell_list(loop_s))
          amat(1, loop_s) = amat(1, loop_s) + bvector(1, loop_b, loop_s)*bvector(1, loop_b, loop_s)
          amat(2, loop_s) = amat(2, loop_s) + bvector(2, loop_b, loop_s)*bvector(2, loop_b, loop_s)
          amat(3, loop_s) = amat(3, loop_s) + bvector(3, loop_b, loop_s)*bvector(3, loop_b, loop_s)
          amat(4, loop_s) = amat(4, loop_s) + bvector(1, loop_b, loop_s)*bvector(2, loop_b, loop_s)
          amat(5, loop_s) = amat(5, loop_s) + bvector(2, loop_b, loop_s)*bvector(3, loop_b, loop_s)
          amat(6, loop_s) = amat(6, loop_s) + bvector(3, loop_b, loop_s)*bvector(1, loop_b, loop_s)
        end do
      end do

      info = 0
      call dgesvd('A', 'A', max_shells, num_shells, amat, max_shells, singv, umat, max_shells, vmat, num_shells, work, lwork, info)
      if (info < 0) then
        if (on_root) write (stdout, '(1x,a,1x,I1,1x,a)') 'kmesh_shell_automatic: Argument', abs(info), 'of dgesvd is incorrect'
        call io_error('kmesh_shell_automatic: Problem with Singular Value Decomposition')
      else if (info > 0) then
        call io_error('kmesh_shell_automatic: Singular Value Decomposition did not converge')
      end if

      if (any(abs(singv) < eps5)) then
        if (num_shells == 1) then
          call io_error('kmesh_shell_automatic: Singular Value Decomposition has found a very small singular value')
        else
          if (on_root) write (stdout, '(1x,a)') '| SVD found small singular value, Rejecting this shell and trying the next   |'
          b1sat = .false.
          num_shells = num_shells - 1
          goto 200
        end if
      end if

      smat = 0.0_dp
      do loop_s = 1, num_shells
        smat(loop_s, loop_s) = 1.0_dp/singv(loop_s)
      end do

      ! S. Ponce: The following below is correct but had to be unpacked because of PGI-15
      ! bweight(1:num_shells)=matmul(transpose(vmat),matmul(smat,matmul(transpose(umat),target)))
      tmp0 = transpose(umat)
      tmp1 = matmul(tmp0, target)
      tmp2 = matmul(smat, tmp1)
      tmp3 = matmul(transpose(vmat), tmp2)
      bweight(1:num_shells) = tmp3

      if (iprint >= 2 .and. on_root) then
        do loop_s = 1, num_shells
          write (stdout, '(1x,a,I2,a,f12.7,5x,a8,36x,a)') '| Shell: ', loop_s, &
            ' w_b ', bweight(loop_s)*lenconfac**2, '('//trim(length_unit)//'^2)', '|'
        end do
      end if

      !check b1
      b1sat = .true.
      do loop_i = 1, 3
        do loop_j = loop_i, 3
          delta = 0.0_dp
          do loop_s = 1, num_shells
            do loop_b = 1, multi(shell_list(loop_s))
              delta = delta + bweight(loop_s)*bvector(loop_i, loop_b, loop_s)*bvector(loop_j, loop_b, loop_s)
            end do
          end do
          if (loop_i == loop_j) then
            if (abs(delta - 1.0_dp) > kmesh_tol) b1sat = .false.
          end if
          if (loop_i /= loop_j) then
            if (abs(delta) > kmesh_tol) b1sat = .false.
          end if
        end do
      end do

      if (.not. b1sat) then
        if (shell < search_shells .and. iprint >= 3) then
          if (on_root) write (stdout, '(1x,a,24x,a1)') '| B1 condition is not satisfied: Adding another shell', '|'
        elseif (shell == search_shells) then
          if (on_root) write (stdout, *) ' '
          if (on_root) write (stdout, '(1x,a,i3,a)') 'Unable to satisfy B1 with any of the first ', search_shells, ' shells'
          if (on_root) write (stdout, '(1x,a)') 'Check that you have specified your unit cell to a high precision'
          if (on_root) write (stdout, '(1x,a)') 'Low precision might cause a loss of symmetry.'
          if (on_root) write (stdout, '(1x,a)') ' '
          if (on_root) write (stdout, '(1x,a)') 'If your cell is very long, or you have an irregular MP grid'
          if (on_root) write (stdout, '(1x,a)') 'Try increasing the parameter search_shells in the win file (default=30)'
          if (on_root) write (stdout, *) ' '
          call io_error('kmesh_get_automatic')
        end if
      end if

200   continue
      deallocate (tmp0, stat=ierr)
      if (ierr /= 0) call io_error('Error deallocating amat in kmesh_shell_automatic')
      deallocate (tmp1, stat=ierr)
      if (ierr /= 0) call io_error('Error deallocating amat in kmesh_shell_automatic')
      deallocate (tmp2, stat=ierr)
      if (ierr /= 0) call io_error('Error deallocating amat in kmesh_shell_automatic')
      deallocate (tmp3, stat=ierr)
      if (ierr /= 0) call io_error('Error deallocating amat in kmesh_shell_automatic')
      deallocate (amat, stat=ierr)
      if (ierr /= 0) call io_error('Error deallocating amat in kmesh_shell_automatic')
      deallocate (umat, stat=ierr)
      if (ierr /= 0) call io_error('Error deallocating umat in kmesh_shell_automatic')
      deallocate (vmat, stat=ierr)
      if (ierr /= 0) call io_error('Error deallocating vmat in kmesh_shell_automatic')
      deallocate (smat, stat=ierr)
      if (ierr /= 0) call io_error('Error deallocating smat in kmesh_shell_automatic')
      deallocate (singv, stat=ierr)
      if (ierr /= 0) call io_error('Error deallocating singv in kmesh_shell_automatic')

      if (b1sat) exit

    end do

    if (.not. b1sat) then
      if (on_root) write (stdout, *) ' '
      if (on_root) write (stdout, '(1x,a,i3,a)') 'Unable to satisfy B1 with any of the first ', search_shells, ' shells'
      if (on_root) write (stdout, '(1x,a)') 'Your cell might be very long, or you may have an irregular MP grid'
      if (on_root) write (stdout, '(1x,a)') 'Try increasing the parameter search_shells in the win file (default=12)'
      if (on_root) write (stdout, *) ' '
      call io_error('kmesh_get_automatic')
    end if

    if (timing_level > 1) call io_stopwatch('kmesh: shell_automatic', 2)

    return

  end subroutine kmesh_shell_automatic