wann_main_gamma Subroutine

public subroutine wann_main_gamma(kmesh_info, wann_control, omega, print_output, wannier_data, m_matrix, u_matrix, real_lattice, num_kpts, num_wann, stdout, timer, error, comm)

Uses

  • proc~~wann_main_gamma~~UsesGraph proc~wann_main_gamma wann_main_gamma module~w90_comms w90_comms proc~wann_main_gamma->module~w90_comms module~w90_constants w90_constants proc~wann_main_gamma->module~w90_constants module~w90_io w90_io proc~wann_main_gamma->module~w90_io module~w90_types w90_types proc~wann_main_gamma->module~w90_types module~w90_utility w90_utility proc~wann_main_gamma->module~w90_utility module~w90_wannier90_readwrite w90_wannier90_readwrite proc~wann_main_gamma->module~w90_wannier90_readwrite module~w90_wannier90_types w90_wannier90_types proc~wann_main_gamma->module~w90_wannier90_types module~w90_comms->module~w90_constants module~w90_error_base w90_error_base module~w90_comms->module~w90_error_base module~w90_io->module~w90_constants module~w90_types->module~w90_constants module~w90_utility->module~w90_comms module~w90_utility->module~w90_constants module~w90_wannier90_readwrite->module~w90_constants module~w90_wannier90_readwrite->module~w90_types module~w90_wannier90_readwrite->module~w90_wannier90_types module~w90_error w90_error module~w90_wannier90_readwrite->module~w90_error module~w90_readwrite w90_readwrite module~w90_wannier90_readwrite->module~w90_readwrite module~w90_wannier90_types->module~w90_constants module~w90_error->module~w90_comms module~w90_error->module~w90_error_base module~w90_readwrite->module~w90_comms module~w90_readwrite->module~w90_constants module~w90_readwrite->module~w90_types

Arguments

Type IntentOptional Attributes Name
type(kmesh_info_type), intent(in) :: kmesh_info
type(wann_control_type), intent(inout) :: wann_control
type(wann_omega_type), intent(inout) :: omega
type(print_output_type), intent(in) :: print_output
type(wannier_data_type), intent(inout) :: wannier_data
complex(kind=dp), intent(inout) :: m_matrix(:,:,:,:)
complex(kind=dp), intent(inout) :: u_matrix(:,:,:)
real(kind=dp), intent(in) :: real_lattice(3,3)
integer, intent(in) :: num_kpts
integer, intent(in) :: num_wann
integer, intent(in) :: stdout
type(timer_list_type), intent(inout) :: timer
type(w90_error_type), intent(out), allocatable :: error
type(w90_comm_type), intent(in) :: comm

Calls

proc~~wann_main_gamma~~CallsGraph proc~wann_main_gamma wann_main_gamma proc~internal_test_convergence internal_test_convergence proc~wann_main_gamma->proc~internal_test_convergence proc~io_stopwatch_start io_stopwatch_start proc~wann_main_gamma->proc~io_stopwatch_start proc~io_stopwatch_stop io_stopwatch_stop proc~wann_main_gamma->proc~io_stopwatch_stop proc~io_time io_time proc~wann_main_gamma->proc~io_time proc~mpirank mpirank proc~wann_main_gamma->proc~mpirank proc~set_error_alloc set_error_alloc proc~wann_main_gamma->proc~set_error_alloc proc~set_error_dealloc set_error_dealloc proc~wann_main_gamma->proc~set_error_dealloc proc~utility_frac_to_cart utility_frac_to_cart proc~wann_main_gamma->proc~utility_frac_to_cart proc~utility_zgemm utility_zgemm proc~wann_main_gamma->proc~utility_zgemm proc~wann_check_unitarity wann_check_unitarity proc~wann_main_gamma->proc~wann_check_unitarity proc~wann_omega_gamma wann_omega_gamma proc~wann_main_gamma->proc~wann_omega_gamma proc~wann_phases wann_phases proc~wann_main_gamma->proc~wann_phases proc~wann_spread_copy wann_spread_copy proc~wann_main_gamma->proc~wann_spread_copy proc~internal_test_convergence->proc~set_error_alloc proc~internal_test_convergence->proc~set_error_dealloc 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 zgemm zgemm proc~utility_zgemm->zgemm proc~wann_check_unitarity->proc~io_stopwatch_start proc~wann_check_unitarity->proc~io_stopwatch_stop proc~set_error_fatal set_error_fatal proc~wann_check_unitarity->proc~set_error_fatal proc~wann_omega_gamma->proc~io_stopwatch_start proc~wann_omega_gamma->proc~io_stopwatch_stop proc~wann_omega_gamma->proc~set_error_alloc proc~wann_omega_gamma->proc~set_error_dealloc proc~wann_phases->proc~io_stopwatch_start proc~wann_phases->proc~io_stopwatch_stop interface~comms_allreduce comms_allreduce proc~wann_phases->interface~comms_allreduce proc~utility_inv3 utility_inv3 proc~wann_phases->proc~utility_inv3 proc~comms_allreduce_cmplx comms_allreduce_cmplx interface~comms_allreduce->proc~comms_allreduce_cmplx proc~comms_allreduce_real comms_allreduce_real interface~comms_allreduce->proc~comms_allreduce_real proc~set_error_fatal->proc~comms_sync_error proc~set_error_fatal->proc~set_base_error proc~comms_allreduce_cmplx->proc~comms_sync_error proc~comms_no_sync_allreduce_cmplx comms_no_sync_allreduce_cmplx proc~comms_allreduce_cmplx->proc~comms_no_sync_allreduce_cmplx proc~comms_allreduce_real->proc~comms_sync_error proc~comms_no_sync_allreduce_real comms_no_sync_allreduce_real proc~comms_allreduce_real->proc~comms_no_sync_allreduce_real

Called by

proc~~wann_main_gamma~~CalledByGraph proc~wann_main_gamma wann_main_gamma proc~w90_wannierise~2 w90_wannierise proc~w90_wannierise~2->proc~wann_main_gamma proc~w90_wannierise w90_wannierise proc~w90_wannierise->proc~w90_wannierise~2 program~wannier wannier program~wannier->proc~w90_wannierise~2

Source Code

  subroutine wann_main_gamma(kmesh_info, wann_control, omega, print_output, wannier_data, &
                             m_matrix, u_matrix, real_lattice, num_kpts, num_wann, stdout, timer, &
                             error, comm)
    !================================================!
    !
    ! Calculate the Unitary Rotations to give
    !            Maximally Localised Wannier Functions
    !                      Gamma version
    !================================================

    use w90_constants, only: dp, cmplx_1, cmplx_0
    use w90_io, only: io_time, io_stopwatch_start, io_stopwatch_stop
    use w90_wannier90_types, only: wann_control_type, wann_omega_type
    use w90_types, only: kmesh_info_type, print_output_type, &
                         wannier_data_type, timer_list_type
    use w90_wannier90_readwrite, only: w90_wannier90_readwrite_write_chkpt
    use w90_utility, only: utility_frac_to_cart, utility_zgemm
    use w90_comms, only: w90_comm_type, mpirank

    implicit none

    ! JJ this function is entirely serial
    ! note that the scaling may be inferior to the non-gamma case
    ! so this is not necessarily the quicker branch
    ! JJ surely numkpts==1 identically???

    ! arguments
    type(wannier_data_type), intent(inout) :: wannier_data
    type(w90_comm_type), intent(in) :: comm
    type(wann_control_type), intent(inout) :: wann_control
    type(wann_omega_type), intent(inout) :: omega
    type(print_output_type), intent(in) :: print_output
    type(kmesh_info_type), intent(in) :: kmesh_info
    type(timer_list_type), intent(inout) :: timer
    type(w90_error_type), allocatable, intent(out) :: error

    integer, intent(in) :: stdout
    integer, intent(in) :: num_wann
    integer, intent(in) :: num_kpts

    real(kind=dp), intent(in) :: real_lattice(3, 3)

    complex(kind=dp), intent(inout) :: u_matrix(:, :, :)
    complex(kind=dp), intent(inout) :: m_matrix(:, :, :, :)

    ! local variables
    type(localisation_vars_type) :: old_spread
    type(localisation_vars_type) :: wann_spread

    integer :: counts(0:1)
    integer :: global_k(1)
    real(kind=dp), allocatable :: rnkb(:, :, :)
    real(kind=dp), allocatable :: ln_tmp(:, :, :)
    logical :: first_pass

    ! guiding centres
    real(kind=dp), allocatable :: rguide(:, :)
    integer :: irguide

    ! local arrays used and passed in subroutines
    real(kind=dp), allocatable :: m_w(:, :, :)
    complex(kind=dp), allocatable :: csheet(:, :, :)
    real(kind=dp), allocatable :: sheet(:, :, :)
    real(kind=dp), allocatable :: rave(:, :), r2ave(:), rave2(:)

    !local arrays not passed into subroutines
    complex(kind=dp), allocatable  :: u0(:, :, :)
    complex(kind=dp), allocatable  :: uc_rot(:, :)
    real(kind=dp), allocatable  :: ur_rot(:, :)
    complex(kind=dp), allocatable  :: cz(:, :)

    real(kind=dp) :: sqwb
    integer :: i, n, nn, iter, ind, ierr, iw
    integer :: tnntot
    logical :: lprint, ldump
    real(kind=dp), allocatable :: history(:)
    logical :: lconverged, lrandom, lfirst
    real(kind=dp) :: save_spread
    integer :: conv_count, noise_count

    if (mpirank(comm) > 0) then
      ! this cannot happen under ordinary circumstances
      call set_error_alloc(error, &
                           'wann_main_gamma called by non-root rank (but the algorithm is serial)', comm)
      return
    end if

    if (print_output%timing_level > 0) call io_stopwatch_start('wann: main_gamma', timer)

    first_pass = .true.

    allocate (history(wann_control%conv_window), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error allocating history in wann_main_gamma', comm)
      return
    end if
    allocate (rnkb(num_wann, kmesh_info%nntot, num_kpts), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating rnkb in wann_main_gamma', comm)
      return
    end if
    allocate (ln_tmp(num_wann, kmesh_info%nntot, num_kpts), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating ln_tmp in wann_main_gamma', comm)
      return
    end if

    rnkb = 0.0_dp
    tnntot = 2*kmesh_info%nntot

    allocate (m_w(num_wann, num_wann, tnntot), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating m_w in wann_main_gamma', comm)
      return
    end if
    allocate (csheet(num_wann, kmesh_info%nntot, num_kpts), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating csheet in wann_main_gamma', comm)
      return
    end if
    allocate (sheet(num_wann, kmesh_info%nntot, num_kpts), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating sheet in wann_main_gamma', comm)
      return
    end if
    allocate (rave(3, num_wann), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating rave in wann_main_gamma', comm)
      return
    end if
    allocate (r2ave(num_wann), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating r2ave in wann_main_gamma', comm)
      return
    end if
    allocate (rave2(num_wann), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating rave2 in wann_main_gamma', comm)
      return
    end if
    allocate (rguide(3, num_wann), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating rguide in wann_main_gamma', comm)
      return
    end if

    csheet = cmplx_1
    sheet = 0.0_dp; rave = 0.0_dp; r2ave = 0.0_dp; rave2 = 0.0_dp; rguide = 0.0_dp

    allocate (u0(num_wann, num_wann, num_kpts), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating u0 in wann_main_gamma', comm)
      return
    end if
    allocate (uc_rot(num_wann, num_wann), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating uc_rot in wann_main_gamma', comm)
      return
    end if
    allocate (ur_rot(num_wann, num_wann), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating ur_rot in wann_main_gamma', comm)
      return
    end if
    allocate (cz(num_wann, num_wann), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error in allocating cz in wann_main_gamma', comm)
      return
    end if

    cz = cmplx_0

    ! Set up the MPI arrays for a serial run.
    counts(0) = 1; global_k(1) = 1

    ! store original U before rotating
!~    ! phase factor ph_g is applied to u_matrix
!~    ! NB: ph_g is applied to u_matrix_opt if (have_disentangled)
!~    if (have_disentangled) then
!~       u0=u_matrix
!~    else
!~       do iw=1,num_wann
!~          u0(iw,:,:)= conjg(ph_g(iw))*u_matrix(iw,:,:)
!~       end do
!~    endif
    u0 = u_matrix

    ! guiding centres are not neede for orthorhombic systems
    if (kmesh_info%nntot .eq. 3) wann_control%guiding_centres%enable = .false.

    if (wann_control%guiding_centres%enable) then
      do n = 1, num_wann
        call utility_frac_to_cart(wann_control%guiding_centres%centres(:, n), rguide(:, n), &
                                  real_lattice)
      end do
    end if

    write (stdout, *)
    write (stdout, '(1x,a)') '*------------------------------- WANNIERISE ---------------------------------*'
    write (stdout, '(1x,a)') '+--------------------------------------------------------------------+<-- CONV'
    if (trim(print_output%length_unit) == 'Ang') then
      write (stdout, '(1x,a)') '| Iter  Delta Spread     RMS Gradient      Spread (Ang^2)      Time  |<-- CONV'
    else
      write (stdout, '(1x,a)') '| Iter  Delta Spread     RMS Gradient      Spread (Bohr^2)     Time  |<-- CONV'
    end if
    write (stdout, '(1x,a)') '+--------------------------------------------------------------------+<-- CONV'
    write (stdout, *)

    irguide = 0
    if (wann_control%guiding_centres%enable .and. (wann_control%guiding_centres%num_no_guide_iter .le. 0)) then
      call wann_phases(csheet, sheet, rguide, irguide, num_wann, kmesh_info, num_kpts, &
                       wann_control%use_ss_functional, m_matrix, print_output%timing_level, &
                       print_output%iprint, timer, num_kpts, global_k, error, comm) ! no plellisation so num_kpts_local = num_kpts
      if (allocated(error)) return
      irguide = 1
    end if

    ! weight m_matrix first to reduce number of operations
    ! m_w : weighted real matrix
    do nn = 1, kmesh_info%nntot
      sqwb = sqrt(kmesh_info%wb(nn))
      m_w(:, :, 2*nn - 1) = sqwb*real(m_matrix(1:num_wann, 1:num_wann, nn, 1), dp)
      m_w(:, :, 2*nn) = sqwb*aimag(m_matrix(1:num_wann, 1:num_wann, nn, 1))
    end do

    ! calculate initial centers and spread
    call wann_omega_gamma(m_w, csheet, sheet, rave, r2ave, rave2, wann_spread, num_wann, &
                          kmesh_info%nntot, kmesh_info%wbtot, kmesh_info%wb, kmesh_info%bk, &
                          omega%invariant, ln_tmp, first_pass, &
                          print_output%timing_level, timer, error, comm)
    if (allocated(error)) return

    ! public variables
    omega%total = wann_spread%om_tot
    omega%invariant = wann_spread%om_i
    omega%tilde = wann_spread%om_d + wann_spread%om_od

    ! Public array of Wannier centres and spreads
    wannier_data%centres = rave
    wannier_data%spreads = r2ave - rave2

    iter = 0
    old_spread%om_tot = 0.0_dp

    ! print initial state
    write (stdout, '(1x,a78)') repeat('-', 78)
    write (stdout, '(1x,a)') 'Initial State'
    do iw = 1, num_wann
      write (stdout, 1000) iw, (rave(ind, iw)*print_output%lenconfac, ind=1, 3), &
        (r2ave(iw) - rave2(iw))*print_output%lenconfac**2
    end do
    write (stdout, 1001) (sum(rave(ind, :))*print_output%lenconfac, ind=1, 3), (sum(r2ave) - sum(rave2))*print_output%lenconfac**2
    write (stdout, *)
    write (stdout, '(1x,i6,2x,E12.3,19x,F18.10,3x,F8.2,2x,a)') &
      iter, (wann_spread%om_tot - old_spread%om_tot)*print_output%lenconfac**2, &
      wann_spread%om_tot*print_output%lenconfac**2, io_time(), '<-- CONV'
    write (stdout, '(8x,a,F15.7,a,F15.7,a,F15.7,a)') &
      'O_D=', wann_spread%om_d*print_output%lenconfac**2, ' O_OD=', wann_spread%om_od*print_output%lenconfac**2, &
      ' O_TOT=', wann_spread%om_tot*print_output%lenconfac**2, ' <-- SPRD'
    write (stdout, '(1x,a78)') repeat('-', 78)

    lconverged = .false.

    ! initialize ur_rot
    ur_rot = 0.0_dp
    do i = 1, num_wann
      ur_rot(i, i) = 1.0_dp
    end do

    ! main iteration loop
    do iter = 1, wann_control%num_iter

      lprint = .false.
      if ((mod(iter, wann_control%num_print_cycles) .eq. 0) .or. (iter .eq. 1) &
          .or. (iter .eq. wann_control%num_iter)) lprint = .true.

      ldump = .false.
      if ((wann_control%num_dump_cycles .gt. 0) .and. &
          (mod(iter, wann_control%num_dump_cycles) .eq. 0)) ldump = .true.

      if (lprint .and. print_output%iprint > 0) write (stdout, '(1x,a,i6)') 'Cycle: ', iter

      if (wann_control%guiding_centres%enable .and. &
          (iter .gt. wann_control%guiding_centres%num_no_guide_iter) &
          .and. (mod(iter, wann_control%guiding_centres%num_guide_cycles) .eq. 0)) then
        call wann_phases(csheet, sheet, rguide, irguide, num_wann, kmesh_info, num_kpts, &
                         wann_control%use_ss_functional, m_matrix, print_output%timing_level, &
                         print_output%iprint, timer, num_kpts, global_k, error, comm, m_w) ! num_kpts_loc == num_kpts here
        if (allocated(error)) return
        irguide = 1
      end if

      call internal_new_u_and_m_gamma(m_w, ur_rot, tnntot, num_wann, print_output%timing_level, &
                                      timer)

      call wann_spread_copy(wann_spread, old_spread)

      ! calculate the new centers and spread
      call wann_omega_gamma(m_w, csheet, sheet, rave, r2ave, rave2, wann_spread, num_wann, &
                            kmesh_info%nntot, kmesh_info%wbtot, kmesh_info%wb, kmesh_info%bk, &
                            omega%invariant, ln_tmp, first_pass, print_output%timing_level, &
                            timer, error, comm)
      if (allocated(error)) return

      ! print the new centers and spreads
      if (lprint) then
        do iw = 1, num_wann
          write (stdout, 1000) iw, (rave(ind, iw)*print_output%lenconfac, ind=1, 3), &
            (r2ave(iw) - rave2(iw))*print_output%lenconfac**2
        end do
        write (stdout, 1001) (sum(rave(ind, :))*print_output%lenconfac, ind=1, 3), &
          (sum(r2ave) - sum(rave2))*print_output%lenconfac**2
        write (stdout, *)
        write (stdout, '(1x,i6,2x,E12.3,19x,F18.10,3x,F8.2,2x,a)') &
          iter, (wann_spread%om_tot - old_spread%om_tot)*print_output%lenconfac**2, &
          wann_spread%om_tot*print_output%lenconfac**2, io_time(), '<-- CONV'
        write (stdout, '(8x,a,F15.7,a,F15.7,a,F15.7,a)') &
          'O_D=', wann_spread%om_d*print_output%lenconfac**2, &
          ' O_OD=', wann_spread%om_od*print_output%lenconfac**2, &
          ' O_TOT=', wann_spread%om_tot*print_output%lenconfac**2, ' <-- SPRD'
        write (stdout, '(1x,a,E15.7,a,E15.7,a,E15.7,a)') &
          'Delta: O_D=', (wann_spread%om_d - old_spread%om_d)*print_output%lenconfac**2, &
          ' O_OD=', (wann_spread%om_od - old_spread%om_od)*print_output%lenconfac**2, &
          ' O_TOT=', (wann_spread%om_tot - old_spread%om_tot)*print_output%lenconfac**2, ' <-- DLTA'
        write (stdout, '(1x,a78)') repeat('-', 78)
      end if

      ! Public array of Wannier centres and spreads
      wannier_data%centres = rave
      wannier_data%spreads = r2ave - rave2

      ! Public variables
      omega%total = wann_spread%om_tot
      omega%tilde = wann_spread%om_d + wann_spread%om_od

! (Jerome Jackson) Removing checkpoint from WF optimisation loop because benefit is limited
!      if (ldump) then
!        uc_rot(:, :) = cmplx(ur_rot(:, :), 0.0_dp, dp)
!        call utility_zgemm(u_matrix, u0, 'N', uc_rot, 'N', num_wann)
!        call w90_wannier90_readwrite_write_chkpt('postdis', exclude_bands, wannier_data, &
!                                                 kmesh_info, kpt_latt, num_kpts, dis_manifold, &
!                                                 num_bands, num_wann, u_matrix, u_matrix_opt, &
!                                                 m_matrix, mp_grid, real_lattice, omega%invariant, &
!                                                 have_disentangled, stdout, seedname)
!      endif

      if (wann_control%conv_window .gt. 1) then
        call internal_test_convergence(old_spread, wann_spread, history, save_spread, iter, &
                                       conv_count, noise_count, lconverged, lrandom, lfirst, &
                                       wann_control, error, comm)
        if (allocated(error)) return
      end if

      if (lconverged) then
        write (stdout, '(/13x,a,es10.3,a,i2,a)') &
          '<<<     Delta <', wann_control%conv_tol, &
          '  over ', wann_control%conv_window, ' iterations     >>>'
        write (stdout, '(13x,a/)') '<<< Wannierisation convergence criteria satisfied >>>'
        exit
      end if

    end do
    ! end of the minimization loop

    ! update M
    do nn = 1, kmesh_info%nntot
      sqwb = 1.0_dp/sqrt(kmesh_info%wb(nn))
      m_matrix(1:num_wann, 1:num_wann, nn, 1) = sqwb*cmplx(m_w(:, :, 2*nn - 1), m_w(:, :, 2*nn), dp)
    end do

    ! update U
    uc_rot(:, :) = cmplx(ur_rot(:, :), 0.0_dp, dp)
    call utility_zgemm(u_matrix, u0, 'N', uc_rot, 'N', num_wann)

    write (stdout, '(1x,a)') 'Final State'
    do iw = 1, num_wann
      write (stdout, 1000) iw, (rave(ind, iw)*print_output%lenconfac, ind=1, 3), &
        (r2ave(iw) - rave2(iw))*print_output%lenconfac**2
    end do
    write (stdout, 1001) (sum(rave(ind, :))*print_output%lenconfac, ind=1, 3), &
      (sum(r2ave) - sum(rave2))*print_output%lenconfac**2
    write (stdout, *)
    write (stdout, '(3x,a21,a,f15.9)') '     Spreads ('//trim(print_output%length_unit)//'^2)', &
      '       Omega I      = ', wann_spread%om_i*print_output%lenconfac**2
    write (stdout, '(3x,a,f15.9)') '     ================       Omega D      = ', &
      wann_spread%om_d*print_output%lenconfac**2
    write (stdout, '(3x,a,f15.9)') '                            Omega OD     = ', &
      wann_spread%om_od*print_output%lenconfac**2
    write (stdout, '(3x,a21,a,f15.9)') 'Final Spread ('//trim(print_output%length_unit)//'^2)', &
      '       Omega Total  = ', wann_spread%om_tot*print_output%lenconfac**2
    write (stdout, '(1x,a78)') repeat('-', 78)

    if (wann_control%guiding_centres%enable) then
      call wann_phases(csheet, sheet, rguide, irguide, num_wann, kmesh_info, num_kpts, &
                       wann_control%use_ss_functional, m_matrix, print_output%timing_level, &
                       print_output%iprint, timer, num_kpts, global_k, error, comm) ! num_kpts_loc == num_kpts here
      if (allocated(error)) return
    end if

    ! unitarity is checked
    call wann_check_unitarity(num_kpts, num_wann, u_matrix, print_output%timing_level, &
                              print_output%iprint, stdout, timer, error, comm)
    if (allocated(error)) return

    ! deallocate sub vars not passed into other subs
    deallocate (cz, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating cz in wann_main_gamma', comm)
      return
    end if
    deallocate (ur_rot, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating ur_rot in wann_main_gamma', comm)
      return
    end if
    deallocate (uc_rot, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating uc_rot in wann_main_gamma', comm)
      return
    end if
    deallocate (u0, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating u0 in wann_main_gamma', comm)
      return
    end if

    ! deallocate sub vars passed into other subs
    deallocate (rguide, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating rguide in wann_main_gamma', comm)
      return
    end if
    deallocate (rave2, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating rave2 in wann_main_gamma', comm)
      return
    end if
    deallocate (rave, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating rave in wann_main_gamma', comm)
      return
    end if
    deallocate (sheet, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating sheet in wann_main_gamma', comm)
      return
    end if
    deallocate (csheet, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating csheet in wann_main_gamma', comm)
      return
    end if
    deallocate (m_w, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating m_w in wann_main_gamma', comm)
      return
    end if

    ! deallocate module data
    deallocate (ln_tmp, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error in deallocating ln_tmp in wann_main_gamma', comm)
      return
    end if
    deallocate (history, stat=ierr)
    if (ierr /= 0) then
      call set_error_dealloc(error, 'Error deallocating history in wann_main_gamma', comm)
      return
    end if

    if (print_output%timing_level > 0) call io_stopwatch_stop('wann: main_gamma', timer)

    return

1000 format(2x, 'WF centre and spread', i5, 2x, '(', f10.6, ',', f10.6, ',', f10.6, ' )', f15.8)
1001 format(2x, 'Sum of centres and spreads', 1x, '(', f10.6, ',', f10.6, ',', f10.6, ' )', f15.8)

  contains

    !================================================!
    subroutine internal_new_u_and_m_gamma(m_w, ur_rot, tnntot, num_wann, timing_level, timer)
      !================================================!

      use w90_constants, only: pi, eps10
      use w90_io, only: io_stopwatch_start, io_stopwatch_stop
      use w90_types, only: timer_list_type

      implicit none

      ! arguments
      real(kind=dp), intent(inout) :: m_w(:, :, :)
      real(kind=dp), intent(inout)  :: ur_rot(:, :)
      integer, intent(in) :: tnntot
      integer, intent(in) :: num_wann
      integer, intent(in) :: timing_level
      type(timer_list_type), intent(inout) :: timer

      ! local variables
      real(kind=dp) :: theta, twotheta
      real(kind=dp) :: a11, a12, a21, a22
      real(kind=dp) :: cc, ss, rtmp1, rtmp2
      real(kind=dp), parameter :: pifour = 0.25_dp*pi
      integer       :: nn, nw1, nw2, nw3

      if (timing_level > 1) call io_stopwatch_start('wann: main_gamma: new_u_and_m_gamma', timer)

      loop_nw1: do nw1 = 1, num_wann
      loop_nw2: do nw2 = nw1 + 1, num_wann

        a11 = 0.0_dp; a12 = 0.0_dp; a22 = 0.0_dp
        do nn = 1, tnntot
          a11 = a11 + (m_w(nw1, nw1, nn) - m_w(nw2, nw2, nn))**2
          a12 = a12 + m_w(nw1, nw2, nn)*(m_w(nw1, nw1, nn) - m_w(nw2, nw2, nn))
          a22 = a22 + m_w(nw1, nw2, nn)**2
        end do
        a12 = 2.0_dp*a12
        a22 = 4.0_dp*a22
        a21 = a22 - a11
        if (abs(a12) .gt. eps10) then
          twotheta = 0.5_dp*(a21 + sqrt(a21**2 + 4.0_dp*a12**2))/a12
          theta = 0.5_dp*atan(twotheta)
        elseif (a21 .lt. eps10) then
          theta = 0.0_dp
        else
          theta = pifour
        end if
        cc = cos(theta)
        ss = sin(theta)

        ! update M
        do nn = 1, tnntot
          ! MR
          do nw3 = 1, num_wann
            rtmp1 = m_w(nw3, nw1, nn)*cc + m_w(nw3, nw2, nn)*ss
            rtmp2 = -m_w(nw3, nw1, nn)*ss + m_w(nw3, nw2, nn)*cc
            m_w(nw3, nw1, nn) = rtmp1
            m_w(nw3, nw2, nn) = rtmp2
          end do
          ! R^+ M R
          do nw3 = 1, num_wann
            rtmp1 = cc*m_w(nw1, nw3, nn) + ss*m_w(nw2, nw3, nn)
            rtmp2 = -ss*m_w(nw1, nw3, nn) + cc*m_w(nw2, nw3, nn)
            m_w(nw1, nw3, nn) = rtmp1
            m_w(nw2, nw3, nn) = rtmp2
          end do
        end do
        ! update U : U=UR
        do nw3 = 1, num_wann
          rtmp1 = ur_rot(nw3, nw1)*cc + ur_rot(nw3, nw2)*ss
          rtmp2 = -ur_rot(nw3, nw1)*ss + ur_rot(nw3, nw2)*cc
          ur_rot(nw3, nw1) = rtmp1
          ur_rot(nw3, nw2) = rtmp2
        end do
      end do loop_nw2
      end do loop_nw1

      if (timing_level > 1) call io_stopwatch_stop('wann: main_gamma: new_u_and_m_gamma', timer)

      return

    end subroutine internal_new_u_and_m_gamma

  end subroutine wann_main_gamma