!> @file
!!  Routines to create descriptor arrays for density and potential
!! @author
!!    Copyright (C) 2007-2015 BigDFT group (LG)
!!    This file is distributed under the terms of the
!!    GNU General Public License, see ~/COPYING file
!!    or http://www.gnu.org/copyleft/gpl.txt .
!!    For the list of contributors, see ~/AUTHORS


!> Denspot initialization
subroutine initialize_DFT_local_fields(denspot, ixc, nspden, alpha_hf)
  use module_dpbox, only: dpbox_null
  use module_types
  use module_xc
  use public_enums
  use PStypes
  use Poisson_Solver
  use module_bigdft_output
  implicit none
  type(DFT_local_fields), intent(inout) :: denspot
  integer, intent(in) :: ixc, nspden
  real(kind=8), intent(in) :: alpha_hf

  denspot%rhov_is = EMPTY
  nullify(denspot%rho_C)
  nullify(denspot%rhohat)
  nullify(denspot%V_ext)
  nullify(denspot%rho_ion)
  nullify(denspot%Vloc_KS)
  nullify(denspot%rho_psi)
  nullify(denspot%V_XC)
  nullify(denspot%f_XC)
  nullify(denspot%rho_work)
  nullify(denspot%pot_work)
  nullify(denspot%rhov)

  denspot%psoffset=0.d0

  if (get_verbose_level() >1) then
     denspot%PSquiet='NO '
  else
     denspot%PSquiet='YES'
  end if

  denspot%pkernel=pkernel_null()
  denspot%pkernelseq=pkernel_null()

  call initialize_rho_descriptors(denspot%rhod)
  denspot%dpbox=dpbox_null()

  nullify(denspot%mix)

  if (ixc < 0) then
     call xc_init(denspot%xc, ixc, XC_MIXED, nspden, alpha_hf)
  else
     call xc_init(denspot%xc, ixc, XC_ABINIT, nspden, alpha_hf)
  end if
end subroutine initialize_DFT_local_fields

subroutine initialize_rho_descriptors(rhod)
  use module_types
  use f_precisions, only: UNINITIALIZED
  implicit none
  type(rho_descriptors), intent(out) :: rhod

  rhod%geocode='X' !fake value
  rhod%icomm=1 !< lda case
  rhod%nrhotot=UNINITIALIZED(rhod%nrhotot)
  rhod%n_csegs=UNINITIALIZED(rhod%n_csegs)
  rhod%n_fsegs=UNINITIALIZED(rhod%n_fsegs)
  rhod%dp_size=UNINITIALIZED(rhod%dp_size)
  rhod%sp_size=UNINITIALIZED(rhod%sp_size)

  nullify(rhod%spkey,rhod%dpkey,rhod%cseg_b,rhod%fseg_b)

end subroutine initialize_rho_descriptors


subroutine denspot_set_history(denspot, scf_enum, &
     npulayit)
  use module_types
  use module_mixing
  use public_enums
  use f_enums
  implicit none
  type(DFT_local_fields), intent(inout) :: denspot

  type(f_enumerator), intent(in) :: scf_enum
  integer,intent(in),optional :: npulayit

  integer :: potden, npoints, ierr,irealfour,imeth
  character(len=500) :: errmess

  if (scf_enum .hasattr. 'MIXING') then
     potden = toi(scf_enum .getattr. 'MIXING_ON')
     select case(potden)
     case(AB7_MIXING_POTENTIAL)
        npoints = denspot%dpbox%mesh%ndims(1)*denspot%dpbox%mesh%ndims(2)*&
             denspot%dpbox%n3p
     case(AB7_MIXING_DENSITY)
        npoints = denspot%dpbox%mesh%ndims(1)*denspot%dpbox%mesh%ndims(2)*&
             denspot%dpbox%n3d
     end select
     irealfour=toi(scf_enum .getattr. 'MIXING_SPACE')
     imeth=toi(scf_enum)
     allocate(denspot%mix)
     if (present(npulayit)) then
        call ab7_mixing_new(denspot%mix,imeth, potden, &
              irealfour, npoints, denspot%dpbox%nrhodim, 0, &
             ierr, errmess, npulayit=npulayit, useprec = .false.)
     else
        call ab7_mixing_new(denspot%mix, imeth, potden, &
              irealfour, npoints, denspot%dpbox%nrhodim, 0, &
             ierr, errmess, useprec = .false.)
     end if
     call ab7_mixing_eval_allocate(denspot%mix)
  else
     nullify(denspot%mix)
  end if

!!$  if (iscf < 10) then
!!$     ! Mixing over potential so use dimension of pot (n3p)
!!$     potden = AB7_MIXING_POTENTIAL
!!$     npoints = denspot%dpbox%ndims(1)*denspot%dpbox%ndims(2)*denspot%dpbox%n3p
!!$!!!     npoints = n1i*n2i*denspot%dpbox%n3p
!!$  else
!!$     ! Mixing over density so use dimension of density (n3d)
!!$     potden = AB7_MIXING_DENSITY
!!$     npoints = denspot%dpbox%ndims(1)*denspot%dpbox%ndims(2)*denspot%dpbox%n3d
!!$!!!     npoints = n1i*n2i*denspot%dpbox%n3d
!!$  end if
!!$  if (iscf > SCF_KIND_DIRECT_MINIMIZATION) then
!!$     allocate(denspot%mix)
!!$     if (present(npulayit)) then
!!$         call ab7_mixing_new(denspot%mix, modulo(iscf, 10), potden, &
!!$              AB7_MIXING_REAL_SPACE, npoints, nspin, 0, &
!!$              ierr, errmess, npulayit=npulayit, useprec = .false.)
!!$     else
!!$         call ab7_mixing_new(denspot%mix, modulo(iscf, 10), potden, &
!!$              AB7_MIXING_REAL_SPACE, npoints, nspin, 0, &
!!$              ierr, errmess, useprec = .false.)
!!$     end if
!!$     call ab7_mixing_eval_allocate(denspot%mix)
!!$  else
!!$     nullify(denspot%mix)
!!$  end if
end subroutine denspot_set_history


subroutine denspot_free_history(denspot)
  use module_types
  use module_mixing
  implicit none
  type(DFT_local_fields), intent(inout) :: denspot

  if (associated(denspot%mix)) then
      call ab7_mixing_deallocate(denspot%mix)
      deallocate(denspot%mix)
      nullify(denspot%mix)
  end if
end subroutine denspot_free_history


!> Set the status of denspot (should be KS_POTENTIAL, HARTREE_POTENTIAL, CHARGE_DENSITY)
subroutine denspot_set_rhov_status(denspot, status, istep, iproc, nproc)
  use module_types
  implicit none
  type(DFT_local_fields), intent(inout) :: denspot
  integer, intent(in) :: status, istep, iproc, nproc

  denspot%rhov_is = status

  if (denspot%c_obj /= 0) then
     call denspot_emit_rhov(denspot, istep, iproc, nproc)
  end if
end subroutine denspot_set_rhov_status

!> Allocate density and potentials.
subroutine allocateRhoPot(nspin,atoms,rxyz,denspot)
  use module_precisions
  use module_types
  use module_interfaces, only: calculate_rhocore
  use module_bigdft_arrays
  use f_enums
  implicit none
  integer, intent(in) :: nspin
  type(atoms_data), intent(in) :: atoms
  real(gp), dimension(3,atoms%astruct%nat), intent(in) :: rxyz
  type(DFT_local_fields), intent(inout) :: denspot

  !allocate ionic potential
  if (denspot%dpbox%n3pi > 0) then
     denspot%V_ext = f_malloc_ptr((/ denspot%dpbox%mesh%ndims(1) , &
          & denspot%dpbox%mesh%ndims(2) , denspot%dpbox%n3pi , 1 /),id='denspot%V_ext')
  else
     denspot%V_ext = f_malloc_ptr((/ 1 , 1 , 1 , 1 /),id='denspot%V_ext')
  end if
  !Allocate XC potential
  if (denspot%dpbox%n3p >0) then
     denspot%V_XC = f_malloc_ptr((/ denspot%dpbox%mesh%ndims(1) , &
          & denspot%dpbox%mesh%ndims(2) , denspot%dpbox%n3p , nspin /),id='denspot%V_XC')
  else
     denspot%V_XC = f_malloc_ptr((/ 1 , 1 , 1 , nspin /),id='denspot%V_XC')
  end if

  !allocate ionic density in the case of a cavity calculation
  if (denspot%pkernel%method /= 'VAC') then
     if (denspot%dpbox%n3pi > 0) then
        denspot%rho_ion = f_malloc_ptr([ denspot%dpbox%mesh%ndims(1) , &
             & denspot%dpbox%mesh%ndims(2) , denspot%dpbox%n3pi , 1 ],id='denspot%rho_ion')
     else
        denspot%rho_ion = f_malloc_ptr([ 1 , 1 , 1 , 1 ],id='denspot%rho_ion')
     end if
  else
     denspot%rho_ion = f_malloc_ptr([ 1 , 1 , 1 , 1 ],id='denspot%rho_ion')
  end if

  if (denspot%dpbox%n3d >0) then
     denspot%rhov = f_malloc_ptr(denspot%dpbox%mesh%ndims(1) * &
          & denspot%dpbox%mesh%ndims(2)*denspot%dpbox%n3d*&
          denspot%dpbox%nrhodim,id='denspot%rhov')
  else
     denspot%rhov = f_malloc0_ptr(denspot%dpbox%nrhodim,id='denspot%rhov')
  end if
  !check if non-linear core correction should be applied, and allocate the
  !pointer if it is the case
  !print *,'i3xcsh',denspot%dpbox%i3s,denspot%dpbox%i3xcsh,denspot%dpbox%n3d
  call calculate_rhocore(atoms,rxyz,denspot%dpbox,denspot%rho_C)

END SUBROUTINE allocateRhoPot

subroutine setRhovFromFile(denspot, filename, iproc, nproc, kind)
  use module_precisions
  use IObox
  use yaml_output
  use module_types, only: DFT_local_fields
  use public_enums
  use at_domain
  use module_bigdft_mpi
  use module_bigdft_errors
  use module_bigdft_arrays
  implicit none
  type(DFT_local_fields), intent(inout) :: denspot
  character(len = *), intent(in) :: filename
  integer, intent(in) :: iproc, nproc, kind

  integer :: nspin, ispin, ierr, ndimpar
  integer, dimension(3) :: ndims
  real(gp), dimension(3) :: hgrids
  real(gp), dimension(:,:,:,:), allocatable :: tmp

  !only the first processor should read this
  if (iproc == 0) then
     select case(kind)
     case (ELECTRONIC_DENSITY)
        call yaml_map('Electronic density file', trim(filename))
        ndimpar = denspot%dpbox%ndimrho
     case (CHARGE_DENSITY)
        call yaml_map('Charge density file', trim(filename))
        ndimpar = denspot%dpbox%ndimrho
     case (KS_POTENTIAL)
        call yaml_map('Local potential file', trim(filename))
        ndimpar = denspot%dpbox%ndimpot
     case (HARTREE_POTENTIAL)
        call yaml_map('Hartree potential file', trim(filename))
        ndimpar = denspot%dpbox%ndimpot
     case default
        call f_err_throw('Unknown kind for rhov', err_name = 'BIGDFT_RUNTIME_ERROR')
     end select
     call read_field_dimensions(trim(filename), domain_geocode(denspot%dpbox%mesh%dom), ndims, nspin)
     if (f_err_raise(nspin /= denspot%dpbox%nrhodim, &
          'The value nspin reading from the file is not the same', &
          err_name = 'BIGDFT_RUNTIME_ERROR')) return
     if (f_err_raise(product(ndims) /= denspot%dpbox%ndimrho, &
          'The value ndims reading from the file is not the same', &
          err_name = 'BIGDFT_RUNTIME_ERROR')) return
     tmp = f_malloc([ndims(1),ndims(2),ndims(3),nspin], id = 'tmp')
     !> Read a density file using file format depending on the extension.
     call read_field(trim(filename), domain_geocode(denspot%dpbox%mesh%dom), &
          ndims, hgrids, nspin, product(ndims), denspot%dpbox%nrhodim, tmp)
  else
     tmp = f_malloc((/ 1, 1, 1, denspot%dpbox%nrhodim /), id = 'tmp')
  end if

  if (nproc > 1) then
     do ispin = 1, denspot%dpbox%nrhodim
        call MPI_SCATTERV(tmp(1,1,1,ispin), &
             denspot%dpbox%ngatherarr(0,1), denspot%dpbox%ngatherarr(0,2), &
             mpidtypw, denspot%rhov((ispin-1) * ndimpar + 1), ndimpar, mpidtypw, 0, &
             bigdft_mpi%mpi_comm, ierr)
     end do
  else
     call vcopy(denspot%dpbox%ndimrho * denspot%dpbox%nrhodim,&
          tmp(1,1,1,1), 1, denspot%rhov(1), 1)
  end if
  !now the meaning is KS potential
  call denspot_set_rhov_status(denspot, kind, 0, iproc, nproc)

  call f_free(tmp)
END SUBROUTINE setRhovFromFile

!!$!> Create the descriptors for the density and the potential
!!$subroutine createDensPotDescriptors(iproc,nproc,atoms,gdim,hxh,hyh,hzh,&
!!$     rxyz,crmult,frmult,radii_cf,nspin,datacode,ixc,rho_commun,&
!!$     n3d,n3p,n3pi,i3xcsh,i3s,nscatterarr,ngatherarr,rhodsc)


!!$  !calculate dimensions of the complete array to be allocated before the reduction procedure
!!$  if (rhodsc%icomm==1) then
!!$     rhodsc%nrhotot=0
!!$     do jproc=0,nproc-1
!!$        rhodsc%nrhotot=rhodsc%nrhotot+nscatterarr(jproc,1)
!!$     end do
!!$  else
!!$     rhodsc%nrhotot=ndims(3)
!!$  end if

!END SUBROUTINE createDensPotDescriptors


subroutine density_descriptors(iproc,nproc,xc,nspin,crmult,frmult,atoms,dpbox,&
     rho_commun,rxyz,rhodsc)
  use module_precisions
  use module_dpbox, only:  denspot_distribution
  use module_types
  use module_xc
  use at_domain, only: domain_geocode
  implicit none
  integer, intent(in) :: iproc,nproc,nspin
  type(xc_info), intent(in) :: xc
  real(gp), intent(in) :: crmult,frmult
  type(atoms_data), intent(in) :: atoms
  type(denspot_distribution), intent(in) :: dpbox
  character(len=3), intent(in) :: rho_commun
  real(gp), dimension(3,atoms%astruct%nat), intent(in) :: rxyz
  !real(gp), dimension(atoms%astruct%ntypes,3), intent(in) :: radii_cf
  type(rho_descriptors), intent(out) :: rhodsc
  !local variables

  if (.not.xc_isgga(xc)) then
     rhodsc%icomm=1
  else
     rhodsc%icomm=0
  endif

  !decide rho communication strategy
  !old way
  !override the  default
  if (rho_commun=='DBL') then
     rhodsc%icomm=0
  else if (rho_commun == 'RSC') then
     rhodsc%icomm=1
  else if (rho_commun=='MIX' .and. (domain_geocode(atoms%astruct%dom).eq.'F') .and. (nproc > 1)) then
     rhodsc%icomm=2
  end if

!!$  !recent way
!!$  if ((atoms%astruct%geocode.eq.'F') .and. (nproc > 1)) then
!!$     rhodsc%icomm=2
!!$  end if
!!$  !override the  default
!!$  if (rho_commun=='DBL') then
!!$     rhodsc%icomm=0
!!$  else if (rho_commun == 'RSC') then
!!$     rhodsc%icomm=1
!!$  end if

  !in the case of taskgroups the RSC scheme should be overridden
  if (rhodsc%icomm==1 .and. size(dpbox%nscatterarr,1) < nproc) then
     if (domain_geocode(atoms%astruct%dom).eq.'F') then
        rhodsc%icomm=2
     else
        rhodsc%icomm=0
     end if
  end if
  !write (*,*) 'hxh,hyh,hzh',hgrids(1),hgrids(2),hgrids(3)
  !create rhopot descriptors
  !allocate rho_descriptors if the density repartition is activated

  if (rhodsc%icomm==2) then !rho_commun=='MIX' .and. (atoms%astruct%geocode.eq.'F') .and. (nproc > 1)) then! .and. xc_isgga()) then
     call rho_segkey(iproc,atoms,rxyz,crmult,frmult,&
          dpbox%mesh%ndims(1),dpbox%mesh%ndims(2),dpbox%mesh%ndims(3),&
          dpbox%mesh%hgrids(1),dpbox%mesh%hgrids(2),dpbox%mesh%hgrids(3),nspin,rhodsc,.false.)
  else
     !nullify rhodsc pointers
     nullify(rhodsc%spkey)
     nullify(rhodsc%dpkey)
     nullify(rhodsc%cseg_b)
     nullify(rhodsc%fseg_b)
  end if

  !calculate dimensions of the complete array to be allocated before the reduction procedure
  if (rhodsc%icomm==1) then
     rhodsc%nrhotot=sum(dpbox%nscatterarr(:,1))
  else
     rhodsc%nrhotot=dpbox%mesh%ndims(3)
  end if

end subroutine density_descriptors

!> routine which initialised the potential data
subroutine default_confinement_data(confdatarr,norbp)
  use locreg_operations, only: confpot_data,nullify_confpot_data
  implicit none
  integer, intent(in) :: norbp
  type(confpot_data), dimension(norbp), intent(out) :: confdatarr
  !local variables
  integer :: iorb

  !initialize the confdatarr
  do iorb=1,norbp
     call nullify_confpot_data(confdatarr(iorb))
  end do
end subroutine default_confinement_data

subroutine define_confinement_data(confdatarr,orbs,rxyz,at,hx,hy,hz,&
           confpotorder,potentialprefac,Lzd,confinementCenter)
  use module_precisions
  use module_types
  use locreg_operations, only: confpot_data
  use locregs, only: get_isf_offset
!!$  use bounds, only: geocode_buffers
  implicit none
  real(gp), intent(in) :: hx,hy,hz
  type(atoms_data), intent(in) :: at
  type(orbitals_data), intent(in) :: orbs
  !!type(linearParameters), intent(in) :: lin
  integer,intent(in):: confpotorder
  real(gp),dimension(at%astruct%ntypes),intent(in):: potentialprefac
  type(local_zone_descriptors), intent(in) :: Lzd
  real(gp), dimension(3,at%astruct%nat), intent(in) :: rxyz
  integer, dimension(orbs%norb), intent(in) :: confinementCenter
  type(confpot_data), dimension(orbs%norbp), intent(out) :: confdatarr
  !local variables
  integer :: iorb,ilr,icenter

  !initialize the confdatarr
  do iorb=1,orbs%norbp
     ilr=orbs%inWhichlocreg(orbs%isorb+iorb)
     icenter=confinementCenter(orbs%isorb+iorb)
     !!confdatarr(iorb)%potorder=lin%confpotorder
     !!confdatarr(iorb)%prefac=lin%potentialprefac(at%astruct%iatype(icenter))
     confdatarr(iorb)%potorder=confpotorder
     confdatarr(iorb)%prefac=potentialprefac(at%astruct%iatype(icenter))
     confdatarr(iorb)%hh(1)=.5_gp*hx
     confdatarr(iorb)%hh(2)=.5_gp*hy
     confdatarr(iorb)%hh(3)=.5_gp*hz
     confdatarr(iorb)%rxyzConf(1:3)=rxyz(1:3,icenter)!Lzd%Llr(ilr)%locregCenter(1:3)

!!$     call geocode_buffers(Lzd%Llr(ilr)%geocode, lzd%glr%geocode, nl1, nl2, nl3)
!!$     confdatarr(iorb)%ioffset(1)=lzd%llr(ilr)%nsi1-nl1-1
!!$     confdatarr(iorb)%ioffset(2)=lzd%llr(ilr)%nsi2-nl2-1
!!$     confdatarr(iorb)%ioffset(3)=lzd%llr(ilr)%nsi3-nl3-1
     confdatarr(iorb)%ioffset(:)=get_isf_offset(lzd%llr(ilr),lzd%glr%mesh)

     !confdatarr(iorb)%ioffset(1)=lzd%llr(ilr)%nsi1-1
     !confdatarr(iorb)%ioffset(2)=lzd%llr(ilr)%nsi2-1
     !confdatarr(iorb)%ioffset(3)=lzd%llr(ilr)%nsi3-1
     !confdatarr(iorb)%ioffset(1)=modulo(lzd%llr(ilr)%nsi1-1,lzd%glr%d%n1i)+1-nl1-1
     !confdatarr(iorb)%ioffset(2)=modulo(lzd%llr(ilr)%nsi2-1,lzd%glr%d%n2i)+1-nl2-1
     !confdatarr(iorb)%ioffset(3)=modulo(lzd%llr(ilr)%nsi3-1,lzd%glr%d%n3i)+1-nl3-1
     confdatarr(iorb)%damping   =1.0_gp
  end do

end subroutine define_confinement_data




!> Print the distribution schemes
subroutine print_distribution_schemes(nproc,nkpts,norb_par,nvctr_par)
  use module_bigdft_output
  implicit none
  !Arguments
  integer, intent(in) :: nproc,nkpts
  integer, dimension(0:nproc-1,nkpts), intent(in) :: norb_par,nvctr_par
  !local variables
  integer :: jproc,ikpt,norbp,isorb,ieorb,isko,ieko,nvctrp,ispsi,iepsi,iekc,iskc
  integer :: iko,ikc,nko,nkc
  integer :: indentlevel

  call yaml_sequence_open('Direct and transposed data repartition')
     do jproc=0,nproc-1
        call start_end_distribution(nproc,nkpts,jproc,norb_par,isko,ieko,norbp)
        call start_end_distribution(nproc,nkpts,jproc,nvctr_par,iskc,iekc,nvctrp)
        iko=isko
        ikc=iskc
        nko=ieko-isko+1
        nkc=iekc-iskc+1
        !print total number of orbitals and components
        call yaml_mapping_open('Process'//trim(yaml_toa(jproc)))

           call yaml_map('Orbitals and Components', (/ norbp, nvctrp /))
           if (norbp /= 0) then
              call yaml_stream_attributes(indent=indentlevel)
              call yaml_sequence_open('Distribution',flow=.true.)
              call yaml_comment('Orbitals: [From, To], Components: [From, To]')
                 call yaml_newline()
                 do ikpt=1,min(nko,nkc)
                    call start_end_comps(nproc,jproc,norb_par(0,iko),isorb,ieorb)
                    call start_end_comps(nproc,jproc,nvctr_par(0,ikc),ispsi,iepsi)
                    call yaml_newline()
                    call yaml_sequence_open(repeat(' ', max(indentlevel+1,0)) // &
                         & "Kpt"//trim(yaml_toa(iko,fmt='(i4.4)')),flow=.true.)
                       call yaml_map("Orbitals",(/ isorb, ieorb /),fmt='(i5)')
                       call yaml_map("Components",(/ ispsi, iepsi /),fmt='(i8)')
                    call yaml_sequence_close()
                    iko=iko+1
                    ikc=ikc+1
                 end do
                 if (nko > nkc) then
                    do ikpt=nkc+1,nko
                       call start_end_comps(nproc,jproc,norb_par(0,iko),isorb,ieorb)
                       call yaml_sequence_open("Kpt"//trim(yaml_toa(iko,fmt='(i4.4)')),flow=.true.)
                       call yaml_map("Orbitals",(/ isorb, ieorb /),fmt='(i5)')
                       call yaml_sequence_close()
                       call yaml_newline()
                       iko=iko+1
                    end do
                 else if (nkc > nko) then
                    do ikpt=nko+1,nkc
                       call start_end_comps(nproc,jproc,nvctr_par(0,ikc),ispsi,iepsi)
                       call yaml_sequence_open("Kpt"//trim(yaml_toa(iko,fmt='(i4.4)')),flow=.true.)
                       call yaml_map("Components",(/ ispsi, iepsi /),fmt='(i8)')
                       call yaml_sequence_close()
                       call yaml_newline()
                    end do
                 end if
              call yaml_sequence_close()
           end if

        call yaml_mapping_close() ! for Process jproc
     end do
  call yaml_sequence_close()  ! for Data distribution

END SUBROUTINE print_distribution_schemes


subroutine start_end_distribution(nproc,nkpts,jproc,ndist,is,ie,norbp)
  implicit none
  integer, intent(in) :: nproc,nkpts,jproc
  integer, dimension(0:nproc-1,nkpts), intent(in) :: ndist
  integer, intent(out) :: is,ie,norbp
  !local variables
  integer :: ikpt
  norbp=0
  do ikpt=1,nkpts
     norbp=norbp+ndist(jproc,ikpt)
  end do
  if (norbp == 0) then
     is=nkpts
     ie=nkpts
  end if
  loop_is: do ikpt=1,nkpts
     if (ndist(jproc,ikpt) /= 0) then
        is=ikpt
        exit loop_is
     end if
  end do loop_is
  loop_ie: do ikpt=nkpts,1,-1
     if (ndist(jproc,ikpt) /= 0) then
        ie=ikpt
        exit loop_ie
     end if
  end do loop_ie
END SUBROUTINE start_end_distribution


subroutine start_end_comps(nproc,jproc,ndist,is,ie)
  implicit none
  integer, intent(in) :: nproc,jproc
  integer, dimension(0:nproc-1), intent(in) :: ndist
  integer, intent(out) :: is,ie
  !local variables
  integer :: kproc

  is=1
  do kproc=0,jproc-1
     is=is+ndist(kproc)
  end do
  ie=is+ndist(jproc)-1

END SUBROUTINE start_end_comps
