!
! Copyright (C) 2001-2007 Quantum ESPRESSO group
! This file is distributed under the terms of the
! GNU General Public License. See the file `License'
! in the root directory of the present distribution,
! or http://www.gnu.org/copyleft/gpl.txt .
!
!
!-----------------------------------------------------------------------
subroutine read_ncpp (iunps, np, upf)
  !-----------------------------------------------------------------------
  !
  USE upf_kinds,  only: dp
  USE upf_params, ONLY: lmaxx
  USE pseudo_types

  implicit none
  !
  TYPE (pseudo_upf) :: upf
  integer :: iunps, np
  !
  real(DP) :: cc(2), alpc(2), aps(6,0:3), alps(3,0:3), &
       a_nlcc, b_nlcc, alpha_nlcc
  real(DP) :: x, vll
  real(DP), allocatable:: vnl(:,:)
  real(DP), parameter :: rcut = 10.d0, e2 = 2.d0
  integer :: nlc, nnl, lmax, lloc, ll(1) 
  integer :: nb, i, l, ir, ios=0
  logical :: bhstype,  numeric
  !
  !====================================================================
  ! read norm-conserving PPs
  !
  read (iunps, *, end=300, err=300, iostat=ios) upf%dft
  if (upf%dft(1:2) .eq.'**') upf%dft = 'PZ'
  read (iunps, *, err=300, iostat=ios) upf%psd, upf%zp, lmax, nlc, &
                                       nnl, upf%nlcc, lloc, bhstype
  if (nlc > 2 .or. nnl > 3) &
       call upf_error ('read_ncpp', 'Wrong nlc or nnl', np)
  if (nlc*nnl < 0) call upf_error ('read_ncpp', 'nlc*nnl < 0 ? ', np)
  if (upf%zp <= 0d0 .or. upf%zp > 100 ) &
       call upf_error ('read_ncpp', 'Wrong zp ', np)
  !
  !   In numeric pseudopotentials both nlc and nnl are zero.
  !
  numeric = (nlc <= 0) .and. (nnl <= 0)
  !
  if (lloc == -1000) lloc = lmax
  if (lloc < 0 .or. lmax < 0 .or. &
       .not.numeric .and. (lloc > min(lmax+1,lmaxx+1) .or. &
       lmax > max(lmaxx,lloc)) .or. &
       numeric .and. (lloc > lmax .or. lmax > lmaxx) ) &
       call upf_error ('read_ncpp', 'wrong lmax and/or lloc', np)
  if (.not.numeric  ) then
     !
     !   read here pseudopotentials in analytic form
     !
     read (iunps, *, err=300, iostat=ios) &
          (alpc(i), i=1,2), (cc(i), i=1,2)
     if (abs (cc(1)+cc(2)-1.d0) > 1.0d-6) &
          call upf_error ('read_ncpp', 'wrong pseudopotential coefficients', 1)
     do l = 0, lmax
        read (iunps, *, err=300, iostat=ios) (alps(i,l), i=1,3), &
                                             (aps(i,l),  i=1,6)
     enddo
     if (upf%nlcc ) then
        read (iunps, *, err=300, iostat=ios) &
             a_nlcc, b_nlcc, alpha_nlcc
        if (alpha_nlcc <= 0.d0) call upf_error('read_ncpp','alpha_nlcc=0',np)
     endif
  endif
  read (iunps, *, err=300, iostat=ios) upf%zmesh, upf%xmin, upf%dx, &
                                       upf%mesh, upf%nwfc 
  if ( upf%mesh <= 0) &
       call upf_error ('read_ncpp', 'wrong number of mesh points', np)
  if ( upf%nwfc < 0 .or. &
       (upf%nwfc < lmax   .and. lloc == lmax) .or. & 
       (upf%nwfc < lmax+1 .and. lloc /= lmax) ) &
       call upf_error ('read_ncpp', 'wrong no. of wfcts', np)
  !
  !  Here pseudopotentials in numeric form are read
  !
  ALLOCATE ( upf%chi(upf%mesh,upf%nwfc), upf%rho_atc(upf%mesh) )
  upf%rho_atc(:) = 0.d0
  ALLOCATE ( upf%lchi(upf%nwfc), upf%oc(upf%nwfc) )
  allocate (vnl(upf%mesh, 0:lmax))
  if (numeric  ) then
     do l = 0, lmax
        read (iunps, '(a)', err=300, iostat=ios)
        read (iunps, *, err=300, iostat=ios) (vnl(ir,l), ir=1,upf%mesh )
     enddo
     if ( upf%nlcc ) then
        read (iunps, *, err=300, iostat=ios) (upf%rho_atc(ir), ir=1,upf%mesh)
     endif
  endif
  !
  !  Here pseudowavefunctions (in numeric form) are read
  !
  do nb = 1, upf%nwfc
     read (iunps, '(a)', err=300, iostat=ios)
     read (iunps, *, err=300, iostat=ios) upf%lchi(nb), upf%oc(nb)
     !
     !     Test lchi and occupation numbers
     !
     if (nb <= lmax .and. upf%lchi(nb)+1 /= nb) &
          call upf_error ('read_ncpp', 'order of wavefunctions', 1)
     if (upf%lchi(nb) > lmaxx .or. upf%lchi(nb) < 0) &
                      call upf_error ('read_ncpp', 'wrong lchi', np)
     if (upf%oc(nb) < 0.d0 .or. upf%oc(nb) > 2.d0*(2*upf%lchi(nb)+1)) &
          call upf_error ('read_ncpp', 'wrong oc', np)
     read (iunps, *, err=300, iostat=ios) ( upf%chi(ir,nb), ir=1,upf%mesh )
  enddo
  !
  !====================================================================
  ! PP read: now setup 
  !
  IF ( numeric ) THEN
     upf%generated='Generated by old ld1 code (numerical format)'
  ELSE
     upf%generated='From published tables, or generated by old fitcar code (analytical format)'
  END IF
  !
  !    calculate the number of beta functions
  !
  upf%nbeta = 0
  do l = 0, lmax
     if (l /= lloc ) upf%nbeta = upf%nbeta + 1
  enddo
  ALLOCATE ( upf%lll(upf%nbeta) )
  nb = 0
  do l = 0, lmax
     if (l /= lloc ) then
        nb = nb + 1 
        upf%lll (nb) = l
     end if
  enddo
  !
  !    compute the radial mesh
  !
  ALLOCATE ( upf%r(upf%mesh), upf%rab(upf%mesh) )
  do ir = 1, upf%mesh
     x = upf%xmin + DBLE (ir - 1) * upf%dx
     upf%r(ir) = exp (x) / upf%zmesh 
     upf%rab(ir) = upf%dx * upf%r(ir)
  enddo
  do ir = 1, upf%mesh
     if ( upf%r(ir) > rcut) then
        upf%kkbeta = ir
        go to 5
     end if
  end do
  upf%kkbeta = upf%mesh
  !
  ! ... force kkbeta to be odd for simpson integration (obsolete?)
  !
5 upf%kkbeta = 2 * ( ( upf%kkbeta + 1 ) / 2) - 1
  !
  ALLOCATE ( upf%kbeta(upf%nbeta) )
  upf%kbeta(:) = upf%kkbeta
  ALLOCATE ( upf%vloc(upf%mesh) )
  upf%vloc (:) = 0.d0
  !
  if (.not. numeric) then
     !
     ! bring analytic potentials into numerical form
     !
     IF ( nlc == 2 .AND. nnl == 3 .AND. bhstype ) THEN
          ll(1) = lmax ! workaround for NAG compiler
          CALL bachel( alps(1,0), aps(1,0), 1, ll )
     END IF
     !
     do i = 1, nlc 
        do ir = 1, upf%kkbeta
           upf%vloc (ir) = upf%vloc (ir) - upf%zp * e2 * cc (i) * &
               erf ( sqrt (alpc(i)) * upf%r(ir) ) / upf%r(ir)
        end do
     end do
     do l = 0, lmax
        vnl (:, l) = upf%vloc (1:upf%mesh)
        do i = 1, nnl 
           vnl (:, l) = vnl (:, l) + e2 * (aps (i, l) + &
                   aps (i + 3, l) * upf%r (:) **2) * &
                   exp ( - upf%r(:) **2 * alps (i, l) )
        enddo
     enddo
     if ( upf%nlcc ) then
          upf%rho_atc(:) = ( a_nlcc + b_nlcc*upf%r(:)**2 ) * &
                      exp ( -upf%r(:)**2 * alpha_nlcc )
     end if
     !
  end if
  !
  ! assume l=lloc as local part and subtract from the other channels
  !
  if (lloc <= lmax ) &
    upf%vloc (:) = vnl (:, lloc)
  ! lloc > lmax is allowed for PP in analytical form only
  ! it means that only the erf part is taken as local part 
  do l = 0, lmax
     if (l /= lloc) vnl (:, l) = vnl(:, l) - upf%vloc(:)
  enddo
  !
  !    compute the atomic charges
  !
  ALLOCATE ( upf%rho_at (upf%mesh) )
  upf%rho_at(:) = 0.d0
  do nb = 1, upf%nwfc
     if ( upf%oc(nb) > 0.d0) then
        do ir = 1, upf%mesh
           upf%rho_at(ir) = upf%rho_at(ir) + upf%oc(nb) * upf%chi(ir,nb)**2
        enddo
     endif
  enddo
  !====================================================================
  ! convert to separable (KB) form
  !
  ALLOCATE ( upf%beta (upf%mesh, upf%nbeta) ) 
  ALLOCATE ( upf%dion (upf%nbeta,upf%nbeta) ) 
  upf%dion (:,:) = 0.d0
  nb = 0
  do l = 0, lmax
     if (l /= lloc ) then
        nb = nb + 1
        ! upf%beta is used here as work space
        do ir = 1, upf%kkbeta
           upf%beta (ir, nb) = upf%chi(ir, l+1) **2 * vnl(ir, l)
        end do
        call simpson (upf%kkbeta, upf%beta (1, nb), upf%rab, vll )
        upf%dion (nb, nb) = 1.d0 / vll
        ! upf%beta stores projectors  |beta(r)> = |V_nl(r)phi(r)>
        do ir = 1, upf%kkbeta
           upf%beta (ir, nb) = vnl (ir, l) * upf%chi (ir, l + 1)
        enddo
        upf%lll (nb) = l
     endif
  enddo
  deallocate (vnl)
  !
  ! for compatibility with USPP and other formats
  !
  upf%nqf = 0
  upf%nqlc= 0
  upf%tvanp =.false.
  upf%tpawp =.false.
  upf%has_so=.false.
  upf%has_wfc=.false.
  upf%has_gipaw=.false.
  upf%tcoulombp=.false.
  upf%is_gth=.false.
  upf%is_multiproj=.false.
  !
  ! Set additional, not present, variables to dummy values
  allocate(upf%els(upf%nwfc))
  upf%els(:) = 'nX'
  allocate(upf%els_beta(upf%nbeta))
  upf%els_beta(:) = 'nX'
  allocate(upf%rcut(upf%nbeta), upf%rcutus(upf%nbeta))
  upf%rcut(:) = 0._dp
  upf%rcutus(:) = 0._dp
  !
  return

300 call upf_error ('read_ncpp', 'pseudo file is empty or wrong', abs (np) )
end subroutine read_ncpp
!
!----------------------------------------------------------------------
subroutine bachel (alps, aps, npseu, lmax)
  !----------------------------------------------------------------------
  !
  USE upf_kinds, ONLY : DP
  USE upf_const, ONLY : pi
  implicit none
  !
  !   First I/O variables
  !
  integer :: npseu, lmax (npseu)
  ! input:  number of pseudopotential
  ! input:  max. angul. momentum of the ps
  real(DP) :: alps (3, 0:3, npseu), aps (6, 0:3, npseu)
  ! input:  the b_l coefficient
  ! in/out: the a_l coefficient
  !
  !   Here local variables
  !
  integer :: np, lmx, l, i, j, k, ia, ka, nik
  ! counter on number of pseudopot.
  ! aux. var. (max. ang. mom. of a fix. ps
  ! counter on angular momentum

  real(DP) :: s (6, 6), alpl, alpi, ail
  ! auxiliary array
  ! first real aux. var. (fix. value of al
  ! second real aux. var. (fix. value of a
  ! third real aux. var.
  !
  do np = 1, npseu
     lmx = lmax (np)
     do l = 0, lmx
        do k = 1, 6
           ka = mod (k - 1, 3) + 1
           alpl = alps (ka, l, np)
           do i = 1, k
              ia = mod (i - 1, 3) + 1
              alpi = alps (ia, l, np)
              ail = alpi + alpl
              s (i, k) = sqrt (pi / ail) / 4.d0 / ail
              nik = int ( (k - 1) / 3) + int ( (i - 1) / 3) + 1
              do j = 2, nik
                 s (i, k) = s (i, k) / 2.d0 / ail * (2 * j - 1)
              enddo
           enddo
        enddo
        !
        do i = 1, 6
           do j = i, 6
              do k = 1, i - 1
                 s (i, j) = s (i, j) - s (k, i) * s (k, j)
              enddo
              if (i.eq.j) then
                 s (i, i) = sqrt (s (i, i) )
              else
                 s (i, j) = s (i, j) / s (i, i)
              endif
           enddo
        enddo
        !
        aps (6, l, np) = - aps (6, l, np) / s (6, 6)
        do i = 5, 1, - 1
           aps (i, l, np) = - aps (i, l, np)
           do k = i + 1, 6
              aps (i, l, np) = aps (i, l, np) - aps (k, l, np) * s (i, k)
           enddo
           aps (i, l, np) = aps (i, l, np) / s (i, i)
        enddo
     enddo

  enddo
  return
end subroutine bachel
