mod_fermisurf_basic.F90 Source File


Source Code

!-----------------------------------------------------------------------------------------!
! Copyright (c) 2016 Peter Grünberg Institut, Forschungszentrum Jülich, Germany           !
! This file is part of kk-prime@juKKR and available as free software under the conditions !
! of the MIT license as expressed in the LICENSE file in more detail.                     !
!-----------------------------------------------------------------------------------------!


module mod_fermisurf_basic

  implicit none

  private
  public :: ROOT_IMAG, ROOT_ANY, ROOT_REAL, roots_along_edge, compare_two_eigv_in_substeps, &
          & connect_eigw_in_substeps, find_roots_any_eigw, find_roots_any_eigw_memopt, &
          & mark_cubes_FScross, mark_cubes_FScross_memopt, &
          & generate_cubevertices, generate_squarevertices, unroll_ixyz, &
          & read_cubesfile, save_cubesfile, find_kpoints_irredset, save_kpointsfile_vis, &
          & save_kpointsfile_int, testpath, get_cubesinfo_filename, &
          & connect_eigw_in_substeps_memopt, roots_along_edge_memopt, compare_two_eigv_in_substeps_memopt
  integer, parameter :: ROOT_ANY=0, ROOT_REAL=1, ROOT_IMAG=2

contains





  subroutine testpath(inc, lattice, cluster, tgmatrx)

    use type_inc,       only: inc_type
    use type_data,      only: lattice_type, cluster_type, tgmatrx_type
    use mod_eigvects,   only: normeigv_new, compare_eigv
!   use mod_symmetries, only: symmetries_type, set_symmetries, get_IBZwedge_faces
    use mod_kkrmat,     only: compute_kkr_eigenvectors
    use mod_mathtools,  only: bubblesort
    use mod_ioinput,    only: IoInput
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(inout) :: tgmatrx

    integer          :: ltest, nsteps
    double precision :: k1(3), k2(3), dkp(3)
    double precision, allocatable :: ksub(:,:)
    double complex,   allocatable :: LVeig(:,:,:),&
                                   & RVeig(:,:,:),&
                                   & eigw(:,:)

!   type(symmetries_type) :: symmetries
    integer               :: nfaces
    double precision      :: bounds(3,2)
    double precision, allocatable :: nvec(:,:), dscal(:)

    integer          :: sorted(inc%almso)
    double precision :: eigwabs(inc%almso)


    integer          :: nrootsteps, nrootiter, roottype, nroot, lmroot(inc%nrootmax)
    double precision :: kends(3,2), rooteps
    double precision :: kroot(3,inc%nrootmax)
!   double complex   :: LVroot(inc%almso,inc%almso,inc%nrootmax),&
!                     & RVroot(inc%almso,inc%almso,inc%nrootmax),&
!                     & eigwroot(inc%almso,inc%nrootmax)
    double complex, allocatable :: LVroot(:,:,:),&
                                 & RVroot(:,:,:),&
                                 & eigwroot(:,:)
    character(len=8) :: rootinp


    integer :: itest, nlmtest, ikp, lm0, lm1, lm2, ierr
    character(len=80) :: filename
    character(len=80) :: uio
    integer,          allocatable :: ilmtest(:), connection(:,:)

    integer :: indum(6)
    integer :: nCub3(3), nmarked
    integer, allocatable :: imarked(:)

    !--------------------------------------!
    !--- Read in options from inputcard ---!
    !--------------------------------------!
    call IoInput('LTEST     ',uio,1,7,ierr)
    read(unit=uio,fmt=*) ltest
    if(ltest/=1) return

    !initialize symmetries
!   call set_symmetries(inc, lattice, symmetries)
!   call get_IBZwedge_faces(lattice%recbv, symmetries%nsym_used, symmetries%rotmat, symmetries%isym_used, nfaces, nvec, dscal, bounds)
!   call init_cube2tetralines()

    ! TESTPART 1 - PRINT EIGENVALUES
    call IoInput('TESTKPOI1 ',uio,1,7,ierr)
    read(unit=uio,fmt=*) k1
    call IoInput('TESTKPOI2 ',uio,1,7,ierr)
    read(unit=uio,fmt=*) k2
    call IoInput('TESTNKPTS ',uio,1,7,ierr)
    read(unit=uio,fmt=*) nsteps
    call IoInput('NLMTEST   ',uio,1,7,ierr)
    read(unit=uio,fmt=*) nlmtest
    allocate( ilmtest(nlmtest) )
    call IoInput('ILMTEST   ',uio,1,7,ierr)
    read(unit=uio,fmt=*) ilmtest

    allocate( ksub(3,nsteps+1),&
            & LVeig(inc%almso,inc%almso,nsteps+1),&
            & RVeig(inc%almso,inc%almso,nsteps+1),&
            & eigw(inc%almso,nsteps+1),&
            & connection(inc%almso,nsteps+1),&
            & STAT=ierr )
    if(ierr/=0) stop 'Problem allocating arrays in testpath'

    allocate( LVroot(inc%almso,inc%almso,inc%nrootmax),&
            & RVroot(inc%almso,inc%almso,inc%nrootmax),&
            & eigwroot(inc%almso,inc%nrootmax),        &
            & STAT=ierr                                )
    if(ierr/=0) stop 'Problem allocating LVroot etc. in testpath'

    !----------------------------------------------------!
    !--- create submesh to divide the input-intervall ---!
    !---  and find the KKR-matrix, -eigenvectors and  ---!
    !---      -eigenvalues on each sub-kpoint         ---!
    !----------------------------------------------------!
    dkp = (k2 - k1)/nsteps
    do ikp=1,nsteps+1
      ksub(:,ikp) = k1 + dble(ikp-1)*dkp
      call compute_kkr_eigenvectors( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
                                   & tgmatrx%tinvll(:,:,:,1), ksub(:,ikp),        &
                                   & eigw(:,ikp), LVeig(:,:,ikp), RVeig(:,:,ikp)  )
!     call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
!                                   & tgmatrx%tmat(:,:,1), ksub(:,ikp),            &
!                                   & eigw(:,ikp), LVeig(:,:,ikp), RVeig(:,:,ikp)  )
    end do!ikp


    !write the (sorted) eigenvalues to a file
    open(unit=135,file='test.eigw.txt',form='formatted',action='write')
    write(135,'("# real(eigw)             | imag(eigw)             | abs(eigw)              | ikp | lm")')
    do ikp=1,nsteps+1
      eigwabs = abs(eigw(:,ikp))
      call bubblesort(inc%almso, eigwabs, sorted)
      do lm0=1,inc%almso
        write(135,'(3ES25.16,2(2X,I0))') eigw(sorted(lm0),ikp), abs(eigw(sorted(lm0),ikp)), ikp, sorted(lm0)
      end do!lm0=1,inc%almso
    end do!ikp
    close(135)

    !for selected eigenvalues, write the eigenvalue-path to a file
    do itest=1,nlmtest
      lm1 = ilmtest(itest)

      write(filename,'("test.path_lm=",I0,".txt")') lm1
      open(unit=368, file=trim(filename), action='write', form='formatted')
      write(368,'("# real(eigw)             | imag(eigw)             | abs(eigw)              | ikp | lm")')
      write(368,'(3ES25.16,2X,I4,2X,I3)') eigw(lm1,1), abs(eigw(lm1,1)), 1, lm1

      write(filename,'("test.proj_lm=",I0,".txt")') lm1
      open(unit=468, file=trim(filename), action='write', form='formatted')
      write(468,'("#  max_{-n}(proj) .... max(proj) ")')

      do ikp=1,nsteps
        call compare_eigv(inc, LVeig(:,lm1,ikp), RVeig(:,:,ikp+1), lm2, 468)
        write(368,'(3ES25.16,2X,I4,2X,I3)') eigw(lm2,ikp+1), abs(eigw(lm2,ikp+1)), ikp+1, lm2
        lm1 = lm2
      end do!ikp
      close(368)
      close(468)
    end do!itest



!######################################################
!### test the subroutine 'connect_eigw_in_substeps' ###
!######################################################
    kends(:,1) = k1
    kends(:,2) = k2
    call connect_eigw_in_substeps( inc, lattice, cluster, tgmatrx, nsteps, kends, &
                                 & connection, ksub, eigw, LVeig, RVeig           )

    !write the (sorted) eigenvalues to a file
    open(unit=335,file='test.connect.eigw.txt',form='formatted',action='write')
    write(335,'("# real(eigw)             | imag(eigw)             | abs(eigw)              | ikp | lm")')
    do ikp=1,nsteps+1
      eigwabs = abs(eigw(:,ikp))
      call bubblesort(inc%almso, eigwabs, sorted)
      do lm0=1,inc%almso
        write(335,'(3ES25.16,2(2X,I0))') eigw(sorted(lm0),ikp), abs(eigw(sorted(lm0),ikp)), ikp, sorted(lm0)
      end do!lm0=1,inc%almso
    end do!ikp
    close(335)

    !for selected eigenvalues, write the eigenvalue-path to a file
    do itest=1,nlmtest
      lm1 = ilmtest(itest)
      write(filename,'("test.connect.lm=",I0,".txt")') lm1
      open(unit=368, file=trim(filename), action='write', form='formatted')

      write(368,'("# real(eigw)             | imag(eigw)             | abs(eigw)              | ikp | lm")')
      write(368,'(3ES25.16,2X,I4,2X,I3)') eigw(lm1,1), abs(eigw(lm1,1)), 1, lm1

      do ikp=1,nsteps
        lm2 = connection(lm1,ikp+1)
        write(368,'(3ES25.16,2X,I4,2X,I3)') eigw(lm2,ikp+1), abs(eigw(lm2,ikp+1)), ikp+1, lm2
      end do!ikp
      close(368)
    end do!itest



!##############################################
!### test the subroutine 'roots_along_edge' ###
!##############################################
    call IoInput('ROOTTSTPS ',uio,1,7,ierr)
    read(unit=uio,fmt=*) nrootsteps
    write(*,'("rootsteps= ",I0)') nrootsteps

    call IoInput('ROOTTITER ',uio,1,7,ierr)
    read(unit=uio,fmt=*) nrootiter
    write(*,'("rootiter= ",I0)') nrootiter

    call IoInput('ROOTTTYPE ',uio,1,7,ierr)
    read (unit=uio,fmt=*) rootinp
    select case (trim(rootinp))
      case('real'); roottype=ROOT_REAL
      case('imag'); roottype=ROOT_IMAG
      case default; stop 'case for roottype not known: real/imag'
    end select
    write(*,'("rootinp= ",(A),", FLAG=",I0)') rootinp, roottype

    call IoInput('ROOTTEPS  ',uio,1,7,ierr)
    read (unit=uio,fmt=*) rooteps
    write(*,'("rooteps= ",ES18.9)') rooteps

    kends(:,1) = k1
    kends(:,2) = k2
    write(*,'("kends(:,1)= (",3ES18.9,")")') kends(:,1)
    write(*,'("kends(:,2)= (",3ES18.9,")")') kends(:,2)
    open(unit=136,file='test.roots_along_edge.txt',form='formatted',action='write')
    call roots_along_edge( inc, lattice, cluster, tgmatrx, nrootsteps, kends, nrootiter, &
                         & roottype, rooteps, nroot, lmroot, kroot, LVroot, RVroot,      &
                         & eigwroot, 136                                                 )
    close(136)

    deallocate(LVroot,RVroot,eigwroot,ksub,LVeig,RVeig,eigw,connection,STAT=ierr)

  end subroutine testpath





  subroutine connect_eigw_in_substeps( inc, lattice, cluster, tgmatrx, nsteps, kends, &
                                     & connection, ksub, eigw, LVeig, RVeig           )
  !===========================================================================================!
  ! Connect the eigenvalues between two k-points, kends(:,1) and kends(:,2).                  !
  ! The connection is made by dividing the intervall into nsteps subintervals,                !
  !   and comparing the eigenvectors of each subinterval.                                     !
  !                                                                                           !
  ! The subroutine returns:                                                                   !
  !  - the connection-array, defined by:                                                      !
  !      eigw(lm1, ikp=1) == eigw(connection(lm1,1),1) <--> eigw(connection(lm1,ikp),ikp)     !
  !  - the kpoints of the submesh                                                             !
  !  - the eigenvalues and correcly normalized (left and right) eigenvectors                  !
  !===========================================================================================!

    use type_inc
    use type_data,    only: lattice_type, cluster_type, tgmatrx_type
    use mod_kkrmat,   only: compute_kkr_eigenvectors
    use mod_eigvects, only: compare_eigv
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(in) :: tgmatrx
    integer,            intent(in) :: nsteps
    double precision,   intent(in) :: kends(3,2)

    integer,          intent(out) :: connection(inc%almso,nsteps+1)
    double precision, intent(out) :: ksub(3,nsteps+1)
    double complex,   intent(out) :: LVeig(inc%almso,inc%almso,nsteps+1),&
                                   & RVeig(inc%almso,inc%almso,nsteps+1),&
                                   & eigw(inc%almso,nsteps+1)

    !--- Locals ---

    integer :: ikp, ierr, lm1, lmconn, istep

    ! helper variables
    double precision :: dkp(3)

    dkp = (kends(:,2) - kends(:,1))/nsteps
    do ikp=1,nsteps+1

      !--- create submesh to divide the input-intervall ---!
      ksub(:,ikp) = kends(:,1) + dble(ikp-1)*dkp

      !--- find the KKR-matrix, -eigenvectors and ---!
      !---  -eigenvalues on each sub-kpoint       ---!
      call compute_kkr_eigenvectors( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
                                   & tgmatrx%tinvll(:,:,:,1), ksub(:,ikp),        &
                                   & eigw(:,ikp), LVeig(:,:,ikp), RVeig(:,:,ikp)  )
!     call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
!                                   & tgmatrx%tmat(:,:,1), ksub(:,ikp),            &
!                                   & eigw(:,ikp), LVeig(:,:,ikp), RVeig(:,:,ikp)  )
    end do!ikp



    !-----------------------------------------------------!
    !--- for each step: make connection of eigenvalues ---!
    !--- between 2 k-points by comparing eigenvectors. ---!
    !-----------------------------------------------------!

    !initialize the connections
    connection = 0
    do lm1=1,inc%almso
        connection(lm1,1) = lm1
    end do!lm1

    !compare eigenvectors and make the connection
    do istep=1,nsteps
      do lm1=1,inc%almso
        lmconn = connection(lm1,istep)
        call compare_eigv(inc, LVeig(:,lmconn,istep), RVeig(:,:,istep+1), connection(lm1,istep+1))
      end do!lm1
    end do!istep


  end subroutine connect_eigw_in_substeps





  subroutine connect_eigw_in_substeps_memopt( inc, lattice, cluster, tgmatrx, nsteps, kends, &
                                     & connection, ksub, eigw, LVeig, RVeig, nb_bands      )
  !===========================================================================================!
  ! Connect the eigenvalues between two k-points, kends(:,1) and kends(:,2).                  !
  ! The connection is made by dividing the intervall into nsteps subintervals,                !
  !   and comparing the eigenvectors of each subinterval.                                     !
  !                                                                                           !
  ! The subroutine returns:                                                                   !
  !  - the connection-array, defined by:                                                      !
  !      eigw(lm1, ikp=1) == eigw(connection(lm1,1),1) <--> eigw(connection(lm1,ikp),ikp)     !
  !  - the kpoints of the submesh                                                             !
  !  - the eigenvalues and correcly normalized (left and right) eigenvectors                  !
  !===========================================================================================!

    use type_inc
    use type_data,    only: lattice_type, cluster_type, tgmatrx_type
    use mod_kkrmat,   only: compute_kkr_eigenvectors, compute_kkr_eigenvectors_memopt
    use mod_eigvects, only: compare_eigv, compare_eigv_memopt
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(in) :: tgmatrx
    integer,            intent(in) :: nsteps
    double precision,   intent(in) :: kends(3,2)

    integer,          intent(out) :: connection(inc%neig,nsteps+1)
    double precision, intent(out) :: ksub(3,nsteps+1)
    double complex,   intent(out) :: LVeig(inc%almso,inc%neig,nsteps+1),&
                                   & RVeig(inc%almso,inc%neig,nsteps+1),&
                                   & eigw(inc%neig,nsteps+1)
    integer                       :: nb_ev(nsteps+1)
    integer,          intent(out) :: nb_bands                       

    !--- Locals ---

    integer :: ikp, ierr, lm1, lmconn, istep

    ! helper variables
    double precision :: dkp(3)

    dkp = (kends(:,2) - kends(:,1))/nsteps
    do ikp=1,nsteps+1

      !--- create submesh to divide the input-intervall ---!
      ksub(:,ikp) = kends(:,1) + dble(ikp-1)*dkp

      !--- find the KKR-matrix, -eigenvectors and ---!
      !---  -eigenvalues on each sub-kpoint       ---!
      call compute_kkr_eigenvectors_memopt( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
                                   & tgmatrx%tinvll(:,:,:,1), ksub(:,ikp),        &
                                   & eigw(:,ikp), LVeig(:,:,ikp), RVeig(:,:,ikp),nb_ev(ikp))
!     call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
!                                   & tgmatrx%tmat(:,:,1), ksub(:,ikp),            &
!                                   & eigw(:,ikp), LVeig(:,:,ikp), RVeig(:,:,ikp)  )
    end do!ikp

    nb_bands=nb_ev(1)


    !-----------------------------------------------------!
    !--- for each step: make connection of eigenvalues ---!
    !--- between 2 k-points by comparing eigenvectors. ---!
    !-----------------------------------------------------!

    !initialize the connections
    connection = 0
    do lm1=1,nb_bands
        connection(lm1,1) = lm1
    end do!lm1

    !compare eigenvectors and make the connection
    do istep=1,nsteps
      do lm1=1,nb_bands
        lmconn = connection(lm1,istep)
        call compare_eigv_memopt(inc, LVeig(:,lmconn,istep), RVeig(:,:,istep+1), nb_ev(istep+1), connection(lm1,istep+1))
      end do!lm1
    end do!istep


  end subroutine connect_eigw_in_substeps_memopt





  subroutine roots_along_edge( inc, lattice, cluster, tgmatrx, nsteps, kends, niterate, &
                             & roottype, rooteps, nroot, lmroot, kroot, LVroot,         &
                             & RVroot, eigwroot, uio, eigwends                          )
  !===========================================================================================!
  ! Find the roots of the KKR eigenvalues along a line from kends(:,1) to kends(:,2).         !
  !                                                                                           !
  ! In a first step, the line is divided into nedgesteps subintervals (see routine            !
  !   connect_eigw_in_substeps for details). Then, an iterative scheme (nested intervals) is  !
  !   used to refine the position of the root on the line.                                    !
  !   If uio>0, then information if written to the io-unit 'uio'.                             !
  !                                                                                           !
  ! The subroutine returns:                                                                   !
  !  - nroot:         the number of roots on the edge.                                        !
  !  - lmroot(j):     the number of eigenvalue belonging to the root at the j-th k-point.     !
  !  - kroot(:,:,j):  the j-th k-point where an eigenvalue becomes zero.                      !
  !  - LVroot(:,:,j): all left EVs at the j-th kpoint.                                        !
  !  - RVroot(:,:,j): all right EVs at the j-th kpoint.                                       !
  !  - eigwroot(:,j): all eigenvalues at the j-th kpoint.                                     !
  !  - eigwends(i,j): the eigenvalues of the band belonging to the j-th k-point at the start  !
  !===========================================================================================!

    use type_inc
    use type_data,    only: lattice_type, cluster_type, tgmatrx_type
    use mod_kkrmat,   only: compute_kkr_eigenvectors
    use mod_eigvects, only: compare_eigv
    use mod_mathtools,only: bubblesort
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(in) :: tgmatrx
    integer,            intent(in) :: nsteps, niterate, uio
    double precision,   intent(in) :: kends(3,2)
    integer,            intent(in) :: roottype
    double precision,   intent(in) :: rooteps
    integer,            intent(out) :: nroot, lmroot(inc%nrootmax)
    double precision,   intent(out) :: kroot(3,inc%nrootmax)
    double complex,     intent(out) :: LVroot(inc%almso,inc%almso,inc%nrootmax), &
                                     & RVroot(inc%almso,inc%almso,inc%nrootmax), &
                                     & eigwroot(inc%almso,inc%nrootmax)
    double complex, intent(out), optional :: eigwends(2,inc%nrootmax)

    integer          :: connection(inc%almso,nsteps+1), root_interval(inc%almso)
    double precision :: kpoints_steps(3,nsteps+1)
    double complex   :: LV_steps(inc%almso,inc%almso,nsteps+1),&
                      & RV_steps(inc%almso,inc%almso,nsteps+1),&
                      & eigw_steps(inc%almso,nsteps+1)

    ! for the iterative scheme
    integer          :: iter, step_intersect, counter
    double precision :: xtmp, dtmp, kleft(3), kright(3), kmiddle(3)
    double complex   :: LVleft(inc%almso), &
                      & RVleft(inc%almso), &
                      & LVright(inc%almso),&
                      & RVright(inc%almso),&
                      & eigwleft,          &
                      & eigwright,         &
                      & eigwmiddle(inc%almso),        &
                      & LVmiddle(inc%almso,inc%almso),&
                      & RVmiddle(inc%almso,inc%almso)

    integer :: lmsort(inc%almso), loopstep, lmi, lm1, ierr, newconnect
    double precision :: dtmpsort(inc%almso)

    call connect_eigw_in_substeps( inc, lattice, cluster, tgmatrx, nsteps, kends,            &
                                   & connection, kpoints_steps, eigw_steps, LV_steps, RV_steps )

    !determine which eigenvalues to scan
    if(inc%ndegen==2)then
      !in case of a degeneracy of each eigenvalue, take only one of each pair
      dtmpsort = abs(eigw_steps(:,1))
      call bubblesort(inc%almso, dtmpsort, lmsort) ! returns permutation in sortindx
      loopstep = 2 !skip every second eigenvalue (see loop below)
    else
      do lm1=1,inc%almso
        lmsort(lm1) = lm1
      end do!lm1
      loopstep = 1
    end if

    root_interval = 0
    !find which lm intersects with zero and store the interval-number
    do lmi=1,inc%almso,loopstep
      call find_roots_lm_eigw(inc%almso,nsteps,connection,eigw_steps,roottype,1d0,lmsort(lmi),root_interval(lmi))
    end do!lmi

    if(uio>0) write(uio,'("Number of possible roots=" ,I0)') count(root_interval>0)

    !find the precise k-point by iteration
    counter = 0
    lmloop: do lmi=1,inc%almso,loopstep

      !pick variables
      lm1 = lmsort(lmi)
      step_intersect = root_interval(lmi)
      if(uio>0) write(uio,'(2X,"lm= ",I0,", interval= ",I0,", abs(eigw)= ",ES18.9)') lm1, step_intersect, abs(eigw_steps(lm1,1))
      if(step_intersect==0) cycle !no intersection of this eigenvalue with the k-point

      ! pick kpoints, eigenvectors and eigenvalues of this subinterval
      kleft(:)  = kpoints_steps(:,step_intersect)
      LVleft(:) = LV_steps(:,connection(lm1,step_intersect),step_intersect)
      RVleft(:) = RV_steps(:,connection(lm1,step_intersect),step_intersect)
      eigwleft  = eigw_steps(connection(lm1,step_intersect),step_intersect)

      kright(:)  = kpoints_steps(:,step_intersect+1)
      LVright(:) = LV_steps(:,connection(lm1,step_intersect+1),step_intersect+1)
      RVright(:) = RV_steps(:,connection(lm1,step_intersect+1),step_intersect+1)
      eigwright  = eigw_steps(connection(lm1,step_intersect+1),step_intersect+1)


      !================ START ===============!
      !--- Refine the k-point on the edge ---!
      !======================================!
      do iter=1,niterate

        !--------------------------------------------------------!
        ! STEP b): determine the interpolated intersection-point !
        !--------------------------------------------------------!
        select case (roottype)
          case(ROOT_REAL)
            xtmp = dble(eigwleft)/(dble(eigwleft)-dble(eigwright))
          case(ROOT_IMAG)
            xtmp = aimag(eigwleft)/(aimag(eigwleft)-aimag(eigwright))
          case default; stop 'option not known: only real/imag'
        end select!roottype

        kmiddle = (1d0-xtmp)*kleft + xtmp*kright

        !--------------------------------------------------------------------!
        ! STEP c): determine the (true) eigenvalue at the interpolated point !
        !--------------------------------------------------------------------!

        call compute_kkr_eigenvectors( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
                                     & tgmatrx%tinvll(:,:,:,1), kmiddle,            &
                                     & eigwmiddle, LVmiddle, RVmiddle               )
!       call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
!                                     & tgmatrx%tmat(:,:,1), kmiddle,                &
!                                     & eigwmiddle, LVmiddle, RVmiddle               )

        ! make the connection to the left end of the interval
        newconnect=0
        call compare_eigv( inc, LVleft, RVmiddle, newconnect )



        !-------------------------------------!
        ! STEP c): determine the new interval !
        !-------------------------------------!
        select case (roottype)
          case(ROOT_REAL)
            dtmp = dble(eigwleft)*dble(eigwmiddle(newconnect))
          case(ROOT_IMAG)
            dtmp = aimag(eigwleft)*aimag(eigwmiddle(newconnect))
          case default; stop 'option not known: only real/imag'
        end select!roottype

        if(dtmp<0d0)then
          kright(:)  = kmiddle
          LVright(:) = LVmiddle(:,newconnect)
          RVright(:) = RVmiddle(:,newconnect)
          eigwright  = eigwmiddle(newconnect)
        else
          kleft(:)  = kmiddle
          LVleft(:) = LVmiddle(:,newconnect)
          RVleft(:) = RVmiddle(:,newconnect)
          eigwleft  = eigwmiddle(newconnect)
        end if

        if(uio>0) write(uio,'(4X,"iter= ",I0,", kmiddle= (",3ES25.16,"), eigw_min=(",2ES18.9,"), abs(eigw_min)= ",ES18.9,", lm_min=",I0)') iter, kmiddle, eigwmiddle(newconnect), abs(eigwmiddle(newconnect)), newconnect

      end do!iter
      !======================================!
      !--- Refine the k-point on the edge ---!
      !=============== END ==================!

      !save results
      if(abs(eigwmiddle(newconnect))<rooteps)then
        counter = counter+1
        if(counter>inc%nrootmax)then
          counter = counter-1
          write(*,*) 'Attention: counter>nrootmax is reached'
          exit lmloop
        end if!counter>inc%nrootmax

        kroot(:,counter)  = kmiddle
        LVroot(:,:,counter) = LVmiddle(:,:)
        RVroot(:,:,counter) = RVmiddle(:,:)
        eigwroot(:,counter) = eigwmiddle(:)
        lmroot(counter)     = newconnect
        if(present(eigwends))then
          eigwends(1,counter) = eigw_steps(connection(lm1,1),1)
          eigwends(2,counter) = eigw_steps(connection(lm1,nsteps+1),nsteps+1)
        end if
      end if!abs(dtmp)<rooteps

    end do lmloop!lmi

    nroot=counter
    if(uio>0) write(uio,'("Number of roots found matching the criteria: ", I0)') nroot
    if(uio>0 .and. nroot>0) write(uio,'(2X,"lm= ",8I8)') lmroot(1:nroot)

  end subroutine roots_along_edge





  subroutine roots_along_edge_memopt( inc, lattice, cluster, tgmatrx, nsteps, kends, niterate, &
                             & roottype, rooteps, nroot, lmroot, kroot, LVroot,                &
                             & RVroot, eigwroot, uio, eigwends                                 )
  !===========================================================================================!
  ! Find the roots of the KKR eigenvalues along a line from kends(:,1) to kends(:,2).         !
  !                                                                                           !
  ! In a first step, the line is divided into nedgesteps subintervals (see routine            !
  !   connect_eigw_in_substeps for details). Then, an iterative scheme (nested intervals) is  !
  !   used to refine the position of the root on the line.                                    !
  !   If uio>0, then information if written to the io-unit 'uio'.                             !
  !                                                                                           !
  ! The subroutine returns:                                                                   !
  !  - nroot:         the number of roots on the edge.                                        !
  !  - lmroot(j):     the number of eigenvalue belonging to the root at the j-th k-point.     !
  !  - kroot(:,:,j):  the j-th k-point where an eigenvalue becomes zero.                      !
  !  - LVroot(:,:,j): all left EVs at the j-th kpoint.                                        !
  !  - RVroot(:,:,j): all right EVs at the j-th kpoint.                                       !
  !  - eigwroot(:,j): all eigenvalues at the j-th kpoint.                                     !
  !  - eigwends(i,j): the eigenvalues of the band belonging to the j-th k-point at the start  !
  !===========================================================================================!

    use type_inc
    use type_data,    only: lattice_type, cluster_type, tgmatrx_type
    use mod_kkrmat,   only: compute_kkr_eigenvectors, compute_kkr_eigenvectors_memopt
    use mod_eigvects, only: compare_eigv, compare_eigv_memopt
    use mod_mathtools,only: bubblesort
    use mod_mympi,    only: myrank, nranks, master
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(in) :: tgmatrx
    integer,            intent(in) :: nsteps, niterate, uio
    double precision,   intent(in) :: kends(3,2)
    integer,            intent(in) :: roottype
    double precision,   intent(in) :: rooteps
    integer,            intent(out) :: nroot, lmroot(inc%nrootmax)
    double precision,   intent(out) :: kroot(3,inc%nrootmax)
    double complex,     intent(out) :: LVroot(inc%almso,inc%neig,inc%nrootmax), &
                                     & RVroot(inc%almso,inc%neig,inc%nrootmax), &
                                     & eigwroot(inc%neig,inc%nrootmax)
    integer                         :: nb_bands_roots(inc%nrootmax)
    double complex, intent(out), optional :: eigwends(2,inc%nrootmax)

    integer          :: connection(inc%neig,nsteps+1), root_interval(inc%neig)
    double precision :: kpoints_steps(3,nsteps+1)
    double complex   :: LV_steps(inc%almso,inc%neig,nsteps+1),&
                      & RV_steps(inc%almso,inc%neig,nsteps+1),&
                      & eigw_steps(inc%neig,nsteps+1)

    ! for the iterative scheme
    integer          :: iter, step_intersect, counter
    double precision :: xtmp, dtmp, kleft(3), kright(3), kmiddle(3)
    double complex   :: LVleft(inc%almso),           &
                      & RVleft(inc%almso),           &
                      & LVright(inc%almso),          &
                      & RVright(inc%almso),          &
                      & eigwleft,                    &
                      & eigwright,                   &
                      & eigwmiddle(inc%neig),        &
                      & LVmiddle(inc%almso,inc%neig),&
                      & RVmiddle(inc%almso,inc%neig)

    integer :: lmsort(inc%neig), loopstep, lmi, lm1, ierr, newconnect, nb_bands
    double precision :: dtmpsort(inc%neig)


    call connect_eigw_in_substeps_memopt( inc, lattice, cluster, tgmatrx, nsteps, kends,            &
                                 & connection, kpoints_steps, eigw_steps, LV_steps, RV_steps, nb_bands )

    !determine which eigenvalues to scan
    if(inc%ndegen==2)then
      !in case of a degeneracy of each eigenvalue, take only one of each pair
      dtmpsort = abs(eigw_steps(:,1))
      call bubblesort(inc%neig, dtmpsort, lmsort) ! returns permutation in sortindx
      loopstep = 2 !skip every second eigenvalue (see loop below)
    else
      do lm1=1,inc%neig
        lmsort(lm1) = lm1
      end do!lm1
      loopstep = 1
    end if

    root_interval = 0
    !find which lm intersects with zero and store the interval-number
    do lmi=1,nb_bands,loopstep
      call find_roots_lm_eigw_memopt(inc%neig,inc%reig,nsteps,connection,eigw_steps,roottype,1d0,lmsort(lmi),root_interval(lmi))
    end do!lmi

    if(uio>0) write(uio,'("Number of possible roots=" ,I0)') count(root_interval>0)

    !find the precise k-point by iteration
    counter = 0
    nb_bands_roots = 0
    lmloop: do lmi=1,nb_bands,loopstep

      !pick variables
      lm1 = lmsort(lmi)
      step_intersect = root_interval(lmi)
!      if(uio>0) write(uio,'(2X,"lm= ",I0,", interval= ",I0,", abs(eigw)= ",ES18.9)') lm1, step_intersect, abs(eigw_steps(lm1,1))
      if(uio>0) write(uio,'(2X,"lm= ",I0,", interval= ",I0,", real(eigw)= ",ES18.9,", imag(eigw)= ",ES18.9)') lm1, step_intersect, dble(eigw_steps(lm1,1)),aimag(eigw_steps(lm1,1))
      if(step_intersect==0) cycle !no intersection of this band with zero

      ! pick kpoints, eigenvectors and eigenvalues of this subinterval
      kleft(:)  = kpoints_steps(:,step_intersect)
      LVleft(:) = LV_steps(:,connection(lm1,step_intersect),step_intersect)
      RVleft(:) = RV_steps(:,connection(lm1,step_intersect),step_intersect)
      eigwleft  = eigw_steps(connection(lm1,step_intersect),step_intersect)

      kright(:)  = kpoints_steps(:,step_intersect+1)
      LVright(:) = LV_steps(:,connection(lm1,step_intersect+1),step_intersect+1)
      RVright(:) = RV_steps(:,connection(lm1,step_intersect+1),step_intersect+1)
      eigwright  = eigw_steps(connection(lm1,step_intersect+1),step_intersect+1)


      !================ START ===============!
      !--- Refine the k-point on the edge ---!
      !======================================!
      do iter=1,niterate

        !--------------------------------------------------------!
        ! STEP b): determine the interpolated intersection-point !
        !--------------------------------------------------------!
        select case (roottype)
          case(ROOT_REAL)
            xtmp = dble(eigwleft)/(dble(eigwleft)-dble(eigwright))
          case(ROOT_IMAG)
            xtmp = aimag(eigwleft)/(aimag(eigwleft)-aimag(eigwright))
          case default; stop 'option not known: only real/imag'
        end select!roottype

        kmiddle = (1d0-xtmp)*kleft + xtmp*kright

        !--------------------------------------------------------------------!
        ! STEP c): determine the (true) eigenvalue at the interpolated point !
        !--------------------------------------------------------------------!

        call compute_kkr_eigenvectors_memopt( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),   &
                                     & tgmatrx%tinvll(:,:,:,1), kmiddle,                      &
                                     & eigwmiddle, LVmiddle, RVmiddle, nb_bands_roots(counter))
!       call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
!                                     & tgmatrx%tmat(:,:,1), kmiddle,                &
!                                     & eigwmiddle, LVmiddle, RVmiddle               )

        ! make the connection to the left end of the interval
        newconnect=0
        call compare_eigv_memopt( inc, LVleft,RVmiddle,nb_bands_roots(counter),newconnect)



        !-------------------------------------!
        ! STEP c): determine the new interval !
        !-------------------------------------!
        select case (roottype)
          case(ROOT_REAL)
            dtmp = dble(eigwleft)*dble(eigwmiddle(newconnect))
          case(ROOT_IMAG)
            dtmp = aimag(eigwleft)*aimag(eigwmiddle(newconnect))
          case default; stop 'option not known: only real/imag'
        end select!roottype

        if(dtmp<0d0)then
          kright(:)  = kmiddle
          LVright(:) = LVmiddle(:,newconnect)
          RVright(:) = RVmiddle(:,newconnect)
          eigwright  = eigwmiddle(newconnect)
        else
          kleft(:)  = kmiddle
          LVleft(:) = LVmiddle(:,newconnect)
          RVleft(:) = RVmiddle(:,newconnect)
          eigwleft  = eigwmiddle(newconnect)
        end if

        if(uio>0) write(uio,'(4X,"iter= ",I0,", kmiddle= (",3ES25.16,"), eigw_min=(",2ES18.9,"), abs(eigw_min)= ",ES18.9,", lm_min=",I0)') iter, kmiddle, eigwmiddle(newconnect), abs(eigwmiddle(newconnect)), newconnect

      end do!iter
      !======================================!
      !--- Refine the k-point on the edge ---!
      !=============== END ==================!

      !save results
      if(abs(eigwmiddle(newconnect))<rooteps)then
        counter = counter+1
        if(counter>inc%nrootmax)then
          counter = counter-1
          write(*,*) 'Attention: counter>nrootmax is reached'
          exit lmloop
        end if!counter>inc%nrootmax

        kroot(:,counter)  = kmiddle
        LVroot(:,:,counter) = LVmiddle(:,:)
        RVroot(:,:,counter) = RVmiddle(:,:)
        eigwroot(:,counter) = eigwmiddle(:)
        lmroot(counter)     = newconnect
        if(present(eigwends))then
          eigwends(1,counter) = eigw_steps(connection(lm1,1),1)
          eigwends(2,counter) = eigw_steps(connection(lm1,nsteps+1),nsteps+1)
        end if
      end if!abs(dtmp)<rooteps

    end do lmloop!lmi
    if(myrank==master)write(123,*)eigwroot(:,1)
    if(myrank==master)write(124,*)eigwroot(:,2)
    nroot=counter
    if(uio>0) write(uio,'("Number of roots found matching the criteria: ", I0)') nroot
    if(uio>0 .and. nroot>0) write(uio,'(2X,"lm= ",8I8)') lmroot(1:nroot)

  end subroutine roots_along_edge_memopt





  subroutine find_roots_any_eigw(almso,nsteps,connection,eigw,roottype,rooteps,anyroot)

    implicit none

    integer,          intent(in) :: almso, nsteps, connection(almso,nsteps+1)
    double complex,   intent(in) :: eigw(almso,nsteps+1)
    integer,          intent(in) :: roottype
    double precision, intent(in) :: rooteps

    logical, intent(out) :: anyroot

    integer          :: istep, lm1
    double precision :: dtmp1, dtmp2, xscal
    double complex   :: ctmp1, ctmp2

    !search for an root on the edge
    anyroot=.false.
    outer: do istep=1,nsteps
      inner: do lm1=1,almso


        ctmp1 = eigw(connection(lm1,istep), istep)
        ctmp2 = eigw(connection(lm1,istep+1), istep+1)

        select case (roottype)
          case(ROOT_ANY)
            dtmp1 =  dble(ctmp1) *  dble(ctmp2)
            dtmp2 = aimag(ctmp1) * aimag(ctmp2)
            if(dtmp1<0d0 .or.  dtmp2<0d0 )then
              anyroot = .true.
              exit outer
            end if
          case(ROOT_REAL)
            dtmp1 =  dble(ctmp1) *  dble(ctmp2)
            xscal = -dble(ctmp1) / (dble(ctmp2) - dble(ctmp1))
            dtmp2 = (aimag(ctmp2)-aimag(ctmp1))*xscal + aimag(ctmp1)
            if(dtmp1<0d0 .and.  abs(dtmp2)<rooteps )then
              anyroot = .true.
              exit outer
            end if
          case(ROOT_IMAG)
            dtmp1 =  aimag(ctmp1) *  aimag(ctmp2)
            xscal = -aimag(ctmp1) / (aimag(ctmp2) - aimag(ctmp1))
            dtmp2 = (dble(ctmp2)-dble(ctmp1))*xscal + dble(ctmp1)
            if(dtmp1<0d0 .and.  abs(dtmp2)<rooteps )then
              anyroot = .true.
              exit outer
            end if
          case default; stop 'option not known'
        end select!roottype

      end do inner!lm1
    end do outer!istep

  end subroutine find_roots_any_eigw





  subroutine find_roots_any_eigw_memopt(neig,reig,nb_bands,nsteps,connection,eigw,roottype,rooteps,anyroot)

    implicit none

    integer,          intent(in) :: neig, nsteps, connection(neig,nsteps+1), nb_bands
    double precision, intent(in) :: reig
    double complex,   intent(in) :: eigw(neig,nsteps+1)
    integer,          intent(in) :: roottype
    double precision, intent(in) :: rooteps

    logical, intent(out) :: anyroot

    integer          :: istep, lm1
    double precision :: dtmp1, dtmp2, xscal
    double complex   :: ctmp1, ctmp2

    !search for an root on the edge
    anyroot=.false.
    outer: do istep=1,nsteps
      inner: do lm1=1,nb_bands


        ctmp1 = eigw(connection(lm1,istep), istep)
        ctmp2 = eigw(connection(lm1,istep+1), istep+1)

        select case (roottype)
          case(ROOT_ANY)
            dtmp1 =  dble(ctmp1) *  dble(ctmp2)
            dtmp2 = aimag(ctmp1) * aimag(ctmp2)
            if(dtmp1<0d0 .or.  dtmp2<0d0 )then
              if(abs(eigw(connection(lm1,istep),istep)) < reig*0.75) then
                ! otherwise probability is high that the two eigen values are not from the
                ! same band and that the root is an accident
                anyroot = .true.
                exit outer
              end if!abs(eigw(connection(lm1,istep),istep)) < reig/2.0
            end if
          case(ROOT_REAL)
            dtmp1 =  dble(ctmp1) *  dble(ctmp2)
            xscal = -dble(ctmp1) / (dble(ctmp2) - dble(ctmp1))
            dtmp2 = (aimag(ctmp2)-aimag(ctmp1))*xscal + aimag(ctmp1)
            if(dtmp1<0d0 .and.  abs(dtmp2)<rooteps )then
              if(abs(eigw(connection(lm1,istep),istep)) < reig*0.75) then
                ! otherwise probability is high that the two eigen values are not from the
                ! same band and that the root is an accident
                anyroot = .true.
                exit outer
              end if!abs(eigw(connection(lm1,istep),istep)) < reig/2.0
            end if
          case(ROOT_IMAG)
            dtmp1 =  aimag(ctmp1) *  aimag(ctmp2)
            xscal = -aimag(ctmp1) / (aimag(ctmp2) - aimag(ctmp1))
            dtmp2 = (dble(ctmp2)-dble(ctmp1))*xscal + dble(ctmp1)
            if(dtmp1<0d0 .and.  abs(dtmp2)<rooteps )then
              if(abs(eigw(connection(lm1,istep),istep)) < reig*0.75) then
                ! otherwise probability is high that the two eigen values are not from the
                ! same band and that the root is an accident
                anyroot = .true.
                exit outer
              end if!abs(eigw(connection(lm1,istep),istep)) < reig/2.0
            end if
          case default; stop 'option not known'
        end select!roottype

      end do inner!lm1
    end do outer!istep

  end subroutine find_roots_any_eigw_memopt





  subroutine find_roots_lm_eigw(almso,nsteps,connection,eigw,roottype,rooteps,lm1,root_interval)

    implicit none

    integer,          intent(in) :: almso, nsteps, connection(almso,nsteps+1)
    double complex,   intent(in) :: eigw(almso,nsteps+1)
    integer,          intent(in) :: roottype, lm1
    double precision, intent(in) :: rooteps

    integer, intent(out) :: root_interval

    integer           :: istep, icount
    double precision  :: dtmp1, dtmp2, xscal
    double complex    :: ctmp1, ctmp2

    !search for an root on the edge
    root_interval = 0
    icount = 0
    do istep=1,nsteps

        ctmp1 = eigw( connection(lm1,istep),   istep   )
        ctmp2 = eigw( connection(lm1,istep+1), istep+1 )

        select case (roottype)
          case(ROOT_ANY)
            dtmp1 =  dble(ctmp1) *  dble(ctmp2)
            dtmp2 = aimag(ctmp1) * aimag(ctmp2)
            if(dtmp1<0d0 .or.  dtmp2<0d0 ) then
              root_interval = istep
              icount = icount+1
            end if
          case(ROOT_REAL)
            dtmp1 =  dble(ctmp1) *  dble(ctmp2)
            xscal = -dble(ctmp1) / (dble(ctmp2) - dble(ctmp1))
            dtmp2 = (aimag(ctmp2)-aimag(ctmp1))*xscal + aimag(ctmp1)
            if(dtmp1<0d0 .and.  abs(dtmp2)<rooteps )then
              root_interval = istep
              icount = icount+1
            end if
          case(ROOT_IMAG)
            dtmp1 =  aimag(ctmp1) *  aimag(ctmp2)
            xscal = -aimag(ctmp1) / (aimag(ctmp2) - aimag(ctmp1))
            dtmp2 = (dble(ctmp2)-dble(ctmp1))*xscal + dble(ctmp1)
            if(dtmp1<0d0 .and.  abs(dtmp2)<rooteps )then
              root_interval = istep
              icount = icount+1
            end if
          case default; stop 'option not known'
        end select!roottype

    end do!istep

    if(icount>1) root_interval = 0

  end subroutine find_roots_lm_eigw





  subroutine find_roots_lm_eigw_memopt(neig,reig,nsteps,connection,eigw,roottype,rooteps,lm1,root_interval)

    implicit none

    integer,          intent(in) :: neig, nsteps, connection(neig,nsteps+1)
    double precision, intent(in) :: reig
    double complex,   intent(in) :: eigw(neig,nsteps+1)
    integer,          intent(in) :: roottype, lm1
    double precision, intent(in) :: rooteps

    integer, intent(out) :: root_interval

    integer           :: istep, icount
    double precision  :: dtmp1, dtmp2, xscal
    double complex    :: ctmp1, ctmp2

    !search for an root on the edge
    root_interval = 0
    icount = 0
    do istep=1,nsteps

        ctmp1 = eigw( connection(lm1,istep),   istep   )
        ctmp2 = eigw( connection(lm1,istep+1), istep+1 )

        select case (roottype)
          case(ROOT_ANY)
            dtmp1 =  dble(ctmp1) *  dble(ctmp2)
            dtmp2 = aimag(ctmp1) * aimag(ctmp2)
            if(dtmp1<0d0 .or.  dtmp2<0d0 ) then
              root_interval = istep
              icount = icount+1
            end if
          case(ROOT_REAL)
            dtmp1 =  dble(ctmp1) *  dble(ctmp2)
            xscal = -dble(ctmp1) / (dble(ctmp2) - dble(ctmp1))
            dtmp2 = (aimag(ctmp2)-aimag(ctmp1))*xscal + aimag(ctmp1)
            if(dtmp1<0d0 .and.  abs(dtmp2)<rooteps )then
              root_interval = istep
              icount = icount+1
            end if
          case(ROOT_IMAG)
            dtmp1 =  aimag(ctmp1) *  aimag(ctmp2)
            xscal = -aimag(ctmp1) / (aimag(ctmp2) - aimag(ctmp1))
            dtmp2 = (dble(ctmp2)-dble(ctmp1))*xscal + dble(ctmp1)
            if(dtmp1<0d0 .and.  abs(dtmp2)<rooteps )then
              root_interval = istep
              icount = icount+1
            end if
          case default; stop 'option not known'
        end select!roottype

        if(abs(eigw(connection(lm1,istep),istep)) >= reig*0.75) then
          ! probability is high that the two eigen values are not from the
          ! same band and that the root is an accident
          root_interval = 0
          icount = icount-1
        end if!eigw(connection(lm1,istep),istep) >= inc%reig/2.0

    end do!istep

    if(icount>1) root_interval = 0

  end subroutine find_roots_lm_eigw_memopt





  subroutine compare_two_eigv_in_substeps( inc, lattice, cluster, tgmatrx, nsteps, &
                                         & kends, lm_in, LV1all, RV2ref, eigw2ref, &
                                         & match                                   )

    use type_inc
    use type_data,     only: lattice_type, cluster_type, tgmatrx_type
    use mod_kkrmat,    only: compute_kkr_eigenvectors
    use mod_eigvects,  only: compare_eigv
    use mod_mathtools, only: bubblesort
    implicit none

    type(inc_type),     intent(in)  :: inc
    type(lattice_type), intent(in)  :: lattice
    type(cluster_type), intent(in)  :: cluster
    type(tgmatrx_type), intent(in)  :: tgmatrx
    integer,            intent(in)  :: nsteps, lm_in
    double precision,   intent(in)  :: kends(3,2)
    double complex,     intent(in)  :: LV1all(inc%almso,inc%almso),&
                                     & RV2ref(inc%almso),&
                                     & eigw2ref
    logical,            intent(out) :: match

    ! kkr-matrix
    double precision :: ksub(3)
    double complex   :: LVleft(inc%almso),&
                      & LVeig(inc%almso,inc%almso),&
                      & RVeig(inc%almso,inc%almso),&
                      & eigw(inc%almso)

    !sorting
    integer          :: lm2, sorted(inc%almso)
    double complex   :: cproj
    double precision :: projs(inc%almso), diffs(inc%almso)

    integer          :: ierr, istep, lm0

!   write(999,'("kends(:,1)=",3ES18.9)') kends(:,1)
!   write(999,'("kends(:,2)=",3ES18.9)') kends(:,2)

    lm0 = lm_in
    LVleft = LV1all(:,lm0)
    LVeig = LV1all

    do istep=1,nsteps+1
      ksub = kends(:,1) + dble(istep)/(nsteps+1)*( kends(:,2) - kends(:,1) )

      call compute_kkr_eigenvectors( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
                                   & tgmatrx%tinvll(:,:,:,1), ksub, eigw, LVeig, RVeig)
!     call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1), &
!                                   & tgmatrx%tmat(:,:,1), ksub, eigw, LVeig, RVeig )

      ! find the corresponding eigenvctor to LVleft
      call compare_eigv(inc, LVleft, RVeig, lm0)

      LVleft = LVeig(:,lm0)
!     write(999,'(2ES18.9)') eigw(lm0)

    end do!istep


    !====================================!
    !=== find the FINAL corresponding ===!
    !===      eigenvctor to RV2       ===!
    !====================================!

!   !calculate projections on other eigenvectors
!   projs  = 0d0
!   do lm2=1,inc%almso
!       cproj = dot_product(LVeig(:,lm2),RV2ref(:))
!       projs(lm2)  = dble(cproj)**2 + dimag(cproj)**2
!   end do!lm2

!   !find if corresponding eigenvector is matching
!   call bubblesort(inc%almso, projs, sorted)
!   match = .false.
!   if(any(sorted(inc%almso+1-inc%ndegen:inc%almso)==lm0)) match=.true.

    !find if the corresponding eigenvalue is matching
    diffs = abs( eigw-eigw2ref )
    call bubblesort(inc%almso, diffs, sorted)

    match = .false.
    if(any(sorted(1:inc%ndegen)==lm0)) match=.true.

  end subroutine compare_two_eigv_in_substeps







  subroutine compare_two_eigv_in_substeps_memopt( inc, lattice, cluster, tgmatrx, nsteps, &
                                                & kends, lm_in, LV1all, RV2ref, eigw2ref, &
                                                & match                                   )

    use type_inc
    use type_data,     only: lattice_type, cluster_type, tgmatrx_type
    use mod_kkrmat,    only: compute_kkr_eigenvectors, compute_kkr_eigenvectors_memopt
    use mod_eigvects,  only: compare_eigv, compare_eigv_memopt 
    use mod_mathtools, only: bubblesort
    implicit none

    type(inc_type),     intent(in)  :: inc
    type(lattice_type), intent(in)  :: lattice
    type(cluster_type), intent(in)  :: cluster
    type(tgmatrx_type), intent(in)  :: tgmatrx
    integer,            intent(in)  :: nsteps, lm_in
    double precision,   intent(in)  :: kends(3,2)
    double complex,     intent(in)  :: LV1all(inc%almso,inc%neig),&
                                     & RV2ref(inc%almso),         &
                                     & eigw2ref
    logical,            intent(out) :: match

    ! kkr-matrix
    double precision :: ksub(3)
    double complex   :: LVleft(inc%almso),&
                      & LVeig(inc%almso,inc%neig),&
                      & RVeig(inc%almso,inc%neig),&
                      & eigw(inc%neig)

    integer          :: nb_ev

    !sorting
    integer          :: lm2, sorted(inc%neig)
    double complex   :: cproj
    double precision :: projs(inc%neig), diffs(inc%neig)

    integer          :: ierr, istep, lm0

!   write(999,'("kends(:,1)=",3ES18.9)') kends(:,1)
!   write(999,'("kends(:,2)=",3ES18.9)') kends(:,2)

    lm0 = lm_in
    LVleft = LV1all(:,lm0)
    LVeig = LV1all

    do istep=1,nsteps+1
      ksub = kends(:,1) + dble(istep)/(nsteps+1)*( kends(:,2) - kends(:,1) )

      call compute_kkr_eigenvectors_memopt( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
                                   & tgmatrx%tinvll(:,:,:,1), ksub, eigw, LVeig, RVeig, nb_ev)
!     call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1), &
!                                   & tgmatrx%tmat(:,:,1), ksub, eigw, LVeig, RVeig )

      ! find the corresponding eigenvctor to LVleft
      call compare_eigv_memopt(inc, LVleft, RVeig, nb_ev, lm0)

      LVleft = LVeig(:,lm0)
!     write(999,'(2ES18.9)') eigw(lm0)

    end do!istep


    !====================================!
    !=== find the FINAL corresponding ===!
    !===      eigenvctor to RV2       ===!
    !====================================!

!   !calculate projections on other eigenvectors
!   projs  = 0d0
!   do lm2=1,inc%almso
!       cproj = dot_product(LVeig(:,lm2),RV2ref(:))
!       projs(lm2)  = dble(cproj)**2 + dimag(cproj)**2
!   end do!lm2

!   !find if corresponding eigenvector is matching
!   call bubblesort(inc%almso, projs, sorted)
!   match = .false.
!   if(any(sorted(inc%almso+1-inc%ndegen:inc%almso)==lm0)) match=.true.

    !find if the corresponding eigenvalue is matching
    diffs = abs( eigw-eigw2ref )
    call bubblesort(inc%neig, diffs, sorted)

    match = .false.
    if(any(sorted(1:inc%ndegen)==lm0)) match=.true.

  end subroutine compare_two_eigv_in_substeps_memopt







  subroutine unroll_ixyz(ixyz, nCub3, ii3)
  !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  !+ helper function to divide the UID to an integer triple +
  !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    implicit none

    integer, intent(in)  :: ixyz, nCub3(3)
    integer, intent(out) :: ii3(3)

    integer :: irest

    ii3(3) = int((ixyz-1)/(nCub3(1)*nCub3(2)))
    irest= ixyz-1-ii3(3)*(nCub3(1)*nCub3(2))
    ii3(2) = int(irest/nCub3(1))
    irest= ixyz-1-ii3(3)*(nCub3(1)*nCub3(2)) - ii3(2)*nCub3(1)
    ii3(1) = irest

  end subroutine unroll_ixyz


  function get_cubesinfo_filename(nCub3,lintermediate) result(filename)
    use mod_ioformat,   only: filename_cubesinfo, ext_formatted, fmt_fn_ext
    implicit none
    integer, intent(in) :: nCub3(3)
    logical, intent(in) :: lintermediate
    character(len=256)  :: filename
    character(len=256)  :: fileprefix

    !create filename
    if(lintermediate) then
      write(fileprefix,'(A,3("_",I0))') filename_cubesinfo, nCub3
    else!ltmp
      fileprefix= filename_cubesinfo
    endif!ltmp
     
    write(filename,fmt_fn_ext) trim(fileprefix), ext_formatted

  end function get_cubesinfo_filename


  subroutine save_cubesfile(nCub3, nmarked, imarked, lintermediate)

    implicit none
    integer, intent(in) :: nCub3(3), nmarked, imarked(nmarked)
    logical, intent(in), optional :: lintermediate
    character(len=256) :: filename
    logical :: ltmp
    integer, parameter :: iounit=1566

    ltmp=.false.
    if(present(lintermediate)) ltmp=lintermediate

    filename = get_cubesinfo_filename(nCub3,ltmp)

    open(unit=iounit, file=filename, form='formatted', action='write')
     write(iounit,'(3I8)')  nCub3
     write(iounit,'(I8)')   nmarked
     write(iounit,'(10I8)') imarked
    close(iounit)

  end subroutine save_cubesfile





  subroutine read_cubesfile(nCub3, nmarked, imarked, nCub3_intermediate)

    use mod_mympi, only: myrank, nranks, master
    use mod_ioformat,   only: filename_cubesinfo, ext_formatted, fmt_fn_ext
#ifdef CPP_MPI
    use mpi
#endif
    implicit none

    integer, intent(in), optional :: nCub3_intermediate(3)
    integer, intent(out) :: nCub3(3), nmarked
    integer, allocatable, intent(out) :: imarked(:)
    integer :: ierr, ntmp3(3)=0
    logical :: ltmp
    character(len=256)  :: filename
    integer, parameter  :: iounit=15668
    integer :: i,j

    if(myrank==master)then

      if(present(nCub3_intermediate))then
        filename = get_cubesinfo_filename(nCub3_intermediate,.true.)
      else!present(nCub3_intermediate)
        filename = get_cubesinfo_filename(ntmp3,.false.)
      end if!present(nCub3_intermediate)

      open(unit=iounit, file=filename, form='formatted', action='read')
      read(iounit,'(3I8)')  nCub3
      read(iounit,'(I8)')   nmarked
      allocate(imarked(nmarked), STAT=ierr)
      if(ierr/=0) stop 'Problem allocating imarked in readin on master'
      read(iounit,'(10I8)') imarked
      close(iounit)

      ! check if twice the same cube in cubesfile
      do i=1,nmarked
        do j=1,nmarked
          if(imarked(i)==imarked(j).and.i/=j) stop 'Twice the same cube in cubesfile'
        end do
      end do
    end if!myrank==master

#ifdef CPP_MPI
    call MPI_Bcast(nCub3, 3, MPI_INTEGER, master, MPI_COMM_WORLD, ierr)
    if(ierr/=MPI_SUCCESS) stop 'Problem in Bcast(nCub3)'
    call MPI_Bcast(nmarked, 1, MPI_INTEGER, master, MPI_COMM_WORLD, ierr)
    if(ierr/=MPI_SUCCESS) stop 'Problem in Bcast(nmarked)'
    if(myrank/=master)then
      allocate(imarked(nmarked), STAT=ierr)
      if(ierr/=0) stop 'Problem allocating imarked in readin on slaves'
    end if!myrank/=master
    call MPI_Bcast(imarked, nmarked, MPI_INTEGER, master, MPI_COMM_WORLD, ierr)
    if(ierr/=MPI_SUCCESS) stop 'Problem in Bcast(imarked)'
#endif

  end subroutine read_cubesfile







  subroutine mark_cubes_FScross(inc, lattice, cluster, tgmatrx, nCub3, nsteps, nverts, nedges, diag_ids, bounds, roottype, rooteps, nmarked, imarked)

    use type_inc,       only: inc_type
    use type_data,      only: lattice_type, cluster_type, tgmatrx_type
    use mod_parutils,   only: distribute_linear_on_tasks
    use mod_mympi,      only: myrank, nranks, master
#ifdef CPP_MPI
    use mpi
#endif
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(in) :: tgmatrx
    integer,            intent(in) :: nCub3(3), nsteps, nverts, nedges, diag_ids(2,nedges)
    double precision,   intent(in) :: bounds(3,2)
    integer,            intent(in) :: roottype
    double precision,   intent(in) :: rooteps
    integer,              intent(inout) :: nmarked
    integer, allocatable, intent(inout) :: imarked(:)

    integer :: ncubmarked_tmp, ioff, nkpt, ntot_pT(0:nranks-1), ioff_pT(0:nranks-1)
    integer :: ncubmarked_pT(0:nranks-1), iioff(0:nranks-1)
    double precision :: kverts(3,nverts)
    integer, allocatable :: icubmarked_tmp(:)

    integer          :: connection(inc%almso,nsteps+1)
    double precision :: ksub(3,nsteps+1), kends(3,2)
    double complex   :: LVeig(inc%almso,inc%almso,nsteps+1),&
                      & RVeig(inc%almso,inc%almso,nsteps+1),&
                      & eigw(inc%almso,nsteps+1)

    integer :: iedge, irank, icub, ierr
    logical :: edgeroot(nedges)

    !Parallelize
    call distribute_linear_on_tasks(nranks,myrank,master, nmarked, ntot_pT, ioff_pT, .false.)
    nkpt = ntot_pT(myrank)
    ioff = ioff_pT(myrank)

    !Create temp arrays
    allocate(icubmarked_tmp(nkpt), STAT=ierr)
    if(ierr/=0) stop 'Problem allocating icubmarked_tmp in mark_cubes_FScross'
    ncubmarked_tmp = 0
    icubmarked_tmp = -1

    !Test whether cubes cross FS
    do icub=1,nkpt
      if(mod(icub,10)==0 .and. myrank==master) write(*,"(2X,F8.3,A)") dble(icub)/nkpt*100, ' percent done'
      select case (nverts)
        case (8); call generate_cubevertices(nCub3,imarked(icub+ioff), bounds, kverts)
        case (4); call generate_squarevertices(nCub3,imarked(icub+ioff), bounds, kverts)
        case default; stop 'Case nverts not allowed in mark_cubes_FScross'
      end select!
      edgeroot = .false.
      do iedge=1,nedges
        kends(:,1) = kverts(:,diag_ids(1,iedge))
        kends(:,2) = kverts(:,diag_ids(2,iedge))
        call connect_eigw_in_substeps( inc, lattice, cluster, tgmatrx, nsteps, kends, &
                                     & connection, ksub, eigw, LVeig, RVeig           )
        call find_roots_any_eigw( inc%almso, nsteps, connection, eigw, &
                                & roottype, rooteps, edgeroot(iedge)   )
      end do!iedge
      if(any(edgeroot))then
        ncubmarked_tmp = ncubmarked_tmp + 1
        icubmarked_tmp(ncubmarked_tmp) = imarked(icub+ioff)
      end if!l_cut
    end do!icub

    deallocate(imarked)

#ifdef CPP_MPI
    !Combine results
    call MPI_Allgather(ncubmarked_tmp, 1, MPI_INTEGER, ncubmarked_pT, 1, MPI_INTEGER, MPI_COMM_WORLD, ierr )
    if(ierr/=MPI_SUCCESS) stop 'Problem in Allgather(ncubmarked_tmp) in mark_cubes_FScross'

    nmarked = sum(ncubmarked_pT)
    allocate(imarked(nmarked), STAT=ierr)
    if(ierr/=0) stop 'Problem allocating imarked in mark_cubes_FScross'

    iioff = 0
    do irank=1,nranks-1
      iioff(irank) = sum(ncubmarked_pT(0:irank-1))
    end do

    call MPI_Allgatherv( icubmarked_tmp, ncubmarked_tmp, MPI_INTEGER, &
                       & imarked, ncubmarked_pT, iioff, MPI_INTEGER,  &
                       & MPI_COMM_WORLD, ierr )
    if(ierr/=MPI_SUCCESS) stop 'Problem in Allgatherv(icubmarked_tmp) in mark_cubes_FScross'

#else
    nmarked=ncubmarked_tmp
    allocate(imarked(nmarked), STAT=ierr)
    if(ierr/=0) stop 'Problem allocating imarked in mark_cubes_FScross'
    imarked = icubmarked_tmp(1:ncubmarked_tmp)
#endif

  end subroutine mark_cubes_FScross





  subroutine mark_cubes_FScross_memopt(inc, lattice, cluster, tgmatrx, nCub3, nsteps, nverts, nedges, diag_ids, bounds, roottype, rooteps, nmarked, imarked)

    use type_inc,       only: inc_type
    use type_data,      only: lattice_type, cluster_type, tgmatrx_type
    use mod_parutils,   only: distribute_linear_on_tasks
    use mod_mympi,      only: myrank, nranks, master
#ifdef CPP_MPI
    use mpi
#endif
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(in) :: tgmatrx
    integer,            intent(in) :: nCub3(3), nsteps, nverts, nedges, diag_ids(2,nedges)
    double precision,   intent(in) :: bounds(3,2)
    integer,            intent(in) :: roottype
    double precision,   intent(in) :: rooteps
    integer,              intent(inout) :: nmarked
    integer, allocatable, intent(inout) :: imarked(:)

    integer :: ncubmarked_tmp, ioff, nkpt, ntot_pT(0:nranks-1), ioff_pT(0:nranks-1)
    integer :: ncubmarked_pT(0:nranks-1), iioff(0:nranks-1)
    double precision :: kverts(3,nverts)
    integer, allocatable :: icubmarked_tmp(:)

    integer          :: connection(inc%neig,nsteps+1), nb_bands
    double precision :: ksub(3,nsteps+1), kends(3,2)
    double complex   :: LVeig(inc%almso,inc%neig,nsteps+1),&
                      & RVeig(inc%almso,inc%neig,nsteps+1),&
                      & eigw(inc%neig,nsteps+1)

    integer :: iedge, irank, icub, ierr
    logical :: edgeroot(nedges)

    !Parallelize
    call distribute_linear_on_tasks(nranks,myrank,master, nmarked, ntot_pT, ioff_pT, .false.)
    nkpt = ntot_pT(myrank)
    ioff = ioff_pT(myrank)

    !Create temp arrays
    allocate(icubmarked_tmp(nkpt), STAT=ierr)
    if(ierr/=0) stop 'Problem allocating icubmarked_tmp in mark_cubes_FScross'
    ncubmarked_tmp = 0
    icubmarked_tmp = -1

    !Test whether cubes cross FS
    do icub=1,nkpt
      if(mod(icub,10)==0 .and. myrank==master) write(*,"(2X,F8.3,A)") dble(icub)/nkpt*100, ' percent done'
      select case (nverts)
        case (8); call generate_cubevertices(nCub3,imarked(icub+ioff), bounds, kverts)
        case (4); call generate_squarevertices(nCub3,imarked(icub+ioff), bounds, kverts)
        case default; stop 'Case nverts not allowed in mark_cubes_FScross'
      end select!
      edgeroot = .false.
      do iedge=1,nedges
        kends(:,1) = kverts(:,diag_ids(1,iedge))
        kends(:,2) = kverts(:,diag_ids(2,iedge))
        nb_bands = 0
        call connect_eigw_in_substeps_memopt( inc, lattice, cluster, tgmatrx, nsteps, kends, &
                                     & connection, ksub, eigw, LVeig, RVeig, nb_bands        )
        call find_roots_any_eigw_memopt( inc%neig, inc%reig, nb_bands, nsteps, connection, eigw, &
                                & roottype, rooteps, edgeroot(iedge)   )
      end do!iedge
      if(any(edgeroot))then
        ncubmarked_tmp = ncubmarked_tmp + 1
        icubmarked_tmp(ncubmarked_tmp) = imarked(icub+ioff)
      end if!l_cut
    end do!icub

    deallocate(imarked)

#ifdef CPP_MPI
    !Combine results
    call MPI_Allgather(ncubmarked_tmp, 1, MPI_INTEGER, ncubmarked_pT, 1, MPI_INTEGER, MPI_COMM_WORLD, ierr )
    if(ierr/=MPI_SUCCESS) stop 'Problem in Allgather(ncubmarked_tmp) in mark_cubes_FScross'

    nmarked = sum(ncubmarked_pT)
    allocate(imarked(nmarked), STAT=ierr)
    if(ierr/=0) stop 'Problem allocating imarked in mark_cubes_FScross'

    iioff = 0
    do irank=1,nranks-1
      iioff(irank) = sum(ncubmarked_pT(0:irank-1))
    end do

    call MPI_Allgatherv( icubmarked_tmp, ncubmarked_tmp, MPI_INTEGER, &
                       & imarked, ncubmarked_pT, iioff, MPI_INTEGER,  &
                       & MPI_COMM_WORLD, ierr )
    if(ierr/=MPI_SUCCESS) stop 'Problem in Allgatherv(icubmarked_tmp) in mark_cubes_FScross'

#else
    nmarked=ncubmarked_tmp
    allocate(imarked(nmarked), STAT=ierr)
    if(ierr/=0) stop 'Problem allocating imarked in mark_cubes_FScross'
    imarked = icubmarked_tmp(1:ncubmarked_tmp)
#endif

  end subroutine mark_cubes_FScross_memopt





  subroutine generate_cubevertices(nCub3,cubeid,bounds,kverts)
    !generates the vertices of a cube given by the cubeid
    implicit none

    integer, intent(in) :: nCub3(3), cubeid
    double precision, intent(in)  :: bounds(3,2)
    double precision, intent(out) :: kverts(3,8)

    integer :: ii3(3), ivert

    call unroll_ixyz(cubeid, nCub3, ii3)

    !generate vertices, limits are from 0 to 1
    kverts(:,1) = dble( (/ ii3(1)  , ii3(2)  , ii3(3)   /) )/nCub3
    kverts(:,2) = dble( (/ ii3(1)+1, ii3(2)  , ii3(3)   /) )/nCub3
    kverts(:,3) = dble( (/ ii3(1)  , ii3(2)+1, ii3(3)   /) )/nCub3
    kverts(:,4) = dble( (/ ii3(1)+1, ii3(2)+1, ii3(3)   /) )/nCub3
    kverts(:,5) = dble( (/ ii3(1)  , ii3(2)  , ii3(3)+1 /) )/nCub3
    kverts(:,6) = dble( (/ ii3(1)+1, ii3(2)  , ii3(3)+1 /) )/nCub3
    kverts(:,7) = dble( (/ ii3(1)  , ii3(2)+1, ii3(3)+1 /) )/nCub3
    kverts(:,8) = dble( (/ ii3(1)+1, ii3(2)+1, ii3(3)+1 /) )/nCub3

    !shift the vertices to the correct bounds
    do ivert=1,8
      kverts(:,ivert) = kverts(:,ivert)*(bounds(:,2)-bounds(:,1))+bounds(:,1)
    end do!ivert

  end subroutine generate_cubevertices




  subroutine generate_squarevertices(nCub3,cubeid,bounds,kverts)
    !generates the vertices of a square given by the id
    implicit none

    integer, intent(in) :: nCub3(3), cubeid
    double precision, intent(in)  :: bounds(3,2)
    double precision, intent(out) :: kverts(3,4)

    integer :: ii3(3), ivert

    call unroll_ixyz(cubeid, nCub3, ii3)

    !generate vertices, limits are from 0 to 1
    kverts(:,1) = dble( (/ ii3(1)  , ii3(2)  , 0 /) )/nCub3
    kverts(:,2) = dble( (/ ii3(1)+1, ii3(2)  , 0 /) )/nCub3
    kverts(:,3) = dble( (/ ii3(1)  , ii3(2)+1, 0 /) )/nCub3
    kverts(:,4) = dble( (/ ii3(1)+1, ii3(2)+1, 0 /) )/nCub3

    !shift the vertices to the correct bounds
    do ivert=1,4
      kverts(:,ivert) = kverts(:,ivert)*(bounds(:,2)-bounds(:,1))+bounds(:,1)
    end do!ivert

  end subroutine generate_squarevertices



  subroutine save_kpointsfile_vis(nkpts, nkpts_irr, kpoints, nsym, isym, kpt2irr, irr2kpt, vis2int, filenamein)

    use mod_ioformat,   only: fmt_fn_sub_ext, ext_formatted, filemode_vis, filename_fsdata
    implicit none

    integer, intent(in) :: nkpts, nkpts_irr, nsym, isym(nsym), kpt2irr(nkpts), irr2kpt(nkpts_irr)
    double precision, intent(in) :: kpoints(3,nkpts)
    integer, intent(in), optional :: vis2int(nkpts)
    character(len=*), intent(in), optional :: filenamein

    double precision :: kpoints_irr(3,nkpts_irr)

    integer :: ii
    character(len=256) :: filename

    kpoints_irr = kpoints(:,irr2kpt)

    if(present(filenamein))then
      filename=filenamein
    else
      write(filename,fmt_fn_sub_ext) filename_fsdata, filemode_vis, ext_formatted
    end if
    open(unit=326523, file=trim(filename), form='formatted', action='write')
    write(326523,'(3I8)') nkpts, nkpts_irr, nsym
    write(326523,*) '#==== isym ====#'
    write(326523,'(12I8)') isym
    write(326523,*) '#==== irr2kpt ====#'
    write(326523,'(10I8)') irr2kpt
    write(326523,*) '#==== kpt2irr ====#'
    write(326523,'(10I8)') kpt2irr
    write(326523,*) '#==== kpoints ====#'
    write(326523,'(3ES25.16)') kpoints_irr
    if(present(vis2int))then
      write(326523,*) '#==== vis2int ====#'
      write(326523,'(10I8)') vis2int
    end if
    close(326523)

  end subroutine save_kpointsfile_vis





  subroutine save_kpointsfile_int(nkpts, kpoints, areas, nsym, isym, filenamein)

    use mod_ioformat,   only: fmt_fn_sub_ext, ext_formatted, filemode_int, filename_fsdata
    implicit none

    integer, intent(in) :: nkpts, nsym, isym(nsym)
    double precision, intent(in) :: kpoints(3,nkpts), areas(nkpts)
    character(len=*), intent(in), optional :: filenamein

    integer :: ii
    character(len=256) :: filename

    if(present(filenamein))then
      filename=filenamein
    else
      write(filename,fmt_fn_sub_ext) filename_fsdata, filemode_int, ext_formatted
    end if
    open(unit=326523, file=trim(filename), form='formatted', action='write')
    write(326523,'(2I8)') nkpts, nsym
    write(326523,'(12I8)') isym
    do ii=1,nkpts
      write(326523,'(4ES25.16)') kpoints(:,ii), areas(ii)
    end do!ii
    close(326523)

  end subroutine save_kpointsfile_int





  subroutine find_kpoints_irredset( bounds, nkpts, kpoints, nkpts_irr, kpt2irr, irr2kpt )
    use mod_parutils, only: parallel_quicksort
    use mod_mympi, only: myrank, nranks, master
    implicit none

    integer, intent(in)  :: nkpts
    double precision, intent(in) :: bounds(3,2), kpoints(3,nkpts)
    integer, intent(out) :: nkpts_irr
    integer, allocatable, intent(out) :: kpt2irr(:), irr2kpt(:)

    integer :: isort(nkpts), itmplist(nkpts)
    double precision, allocatable :: values(:)

    integer :: ipoint, ierr, ikp
    double precision :: delk(3), kpoint0(3)
    double precision, parameter :: eps = 1.0d-12

    !sort kpoints
    allocate(values(nkpts), kpt2irr(nkpts), STAT=ierr)
    if(ierr/=0) stop 'Problem allocating values'
    values = 1d0*(kpoints(1,:)-bounds(1,1)) + 3d0*(kpoints(2,:)-bounds(2,1)) + 5d0*(kpoints(3,:)-bounds(3,1))
    call parallel_quicksort(nranks, myrank, master, nkpts, values, isort)
    deallocate(values)

    !filter the irreducibe number
    nkpts_irr = 1
    ipoint  = isort(1)
    itmplist(1) = ipoint
    kpt2irr(ipoint) = 1
    kpoint0 = kpoints(:,ipoint)
    do ikp=2,nkpts
      ipoint = isort(ikp)
      delk   = kpoints(:,ipoint) - kpoint0
      if(any(abs(delk)>=eps)) then
        nkpts_irr = nkpts_irr+1
        kpoint0  = kpoints(:,ipoint)
        itmplist(nkpts_irr) = ipoint
      end if
      kpt2irr(ipoint) = nkpts_irr
    end do

    allocate( irr2kpt(nkpts_irr), STAT=ierr )
    if(ierr/=0) stop 'Problem allocating irr2kpt etc.'

    irr2kpt = itmplist(1:nkpts_irr)

  end subroutine find_kpoints_irredset



end module mod_fermisurf_basic