library_extra.F90 Source File


This file depends on

sourcefile~~library_extra.f90~~EfferentGraph sourcefile~library_extra.f90 library_extra.F90 sourcefile~comms.f90 comms.F90 sourcefile~library_extra.f90->sourcefile~comms.f90 sourcefile~constants.f90 constants.F90 sourcefile~library_extra.f90->sourcefile~constants.f90 sourcefile~error.f90 error.F90 sourcefile~library_extra.f90->sourcefile~error.f90 sourcefile~error_base.f90 error_base.F90 sourcefile~library_extra.f90->sourcefile~error_base.f90 sourcefile~io.f90 io.F90 sourcefile~library_extra.f90->sourcefile~io.f90 sourcefile~kmesh.f90 kmesh.F90 sourcefile~library_extra.f90->sourcefile~kmesh.f90 sourcefile~library_interface.f90 library_interface.F90 sourcefile~library_extra.f90->sourcefile~library_interface.f90 sourcefile~overlap.f90 overlap.F90 sourcefile~library_extra.f90->sourcefile~overlap.f90 sourcefile~readwrite.f90 readwrite.F90 sourcefile~library_extra.f90->sourcefile~readwrite.f90 sourcefile~wannier90_readwrite.f90 wannier90_readwrite.F90 sourcefile~library_extra.f90->sourcefile~wannier90_readwrite.f90 sourcefile~comms.f90->sourcefile~constants.f90 sourcefile~comms.f90->sourcefile~error_base.f90 sourcefile~error.f90->sourcefile~comms.f90 sourcefile~error.f90->sourcefile~error_base.f90 sourcefile~io.f90->sourcefile~comms.f90 sourcefile~io.f90->sourcefile~constants.f90 sourcefile~io.f90->sourcefile~error_base.f90 sourcefile~types.f90 types.F90 sourcefile~io.f90->sourcefile~types.f90 sourcefile~kmesh.f90->sourcefile~comms.f90 sourcefile~kmesh.f90->sourcefile~constants.f90 sourcefile~kmesh.f90->sourcefile~error.f90 sourcefile~kmesh.f90->sourcefile~io.f90 sourcefile~kmesh.f90->sourcefile~types.f90 sourcefile~utility.f90 utility.F90 sourcefile~kmesh.f90->sourcefile~utility.f90 sourcefile~library_interface.f90->sourcefile~comms.f90 sourcefile~library_interface.f90->sourcefile~constants.f90 sourcefile~library_interface.f90->sourcefile~error.f90 sourcefile~library_interface.f90->sourcefile~error_base.f90 sourcefile~library_interface.f90->sourcefile~io.f90 sourcefile~library_interface.f90->sourcefile~kmesh.f90 sourcefile~library_interface.f90->sourcefile~overlap.f90 sourcefile~library_interface.f90->sourcefile~readwrite.f90 sourcefile~library_interface.f90->sourcefile~wannier90_readwrite.f90 sourcefile~disentangle.f90 disentangle.F90 sourcefile~library_interface.f90->sourcefile~disentangle.f90 sourcefile~plot.f90 plot.F90 sourcefile~library_interface.f90->sourcefile~plot.f90 sourcefile~transport.f90 transport.F90 sourcefile~library_interface.f90->sourcefile~transport.f90 sourcefile~library_interface.f90->sourcefile~types.f90 sourcefile~wannier90_types.f90 wannier90_types.F90 sourcefile~library_interface.f90->sourcefile~wannier90_types.f90 sourcefile~wannierise.f90 wannierise.F90 sourcefile~library_interface.f90->sourcefile~wannierise.f90 sourcefile~overlap.f90->sourcefile~comms.f90 sourcefile~overlap.f90->sourcefile~constants.f90 sourcefile~overlap.f90->sourcefile~error.f90 sourcefile~overlap.f90->sourcefile~io.f90 sourcefile~sitesym.f90 sitesym.F90 sourcefile~overlap.f90->sourcefile~sitesym.f90 sourcefile~overlap.f90->sourcefile~types.f90 sourcefile~overlap.f90->sourcefile~utility.f90 sourcefile~overlap.f90->sourcefile~wannier90_types.f90 sourcefile~readwrite.f90->sourcefile~comms.f90 sourcefile~readwrite.f90->sourcefile~constants.f90 sourcefile~readwrite.f90->sourcefile~error.f90 sourcefile~readwrite.f90->sourcefile~io.f90 sourcefile~readwrite.f90->sourcefile~types.f90 sourcefile~readwrite.f90->sourcefile~utility.f90 sourcefile~wannier90_readwrite.f90->sourcefile~constants.f90 sourcefile~wannier90_readwrite.f90->sourcefile~error.f90 sourcefile~wannier90_readwrite.f90->sourcefile~io.f90 sourcefile~wannier90_readwrite.f90->sourcefile~readwrite.f90 sourcefile~wannier90_readwrite.f90->sourcefile~types.f90 sourcefile~wannier90_readwrite.f90->sourcefile~utility.f90 sourcefile~wannier90_readwrite.f90->sourcefile~wannier90_types.f90 sourcefile~disentangle.f90->sourcefile~comms.f90 sourcefile~disentangle.f90->sourcefile~constants.f90 sourcefile~disentangle.f90->sourcefile~error.f90 sourcefile~disentangle.f90->sourcefile~io.f90 sourcefile~disentangle.f90->sourcefile~sitesym.f90 sourcefile~disentangle.f90->sourcefile~types.f90 sourcefile~disentangle.f90->sourcefile~utility.f90 sourcefile~disentangle.f90->sourcefile~wannier90_types.f90 sourcefile~plot.f90->sourcefile~comms.f90 sourcefile~plot.f90->sourcefile~constants.f90 sourcefile~plot.f90->sourcefile~error.f90 sourcefile~plot.f90->sourcefile~io.f90 sourcefile~plot.f90->sourcefile~types.f90 sourcefile~plot.f90->sourcefile~utility.f90 sourcefile~plot.f90->sourcefile~wannier90_types.f90 sourcefile~hamiltonian.f90 hamiltonian.F90 sourcefile~plot.f90->sourcefile~hamiltonian.f90 sourcefile~ws_distance.f90 ws_distance.F90 sourcefile~plot.f90->sourcefile~ws_distance.f90 sourcefile~sitesym.f90->sourcefile~comms.f90 sourcefile~sitesym.f90->sourcefile~constants.f90 sourcefile~sitesym.f90->sourcefile~error.f90 sourcefile~sitesym.f90->sourcefile~utility.f90 sourcefile~sitesym.f90->sourcefile~wannier90_types.f90 sourcefile~transport.f90->sourcefile~comms.f90 sourcefile~transport.f90->sourcefile~constants.f90 sourcefile~transport.f90->sourcefile~error.f90 sourcefile~transport.f90->sourcefile~io.f90 sourcefile~transport.f90->sourcefile~types.f90 sourcefile~transport.f90->sourcefile~wannier90_types.f90 sourcefile~transport.f90->sourcefile~hamiltonian.f90 sourcefile~types.f90->sourcefile~constants.f90 sourcefile~utility.f90->sourcefile~comms.f90 sourcefile~utility.f90->sourcefile~constants.f90 sourcefile~utility.f90->sourcefile~error.f90 sourcefile~wannier90_types.f90->sourcefile~constants.f90 sourcefile~wannierise.f90->sourcefile~comms.f90 sourcefile~wannierise.f90->sourcefile~constants.f90 sourcefile~wannierise.f90->sourcefile~error.f90 sourcefile~wannierise.f90->sourcefile~io.f90 sourcefile~wannierise.f90->sourcefile~wannier90_readwrite.f90 sourcefile~wannierise.f90->sourcefile~sitesym.f90 sourcefile~wannierise.f90->sourcefile~types.f90 sourcefile~wannierise.f90->sourcefile~utility.f90 sourcefile~wannierise.f90->sourcefile~wannier90_types.f90 sourcefile~wannierise.f90->sourcefile~hamiltonian.f90 sourcefile~hamiltonian.f90->sourcefile~comms.f90 sourcefile~hamiltonian.f90->sourcefile~constants.f90 sourcefile~hamiltonian.f90->sourcefile~error.f90 sourcefile~hamiltonian.f90->sourcefile~io.f90 sourcefile~hamiltonian.f90->sourcefile~types.f90 sourcefile~hamiltonian.f90->sourcefile~utility.f90 sourcefile~hamiltonian.f90->sourcefile~wannier90_types.f90 sourcefile~ws_distance.f90->sourcefile~comms.f90 sourcefile~ws_distance.f90->sourcefile~constants.f90 sourcefile~ws_distance.f90->sourcefile~error.f90 sourcefile~ws_distance.f90->sourcefile~io.f90 sourcefile~ws_distance.f90->sourcefile~types.f90 sourcefile~ws_distance.f90->sourcefile~utility.f90

Files dependent on this one

sourcefile~~library_extra.f90~~AfferentGraph sourcefile~library_extra.f90 library_extra.F90 sourcefile~wannier_prog.f90 wannier_prog.F90 sourcefile~wannier_prog.f90->sourcefile~library_extra.f90

Source Code

!-*- mode: F90 -*-!
!------------------------------------------------------------!
!                                                            !
!                       WANNIER90                            !
!                                                            !
!          The Maximally-Localised Generalised               !
!                 Wannier Functions Code                     !
!                                                            !
! Please cite                                                !
!                                                            !
!  [ref] "Wannier90 as a community code:                     !
!        new features and applications",                     !
!        G. Pizzi et al.,  J. Phys. Cond. Matt. 32,          !
!        165902 (2020).                                      !
!        http://doi.org/10.1088/1361-648X/ab51ff             !
!                                                            !
! in any publications arising from the use of this code.     !
!                                                            !
! Wannier90 is based on Wannier77, written by N. Marzari,    !
! I. Souza and D. Vanderbilt. For the method please cite     !
!                                                            !
! [ref] N. Marzari and D. Vanderbilt,                        !
!       Phys. Rev. B 56 12847 (1997)                         !
!       http://dx.doi.org/10.1103/PhysRevB.56.12847          !
!                                                            !
! [ref] I. Souza, N. Marzari and D. Vanderbilt,              !
!       Phys. Rev. B 65 035109 (2001)                        !
!       http://dx.doi.org/10.1103/PhysRevB.65.035109         !
!                                                            !
! [ref] N. Marzari, A. A. Mostofi, J. R. Yates, I. Souza,    !
!       D. Vanderbilt, "Maximally localized Wannier          !
!       functions: theory and applications",                 !
!       Rev. Mod. Phys. 84, 1419 (2012)                      !
!       http://dx.doi.org/10.1103/RevModPhys.84.1419         !
!                                                            !
! For a full list of authors and contributors, please        !
! see the README file in the root directory of the           !
! distribution.                                              !
!                                                            !
! Copyright (C) 2026 Wannier Developer Group                 !
!                                                            !
! This library is free software; you can redistribute it     !
! and/or modify it under the terms of the GNU Lesser General !
! Public License as published by the Free Software           !
! Foundation; either version 2.1 of the License, or (at your !
! option) any later version.                                 !
!                                                            !
! This library is distributed in the hope that it will be    !
! useful,but WITHOUT ANY WARRANTY; without even the implied  !
! warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR    !
! PURPOSE.  See the GNU Lesser General Public License for    !
! more details.                                              !
!                                                            !
! You should have received a copy of the GNU Lesser General  !
! Public License along with this library; if not, see        !
! <https://www.gnu.org/licenses/>.                           !
!                                                            !
! The webpage of the Wannier90 code is                       !
! <https://www.wannier.org>.                                 !
!                                                            !
! The Wannier90 code is hosted on GitHub                     !
! <https://github.com/wannier-developers/wannier90>          !
!------------------------------------------------------------!

module w90_library_extra
  use w90_constants, only: dp
  use w90_io, only: prterr
  use w90_library

  private
  public :: input_reader_special
  public :: overlaps
  public :: print_times
  public :: read_chkpt
  public :: read_eigvals
  public :: set_kpoint_distribution
  public :: write_chkpt
  public :: write_kmesh

contains
  subroutine input_reader_special(common_data, seedname, istdout, istderr, ierr)
    !! Read key variables from main input (.win) file; of use by wannier90.x only

    use w90_error_base, only: w90_error_type
    use w90_error, only: set_error_input, set_error_fatal, set_error_alloc
    use w90_readwrite, only: w90_readwrite_in_file, w90_readwrite_clean_infile
    use w90_wannier90_readwrite, only: w90_wannier90_readwrite_read_special

    implicit none

    ! arguments
    character(len=*), intent(in) :: seedname
    integer, intent(in) :: istdout, istderr
    integer, intent(out) :: ierr
    type(lib_common_type), intent(inout) :: common_data

    ! local variables
    type(w90_error_type), allocatable :: error

    ierr = 0

    ! read data from .win file to internal string array
    call w90_readwrite_in_file(common_data%settings, seedname, error, common_data%comm)
    if (allocated(error)) then
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    call w90_wannier90_readwrite_read_special(common_data%settings, common_data%atom_data, &
                                              common_data%kmesh_input, common_data%kmesh_info, &
                                              common_data%kpt_latt, common_data%wann_control, &
                                              common_data%proj, common_data%proj_input, &
                                              common_data%select_proj, common_data%w90_system, &
                                              common_data%w90_calculation, &
                                              common_data%real_lattice, common_data%physics%bohr, &
                                              common_data%mp_grid, common_data%num_bands, &
                                              common_data%exclude_bands, common_data%num_kpts, &
                                              common_data%num_proj, common_data%num_wann, &
                                              common_data%gamma_only, common_data%lhasproj, &
                                              common_data%use_bloch_phases, &
                                              common_data%dist_kpoints, istdout, error, &
                                              common_data%comm)
    if (allocated(error)) then
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    common_data%seedname = seedname

    if (common_data%num_bands > common_data%num_wann) then
      allocate (common_data%dis_manifold%ndimwin(common_data%num_kpts), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, &
                             'Error allocating ndimwin in input_reader_special() call', common_data%comm)
        call prterr(error, ierr, istdout, istderr, common_data%comm)
        return
      end if
      allocate (common_data%dis_manifold%nfirstwin(common_data%num_kpts), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, &
                             'Error allocating nfirstwin in input_reader_special() call', common_data%comm)
        call prterr(error, ierr, istdout, istderr, common_data%comm)
        return
      end if
      allocate (common_data%dis_manifold%lwindow(common_data%num_bands, common_data%num_kpts), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, &
                             'Error allocating lwindow in input_reader_special() call', common_data%comm)
        call prterr(error, ierr, istdout, istderr, common_data%comm)
        return
      end if
    end if
    allocate (common_data%wannier_data%centres(3, common_data%num_wann), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, &
                           'Error allocating wannier_centres in input_reader_special() call', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if
    common_data%wannier_data%centres = 0.0_dp
    allocate (common_data%wannier_data%spreads(common_data%num_wann), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, &
                           'Error in allocating wannier_spreads in input_reader_special() call', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if
    common_data%wannier_data%spreads = 0.0_dp

    ! remove any remaining acceptable keywords; anything that remains is an input error
    call w90_readwrite_clean_infile(common_data%settings, istdout, seedname, error, common_data%comm)
    if (allocated(error)) then
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    if (allocated(common_data%settings%in_data)) deallocate (common_data%settings%in_data)
  end subroutine input_reader_special

  subroutine write_kmesh(common_data, istdout, istderr, ierr)
    !! Writes the .nnkp file instructing a DFT code what projections and overlaps to construct

    use w90_comms, only: mpirank, comms_sync_error
    use w90_error_base, only: w90_error_type
    use w90_error, only: set_error_fatal
    use w90_kmesh, only: kmesh_write

    implicit none

    ! arguments
    integer, intent(in) :: istdout, istderr
    integer, intent(out) :: ierr
    type(lib_common_type), intent(inout) :: common_data

    ! local variables
    type(w90_error_type), allocatable :: error

    ierr = 0

    if (.not. allocated(common_data%kmesh_info%nnlist)) then
      ! should be called by all ranks
      call w90_create_kmesh(common_data, istdout, istderr, ierr)
      if (ierr /= 0) then
        call set_error_fatal(error, 'Error in setting up k-mesh!', common_data%comm)
      end if
    end if

    if (allocated(error)) then
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    if (mpirank(common_data%comm) == 0) then ! root only; no error condition
      call kmesh_write(common_data%exclude_bands, common_data%kmesh_info, &
                       common_data%select_proj%auto_projections, common_data%proj_input, &
                       common_data%print_output, common_data%kpt_latt, common_data%real_lattice, &
                       common_data%num_kpts, common_data%num_proj, common_data%calc_only_A, &
                       common_data%w90_system%spinors, common_data%seedname, common_data%timer)
    end if
  end subroutine write_kmesh

  subroutine overlaps(common_data, istdout, istderr, ierr)
    use w90_error_base, only: w90_error_type
    use w90_error, only: set_error_fatal
    use w90_overlap, only: overlap_read

    implicit none

    ! arguments
    integer, intent(in) :: istdout, istderr
    integer, intent(out) :: ierr
    type(lib_common_type), intent(inout) :: common_data

    ! local variables
    logical :: cp_pp = .false.
    type(w90_error_type), allocatable :: error

    ierr = 0

    if (.not. common_data%setup_complete) then
      call set_error_fatal(error, 'Error: kmesh is not setup before reading overlap matrix', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    ! projections are stored in u_opt
    call overlap_read(common_data%kmesh_info, common_data%select_proj, common_data%u_matrix_opt, &
                      common_data%m_matrix_local, common_data%num_bands, common_data%num_kpts, &
                      common_data%num_proj, common_data%num_wann, common_data%print_output, &
                      common_data%print_output%timing_level, cp_pp, common_data%use_bloch_phases, &
                      common_data%seedname, istdout, common_data%timer, common_data%dist_kpoints, &
                      error, common_data%comm)
    if (allocated(error)) then
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if
  end subroutine overlaps

  subroutine read_eigvals(common_data, eigval, istdout, istderr, ierr)
    use w90_error, only: w90_error_type, set_error_fatal
    use w90_readwrite, only: w90_readwrite_read_eigvals

    implicit none

    ! arguments
    integer, intent(in) :: istdout, istderr
    real(kind=dp), intent(inout) :: eigval(:, :)
    type(lib_common_type), intent(inout) :: common_data
    integer, intent(out) :: ierr

    ! local vars
    type(w90_error_type), allocatable :: error
    logical :: eig_found

    ierr = 0

    if (size(eigval, 1) /= common_data%num_bands) then
      call set_error_fatal(error, &
                           'Error: eigval not dimensioned correctly (num_bands,num_kpts) in read_eigvals', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    elseif (size(eigval, 2) /= common_data%num_kpts) then
      call set_error_fatal(error, &
                           'Error: eigval not dimensioned correctly (num_bands,num_kpts) in read_eigvals', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    call w90_readwrite_read_eigvals(eig_found, eigval, common_data%num_bands, common_data%num_kpts, &
                                    istdout, common_data%seedname, error, common_data%comm)
    if (allocated(error)) then
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    else if (.not. eig_found) then
      call set_error_fatal(error, &
                           'Error: failed to read eigenvalues file in read_eigvals', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if
  end subroutine read_eigvals

  subroutine write_chkpt(common_data, label, istdout, istderr, ierr)
    use w90_comms, only: comms_reduce, mpirank
    use w90_error_base, only: w90_error_type
    use w90_error, only: set_error_alloc, set_error_dealloc, set_error_fatal
    use w90_wannier90_readwrite, only: w90_wannier90_readwrite_write_chkpt

    implicit none

    ! arguments
    character(len=*), intent(in) :: label ! e.g. 'postdis' or 'postwann' after disentanglement, wannierisation
    integer, intent(in) :: istdout, istderr
    integer, intent(inout) :: ierr
    type(lib_common_type), target, intent(in) :: common_data

    ! local variables
    complex(kind=dp), allocatable :: m(:, :, :, :)
    integer, allocatable :: global_k(:)
    integer, pointer :: nw, nb, nk, nn
    integer :: rank, nkrank, ikg, ikl, istat
    type(w90_error_type), allocatable :: error

    ierr = 0
    rank = mpirank(common_data%comm)
    nkrank = count(common_data%dist_kpoints == rank)

    nb => common_data%num_bands
    nk => common_data%num_kpts
    nn => common_data%kmesh_info%nntot
    nw => common_data%num_wann

    if (.not. associated(common_data%u_matrix_opt)) then
      call set_error_fatal(error, &
                           'Error: u_matrix_opt not associated for write_chkpt call', common_data%comm)
    else if (.not. associated(common_data%u_matrix)) then
      call set_error_fatal(error, &
                           'Error: u_matrix not associated for write_chkpt call', common_data%comm)
    else if (.not. associated(common_data%m_matrix_local)) then
      call set_error_fatal(error, &
                           'Error: m_matrix_local not set for write_chkpt call', common_data%comm)
    end if
    if (allocated(error)) then
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    allocate (global_k(nkrank), stat=istat)
    if (istat /= 0) then
      call set_error_alloc(error, 'Error allocating global_k in write_chkpt', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    global_k = huge(1)
    ikl = 1
    do ikg = 1, nk
      if (rank == common_data%dist_kpoints(ikg)) then
        global_k(ikl) = ikg
        ikl = ikl + 1
      end if
    end do

    ! reassemble full m matrix by MPI reduction
    !
    ! allocating and partially assigning the full matrix on all ranks and reducing is a terrible idea
    ! alternatively, allocate on root and use point-to-point
    ! or, if required only for checkpoint file writing, then use mpi-io (but needs to be ordered io, alas)
    ! or, even better, use parallel hdf5. JJ Nov 22
    allocate (m(nw, nw, nn, nk), stat=istat) ! all kpts
    if (istat /= 0) call set_error_alloc(error, 'Error allocating m in write_chkpt', common_data%comm)
    if (allocated(error)) then
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if
    m(:, :, :, :) = 0.d0
    do ikl = 1, nkrank
      ikg = global_k(ikl)
      m(:, :, :, ikg) = common_data%m_matrix_local(1:nw, 1:nw, :, ikl)
    end do
    call comms_reduce(m(1, 1, 1, 1), nw*nw*nn*nk, 'SUM', error, common_data%comm)
    if (allocated(error)) then
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    if (rank == 0) then
      call w90_wannier90_readwrite_write_chkpt(label, common_data%exclude_bands, &
                                               common_data%wannier_data, common_data%kmesh_info, &
                                               common_data%kpt_latt, nk, common_data%dis_manifold, &
                                               nb, nw, common_data%u_matrix, &
                                               common_data%u_matrix_opt, m, common_data%mp_grid, &
                                               common_data%real_lattice, &
                                               common_data%omega%invariant, &
                                               common_data%have_disentangled, &
                                               common_data%print_output%iprint, istdout, &
                                               common_data%seedname)
    end if

    deallocate (m, stat=istat)
    if (istat /= 0) then
      call set_error_dealloc(error, 'Error deallocating m in write_chkpt', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if
  end subroutine write_chkpt

  subroutine read_chkpt(common_data, checkpoint, istdout, istderr, ierr)
    use w90_comms, only: mpirank
    use w90_error_base, only: w90_error_type
    use w90_error, only: set_error_alloc, set_error_dealloc
    use w90_readwrite, only: w90_readwrite_read_chkpt, w90_readwrite_chkpt_dist

    implicit none

    ! arguments
    character(len=20), intent(out) :: checkpoint
    integer, intent(in) :: istdout, istderr
    integer, intent(out) :: ierr
    type(lib_common_type), target, intent(inout) :: common_data

    ! local variables
    complex(kind=dp), allocatable :: m(:, :, :, :)
    integer, pointer :: nw, nb, nk, nn
    integer :: rank, nexclude = 0, istat
    logical :: ispostw90 = .false. ! ispostw90 is used to print a different error message in case the chk file is missing (did you run w90 first?)
    type(w90_error_type), allocatable :: error

    ierr = 0
    rank = mpirank(common_data%comm)

    nb => common_data%num_bands
    nk => common_data%num_kpts
    nn => common_data%kmesh_info%nntot
    nw => common_data%num_wann

    ! allocating and partially assigning the full matrix on all ranks and reducing is a terrible idea at scale
    ! alternatively, allocate on root and use point-to-point
    ! or, if required only for checkpoint file writing, then use mpi-io (but needs to be ordered io, alas)
    ! or, even better, use parallel hdf5
    allocate (m(nw, nw, nn, nk), stat=istat) ! all kpts
    if (istat /= 0) then
      call set_error_alloc(error, 'Error allocating m in read_chkpt', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    if (rank == 0) then
      if (allocated(common_data%exclude_bands)) nexclude = size(common_data%exclude_bands)

      call w90_readwrite_read_chkpt(common_data%dis_manifold, common_data%exclude_bands, &
                                    common_data%kmesh_info, common_data%kpt_latt, &
                                    common_data%wannier_data, m, common_data%u_matrix, &
                                    common_data%u_matrix_opt, common_data%real_lattice, &
                                    common_data%omega%invariant, common_data%mp_grid, nb, &
                                    nexclude, nk, nw, checkpoint, common_data%have_disentangled, &
                                    ispostw90, common_data%seedname, istdout, error, &
                                    common_data%comm)
      if (allocated(error)) then
        call prterr(error, ierr, istdout, istderr, common_data%comm)
        return
      end if
    end if

    ! scatter from m_matrix to m_matrix_local (cf overlap_read)
    call w90_readwrite_chkpt_dist(common_data%dis_manifold, common_data%wannier_data, &
                                  common_data%u_matrix, common_data%u_matrix_opt, m, &
                                  common_data%m_matrix_local, common_data%omega%invariant, &
                                  nb, nk, nw, nn, checkpoint, common_data%have_disentangled, &
                                  common_data%dist_kpoints, error, common_data%comm)
    if (allocated(error)) then
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if

    deallocate (m, stat=istat)
    if (istat /= 0) then
      call set_error_alloc(error, 'Error deallocating m in read_chkpt', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if
  end subroutine read_chkpt

  subroutine print_times(common_data, istdout)
    use w90_io, only: io_print_timings
    implicit none

    type(lib_common_type), intent(in) :: common_data
    integer, intent(in) :: istdout

    if (common_data%print_output%iprint > 0) call io_print_timings(common_data%timer, istdout)
  end subroutine print_times

  subroutine set_kpoint_distribution(common_data, dist, istdout, istderr, ierr)
    use w90_error_base, only: w90_error_type
    use w90_error, only: set_error_fatal

    implicit none

    ! arguments
    integer, intent(in) :: istderr, istdout, dist(:)
    integer, intent(out) :: ierr
    type(lib_common_type), intent(inout) :: common_data

    ! local variables
    type(w90_error_type), allocatable :: error

    ierr = 0

    if (size(dist) < 1) then
      call set_error_fatal(error, 'Error in k-point distribution, mpisize < 1', common_data%comm)
      call prterr(error, ierr, istdout, istderr, common_data%comm)
      return
    end if
    common_data%dist_kpoints = dist
  end subroutine set_kpoint_distribution
end module w90_library_extra