check_and_sort_similar_centres Subroutine

private subroutine check_and_sort_similar_centres(signatures, num_G, atom_data, transport, print_output, num_wann, wannier_centres_translated, coord, tran_sorted_idx, write_xyz, stdout, seedname, timer, error, comm)

Uses

  • proc~~check_and_sort_similar_centres~~UsesGraph proc~check_and_sort_similar_centres check_and_sort_similar_centres module~w90_constants w90_constants proc~check_and_sort_similar_centres->module~w90_constants module~w90_error w90_error proc~check_and_sort_similar_centres->module~w90_error module~w90_io w90_io proc~check_and_sort_similar_centres->module~w90_io module~w90_types w90_types proc~check_and_sort_similar_centres->module~w90_types module~w90_wannier90_types w90_wannier90_types proc~check_and_sort_similar_centres->module~w90_wannier90_types module~w90_comms w90_comms module~w90_error->module~w90_comms module~w90_error_base w90_error_base module~w90_error->module~w90_error_base module~w90_io->module~w90_constants module~w90_types->module~w90_constants module~w90_wannier90_types->module~w90_constants module~w90_comms->module~w90_constants module~w90_comms->module~w90_error_base

Arguments

Type IntentOptional Attributes Name
real(kind=dp), intent(in) :: signatures(:,:)
integer, intent(in) :: num_G
type(atom_data_type), intent(in) :: atom_data
type(transport_type), intent(inout) :: transport
type(print_output_type), intent(in) :: print_output
integer, intent(in) :: num_wann
real(kind=dp), intent(in) :: wannier_centres_translated(:,:)
integer, intent(in) :: coord(3)
integer, intent(inout) :: tran_sorted_idx(:)
logical, intent(in) :: write_xyz
integer, intent(in) :: stdout
character(len=50), intent(in) :: seedname
type(timer_list_type), intent(inout) :: timer
type(w90_error_type), intent(out), allocatable :: error
type(w90_comm_type), intent(in) :: comm

Calls

proc~~check_and_sort_similar_centres~~CallsGraph proc~check_and_sort_similar_centres check_and_sort_similar_centres proc~io_stopwatch_start io_stopwatch_start proc~check_and_sort_similar_centres->proc~io_stopwatch_start proc~io_stopwatch_stop io_stopwatch_stop proc~check_and_sort_similar_centres->proc~io_stopwatch_stop proc~set_error_alloc set_error_alloc proc~check_and_sort_similar_centres->proc~set_error_alloc proc~set_error_dealloc set_error_dealloc proc~check_and_sort_similar_centres->proc~set_error_dealloc proc~set_error_fatal set_error_fatal proc~check_and_sort_similar_centres->proc~set_error_fatal proc~tran_write_xyz tran_write_xyz proc~check_and_sort_similar_centres->proc~tran_write_xyz proc~comms_sync_error comms_sync_error proc~set_error_alloc->proc~comms_sync_error proc~set_base_error set_base_error proc~set_error_alloc->proc~set_base_error proc~set_error_dealloc->proc~comms_sync_error proc~set_error_dealloc->proc~set_base_error proc~set_error_fatal->proc~comms_sync_error proc~set_error_fatal->proc~set_base_error proc~io_date io_date proc~tran_write_xyz->proc~io_date

Called by

proc~~check_and_sort_similar_centres~~CalledByGraph proc~check_and_sort_similar_centres check_and_sort_similar_centres proc~tran_lcr_2c2_sort tran_lcr_2c2_sort proc~tran_lcr_2c2_sort->proc~check_and_sort_similar_centres proc~tran_main tran_main proc~tran_main->proc~tran_lcr_2c2_sort proc~w90_transport w90_transport proc~w90_transport->proc~tran_main program~wannier wannier program~wannier->proc~w90_transport

Source Code

  subroutine check_and_sort_similar_centres(signatures, num_G, atom_data, transport, print_output, &
                                            num_wann, wannier_centres_translated, coord, &
                                            tran_sorted_idx, write_xyz, stdout, seedname, timer, &
                                            error, comm)
    !================================================!
    ! Here, we consider the possiblity of wannier functions
    ! with similar centres, such as a set of d-orbitals
    ! centred on an atom. We use tran_group_threshold to
    ! identify them, if they exist, then use the signatures
    ! to dishinguish and sort then consistently from unit
    ! cell to unit cell.
    !
    ! MS: For 2two-shot and beyond, some parameters,
    ! eg, first_group_element will need changing to consider
    ! the geometry of the new systems.
    !================================================!

    use w90_constants, only: dp
    use w90_io, only: io_stopwatch_start, io_stopwatch_stop
    use w90_types, only: atom_data_type, print_output_type, timer_list_type
    use w90_wannier90_types, only: transport_type
    use w90_error, only: w90_error_type, set_error_alloc, set_error_dealloc, set_error_fatal

    implicit none

    ! arguments
    type(atom_data_type), intent(in) :: atom_data
    type(print_output_type), intent(in) :: print_output
    type(transport_type), intent(inout) :: transport
    type(timer_list_type), intent(inout) :: timer
    type(w90_error_type), allocatable, intent(out) :: error
    type(w90_comm_type), intent(in) :: comm
    integer, intent(in) :: coord(3)
    integer, intent(in) :: num_G
    integer, intent(in) :: num_wann
    integer, intent(inout) :: tran_sorted_idx(:)
    integer, intent(in) :: stdout
    real(kind=dp), intent(in) :: wannier_centres_translated(:, :)
    real(kind=dp), intent(in) :: signatures(:, :)
    character(len=50), intent(in)  :: seedname
    logical, intent(in) :: write_xyz

    ! local variables
    integer, allocatable :: idx_similar_wf(:), group_verifier(:), sorted_idx(:), centre_id(:)
    integer, allocatable :: tmp_wf_verifier(:, :), wf_verifier(:, :), first_group_element(:, :)
    integer, allocatable :: ref_similar_centres(:, :), unsorted_similar_centres(:, :)
    integer, allocatable :: wf_similar_centres(:, :, :)
    logical, allocatable :: has_similar_centres(:)
    integer :: i, j, k, l, ierr, group_iterator, coord_iterator, num_wf_iterator, num_wann_cell_ll
    integer :: iterator, max_position(1), p, num_wf_cell_iter
    real(kind=dp), allocatable :: dot_p(:)

    if (print_output%timing_level > 2) call io_stopwatch_start('tran: lcr_2c2_sort: similar_centres', timer)

    num_wann_cell_ll = transport%num_ll/transport%num_cell_ll

    allocate (wf_similar_centres(transport%num_cell_ll*4, num_wann_cell_ll, num_wann_cell_ll), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating wf_similar_centre in check_and_sort_similar_centres', comm)
      return
    end if
    allocate (idx_similar_wf(num_wann_cell_ll), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating idx_similar_wf in check_and_sort_similar_centres', comm)
      return
    end if
    allocate (has_similar_centres(num_wann_cell_ll), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating has_similar_centres in check_and_sort_similar_centres', comm)
      return
    end if
    allocate (tmp_wf_verifier(4*transport%num_cell_ll, num_wann_cell_ll), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating tmp_wf_verifier in check_and_sort_similar_centres', comm)
      return
    end if
    allocate (group_verifier(4*transport%num_cell_ll), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating group_verifier in check_and_sort_similar_centres', comm)
      return
    end if
    allocate (first_group_element(4*transport%num_cell_ll, num_wann_cell_ll), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating first_group_element in check_and_sort_similar_centres', comm)
      return
    end if
    allocate (centre_id(num_wann_cell_ll), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating centre_id in check_and_sort_similar_centres', comm)
      return
    end if

    ! First find WFs with similar centres: store in wf_similar_centres(cell#,group#,WF#)

    group_verifier = 0
    tmp_wf_verifier = 0
    first_group_element = 0
    centre_id = 0

    ! Loop over unit cells in PL1,PL2,PL3 and PL4

    do i = 1, 4*transport%num_cell_ll
      group_iterator = 0
      has_similar_centres = .false.

      ! Loops over wannier functions in present unit cell

      num_wf_cell_iter = 0
      do j = 1, num_wann_cell_ll
        num_wf_iterator = 0

        ! 2nd Loop over wannier functions in the present unit cell

        do k = 1, num_wann_cell_ll
          if ((.not. has_similar_centres(k)) .and. (j .ne. k)) then
            coord_iterator = 0

            ! Loop over x,y,z to find similar centres

            do l = 1, 3
              if (i .le. 2*transport%num_cell_ll) then
                if (abs(wannier_centres_translated(coord(l), tran_sorted_idx(j + (i - 1)*num_wann_cell_ll)) - &
                        wannier_centres_translated(coord(l), tran_sorted_idx(k + (i - 1)*num_wann_cell_ll))) &
                    .le. transport%group_threshold) then
                  coord_iterator = coord_iterator + 1
                else
                  exit
                end if
              else
                if (abs(wannier_centres_translated(coord(l), &
                                                   tran_sorted_idx(num_wann - 2*transport%num_ll &
                                                                   + j + (i - 2*transport%num_cell_ll - 1)*num_wann_cell_ll)) &
                        - wannier_centres_translated(coord(l), &
                                                     tran_sorted_idx(num_wann - 2*transport%num_ll &
                                                                     + k + (i - 2*transport%num_cell_ll - 1)*num_wann_cell_ll))) &
                    .le. transport%group_threshold) then
                  coord_iterator = coord_iterator + 1
                else
                  exit
                end if
              end if
            end do
            if (coord_iterator .eq. 3) then
              if (.not. has_similar_centres(j)) then
                num_wf_iterator = num_wf_iterator + 1
                if (i .le. 2*transport%num_cell_ll) then
                  idx_similar_wf(num_wf_iterator) = tran_sorted_idx(j + (i - 1)*num_wann_cell_ll)
                else
                  idx_similar_wf(num_wf_iterator) = tran_sorted_idx(j + num_wann - 2*transport%num_ll + &
                                                                    (i - 2*transport%num_cell_ll - 1)*num_wann_cell_ll)
                end if
                if (i .le. 2*transport%num_cell_ll) then
                  first_group_element(i, j) = j + (i - 1)*num_wann_cell_ll
                else
                  first_group_element(i, j) = num_wann - 2*transport%num_ll + &
                                              j + (i - 2*transport%num_cell_ll - 1)*num_wann_cell_ll
                end if
                num_wf_cell_iter = num_wf_cell_iter + 1
                centre_id(num_wf_cell_iter) = j
              end if
              has_similar_centres(k) = .true.
              has_similar_centres(j) = .true.
              num_wf_iterator = num_wf_iterator + 1
              if (i .le. 2*transport%num_cell_ll) then
                idx_similar_wf(num_wf_iterator) = tran_sorted_idx(k + (i - 1)*num_wann_cell_ll)
              else
                idx_similar_wf(num_wf_iterator) = tran_sorted_idx(k + num_wann - 2*transport%num_ll + &
                                                                  (i - 2*transport%num_cell_ll - 1)*num_wann_cell_ll)
              end if
            end if
          end if
        end do ! loop over k
        if (num_wf_iterator .gt. 0) then
          group_iterator = group_iterator + 1
          wf_similar_centres(i, group_iterator, :) = idx_similar_wf(:)

          !Save number of WFs in each group

          tmp_wf_verifier(i, group_iterator) = num_wf_iterator
        end if
      end do
      if ((count(has_similar_centres) .eq. 0) .and. (i .eq. 1)) then
        write (stdout, '(a)') ' No wannier functions found with similar centres: sorting completed'
        exit
      elseif (i .eq. 1) then
        write (stdout, *) ' Wannier functions found with similar centres: '
        write (stdout, *) '  -> using signatures to complete sorting '
      end if

      !Save number of group of WFs in each unit cell and compare to previous unit cell

      group_verifier(i) = group_iterator
      if (print_output%iprint .ge. 4) write (stdout, '(a11,i4,a13,i4)') ' Unit cell:', i, '  Num groups:', group_verifier(i)
      if (i .ne. 1) then
        if (group_verifier(i) .ne. group_verifier(i - 1)) then
          if (write_xyz) call tran_write_xyz(atom_data, transport, wannier_centres_translated, &
                                             tran_sorted_idx, num_wann, seedname, stdout)
          call set_error_fatal(error, 'Inconsistent number of groups of similar centred wannier functions between unit cells', comm)
          return
        elseif (i .eq. 4*transport%num_cell_ll) then
          write (stdout, *) ' Consistent groups of similar centred wannier functions between '
          write (stdout, *) ' unit cells found'
          write (stdout, *) ' '
        end if
      end if
    end do  !Loop over all unit cells in PL1,PL2,PL3,PL4

    ! Perform check to ensure consistent number of WFs between equivalent groups in different unit cells

    if (any(has_similar_centres)) then

      allocate (wf_verifier(4*transport%num_cell_ll, group_verifier(1)), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error in allocating wf_verifier in check_and_sort_similar_centres', comm)
        return
      end if

      if (print_output%iprint .ge. 4) write (stdout, *) 'Unit cell   Group number   Num WFs'
      wf_verifier = 0
      wf_verifier = tmp_wf_verifier(:, 1:group_verifier(1))
      do i = 1, 4*transport%num_cell_ll
        do j = 1, group_verifier(1)
          if (print_output%iprint .ge. 4) write (stdout, '(a3,i4,a9,i4,a7,i4)') '   ', i, '         ', &
            j, '       ', wf_verifier(i, j)
          if (i .ne. 1) then
            if (wf_verifier(i, j) .ne. wf_verifier(i - 1, j)) then
              call set_error_fatal(error, 'Inconsistent number of wannier &
                  &functions between equivalent groups of similar &
                  &centred wannier functions', comm)
              return
            end if
          end if
        end do
      end do
      write (stdout, *) ' Consistent number of wannier functions between equivalent groups of similar'
      write (stdout, *) ' centred wannier functions'
      write (stdout, *) ' '

      write (stdout, *) ' Fixing order of similar centred wannier functions using parity signatures'

      do i = 2, 4*transport%num_cell_ll
        do j = 1, group_verifier(1)

          ! Make array of WF numbers which act as a reference to sort against
          ! and an array which need sorting

          allocate (ref_similar_centres(group_verifier(1), wf_verifier(1, j)), stat=ierr)
          if (ierr /= 0) then
            call set_error_alloc(error, 'Error in allocating ref_similar_centres in check_and_sort_similar_centres', comm)
            return
          end if
          allocate (unsorted_similar_centres(group_verifier(1), wf_verifier(1, j)), stat=ierr)
          if (ierr /= 0) then
            call set_error_alloc(error, 'Error in allocating unsorted_similar_centres in check_and_sort_similar_centres', comm)
            return
          end if
          allocate (sorted_idx(wf_verifier(1, j)), stat=ierr)
          if (ierr /= 0) then
            call set_error_alloc(error, 'Error in allocating sorted_idx in check_and_sort_similar_centres', comm)
            return
          end if
          allocate (dot_p(wf_verifier(1, j)), stat=ierr)
          if (ierr /= 0) then
            call set_error_alloc(error, 'Error in allocating dot_p in check_and_sort_similar_centres', comm)
            return
          end if

          do k = 1, wf_verifier(1, j)
            ref_similar_centres(j, k) = wf_similar_centres(1, j, k)
            unsorted_similar_centres(j, k) = wf_similar_centres(i, j, k)
          end do

          sorted_idx = 0
          do k = 1, wf_verifier(1, j)
            dot_p = 0.0_dp

            ! building the array of positive dot products of signatures between unsorted_similar_centres(j,k)
            ! and all the ref_similar_centres(j,:)

            do l = 1, wf_verifier(1, j)
              do p = 1, num_G
                dot_p(l) = dot_p(l) + abs(signatures(p, unsorted_similar_centres(j, k)))* &
                           abs(signatures(p, ref_similar_centres(j, l)))
              end do
            end do

            max_position = maxloc(dot_p)

            sorted_idx(max_position(1)) = unsorted_similar_centres(j, k)
          end do

          ! we have the properly ordered indexes for group j in unit cell i, now we need
          ! to overwrite the tran_sorted_idx array at the proper position

          tran_sorted_idx(first_group_element(i, centre_id(j)):first_group_element(i, centre_id(j)) +&
               &wf_verifier(i, j) - 1) = sorted_idx(:)

          deallocate (dot_p, stat=ierr)
          if (ierr /= 0) then
            call set_error_dealloc(error, 'Error in deallocating dot_p in check_and_sort_similar_centres', comm)
            return
          end if
          deallocate (sorted_idx, stat=ierr)
          if (ierr /= 0) then
            call set_error_dealloc(error, 'Error in deallocating sorted_idx in check_and_sort_similar_centres', comm)
            return
          end if
          deallocate (unsorted_similar_centres, stat=ierr)
          if (ierr /= 0) then
            call set_error_dealloc(error, 'Error in deallocating unsorted_similar_centres in check_and_sort_similar_centres', comm)
            return
          end if
          deallocate (ref_similar_centres, stat=ierr)
          if (ierr /= 0) then
            call set_error_dealloc(error, 'Error in deallocating ref_similar_centres in check_and_sort_similar_centres', comm)
            return
          end if
        end do
      end do

      ! checking that all the indices of WFs in the new tran_sorted_idx are distinct
      ! Remark: physically, no two WFs with similar centres can have the same type so we should expect
      ! this check to always pass unless the signatures/wf are very weird !!

      do k = 1, num_wann
        iterator = 0
        do l = 1, num_wann
          if (tran_sorted_idx(l) .eq. k) then
            iterator = iterator + 1
          end if
        end do

        if ((iterator .ge. 2) .or. (iterator .eq. 0)) then
          call set_error_fatal(error, &
              'A Wannier Function appears either zero times or twice after sorting, this may be due to a &
              &poor wannierisation and/or disentanglement', comm)
          return
        end if
        !write(stdout,*) ' WF : ',k,' appears ',iterator,' time(s)'
      end do
      deallocate (wf_verifier, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error deallocating wf_verifier in check_and_sort_similar_centres', comm)
        return
      end if
    end if

    deallocate (centre_id, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error deallocating centre_id in check_and_sort_similar_centres', comm)
      return
    end if
    deallocate (first_group_element, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error deallocating first_group_element in check_and_sort_similar_centres', comm)
      return
    end if
    deallocate (group_verifier, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error deallocating group_verifier in check_and_sort_similar_centres', comm)
      return
    end if
    deallocate (tmp_wf_verifier, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error deallocating tmp_wf_verifier in check_and_sort_similar_centres', comm)
      return
    end if
    deallocate (has_similar_centres, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error deallocating has_similar_centres in check_and_sort_similar_centres', comm)
      return
    end if
    deallocate (idx_similar_wf, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error deallocating idx_similar_wf in check_and_sort_similar_centres', comm)
      return
    end if
    deallocate (wf_similar_centres, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error deallocating wf_similar_centre in check_and_sort_similar_centres', comm)
      return
    end if

    if (print_output%timing_level > 2) call io_stopwatch_stop('tran: lcr_2c2_sort: similar_centres', timer)

    return

  end subroutine check_and_sort_similar_centres