wannier90_readwrite.F90 Source File


This file depends on

sourcefile~~wannier90_readwrite.f90~~EfferentGraph sourcefile~wannier90_readwrite.f90 wannier90_readwrite.F90 sourcefile~constants.f90 constants.F90 sourcefile~wannier90_readwrite.f90->sourcefile~constants.f90 sourcefile~error.f90 error.F90 sourcefile~wannier90_readwrite.f90->sourcefile~error.f90 sourcefile~io.f90 io.F90 sourcefile~wannier90_readwrite.f90->sourcefile~io.f90 sourcefile~readwrite.f90 readwrite.F90 sourcefile~wannier90_readwrite.f90->sourcefile~readwrite.f90 sourcefile~types.f90 types.F90 sourcefile~wannier90_readwrite.f90->sourcefile~types.f90 sourcefile~utility.f90 utility.F90 sourcefile~wannier90_readwrite.f90->sourcefile~utility.f90 sourcefile~wannier90_types.f90 wannier90_types.F90 sourcefile~wannier90_readwrite.f90->sourcefile~wannier90_types.f90 sourcefile~comms.f90 comms.F90 sourcefile~error.f90->sourcefile~comms.f90 sourcefile~error_base.f90 error_base.F90 sourcefile~error.f90->sourcefile~error_base.f90 sourcefile~io.f90->sourcefile~constants.f90 sourcefile~io.f90->sourcefile~types.f90 sourcefile~io.f90->sourcefile~comms.f90 sourcefile~io.f90->sourcefile~error_base.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~readwrite.f90->sourcefile~comms.f90 sourcefile~types.f90->sourcefile~constants.f90 sourcefile~utility.f90->sourcefile~constants.f90 sourcefile~utility.f90->sourcefile~error.f90 sourcefile~utility.f90->sourcefile~comms.f90 sourcefile~wannier90_types.f90->sourcefile~constants.f90 sourcefile~comms.f90->sourcefile~constants.f90 sourcefile~comms.f90->sourcefile~error_base.f90

Files dependent on this one

sourcefile~~wannier90_readwrite.f90~~AfferentGraph sourcefile~wannier90_readwrite.f90 wannier90_readwrite.F90 sourcefile~library_extra.f90 library_extra.F90 sourcefile~library_extra.f90->sourcefile~wannier90_readwrite.f90 sourcefile~library_interface.f90 library_interface.F90 sourcefile~library_extra.f90->sourcefile~library_interface.f90 sourcefile~library_interface.f90->sourcefile~wannier90_readwrite.f90 sourcefile~wannierise.f90 wannierise.F90 sourcefile~library_interface.f90->sourcefile~wannierise.f90 sourcefile~wannierise.f90->sourcefile~wannier90_readwrite.f90 sourcefile~c_interface.f90 c_interface.F90 sourcefile~c_interface.f90->sourcefile~library_interface.f90 sourcefile~wannier_prog.f90 wannier_prog.F90 sourcefile~wannier_prog.f90->sourcefile~library_extra.f90 sourcefile~wannier_prog.f90->sourcefile~library_interface.f90

Source Code

!-*- mode: F90 -*-!
!------------------------------------------------------------!
! 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>          !
!------------------------------------------------------------!
!                                                            !
!  w90_wannier90_readwrite: input/output routines            !
!     specific to wannier90.x                                !
!                                                            !
!------------------------------------------------------------!

module w90_wannier90_readwrite

  !! Read/write routines specific to wannier90.x data types

  use w90_constants, only: dp
  use w90_types
  use w90_error
  use w90_readwrite
  use w90_wannier90_types

  implicit none

  private

  public :: w90_wannier90_readwrite_memory_estimate
  public :: w90_wannier90_readwrite_read
  public :: w90_wannier90_readwrite_read_special
  public :: w90_wannier90_readwrite_w90_dealloc
  public :: w90_wannier90_readwrite_write
  public :: w90_wannier90_readwrite_write_chkpt

contains

  !================================================!
  subroutine w90_wannier90_readwrite_read_special(settings, atom_data, kmesh_input, kmesh_info, &
                                                  kpt_latt, wann_control, proj, proj_input, &
                                                  select_proj, w90_system, w90_calculation, &
                                                  real_lattice, bohr, mp_grid, num_bands, &
                                                  exclude_bands, num_kpts, num_proj, num_wann, &
                                                  gamma_only, lhasproj, use_bloch_phases, distk, &
                                                  stdout, error, comm)
    !================================================!
    !
    !! Read parameters and calculate derived values
    !!
    !! Note on parallelization: this function should be called
    !! from the root node only!
    !!
    !
    !================================================

    use w90_constants, only: w90_physical_constants_type
    use w90_utility, only: utility_recip_lattice, utility_inverse_mat

    implicit none

    ! arguments
    type(atom_data_type), intent(inout) :: atom_data
    type(kmesh_info_type), intent(inout) :: kmesh_info
    type(kmesh_input_type), intent(inout) :: kmesh_input
    type(proj_type), allocatable, intent(inout) :: proj(:), proj_input(:)
    type(select_projection_type), intent(inout) :: select_proj
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error
    type(w90_system_type), intent(inout) :: w90_system
    type(wann_control_type), intent(inout) :: wann_control
    type(w90_calculation_type), intent(inout) :: w90_calculation !check if really needed??

    integer, allocatable, intent(inout) :: exclude_bands(:)
    integer, allocatable, intent(inout) :: distk(:)
    integer, intent(inout) :: mp_grid(3)
    integer, intent(inout) :: num_bands
    integer, intent(inout) :: num_kpts
    integer, intent(inout) :: num_proj
    integer, intent(inout) :: num_wann
    integer, intent(in) :: stdout

    real(kind=dp), allocatable, intent(inout) :: kpt_latt(:, :)
    real(kind=dp), intent(in) :: bohr
    real(kind=dp), intent(inout) :: real_lattice(3, 3)

    logical, intent(inout) :: lhasproj
    logical, intent(inout) :: use_bloch_phases
    logical, intent(inout) :: gamma_only

    ! local variables
    logical :: disentanglement
    real(kind=dp) :: inv_lattice(3, 3)
    integer :: ip, ierr
    integer :: num_exclude_bands, total_bands

    call w90_readwrite_read_lattice(settings, real_lattice, bohr, error, comm)
    if (allocated(error)) return

    call w90_readwrite_read_atoms(settings, atom_data, real_lattice, bohr, error, comm)
    if (allocated(error)) return

    call w90_readwrite_read_num_wann(settings, num_wann, error, comm)
    if (allocated(error)) return

    call w90_readwrite_read_exclude_bands(settings, exclude_bands, num_exclude_bands, error, comm)
    if (allocated(error)) return

    total_bands = 0
    call w90_readwrite_read_total_bands(settings, total_bands, error, comm)
    if (allocated(error)) return
    if (total_bands > 0) then
      num_bands = total_bands - num_exclude_bands
    else
      call w90_readwrite_read_num_bands(settings, .false., num_bands, num_wann, error, comm)
      if (allocated(error)) return
    end if

    disentanglement = (num_bands > num_wann)

    call w90_readwrite_read_mp_grid(settings, .false., mp_grid, num_kpts, error, comm)
    if (allocated(error)) return

    call w90_readwrite_read_distk(settings, distk, num_kpts, stdout, error, comm)
    if (allocated(error)) return

    call w90_readwrite_read_kmesh_data(settings, kmesh_input, error, comm)
    if (allocated(error)) return

    call w90_readwrite_read_kpoints(settings, .false., kpt_latt, num_kpts, mp_grid, bohr, error, &
                                    comm)
    if (allocated(error)) return

    call w90_wannier90_readwrite_read_explicit_kpts(settings, w90_calculation, kmesh_info, &
                                                    num_kpts, bohr, error, comm)
    if (allocated(error)) return

    call w90_readwrite_read_system(settings, w90_system, error, comm)
    if (allocated(error)) return

    num_proj = num_wann !default, no projections specified

    call utility_inverse_mat(real_lattice, inv_lattice)
    call w90_wannier90_readwrite_read_projections(settings, proj, proj_input, use_bloch_phases, &
                                                  lhasproj, wann_control%guiding_centres%enable, &
                                                  select_proj, num_proj, atom_data, inv_lattice, &
                                                  num_wann, gamma_only, w90_system%spinors, bohr, &
                                                  stdout, error, comm)
    if (allocated(error)) return

    if (allocated(proj)) then
      allocate (wann_control%guiding_centres%centres(3, num_proj), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error in allocating ann_control%guiding_centres%centres &
        & in w90_wannier90_readwrite_read_special', comm)
        return
      end if
      do ip = 1, num_proj
        wann_control%guiding_centres%centres(:, ip) = proj(ip)%site(:)
      end do
    end if

  end subroutine w90_wannier90_readwrite_read_special

  !================================================!
  subroutine w90_wannier90_readwrite_read(settings, band_plot, dis_control, dis_spheres, &
                                          dis_manifold, fermi_energy_list, fermi_surface_data, &
                                          output_file, wvfn_read, wann_control, real_space_ham, &
                                          kpoint_path, w90_system, tran, print_output, wann_plot, &
                                          ws_region, real_lattice, w90_calculation, bohr, &
                                          symmetrize_eps, num_bands, num_kpts, num_wann, &
                                          optimisation, calc_only_A, cp_pp, gamma_only, &
                                          lsitesymmetry, use_bloch_phases, seedname, stdout, &
                                          error, comm)
    !================================================!
    !
    !! Read parameters and calculate derived values
    !!
    !! Note on parallelization: this function should be called
    !! from the root node only!
    !!
    !
    !================================================

    use w90_constants, only: w90_physical_constants_type
    use w90_utility, only: utility_recip_lattice, utility_inverse_mat

    implicit none

    ! arguments
    type(band_plot_type), intent(inout) :: band_plot
    type(dis_control_type), intent(inout) :: dis_control
    type(dis_manifold_type), intent(inout) :: dis_manifold
    type(dis_spheres_type), intent(inout) :: dis_spheres
    type(fermi_surface_plot_type), intent(inout) :: fermi_surface_data
    type(kpoint_path_type), intent(inout) :: kpoint_path
    type(output_file_type), intent(inout) :: output_file
    type(print_output_type), intent(inout) :: print_output
    type(real_space_ham_type), intent(inout) :: real_space_ham
    type(settings_type), intent(inout) :: settings
    type(transport_type), intent(inout) :: tran
    type(w90_calculation_type), intent(inout) :: w90_calculation
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error
    type(w90_system_type), intent(inout) :: w90_system
    type(wann_control_type), intent(inout) :: wann_control
    type(wannier_plot_type), intent(inout) :: wann_plot
    type(ws_region_type), intent(inout) :: ws_region
    type(wvfn_read_type), intent(inout) :: wvfn_read

    integer, intent(inout) :: num_bands
    integer, intent(inout) :: num_kpts
    integer, intent(inout) :: num_wann
    integer, intent(inout) :: optimisation
    integer, intent(in) :: stdout

    real(kind=dp), allocatable, intent(inout) :: fermi_energy_list(:)
    real(kind=dp), intent(in) :: bohr
    real(kind=dp), intent(inout) :: real_lattice(3, 3)
    real(kind=dp), intent(inout) :: symmetrize_eps

    character(len=*), intent(in)  :: seedname

    !Projections
    ! RS: symmetry-adapted Wannier functions
    logical, intent(inout) :: lsitesymmetry
    logical, intent(out) :: use_bloch_phases, cp_pp, calc_only_A
    logical, intent(inout) :: gamma_only

    ! local variables
    logical :: has_kpath
    logical :: has_explicit_kpath
!    integer :: num_exclude_bands
    logical :: found_fermi_energy
    logical :: disentanglement
    character(len=20) :: energy_unit  ! is this not used???
    !! Units for energy

    disentanglement = .false.
    call w90_wannier90_readwrite_read_sym(settings, symmetrize_eps, lsitesymmetry, error, comm)
    if (allocated(error)) return

    call w90_readwrite_read_verbosity(settings, print_output, output_file%svd_omega, error, comm)
    if (allocated(error)) return

    call w90_readwrite_read_algorithm_control(settings, optimisation, error, comm)
    if (allocated(error)) return

    call w90_wannier90_readwrite_read_w90_calcs(settings, w90_calculation, error, comm)
    if (allocated(error)) return

    call w90_wannier90_readwrite_read_transport(settings, w90_calculation%transport, tran, &
                                                w90_calculation%restart, error, comm)
    if (allocated(error)) return

    call w90_wannier90_readwrite_read_dist_cutoff(settings, real_space_ham, error, comm)
    if (allocated(error)) return

    if (.not. (w90_calculation%transport .and. tran%read_ht)) then
      call w90_readwrite_read_units(settings, print_output%lenconfac, print_output%length_unit, &
                                    energy_unit, bohr, error, comm)
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_wannierise(settings, wann_control, num_wann, &
                                                   stdout, print_output%iprint, error, comm)
      if (allocated(error)) return

      call w90_readwrite_read_gamma_only(settings, gamma_only, num_kpts, error, comm)
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_post_proc(settings, cp_pp, calc_only_A, &
                                                  w90_calculation%postproc_setup, error, comm)
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_restart(settings, w90_calculation, seedname, error, comm)
      if (allocated(error)) return

      call w90_readwrite_read_kpath(settings, kpoint_path, has_kpath, w90_calculation%bands_plot, &
                                    error, comm)
      if (allocated(error)) return

      call w90_readwrite_read_explicit_kpath(settings, kpoint_path, has_explicit_kpath, w90_calculation%bands_plot, &
                                             bohr, error, comm)
      if (allocated(error)) return

      if (has_kpath .and. has_explicit_kpath) then
        call set_error_input(error, 'Error: cannot specify both kpath and explicit_kpath', comm)
      end if
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_plot_info(settings, wvfn_read, error, comm)
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_band_plot(settings, band_plot, num_wann, has_kpath, &
                                                  has_explicit_kpath, w90_calculation%bands_plot, error, comm)
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_wann_plot(settings, wann_plot, num_wann, &
                                                  w90_calculation%wannier_plot, error, comm)
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_fermi_surface(settings, fermi_surface_data, &
                                                      w90_calculation%fermi_surface_plot, error, &
                                                      comm)
      if (allocated(error)) return

      call w90_readwrite_read_fermi_energy(settings, found_fermi_energy, fermi_energy_list, error, &
                                           comm)
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_outfiles(settings, output_file, num_kpts, &
                                                 w90_system%num_valence_bands, disentanglement, &
                                                 gamma_only, error, comm)
      if (allocated(error)) return

    end if

    call w90_wannier90_readwrite_read_one_dim(settings, w90_calculation, band_plot, real_space_ham, &
                                              tran%read_ht, error, comm)
    if (allocated(error)) return

    call w90_readwrite_read_ws_data(settings, ws_region, error, comm) !ws_search etc
    if (allocated(error)) return

    if (.not. (w90_calculation%transport .and. tran%read_ht)) then
      call w90_readwrite_read_dis_manifold(settings, dis_manifold, error, comm)
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_disentangle(settings, dis_control, dis_spheres, num_bands, &
                                                    num_wann, bohr, error, comm)
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_hamil(settings, real_space_ham, error, comm)
      if (allocated(error)) return

      call w90_wannier90_readwrite_read_bloch_phase(settings, use_bloch_phases, disentanglement, &
                                                    error, comm)
      if (allocated(error)) return

      if (wann_control%constrain%constrain) then
        call w90_wannier90_readwrite_read_constrained_centres(settings, &
                                                              wann_control, real_lattice, &
                                                              num_wann, print_output%iprint, &
                                                              stdout, error, comm)
        if (allocated(error)) return
      end if
    end if

  end subroutine w90_wannier90_readwrite_read

  !================================================!
  subroutine w90_wannier90_readwrite_read_sym(settings, symmetrize_eps, lsitesymmetry, error, comm)
    !================================================!
    ! Site symmetry
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    logical, intent(inout) :: lsitesymmetry
    real(kind=dp), intent(inout) :: symmetrize_eps
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found

    ! default value is lsitesymmetry=.false.
    call w90_readwrite_get_keyword(settings, 'site_symmetry', found, error, comm, &
                                   l_value=lsitesymmetry)
    if (allocated(error)) return

    ! default value is symmetrize_eps=0.001
    call w90_readwrite_get_keyword(settings, 'symmetrize_eps', found, error, comm, &
                                   r_value=symmetrize_eps)
    if (allocated(error)) return

  end subroutine w90_wannier90_readwrite_read_sym

  !================================================!
  subroutine w90_wannier90_readwrite_read_w90_calcs(settings, w90_calculation, error, comm)
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    type(settings_type), intent(inout) :: settings
    type(w90_calculation_type), intent(inout) :: w90_calculation
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found

    call w90_readwrite_get_keyword(settings, 'transport', found, error, comm, &
                                   l_value=w90_calculation%transport)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'wannier_plot', found, error, comm, &
                                   l_value=w90_calculation%wannier_plot)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'bands_plot', found, error, comm, &
                                   l_value=w90_calculation%bands_plot)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'fermi_surface_plot', found, error, comm, &
                                   l_value=w90_calculation%fermi_surface_plot)
    if (allocated(error)) return

  end subroutine w90_wannier90_readwrite_read_w90_calcs

  !================================================!
  subroutine w90_wannier90_readwrite_read_transport(settings, transport, tran, restart, error, comm)
    !================================================!
    ! Transport
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    character(len=*), intent(inout) :: restart
    logical, intent(in) :: transport
    type(settings_type), intent(inout) :: settings
    type(transport_type), intent(inout) :: tran
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found

    call w90_readwrite_get_keyword(settings, 'tran_read_ht', found, error, comm, &
                                   l_value=tran%read_ht)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_easy_fix', found, error, comm, &
                                   l_value=tran%easy_fix)
    if (allocated(error)) return

    if (transport .and. tran%read_ht) restart = ' '

    call w90_readwrite_get_keyword(settings, 'transport_mode', found, error, comm, &
                                   c_value=tran%mode)
    if (allocated(error)) return

!    if ( .not.tran_read_ht  .and. (index(transport_mode,'lcr').ne.0) ) then
!       call set_error_input(error, 'Error: transport_mode.eq.lcr not compatible with tran_read_ht.eq.false', comm)
!       return
!    endif

    call w90_readwrite_get_keyword(settings, 'tran_win_min', found, error, comm, &
                                   r_value=tran%win_min)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_win_max', found, error, comm, &
                                   r_value=tran%win_max)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_energy_step', found, error, comm, &
                                   r_value=tran%energy_step)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_num_bb', found, error, comm, i_value=tran%num_bb)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_num_ll', found, error, comm, i_value=tran%num_ll)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_num_rr', found, error, comm, i_value=tran%num_rr)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_num_cc', found, error, comm, i_value=tran%num_cc)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_num_lc', found, error, comm, i_value=tran%num_lc)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_num_cr', found, error, comm, i_value=tran%num_cr)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_num_bandc', found, error, comm, &
                                   i_value=tran%num_bandc)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_write_ht', found, error, comm, &
                                   l_value=tran%write_ht)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_use_same_lead', found, error, comm, &
                                   l_value=tran%use_same_lead)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_num_cell_ll', found, error, comm, &
                                   i_value=tran%num_cell_ll)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_num_cell_rr', found, error, comm, &
                                   i_value=tran%num_cell_rr)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'tran_group_threshold', found, error, comm, &
                                   r_value=tran%group_threshold)
    if (allocated(error)) return

    ! checks
    if (transport) then
      if ((index(tran%mode, 'bulk') .eq. 0) .and. (index(tran%mode, 'lcr') .eq. 0)) then
        call set_error_input(error, 'Error: transport_mode not recognised', comm)
        return
      end if
      if (tran%num_bb < 0) then
        call set_error_input(error, 'Error: tran_num_bb < 0', comm)
        return
      end if
      if (tran%num_ll < 0) then
        call set_error_input(error, 'Error: tran_num_ll < 0', comm)
        return
      end if
      if (tran%num_rr < 0) then
        call set_error_input(error, 'Error: tran_num_rr < 0', comm)
        return
      end if
      if (tran%num_cc < 0) then
        call set_error_input(error, 'Error: tran_num_cc < 0', comm)
        return
      end if
      if (tran%num_lc < 0) then
        call set_error_input(error, 'Error: tran_num_lc < 0', comm)
        return
      end if
      if (tran%num_cr < 0) then
        call set_error_input(error, 'Error: tran_num_cr < 0', comm)
        return
      end if
      if (tran%num_bandc < 0) then
        call set_error_input(error, 'Error: tran_num_bandc < 0', comm)
        return
      end if
      if (tran%num_cell_ll < 0) then
        call set_error_input(error, 'Error: tran_num_cell_ll < 0', comm)
        return
      end if
      if (tran%num_cell_rr < 0) then
        call set_error_input(error, 'Error: tran_num_cell_rr < 0', comm)
        return
      end if
      if (tran%group_threshold < 0.0_dp) then
        call set_error_input(error, 'Error: tran_group_threshold < 0', comm)
        return
      end if
    end if

  end subroutine w90_wannier90_readwrite_read_transport

  !================================================!
  subroutine w90_wannier90_readwrite_read_dist_cutoff(settings, real_space_ham, error, comm)
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    type(real_space_ham_type), intent(inout) :: real_space_ham
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found

    call w90_readwrite_get_keyword(settings, 'dist_cutoff_mode', found, error, comm, &
                                   c_value=real_space_ham%dist_cutoff_mode)
    if (allocated(error)) return
    if ((index(real_space_ham%dist_cutoff_mode, 'three_dim') .eq. 0) &
        .and. (index(real_space_ham%dist_cutoff_mode, 'two_dim') .eq. 0) &
        .and. (index(real_space_ham%dist_cutoff_mode, 'one_dim') .eq. 0)) then
      call set_error_input(error, 'Error: dist_cutoff_mode not recognised', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'dist_cutoff', found, error, comm, &
                                   r_value=real_space_ham%dist_cutoff)
    if (allocated(error)) return

    real_space_ham%dist_cutoff_hc = real_space_ham%dist_cutoff
    call w90_readwrite_get_keyword(settings, 'dist_cutoff_hc', found, error, comm, &
                                   r_value=real_space_ham%dist_cutoff_hc)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'hr_cutoff', found, error, comm, &
                                   r_value=real_space_ham%hr_cutoff)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'bands_plot_dim', found, error, comm, &
                                   i_value=real_space_ham%system_dim)
    if (allocated(error)) return

  end subroutine w90_wannier90_readwrite_read_dist_cutoff

  !================================================!
  subroutine w90_wannier90_readwrite_read_wannierise(settings, wann_control, num_wann, &
                                                     stdout, iprint, error, comm)
    !================================================!
    ! Wannierise
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    ! arguments
    integer, intent(in) :: num_wann
    integer, intent(in) :: stdout
    integer, intent(in) :: iprint
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error
    type(wann_control_type), intent(inout) :: wann_control

    ! local variables
    integer :: ierr
    logical :: found

    call w90_readwrite_get_keyword(settings, 'num_dump_cycles', found, error, comm, &
                                   i_value=wann_control%num_dump_cycles)
    if (allocated(error)) return

    if (wann_control%num_dump_cycles < 0) then
      call set_error_input(error, 'Error: num_dump_cycles must be positive', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'num_print_cycles', found, error, comm, &
                                   i_value=wann_control%num_print_cycles)
    if (allocated(error)) return

    if (wann_control%num_print_cycles < 0) then
      call set_error_input(error, 'Error: num_print_cycles must be positive', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'num_iter', found, error, comm, &
                                   i_value=wann_control%num_iter)
    if (allocated(error)) return

    if (wann_control%num_iter < 0) then
      call set_error_input(error, 'Error: num_iter must be positive', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'num_cg_steps', found, error, comm, &
                                   i_value=wann_control%num_cg_steps)
    if (allocated(error)) return

    if (wann_control%num_cg_steps < 0) then
      call set_error_input(error, 'Error: num_cg_steps must be positive', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'conv_noise_amp', found, error, comm, &
                                   r_value=wann_control%conv_noise_amp)
    if (allocated(error)) return

    ! note that the default here is not to check convergence
    wann_control%conv_window = -1
    if (wann_control%conv_noise_amp > 0.0_dp) wann_control%conv_window = 5
    call w90_readwrite_get_keyword(settings, 'conv_window', found, error, comm, &
                                   i_value=wann_control%conv_window)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'conv_tol', found, error, comm, &
                                   r_value=wann_control%conv_tol)
    if (allocated(error)) return

    if (wann_control%conv_tol < 0.0_dp) then
      call set_error_input(error, 'Error: conv_tol must be positive', comm)
      return
    end if

    if (found .and. wann_control%conv_window .le. 1) then
      if (iprint > 0) then
        write (stdout, '(a)') ' Warning: conv_window is not set to a value greater than 1, &
          &so conv_tol is ignored and wannierisation will always run for num_iter iterations.&
          &Set conv_window to a value greater than 1 if you want the minimisation &
          &to stop early once the spread change is below conv_tol for that many &
          &consecutive iterations.'
      end if
    end if

    call w90_readwrite_get_keyword(settings, 'conv_noise_num', found, error, comm, &
                                   i_value=wann_control%conv_noise_num)
    if (allocated(error)) return

    if (wann_control%conv_noise_num < 0) then
      call set_error_input(error, 'Error: conv_noise_num must be positive', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'guiding_centres', found, error, comm, &
                                   l_value=wann_control%guiding_centres%enable)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'use_ss_functional', found, error, comm, &
                                   l_value=wann_control%use_ss_functional)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'num_guide_cycles', found, error, comm, &
                                   i_value=wann_control%guiding_centres%num_guide_cycles)
    if (allocated(error)) return

    if (wann_control%guiding_centres%num_guide_cycles < 0) then
      call set_error_input(error, 'Error: num_guide_cycles must be >= 0', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'num_no_guide_iter', found, error, comm, &
                                   i_value=wann_control%guiding_centres%num_no_guide_iter)
    if (allocated(error)) return

    if (wann_control%guiding_centres%num_no_guide_iter < 0) then
      call set_error_input(error, 'Error: num_no_guide_iter must be >= 0', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'fixed_step', found, error, comm, &
                                   r_value=wann_control%fixed_step)
    if (allocated(error)) return

    if (found .and. (wann_control%fixed_step < 0.0_dp)) then
      call set_error_input(error, 'Error: fixed_step must be > 0', comm)
      return
    end if
    if (wann_control%fixed_step > 0.0_dp) wann_control%lfixstep = .true.

    call w90_readwrite_get_keyword(settings, 'trial_step', found, error, comm, &
                                   r_value=wann_control%trial_step)
    if (allocated(error)) return

    if (found .and. wann_control%lfixstep) then
      call set_error_input(error, 'Error: cannot specify both fixed_step and trial_step', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'precond', found, error, comm, &
                                   l_value=wann_control%precond)
    if (allocated(error)) return

    wann_control%constrain%slwf_num = num_wann
    call w90_readwrite_get_keyword(settings, 'slwf_num', found, error, comm, &
                                   i_value=wann_control%constrain%slwf_num)
    if (allocated(error)) return

    if (found) then
      if (wann_control%constrain%slwf_num .gt. num_wann .or. &
          wann_control%constrain%slwf_num .lt. 1) then
        call set_error_input(error, 'Error: slwf_num must be an integer between 1 and num_wann', comm)
        return
      end if
      if (wann_control%constrain%slwf_num .lt. num_wann) &
        wann_control%constrain%selective_loc = .true.
    end if

    call w90_readwrite_get_keyword(settings, 'slwf_constrain', found, error, comm, &
                                   l_value=wann_control%constrain%constrain)
    if (allocated(error)) return

    if (found .and. wann_control%constrain%constrain) then
      if (wann_control%constrain%selective_loc) then
        allocate (wann_control%constrain%centres(num_wann, 3), stat=ierr)
        if (ierr /= 0) then
          call set_error_alloc(error, 'Error allocating wann_control%constrain%centres &
          & w90_wannier90_readwrite_read_wannierise', comm)
          return
        end if
      else
        write (stdout, *) ' No selective localisation requested. Ignoring constraints on centres'
        wann_control%constrain%constrain = .false.
      end if
    end if

    call w90_readwrite_get_keyword(settings, 'slwf_lambda', found, error, comm, &
                                   r_value=wann_control%constrain%lambda)
    if (allocated(error)) return

    if (found) then
      if (wann_control%constrain%lambda < 0.0_dp) then
        call set_error_input(error, 'Error: slwf_lambda  must be positive.', comm)
        return
      end if
    end if
  end subroutine w90_wannier90_readwrite_read_wannierise

  !================================================!
  subroutine w90_wannier90_readwrite_read_disentangle(settings, dis_control, dis_spheres, &
                                                      num_bands, num_wann, bohr, error, comm)
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    integer, intent(in) :: num_bands, num_wann
    real(kind=dp), intent(in) :: bohr
    type(dis_control_type), intent(inout) :: dis_control
    type(dis_spheres_type), intent(inout) :: dis_spheres
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    integer :: nkp, ierr
    logical :: found

    call w90_readwrite_get_keyword(settings, 'dis_num_iter', found, error, comm, &
                                   i_value=dis_control%num_iter)
    if (allocated(error)) return
    if (dis_control%num_iter < 0) then
      call set_error_input(error, 'Error: dis_num_iter must be positive', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'dis_mix_ratio', found, error, comm, &
                                   r_value=dis_control%mix_ratio)
    if (allocated(error)) return
    if (dis_control%mix_ratio <= 0.0_dp .or. dis_control%mix_ratio > 1.0_dp) then
      call set_error_input(error, 'Error: dis_mix_ratio must be greater than 0.0 but not greater than 1.0', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'dis_conv_tol', found, error, comm, &
                                   r_value=dis_control%conv_tol)
    if (allocated(error)) return
    if (dis_control%conv_tol < 0.0_dp) then
      call set_error_input(error, 'Error: dis_conv_tol must be positive', comm)
      return
    end if

    call w90_readwrite_get_keyword(settings, 'dis_conv_window', found, error, comm, &
                                   i_value=dis_control%conv_window)
    if (allocated(error)) return
    if (dis_control%conv_window < 0) then
      call set_error_input(error, 'Error: dis_conv_window must be positive', comm)
      return
    end if

    ! GS-start
    call w90_readwrite_get_keyword(settings, 'dis_spheres_first_wann', found, error, comm, &
                                   i_value=dis_spheres%first_wann)
    if (allocated(error)) return
    if (dis_spheres%first_wann < 1) then
      call set_error_input(error, 'Error: dis_spheres_first_wann must be greater than 0', comm)
      return
    end if
    if (dis_spheres%first_wann > num_bands - num_wann + 1) then
      call set_error_input(error, 'Error: dis_spheres_first_wann is larger than num_bands-num_wann+1', comm)
      return
    end if
    call w90_readwrite_get_keyword(settings, 'dis_spheres_num', found, error, comm, &
                                   i_value=dis_spheres%num)
    if (allocated(error)) return
    if (dis_spheres%num < 0) then
      call set_error_input(error, 'Error: dis_spheres_num cannot be negative', comm)
      return
    end if
    if (dis_spheres%num > 0) then
      allocate (dis_spheres%spheres(4, dis_spheres%num), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating dis_spheres in w90_wannier90_readwrite_read_disentangle', comm)
        return
      end if
      call w90_readwrite_get_keyword_block(settings, 'dis_spheres', found, dis_spheres%num, 4, &
                                           bohr, error, comm, r_value=dis_spheres%spheres)
      if (allocated(error)) return
      if (.not. found) then
        call set_error_input(error, 'Error: Did not find dis_spheres in the input file', comm)
        return
      end if
      do nkp = 1, dis_spheres%num
        if (dis_spheres%spheres(4, nkp) < 1.0e-15_dp) then
          call set_error_input(error, 'Error: radius for dis_spheres must be > 0', comm)
          return
        end if
      end do
    end if
    ! GS-end
  end subroutine w90_wannier90_readwrite_read_disentangle

  !================================================!
  subroutine w90_wannier90_readwrite_read_post_proc(settings, cp_pp, pp_only_A, postproc_setup, &
                                                    error, comm)
    !================================================!
    ! check for input option to activate 'post processing' mode (i.e. writing nnkp data)
    ! the main() routine separately looks for '-pp' command line argument
    use w90_error, only: w90_error_type
    implicit none

    logical, intent(inout) :: cp_pp, pp_only_A, postproc_setup
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found

    call w90_readwrite_get_keyword(settings, 'postproc_setup', found, error, comm, &
                                   l_value=postproc_setup)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'cp_pp', found, error, comm, l_value=cp_pp)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'calc_only_A', found, error, comm, l_value=pp_only_A)
    if (allocated(error)) return
  end subroutine w90_wannier90_readwrite_read_post_proc

  !================================================!
  subroutine w90_wannier90_readwrite_read_restart(settings, w90_calculation, seedname, error, comm)
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    character(len=*), intent(in)  :: seedname
    type(settings_type), intent(inout) :: settings
    type(w90_calculation_type), intent(inout) :: w90_calculation
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found, chk_found

    call w90_readwrite_get_keyword(settings, 'restart', found, error, comm, &
                                   c_value=w90_calculation%restart)
    if (allocated(error)) return
    if (found) then
      if ((w90_calculation%restart .ne. 'default') .and. (w90_calculation%restart .ne. 'wannierise') &
          .and. (w90_calculation%restart .ne. 'plot') .and. (w90_calculation%restart .ne. 'transport')) then
        call set_error_input(error, 'Error in input file: value of restart not recognised', comm)
        return
      else
        inquire (file=trim(seedname)//'.chk', exist=chk_found)
        if (.not. chk_found) then
          call set_error_file(error, 'Error: restart requested but '//trim(seedname)//'.chk file not found', comm)
          return
        end if
      end if
    end if
    !post processing takes priority (user is not warned of this)
    if (w90_calculation%postproc_setup) w90_calculation%restart = ' '
  end subroutine w90_wannier90_readwrite_read_restart

  !================================================!
  subroutine w90_wannier90_readwrite_read_outfiles(settings, output_file, num_kpts, &
                                                   num_valence_bands, disentanglement, gamma_only, &
                                                   error, comm)
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    integer, intent(in) :: num_kpts
    integer, intent(in) :: num_valence_bands
    logical, intent(in) :: disentanglement, gamma_only
    type(output_file_type), intent(inout) :: output_file
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found, hr_plot

    call w90_readwrite_get_keyword(settings, 'write_xyz', found, error, comm, &
                                   l_value=output_file%write_xyz)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'write_r2mn', found, error, comm, &
                                   l_value=output_file%write_r2mn)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'write_proj', found, error, comm, &
                                   l_value=output_file%write_proj)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'write_hr_diag', found, error, comm, &
                                   l_value=output_file%write_hr_diag)
    if (allocated(error)) return

    hr_plot = .false.
    call w90_readwrite_get_keyword(settings, 'hr_plot', found, error, comm, l_value=hr_plot)
    if (allocated(error)) return
    if (found) then
      call set_error_input(error, 'Input parameter hr_plot is no longer used. Please use write_hr instead.', comm)
      return
    end if
    call w90_readwrite_get_keyword(settings, 'write_hr', found, error, comm, &
                                   l_value=output_file%write_hr)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'write_rmn', found, error, comm, &
                                   l_value=output_file%write_rmn)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'write_tb', found, error, comm, &
                                   l_value=output_file%write_tb)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'dump_inputs', found, error, comm, &
                                   l_value=output_file%write_win_ammats)
    if (allocated(error)) return

    !%%%%%%%%%%%%%%%%
    !  Other Stuff
    !%%%%%%%%%%%%%%%%

    ! aam: vdW
    call w90_readwrite_get_keyword(settings, 'write_vdw_data', found, error, comm, &
                                   l_value=output_file%write_vdw_data)
    if (allocated(error)) return
    if (output_file%write_vdw_data) then
      if ((.not. gamma_only) .or. (num_kpts .ne. 1)) then
        call set_error_input(error, 'Error: write_vdw_data may only be used with a single k-point at Gamma', comm)
        return
      end if
      if (disentanglement .and. num_valence_bands <= 0) then
        call set_error_input(error, 'If writing vdw data and disentangling then num_valence_bands must be defined', comm)
        return
      end if
    end if

    call w90_readwrite_get_keyword(settings, 'write_u_matrices', found, error, comm, &
                                   l_value=output_file%write_u_matrices)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'write_bvec', found, error, comm, &
                                   l_value=output_file%write_bvec)
    if (allocated(error)) return

  end subroutine w90_wannier90_readwrite_read_outfiles

  !================================================!
  subroutine w90_wannier90_readwrite_read_plot_info(settings, wvfn_read, error, comm)
    !================================================!
    ! Plotting
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error
    type(wvfn_read_type), intent(inout) :: wvfn_read

    logical :: found
    character(len=6) :: spin_str

    call w90_readwrite_get_keyword(settings, 'wvfn_formatted', found, error, comm, &
                                   l_value=wvfn_read%formatted)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'spin', found, error, comm, c_value=spin_str)
    if (allocated(error)) return
    if (found) then
      if (index(spin_str, 'up') > 0) then
        wvfn_read%spin_channel = 1
      elseif (index(spin_str, 'down') > 0) then
        wvfn_read%spin_channel = 2
      else
        call set_error_input(error, 'Error: unrecognised value of spin found: '//trim(spin_str), comm)
        return
      end if
    end if

  end subroutine w90_wannier90_readwrite_read_plot_info

  !================================================!
  subroutine w90_wannier90_readwrite_read_band_plot(settings, band_plot, num_wann, has_kpath, &
                                                    has_explicit_kpath, bands_plot, error, comm)
    !================================================!
    ! Plotting
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    integer, intent(in) :: num_wann
    logical, intent(in) :: bands_plot
    logical, intent(in) :: has_kpath
    logical, intent(in) :: has_explicit_kpath
    type(band_plot_type), intent(inout) :: band_plot
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    integer :: ierr, num_project
    logical :: found

    call w90_readwrite_get_keyword(settings, 'bands_plot_format', found, error, comm, &
                                   c_value=band_plot%format)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'bands_plot_mode', found, error, comm, c_value=band_plot%mode)
    if (allocated(error)) return

    num_project = 0
    call w90_readwrite_get_range_vector(settings, 'bands_plot_project', found, num_project, .true., error, comm)
    if (allocated(error)) return
    if (found) then
      if (num_project < 1) then
        call set_error_input(error, 'Error: problem reading bands_plot_project', comm)
        return
      end if
      if (allocated(band_plot%project)) then
        deallocate (band_plot%project, stat=ierr)
        if (ierr /= 0) then
          call set_error_dealloc(error, 'Error deallocating bands_plot%project in &
          & w90_wannier90_readwrite_read_band_plot', comm)
          return
        end if
      end if
      allocate (band_plot%project(num_project), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating bands_plot%project in w90_wannier90_readwrite_read_band_plot', comm)
        return
      end if
      call w90_readwrite_get_range_vector(settings, 'bands_plot_project', found, &
                                          num_project, .false., error, comm, band_plot%project)
      if (allocated(error)) return
      if (any(band_plot%project < 1) .or. any(band_plot%project > num_wann)) then
        call set_error_input(error, 'Error: bands_plot_project asks for a non-valid wannier function to be projected', comm)
        return
      end if
    end if

    if ((.not. has_kpath) .and. (.not. has_explicit_kpath) .and. bands_plot) then
      call set_error_input(error, &
                           'A bandstructure plot has been requested but there is no kpoint_path or explicit_kpath block', comm)
      return
    end if

    ! checks
    if (bands_plot) then
      if ((index(band_plot%format, 'gnu') .eq. 0) .and. &
          (index(band_plot%format, 'xmgr') .eq. 0)) then
        call set_error_input(error, 'Error: bands_plot_format not recognised', comm)
        return
      end if
      if ((index(band_plot%mode, 's-k') .eq. 0) .and. (index(band_plot%mode, 'cut') .eq. 0)) then
        call set_error_input(error, 'Error: bands_plot_mode not recognised', comm)
        return
      end if
    end if

  end subroutine w90_wannier90_readwrite_read_band_plot

  !================================================!
  subroutine w90_wannier90_readwrite_read_wann_plot(settings, wann_plot, num_wann, wannier_plot, &
                                                    error, comm)
    !================================================!
    ! Plotting
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    integer, intent(in) :: num_wann
    logical, intent(in) :: wannier_plot
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error
    type(wannier_plot_type), intent(inout) :: wann_plot

    integer :: i, loop, ierr, wann_plot_num
    logical :: found

    found = .false.

    call w90_readwrite_get_vector_length(settings, 'wannier_plot_supercell', found, i, error, comm)
    if (allocated(error)) return

    if (found) then
      if (i .eq. 1) then
        call w90_readwrite_get_keyword_vector(settings, 'wannier_plot_supercell', found, 1, error, comm, &
                                              i_value=wann_plot%supercell)
        if (allocated(error)) return

        wann_plot%supercell(2) = wann_plot%supercell(1)
        wann_plot%supercell(3) = wann_plot%supercell(1)
      elseif (i .eq. 3) then
        call w90_readwrite_get_keyword_vector(settings, 'wannier_plot_supercell', found, 3, error, comm, &
                                              i_value=wann_plot%supercell)
        if (allocated(error)) return

      else
        call set_error_input(error, 'Error: wannier_plot_supercell must be provided as either' &
                             //'one integer or a vector of three integers', comm)
        return
      end if
      if (any(wann_plot%supercell <= 0)) then
        call set_error_input(error, 'Error: wannier_plot_supercell elements must be greater than zero', comm)
        return
      end if
    end if

    call w90_readwrite_get_keyword(settings, 'wannier_plot_format', found, error, comm, c_value=wann_plot%format)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'wannier_plot_mode', found, error, comm, c_value=wann_plot%mode)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'wannier_plot_spinor_mode', found, error, comm, &
                                   c_value=wann_plot%spinor_mode)
    if (allocated(error)) return
    call w90_readwrite_get_keyword(settings, 'wannier_plot_spinor_phase', found, error, comm, &
                                   l_value=wann_plot%spinor_phase)
    if (allocated(error)) return

    wann_plot_num = 0
    call w90_readwrite_get_range_vector(settings, 'wannier_plot_list', found, wann_plot_num, .true., error, comm)
    if (allocated(error)) return
    if (found) then
      if (wann_plot_num < 1) then
        call set_error_input(error, 'Error: problem reading wannier_plot_list', comm)
        return
      end if
      if (allocated(wann_plot%list)) then
        deallocate (wann_plot%list, stat=ierr)
        if (ierr /= 0) then
          call set_error_dealloc(error, 'Error deallocating wannier_plot%list in w90_wannier90_readwrite_read', comm)
          return
        end if
      end if
      allocate (wann_plot%list(wann_plot_num), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating wannier_plot%list in w90_wannier90_readwrite_read', comm)
        return
      end if
      call w90_readwrite_get_range_vector(settings, 'wannier_plot_list', found, wann_plot_num, .false., &
                                          error, comm, wann_plot%list)
      if (allocated(error)) return
      if (any(wann_plot%list < 1) .or. any(wann_plot%list > num_wann)) then
        call set_error_input(error, 'Error: wannier_plot_list asks for a non-valid wannier function to be plotted', comm)
        return
      end if
    else
      ! we plot all wannier functions
      wann_plot_num = num_wann
      if (allocated(wann_plot%list)) then
        deallocate (wann_plot%list, stat=ierr)
        if (ierr /= 0) then
          call set_error_dealloc(error, 'Error deallocating wannier_plot%list &
          & in w90_wannier90_readwrite_read_wann_plot', comm)
          return
        end if
      end if
      allocate (wann_plot%list(wann_plot_num), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating wannier_plot%list in w90_wannier90_readwrite_read_wann_plot', comm)
        return
      end if
      do loop = 1, num_wann
        wann_plot%list(loop) = loop
      end do
    end if

    call w90_readwrite_get_keyword(settings, 'wannier_plot_radius', found, error, comm, r_value=wann_plot%radius)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'wannier_plot_scale', found, error, comm, r_value=wann_plot%scale)
    if (allocated(error)) return

    ! checks
    if (wannier_plot) then
      if ((index(wann_plot%format, 'xcrys') .eq. 0) .and. (index(wann_plot%format, 'cub') .eq. 0)) then
        call set_error_input(error, 'Error: wannier_plot_format not recognised', comm)
        return
      end if
      if ((index(wann_plot%mode, 'crys') .eq. 0) .and. (index(wann_plot%mode, 'mol') .eq. 0)) then
        call set_error_input(error, 'Error: wannier_plot_mode not recognised', comm)
        return
      end if
      if ((index(wann_plot%spinor_mode, 'total') .eq. 0) &
          .and. (index(wann_plot%spinor_mode, 'up') .eq. 0) &
          .and. (index(wann_plot%spinor_mode, 'down') .eq. 0)) then
        call set_error_input(error, 'Error: wannier_plot_spinor_mode not recognised', comm)
        return
      end if
      if (wann_plot%radius < 0.0_dp) then
        call set_error_input(error, 'Error: wannier_plot_radius must be positive', comm)
        return
      end if
      if (wann_plot%scale < 0.0_dp) then
        call set_error_input(error, 'Error: wannier_plot_scale must be positive', comm)
        return
      end if
    end if

  end subroutine w90_wannier90_readwrite_read_wann_plot

  !================================================!
  subroutine w90_wannier90_readwrite_read_fermi_surface(settings, fermi_surface_data, &
                                                        fermi_surface_plot, error, comm)
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    logical, intent(in) :: fermi_surface_plot
    type(fermi_surface_plot_type), intent(inout) :: fermi_surface_data
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found

    call w90_readwrite_get_keyword(settings, 'fermi_surface_num_points', found, error, comm, &
                                   i_value=fermi_surface_data%num_points)
    if (allocated(error)) return

    call w90_readwrite_get_keyword(settings, 'fermi_surface_plot_format', found, error, comm, &
                                   c_value=fermi_surface_data%plot_format)
    if (allocated(error)) return

    if (fermi_surface_plot) then
      if ((index(fermi_surface_data%plot_format, 'xcrys') .eq. 0)) then
        call set_error_input(error, 'Error: fermi_surface_plot_format not recognised', comm)
        return
      end if
      if (fermi_surface_data%num_points < 0) then
        call set_error_input(error, 'Error: fermi_surface_num_points must be positive', comm)
        return
      end if
    end if
  end subroutine w90_wannier90_readwrite_read_fermi_surface

  !================================================!
  subroutine w90_wannier90_readwrite_read_one_dim(settings, w90_calculation, band_plot, &
                                                  real_space_ham, tran_read_ht, error, comm)
    !================================================!
    use w90_error, only: w90_error_type
    implicit none

    logical, intent(in) :: tran_read_ht
    type(band_plot_type), intent(in) :: band_plot
    type(real_space_ham_type), intent(inout) :: real_space_ham
    type(settings_type), intent(inout) :: settings
    type(w90_calculation_type), intent(in) :: w90_calculation
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found
    character(len=256) :: one_dim_axis

    call w90_readwrite_get_keyword(settings, 'one_dim_axis', found, error, comm, c_value=one_dim_axis)
    if (allocated(error)) return

    if (index(one_dim_axis, 'x') > 0) real_space_ham%one_dim_dir = 1
    if (index(one_dim_axis, 'y') > 0) real_space_ham%one_dim_dir = 2
    if (index(one_dim_axis, 'z') > 0) real_space_ham%one_dim_dir = 3
    if (w90_calculation%transport .and. .not. tran_read_ht .and. &
        (real_space_ham%one_dim_dir .eq. 0)) then
      call set_error_input(error, 'Error: one_dim_axis not recognised', comm)
      return
    end if
    if (w90_calculation%bands_plot .and. (index(band_plot%mode, 'cut') .ne. 0) .and. &
        ((real_space_ham%system_dim .ne. 3) .or. &
         (index(real_space_ham%dist_cutoff_mode, 'three_dim') .eq. 0)) .and. &
        (real_space_ham%one_dim_dir .eq. 0)) then
      call set_error_input(error, 'Error: one_dim_axis not recognised', comm)
      return
    end if
  end subroutine w90_wannier90_readwrite_read_one_dim

  !================================================!
  subroutine w90_wannier90_readwrite_read_hamil(settings, hamiltonian, error, comm)
    !================================================!
    use w90_error, only: w90_error_type
    implicit none
    real(kind=dp) :: rv_temp(3)
    type(real_space_ham_type), intent(inout) :: hamiltonian
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found

    call w90_readwrite_get_keyword(settings, 'translate_home_cell', found, error, comm, &
                                   l_value=hamiltonian%translate_home_cell)
    if (allocated(error)) return

    call w90_readwrite_get_keyword_vector(settings, 'translation_centre_frac', found, 3, error, comm, &
                                          r_value=rv_temp)
    if (allocated(error)) return

    if (found) then
      hamiltonian%translation_centre_frac = rv_temp
      hamiltonian%automatic_translation = .false.
    end if
  end subroutine w90_wannier90_readwrite_read_hamil

  !================================================!
  subroutine w90_wannier90_readwrite_read_bloch_phase(settings, use_bloch_phases, disentanglement, &
                                                      error, comm)
    !================================================!
    use w90_error, only: w90_error_type
    implicit none
    logical, intent(in) :: disentanglement
    logical, intent(inout) :: use_bloch_phases
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    logical :: found

    call w90_readwrite_get_keyword(settings, 'use_bloch_phases', found, error, comm, l_value=use_bloch_phases)
    if (allocated(error)) return

    if (disentanglement .and. use_bloch_phases) then
      call set_error_input(error, 'Error: Cannot use bloch phases for disentanglement', comm)
      return
    end if
  end subroutine w90_wannier90_readwrite_read_bloch_phase

  !================================================!
  subroutine w90_wannier90_readwrite_read_explicit_kpts(settings, w90_calculation, kmesh_info, &
                                                        num_kpts, bohr, error, comm)
    !================================================!

    use w90_error, only: w90_error_type
    use w90_utility, only: utility_recip_lattice

    implicit none

    ! arguments
    integer, intent(in) :: num_kpts
    real(kind=dp), intent(in) :: bohr
    type(kmesh_info_type), intent(inout) :: kmesh_info
    type(settings_type), intent(inout) :: settings
    type(w90_calculation_type), intent(in) :: w90_calculation
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    ! local variables
    integer, allocatable :: nnkpts_block(:, :)
    integer, allocatable :: nnkpts_idx(:)
    integer :: i, k, ierr, rows
    logical :: found

    call w90_readwrite_get_block_length(settings, 'nnkpts', kmesh_info%explicit_nnkpts, rows, error, comm)
    if (allocated(error)) return

    if (kmesh_info%explicit_nnkpts) then
      if (modulo(rows, num_kpts) /= 0) then
        call set_error_input(error, 'The number of rows in nnkpts must be a multiple of num_kpts', comm)
        return
      end if
      kmesh_info%nntot = rows/num_kpts

      if (allocated(nnkpts_block)) then
        deallocate (nnkpts_block, stat=ierr)
        if (ierr /= 0) then
          call set_error_dealloc(error, 'Error deallocating nnkpts_block in &
          & w90_wannier90_readwrite_read_explicit_kpts', comm)
          return
        end if
      end if
      allocate (nnkpts_block(5, rows), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating nnkpts_block in w90_wannier90_readwrite_read_explicit_kpts', comm)
        return
      end if
      call w90_readwrite_get_keyword_block(settings, 'nnkpts', found, rows, 5, bohr, error, comm, &
                                           i_value=nnkpts_block)
      if (allocated(error)) return

      ! check that postproc_setup is true
      if (.not. w90_calculation%postproc_setup) then
        call set_error_input(error, 'Input parameter nnkpts_block is allowed only if postproc_setup = .true.', comm)
        return
      end if

      ! assign the values in nnkpts_block to nnlist and nncell
      ! this keeps track of how many neighbours have been seen for each k-point
      if (allocated(nnkpts_idx)) then
        deallocate (nnkpts_idx, stat=ierr)
        if (ierr /= 0) then
          call set_error_dealloc(error, 'Error deallocating nnkpts_idx in w90_wannier90_readwrite_read_explicit_kpts', comm)
          return
        end if
      end if
      allocate (nnkpts_idx(num_kpts), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating nnkpts_idx in w90_wannier90_readwrite_read_explicit_kpts', comm)
        return
      end if
      nnkpts_idx = 1
      ! allocating "global" nnlist & nncell
      ! These are deallocated in kmesh_dealloc
      if (allocated(kmesh_info%nnlist)) then
        deallocate (kmesh_info%nnlist, stat=ierr)
        if (ierr /= 0) then
          call set_error_dealloc(error, 'Error deallocating nnlist in w90_wannier90_readwrite_read_explicit_kpts', comm)
          return
        end if
      end if
      allocate (kmesh_info%nnlist(num_kpts, kmesh_info%nntot), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating nnlist in w90_wannier90_readwrite_read_explicit_kpts', comm)
        return
      end if
      if (allocated(kmesh_info%nncell)) then
        deallocate (kmesh_info%nncell, stat=ierr)
        if (ierr /= 0) then
          call set_error_dealloc(error, 'Error deallocating nncell in w90_wannier90_readwrite_read_explicit_kpts', comm)
          return
        end if
      end if
      allocate (kmesh_info%nncell(3, num_kpts, kmesh_info%nntot), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating nncell in w90_wannier90_readwrite_read_explicit_kpts', comm)
        return
      end if
      do i = 1, num_kpts*kmesh_info%nntot
        k = nnkpts_block(1, i)
        kmesh_info%nnlist(k, nnkpts_idx(k)) = nnkpts_block(2, i)
        kmesh_info%nncell(:, k, nnkpts_idx(k)) = nnkpts_block(3:, i)
        nnkpts_idx(k) = nnkpts_idx(k) + 1
      end do
      ! check that all k-points have the same number of neighbours
      if (any(nnkpts_idx /= (/(kmesh_info%nntot + 1, i=1, num_kpts)/))) then
        call set_error_input(error, 'Inconsistent number of nearest neighbours.', comm)
        return
      end if
      deallocate (nnkpts_idx, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error deallocating nnkpts_idx in w90_wannier90_readwrite_read_explicit_kpts', comm)
        return
      end if
      deallocate (nnkpts_block, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error deallocating nnkpts_block in w90_wannier90_readwrite_read_explicit_kpts', comm)
        return
      end if
    end if

  end subroutine w90_wannier90_readwrite_read_explicit_kpts

  !================================================!
  subroutine w90_wannier90_readwrite_read_projections(settings, proj, proj_input, &
                                                      use_bloch_phases, lhasproj, &
                                                      guiding_centres, select_proj, num_proj, &
                                                      atom_data, recip_lattice, num_wann, &
                                                      gamma_only, spinors, bohr, stdout, error, &
                                                      comm)
    !================================================!
    ! Obtain projector definitions
    use w90_error, only: w90_error_type

    implicit none

    ! arguments
    integer, intent(in) :: num_wann
    integer, intent(inout) :: num_proj
    integer, intent(in) :: stdout
    logical, intent(in) :: gamma_only
    logical, intent(in) :: spinors
    logical, intent(in) :: use_bloch_phases, guiding_centres
    logical, intent(out) :: lhasproj
    real(kind=dp), intent(in) :: bohr
    real(kind=dp), intent(in) :: recip_lattice(3, 3)
    type(atom_data_type), intent(in) :: atom_data
    type(proj_type), allocatable, intent(inout) :: proj(:), proj_input(:)
    type(select_projection_type), intent(inout) :: select_proj
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error

    ! local variables
    integer :: i, j, i_temp, loop, ierr
    logical :: found
    ! projections selection
    integer :: num_select_projections
    integer, allocatable :: select_projections(:)
    integer :: imap

    lhasproj = .false.

    ! Projections
    call w90_readwrite_get_keyword(settings, 'auto_projections', found, error, comm, &
                                   l_value=select_proj%auto_projections)
    if (allocated(error)) return

    call w90_readwrite_get_block_length(settings, 'projections', found, i_temp, error, comm)
    if (allocated(error)) return

    if (found) then
      if (select_proj%auto_projections) then
        call set_error_input(error, 'Error: Cannot specify both auto_projections and projections block', comm)
        return
      end if
      lhasproj = .true.
      call w90_readwrite_get_projections(settings, num_proj, atom_data, num_wann, proj_input, &
                                         recip_lattice, .true., spinors, bohr, stdout, error, comm)
      if (allocated(error)) return
      ! num_proj is assigned in get_projections() call
    else
      if (guiding_centres .and. .not. (gamma_only .and. use_bloch_phases)) then
        call set_error_input(error, 'w90_wannier90_readwrite_read: Guiding centres requested, but no projection block found', comm)
        return
      end if
      lhasproj = .false.
      num_proj = num_wann
    end if

    ! attempt to read projections from library interface
    if (allocated(settings%entries)) then
      if (found) then
        call set_error_input(error, 'w90_wannier90_readwrite_read: attempting to read .win file with unspent lib options', comm)
        return
      end if

      if (atom_data%num_species > 0) then
        ! only read projections if atom positions are known
        ! Count pass first: num_proj may exceed num_wann when there are more initial
        ! projections than target Wannier functions (valid for disentanglement).
        ! Without this, input_proj is allocated at size num_wann and overflows.
        call w90_readwrite_get_projections(settings, num_proj, atom_data, num_wann, proj_input, &
                                           recip_lattice, .true., spinors, bohr, stdout, error, comm)
        if (allocated(error)) return
        call w90_readwrite_get_projections(settings, num_proj, atom_data, num_wann, proj_input, &
                                           recip_lattice, .false., spinors, bohr, stdout, error, comm)
        if (allocated(error)) return
        lhasproj = .true.
      end if
    end if

    num_select_projections = num_proj !num proj is the size of proj_input
    call w90_readwrite_get_range_vector(settings, 'select_projections', found, num_select_projections, &
                                        .true., error, comm)
    if (allocated(error)) return

    if (found) then
      if (num_select_projections < 1) then
        call set_error_input(error, 'Error: problem reading select_projections', comm)
        return
      end if
      if (allocated(select_projections)) then
        deallocate (select_projections, stat=ierr)
        if (ierr /= 0) then
          call set_error_dealloc(error, 'Error deallocating select_projections &
          & in w90_wannier90_readwrite_read_projections', comm)
          return
        end if
      end if
      allocate (select_projections(num_select_projections), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating select_projections in w90_wannier90_readwrite_read_projections', comm)
        return
      end if
      call w90_readwrite_get_range_vector(settings, 'select_projections', found, num_select_projections, &
                                          .false., error, comm, select_projections)
      if (allocated(error)) return

      if (any(select_projections < 1)) then
        call set_error_input(error, 'Error: select_projections must contain positive numbers', comm)
        return
      end if
      if (num_select_projections < num_wann) then
        call set_error_input(error, 'Error: too few projections selected', comm)
        return
      end if
      if (num_select_projections > num_wann) then
        call set_error_input(error, 'Error: too many projections selected', comm)
        return
      end if
      if (.not. lhasproj) then
        call set_error_input(error, 'Error: select_projections cannot be used without defining the projections', comm)
        return
      end if
      if (maxval(select_projections(:)) > num_proj) then
        call set_error_input(error, 'Error: select_projections contains a number greater than num_proj', comm)
        return
      end if
      select_proj%lselproj = .true.
    end if ! found 'select_projections'

    if (allocated(select_proj%proj2wann_map)) then
      deallocate (select_proj%proj2wann_map, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error deallocating proj2wann_map in w90_wannier90_readwrite_read_projections', comm)
        return
      end if
    end if
    allocate (select_proj%proj2wann_map(num_proj), stat=ierr)
    if (ierr /= 0) then
      call set_error_alloc(error, 'Error allocating proj2wann_map in w90_wannier90_readwrite_read_projections', comm)
      return
    end if
    select_proj%proj2wann_map = -1

    if (select_proj%lselproj) then
      do i = 1, num_proj
        do j = 1, num_select_projections
          if (select_projections(j) == i) select_proj%proj2wann_map(i) = j
        end do
      end do
    else
      do i = 1, num_wann
        select_proj%proj2wann_map(i) = i
      end do
    end if

    if (lhasproj) then
      call w90_readwrite_get_projections(settings, num_proj, atom_data, num_wann, proj_input, &
                                         recip_lattice, .false., spinors, bohr, stdout, error, comm)
      if (allocated(error)) return

      allocate (proj(num_proj), stat=ierr)
      if (ierr /= 0) then
        call set_error_alloc(error, 'Error allocating proj in w90_wannier90_readwrite_read_projections', comm)
        return
      end if
      do loop = 1, num_proj
        imap = select_proj%proj2wann_map(loop)
        if (imap < 0) cycle
        if (imap > num_proj) then
          write (*, *) "logic error, imapping"
          stop
        end if
        proj(imap) = proj_input(loop)
      end do
    end if !lhasproj

  end subroutine w90_wannier90_readwrite_read_projections

  !================================================!
  subroutine w90_wannier90_readwrite_read_constrained_centres(settings, wann_control, &
                                                              real_lattice, num_wann, iprint, &
                                                              stdout, error, comm)
    !================================================!
    implicit none

    integer, intent(in) :: num_wann, iprint, stdout
    real(kind=dp), intent(in) :: real_lattice(3, 3)
    type(settings_type), intent(inout) :: settings
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error
    type(wann_control_type), intent(inout) :: wann_control

    integer :: i_temp
    logical :: found

    ! Constrained centres
    call w90_readwrite_get_block_length(settings, 'slwf_centres', found, i_temp, error, comm)
    if (allocated(error)) return

    if (found) then
      if (wann_control%constrain%constrain) then
        ! Allocate array for constrained centres
        call w90_readwrite_get_centre_constraints(settings, &
                                                  wann_control%constrain%centres, &
                                                  wann_control%guiding_centres%centres, &
                                                  num_wann, real_lattice, error, comm)
        if (allocated(error)) return

      else
        write (stdout, '(a)') ' slwf_constrain set to false. Ignoring <slwf_centres> block '
      end if
      ! Check that either projections or constrained centres are specified if slwf_constrain=.true.
    elseif (.not. found) then
      if (wann_control%constrain%constrain) then
        if (.not. allocated(wann_control%guiding_centres%centres)) then
          call set_error_input(error, 'Error: slwf_constrain = true, but neither <slwf_centre> block  nor &
               & <projection_block> are specified.', comm)
          return
        else
          ! Allocate array for constrained centres
          call w90_readwrite_get_centre_constraints(settings, &
                                                    wann_control%constrain%centres, &
                                                    wann_control%guiding_centres%centres, &
                                                    num_wann, real_lattice, error, comm)
          if (allocated(error)) return

        end if
      end if
    end if

    ! Warning
    if (.not. found) then
      if (wann_control%constrain%constrain .and. allocated(wann_control%guiding_centres%centres)) then
        if (iprint > 0) then
          write (stdout, '(a)') ' Warning: No <slwf_centres> block found, but slwf_constrain set to true. &
          & Desired centres for SLWF same as projection centres.'
        end if
      end if
    end if
  end subroutine w90_wannier90_readwrite_read_constrained_centres

  !================================================!
  subroutine w90_wannier90_readwrite_write(atom_data, band_plot, dis_control, dis_spheres, &
                                           fermi_energy_list, fermi_surface_data, kpt_latt, &
                                           output_file, wvfn_read, wann_control, proj, proj_input, &
                                           real_space_ham, select_proj, kpoint_path, tran, &
                                           print_output, wannier_data, wann_plot, w90_calculation, &
                                           real_lattice, symmetrize_eps, mp_grid, num_bands, &
                                           num_kpts, num_proj, num_wann, optimisation, cp_pp, &
                                           gamma_only, lsitesymmetry, spinors, use_bloch_phases, &
                                           stdout)
    !================================================!
    !
    !! write wannier90 parameters to stdout
    !
    !================================================
    use w90_utility, only: utility_recip_lattice_base, utility_inverse_mat, utility_cart_to_frac, &
                           utility_frac_to_cart

    implicit none

    !passed vaiables
    type(w90_calculation_type), intent(in) :: w90_calculation
    type(output_file_type), intent(in) :: output_file
    type(real_space_ham_type), intent(in) :: real_space_ham
    type(wvfn_read_type), intent(in) :: wvfn_read
    type(print_output_type), intent(in) :: print_output
    type(band_plot_type), intent(in) :: band_plot
    type(wann_control_type), intent(in) :: wann_control
    type(wannier_data_type), intent(in) :: wannier_data
    type(dis_control_type), intent(in) :: dis_control
    type(dis_spheres_type), intent(in) :: dis_spheres
    type(fermi_surface_plot_type), intent(in) :: fermi_surface_data
    type(transport_type), intent(in) :: tran
    type(atom_data_type), intent(in) :: atom_data
    type(select_projection_type), intent(in) :: select_proj
    type(proj_type), allocatable, intent(in) :: proj_input(:)
    type(kpoint_path_type), intent(in) :: kpoint_path
    type(wannier_plot_type), intent(in) :: wann_plot
    type(proj_type), allocatable, intent(in) :: proj(:)

    integer, intent(in) :: num_bands
    integer, intent(in) :: num_wann
    integer, intent(in) :: stdout
    integer, intent(in) :: mp_grid(3)
    integer, intent(in) :: num_proj
    integer, intent(in) :: num_kpts
    integer, intent(in) :: optimisation

    real(kind=dp), intent(in) :: real_lattice(3, 3)
    real(kind=dp), intent(in) :: symmetrize_eps
    real(kind=dp), intent(in) :: kpt_latt(:, :)
    real(kind=dp), allocatable, intent(in) :: fermi_energy_list(:)

    ! RS: symmetry-adapted Wannier functions
    logical, intent(in) :: lsitesymmetry
    logical, intent(in) :: cp_pp, use_bloch_phases
    logical, intent(in) :: gamma_only
    logical, intent(in) :: spinors

    ! local variables
    character(len=4) :: one_dim_axis
    integer :: i, nkp, loop, nat, nsp, bands_num_spec_points
    logical :: disentanglement
    real(kind=dp) :: ccentres_frac(3)
    real(kind=dp) :: cell_volume
    real(kind=dp) :: recip_lattice(3, 3), inv_lattice(3, 3), pos_frac(3), kpt_cart(3), volume

    disentanglement = (num_bands > num_wann)

    ! `one_dim_axis` is only meaningful when the system is treated as reduced-
    ! dimensional, but it is printed unconditionally below (for any run with
    ! transport enabled or iprint > 2). Without a default it would be written
    ! while undefined whenever the input does not set `one_dim_axis`.
    one_dim_axis = 'none'
    if (real_space_ham%one_dim_dir == 1) one_dim_axis = 'x'
    if (real_space_ham%one_dim_dir == 2) one_dim_axis = 'y'
    if (real_space_ham%one_dim_dir == 3) one_dim_axis = 'z'

    call utility_inverse_mat(real_lattice, inv_lattice)

    ! skip most printout if (w90_calculation%transport .and. tran%read_ht); continues with transport at end

    if (print_output%iprint > 0 .and. .not. (w90_calculation%transport .and. tran%read_ht)) then

      ! System
      write (stdout, *)
      write (stdout, '(36x,a6)') '------'
      write (stdout, '(36x,a6)') 'SYSTEM'
      write (stdout, '(36x,a6)') '------'
      write (stdout, *)
      if (trim(print_output%length_unit) == 'Ang') then
        write (stdout, '(30x,a21)') 'Lattice Vectors (Ang)'
      else
        write (stdout, '(28x,a22)') 'Lattice Vectors (Bohr)'
      end if
      write (stdout, 101) 'a_1', (real_lattice(1, I)*print_output%lenconfac, i=1, 3)
      write (stdout, 101) 'a_2', (real_lattice(2, I)*print_output%lenconfac, i=1, 3)
      write (stdout, 101) 'a_3', (real_lattice(3, I)*print_output%lenconfac, i=1, 3)
      write (stdout, *)
      cell_volume = real_lattice(1, 1)*(real_lattice(2, 2)*real_lattice(3, 3) - real_lattice(3, 2)*real_lattice(2, 3)) + &
                    real_lattice(1, 2)*(real_lattice(2, 3)*real_lattice(3, 1) - real_lattice(3, 3)*real_lattice(2, 1)) + &
                    real_lattice(1, 3)*(real_lattice(2, 1)*real_lattice(3, 2) - real_lattice(3, 1)*real_lattice(2, 2))
      write (stdout, '(19x,a17,3x,f11.5)', advance='no') &
        'Unit Cell Volume:', cell_volume*print_output%lenconfac**3
      if (trim(print_output%length_unit) == 'Ang') then
        write (stdout, '(2x,a7)') '(Ang^3)'
      else
        write (stdout, '(2x,a8)') '(Bohr^3)'
      end if
      write (stdout, *)
      if (trim(print_output%length_unit) == 'Ang') then
        write (stdout, '(24x,a33)') 'Reciprocal-Space Vectors (Ang^-1)'
      else
        write (stdout, '(22x,a34)') 'Reciprocal-Space Vectors (Bohr^-1)'
      end if
      call utility_recip_lattice_base(real_lattice, recip_lattice, volume)
      write (stdout, 101) 'b_1', (recip_lattice(1, I)/print_output%lenconfac, i=1, 3)
      write (stdout, 101) 'b_2', (recip_lattice(2, I)/print_output%lenconfac, i=1, 3)
      write (stdout, 101) 'b_3', (recip_lattice(3, I)/print_output%lenconfac, i=1, 3)
      write (stdout, *) ' '
      ! Atoms
      if (atom_data%num_atoms > 0) then
        write (stdout, '(1x,a)') '*----------------------------------------------------------------------------*'
        if (trim(print_output%length_unit) == 'Ang') then
          write (stdout, '(1x,a)') '|   Site       Fractional Coordinate          Cartesian Coordinate (Ang)     |'
        else
          write (stdout, '(1x,a)') '|   Site       Fractional Coordinate          Cartesian Coordinate (Bohr)    |'
        end if
        write (stdout, '(1x,a)') '+----------------------------------------------------------------------------+'
        do nsp = 1, atom_data%num_species
          do nat = 1, atom_data%species_num(nsp)
            call utility_cart_to_frac(atom_data%pos_cart(:, nat, nsp), pos_frac, inv_lattice)
            write (stdout, '(1x,a1,1x,a2,1x,i3,3F10.5,3x,a1,1x,3F10.5,4x,a1)') &
    &                 '|', atom_data%symbol(nsp), nat, pos_frac(:),&
    &                 '|', atom_data%pos_cart(:, nat, nsp)*print_output%lenconfac, '|'
          end do
        end do
        write (stdout, '(1x,a)') '*----------------------------------------------------------------------------*'
      else
        write (stdout, '(25x,a)') 'No atom positions specified'
      end if
      ! Constrained centres
      if (wann_control%constrain%selective_loc .and. &
          wann_control%constrain%constrain) then
        write (stdout, *) ' '
        write (stdout, '(1x,a)') '*----------------------------------------------------------------------------*'
        write (stdout, '(1x,a)') '| Wannier#        Original Centres              Constrained centres          |'
        write (stdout, '(1x,a)') '+----------------------------------------------------------------------------+'
        do i = 1, wann_control%constrain%slwf_num
          call utility_cart_to_frac(wann_control%constrain%centres(i, :), ccentres_frac, inv_lattice)
          ! note, this printout is in crystal coordinates; not sure why wannier_centres are printed here??
          write (stdout, '(1x,a1,2x,i3,2x,3F10.5,3x,a1,1x,3F10.5,4x,a1)') &
    &                    '|', i, ccentres_frac(:), '|', wannier_data%centres(:, i), '|'
        end do
        write (stdout, '(1x,a)') '*----------------------------------------------------------------------------*'
      end if
      ! Projections
      if (print_output%iprint > 1 .and. allocated(proj_input)) then
        write (stdout, '(32x,a)') '-----------'
        write (stdout, '(32x,a)') 'PROJECTIONS'
        write (stdout, '(32x,a)') '-----------'
        write (stdout, *) ' '
        write (stdout, '(1x,a)') '+----------------------------------------------------------------------------+'
        write (stdout, '(1x,a)') '|     Frac. Coord.   l mr  r        z-axis               x-axis          Z/a |'
        write (stdout, '(1x,a)') '+----------------------------------------------------------------------------+'
        do nsp = 1, num_proj
          write (stdout, '(1x,a1,3(1x,f5.2),1x,i2,1x,i2,1x,i2,3(1x,f6.3),3(1x,f6.3),2x,f4.1,1x,a1)') &
            '|', proj_input(nsp)%site(1), proj_input(nsp)%site(2), &
            proj_input(nsp)%site(3), proj_input(nsp)%l, &
            proj_input(nsp)%m, proj_input(nsp)%radial, &
            proj_input(nsp)%z(1), proj_input(nsp)%z(2), &
            proj_input(nsp)%z(3), proj_input(nsp)%x(1), &
            proj_input(nsp)%x(2), proj_input(nsp)%x(3), &
            proj_input(nsp)%zona, '|'
        end do
        write (stdout, '(1x,a)') '+----------------------------------------------------------------------------+'
        write (stdout, *) ' '
      end if

      if (print_output%iprint > 1 .and. select_proj%lselproj .and. &
          allocated(wann_control%guiding_centres%centres)) then
        write (stdout, '(30x,a)') '--------------------'
        write (stdout, '(30x,a)') 'SELECTED PROJECTIONS'
        write (stdout, '(30x,a)') '--------------------'
        write (stdout, *) ' '
        write (stdout, '(1x,a)') '+----------------------------------------------------------------------------+'
        write (stdout, '(1x,a)') '|     Frac. Coord.   l mr  r        z-axis               x-axis          Z/a |'
        write (stdout, '(1x,a)') '+----------------------------------------------------------------------------+'
        do nsp = 1, num_wann
          if (select_proj%proj2wann_map(nsp) < 0) cycle
          write (stdout, '(1x,a1,3(1x,f5.2),1x,i2,1x,i2,1x,i2,3(1x,f6.3),3(1x,f6.3),2x,f4.1,1x,a1)')&
              &              '|', wann_control%guiding_centres%centres(1, nsp), &
              wann_control%guiding_centres%centres(2, nsp), &
              wann_control%guiding_centres%centres(3, nsp), proj(nsp)%l, &
              proj(nsp)%m, proj(nsp)%radial, &
               proj(nsp)%z(1), proj(nsp)%z(2), proj(nsp)%z(3), proj(nsp)%x(1), &
               proj(nsp)%x(2), proj(nsp)%x(3), proj(nsp)%zona, '|'
        end do
        write (stdout, '(1x,a)') '+----------------------------------------------------------------------------+'
        write (stdout, *) ' '
      end if

      ! K-points
      write (stdout, '(32x,a)') '------------'
      write (stdout, '(32x,a)') 'K-POINT GRID'
      write (stdout, '(32x,a)') '------------'
      write (stdout, *) ' '
      write (stdout, '(13x,a,i3,1x,a1,i3,1x,a1,i3,6x,a,i5)') 'Grid size =', mp_grid(1), 'x', mp_grid(2), 'x', mp_grid(3), &
        'Total points =', num_kpts
      write (stdout, *) ' '
      if (print_output%iprint > 1) then
        write (stdout, '(1x,a)') '*----------------------------------------------------------------------------*'
        if (trim(print_output%length_unit) == 'Ang') then
          write (stdout, '(1x,a)') '| k-point      Fractional Coordinate        Cartesian Coordinate (Ang^-1)    |'
        else
          write (stdout, '(1x,a)') '| k-point      Fractional Coordinate        Cartesian Coordinate (Bohr^-1)   |'
        end if
        write (stdout, '(1x,a)') '+----------------------------------------------------------------------------+'
        do nkp = 1, num_kpts
          call utility_frac_to_cart(kpt_latt(:, nkp), kpt_cart, recip_lattice)
          write (stdout, '(1x,a1,i6,1x,3F10.5,3x,a1,1x,3F10.5,4x,a1)') '|', nkp, kpt_latt(:, nkp), '|', &
            kpt_cart(:)/print_output%lenconfac, '|'
        end do
        write (stdout, '(1x,a)') '*----------------------------------------------------------------------------*'
        write (stdout, *) ' '
      end if
      ! Main
      write (stdout, *) ' '
      write (stdout, '(1x,a78)') '*---------------------------------- MAIN ------------------------------------*'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Number of Wannier Functions               :', num_wann, '|'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Number of Objective Wannier Functions     :', &
        wann_control%constrain%slwf_num, '|'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Number of input Bloch states              :', num_bands, '|'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Output verbosity (1=low, 5=high)          :', print_output%iprint, '|'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Timing Level (1=low, 5=high)              :', print_output%timing_level, '|'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Optimisation (0=memory, 3=speed)          :', optimisation, '|'
      write (stdout, '(1x,a46,10x,a8,13x,a1)') '|  Length Unit                               :', trim(print_output%length_unit), '|'
      write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Post-processing setup (write *.nnkp)      :', &
        w90_calculation%postproc_setup, '|'
      write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Using Gamma-only branch of algorithms     :', gamma_only, '|'
      !YN: RS:
      if (lsitesymmetry) then
        write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Using symmetry-adapted WF mode            :', lsitesymmetry, '|'
        write (stdout, '(1x,a46,8x,E10.3,13x,a1)') '|  Tolerance for symmetry condition on U     :', symmetrize_eps, '|'
      end if

      if (cp_pp .or. print_output%iprint > 2) &
        write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  CP code post-processing                   :', &
        cp_pp, '|'
      if (w90_calculation%wannier_plot .or. print_output%iprint > 2) then
        if (wvfn_read%formatted) then
          write (stdout, '(1x,a46,9x,a9,13x,a1)') '|  Wavefunction (UNK) file-type              :', 'formatted', '|'
        else
          write (stdout, '(1x,a46,7x,a11,13x,a1)') '|  Wavefunction (UNK) file-type              :', 'unformatted', '|'
        end if
        if (wvfn_read%spin_channel == 1) then
          write (stdout, '(1x,a46,16x,a2,13x,a1)') '|  Wavefunction spin channel                 :', 'up', '|'
        else
          write (stdout, '(1x,a46,14x,a4,13x,a1)') '|  Wavefunction spin channel                 :', 'down', '|'
        end if
      end if

      write (stdout, '(1x,a78)') '*----------------------------------------------------------------------------*'

      ! Wannierise
      write (stdout, '(1x,a78)') '*------------------------------- WANNIERISE ---------------------------------*'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Total number of iterations                :', &
        wann_control%num_iter, '|'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Number of CG steps before reset           :', &
        wann_control%num_cg_steps, '|'
      if (wann_control%lfixstep) then
        write (stdout, '(1x,a46,10x,f8.3,13x,a1)') '|  Fixed step length for minimisation        :', &
          wann_control%fixed_step, '|'
      else
        write (stdout, '(1x,a46,10x,f8.3,13x,a1)') '|  Trial step length for line search         :', &
          wann_control%trial_step, '|'
      end if
      write (stdout, '(1x,a46,8x,E10.3,13x,a1)') '|  Convergence tolerence                     :', &
        wann_control%conv_tol, '|'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Convergence window                        :', &
        wann_control%conv_window, '|'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Iterations between writing output         :', &
        wann_control%num_print_cycles, '|'
      write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Iterations between backing up to disk     :', &
        wann_control%num_dump_cycles, '|'
      write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Write r^2_nm to file                      :', &
        output_file%write_r2mn, '|'
      write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Write xyz WF centres to file              :', &
        output_file%write_xyz, '|'
      write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Write on-site energies <0n|H|0n> to file  :', &
        output_file%write_hr_diag, '|'
      write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Use guiding centre to control phases      :', &
        wann_control%guiding_centres%enable, '|'
      write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Use phases for initial projections        :', &
        use_bloch_phases, '|'
      if (wann_control%guiding_centres%enable .or. print_output%iprint > 2) then
        write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Iterations before starting guiding centres:', &
          wann_control%guiding_centres%num_no_guide_iter, '|'
        write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Iterations between using guiding centres  :', &
          wann_control%guiding_centres%num_guide_cycles, '|'
      end if
      if (wann_control%constrain%selective_loc .or. print_output%iprint > 2) then
        write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Perform selective localization            :', &
          wann_control%constrain%selective_loc, '|'
      end if
      if (wann_control%constrain%constrain .or. print_output%iprint > 2) then
        write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Use constrains in selective localization  :', &
          wann_control%constrain%constrain, '|'
        write (stdout, '(1x,a46,8x,E10.3,13x,a1)') '|  Value of the Lagrange multiplier          :',&
             &wann_control%constrain%lambda, '|'
      end if
      write (stdout, '(1x,a78)') '*----------------------------------------------------------------------------*'
      !
      ! Disentanglement
      !
      if (disentanglement .or. print_output%iprint > 2) then
        write (stdout, '(1x,a78)') '*------------------------------- DISENTANGLE --------------------------------*'
        write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Using band disentanglement                :', &
          disentanglement, '|'
        write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Total number of iterations                :', dis_control%num_iter, '|'
        write (stdout, '(1x,a46,10x,F8.3,13x,a1)') '|  Mixing ratio                              :', dis_control%mix_ratio, '|'
        write (stdout, '(1x,a46,8x,ES10.3,13x,a1)') '|  Convergence tolerence                     :', dis_control%conv_tol, '|'
        write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Convergence window                        :', dis_control%conv_window, '|'
        ! GS-start
        if (dis_spheres%num .gt. 0) then
          write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Number of spheres in k-space              :', dis_spheres%num, '|'
          do nkp = 1, dis_spheres%num
            write (stdout, '(1x,a13,I4,a2,2x,3F8.3,a15,F8.3,9x,a1)') &
              '|   center n.', nkp, ' :', dis_spheres%spheres(1:3, nkp), ',    radius   =', dis_spheres%spheres(4, nkp), '|'
          end do
          write (stdout, '(1x,a46,10x,I8,13x,a1)') '|  Index of first Wannier band               :', &
            dis_spheres%first_wann, '|'
        end if
        ! GS-end
        write (stdout, '(1x,a78)') '*----------------------------------------------------------------------------*'
      end if
      !
      ! Plotting
      !
      if (w90_calculation%wannier_plot .or. w90_calculation%bands_plot .or. w90_calculation%fermi_surface_plot &
          .or. output_file%write_hr .or. print_output%iprint > 2) then
        !
        write (stdout, '(1x,a78)') '*-------------------------------- PLOTTING ----------------------------------*'
        !
        if (w90_calculation%wannier_plot .or. print_output%iprint > 2) then
          write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Plotting Wannier functions                :', &
            w90_calculation%wannier_plot, '|'
          write (stdout, '(1x,a46,1x,I5,a1,I5,a1,I5,13x,a1)') &
            '|   Size of supercell for plotting           :', &
            wann_plot%supercell(1), 'x', wann_plot%supercell(2), 'x', wann_plot%supercell(3), '|'

          if (real_space_ham%translate_home_cell) then
            write (stdout, '(1x,a46,10x,L8,13x,a1)') &
              '|  Translating WFs to home cell              :', real_space_ham%translate_home_cell, '|'
          end if

          write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   Plotting mode (molecule or crystal)      :', &
            trim(wann_plot%mode), '|'
          if (spinors) then
            write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   Plotting mode for spinor WFs             :', &
              trim(wann_plot%spinor_mode), '|'
            write (stdout, '(1x,a46,10x,L8,13x,a1)') '|   Include phase for spinor WFs             :', &
              wann_plot%spinor_phase, '|'
          end if
          write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   Plotting format                          :', &
            trim(wann_plot%format), '|'
          if (index(wann_plot%format, 'cub') > 0 .or. print_output%iprint > 2) then
            write (stdout, '(1x,a46,10x,F8.3,13x,a1)') '|   Plot radius                              :', &
              wann_plot%radius, '|'
            write (stdout, '(1x,a46,10x,F8.3,13x,a1)') '|   Plot scale                               :', &
              wann_plot%scale, '|'
          end if
          write (stdout, '(1x,a78)') '*----------------------------------------------------------------------------*'
        end if
        !
        if (w90_calculation%fermi_surface_plot .or. print_output%iprint > 2) then
          write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Plotting Fermi surface                    :', &
            w90_calculation%fermi_surface_plot, '|'
          write (stdout, '(1x,a46,10x,I8,13x,a1)') '|   Number of plotting points (along b_1)    :', &
            fermi_surface_data%num_points, '|'
          write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   Plotting format                          :', &
            trim(fermi_surface_data%plot_format), '|'
          write (stdout, '(1x,a78)') '*----------------------------------------------------------------------------*'
        end if
        !
        if (w90_calculation%bands_plot .or. print_output%iprint > 2) then
          write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Plotting interpolated bandstructure       :', w90_calculation%bands_plot, '|'
          bands_num_spec_points = 0
          if (allocated(kpoint_path%labels)) bands_num_spec_points = size(kpoint_path%labels)
          if (kpoint_path%bands_kpt_explicit) then
            write (stdout, '(1x,a46,10x,I8,13x,a1)') '|   Number of high-symmetry points           :', bands_num_spec_points, '|'
            write (stdout, '(1x,a46,10x,I8,13x,a1)') '|   Total number of points along K-path      :', &
              size(kpoint_path%bands_kpt_frac, 2), '|'
          else
            write (stdout, '(1x,a46,10x,I8,13x,a1)') '|   Number of K-path sections                :', &
              bands_num_spec_points/2, '|'
            write (stdout, '(1x,a46,10x,I8,13x,a1)') '|   Divisions along first K-path section     :', &
              kpoint_path%num_points_first_segment, '|'
          end if
          write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   Output format                            :', &
            trim(band_plot%format), '|'
          write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   Output mode                              :', &
            trim(band_plot%mode), '|'
          if (index(band_plot%mode, 'cut') .ne. 0) then
            write (stdout, '(1x,a46,10x,I8,13x,a1)') '|   Dimension of the system                  :', &
              real_space_ham%system_dim, '|'
            if (real_space_ham%system_dim .eq. 1) &
              write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   System extended in                       :', &
              adjustr(one_dim_axis), '|'
            if (real_space_ham%system_dim .eq. 2) &
              write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   System confined in                       :', &
              adjustr(one_dim_axis), '|'
            write (stdout, '(1x,a46,10x,F8.3,13x,a1)') '|   Hamiltonian cut-off value                :', &
              real_space_ham%hr_cutoff, '|'
            write (stdout, '(1x,a46,10x,F8.3,13x,a1)') '|   Hamiltonian cut-off distance             :', &
              real_space_ham%dist_cutoff, '|'
            write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   Hamiltonian cut-off distance mode        :', &
              trim(real_space_ham%dist_cutoff_mode), '|'
          end if
          write (stdout, '(1x,a78)') '*----------------------------------------------------------------------------*'
          if (kpoint_path%bands_kpt_explicit) then
            write (stdout, '(1x,a78)') '|   K-space path high symmetry points:                                       |'
          else
            write (stdout, '(1x,a78)') '|   K-space path sections:                                                   |'
          end if
          if (bands_num_spec_points == 0) then
            write (stdout, '(1x,a78)') '|     None defined                                                           |'
          else
            if (kpoint_path%bands_kpt_explicit) then
              do loop = 1, bands_num_spec_points
                write (stdout, '(1x,a5,a5,1x,3F7.3,a46)') '|    ', kpoint_path%labels(loop), &
                  (kpoint_path%points(i, loop), i=1, 3), '                                             |'
              end do
            else
              do loop = 1, bands_num_spec_points, 2
                write (stdout, '(1x,a10,1x,a5,1x,3F7.3,5x,a3,1x,a5,1x,3F7.3,3x,a1)') '|    From:', &
                  kpoint_path%labels(loop), (kpoint_path%points(i, loop), i=1, 3), &
                  'To:', kpoint_path%labels(loop + 1), (kpoint_path%points(i, loop + 1), i=1, 3), '|'
              end do
            end if
          end if
          write (stdout, '(1x,a78)') '*----------------------------------------------------------------------------*'
        end if
        !
        if (output_file%write_hr .or. print_output%iprint > 2) then
          write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Plotting Hamiltonian in WF basis          :', output_file%write_hr, '|'
          write (stdout, '(1x,a78)') '*----------------------------------------------------------------------------*'
        end if
        if (output_file%write_vdw_data .or. print_output%iprint > 2) then
          write (stdout, '(1x,a46,10x,L8,13x,a1)') '|  Writing data for Van der Waals post-proc  :', &
            output_file%write_vdw_data, '|'
          write (stdout, '(1x,a78)') '*----------------------------------------------------------------------------*'
        end if
        !
      end if
    end if !iprint > 0 and not (transport && read_ht)

    !
    ! Transport
    !
    if (w90_calculation%transport .or. print_output%iprint > 2) then
      !
      write (stdout, '(1x,a78)') '*------------------------------- TRANSPORT ----------------------------------*'
      !
      write (stdout, '(1x,a46,10x,a8,13x,a1)') '|  Transport mode                            :', trim(tran%mode), '|'
      !
      if (tran%read_ht) then
        !
        write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   Hamiltonian from external files          :', 'T', '|'
        !
      else
        !
        write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   Hamiltonian from external files          :', 'F', '|'

        write (stdout, '(1x,a46,10x,a8,13x,a1)') '|   System extended in                       :', &
          adjustr(one_dim_axis), '|'
        !
      end if

      write (stdout, '(1x,a78)') '|   Centre of the unit cell to which WF are translated (fract. coords):      |'
      write (stdout, '(1x,a1,35x,F12.6,a1,F12.6,a1,F12.6,3x,a1)') '|', real_space_ham%translation_centre_frac(1), ',', &
        real_space_ham%translation_centre_frac(2), ',', &
        real_space_ham%translation_centre_frac(3), '|'

      if (size(fermi_energy_list) == 1) then
        write (stdout, '(1x,a46,10x,f8.3,13x,a1)') '|  Fermi energy (eV)                         :', fermi_energy_list(1), '|'
      else
        write (stdout, '(1x,a21,I8,a12,f8.3,a4,f8.3,a3,13x,a1)') '|  Fermi energy     :', size(fermi_energy_list), &
          ' steps from ', fermi_energy_list(1), ' to ', &
          fermi_energy_list(size(fermi_energy_list)), ' eV', '|'
      end if
      !
      write (stdout, '(1x,a78)') '*----------------------------------------------------------------------------*'
      !
    end if

101 format(20x, a3, 2x, 3F11.6)

  end subroutine w90_wannier90_readwrite_write

  !================================================!
  subroutine w90_wannier90_readwrite_w90_dealloc(atom_data, band_plot, dis_spheres, dis_manifold, &
                                                 exclude_bands, kmesh_input, kpt_latt, &
                                                 wann_control, proj, proj_input, select_proj, &
                                                 kpoint_path, wannier_data, wann_plot, eigval, &
                                                 error, comm)
    !================================================!
    use w90_error, only: w90_error_type

    implicit none

    ! arguments
    type(band_plot_type), intent(inout) :: band_plot
    type(wann_control_type), intent(inout) :: wann_control
    type(wannier_data_type), intent(inout) :: wannier_data
    type(kmesh_input_type), intent(inout) :: kmesh_input
    type(dis_spheres_type), intent(inout) :: dis_spheres
    type(dis_manifold_type), intent(inout) :: dis_manifold
    type(atom_data_type), intent(inout) :: atom_data
    type(kpoint_path_type), intent(inout) :: kpoint_path
    type(select_projection_type), intent(inout) :: select_proj
    type(wannier_plot_type), intent(inout) :: wann_plot
    type(proj_type), allocatable, intent(inout) :: proj(:)
    type(proj_type), allocatable, intent(inout) :: proj_input(:)
    type(w90_error_type), allocatable, intent(out) :: error
    type(w90_comm_type), intent(in) :: comm

    integer, allocatable, intent(inout) :: exclude_bands(:)

    real(kind=dp), allocatable, intent(inout) :: eigval(:, :)
    real(kind=dp), allocatable, intent(inout) :: kpt_latt(:, :)

    ! local variables
    integer :: ierr

    call w90_readwrite_dealloc(exclude_bands, wannier_data, proj_input, kmesh_input, kpt_latt, &
                               dis_manifold, atom_data, eigval, kpoint_path, error, comm)
    if (allocated(error)) return

    if (allocated(wann_plot%list)) then
      deallocate (wann_plot%list, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error in deallocating wann_plot%list in w90_wannier90_readwrite_w90_dealloc', comm)
        return
      end if
    end if
    if (allocated(band_plot%project)) then
      deallocate (band_plot%project, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error in deallocating band_plot%project in &
        & w90_wannier90_readwrite_w90_dealloc', comm)
        return
      end if
    end if
    if (allocated(wann_control%guiding_centres%centres)) then
      deallocate (wann_control%guiding_centres%centres, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error in deallocating wann_control%guiding_centres%centres &
        & in w90_wannier90_readwrite_w90_dealloc', comm)
        return
      end if
    end if
    if (allocated(wann_control%constrain%centres)) then
      deallocate (wann_control%constrain%centres, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error deallocating wann_control%constrain%centres &
        & in w90_wannier90_readwrite_w90_dealloc', comm)
        return
      end if
    end if
    if (allocated(proj)) then
      deallocate (proj, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error in deallocating proj in w90_wannier90_readwrite_w90_dealloc', comm)
        return
      end if
    end if
    if (allocated(dis_spheres%spheres)) then
      deallocate (dis_spheres%spheres, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error in deallocating dis_spheres%spheres &
        &  in w90_wannier90_readwrite_w90_dealloc', comm)
        return
      end if
    end if
    if (allocated(select_proj%proj2wann_map)) then
      deallocate (select_proj%proj2wann_map, stat=ierr)
      if (ierr /= 0) then
        call set_error_dealloc(error, 'Error in deallocating select_proj%proj2wann_map &
        & in w90_wannier90_readwrite_w90_dealloc', comm)
        return
      end if
    end if
  end subroutine w90_wannier90_readwrite_w90_dealloc

  !================================================!
  subroutine w90_wannier90_readwrite_write_chkpt(chkpt, 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, iprint, stdout, seedname)
    !================================================!
    !! Write checkpoint file
    !! IMPORTANT! If you change the chkpt format, adapt
    !! accordingly also the w90chk2chk.x utility!
    !! note that this routine writes the full u_matrix and the m_matrix
    !! --remember to gather them from u_matrix_loc and m_matrix_loc first!
    !! (nothing here is parallel)
    !================================================!

    use w90_io, only: io_date
    use w90_utility, only: utility_recip_lattice_base

    implicit none

    ! arguments
    type(wannier_data_type), intent(in) :: wannier_data
    type(kmesh_info_type), intent(in) :: kmesh_info
    type(dis_manifold_type), intent(in) :: dis_manifold

    complex(kind=dp), intent(in) :: m_matrix(:, :, :, :)
    complex(kind=dp), intent(in) :: u_matrix(:, :, :)
    complex(kind=dp), intent(in) :: u_matrix_opt(:, :, :)

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

    integer, allocatable, intent(in) :: exclude_bands(:)
    integer, intent(in) :: mp_grid(3)
    integer, intent(in) :: num_bands
    integer, intent(in) :: num_kpts
    integer, intent(in) :: num_wann
    integer, intent(in) :: stdout, iprint

    character(len=*), intent(in)  :: seedname
    character(len=*), intent(in) :: chkpt

    logical, intent(in) :: have_disentangled

    ! local variables
    integer :: chk_unit, nkp, i, j, k, l, num_exclude_bands
    real(kind=dp) :: recip_lattice(3, 3), volume
    character(len=9) :: cdate, ctime
    character(len=33) :: header
    character(len=20) :: chkpt1

    if (iprint > 0) write (stdout, '(/1x,3a)', advance='no') 'Writing checkpoint file ', trim(seedname), '.chk...'

    call io_date(cdate, ctime)
    header = 'written on '//cdate//' at '//ctime

    open (newunit=chk_unit, file=trim(seedname)//'.chk', form='unformatted')

    write (chk_unit) header                                   ! Date and time
    write (chk_unit) num_bands                                ! Number of bands
    if (allocated(exclude_bands)) then
      num_exclude_bands = size(exclude_bands)
    else
      num_exclude_bands = 0
    end if
    write (chk_unit) num_exclude_bands         ! Number of excluded bands
    write (chk_unit) (exclude_bands(i), i=1, num_exclude_bands) ! Excluded bands
    write (chk_unit) ((real_lattice(i, j), i=1, 3), j=1, 3)        ! Real lattice
    call utility_recip_lattice_base(real_lattice, recip_lattice, volume)
    write (chk_unit) ((recip_lattice(i, j), i=1, 3), j=1, 3)       ! Reciprocal lattice
    write (chk_unit) num_kpts                                 ! Number of k-points
    write (chk_unit) (mp_grid(i), i=1, 3)                       ! M-P grid
    write (chk_unit) ((kpt_latt(i, nkp), i=1, 3), nkp=1, num_kpts) ! K-points
    write (chk_unit) kmesh_info%nntot                  ! Number of nearest k-point neighbours
    write (chk_unit) num_wann               ! Number of wannier functions
    chkpt1 = adjustl(trim(chkpt))
    write (chk_unit) chkpt1                 ! Position of checkpoint
    write (chk_unit) have_disentangled      ! Whether a disentanglement has been performed
    if (have_disentangled) then
      write (chk_unit) omega_invariant     ! Omega invariant
      ! lwindow, ndimwin and U_matrix_opt
      write (chk_unit) ((dis_manifold%lwindow(i, nkp), i=1, num_bands), nkp=1, num_kpts)
      write (chk_unit) (dis_manifold%ndimwin(nkp), nkp=1, num_kpts)
      write (chk_unit) (((u_matrix_opt(i, j, nkp), i=1, num_bands), j=1, num_wann), nkp=1, num_kpts)
    end if
    write (chk_unit) (((u_matrix(i, j, k), i=1, num_wann), j=1, num_wann), k=1, num_kpts)               ! U_matrix
    write (chk_unit) ((((m_matrix(i, j, k, l), i=1, num_wann), j=1, num_wann), k=1, kmesh_info%nntot), l=1, num_kpts) ! M_matrix
    write (chk_unit) ((wannier_data%centres(i, j), i=1, 3), j=1, num_wann)
    write (chk_unit) (wannier_data%spreads(i), i=1, num_wann)
    close (chk_unit)

    if (iprint > 0) write (stdout, '(a/)') ' done'

    return

  end subroutine w90_wannier90_readwrite_write_chkpt

  !================================================!
  subroutine w90_wannier90_readwrite_memory_estimate(atom_data, kmesh_info, wann_control, &
                                                     proj_input, print_output, num_bands, &
                                                     num_kpts, num_proj, num_wann, optimisation, &
                                                     gamma_only, stdout)
    !================================================!
    !
    !! Estimate how much memory we will allocate
    !
    !================================================!

    implicit none

    ! arguments
    type(print_output_type), intent(in) :: print_output
    type(wann_control_type), intent(in) :: wann_control
    type(kmesh_info_type), intent(in) :: kmesh_info
    type(proj_type), allocatable, intent(in) :: proj_input(:)
    type(atom_data_type), intent(in) :: atom_data

    integer, intent(in) :: num_bands
    integer, intent(in) :: num_wann
    integer, intent(in) :: stdout
    integer, intent(in) :: num_proj
    integer, intent(in) :: num_kpts
    integer, intent(in) :: optimisation
    logical, intent(in) :: gamma_only

    ! local variables
    real(kind=dp), parameter :: size_log = 1.0_dp
    real(kind=dp), parameter :: size_int = 4.0_dp
    real(kind=dp), parameter :: size_real = 8.0_dp
    real(kind=dp), parameter :: size_cmplx = 16.0_dp
    real(kind=dp) :: mem_wan, mem_wan1, mem_param, mem_dis, mem_dis2, mem_dis1
    real(kind=dp) :: mem_bw
    logical :: disentanglement

    disentanglement = (num_bands > num_wann)
    mem_param = 0
    mem_dis = 0
    mem_dis1 = 0
    mem_dis2 = 0
    mem_wan = 0
    mem_wan1 = 0
    mem_bw = 0

    ! First the data stored in the parameters module
    mem_param = mem_param + num_wann*num_wann*num_kpts*size_cmplx                   !u_matrix
    if (.not. disentanglement) &
      mem_param = mem_param + num_wann*num_wann*kmesh_info%nntot*num_kpts*size_cmplx       !m_matrix

    if (disentanglement) then
      mem_param = mem_param + num_bands*num_wann*num_kpts*size_cmplx             ! u_matrix_opt
    end if

    if (allocated(atom_data%species_num)) then
      mem_param = mem_param + (atom_data%num_species)*size_int                               !atoms_species_num
      mem_param = mem_param + (atom_data%num_species)*size_real                              !atoms_label
      mem_param = mem_param + (atom_data%num_species)*size_real                              !atoms_symbol
      !mem_param = mem_param + (3*maxval(atom_data%species_num)*atom_data%num_species)*size_real  !atoms_pos_frac
      mem_param = mem_param + (3*maxval(atom_data%species_num)*atom_data%num_species)*size_real  !atoms_pos_cart
    end if

    if (allocated(proj_input)) then
      mem_param = mem_param + (3*num_proj)*size_real              !input_proj_site
      mem_param = mem_param + (num_proj)*size_int                !input_proj_l
      mem_param = mem_param + (num_proj)*size_int                 !input_proj_m
      mem_param = mem_param + (3*num_proj)*size_real             !input_proj_z
      mem_param = mem_param + (3*num_proj)*size_real             !input_proj_x
      mem_param = mem_param + (num_proj)*size_real                !input_proj_radial
      mem_param = mem_param + (num_proj)*size_real                !input_proj_zona
    end if

    if (allocated(wann_control%guiding_centres%centres)) then
      mem_param = mem_param + (3*num_wann)*size_real              !proj_site
      mem_param = mem_param + (num_wann)*size_int                !proj_l
      mem_param = mem_param + (num_wann)*size_int                 !proj_m
      mem_param = mem_param + (3*num_wann)*size_real             !proj_z
      mem_param = mem_param + (3*num_wann)*size_real             !proj_x
      mem_param = mem_param + (num_wann)*size_real                !proj_radial
      mem_param = mem_param + (num_wann)*size_real                !proj_zona
    end if

    mem_param = mem_param + num_kpts*kmesh_info%nntot*size_int    !nnlist
    mem_param = mem_param + num_kpts*kmesh_info%nntot/2*size_int  !neigh
    mem_param = mem_param + 3*num_kpts*kmesh_info%nntot*size_int  !nncell
    mem_param = mem_param + kmesh_info%nntot*size_real            !wb
    mem_param = mem_param + 3*kmesh_info%nntot/2*size_real        !bka
    mem_param = mem_param + 3*kmesh_info%nntot*num_kpts*size_real !bk

    mem_param = mem_param + num_bands*num_kpts*size_real             !eigval
    !mem_param = mem_param + 3*num_kpts*size_real                     !kpt_cart
    mem_param = mem_param + 3*num_kpts*size_real                     !kpt_latt
    if (disentanglement) then
      mem_param = mem_param + num_kpts*size_int                     !ndimwin
      mem_param = mem_param + num_bands*num_kpts*size_log           !lwindow
    end if
    mem_param = mem_param + 3*num_wann*size_real                     !wannier_centres
    mem_param = mem_param + num_wann*size_real                       !wannier_spreads

    if (disentanglement) then
      ! Module vars
      mem_dis = mem_dis + num_bands*num_kpts*size_real              !eigval_opt
      mem_dis = mem_dis + num_kpts*size_int                         !nfirstwin
      mem_dis = mem_dis + num_kpts*size_int                         !ndimfroz
      mem_dis = mem_dis + num_bands*num_kpts*size_int               !indxfroz
      mem_dis = mem_dis + num_bands*num_kpts*size_int               !indxnfroz
      mem_dis = mem_dis + num_bands*num_kpts*size_log               !lfrozen

      !the memory high-water wiil occur in dis_extract or when we allocate m_matrix

      mem_dis1 = mem_dis1 + num_wann*num_bands*size_cmplx              !cwb
      mem_dis1 = mem_dis1 + num_wann*num_wann*size_cmplx               !cww
      mem_dis1 = mem_dis1 + num_bands*num_wann*size_cmplx              !cbw
      mem_dis1 = mem_dis1 + 5*num_bands*size_int                       !iwork
      mem_dis1 = mem_dis1 + num_bands*size_int                         !ifail
      mem_dis1 = mem_dis1 + num_bands*size_real                        !w
      if (gamma_only) then
        mem_dis1 = mem_dis1 + (num_bands*(num_bands + 1))/2*size_real    !cap_r
        mem_dis1 = mem_dis1 + 8*num_bands*size_real                    !work
        mem_dis1 = mem_dis1 + num_bands*num_bands*size_real            !rz
      else
        mem_dis1 = mem_dis1 + 7*num_bands*size_real                    !rwork
        mem_dis1 = mem_dis1 + (num_bands*(num_bands + 1))/2*size_cmplx   !cap
        mem_dis1 = mem_dis1 + 2*num_bands*size_cmplx                   !cwork
        mem_dis1 = mem_dis1 + num_bands*num_bands*size_cmplx           !cz
      end if
      mem_dis1 = mem_dis1 + num_kpts*size_real                         !wkomegai1
      mem_dis1 = mem_dis1 + num_bands*num_bands*num_kpts*size_cmplx    !ceamp
      mem_dis1 = mem_dis1 + num_bands*num_bands*num_kpts*size_cmplx    !cham
      mem_dis2 = mem_dis2 + num_wann*num_wann*kmesh_info%nntot*num_kpts*size_cmplx!m_matrix

      if (optimisation <= 0) then
        mem_dis = mem_dis + mem_dis1
      else
        mem_dis = mem_dis + max(mem_dis1, mem_dis2)
      end if

      mem_dis = mem_dis + num_bands*num_bands*kmesh_info%nntot*num_kpts*size_cmplx      ! m_matrix_orig
      mem_dis = mem_dis + num_bands*num_wann*num_kpts*size_cmplx             ! a_matrix

    end if

    !Wannierise

    mem_wan1 = mem_wan1 + (num_wann*num_wann*kmesh_info%nntot*num_kpts)*size_cmplx     !  'm0'
    if (optimisation > 0) then
      mem_wan = mem_wan + mem_wan1
    end if
    mem_wan = mem_wan + (num_wann*num_wann*num_kpts)*size_cmplx           !  'u0'
    mem_wan = mem_wan + (num_wann*kmesh_info%nntot*num_kpts)*size_real    !  'rnkb'
    mem_wan = mem_wan + (num_wann*kmesh_info%nntot*num_kpts)*size_real     !  'ln_tmp'
    mem_wan = mem_wan + (num_wann*kmesh_info%nntot*num_kpts)*size_cmplx    !  'csheet'
    mem_wan = mem_wan + (num_wann*kmesh_info%nntot*num_kpts)*size_real     !  'sheet'
    mem_wan = mem_wan + (3*num_wann)*size_real                             !  'rave'
    mem_wan = mem_wan + (num_wann)*size_real                              !  'r2ave'
    mem_wan = mem_wan + (num_wann)*size_real                               !  'rave2'
    mem_wan = mem_wan + (3*num_wann)*size_real                            !  'rguide'
    mem_wan = mem_wan + (num_wann*num_wann)*size_cmplx                  !  'cz'
    if (gamma_only) then
      mem_wan = mem_wan + num_wann*num_wann*kmesh_info%nntot*2*size_cmplx    ! m_w
      mem_wan = mem_wan + num_wann*num_wann*size_cmplx            ! uc_rot
      mem_wan = mem_wan + num_wann*num_wann*size_real             ! ur_rot
      !internal_svd_omega_i
      mem_wan = mem_wan + 10*num_wann*size_cmplx                   ! cw1
      mem_wan = mem_wan + 10*num_wann*size_cmplx                   ! cw2
      mem_wan = mem_wan + num_wann*num_wann*size_cmplx             ! cv1
      mem_wan = mem_wan + num_wann*num_wann*size_cmplx             ! cv2
      mem_wan = mem_wan + num_wann*num_wann*size_real              ! cpad1
      mem_wan = mem_wan + num_wann*size_cmplx                      ! singvd
    else
      mem_wan = mem_wan + (num_wann)*size_cmplx                              !  'cwschur1'
      mem_wan = mem_wan + (10*num_wann)*size_cmplx                        !  'cwschur2'
      mem_wan = mem_wan + (num_wann)*size_cmplx                              !  'cwschur3'
      mem_wan = mem_wan + (num_wann)*size_cmplx                             !  'cwschur4'
      mem_wan = mem_wan + (num_wann*num_wann*num_kpts)*size_cmplx         !  'cdq'
      mem_wan = mem_wan + (num_wann*num_wann)*size_cmplx                   !  'cmtmp'
      mem_wan = mem_wan + (num_wann*num_wann*num_kpts)*size_cmplx         !  'cdqkeep'
      mem_wan = mem_wan + (num_wann*num_wann)*size_cmplx                      !  'tmp_cdq'
      mem_wan = mem_wan + (num_wann)*size_real                               !  'evals'
      mem_wan = mem_wan + (4*num_wann)*size_cmplx                            !  'cwork'
      mem_wan = mem_wan + (3*num_wann - 2)*size_real                           !  'rwork'
      !d_omega
      mem_wan = mem_wan + (num_wann*num_wann)*size_cmplx   !  'cr'
      mem_wan = mem_wan + (num_wann*num_wann)*size_cmplx    !  'crt'
    end if

    if (disentanglement) &
      mem_wan = mem_wan + num_wann*num_wann*kmesh_info%nntot*num_kpts*size_cmplx       !m_matrix

    if (print_output%iprint > 0) then
      write (stdout, '(1x,a)') '*============================================================================*'
      write (stdout, '(1x,a)') '|                              MEMORY ESTIMATE                               |'
      write (stdout, '(1x,a)') '|         Maximum RAM allocated during each phase of the calculation         |'
      write (stdout, '(1x,a)') '*============================================================================*'
      if (disentanglement) &
        write (stdout, '(1x,"|",24x,a15,f16.2,a,18x,"|")') 'Disentanglement:', (mem_param + mem_dis)/(1024**2), ' Mb'
      write (stdout, '(1x,"|",24x,a15,f16.2,a,18x,"|")') 'Wannierise:', (mem_param + mem_wan)/(1024**2), ' Mb'
      if (optimisation > 0 .and. print_output%iprint > 1) then
        write (stdout, '(1x,a)') '|                                                                            |'
        write (stdout, '(1x,a)') '|   N.B. by setting optimisation=0 memory usage will be reduced to:          |'
        if (disentanglement) &
          write (stdout, '(1x,"|",24x,a15,f16.2,a,18x,"|")') 'Disentanglement:', &
          (mem_param + mem_dis - max(mem_dis1, mem_dis2) + mem_dis1)/(1024**2), ' Mb'
        if (gamma_only) then
          write (stdout, '(1x,"|",24x,a15,f16.2,a,18x,"|")') 'Wannierise:', (mem_param + mem_wan)/(1024**2), ' Mb'
        else
          write (stdout, '(1x,"|",24x,a15,f16.2,a,18x,"|")') 'Wannierise:', &
            (mem_param + mem_wan - mem_wan1)/(1024**2), ' Mb'
        end if
        write (stdout, '(1x,a)') '|   However, this will result in more i/o and slow down the calculation      |'
      end if

      write (stdout, '(1x,"|",24x,a15,f16.2,a,18x,"|")') 'plot_wannier:', (mem_param + mem_wan)/(1024**2), ' Mb'
      write (stdout, '(1x,a)') '*----------------------------------------------------------------------------*'
      write (stdout, *) ' '
    end if

!    if(w90_calculation%disentanglement) then
!       write(*,'(a12,f12.4,a)') 'Disentangle',(mem_param+mem_dis)/(1024**2),' Mb'
!    end if
!    write(*,'(a12,f12.4,a)') 'Wannierise ',(mem_wan+mem_param)/(1024**2),' Mb'
!    write(*,'(a12,f12.4,a)') 'Module',(mem_param)/(1024**2),' Mb'

    return
  end subroutine w90_wannier90_readwrite_memory_estimate

end module w90_wannier90_readwrite