dis_windows_proj Subroutine

public subroutine dis_windows_proj(dis_manifold, eigval_opt, a_matrix, m_matrix_orig_local, indxfroz, indxnfroz, ndimfroz, nfirstwin, iprint, nnlist, nntot, num_bands, num_kpts, num_wann, timing_level, lfrozen, linner, on_root, stdout, dist_k, global_k, my_node_id, timer, error, comm)

Uses

  • proc~~dis_windows_proj~~UsesGraph proc~dis_windows_proj dis_windows_proj module~w90_comms w90_comms proc~dis_windows_proj->module~w90_comms module~w90_constants w90_constants proc~dis_windows_proj->module~w90_constants module~w90_error w90_error proc~dis_windows_proj->module~w90_error module~w90_io w90_io proc~dis_windows_proj->module~w90_io module~w90_types w90_types proc~dis_windows_proj->module~w90_types module~w90_wannier90_types w90_wannier90_types proc~dis_windows_proj->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_error->module~w90_comms 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

This subroutine selects the states for disentanglement and frozen based on projectability. States with projectability < dis_proj_min are discarded, states with projectability >= dis_proj_min are included in the disentanglement, states with projectability

= dis_proj_max are frozen.

Arguments

Type IntentOptional Attributes Name
type(dis_manifold_type), intent(inout) :: dis_manifold
real(kind=dp), intent(inout) :: eigval_opt(:,:)
complex(kind=dp), intent(inout) :: a_matrix(:,:,:)
complex(kind=dp), intent(inout) :: m_matrix_orig_local(:,:,:,:)
integer, intent(inout) :: indxfroz(:,:)
integer, intent(inout) :: indxnfroz(:,:)
integer, intent(inout) :: ndimfroz(:)
integer, intent(inout) :: nfirstwin(:)
integer, intent(in) :: iprint
integer, intent(in) :: nnlist(:,:)
integer, intent(in) :: nntot
integer, intent(in) :: num_bands
integer, intent(in) :: num_kpts
integer, intent(in) :: num_wann
integer, intent(in) :: timing_level
logical, intent(inout) :: lfrozen(:,:)
logical, intent(inout) :: linner
logical, intent(in) :: on_root
integer, intent(in) :: stdout
integer, intent(in) :: dist_k(:)

assignment of k-points to MPI processes and global/local k index map

integer, intent(in) :: global_k(:)

assignment of k-points to MPI processes and global/local k index map

integer, intent(in) :: my_node_id
type(timer_list_type), intent(inout) :: timer
type(w90_error_type), intent(out), allocatable :: error
type(w90_comm_type), intent(in) :: comm

Calls

proc~~dis_windows_proj~~CallsGraph proc~dis_windows_proj dis_windows_proj 10 10 proc~dis_windows_proj->10 proc~dis_otsu_thresholds dis_otsu_thresholds proc~dis_windows_proj->proc~dis_otsu_thresholds proc~io_stopwatch_start io_stopwatch_start proc~dis_windows_proj->proc~io_stopwatch_start proc~io_stopwatch_stop io_stopwatch_stop proc~dis_windows_proj->proc~io_stopwatch_stop proc~set_error_alloc set_error_alloc proc~dis_windows_proj->proc~set_error_alloc proc~set_error_fatal set_error_fatal proc~dis_windows_proj->proc~set_error_fatal 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_fatal->proc~comms_sync_error proc~set_error_fatal->proc~set_base_error

Called by

proc~~dis_windows_proj~~CalledByGraph proc~dis_windows_proj dis_windows_proj proc~dis_main dis_main proc~dis_main->proc~dis_windows_proj proc~w90_disentangle~2 w90_disentangle proc~w90_disentangle~2->proc~dis_main proc~w90_disentangle w90_disentangle proc~w90_disentangle->proc~w90_disentangle~2 program~wannier wannier program~wannier->proc~w90_disentangle~2

Source Code

  subroutine dis_windows_proj(dis_manifold, eigval_opt, a_matrix, m_matrix_orig_local, &
                              indxfroz, indxnfroz, ndimfroz, nfirstwin, iprint, nnlist, &
                              nntot, num_bands, num_kpts, num_wann, timing_level, lfrozen, &
                              linner, on_root, stdout, dist_k, global_k, my_node_id, timer, error, comm)
    !==================================================================!
    !                                                                  !
    !! This subroutine selects the states for disentanglement and frozen
    !! based on projectability. States with projectability < dis_proj_min
    !! are discarded, states with projectability >= dis_proj_min are
    !! included in the disentanglement, states with projectability
    !! >= dis_proj_max are frozen.
    !                                                                  !
    !==================================================================!

    ! OUTPUT:
    !     ndimwin(nkp)   number of bands inside outer window at nkp-th k point
    !     ndimfroz(nkp)  number of frozen bands at nkp-th k point
    !     lfrozen(i,nkp) true if the i-th band inside outer window is frozen
    !     linner         true if there is an inner window
    !     indxfroz(i,nkp) outer-window band index for the i-th frozen state
    !                     (equals 1 if it is the bottom of outer window.
    !                      The indexes are reordered after excluding
    !                      low-projectability states.)
    !     indxnfroz(i,nkp) outer-window band index for the i-th non-frozen s
    !                     (equals 1 if it is the bottom of outer window.
    !                      The indexes are reordered after excluding
    !                      low-projectability states.)
    !     nfirstwin(nkp) index of lowest band inside outer window at nkp-th
    ! MODIFIED:
    !     eigval_opt(nb,nkp) At input it contains a large set of eigenvalues. At
    !                    it is slimmed down to contain only those inside the
    !                    energy window, stored in nb=1,...,ndimwin(nkp)
    use w90_comms, only: w90_comm_type
    use w90_constants, only: dp, cmplx_0
    use w90_error
    use w90_io, only: io_stopwatch_start, io_stopwatch_stop
    use w90_types, only: dis_manifold_type, timer_list_type
    use w90_wannier90_types, only: dis_control_type

    implicit none

    ! arguments
    type(dis_manifold_type), intent(inout) :: dis_manifold ! ndimwin alone is modified
    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) :: dist_k(:), global_k(:)
    !! assignment of k-points to MPI processes and global/local k index map
    integer, intent(in) :: iprint, timing_level
    integer, intent(in) :: stdout
    integer, intent(in) :: nntot, nnlist(:, :) ! (num_kpts, nntot)
    integer, intent(in) :: num_bands, num_kpts, num_wann
    integer, intent(in) :: my_node_id
    integer, intent(inout) :: ndimfroz(:)
    integer, intent(inout) :: indxfroz(:, :)
    integer, intent(inout) :: indxnfroz(:, :)
    integer, intent(inout) :: nfirstwin(:)

    complex(kind=dp), intent(inout) :: a_matrix(:, :, :)
    complex(kind=dp), intent(inout) :: m_matrix_orig_local(:, :, :, :)
    real(kind=dp), intent(inout) :: eigval_opt(:, :)

    logical, intent(in) :: on_root
    logical, intent(inout) :: linner
    logical, intent(inout) :: lfrozen(:, :)

    ! local variables
    integer :: indxkeep(num_bands, num_kpts)
    !     indxkeep(i,nkp) original outer-window band index for the i-th state
    !                     included in disentanglement, i.e. frozen + non-frozen state.
    !                     This is used to allow excluding states in the middle of
    !                     orignal outter window, and to generate a new outter window.
    !                     (equals 1 if it is the bottom of outer window)

    integer :: nkp, nn, nkp2, nkp_global
    integer :: i, j, k, l
    real(kind=dp) :: projs(num_bands)
    integer :: invindxkeep(num_bands)
    real(kind=dp), allocatable :: pooled(:), otsu_thr(:)
    real(kind=dp) :: pval
    integer :: ip, ierr, nclasses_eff
    logical :: degenerate

    if (timing_level > 1 .and. on_root) call io_stopwatch_start('dis: windows_proj', timer)

    linner = .false.

    ! Automatic projectability thresholds via multi-Otsu (dis_proj_auto). The
    ! a_matrix is full on every rank, so pooling over all bands and k-points is
    ! rank-uniform and needs no MPI communication.
    if (dis_manifold%proj_auto) then
      allocate (pooled(num_bands*num_kpts), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating pooled in dis_windows_proj', comm)
        return
      end if
      ip = 0
      do nkp = 1, num_kpts
        do i = 1, num_bands
          pval = 0.0_dp
          do j = 1, num_wann
            pval = pval + real(a_matrix(i, j, nkp), dp)**2 + aimag(a_matrix(i, j, nkp))**2
          end do
          if (pval < 0.0_dp) pval = 0.0_dp
          if (pval > 1.0_dp) pval = 1.0_dp
          ip = ip + 1
          pooled(ip) = pval
        end do
      end do

      allocate (otsu_thr(dis_manifold%proj_auto_num_classes - 1), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating otsu_thr in dis_windows_proj', comm)
        return
      end if
      call dis_otsu_thresholds(pooled, otsu_lower_bound, otsu_upper_bound, otsu_nbins, &
                               dis_manifold%proj_auto_num_classes, otsu_thr, nclasses_eff, degenerate)
      deallocate (pooled)

      if (degenerate) then
        deallocate (otsu_thr)
        ! message must fit the 128-char w90_error_type buffer
        call set_error_fatal(error, 'Error: dis_proj_auto: fewer than 3 distinct projectability '// &
                             'clusters; set dis_proj_min/dis_proj_max manually', comm)
        return
      end if
      ! A class needs its own populated bin, so more classes than clusters is
      ! not resolvable; reduce and tell the user.
      if (nclasses_eff < dis_manifold%proj_auto_num_classes .and. on_root) then
        write (stdout, '(1x,a,i0,a,i0,a,i0)') &
          ' dis_proj_auto: only ', nclasses_eff, ' distinct projectability clusters; reducing classes from ', &
          dis_manifold%proj_auto_num_classes, ' to ', nclasses_eff
      end if
      dis_manifold%proj_min = otsu_thr(1)
      dis_manifold%proj_max = otsu_thr(nclasses_eff - 1)
      deallocate (otsu_thr)
    end if

    if (on_root) write (stdout, '(1x,a)') &
      '+----------------------------------------------------------------------------+'
    if (on_root) write (stdout, '(1x,a)') &
      '|                              Energy  Windows                               |'
    if (on_root) write (stdout, '(1x,a)') &
      '|                              ---------------                               |'
    if (on_root) write (stdout, '(1x,a,f10.5,a,f10.5,a)') &
      '|                   Outer: ', dis_manifold%win_min, '  to ', dis_manifold%win_max, &
      '  (eV)                   |'
    if (dis_manifold%frozen_states) then
      if (on_root) write (stdout, '(1x,a,f10.5,a,f10.5,a)') &
        '|                   Inner: ', dis_manifold%froz_min, '  to ', dis_manifold%froz_max, &
        '  (eV)                   |'
    else
      if (on_root) write (stdout, '(1x,a)') &
        '|                   No frozen states were specified                          |'
    end if
    if (on_root) write (stdout, '(1x,a)') &
      '|----------------------------------------------------------------------------|'
    if (on_root) write (stdout, '(1x,a)') &
      '|                          Projectability  Windows                           |'
    if (on_root) write (stdout, '(1x,a)') &
      '|                          -----------------------                           |'
    if (dis_manifold%proj_auto) then
      if (on_root) write (stdout, '(1x,a,i2,a)') &
        '|         Thresholds determined automatically (multi-Otsu, ', &
        nclasses_eff, ' classes)       |'
    end if
    if (on_root) write (stdout, '(1x,a,f10.5,a,f10.5,a)') &
      '|               Discarded: ', 0.0_dp, '  to ', dis_manifold%proj_min, &
      '                         |'
    if (on_root) write (stdout, '(1x,a,f10.5,a,f10.5,a)') &
      '|            Disentangled: ', dis_manifold%proj_min, '  to ', 1.0_dp, &
      '                         |'
    if (dis_manifold%frozen_proj) then
      if (on_root) write (stdout, '(1x,a,f10.5,a,f10.5,a)') &
        '|                  Frozen: ', dis_manifold%proj_max, '  to ', 1.0_dp, &
        '                         |'
    else
      if (on_root) write (stdout, '(1x,a)') &
        '|                   No frozen states were specified                          |'
    end if
    if (on_root) write (stdout, '(1x,a)') &
      '+----------------------------------------------------------------------------+'

    do nkp = 1, num_kpts
      ! Generate the projectability array
      projs = 0.0_dp
      do i = 1, num_bands
        do j = 1, num_wann
          projs(i) = projs(i) + real(a_matrix(i, j, nkp), dp)**2 + aimag(a_matrix(i, j, nkp))**2
        end do
        if ((projs(i) < 0.0_dp) .or. (projs(i) > 1.0_dp)) then
          if (on_root) write (stdout, *) ' Error at k-point: ', nkp, '  band: ', i
          if (on_root) write (stdout, 411) (eigval_opt(j, nkp), j=1, num_bands)
411       format('Bands (eV): ', 10(F10.5, 1X))
          if (on_root) write (stdout, 412) (projs(j), j=1, num_bands)
412       format('Projectability: ', 10(F10.5, 1X))
          call set_error_fatal(error, 'dis_windows_proj: projectability < 0.0 or > 1.0', comm)
          return
        end if
      end do

      ! Check which eigenvalues fall within the inner/outer windows
      !
      ! Inside this subroutine, I just use indxkeep which is more flexible that
      ! allows me to exclude states in the middle of the outer window; outside
      ! of this subroutine, since I have already slimmed down the a_matrix
      ! and m_matrix, so nfirstwin = 1 is fine.
      nfirstwin(nkp) = 1
      indxkeep(:, nkp) = 0
      indxfroz(:, nkp) = 0
      indxnfroz(:, nkp) = 0
      lfrozen(:, nkp) = .false.
      dis_manifold%lwindow(:, nkp) = .false.
      j = 0 ! counter for all keep states
      k = 0 ! counter for frozen states
      l = 0 ! counter for non-frozen states
      do i = 1, num_bands
        ! exclude states outside disentanglement energy window
        if ((eigval_opt(i, nkp) < dis_manifold%win_min) .or. &
            (eigval_opt(i, nkp) > dis_manifold%win_max)) cycle
        ! freeze high-proj states + states inside frozen energy window, i.e. their union
        if ((projs(i) >= dis_manifold%proj_max) .or. &
            (dis_manifold%frozen_states .and. ((eigval_opt(i, nkp) >= dis_manifold%froz_min) &
                                               .and. (eigval_opt(i, nkp) <= dis_manifold%froz_max)))) then
          j = j + 1
          ! Inside outer window, relative to bottom of outer window, however the bottom is 1
          indxkeep(j, nkp) = i
          k = k + 1
          indxfroz(k, nkp) = i
          lfrozen(j, nkp) = .true.
          ! Relative to the total num_bands
          dis_manifold%lwindow(i, nkp) = .true.
        else if ((projs(i) >= dis_manifold%proj_min) .and. (projs(i) < dis_manifold%proj_max)) then
          j = j + 1
          indxkeep(j, nkp) = i
          l = l + 1
          indxnfroz(l, nkp) = i
          ! Relative to the total num_bands
          dis_manifold%lwindow(i, nkp) = .true.
        end if
      end do
      dis_manifold%ndimwin(nkp) = j
      ndimfroz(nkp) = k

      if (j /= k + l) then
        if (on_root) write (stdout, *) ' ERROR AT K-POINT: ', nkp
        if (on_root) write (stdout, '(3(a,i5))') ' ndimwin: ', dis_manifold%ndimwin(nkp), &
          ' ndimfroz: ', ndimfroz(nkp), ' ndimnfroz: ', l
        call set_error_fatal(error, 'dis_windows_proj: (ndimfroz + ndimnfroz) /= ndimwin at this k-point', comm)
        return
      end if

      if (dis_manifold%ndimwin(nkp) == 0) then
        if (on_root) write (stdout, *) ' ERROR AT K-POINT: ', nkp
        if (on_root) write (stdout, *) ' dis_proj_min:     ', dis_manifold%proj_min
        if (on_root) write (stdout, *) ' EIGENVALUE projectability: [', &
          minval(projs), ', ', maxval(projs), ']'
        call set_error_fatal(error, 'dis_windows_proj: The outer energy window contains no eigenvalues' &
                             //', consider decreasing dis_proj_min/increasing dis_win_max?', comm)
        return
      end if

      if (dis_manifold%ndimwin(nkp) < num_wann) then
        if (on_root) write (stdout, '(1x,a17,i4,a8,i3,a9,i3)') 'ERROR AT K-POINT ', &
          nkp, '  ndimwin=', dis_manifold%ndimwin(nkp), '  num_wann=', num_wann
        if (on_root) write (stdout, '(a)') 'Bands (eV):'
        if (on_root) write (stdout, 411) (eigval_opt(j, nkp), j=1, num_bands)
        if (on_root) write (stdout, '(a)') 'Projectability:'
        if (on_root) write (stdout, 412) (projs(j), j=1, num_bands)
        call set_error_fatal(error, 'dis_windows_proj: Energy window contains fewer states than number of target WFs' &
                             //', consider decreasing dis_proj_min/increasing dis_win_max?', comm)
        return
      end if

      if (ndimfroz(nkp) > num_wann) then
        if (on_root) write (stdout, 413) nkp, ndimfroz(nkp), num_wann
413     format(' ERROR AT K-POINT ', i4, ' THERE ARE ', i2, &
               ' BANDS INSIDE THE INNER WINDOW AND ONLY', i2, &
               ' TARGET BANDS')
        if (on_root) write (stdout, 414) (eigval_opt(indxfroz(i, nkp), nkp), i=1, ndimfroz(nkp))
414     format('BANDS: (eV)', 10(F10.5, 1X))
        call set_error_fatal(error, 'dis_windows_proj: More states in the frozen window than target WFs', comm)
        return
      end if

      if (ndimfroz(nkp) > 0) linner = .true.
      ! DEBUG
      !         write(*,'(a,i4,a,i2,a,i2)') 'k point ',nkp,
      !     &    ' lowest band in outer win is # ',imin,
      !     &    '   # frozen states is ',ndimfroz(nkp)
      ! ENDDEBUG

      ! Slim down eigval vector at present k, i.e. remove low-projectability states
      do i = 1, dis_manifold%ndimwin(nkp)
        j = indxkeep(i, nkp)
        if (j == i) cycle
        eigval_opt(i, nkp) = eigval_opt(j, nkp)
      end do
      eigval_opt(dis_manifold%ndimwin(nkp) + 1:num_bands, nkp) = 0.0_dp
      ! slim down a_matrix
      if (dis_manifold%ndimwin(nkp) .ne. num_bands) then
        do j = 1, num_wann
          do i = 1, dis_manifold%ndimwin(nkp)
            a_matrix(i, j, nkp) = a_matrix(indxkeep(i, nkp), j, nkp)
          end do
          a_matrix(dis_manifold%ndimwin(nkp) + 1:num_bands, j, nkp) = cmplx_0
        end do
      end if
      ! No need to slim u_matrix_opt, it is calculated from a_matrix in dis_project().
      ! Reorder the indexes.
      ! Find the reverse mapping.
      invindxkeep = 0
      do i = 1, dis_manifold%ndimwin(nkp)
        invindxkeep(indxkeep(i, nkp)) = i
      end do
      ! Reorder the indexes, to remove low-projectability states (which are excluded
      ! from disentanglement) that are in the middle of high-projectability states
      ! (which are included in disentanglement). So now these indexes are for the
      ! slimmed matrices, instead of the original num_bands-sized matrices.
      do i = 1, ndimfroz(nkp)
        j = indxfroz(i, nkp)
        indxfroz(i, nkp) = invindxkeep(j)
      end do
      indxfroz((ndimfroz(nkp) + 1):num_bands, nkp) = 0
      do i = 1, dis_manifold%ndimwin(nkp) - ndimfroz(nkp)
        j = indxnfroz(i, nkp)
        indxnfroz(i, nkp) = invindxkeep(j)
      end do
      indxnfroz((dis_manifold%ndimwin(nkp) - ndimfroz(nkp) + 1):num_bands, nkp) = 0

    end do
    ! [k-point loop (nkp)]

    ! slim down m_matrix since some states in the middle might be removed due to
    ! low projectability. I remove them here so that I can use the local variable
    ! indxkeep, then I will skip the internal_slim_m step which is for removing
    ! states outside of energy outer window.
    !
    ! slim down m_matrix_orig_local
    ! this is done outside of previous do loop since we need indxkeep on nn kpoint nkp2
    do nkp = 1, count(dist_k(:) == my_node_id)
      nkp_global = global_k(nkp)

      do nn = 1, nntot
        nkp2 = nnlist(nkp_global, nn)
        do j = 1, dis_manifold%ndimwin(nkp2)
          do i = 1, dis_manifold%ndimwin(nkp_global)
            m_matrix_orig_local(i, j, nn, nkp) = m_matrix_orig_local( &
                                                 indxkeep(i, nkp_global), indxkeep(j, nkp2), nn, nkp)
          end do
        end do
        m_matrix_orig_local(dis_manifold%ndimwin(nkp_global) + 1:num_bands, &
                            dis_manifold%ndimwin(nkp2) + 1:num_bands, nn, nkp) = cmplx_0
      end do
    end do

    if (iprint > 1) then
      if (on_root) write (stdout, '(1x,a)') &
        '|                        K-points with Frozen States                         |'
      if (on_root) write (stdout, '(1x,a)') &
        '|                        ---------------------------                         |'
      i = 0
      do nkp = 1, num_kpts
        if (ndimfroz(nkp) .gt. 0) then
          i = i + 1
          if (i .eq. 1) then
            if (on_root) write (stdout, '(1x,a,i6)', advance='no') '|', nkp
          else if ((i .gt. 1) .and. (i .lt. 12)) then
            if (on_root) write (stdout, '(i6)', advance='no') nkp
          else if (i .eq. 12) then
            if (on_root) write (stdout, '(i6,a)') nkp, '    |'
            i = 0
          end if
        end if
      end do
      if (i .ne. 0) then
        do j = 1, 12 - i
          if (on_root) write (stdout, '(6x)', advance='no')
        end do
        if (on_root) write (stdout, '(a)') '    |'
      end if
      if (on_root) write (stdout, '(1x,a)') &
        '+----------------------------------------------------------------------------+'
    end if

    if (on_root) write (stdout, '(3x,a,i4)') 'Number of target bands to extract: ', num_wann
    if (iprint > 1) then
      if (on_root) write (stdout, '(1x,a)') &
        '+----------------------------------------------------------------------------+'
      if (on_root) write (stdout, '(1x,a)') &
        '|                                  Windows                                   |'
      if (on_root) write (stdout, '(1x,a)') &
        '|                                  -------                                   |'
      if (on_root) write (stdout, '(1x,a)') &
        '|               K-point      Ndimwin     Ndimfroz    Nfirstwin               |'
      if (on_root) write (stdout, '(1x,a)') &
        '|               ----------------------------------------------               |'
      do nkp = 1, num_kpts
        if (on_root) write (stdout, 415) nkp, dis_manifold%ndimwin(nkp), ndimfroz(nkp), nfirstwin(nkp)
      end do
415   format(1x, '|', 14x, i6, 7x, i6, 7x, i6, 6x, i6, 18x, '|')
      if (on_root) write (stdout, '(1x,a)') &
        '+----------------------------------------------------------------------------+'
    end if

    if (iprint > 2) then
      if (on_root) then
        write (stdout, '(1x,a)') &
          '+----------------------------------------------------------------------------+'
        write (stdout, '(1x,a)') &
          '|                         Kept bands at each K-point                         |'
        write (stdout, '(1x,a)') &
          '|               ----------------------------------------------               |'
        do nkp = 1, num_kpts
          write (stdout, '(1x,"|")', advance="no")
          do i = 1, dis_manifold%ndimwin(nkp)
            write (stdout, '(1x,i0)', advance="no") indxkeep(i, nkp)
          end do
          write (stdout, '(1x,"|")')
        end do
        write (stdout, '(1x,a)') &
          '+----------------------------------------------------------------------------+'
      end if
    end if

    if (iprint > 2) then
      if (on_root) then
        write (stdout, '(1x,a)') &
          '+----------------------------------------------------------------------------+'
        write (stdout, '(1x,a)') &
          '|                       Frozen bands at each K-point                         |'
        write (stdout, '(1x,a)') &
          '|               ----------------------------------------------               |'
        do nkp = 1, num_kpts
          write (stdout, '(1x,"|")', advance="no")
          do i = 1, ndimfroz(nkp)
            write (stdout, '(1x,i0)', advance="no") indxfroz(i, nkp)
          end do
          write (stdout, '(1x,"|")')
        end do
        write (stdout, '(1x,a)') &
          '+----------------------------------------------------------------------------+'
      end if
    end if

    if (timing_level > 1) call io_stopwatch_stop('dis: windows_proj', timer)

    return
  end subroutine dis_windows_proj