!-*- 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_kpath: evaluate properties along a path in k-space    !
!                                                            !
!------------------------------------------------------------!

module w90_kpath

  !! Calculates quantities along a specified k-path:
  !!
  !!  - Energy bands (eventually colored by the spin)
  !!  - Energy bands (colored by Berry curvature-like
  !!                  term of spin Hall conductivity)
  !!
  !!  - (Berry curvature)x(-1) summed over occupied bands
  !!  - Berry curvature-like term of spin Hall conductivity
  !!    summed over occupied bands
  !!
  !!  - Integrand of orbital magnetization Morb=LCtil+ICtil

  use w90_constants, only: dp
  use w90_error, only: w90_error_type, set_error_alloc, set_error_dealloc, set_error_fatal, &
                       set_error_input, set_error_fatal, set_error_file

  implicit none

  private

  public :: k_path

contains

  !================================================!
  !                   PUBLIC PROCEDURES
  !================================================!

  subroutine k_path(pw90_berry, dis_manifold, fermi_energy_list, kmesh_info, pw90_kpath, kpt_latt, &
                    pw90_oper_read, pw90_band_deriv_degen, pw90_spin, ws_region, kpoint_path, &
                    pw90_spin_hall, print_output, wannier_data, ws_distance, wigner_seitz, AA_R, &
                    BB_R, CC_R, HH_R, SH_R, SHR_R, SR_R, SS_R, SAA_R, SBB_R, v_matrix, u_matrix, &
                    bohr, eigval, real_lattice, scissors_shift, mp_grid, fermi_n, num_wann, &
                    num_bands, num_kpts, num_valence_bands, effective_model, have_disentangled, &
                    seedname, stdout, timer, error, comm)
    !================================================!
    !
    !! Main routine
    !
    !================================================!

    use w90_comms, only: w90_comm_type, mpirank, mpisize, comms_array_split, comms_scatterv, &
                         comms_gatherv, comms_bcast
    use w90_constants, only: dp, eps8
    use w90_get_oper, only: get_HH_R, get_AA_R_effective, get_AA_R, get_BB_R, get_CC_R, get_SS_R, get_SHC_R
    use w90_io, only: io_time
    use w90_postw90_common, only: pw90common_fourier_R_to_k
    use w90_types, only: kpoint_path_type, print_output_type, wannier_data_type, &
                         dis_manifold_type, kmesh_info_type, ws_region_type, ws_distance_type, timer_list_type
    use w90_postw90_types, only: pw90_berry_mod_type, pw90_spin_hall_type, pw90_kpath_mod_type, &
                                 pw90_spin_mod_type, pw90_band_deriv_degen_type, pw90_oper_read_type, wigner_seitz_type
    use w90_berry, only: berry_get_imf_klist, berry_get_imfgh_klist, berry_get_shc_klist
    use w90_spin, only: spin_get_nk
    use w90_utility, only: utility_diagonalize, utility_recip_lattice_base

    implicit none

    ! arguments
    type(pw90_berry_mod_type), intent(in) :: pw90_berry
    type(dis_manifold_type), intent(in) :: dis_manifold
    type(kmesh_info_type), intent(in) :: kmesh_info
    type(pw90_kpath_mod_type), intent(in) :: pw90_kpath
    type(pw90_band_deriv_degen_type), intent(in) :: pw90_band_deriv_degen
    type(pw90_oper_read_type), intent(in) :: pw90_oper_read
    type(pw90_spin_mod_type), intent(in) :: pw90_spin
    type(print_output_type), intent(in) :: print_output
    type(ws_region_type), intent(in) :: ws_region
    type(kpoint_path_type), intent(in) :: kpoint_path
    type(pw90_spin_hall_type), intent(in) :: pw90_spin_hall
    type(w90_comm_type), intent(in) :: comm
    type(wannier_data_type), intent(in) :: wannier_data
    type(wigner_seitz_type), intent(inout) :: wigner_seitz
    type(ws_distance_type), intent(inout) :: ws_distance
    type(timer_list_type), intent(inout) :: timer
    type(w90_error_type), allocatable, intent(out) :: error

    complex(kind=dp), allocatable, intent(inout) :: AA_R(:, :, :, :) ! <0n|r|Rm>
    complex(kind=dp), allocatable, intent(inout) :: BB_R(:, :, :, :) ! <0|H(r-R)|R>
    complex(kind=dp), allocatable, intent(inout) :: CC_R(:, :, :, :, :) ! <0|r_alpha.H(r-R)_beta|R>
    complex(kind=dp), allocatable, intent(inout) :: HH_R(:, :, :) !  <0n|r|Rm>
    complex(kind=dp), allocatable, intent(inout) :: SH_R(:, :, :, :) ! <0n|sigma_x,y,z.H|Rm>
    complex(kind=dp), allocatable, intent(inout) :: SHR_R(:, :, :, :, :) ! <0n|sigma_x,y,z.H.(r-R)_alpha|Rm>
    complex(kind=dp), allocatable, intent(inout) :: SR_R(:, :, :, :, :) ! <0n|sigma_x,y,z.(r-R)_alpha|Rm>
    complex(kind=dp), allocatable, intent(inout) :: SS_R(:, :, :, :) ! <0n|sigma_x,y,z|Rm>
    complex(kind=dp), allocatable, intent(inout) :: SAA_R(:, :, :, :, :) !<0n|sigma_x,y,z.(r-R)_alpha|Rm>
    complex(kind=dp), allocatable, intent(inout) :: SBB_R(:, :, :, :, :) !<0n|sigma_x,y,z.H.(r-R)_alpha|Rm>
    complex(kind=dp), intent(in) :: v_matrix(:, :, :), u_matrix(:, :, :)

    real(kind=dp), intent(in) :: bohr
    real(kind=dp), intent(in) :: eigval(:, :)
    real(kind=dp), intent(in) :: real_lattice(3, 3)
    real(kind=dp), intent(in) :: scissors_shift
    real(kind=dp), allocatable, intent(in) :: fermi_energy_list(:)
    real(kind=dp), intent(in) :: kpt_latt(:, :)

    integer, intent(in) :: mp_grid(3)
    integer, intent(in) :: num_wann, num_bands, num_kpts, num_valence_bands, fermi_n
    integer, intent(in) :: stdout

    character(len=50), intent(in)  :: seedname
    logical, intent(in) :: have_disentangled
    logical, intent(in) :: effective_model

    ! local variables
    real(kind=dp)     :: recip_lattice(3, 3), volume
    integer           :: i, j, n, num_paths, num_spts, loop_kpt, &
                         total_pts, loop_i, dataunit, gnuunit, pyunit, &
                         my_num_pts
    real(kind=dp)     :: ymin, ymax, kpt(3), spn_k(num_wann), &
                         imf_k_list(3, 3, fermi_n), img_k_list(3, 3, fermi_n), &
                         imh_k_list(3, 3, fermi_n), Morb_k(3, 3), &
                         range, zmin, zmax
    real(kind=dp)     :: shc_k_band(num_wann), shc_k_fermi(fermi_n)
    real(kind=dp), allocatable :: kpath_len(:)
    logical           :: plot_bands, plot_curv, plot_morb, plot_shc
    character(len=120) :: file_name

    complex(kind=dp), allocatable :: HH(:, :)
    complex(kind=dp), allocatable :: UU(:, :)
    real(kind=dp), allocatable    :: xval(:), eig(:, :), my_eig(:, :), &
                                     curv(:, :), my_curv(:, :), &
                                     morb(:, :), my_morb(:, :), &
                                     color(:, :), my_color(:, :), &
                                     plot_kpoint(:, :), my_plot_kpoint(:, :), &
                                     shc(:), my_shc(:)
    character(len=3), allocatable  :: glabel(:)

    integer, allocatable :: counts(:), displs(:)
    logical :: on_root = .false.
    integer :: my_node_id, num_nodes

    my_node_id = mpirank(comm)
    num_nodes = mpisize(comm)
    allocate (counts(0:num_nodes - 1))
    allocate (displs(0:num_nodes - 1))
    if (my_node_id == 0) on_root = .true.

    ! Everything is done on the root node (not worthwhile parallelizing)
    ! However, we still have to read and distribute the data if we
    ! are in parallel. So calls to get_oper are done on all nodes at the moment

    plot_bands = index(pw90_kpath%task, 'bands') > 0
    plot_curv = index(pw90_kpath%task, 'curv') > 0
    plot_morb = index(pw90_kpath%task, 'morb') > 0
    plot_shc = index(pw90_kpath%task, 'shc') > 0

    if (on_root) then
      if (plot_shc .or. (plot_bands .and. pw90_kpath%bands_colour == 'shc')) then
        ! not allowed to use adpt smr, since adpt smr needs berry_kmesh,
        ! see line 1837 of berry.F90
        if (pw90_berry%kubo_smearing%use_adaptive) then
          call set_error_input(error, 'Error: Must use fixed smearing when plotting spin Hall conductivity', comm)
          return
        end if
      end if
      if (plot_shc) then
        if (fermi_n == 0) then
          call set_error_input(error, 'Error: must specify Fermi energy', comm)
          return
        else if (fermi_n /= 1) then
          call set_error_input(error, 'Error: kpath plot only accept one Fermi energy, ' &
                               //'use fermi_energy instead of fermi_energy_min', comm)
          return
        end if
      end if
    end if

    call k_path_print_info(plot_bands, plot_curv, plot_morb, plot_shc, fermi_energy_list, &
                           pw90_kpath, pw90_berry%curv_unit, stdout, error, comm)
    if (allocated(error)) return

    ! Set up the needed Wannier matrix elements

    call get_HH_R(dis_manifold, kpt_latt, print_output, wigner_seitz, HH_R, u_matrix, v_matrix, &
                  eigval, real_lattice, scissors_shift, num_bands, num_kpts, num_wann, &
                  num_valence_bands, effective_model, have_disentangled, seedname, ws_distance, ws_region, &
                  stdout, timer, error, comm)
    if (allocated(error)) return

    if (plot_curv .or. plot_morb) then
      if (effective_model) then
        call get_AA_R_effective(print_output, AA_R, HH_R, wigner_seitz%nrpts, num_wann, seedname, &
                                stdout, timer, error, comm)
      else
        call get_AA_R(pw90_berry, dis_manifold, kmesh_info, kpt_latt, print_output, wannier_data, AA_R, &
                      v_matrix, eigval, wigner_seitz, ws_distance, ws_region, num_bands, num_kpts, &
                      num_wann, have_disentangled, seedname, stdout, timer, error, comm)
      end if
      if (allocated(error)) return

    end if
    if (plot_morb) then

      call get_BB_R(pw90_berry, dis_manifold, kmesh_info, kpt_latt, print_output, HH_R, BB_R, v_matrix, &
                    eigval, scissors_shift, wigner_seitz, ws_distance, ws_region, num_bands, num_kpts, &
                    num_wann, have_disentangled, seedname, stdout, timer, error, comm)
      if (allocated(error)) return

      call get_CC_R(pw90_berry, dis_manifold, kmesh_info, kpt_latt, print_output, pw90_oper_read, &
                    HH_R, BB_R, CC_R, v_matrix, eigval, scissors_shift, wigner_seitz, ws_distance, &
                    ws_region, num_bands, num_kpts, num_wann, have_disentangled, seedname, stdout, &
                    timer, error, comm)
      if (allocated(error)) return

    end if

    if (plot_shc .or. (plot_bands .and. pw90_kpath%bands_colour == 'shc')) then

      if (effective_model) then
        call get_AA_R_effective(print_output, AA_R, HH_R, wigner_seitz%nrpts, num_wann, seedname, &
                                stdout, timer, error, comm)
      else
        call get_AA_R(pw90_berry, dis_manifold, kmesh_info, kpt_latt, print_output, wannier_data, AA_R, &
                      v_matrix, eigval, wigner_seitz, ws_distance, ws_region, num_bands, num_kpts, &
                      num_wann, have_disentangled, seedname, stdout, timer, error, comm)
      end if
      if (allocated(error)) return

      call get_SS_R(dis_manifold, kpt_latt, print_output, pw90_oper_read, SS_R, v_matrix, eigval, &
                    wigner_seitz, ws_distance, ws_region, num_bands, num_kpts, num_wann, &
                    have_disentangled, seedname, stdout, timer, error, comm)
      if (allocated(error)) return

      call get_SHC_R(dis_manifold, kmesh_info, kpt_latt, print_output, pw90_oper_read, &
                     pw90_spin_hall, SH_R, SHR_R, SR_R, v_matrix, eigval, scissors_shift, &
                     wigner_seitz, ws_distance, ws_region, num_bands, num_kpts, num_wann, &
                     num_valence_bands, have_disentangled, seedname, stdout, timer, error, comm)
      if (allocated(error)) return

    end if

    if (plot_bands .and. pw90_kpath%bands_colour == 'spin') then
      call get_SS_R(dis_manifold, kpt_latt, print_output, pw90_oper_read, SS_R, v_matrix, eigval, &
                    wigner_seitz, ws_distance, ws_region, num_bands, num_kpts, num_wann, &
                    have_disentangled, seedname, stdout, timer, error, comm)
      if (allocated(error)) return

    end if

    num_paths = 0
    if (on_root) then
      call utility_recip_lattice_base(real_lattice, recip_lattice, volume)
      ! Determine the number of k-points (total_pts) as well as
      ! their reciprocal-lattice coordinates long the path (plot_kpoint)
      ! and their associated horizontal coordinate for the plot (xval)
      call k_path_get_points(num_paths, kpath_len, total_pts, xval, plot_kpoint, kpoint_path, &
                             recip_lattice, pw90_kpath)
      ! (paths)
      num_spts = num_paths + 1 ! number of path endpoints (special pts)
    else
      ! Dummy allocation for making scatterv work
      allocate (plot_kpoint(1, 1))
    end if

    ! Broadcast number of k-points on the path
    call comms_bcast(total_pts, 1, error, comm)
    if (allocated(error)) return

    ! Partition set of k-points into junks
!   call comms_array_split(total_pts, counts, displs)
    call comms_array_split(total_pts, counts, displs, comm)
    !kpt_lo = displs(my_node_id)+1
    !kpt_hi = displs(my_node_id)+counts(my_node_id)
    my_num_pts = counts(my_node_id)

    ! Distribute coordinates
    allocate (my_plot_kpoint(3, my_num_pts))
    call comms_scatterv(my_plot_kpoint, 3*my_num_pts, &
                        plot_kpoint, 3*counts, 3*displs, error, comm)
    if (allocated(error)) return

    ! Value of the vertical coordinate in the actual plots: energy bands
    !
    if (plot_bands) then
      allocate (HH(num_wann, num_wann))
      allocate (UU(num_wann, num_wann))
      allocate (my_eig(num_wann, my_num_pts))
      if (pw90_kpath%bands_colour /= 'none') allocate (my_color(num_wann, my_num_pts))
    end if

    ! Value of the vertical coordinate in the actual plots
    !
    if (plot_curv) allocate (my_curv(my_num_pts, 3))
    if (plot_morb) allocate (my_morb(my_num_pts, 3))
    if (plot_shc) allocate (my_shc(my_num_pts))

    ! Loop over local junk of k-points on the path and evaluate the requested quantities
    !
    do loop_kpt = 1, my_num_pts
      kpt(:) = my_plot_kpoint(:, loop_kpt)

      if (plot_bands) then
        call pw90common_fourier_R_to_k(ws_region, wannier_data, ws_distance, wigner_seitz, HH, &
                                       HH_R, kpt, real_lattice, mp_grid, 0, num_wann, error, comm)
        if (allocated(error)) return

        call utility_diagonalize(HH, num_wann, my_eig(:, loop_kpt), UU, error, comm)
        if (allocated(error)) return

        !
        ! Color-code energy bands with the spin projection along the
        ! chosen spin quantization axis
        !
        if (pw90_kpath%bands_colour == 'spin') then
          call spin_get_nk(ws_region, pw90_spin, wannier_data, ws_distance, wigner_seitz, HH_R, &
                           SS_R, kpt, real_lattice, spn_k, mp_grid, num_wann, error, comm)
          if (allocated(error)) return

          my_color(:, loop_kpt) = spn_k(:)
          !
          ! The following is needed to prevent bands from disappearing
          ! when the magnitude of the Wannier interpolated spn_k (very
          ! slightly) exceeds 1.0 (e.g. in bcc Fe along N--G--H)
          !
          do n = 1, num_wann
            if (my_color(n, loop_kpt) > 1.0_dp - eps8) then
              my_color(n, loop_kpt) = 1.0_dp - eps8
            else if (my_color(n, loop_kpt) < -1.0_dp + eps8) then
              my_color(n, loop_kpt) = -1.0_dp + eps8
            end if
          end do
        else if (pw90_kpath%bands_colour == 'shc') then
          call berry_get_shc_klist(pw90_berry, dis_manifold, fermi_energy_list, kpt_latt, &
                                   pw90_band_deriv_degen, ws_region, pw90_spin_hall, print_output, &
                                   wannier_data, ws_distance, wigner_seitz, AA_R, HH_R, SH_R, &
                                   SHR_R, SR_R, SS_R, SAA_R, SBB_R, u_matrix, v_matrix, eigval, &
                                   kpt, real_lattice, scissors_shift, mp_grid, fermi_n, num_bands, &
                                   num_kpts, num_wann, num_valence_bands, effective_model, &
                                   have_disentangled, seedname, stdout, timer, error, comm, &
                                   shc_k_band=shc_k_band)
          if (allocated(error)) return

          my_color(:, loop_kpt) = shc_k_band
        end if
      end if

      if (plot_morb) then
        call berry_get_imfgh_klist(dis_manifold, fermi_energy_list, kpt_latt, ws_region, &
                                   print_output, wannier_data, ws_distance, wigner_seitz, AA_R, &
                                   BB_R, CC_R, HH_R, u_matrix, v_matrix, eigval, kpt, &
                                   real_lattice, scissors_shift, mp_grid, fermi_n, num_bands, &
                                   num_kpts, num_wann, num_valence_bands, effective_model, &
                                   have_disentangled, seedname, stdout, timer, error, comm, &
                                   imf_k_list, img_k_list, imh_k_list)
        if (allocated(error)) return

        Morb_k = img_k_list(:, :, 1) + imh_k_list(:, :, 1) &
                 - 2.0_dp*fermi_energy_list(1)*imf_k_list(:, :, 1)
        Morb_k = -Morb_k/2.0_dp ! differs by -1/2 from Eq.97 LVTS12
        my_morb(loop_kpt, 1) = sum(Morb_k(:, 1))
        my_morb(loop_kpt, 2) = sum(Morb_k(:, 2))
        my_morb(loop_kpt, 3) = sum(Morb_k(:, 3))
      end if

      if (plot_curv) then
        if (.not. plot_morb) then
          call berry_get_imf_klist(dis_manifold, fermi_energy_list, kpt_latt, ws_region, &
                                   print_output, wannier_data, ws_distance, wigner_seitz, AA_R, &
                                   BB_R, CC_R, HH_R, u_matrix, v_matrix, eigval, kpt, &
                                   real_lattice, imf_k_list, scissors_shift, mp_grid, num_bands, &
                                   num_kpts, num_wann, num_valence_bands, effective_model, &
                                   have_disentangled, seedname, stdout, timer, error, comm)
          if (allocated(error)) return

        end if
        my_curv(loop_kpt, 1) = sum(imf_k_list(:, 1, 1))
        my_curv(loop_kpt, 2) = sum(imf_k_list(:, 2, 1))
        my_curv(loop_kpt, 3) = sum(imf_k_list(:, 3, 1))
      end if

      if (plot_shc) then
        call berry_get_shc_klist(pw90_berry, dis_manifold, fermi_energy_list, kpt_latt, &
                                 pw90_band_deriv_degen, ws_region, pw90_spin_hall, print_output, &
                                 wannier_data, ws_distance, wigner_seitz, AA_R, HH_R, SH_R, SHR_R, &
                                 SR_R, SS_R, SAA_R, SBB_R, u_matrix, v_matrix, eigval, kpt, &
                                 real_lattice, scissors_shift, mp_grid, fermi_n, num_bands, &
                                 num_kpts, num_wann, num_valence_bands, effective_model, &
                                 have_disentangled, seedname, stdout, timer, error, comm, &
                                 shc_k_fermi=shc_k_fermi)
        if (allocated(error)) return
        my_shc(loop_kpt) = shc_k_fermi(1)
      end if
    end do !loop_kpt

    ! Send results to root process
    if (plot_bands) then
      allocate (eig(num_wann, total_pts))
      call comms_gatherv(my_eig, num_wann*my_num_pts, &
                         eig, num_wann*counts, num_wann*displs, error, comm)
      if (allocated(error)) return
      if (pw90_kpath%bands_colour /= 'none') then
        allocate (color(num_wann, total_pts))
        call comms_gatherv(my_color, num_wann*my_num_pts, &
                           color, num_wann*counts, num_wann*displs, error, comm)
        if (allocated(error)) return
      end if
    end if

    if (plot_curv) then
      allocate (curv(total_pts, 3))
      do i = 1, 3
        call comms_gatherv(my_curv(:, i), my_num_pts, &
                           curv(:, i), counts, displs, error, comm)
        if (allocated(error)) return
      end do
    end if

    if (plot_morb) then
      allocate (morb(total_pts, 3))
      do i = 1, 3
        call comms_gatherv(my_morb(:, i), my_num_pts, &
                           morb(:, i), counts, displs, error, comm)
        if (allocated(error)) return
      end do
    end if

    if (plot_shc) then
      allocate (shc(total_pts))
      call comms_gatherv(my_shc, my_num_pts, shc, counts, displs, error, comm)
      if (allocated(error)) return
    end if

    if (on_root) then
      num_spts = num_paths + 1
      allocate (glabel(num_spts))

      if (plot_bands) then
        !
        ! Write out the kpoints in the path in a format that can be inserted
        ! directly in the pwscf input file (the '1.0_dp' in the second column is
        ! a k-point weight, expected by pwscf)
        !
        open (newunit=dataunit, file=trim(seedname)//'-path.kpt', form='formatted')
        write (dataunit, *) total_pts
        do loop_kpt = 1, total_pts
          write (dataunit, '(3f12.6,3x,f4.1)') &
            (plot_kpoint(loop_i, loop_kpt), loop_i=1, 3), 1.0_dp
        end do
        close (dataunit)
      end if
      if (plot_curv .and. pw90_berry%curv_unit == 'bohr2') curv = curv/bohr**2

      if (plot_bands .and. pw90_kpath%bands_colour == 'shc') then
        if (pw90_berry%curv_unit == 'bohr2') color = color/bohr**2
      end if
      if (plot_shc) then
        if (pw90_berry%curv_unit == 'bohr2') shc = shc/bohr**2
      end if

      ! Axis labels
      !
      glabel(1) = ' '//kpoint_path%labels(1)//' '
      do i = 2, num_paths
        if (kpoint_path%labels(2*(i - 1)) /= kpoint_path%labels(2*(i - 1) + 1)) then
          glabel(i) = kpoint_path%labels(2*(i - 1))//'/'//kpoint_path%labels(2*(i - 1) + 1)
        else
          glabel(i) = ' '//kpoint_path%labels(2*(i - 1))//' '
        end if
      end do
      glabel(num_spts) = ' '//kpoint_path%labels(num_paths*2)//' '

      ! Now write the plotting files

      write (stdout, '(/,1x,a)') 'Output files:'

      if (plot_bands) then
        file_name = trim(seedname)//'-path.kpt'
        write (stdout, '(/,3x,a)') file_name
        !
        ! Data file
        !
        file_name = trim(seedname)//'-bands.dat'
        write (stdout, '(/,3x,a)') file_name
        open (newunit=dataunit, file=file_name, form='formatted')
        do i = 1, num_wann
          do loop_kpt = 1, total_pts
            if (pw90_kpath%bands_colour == 'none') then
              write (dataunit, '(2E16.8)') xval(loop_kpt), eig(i, loop_kpt)
            else
              write (dataunit, '(3E16.8)') xval(loop_kpt), &
                eig(i, loop_kpt), color(i, loop_kpt)
            end if
          end do
          write (dataunit, *) ' '
        end do
        close (dataunit)
      end if

      if (plot_bands .and. .not. plot_curv .and. .not. plot_morb &
          .and. .not. plot_shc) then
        !
        ! Gnuplot script
        !
        ymin = minval(eig) - 1.0_dp
        ymax = maxval(eig) + 1.0_dp
        file_name = trim(seedname)//'-bands.gnu'
        write (stdout, '(/,3x,a)') file_name
        open (newunit=gnuunit, file=file_name, form='formatted')
        do i = 1, num_paths - 1
          write (gnuunit, 705) sum(kpath_len(1:i)), ymin, &
            sum(kpath_len(1:i)), ymax
        end do
        if (pw90_kpath%bands_colour == 'none') then
          write (gnuunit, 701) xval(total_pts), ymin, ymax
          write (gnuunit, 702, advance="no") glabel(1), 0.0_dp, &
            (glabel(i + 1), sum(kpath_len(1:i)), i=1, num_paths - 1)
          write (gnuunit, 703) glabel(1 + num_paths), sum(kpath_len(:))
          write (gnuunit, *) 'plot ', '"'//trim(seedname)//'-bands.dat', '"'
        else if (pw90_kpath%bands_colour == 'spin') then
          !
          ! Only works with gnuplot v4.2 and higher
          !
          write (gnuunit, 706) xval(total_pts), ymin, ymax
          write (gnuunit, 702, advance="no") glabel(1), 0.0_dp, &
            (glabel(i + 1), sum(kpath_len(1:i)), i=1, num_paths - 1)
          write (gnuunit, 703) glabel(1 + num_paths), sum(kpath_len(:))
          write (gnuunit, *) &
            'set palette defined (-1 "blue", 0 "green", 1 "red")'
          write (gnuunit, *) 'set pm3d map'
          write (gnuunit, *) 'set zrange [-1:1]'
          write (gnuunit, *) 'splot ', '"'//trim(seedname)//'-bands.dat', &
            '" with dots palette'
        else if (pw90_kpath%bands_colour == 'shc') then
          !
          ! Only works with gnuplot v4.2 and higher
          !
          write (gnuunit, 706) xval(total_pts), ymin, ymax
          write (gnuunit, 702, advance="no") glabel(1), 0.0_dp, &
            (glabel(i + 1), sum(kpath_len(1:i)), i=1, num_paths - 1)
          write (gnuunit, 703) glabel(1 + num_paths), sum(kpath_len(:))
          write (gnuunit, *) &
            'sgnlog10(x) = abs(x) > 10.0 ? log10(abs(x))*sgn(x) : x/10.0'
          ! merge: Fortran ternary operator: similar to ? : in C
          zmin = minval(color)
          zmin = merge(sign(log10(abs(zmin)), zmin), zmin/10.0_dp, abs(zmin) > 10.0_dp)
          zmax = maxval(color)
          zmax = merge(sign(log10(abs(zmax)), zmax), zmax/10.0_dp, abs(zmax) > 10.0_dp)
          write (gnuunit, *) &
            'set palette defined (', zmin, ' "blue", 0 "green", ', zmax, ' "red")'
          write (gnuunit, *) 'set pm3d map'
          write (gnuunit, *) 'set zrange [', zmin, ':', zmax, ']'
          write (gnuunit, *) 'splot ', '"'//trim(seedname)//'-bands.dat', &
            '" u 1:2:(sgnlog10($3)) with dots palette'
        end if
        close (gnuunit)
        !
        ! python script
        !
        file_name = trim(seedname)//'-bands.py'
        write (stdout, '(/,3x,a)') file_name
        open (newunit=pyunit, file=file_name, form='formatted')
        write (pyunit, '(a)') 'import pylab as pl'
        write (pyunit, '(a)') 'import numpy as np'
        write (pyunit, '(a)') "data = np.loadtxt('"//trim(seedname)// &
          "-bands.dat')"
        write (pyunit, '(a)') "x=data[:,0]"
        write (pyunit, '(a)') "y=data[:,1]"
        if (pw90_kpath%bands_colour == 'spin' &
            .or. pw90_kpath%bands_colour == 'shc') write (pyunit, '(a)') "z=data[:,2]"
        if (pw90_kpath%bands_colour == 'shc') write (pyunit, '(a)') &
          "z=np.array([np.log10(abs(elem))*np.sign(elem) " &
          //"if abs(elem)>10 else elem/10.0 for elem in z])"
        write (pyunit, '(a)') "tick_labels=[]"
        write (pyunit, '(a)') "tick_locs=[]"
        do j = 1, num_spts
          if (trim(glabel(j)) == ' G') then
            write (pyunit, '(a)') "tick_labels.append('$\Gamma$')"
          else
            write (pyunit, '(a)') "tick_labels.append('"//trim(glabel(j)) &
              //"'.strip())"
          end if
          if (j == 1) then
            write (pyunit, '(a,F12.6,a)') "tick_locs.append(0)"
          else
            write (pyunit, '(a,F12.6,a)') "tick_locs.append(", &
              sum(kpath_len(1:j - 1)), ")"
          end if
        end do
        if (pw90_kpath%bands_colour == 'none') then
          write (pyunit, '(a)') "pl.scatter(x,y,color='k',marker='+',s=0.1)"
        else if (pw90_kpath%bands_colour == 'spin' .or. &
                 pw90_kpath%bands_colour == 'shc') then
          write (pyunit, '(a)') &
            "pl.scatter(x,y,c=z,marker='+',s=1,cmap=pl.cm.jet)"
        end if
        write (pyunit, '(a)') "pl.xlim([0,max(x)])"
        write (pyunit, '(a)') "pl.ylim([min(y)-0.025*(max(y)-min(y))," &
          //"max(y)+0.025*(max(y)-min(y))])"
        write (pyunit, '(a)') "pl.xticks(tick_locs,tick_labels)"
        write (pyunit, '(a)') "for n in range(1,len(tick_locs)):"
        write (pyunit, '(a)') "   pl.plot([tick_locs[n],tick_locs[n]]," &
          //"[pl.ylim()[0],pl.ylim()[1]],color='gray'," &
          //"linestyle='-',linewidth=0.5)"
        write (pyunit, '(a)') "pl.ylabel('Energy [eV]')"
        if (pw90_kpath%bands_colour == 'spin' .or. pw90_kpath%bands_colour == 'shc') then
          write (pyunit, '(a)') &
            "pl.axes().set_aspect(aspect=0.65*max(x)/(max(y)-min(y)))"
          write (pyunit, '(a)') "pl.colorbar(shrink=0.7)"
        end if
        write (pyunit, '(a)') "outfile = '"//trim(seedname)//"-bands.pdf'"
        write (pyunit, '(a)') "pl.savefig(outfile,bbox_inches='tight')"
        write (pyunit, '(a)') "pl.show()"

      end if ! plot_bands .and. .not.plot_curv .and. .not.plot_morb .and. .not. plot_shc

      if (plot_curv) then
        ! It is conventional to plot the negative curvature
        curv = -curv
        file_name = trim(seedname)//'-curv.dat'
        write (stdout, '(/,3x,a)') file_name
        open (newunit=dataunit, file=file_name, form='formatted')
        do loop_kpt = 1, total_pts
          write (dataunit, '(4E16.8)') xval(loop_kpt), &
            curv(loop_kpt, :)
        end do
        write (dataunit, *) ' '
        close (dataunit)
      end if

      if (plot_curv .and. .not. plot_bands) then

        do i = 1, 3
          !
          ! gnuplot script
          !
          file_name = trim(seedname)//'-curv_'//achar(119 + i)//'.gnu'
          write (stdout, '(/,3x,a)') file_name
          open (newunit=gnuunit, file=file_name, form='formatted')
          ymin = minval(curv(:, i))
          ymax = maxval(curv(:, i))
          range = ymax - ymin
          ymin = ymin - 0.02_dp*range
          ymax = ymax + 0.02_dp*range
          write (gnuunit, 707) xval(total_pts), ymin, ymax
          do j = 1, num_paths - 1
            write (gnuunit, 705) sum(kpath_len(1:j)), ymin, &
              sum(kpath_len(1:j)), ymax
          end do
          write (gnuunit, 702, advance="no") glabel(1), 0.0_dp, &
            (glabel(j + 1), sum(kpath_len(1:j)), j=1, num_paths - 1)
          write (gnuunit, 703) glabel(1 + num_paths), sum(kpath_len(:))
          write (gnuunit, *) &
            'plot ', '"'//trim(seedname)//'-curv.dat', '" u 1:'//achar(49 + i)
          close (gnuunit)
          !
          ! python script
          !
          file_name = trim(seedname)//'-curv_'//achar(119 + i)//'.py'
          write (stdout, '(/,3x,a)') file_name
          open (newunit=pyunit, file=file_name, form='formatted')
          write (pyunit, '(a)') 'import pylab as pl'
          write (pyunit, '(a)') 'import numpy as np'
          write (pyunit, '(a)') "data = np.loadtxt('"//trim(seedname)// &
            "-curv.dat')"
          write (pyunit, '(a)') "x=data[:,0]"
          write (pyunit, '(a)') "y=data[:,"//achar(48 + i)//"]"
          write (pyunit, '(a)') "tick_labels=[]"
          write (pyunit, '(a)') "tick_locs=[]"
          do j = 1, num_spts
            if (trim(glabel(j)) == ' G') then
              write (pyunit, '(a)') "tick_labels.append('$\Gamma$')"
            else
              write (pyunit, '(a)') "tick_labels.append('" &
                //trim(glabel(j))//"'.strip())"
            end if
            if (j == 1) then
              write (pyunit, '(a,F12.6,a)') "tick_locs.append(0)"
            else
              write (pyunit, '(a,F12.6,a)') "tick_locs.append(", &
                sum(kpath_len(1:j - 1)), ")"
            end if
          end do
          write (pyunit, '(a)') "pl.plot(x,y,color='k')"
          write (pyunit, '(a)') "pl.xlim([0,max(x)])"
          write (pyunit, '(a)') "pl.ylim([min(y)-0.025*(max(y)-min(y))," &
            //"max(y)+0.025*(max(y)-min(y))])"
          write (pyunit, '(a)') "pl.xticks(tick_locs,tick_labels)"
          write (pyunit, '(a)') "for n in range(1,len(tick_locs)):"
          write (pyunit, '(a)') "   pl.plot([tick_locs[n],tick_locs[n]]," &
            //"[pl.ylim()[0],pl.ylim()[1]],color='gray'," &
            //"linestyle='-',linewidth=0.5)"
          if (pw90_berry%curv_unit == 'ang2') then
            write (pyunit, '(a)') "pl.ylabel('$-\Omega_"//achar(119 + i) &
              //"(\mathbf{k})$  [ $\AA^2$ ]')"
          else if (pw90_berry%curv_unit == 'bohr2') then
            write (pyunit, '(a)') "pl.ylabel('$-\Omega_"//achar(119 + i) &
              //"(\mathbf{k})$  [ bohr$^2$ ]')"
          end if
          write (pyunit, '(a)') "outfile = '"//trim(seedname)// &
            "-curv_"//achar(119 + i)//".pdf'"
          write (pyunit, '(a)') "pl.savefig(outfile,bbox_inches='tight')"
          write (pyunit, '(a)') "pl.show()"
        end do

      end if ! plot_curv .and. .not.plot_bands

      if (plot_morb) then
        file_name = trim(seedname)//'-morb.dat'
        write (stdout, '(/,3x,a)') file_name
        open (newunit=dataunit, file=file_name, form='formatted')
        do loop_kpt = 1, total_pts
          write (dataunit, '(4E16.8)') xval(loop_kpt), morb(loop_kpt, :)
        end do
        write (dataunit, *) ' '
        close (dataunit)
      end if

      if (plot_morb .and. .not. plot_bands) then
        do i = 1, 3
          !
          ! gnuplot script
          !
          file_name = trim(seedname)//'-morb_'//achar(119 + i)//'.gnu'
          write (stdout, '(/,3x,a)') file_name
          open (newunit=gnuunit, file=file_name, form='formatted')
          ymin = minval(morb(:, i))
          ymax = maxval(morb(:, i))
          range = ymax - ymin
          ymin = ymin - 0.02_dp*range
          ymax = ymax + 0.02_dp*range
          write (gnuunit, 707) xval(total_pts), ymin, ymax
          do j = 1, num_paths - 1
            write (gnuunit, 705) sum(kpath_len(1:j)), ymin, &
              sum(kpath_len(1:j)), ymax
          end do
          write (gnuunit, 702, advance="no") glabel(1), 0.0_dp, &
            (glabel(j + 1), sum(kpath_len(1:j)), j=1, num_paths - 1)
          write (gnuunit, 703) glabel(1 + num_paths), sum(kpath_len(:))
          write (gnuunit, *) &
            'plot ', '"'//trim(seedname)//'-morb.dat', '" u 1:'//achar(49 + i)
          close (gnuunit)
          !
          ! python script
          !
          file_name = trim(seedname)//'-morb_'//achar(119 + i)//'.py'
          write (stdout, '(/,3x,a)') file_name
          open (newunit=pyunit, file=file_name, form='formatted')
          write (pyunit, '(a)') 'import pylab as pl'
          write (pyunit, '(a)') 'import numpy as np'
          write (pyunit, '(a)') "data = np.loadtxt('"//trim(seedname)// &
            "-morb.dat')"
          write (pyunit, '(a)') "x=data[:,0]"
          write (pyunit, '(a)') "y=data[:,"//achar(48 + i)//"]"
          write (pyunit, '(a)') "tick_labels=[]"
          write (pyunit, '(a)') "tick_locs=[]"
          do j = 1, num_spts
            if (trim(glabel(j)) == ' G') then
              write (pyunit, '(a)') "tick_labels.append('$\Gamma$')"
            else
              write (pyunit, '(a)') &
                "tick_labels.append('"//trim(glabel(j))//"'.strip())"
            end if
            if (j == 1) then
              write (pyunit, '(a,F12.6,a)') "tick_locs.append(0)"
            else
              write (pyunit, '(a,F12.6,a)') "tick_locs.append(", &
                sum(kpath_len(1:j - 1)), ")"
            end if
          end do
          write (pyunit, '(a)') "pl.plot(x,y,color='k')"
          write (pyunit, '(a)') "pl.xlim([0,max(x)])"
          write (pyunit, '(a)') "pl.ylim([min(y)-0.025*(max(y)-min(y))," &
            //"max(y)+0.025*(max(y)-min(y))])"
          write (pyunit, '(a)') "pl.xticks(tick_locs,tick_labels)"
          write (pyunit, '(a)') "for n in range(1,len(tick_locs)):"
          write (pyunit, '(a)') "   pl.plot([tick_locs[n],tick_locs[n]]," &
            //"[pl.ylim()[0],pl.ylim()[1]],color='gray'," &
            //"linestyle='-',linewidth=0.5)"
          write (pyunit, '(a)') "pl.ylabel(r'$M^{\rm{orb}}_z(\mathbf{k})$" &
            //"  [ Ry$\cdot\AA^2$ ]')"
          write (pyunit, '(a)') "outfile = '"//trim(seedname)// &
            "-morb_"//achar(119 + i)//".pdf'"
          write (pyunit, '(a)') "pl.savefig(outfile,bbox_inches='tight')"
          write (pyunit, '(a)') "pl.show()"
        end do

      end if ! plot_morb .and. .not.plot_bands

      if (plot_shc) then
        file_name = trim(seedname)//'-shc.dat'
        write (stdout, '(/,3x,a)') file_name
        open (newunit=dataunit, file=file_name, form='formatted')
        do loop_kpt = 1, total_pts
          write (dataunit, '(2E16.8)') xval(loop_kpt), &
            shc(loop_kpt)
        end do
        write (dataunit, *) ' '
        close (dataunit)
      end if

      if (plot_shc .and. .not. plot_bands) then
        !
        ! gnuplot script
        !
        file_name = trim(seedname)//'-shc'//'.gnu'
        write (stdout, '(/,3x,a)') file_name
        open (newunit=gnuunit, file=file_name, form='formatted')
        ymin = minval(shc(:))
        ymax = maxval(shc(:))
        range = ymax - ymin
        ymin = ymin - 0.02_dp*range
        ymax = ymax + 0.02_dp*range
        write (gnuunit, 707) xval(total_pts), ymin, ymax
        do j = 1, num_paths - 1
          write (gnuunit, 705) sum(kpath_len(1:j)), ymin, &
            sum(kpath_len(1:j)), ymax
        end do
        write (gnuunit, 702, advance="no") glabel(1), 0.0_dp, &
          (glabel(j + 1), sum(kpath_len(1:j)), j=1, num_paths - 1)
        write (gnuunit, 703) glabel(1 + num_paths), sum(kpath_len(:))
        write (gnuunit, *) &
          'plot ', '"'//trim(seedname)//'-shc.dat', '" u 1:2'
        close (gnuunit)
        !
        ! python script
        !
        file_name = trim(seedname)//'-shc'//'.py'
        write (stdout, '(/,3x,a)') file_name
        open (newunit=pyunit, file=file_name, form='formatted')
        write (pyunit, '(a)') "# uncomment these two lines if you are " &
          //"running in non-GUI environment"
        write (pyunit, '(a)') "#import matplotlib"
        write (pyunit, '(a)') "#matplotlib.use('Agg')"
        write (pyunit, '(a)') 'import pylab as pl'
        write (pyunit, '(a)') 'import numpy as np'
        write (pyunit, '(a)') "data = np.loadtxt('"//trim(seedname)// &
          "-shc.dat')"
        write (pyunit, '(a)') "x=data[:,0]"
        write (pyunit, '(a)') "y=data[:,1]"
        write (pyunit, '(a)') "tick_labels=[]"
        write (pyunit, '(a)') "tick_locs=[]"
        do j = 1, num_spts
          if (trim(glabel(j)) == ' G') then
            write (pyunit, '(a)') "tick_labels.append('$\Gamma$')"
          else
            write (pyunit, '(a)') "tick_labels.append('" &
              //trim(glabel(j))//"'.strip())"
          end if
          if (j == 1) then
            write (pyunit, '(a,F12.6,a)') "tick_locs.append(0)"
          else
            write (pyunit, '(a,F12.6,a)') "tick_locs.append(", &
              sum(kpath_len(1:j - 1)), ")"
          end if
        end do
        write (pyunit, '(a)') "pl.plot(x,y,color='k')"
        write (pyunit, '(a)') "pl.xlim([0,max(x)])"
        write (pyunit, '(a)') "pl.ylim([min(y)-0.025*(max(y)-min(y))," &
          //"max(y)+0.025*(max(y)-min(y))])"
        write (pyunit, '(a)') "pl.xticks(tick_locs,tick_labels)"
        write (pyunit, '(a)') "for n in range(1,len(tick_locs)):"
        write (pyunit, '(a)') "   pl.plot([tick_locs[n],tick_locs[n]]," &
          //"[pl.ylim()[0],pl.ylim()[1]],color='gray'," &
          //"linestyle='-',linewidth=0.5)"
        if (pw90_berry%curv_unit == 'ang2') then
          write (pyunit, '(a)') "pl.ylabel('$\Omega_{" &
            //achar(119 + pw90_spin_hall%alpha)//achar(119 + pw90_spin_hall%beta) &
            //"}^{spin"//achar(119 + pw90_spin_hall%gamma) &
            //"}(\mathbf{k})$  [ $\AA^2$ ]')"
        else if (pw90_berry%curv_unit == 'bohr2') then
          write (pyunit, '(a)') "pl.ylabel('$\Omega_{" &
            //achar(119 + pw90_spin_hall%alpha)//achar(119 + pw90_spin_hall%beta) &
            //"}^{spin"//achar(119 + pw90_spin_hall%gamma) &
            //"}(\mathbf{k})$  [ bohr$^2$ ]')"
        end if
        write (pyunit, '(a)') "outfile = '"//trim(seedname)// &
          "-shc"//".pdf'"
        write (pyunit, '(a)') "pl.savefig(outfile,bbox_inches='tight')"
        write (pyunit, '(a)') "pl.show()"

      end if ! plot_shc .and. .not.plot_bands

      if (plot_bands .and. plot_shc) then
        !
        ! python script
        !
        file_name = trim(seedname)//'-bands+shc'//'.py'
        write (stdout, '(/,3x,a)') file_name
        open (newunit=pyunit, file=file_name, form='formatted')
        write (pyunit, '(a)') "# uncomment these two lines if you are " &
          //"running in non-GUI environment"
        write (pyunit, '(a)') "#import matplotlib"
        write (pyunit, '(a)') "#matplotlib.use('Agg')"
        write (pyunit, '(a)') 'import pylab as pl'
        write (pyunit, '(a)') 'import numpy as np'
        write (pyunit, '(a)') 'from matplotlib.gridspec import GridSpec'
        write (pyunit, '(a)') "tick_labels=[]"
        write (pyunit, '(a)') "tick_locs=[]"
        do j = 1, num_spts
          if (trim(glabel(j)) == ' G') then
            write (pyunit, '(a)') "tick_labels.append('$\Gamma$')"
          else
            write (pyunit, '(a)') "tick_labels.append('"//trim(glabel(j)) &
              //"'.strip())"
          end if
          if (j == 1) then
            write (pyunit, '(a,F12.6,a)') "tick_locs.append(0)"
          else
            write (pyunit, '(a,F12.6,a)') "tick_locs.append(", &
              sum(kpath_len(1:j - 1)), ")"
          end if
        end do
        write (pyunit, '(a)') "fig = pl.figure()"
        write (pyunit, '(a)') "gs = GridSpec(2,52,hspace=0.00,wspace=1)"
        !
        ! upper panel (energy bands)
        !
        write (pyunit, '(a)') "axes1 = pl.subplot(gs[0, :-2])"
        write (pyunit, '(a)') "data = np.loadtxt('"//trim(seedname)// &
          "-bands.dat')"
        write (pyunit, '(a)') "x=data[:,0]"
        write (pyunit, '(a,F12.6)') "y=data[:,1]-", fermi_energy_list(1)
        if (pw90_kpath%bands_colour == 'spin' .or. pw90_kpath%bands_colour == 'shc') &
          write (pyunit, '(a)') "z=data[:,2]"
        if (pw90_kpath%bands_colour == 'shc') &
          write (pyunit, '(a)') "z=np.array([np.log10(abs(elem))*np.sign(elem) " &
          //"if abs(elem)>10 else elem/10.0 for elem in z])"
        if (pw90_kpath%bands_colour == 'none') then
          write (pyunit, '(a)') "pl.scatter(x,y,color='k',marker='+',s=0.1)"
        else if (pw90_kpath%bands_colour == 'spin' &
                 .or. pw90_kpath%bands_colour == 'shc') then
          write (pyunit, '(a)') &
            "pl.scatter(x,y,c=z,marker='+',s=1,cmap=pl.cm.jet)"
        end if
        write (pyunit, '(a)') "pl.xlim([0,max(x)])"
        write (pyunit, '(a)') "pl.ylim([-0.65,0.65]) # Adjust this range as needed"
        write (pyunit, '(a)') "pl.plot([tick_locs[0],tick_locs[-1]],[0,0]," &
          //"color='black',linestyle='--',linewidth=0.5)"
        write (pyunit, '(a)') "pl.xticks(tick_locs,tick_labels)"
        write (pyunit, '(a)') "for n in range(1,len(tick_locs)):"
        write (pyunit, '(a)') "   pl.plot([tick_locs[n],tick_locs[n]]," &
          //"[pl.ylim()[0],pl.ylim()[1]],color='gray'," &
          //"linestyle='-',linewidth=0.5)"
        write (pyunit, '(a)') "pl.ylabel('Energy$-$E$_F$ [eV]')"
        write (pyunit, '(a)') "pl.tick_params(axis='x'," &
          //"which='both',bottom='off',top='off',labelbottom='off')"
        !
        ! color bar for upper panel
        !
        write (pyunit, '(a)') "# Now adding the colorbar"
        write (pyunit, '(a)') "cbaxes = pl.subplot(gs[:, -2:])"
        write (pyunit, '(a)') "cb = pl.colorbar(cax = cbaxes," &
          //"orientation='vertical') "
        write (pyunit, '(a)') "#cblim = int(min(abs(max(z)),abs(min(z))))"
        write (pyunit, '(a)') "#cb.set_ticks([-cblim,0,cblim])"
        write (pyunit, '(a)') "#cblim = [min(z),0,max(z)]"
        write (pyunit, '(a)') "#cb.set_ticks([min(z),0,max(z)])"
        write (pyunit, '(a)') "#cb.set_ticklabels(['-','0','+'])"
        !
        ! lower panel (SHC)
        !
        write (pyunit, '(a)') "axes2 = pl.subplot(gs[1, :-2])"
        write (pyunit, '(a)') "data = np.loadtxt('"//trim(seedname)// &
          "-shc.dat')"
        write (pyunit, '(a)') "x=data[:,0]"
        write (pyunit, '(a)') "y=data[:,1]"
        write (pyunit, '(a)') &
                "y=np.array([np.log10(abs(elem))*np.sign(elem) &
                        &if abs(elem)>10 else elem/10.0 for elem in y])"
        write (pyunit, '(a)') "pl.plot(x,y,color='k')"
        write (pyunit, '(a)') "pl.xlim([0,max(x)])"
        write (pyunit, '(a)') "pl.ylim([min(y)-0.025*(max(y)-min(y))," &
          //"max(y)+0.025*(max(y)-min(y))])"
        write (pyunit, '(a)') "pl.plot([0,max(x)],[0,0],color='black'," &
          //"linestyle='--',linewidth=0.5)"
        write (pyunit, '(a)') "pl.xticks(tick_locs,tick_labels)"
        write (pyunit, '(a)') "for n in range(1,len(tick_locs)):"
        write (pyunit, '(a)') "   pl.plot([tick_locs[n],tick_locs[n]]," &
          //"[pl.ylim()[0],pl.ylim()[1]],color='gray'," &
          //"linestyle='-',linewidth=0.5)"
        if (pw90_berry%curv_unit == 'ang2') then
          write (pyunit, '(a)') "pl.ylabel('$log_{10}|\Omega_{" &
            //achar(119 + pw90_spin_hall%alpha)//achar(119 + pw90_spin_hall%beta) &
            //"}^{spin"//achar(119 + pw90_spin_hall%gamma) &
            //"}(\mathbf{k})|$  [ $\AA^2$ ]')"
        else if (pw90_berry%curv_unit == 'bohr2') then
          write (pyunit, '(a)') "pl.ylabel('$\Omega_{" &
            //achar(119 + pw90_spin_hall%alpha)//achar(119 + pw90_spin_hall%beta) &
            //"}^{spin"//achar(119 + pw90_spin_hall%gamma) &
            //"}(\mathbf{k})$  [ bohr$^2$ ]')"
        end if
        write (pyunit, '(a)') "outfile = '"//trim(seedname)// &
          "-bands+shc"//".pdf'"
        write (pyunit, '(a)') "pl.savefig(outfile,bbox_inches='tight')"
        write (pyunit, '(a)') "pl.show()"

      end if ! plot_bands .and. plot_shc

      if (plot_bands .and. (plot_curv .or. plot_morb)) then
        !
        ! python script
        !
        do i = 1, 3
          if (plot_curv) then
            file_name = trim(seedname)//'-bands+curv_'//achar(119 + i)//'.py'
          else if (plot_morb) then
            file_name = trim(seedname)//'-bands+morb_'//achar(119 + i)//'.py'
          end if
          write (stdout, '(/,3x,a)') file_name
          open (newunit=pyunit, file=file_name, form='formatted')
          write (pyunit, '(a)') 'import pylab as pl'
          write (pyunit, '(a)') 'import numpy as np'
          write (pyunit, '(a)') 'from matplotlib.gridspec import GridSpec'
          write (pyunit, '(a)') "tick_labels=[]"
          write (pyunit, '(a)') "tick_locs=[]"
          do j = 1, num_spts
            if (trim(glabel(j)) == ' G') then
              write (pyunit, '(a)') "tick_labels.append('$\Gamma$')"
            else
              write (pyunit, '(a)') "tick_labels.append('"//trim(glabel(j)) &
                //"'.strip())"
            end if
            if (j == 1) then
              write (pyunit, '(a,F12.6,a)') "tick_locs.append(0)"
            else
              write (pyunit, '(a,F12.6,a)') "tick_locs.append(", &
                sum(kpath_len(1:j - 1)), ")"
            end if
          end do
          write (pyunit, '(a)') "fig = pl.figure()"
          write (pyunit, '(a)') "gs = GridSpec(2, 1,hspace=0.00)"
          !
          ! upper panel (energy bands)
          !
          write (pyunit, '(a)') "axes1 = pl.subplot(gs[0, 0:])"
          write (pyunit, '(a)') "data = np.loadtxt('"//trim(seedname)// &
            "-bands.dat')"
          write (pyunit, '(a)') "x=data[:,0]"
          write (pyunit, '(a,F12.6)') "y=data[:,1]-", fermi_energy_list(1)
          if (pw90_kpath%bands_colour == 'spin') write (pyunit, '(a)') "z=data[:,2]"
          if (pw90_kpath%bands_colour == 'shc') then
            write (pyunit, '(a)') "z=data[:,2]"
            write (pyunit, '(a)') "z=np.array([np.log10(abs(elem))*np.sign(elem) " &
              //"if abs(elem)>10 else elem/10.0 for elem in z])"
          end if
          if (pw90_kpath%bands_colour == 'none') then
            write (pyunit, '(a)') "pl.scatter(x,y,color='k',marker='+',s=0.1)"
          else if (pw90_kpath%bands_colour == 'spin' .or. pw90_kpath%bands_colour == 'shc') then
            write (pyunit, '(a)') &
              "pl.scatter(x,y,c=z,marker='+',s=1,cmap=pl.cm.jet)"
          end if
          write (pyunit, '(a)') "pl.xlim([0,max(x)])"
          write (pyunit, '(a)') "pl.ylim([-0.65,0.65]) # Adjust this range as needed"
          write (pyunit, '(a)') "pl.plot([tick_locs[0],tick_locs[-1]],[0,0]," &
            //"color='black',linestyle='--',linewidth=0.5)"
          write (pyunit, '(a)') "pl.xticks(tick_locs,tick_labels)"
          write (pyunit, '(a)') "for n in range(1,len(tick_locs)):"
          write (pyunit, '(a)') "   pl.plot([tick_locs[n],tick_locs[n]]," &
            //"[pl.ylim()[0],pl.ylim()[1]],color='gray'," &
            //"linestyle='-',linewidth=0.5)"
          write (pyunit, '(a)') "pl.ylabel('Energy$-$E$_F$ [eV]')"
          write (pyunit, '(a)') "pl.tick_params(axis='x'," &
            //"which='both',bottom='off',top='off',labelbottom='off')"
          !
          ! lower panel (curvature or orbital magnetization)
          !
          write (pyunit, '(a)') "axes2 = pl.subplot(gs[1, 0:])"
          if (plot_curv) then
            write (pyunit, '(a)') "data = np.loadtxt('"//trim(seedname)// &
              "-curv.dat')"
          else if (plot_morb) then
            write (pyunit, '(a)') "data = np.loadtxt('"//trim(seedname)// &
              "-morb.dat')"
          end if
          write (pyunit, '(a)') "x=data[:,0]"
          write (pyunit, '(a)') "y=data[:,"//achar(48 + i)//"]"
          write (pyunit, '(a)') "pl.plot(x,y,color='k')"
          write (pyunit, '(a)') "pl.xlim([0,max(x)])"
          write (pyunit, '(a)') "pl.ylim([min(y)-0.025*(max(y)-min(y))," &
            //"max(y)+0.025*(max(y)-min(y))])"
          write (pyunit, '(a)') "pl.xticks(tick_locs,tick_labels)"
          write (pyunit, '(a)') "for n in range(1,len(tick_locs)):"
          write (pyunit, '(a)') "   pl.plot([tick_locs[n],tick_locs[n]]," &
            //"[pl.ylim()[0],pl.ylim()[1]],color='gray'," &
            //"linestyle='-',linewidth=0.5)"
          if (plot_curv) then
            if (pw90_berry%curv_unit == 'ang2') then
              write (pyunit, '(a)') "pl.ylabel('$-\Omega_"//achar(119 + i) &
                //"(\mathbf{k})$  [ $\AA^2$ ]')"
            else if (pw90_berry%curv_unit == 'bohr2') then
              write (pyunit, '(a)') "pl.ylabel('$-\Omega_"//achar(119 + i) &
                //"(\mathbf{k})$  [ bohr$^2$ ]')"
            end if
            write (pyunit, '(a)') "outfile = '"//trim(seedname)// &
              "-bands+curv_"//achar(119 + i)//".pdf'"
          else if (plot_morb) then
            write (pyunit, '(a)') "pl.ylabel(r'$M^{\rm{orb}}_z(\mathbf{k})$" &
              //"  [ Ry$\cdot\AA^2$ ]')"
            write (pyunit, '(a)') "outfile = '"//trim(seedname)// &
              "-morb_"//achar(119 + i)//".pdf'"
          end if
          write (pyunit, '(a)') "pl.savefig(outfile,bbox_inches='tight')"
          write (pyunit, '(a)') "pl.show()"
        end do

      end if ! plot_bands .and. plot_curv

    end if ! on_root

701 format('set style data dots', /, 'unset key', /, &
           'set xrange [0:', F8.5, ']', /, 'set yrange [', F16.8, ' :', F16.8, ']')
702 format('set xtics (', :20('"', A3, '" ', F8.5, ','))
703 format(A3, '" ', F8.5, ')')
!704 format('set palette defined (', F8.5, ' "red", 0 "green", ', F8.5, ' "blue")') !not used
705 format('set arrow from ', F16.8, ',', F16.8, ' to ', F16.8, ',', F16.8, ' nohead')
706 format('unset key', /, &
           'set xrange [0:', F9.5, ']', /, 'set yrange [', F16.8, ' :', F16.8, ']')
707 format('set style data lines', /, 'set nokey', /, &
           'set xrange [0:', F8.5, ']', /, 'set yrange [', F16.8, ' :', F16.8, ']')

  end subroutine k_path

  !================================================!
  !                   PRIVATE PROCEDURES                      !
  !================================================!
  subroutine k_path_print_info(plot_bands, plot_curv, plot_morb, plot_shc, fermi_energy_list, &
                               pw90_kpath, berry_curv_unit, stdout, error, comm)
    !================================================!

    use w90_postw90_types, only: pw90_kpath_mod_type
    use w90_comms, only: w90_comm_type, mpirank

    ! arguments
    real(kind=dp), allocatable, intent(in) :: fermi_energy_list(:)
    type(pw90_kpath_mod_type), intent(in) :: pw90_kpath
    type(w90_comm_type), intent(in) :: comm
    type(w90_error_type), allocatable, intent(out) :: error
    integer, intent(in) :: stdout
    character(len=*), intent(in) :: berry_curv_unit
    logical, intent(in) :: plot_bands, plot_curv, plot_morb, plot_shc

    ! local variables
    integer :: fermi_n
    logical :: on_root = .false.
    if (mpirank(comm) == 0) on_root = .true.

    if (on_root) then
      write (stdout, '(/,/,1x,a)') &
        'Properties calculated in module  k p a t h'
      write (stdout, '(1x,a)') &
        '------------------------------------------'

      if (plot_bands) then
        select case (pw90_kpath%bands_colour)
        case ("none")
          write (stdout, '(/,3x,a)') '* Energy bands in eV'
        case ("spin")
          write (stdout, '(/,3x,a)') '* Energy bands in eV, coloured by spin'
        case ("shc")
          write (stdout, '(/,3x,a)') '* Energy bands in eV, coloured by SHC'
        end select
      end if
      fermi_n = 0
      if (allocated(fermi_energy_list)) fermi_n = size(fermi_energy_list)
      if (plot_curv) then
        if (berry_curv_unit == 'ang2') then
          write (stdout, '(/,3x,a)') '* Negative Berry curvature in Ang^2'
        else if (berry_curv_unit == 'bohr2') then
          write (stdout, '(/,3x,a)') '* Negative Berry curvature in Bohr^2'
        end if
        if (fermi_n /= 1) then
          call set_error_input(error, 'Must specify one Fermi level when kpath_task=curv', comm)
          return
        end if
      end if
      if (plot_morb) then
        write (stdout, '(/,3x,a)') &
          '* Orbital magnetization k-space integrand in eV.Ang^2'
        if (fermi_n /= 1) then
          call set_error_input(error, 'Must specify one Fermi level when kpath_task=morb', comm)
          return
        end if
      end if
      if (plot_shc) then
        if (berry_curv_unit == 'ang2') then
          write (stdout, '(/,3x,a)') '* Berry curvature-like term for' &
            //' spin Hall conductivity in Ang^2'
        else if (berry_curv_unit == 'bohr2') then
          write (stdout, '(/,3x,a)') '* Berry curvature-like term for' &
            //' spin Hall conductivity in Bohr^2'
        end if
        if (fermi_n /= 1) then
          call set_error_input(error, 'Must specify one Fermi level when kpath_task=shc', comm)
          return
        end if
      end if
    end if ! on_root

  end subroutine

  !================================================!
  subroutine k_path_get_points(num_paths, kpath_len, total_pts, xval, plot_kpoint, kpoint_path, &
                               recip_lattice, pw90_kpath)
    !================================================!
    ! Determine the number of k-points (total_pts) as well as           !
    ! their reciprocal-lattice coordinates long the path (plot_kpoint)  !
    ! and their associated horizontal coordinate for the plot (xval)    !
    !================================================!

    use w90_postw90_types, only: pw90_kpath_mod_type
    use w90_types, only: kpoint_path_type
    use w90_utility, only: utility_metric

    ! arguments
    type(pw90_kpath_mod_type), intent(in) :: pw90_kpath
    type(kpoint_path_type), intent(in) :: kpoint_path
    integer, intent(out) :: num_paths, total_pts
    real(kind=dp), allocatable, intent(out)   :: kpath_len(:), xval(:)
    real(kind=dp), allocatable, intent(out) :: plot_kpoint(:, :)
    real(kind=dp), intent(in) :: recip_lattice(3, 3)

    ! local variables
    integer :: counter, loop_path, loop_i
    integer, allocatable :: kpath_pts(:)
    real(kind=dp) :: vec(3)
    real(kind=dp) :: recip_metric(3, 3)

    call utility_metric(recip_lattice, recip_metric)
    ! Work out how many points there are in the total path, and the
    ! positions of the special points
    !
    if (allocated(kpoint_path%labels)) then
      !num_paths = kpoint_path%bands_num_spec_points/2 ! number of straight line segments
      num_paths = size(kpoint_path%labels)/2
    else
      num_paths = 0
    end if
    allocate (kpath_pts(num_paths))
    allocate (kpath_len(num_paths))
    do loop_path = 1, num_paths
      vec = kpoint_path%points(:, 2*loop_path) &
            - kpoint_path%points(:, 2*loop_path - 1)
      kpath_len(loop_path) = &
        sqrt(dot_product(vec, (matmul(recip_metric, vec))))
      !
      ! kpath_pts(loop_path) is the number of points in path number
      ! loop_path (all segments have the same density of points)
      !
      if (loop_path == 1) then
        kpath_pts(loop_path) = pw90_kpath%num_points
      else
        kpath_pts(loop_path) = nint(real(pw90_kpath%num_points, dp) &
                                    *kpath_len(loop_path)/kpath_len(1))
      end if
    end do
    total_pts = sum(kpath_pts) + 1

    ! Reciprocal-lattice coordinates of the k-points along the path
    !
    allocate (plot_kpoint(3, total_pts))

    ! Value of the horizontal coordinate in the actual plots (units of
    ! distance in k-space)
    !
    allocate (xval(total_pts))

    ! Find the position of each kpoint along the path
    !
    counter = 0
    do loop_path = 1, num_paths
      do loop_i = 1, kpath_pts(loop_path)
        counter = counter + 1
        if (counter == 1) then
          xval(counter) = 0.0_dp
        else
          xval(counter) = xval(counter - 1) &
                          + kpath_len(loop_path)/real(kpath_pts(loop_path), dp)
        end if
        plot_kpoint(:, counter) = kpoint_path%points(:, 2*loop_path - 1) &
                                  + (kpoint_path%points(:, 2*loop_path) &
                                     - kpoint_path%points(:, 2*loop_path - 1) &
                                     ) &
                                  *(real(loop_i - 1, dp)/real(kpath_pts(loop_path), dp))
      end do
    end do
    !
    ! Last point
    !
    xval(total_pts) = sum(kpath_len)
    plot_kpoint(:, total_pts) = kpoint_path%points(:, num_paths*2)

  end subroutine

end module w90_kpath
