!
! Copyright (C) 2001-2013 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 o_rcgdiagg( npwx, npw, nbnd, psi, e, precondition, &
                     ethr, maxter, reorder, notconv, avg_iter ,&
                      numv, v_states,hdiag,ptype,fcw_number,fcw_state,fcw_mat)
  !----------------------------------------------------------------------------
  !
  ! ... "poor man" iterative diagonalization of a complex hermitian matrix
  ! ... through preconditioned conjugate gradient algorithm
  ! ... Band-by-band algorithm with minimal use of memory

  !
  USE constants, ONLY : pi
  USE kinds,     ONLY : DP
  USE gvect,     ONLY : gstart
  USE mp,        ONLY : mp_sum
  USE mp_world,  ONLY : world_comm
  USE fft_base,  ONLY : dffts
  USE io_global, ONLY :stdout
   
  !
  IMPLICIT NONE
  !
  ! ... I/O variables
  !
  INTEGER,      INTENT(IN)    :: npwx, npw, nbnd, maxter
   REAL (DP),    INTENT(IN)    :: precondition(npw), ethr
  COMPLEX (DP), INTENT(INOUT) :: psi(npwx,nbnd)
  REAL (DP),    INTENT(INOUT) :: e(nbnd)
  INTEGER,      INTENT(OUT)   :: notconv
  REAL (DP),    INTENT(OUT)   :: avg_iter

  INTEGER, INTENT(in) :: numv!number of valence states                                                               
  REAL(kind=DP), INTENT(in) :: v_states(dffts%nnr,numv)!valence states in real space
  REAL(kind=DP), INTENT(in) :: hdiag(npw)!inverse of estimation of diagonal part of hamiltonian
  INTEGER, INTENT(in) :: ptype!type of approximation for O operator
  INTEGER, INTENT(in) :: fcw_number!number of "fake conduction" states for O matrix method 
  COMPLEX(kind=DP) :: fcw_state(npw,fcw_number)! "fake conduction" states for O matrix method
  REAL(kind=DP) :: fcw_mat(fcw_number,fcw_number)! "fake conduction" matrix                                                            


  !
  ! ... local variables
  !
  INTEGER                   :: i, j, m, iter, moved,ig
  REAL (DP),    ALLOCATABLE :: lagrange(:)
  COMPLEX (DP), ALLOCATABLE :: hpsi(:), spsi(:), g(:), cg(:), &
                               scg(:), ppsi(:), g0(:)  
  REAL (DP)                 :: psi_norm, a0, b0, gg0, gamma, gg, gg1, &
                               cg0, e0, es(2)
  REAL (DP)                 :: theta, cost, sint, cos2t, sin2t
  LOGICAL                   :: reorder
  INTEGER                   :: npw2, npwx2
  REAL (DP)                 :: empty_ethr,sca
  !
  ! ... external functions
  !
  REAL (DP), EXTERNAL :: ddot
  !
  !
  CALL start_clock( 'rcgdiagg' )
  !
  empty_ethr = MAX( ( ethr * 5.D0 ), 1.D-5 )
  !
  npw2 = 2 * npw
  npwx2 = 2 * npwx
  !
  ALLOCATE( spsi( npwx ) )
  ALLOCATE( scg(  npwx ) )
  ALLOCATE( hpsi( npwx ) )
  ALLOCATE( g(    npwx ) )
  ALLOCATE( cg(   npwx ) )
  ALLOCATE( g0(   npwx ) )
  ALLOCATE( ppsi( npwx ) )
  !    
  ALLOCATE( lagrange( nbnd ) )
  !
  avg_iter = 0.D0
  notconv  = 0
  moved    = 0
  !
  ! ... every eigenfunction is calculated separately
  !
  DO m = 1, nbnd
     !
     ! ... calculate S|psi>
     !
     spsi(1:npw)=psi(1:npw,m)
    
     !
     ! ... orthogonalize starting eigenfunction to those already calculated
     !
     CALL DGEMV( 'T', npw2, m, 2.D0, psi, npwx2, spsi, 1, 0.D0, lagrange, 1 )
     !
     IF ( gstart == 2 ) lagrange(1:m) = lagrange(1:m) - psi(1,1:m) * spsi(1)
     !
     CALL mp_sum( lagrange( 1:m ), world_comm)
     !
     psi_norm = lagrange(m)
     !
     DO j = 1, m - 1
        !
        psi(:,m)  = psi(:,m) - lagrange(j) * psi(:,j)
        !
        psi_norm = psi_norm - lagrange(j)**2
        !
     END DO
     !
     psi_norm = SQRT( psi_norm )
     !
     psi(:,m) = psi(:,m) / psi_norm
     ! ... set Im[ psi(G=0) ] -  needed for numerical stability
     IF ( gstart == 2 ) psi(1,m) = CMPLX( DBLE(psi(1,m)), 0.D0 ,kind=DP)
     !
     ! ... calculate starting gradient (|hpsi> = H|psi>) ...
     !
     !CALL hs_1psi( npwx, npw, psi(1,m), hpsi, spsi )
     call o_1psi_gamma( numv, v_states, psi(1,m), hpsi,.false.,hdiag, ptype,fcw_number,fcw_state,fcw_mat,ethr)
     spsi(1:npw)=psi(1:npw,m)
     

    !
     ! ... and starting eigenvalue (e = <y|PHP|y> = <psi|H|psi>)
     !
     ! ... NB:  ddot(2*npw,a,1,b,1) = DBLE( zdotc(npw,a,1,b,1) )
     !
     e(m) = 2.D0 * ddot( npw2, psi(1,m), 1, hpsi, 1 )
     !
     IF ( gstart == 2 ) e(m) = e(m) - psi(1,m) * hpsi(1)
     !
     CALL mp_sum( e(m), world_comm)
     !
     ! ... start iteration for this band
     !
     iterate: DO iter = 1, maxter
        !
        ! ... calculate  P (PHP)|y>
        ! ... ( P = preconditioning matrix, assumed diagonal )
        !
        g(1:npw)    = hpsi(1:npw)! / precondition(:)
        ppsi(1:npw) = spsi(1:npw)! / precondition(:)
        !
        ! ... ppsi is now S P(P^2)|y> = S P^2|psi>)
        !
        es(1) = 2.D0 * ddot( npw2, spsi(1), 1, g(1), 1 )
        es(2) = 2.D0 * ddot( npw2, spsi(1), 1, ppsi(1), 1 )
        !
        IF ( gstart == 2 ) THEN
           !
           es(1) = es(1) - spsi(1) * g(1)
           es(2) = es(2) - spsi(1) * ppsi(1)
           !
        END IF
        !
        CALL mp_sum(  es, world_comm )
        !
        es(1) = es(1) / es(2)
        !
        g(:) = g(:) - es(1) * ppsi(:)
        !
        ! ... e1 = <y| S P^2 PHP|y> / <y| S S P^2|y>  ensures that  
        ! ... <g| S P^2|y> = 0
        !
        ! ... orthogonalize to lowest eigenfunctions (already calculated)
        !
        ! ... scg is used as workspace
        !
        !CALL s_1psi( npwx, npw, g(1), scg(1) )
        scg(1:npw)=g(1:npw)
        !
        CALL DGEMV( 'T', npw2, ( m - 1 ), 2.D0, &
                    psi, npwx2, scg, 1, 0.D0, lagrange, 1 )
        !
        IF ( gstart == 2 ) &
           lagrange(1:m-1) = lagrange(1:m-1) - psi(1,1:m-1) * scg(1)
        !
        CALL mp_sum( lagrange( 1 : m-1 ), world_comm)
        !
        DO j = 1, ( m - 1 )
           !
           g(:)   = g(:)   - lagrange(j) * psi(:,j)
           scg(:) = scg(:) - lagrange(j) * psi(:,j)
           !
        END DO
        !
        IF ( iter /= 1 ) THEN
           !
           ! ... gg1 is <g(n+1)|S|g(n)> (used in Polak-Ribiere formula)
           !
           gg1 = 2.D0 * ddot( npw2, g(1), 1, g0(1), 1 )
           !
           IF ( gstart == 2 ) gg1 = gg1 - g(1) * g0(1)
           !
           CALL mp_sum(  gg1, world_comm )
           !
        END IF
        !
        ! ... gg is <g(n+1)|S|g(n+1)>
        !
        g0(:) = scg(:)
        !
        g0(1:npw) = g0(1:npw)! * precondition(:)
        !
        gg = 2.D0 * ddot( npw2, g(1), 1, g0(1), 1 )
        !
        IF ( gstart == 2 ) gg = gg - g(1) * g0(1)
        !
        CALL mp_sum(  gg, world_comm )
        !
        IF ( iter == 1 ) THEN
           !
           ! ... starting iteration, the conjugate gradient |cg> = |g>
           !
           gg0 = gg
           !
           cg(:) = g(:)
           !
        ELSE
           !
           ! ... |cg(n+1)> = |g(n+1)> + gamma(n) * |cg(n)>
           !
           ! ... Polak-Ribiere formula :
           !
           gamma = ( gg - gg1 ) / gg0
           gg0   = gg
           !
           cg(:) = cg(:) * gamma
           cg(:) = g + cg(:)
           !
           ! ... The following is needed because <y(n+1)| S P^2 |cg(n+1)> 
           ! ... is not 0. In fact :
           ! ... <y(n+1)| S P^2 |cg(n)> = sin(theta)*<cg(n)|S|cg(n)>
           !
           psi_norm = gamma * cg0 * sint
           !
           cg(:) = cg(:) - psi_norm * psi(:,m)
           !
        END IF
        !
        ! ... |cg> contains now the conjugate gradient
        ! ... set Im[ cg(G=0) ] -  needed for numerical stability
        IF ( gstart == 2 ) cg(1) = CMPLX( DBLE(cg(1)), 0.D0 ,kind=DP)
        !
        ! ... |scg> is S|cg>
        !
        !CALL hs_1psi( npwx, npw, cg(1), ppsi(1), scg(1) )
        call o_1psi_gamma( numv, v_states, cg, ppsi,.false.,hdiag, ptype,fcw_number,fcw_state,fcw_mat,ethr)
        sca=0.d0
        do ig=1,npw
           sca=sca+2.d0*dble(conjg(cg(ig))*ppsi(ig))
        enddo
        if(gstart==2) sca=sca-dble(conjg(cg(1))*ppsi(1))
        call mp_sum(sca, world_comm)
       
     
        scg(1:npw)=cg(1:npw)
  !
        cg0 = 2.D0 * ddot( npw2, cg(1), 1, scg(1), 1 )
        !
        IF ( gstart == 2 ) cg0 = cg0 - cg(1) * scg(1)
        !
        CALL mp_sum(  cg0, world_comm )
        !
        cg0 = SQRT( cg0 )
        !
        ! ... |ppsi> contains now HP|cg>
        ! ... minimize <y(t)|PHP|y(t)> , where :
        ! ...                         |y(t)> = cos(t)|y> + sin(t)/cg0 |cg>
        ! ... Note that  <y|P^2S|y> = 1, <y|P^2S|cg> = 0 ,
        ! ...           <cg|P^2S|cg> = cg0^2
        ! ... so that the result is correctly normalized :
        ! ...                           <y(t)|P^2S|y(t)> = 1
        !
        a0 = 4.D0 * ddot( npw2, psi(1,m), 1, ppsi(1), 1 )
        !
        IF ( gstart == 2 ) a0 = a0 - 2.D0 * psi(1,m) * ppsi(1)
        !
        a0 = a0 / cg0
        !
        CALL mp_sum(  a0, world_comm )
        !
        b0 = 2.D0 * ddot( npw2, cg(1), 1, ppsi(1), 1 )
        !
        IF ( gstart == 2 ) b0 = b0 - cg(1) * ppsi(1)
        !
        b0 = b0 / cg0**2
        !
        CALL mp_sum(  b0, world_comm )
        !
        e0 = e(m)
        !
        theta = 0.5D0 * ATAN( a0 / ( e0 - b0 ) )
        !
        cost = COS( theta )
        sint = SIN( theta )
        !
        cos2t = cost*cost - sint*sint
        sin2t = 2.D0*cost*sint
        !
        es(1) = 0.5D0 * (   ( e0 - b0 ) * cos2t + a0 * sin2t + e0 + b0 )
        es(2) = 0.5D0 * ( - ( e0 - b0 ) * cos2t - a0 * sin2t + e0 + b0 )
        !
        ! ... there are two possible solutions, choose the minimum
        !
        IF ( es(2) < es(1) ) THEN
           !
           theta = theta + 0.5D0 * pi
           !
           cost = COS( theta )
           sint = SIN( theta )
           !
        END IF
        !
        ! ... new estimate of the eigenvalue
        !
        e(m) = MIN( es(1), es(2) )
      
    
        !
        ! ... upgrade |psi>
        !
        psi(:,m) = cost * psi(:,m) + sint / cg0 * cg(:)
        !
        ! ... here one could test convergence on the energy
        !
       
           !
        IF ( ABS( e(m) - e0 ) < ethr ) EXIT iterate
           !
        
        !
        ! ... upgrade H|psi> and S|psi>
        !
        spsi(:) = cost * spsi(:) + sint / cg0 * scg(:)
        !
        hpsi(:) = cost * hpsi(:) + sint / cg0 * ppsi(:)
        !
     END DO iterate
     !
     IF ( iter >= maxter ) notconv = notconv + 1
     !
     avg_iter = avg_iter + iter + 1
     !
     ! ... reorder eigenvalues if they are not in the right order
     ! ... ( this CAN and WILL happen in not-so-special cases )
     !
     IF ( m > 1 .AND. reorder ) THEN
        !
        IF ( e(m) - e(m-1) < - 2.D0 * ethr ) THEN
           !
           ! ... if the last calculated eigenvalue is not the largest...
           !
           DO i = m - 2, 1, - 1
              !
              IF ( e(m) - e(i) > 2.D0 * ethr ) EXIT
              !
           END DO
           !
           i = i + 1
           !
           moved = moved + 1
           !
           ! ... last calculated eigenvalue should be in the 
           ! ... i-th position: reorder
           !
           e0 = e(m)
           !
           ppsi(:) = psi(:,m)
           !
           DO j = m, i + 1, - 1
              !
              e(j) = e(j-1)
              !
              psi(:,j) = psi(:,j-1)
              !
           END DO
           !
           e(i) = e0
           !
           psi(:,i) = ppsi(:)
           !
           ! ... this procedure should be good if only a few inversions occur,
           ! ... extremely inefficient if eigenvectors are often in bad order
           ! ... ( but this should not happen )
           !
        END IF
        !
     END IF
     !
  END DO
  !
  avg_iter = avg_iter / DBLE( nbnd )
  !
  DEALLOCATE( lagrange )
  DEALLOCATE( ppsi )
  DEALLOCATE( g0 )
  DEALLOCATE( cg )
  DEALLOCATE( g )
  DEALLOCATE( hpsi )
  DEALLOCATE( scg )
  DEALLOCATE( spsi )
  !
  CALL stop_clock( 'rcgdiagg' )
  !
  RETURN
  !
END SUBROUTINE o_rcgdiagg



!
!----------------------------------------------------------------------------
SUBROUTINE o_1psi_gamma( numv, v_states, psi, opsi,l_freq,hdiag, ptype,fcw_number,fcw_state,fcw_mat,ethr)
  !----------------------------------------------------------------------------
  !
  !
  !this subroutines applies the O oprator to a state psi
  !IT WORKS ONLY FOR NORMCONSERVING PSEUDOPOTENTIALS
  !the valence states in G space must be in evc  
  ! Gamma point version

   USE io_global,            ONLY : stdout, ionode, ionode_id
   USE kinds,    ONLY : DP
   USE wannier_gw
   USE gvect
   USE constants, ONLY : e2, pi, tpi, fpi
   USE cell_base, ONLY: at, alat, tpiba, omega, tpiba2
   USE wvfct,    ONLY : g2kin, npwx, npw, nbnd, et
   USE wavefunctions, ONLY : evc, psic
   USE mp, ONLY : mp_sum, mp_barrier, mp_bcast
   USE mp_world, ONLY : world_comm, mpime, nproc
   USE gvecs,              ONLY : doublegrid
   USE kinds, ONLY : DP
   USE fft_base,             ONLY : dfftp, dffts
   USE fft_interfaces,       ONLY : fwfft, invfft
   USE becmod,           ONLY : becp,allocate_bec_type,deallocate_bec_type
   USE uspp,                 ONLY : vkb, nkb, okvan
   USE g_psi_mod,            ONLY : h_diag, s_diag
   USE klist,                ONLY : xk,igk_k
   
  !
  IMPLICIT NONE

  INTEGER, INTENT(in) :: numv!number of valence states
  REAL(kind=DP), INTENT(in) :: v_states(dffts%nnr,numv)!valence states in real space
  COMPLEX(kind=DP), INTENT(in) :: psi(npw)!input wavefunction
  COMPLEX(kind=DP), INTENT(out) :: opsi(npw)!O|\psi>
  LOGICAL, INTENT(in) :: l_freq!if true estimates the operator a 0 frequency
  REAL(kind=DP), INTENT(in) :: hdiag(npw)!inverse of estimation of diagonal part of hamiltonian
  INTEGER, INTENT(in) :: ptype!type of approximation for O operator
  INTEGER, INTENT(in) :: fcw_number!number of "fake conduction" states for O matrix method
  COMPLEX(kind=DP) :: fcw_state(npw,fcw_number)! "fake conduction" states for O matrix method
  REAL(kind=DP) :: fcw_mat(fcw_number,fcw_number)! "fake conduction" matrix
  REAL(kind=DP), INTENT(in) :: ethr!threshold on (H-e) inversion
  

  REAL(kind=DP), ALLOCATABLE :: psi_r(:,:), psi_v(:)
  COMPLEX(kind=DP), ALLOCATABLE :: psi_g(:,:), h_psi_g(:,:),s_psi_g(:,:)
  REAL(kind=DP) :: ec
  INTEGER :: iv,ii,jj,ig

  REAL(kind=DP),ALLOCATABLE  :: p_terms(:),s_terms(:)
  INTEGER :: l_blk,nbegin,nend,nsize
  !REAL(kind=DP), ALLOCATABLE :: h_diag (:,:)
  COMPLEX(kind=DP), ALLOCATABLE :: psi_g2(:,:)
  INTEGER :: kter
  LOGICAL :: lconv_root,lfirst
  REAL(kind=DP) :: anorm
  EXTERNAL :: hpsi_pw4gww,cg_psi_pw4gww
  COMPLEX(kind=DP), POINTER, SAVE :: tmp_psi(:,:)


  allocate(psi_r(dffts%nnr,2),psi_v(dffts%nnr))
  if(pmat_type/=0) then
     allocate(h_psi_g(npw,2),s_psi_g(npw,2),psi_g(npw,2))
  else
     allocate(h_psi_g(npw,numv),s_psi_g(npw,numv),psi_g(npw,numv))
  endif
  
!fourier transform psi to R space

  opsi(1:npw)=(0.d0,0.d0)


  if(pmat_type==0 .or. pmat_type==1 .or. pmat_type==2) then
     psic(:)=(0.d0,0.d0)
     psic(dffts%nl(1:npw))  = psi(1:npw)
     psic(dffts%nlm(1:npw)) = CONJG( psi(1:npw) )
     CALL invfft ('Wave', psic, dffts)
     psi_v(:)= DBLE(psic(:))
  endif
  
  if(pmat_type==0) then
     call start_clock('opsi_total')
     call allocate_bec_type ( nkb, numv, becp)
     IF ( nkb > 0 )  CALL init_us_2( npw, igk_k(1,1), xk(1,1), vkb )
     if(.not.associated(tmp_psi)) then
        allocate( tmp_psi(npw,num_nbndv(1)))
        lfirst=.true.
     else
        lfirst=.false.
     endif
     allocate (h_diag(npw, numv),s_diag(npw,numv))
     allocate(psi_g2(npw,numv))
     !      
     ! compute the kinetic energy
     !                                                                                                                                                   
        do ig = 1, npw
           g2kin (ig) = ( g (1,ig)**2 + g (2,ig)**2 + g (3,ig)**2 ) * tpiba2
        enddo
        h_diag=0.d0
        do iv = 1, numv
           do ig = 1, npw
              !h_diag(ig,ibnd)=1.d0/max(1.0d0,g2kin(ig)/eprec(ibnd,ik))
              !h_diag(ig,iv) = 1.D0 + g2kin(ig) + &
              !     SQRT( 1.D0 + ( g2kin(ig) - 1.D0 )**2 )
              h_diag(ig,iv)=g2kin(ig)
              !h_diag(ig,iv)=1.d0/max(1.0d0,g2kin(ig)/8.d0)
           enddo
        enddo
      do iv=1,numv,2
!!product with psi_v
         if(iv/=numv) then
           psi_r(1:dffts%nnr,1)=psi_v(1:dffts%nnr)*v_states(1:dffts%nnr, iv)
           psi_r(1:dffts%nnr,2)=psi_v(1:dffts%nnr)*v_states(1:dffts%nnr, iv+1)
        else
           psi_r(1:dffts%nnr,1)=psi_v(1:dffts%nnr)*v_states(1:dffts%nnr, iv)
        endif
!!fourier transfrm to G
        if(iv/=numv) then
           psic(1:dffts%nnr)=cmplx(psi_r(1:dffts%nnr,1),psi_r(1:dffts%nnr,2))
        else
           psic(1:dffts%nnr)=cmplx(psi_r(1:dffts%nnr,1),0.d0)
        endif
        call start_clock('opsi_fft')
        CALL fwfft ('Wave', psic, dffts)
        call stop_clock('opsi_fft')
        if(iv/=numv) then
           psi_g(1:npw,iv)=0.5d0*(psic(dffts%nl(1:npw))+conjg(psic(dffts%nlm(1:npw))))
           psi_g(1:npw,iv+1)=(0.d0,-0.5d0)*(psic(dffts%nl(1:npw))-conjg(psic(dffts%nlm(1:npw))))
           if(gstart==2) psi_g(1,iv)=dble(psi_g(1,iv))
           if(gstart==2) psi_g(1,iv+1)=dble(psi_g(1,iv+1))
        else
           psi_g(1:npw,iv)=psic(dffts%nl(1:npw))
           if(gstart==2) psi_g(1,iv)=dble(psi_g(1,iv))
        endif

!!project on conduction manifold                                
        call start_clock('opsi_pc')
        if(iv/=numv) then
           call pc_operator(psi_g(:,iv),1,.false.)
           call pc_operator(psi_g(:,iv+1),1,.false.)
        else
           call pc_operator(psi_g(:,iv),1,.false.)
        endif
        call stop_clock('opsi_pc')
     enddo

     write(stdout,*) 'DEBUG1'
     FLUSH(stdout)
!call (H-e)^-1 solver
     if(.true.) then
        psi_g2(1:npw,1:numv)=psi_g(1:npw,1:numv)
     else
        psi_g2(1:npw,1:numv)=tmp_psi(1:npw,1:numv)
     endif
     write(stdout,*) 'DEBUG1.5'
     FLUSH(stdout)
     call cgsolve_all_gamma (hpsi_pw4gww,cg_psi_pw4gww,et(1,1),psi_g,psi_g2, &
              h_diag,npw,npw,ethr,1,kter,lconv_root,anorm,numv,1)

     tmp_psi(1:npw,1:numv)=psi_g2(1:npw,1:numv)
     write(stdout,*) 'DEBUG2',kter,lconv_root,anorm
     FLUSH(stdout)


     do iv=1,numv,2
        !!project on conduction manifold                                                                                                                            
        call start_clock('opsi_pc')
        if(iv/=numv) then
           call pc_operator(psi_g2(:,iv),1,.false.)
           call pc_operator(psi_g2(:,iv+1),1,.false.)
        else
           call pc_operator(psi_g2(:,iv),1,.false.)
        endif
        call stop_clock('opsi_pc')


        !!fourier transform to R space 
        psic(:)=(0.d0,0.d0)
        if(iv/=numv) then
           psic(dffts%nl(1:npw))  = psi_g2(1:npw,iv)+(0.d0,1.d0)*psi_g2(1:npw,iv+1)
           psic(dffts%nlm(1:npw)) = CONJG( psi_g2(1:npw,iv) )+(0.d0,1.d0)*conjg(psi_g2(1:npw,iv+1))
        else
           psic(dffts%nl(1:npw))  = psi_g2(1:npw,iv)
           psic(dffts%nlm(1:npw)) = CONJG( psi_g2(1:npw,iv) )
        endif
        call start_clock('opsi_fft')
        CALL invfft ('Wave', psic, dffts)
        call stop_clock('opsi_fft')
        if(iv/=numv) then
           psi_r(:,1)= DBLE(psic(:))
           psi_r(:,2)= dimag(psic(:))
        else
           psi_r(:,1)= DBLE(psic(:))
        endif
!!product with psi_v          
        if(iv/=numv) then
           psi_r(1:dffts%nnr,1)=psi_r(1:dffts%nnr,1)*v_states(1:dffts%nnr,iv)
           psi_r(1:dffts%nnr,2)=psi_r(1:dffts%nnr,2)*v_states(1:dffts%nnr,iv+1)
        else
           psi_r(1:dffts%nnr,1)=psi_r(1:dffts%nnr,1)*v_states(1:dffts%nnr,iv)
        endif
!!fourier transform in G space!! sum up results
!!TAKE CARE OF SIGN 
        if(iv/=numv) then
           psic(:)=cmplx(psi_r(:,1),psi_r(:,2))
        else
           psic(:)=cmplx(psi_r(:,1),0.d0)
        endif
        CALL fwfft ('Wave', psic, dffts)
        if(iv/=numv) then
           opsi(1:npw)=opsi(1:npw)-0.5d0*(psic(dffts%nl(1:npw))+conjg(psic(dffts%nlm(1:npw))))
           opsi(1:npw)=opsi(1:npw)-(0.d0,-0.5d0)*(psic(dffts%nl(1:npw))-conjg(psic(dffts%nlm(1:npw))))
        else
           opsi(1:npw)=opsi(1:npw)-psic(dffts%nl(igk_k(1:npw,1)))
        endif
     enddo
     deallocate(h_diag,s_diag)
     deallocate(psi_g2)
     call deallocate_bec_type(becp)
     call stop_clock('opsi_total')
    ! call print_clock('opsi_total')
    ! call print_clock('opsi_fft')
    ! call print_clock('opsi_pc')                   
    
  else if(pmat_type==1) then
!loop on v
     call start_clock('opsi_total')
     do iv=1,numv,2
!!product with psi_v
        if(iv/=numv) then
           psi_r(1:dffts%nnr,1)=psi_v(1:dffts%nnr)*v_states(1:dffts%nnr, iv)
           psi_r(1:dffts%nnr,2)=psi_v(1:dffts%nnr)*v_states(1:dffts%nnr, iv+1)
        else
           psi_r(1:dffts%nnr,1)=psi_v(1:dffts%nnr)*v_states(1:dffts%nnr, iv)
        endif
!!fourier transfrm to G
        if(iv/=numv) then
           psic(1:dffts%nnr)=cmplx(psi_r(1:dffts%nnr,1),psi_r(1:dffts%nnr,2))
        else
           psic(1:dffts%nnr)=cmplx(psi_r(1:dffts%nnr,1),0.d0)
        endif
        call start_clock('opsi_fft')
        CALL fwfft ('Wave', psic, dffts)
        call stop_clock('opsi_fft')
        if(iv/=numv) then
           psi_g(1:npw,1)=0.5d0*(psic(dffts%nl(1:npw))+conjg(psic(dffts%nlm(1:npw))))
           psi_g(1:npw,2)=(0.d0,-0.5d0)*(psic(dffts%nl(1:npw))-conjg(psic(dffts%nlm(1:npw))))
           if(gstart==2) psi_g(1,1)=dble(psi_g(1,1))
           if(gstart==2) psi_g(1,2)=dble(psi_g(1,2))
        else
           psi_g(1:npw,1)=psic(dffts%nl(1:npw))
           if(gstart==2) psi_g(1,1)=dble(psi_g(1,1))
        endif

!!project on conduction manifold
        call start_clock('opsi_pc')
        if(iv/=numv) then
           call pc_operator(psi_g(:,1),1,.false.)
           call pc_operator(psi_g(:,2),1,.false.)
        else
           call pc_operator(psi_g(:,1),1,.false.)
        endif
     !call pc_operator_test(psi_g)
        if(l_freq) then
          
          !    call cgsolve_all_gamma (h_psi, cg_psi, e, d0psi, dpsi, h_diag, &
          !         ndmx, ndim, ethr, ik, kter, conv_root, anorm, nbnd, npol)
          
          
        endif
        call stop_clock('opsi_pc')
!!fourier transform to R space
        psic(:)=(0.d0,0.d0)
        if(iv/=numv) then
           psic(dffts%nl(1:npw))  = psi_g(1:npw,1)+(0.d0,1.d0)*psi_g(1:npw,2)
           psic(dffts%nlm(1:npw)) = CONJG( psi_g(1:npw,1) )+(0.d0,1.d0)*conjg(psi_g(1:npw,2))
        else
           psic(dffts%nl(1:npw))  = psi_g(1:npw,1)
           psic(dffts%nlm(1:npw)) = CONJG( psi_g(1:npw,1) )
        endif
        call start_clock('opsi_fft')
        CALL invfft ('Wave', psic, dffts)
        call stop_clock('opsi_fft')
        if(iv/=numv) then
           psi_r(:,1)= DBLE(psic(:))
           psi_r(:,2)= dimag(psic(:))
        else
           psi_r(:,1)= DBLE(psic(:))
        endif
!!product with psi_v

        if(iv/=numv) then
           psi_r(1:dffts%nnr,1)=psi_r(1:dffts%nnr,1)*v_states(1:dffts%nnr,iv)
           psi_r(1:dffts%nnr,2)=psi_r(1:dffts%nnr,2)*v_states(1:dffts%nnr,iv+1)
        else
           psi_r(1:dffts%nnr,1)=psi_r(1:dffts%nnr,1)*v_states(1:dffts%nnr,iv)
        endif
!!fourier transform in G space
!! sum up results
!!TAKE CARE OF SIGN

        if(iv/=numv) then
           psic(:)=cmplx(psi_r(:,1),psi_r(:,2))
        else
           psic(:)=cmplx(psi_r(:,1),0.d0)
        endif
        CALL fwfft ('Wave', psic, dffts)
        if(iv/=numv) then
           opsi(1:npw)=opsi(1:npw)-0.5d0*(psic(dffts%nl(1:npw))+conjg(psic(dffts%nlm(1:npw))))
           opsi(1:npw)=opsi(1:npw)-(0.d0,-0.5d0)*(psic(dffts%nl(1:npw))-conjg(psic(dffts%nlm(1:npw))))
        else
           opsi(1:npw)=opsi(1:npw)-psic(dffts%nl(igk_k(1:npw,1)))
        endif

     enddo
     call stop_clock('opsi_total')
    ! call print_clock('opsi_total')
    ! call print_clock('opsi_fft')
    ! call print_clock('opsi_pc')
  else if(pmat_type==2) then
     psi_r(:,1)=0.d0
     do iv=1,numv
        psi_r(1:dffts%nnr,1)=psi_r(1:dffts%nnr,1)+psi_v(1:dffts%nnr)*v_states(1:dffts%nnr, iv)
     enddo
     
     psic(:)=cmplx(psi_r(:,1),0.d0)
     CALL fwfft ('Wave', psic, dffts)
     psi_g(1:npw,1)=psic(dffts%nl(igk_k(1:npw,1)))
     if(gstart==2) psi_g(1,1)=dble(psi_g(1,1))
     
     call pc_operator(psi_g(:,1),1,.false.)
     psi_g(1:npw,1)=psi_g(1:npw,1)*hdiag(1:npw)
     call pc_operator(psi_g(:,1),1,.false.)

     psic(dffts%nl(igk_k(1:npw,1)))  = psi_g(1:npw,1)
     psic(dffts%nlm(igk_k(1:npw,1))) = CONJG( psi_g(1:npw,1) )
     CALL invfft ('Wave', psic, dffts)
     psi_r(:,1)=dble(psic(:))
  
     psi_v(:)= psi_r(:,1)
     psi_r(:,1)=0.d0
     do iv=1,numv
        psi_r(1:dffts%nnr,1)=psi_r(1:dffts%nnr,1)+psi_v(1:dffts%nnr)*v_states(1:dffts%nnr, iv)
     enddo

     psic(:)=cmplx(psi_r(:,1),0.d0)
     CALL fwfft ('Wave', psic, dffts)
     opsi(1:npw)=-psic(dffts%nl(igk_k(1:npw,1)))
    
  else!cases 3,4
!form scalar products
     allocate(p_terms(fcw_number),s_terms(fcw_number))
     call dgemm('T','N',fcw_number,1,2*npw,2.d0,fcw_state,2*npw,psi,2*npw,0.d0,p_terms,fcw_number)
     if(gstart==2) then
        do ii=1,fcw_number
           p_terms(ii)=p_terms(ii)-dble(conjg(fcw_state(1,ii))*psi(1))
        enddo
     endif
     call mp_sum(p_terms(:),world_comm)
     
!multiply to D matrix     
     l_blk= (fcw_number)/nproc
     if(l_blk*nproc < (fcw_number)) l_blk = l_blk+1
     nbegin=mpime*l_blk+1
     nend=nbegin+l_blk-1
     if(nend > fcw_number) nend=fcw_number
     nsize=nend-nbegin+1
   

     s_terms(:)=0.d0
     if(nsize>0) then
        call dgemm('T','N',nsize,1,fcw_number,1.d0,fcw_mat,fcw_number,p_terms,fcw_number,0.d0,&
          &s_terms(nbegin:nend),nsize)
     endif
  
!collect from processors
     call mp_sum(s_terms,world_comm)

!multiply with gamma functions
     call dgemm('N','N',2*npw,1,fcw_number,-1.d0,fcw_state,2*npw,s_terms,fcw_number,0.d0,opsi,2*npw)
     
   
     deallocate(p_terms,s_terms)
  endif

  if(gstart==2) opsi(1)=(0.d0,0.d0)
  !
  deallocate(psi_r, psi_g,psi_v)
  deallocate(h_psi_g,s_psi_g)
  !
  RETURN
  !
END SUBROUTINE o_1psi_gamma


SUBROUTINE evc_to_real(numv, v_states)
!this subroutine fourier transform states from evc
!to real space

   USE io_global,            ONLY : stdout, ionode, ionode_id
   USE kinds,    ONLY : DP
   USE wvfct,    ONLY : npwx, npw, nbnd
   USE wavefunctions, ONLY : evc, psic
   USE gvecs,              ONLY : doublegrid
   USE fft_base,             ONLY : dfftp, dffts
   USE fft_interfaces,       ONLY : fwfft, invfft
   USE klist,  ONLY : igk_k

   implicit none

  INTEGER, INTENT(in) :: numv!number of states to be transformed
  REAL(kind=DP), INTENT(out) :: v_states(dffts%nnr,numv)!target arrsy
  
  INTEGER :: iv

  do iv=1,numv,2
     psic(:)=(0.d0,0.d0)
     if(iv < numv) then
        psic(dffts%nl(igk_k(1:npw,1)))  = evc(1:npw,iv)+(0.d0,1.d0)*evc(1:npw,iv+1)
        psic(dffts%nlm(igk_k(1:npw,1))) = CONJG( evc(1:npw,iv) )+(0.d0,1.d0)*CONJG(evc(1:npw,iv+1))
     else
        psic(dffts%nl(igk_k(1:npw,1)))  = evc(1:npw,iv)
        psic(dffts%nlm(igk_k(1:npw,1))) = CONJG( evc(1:npw,iv) )
     endif
     CALL invfft ('Wave', psic, dffts)
     if(iv<numv) then
        v_states(1:dffts%nnr,iv)=dble(psic(1:dffts%nnr))
        v_states(1:dffts%nnr,iv+1)=dimag(psic(1:dffts%nnr))
     else
        v_states(1:dffts%nnr,iv)=dble(psic(1:dffts%nnr))
     endif

  enddo
return

END SUBROUTINE evc_to_real


SUBROUTINE o_basis_init(numpw,o_basis,numv,v_states,cutoff, ptype,fcw_number,fcw_state,fcw_mat,ethr)
!this subroutine initializes the polarization basis to
!random values and diagonalize with respect to the O matrix


  USE gvect, ONLY : g
  USE io_global,            ONLY : stdout, ionode, ionode_id
  USE kinds,    ONLY : DP
  USE wvfct,    ONLY : g2kin, npwx, npw, nbnd
  USE wavefunctions, ONLY : evc, psic
  USE gvecs,              ONLY : doublegrid
  USE constants, ONLY : tpi
  USE random_numbers, ONLY : randy
  USE klist,                ONLY : xk,igk_k
  USE cell_base,            ONLY : tpiba2
  USE fft_base,             ONLY : dfftp, dffts
  USE fft_interfaces,       ONLY : fwfft, invfft
  

   implicit none

   INTEGER, INTENT(in) :: numv!number of states to be transformed
   REAL(kind=DP), INTENT(in) :: v_states(dffts%nnr,numv)!valence states in real space
   INTEGER, INTENT(in) :: numpw!dimesion of the polarization basis
   COMPLEX(kind=DP), INTENT(out) :: o_basis(npw,numpw)!polarization basis
   REAL(kind=DP), INTENT(in) :: cutoff!cutoff for planewaves
   INTEGER, INTENT(in) :: ptype!type of approximation for O operator
   INTEGER, INTENT(in) :: fcw_number!number of "fake conduction" states for O matrix method
   COMPLEX(kind=DP) :: fcw_state(npw,fcw_number)! "fake conduction" states for O matrix method
   REAL(kind=DP) :: fcw_mat(fcw_number,fcw_number)! "fake conduction" matrix
   REAL(kind=DP), INTENT(in) :: ethr!threshold o_1psi_gamma


   INTEGER :: iw,ig
   REAL(kind=DP) :: rr, arg
   REAL(kind=DP), ALLOCATABLE :: e(:)
   REAL(kind=DP), ALLOCATABLE :: hdiag(:)


  
   allocate(hdiag(npw))

   g2kin(1:npw) = ( (g(1,igk_k(1:npw,1)) )**2 + &
        ( g(2,igk_k(1:npw,1)) )**2 + &
        ( g(3,igk_k(1:npw,1)) )**2 ) * tpiba2

  
   do ig=1,npw
      !if(g2kin(ig) <= 3.d0) then
      if(g2kin(ig) <= cutoff) then
         hdiag(ig)=1.d0!/(1.d0+g2kin(ig))
      else
        hdiag(ig)=0.d0
     endif
  enddo
  hdiag(:)=1.d0
  

   allocate( e(numpw))

   DO iw = 1, numpw
      !
      DO ig = 1, npw
                   !
         rr  = randy()
         
         arg = tpi * randy()
                   !
         o_basis(ig,iw) = CMPLX( rr*COS( arg ), rr*SIN( arg ) ) / &
              ( g(1,igk_k(ig,1))**2 +  g(2,igk_k(ig,1))**2 + g(3,igk_k(ig,1))**2 + 1.D0) 
                   !
      END DO
                !
   END DO

   !CALL rinitcgg( npwx, npw, n_starting_wfc, &
   !                         nbnd, wfcatom, wfcatom, etatom )

  

   call o_rinitcgg( npwx, npw, numpw, numpw, o_basis, o_basis, e, numv, v_states,hdiag,ptype,fcw_number,fcw_state,fcw_mat,ethr)
   do iw=1,numpw
      write(stdout,*) 'E', iw, e(iw)
   enddo

   deallocate(e)
   deallocate(hdiag)
   return

 END SUBROUTINE o_basis_init


 SUBROUTINE o_basis_write(numpw, o_basis,lcutoff,ecutoff, l_pbc)

!this subroutines writes the basis of the polarization on file
   USE io_global,            ONLY : stdout, ionode, ionode_id
   USE kinds,    ONLY : DP
   USE wvfct,    ONLY : npwx, npw, nbnd
   USE wavefunctions, ONLY : evc, psic
   USE gvecs,              ONLY : doublegrid
   USE wavefunctions, ONLY : psic
   USE io_files,  ONLY : diropn, prefix
   USE gvect,     ONLY : ngm, gg,gstart
   USE cell_base, ONLY: tpiba2
   USE wannier_gw, ONLY : max_ngm
   USE fft_base,             ONLY : dfftp, dffts
   USE fft_interfaces,       ONLY : fwfft, invfft
   USE klist,   ONLY : igk_k

   implicit none 

   INTEGER, EXTERNAL :: find_free_unit

   INTEGER, INTENT(inout) :: numpw!dimension of the polarization basis
   COMPLEX(kind=DP), INTENT(in) :: o_basis(npw,numpw)
   REAL(kind=DP), INTENT(in) :: ecutoff!cutoff in Rydberg for g sum  
   LOGICAL, INTENT(in) :: lcutoff !if true uses cutoff on G defined by ecutoff
   LOGICAL, INTENT(in) :: l_pbc!if true PBC are assumed and element G=0 is added as the last one
   
   INTEGER :: iw, iungprod, ig,ngm_max
   LOGICAL :: exst
   COMPLEX(kind=DP), ALLOCATABLE :: tmp_g(:)

   allocate(tmp_g(max_ngm))

   if(lcutoff) then
      ngm_max=0
      do ig=1,ngm
         if(gg(ig)*tpiba2 >= ecutoff) exit
         ngm_max=ngm_max+1
      enddo
   else
      ngm_max=ngm
   endif

   write(stdout,*) 'NGM MAX:', ngm_max, ngm

   iungprod = find_free_unit()
   CALL diropn( iungprod, 'wiwjwfc_red', max_ngm*2, exst )



   do iw=1,numpw

      psic(:)=(0.d0,0.d0)
      psic(dffts%nl(igk_k(1:npw,1)))  = o_basis(1:npw,iw)
      psic(dffts%nlm(igk_k(1:npw,1))) = CONJG( o_basis(1:npw,iw))
      tmp_g(1:max_ngm)=psic(dfftp%nl(1:max_ngm))
      if(gstart==2) tmp_g(1)=(0.d0,0.d0)
      CALL davcio(tmp_g, max_ngm*2,iungprod,iw,1)
   enddo

   if(l_pbc) then
      numpw=numpw+1
      tmp_g(1:max_ngm)=(0.d0,0.d0)
      if(gstart==2) tmp_g(1)=(1.d0,0.d0)
      CALL davcio(tmp_g, max_ngm*2,iungprod,numpw,1)
   endif
   close(iungprod)
   deallocate(tmp_g)

   return

 END SUBROUTINE o_basis_write


!----------------------------------------------------------------------------
SUBROUTINE o_1psi_gamma_real( numv, v_states, psi, opsi)
  !----------------------------------------------------------------------------
  !
  !
  !this subroutines applies the O oprator to a state psi
  !IT WORKS ONLY FOR NORMCONSERVING PSEUDOPOTENTIALS
  !the valence states in G space must be in evc
  ! Gamma point version in real space

   USE io_global,            ONLY : stdout, ionode, ionode_id
   USE kinds,    ONLY : DP
   USE wannier_gw
   USE gvect
   USE constants, ONLY : e2, pi, tpi, fpi
   USE cell_base, ONLY: at, alat, tpiba, omega, tpiba2
   USE wvfct,    ONLY : npwx, npw, nbnd
   USE wavefunctions, ONLY : evc, psic
   USE mp, ONLY : mp_sum, mp_barrier, mp_bcast
   USE mp_world, ONLY : mpime, world_comm
   USE gvecs,              ONLY : doublegrid
   USE fft_base,             ONLY : dfftp, dffts
   USE fft_interfaces,       ONLY : fwfft, invfft
   USE klist,  ONLY : igk_k

  USE kinds, ONLY : DP
  !
  IMPLICIT NONE

  INTEGER, INTENT(in) :: numv!number of valence states
  REAL(kind=DP), INTENT(in) :: v_states(dffts%nnr,numv)!valence states in real space
  COMPLEX(kind=DP), INTENT(in) :: psi(npw)!input wavefunction
  COMPLEX(kind=DP), INTENT(out) :: opsi(npw)!O|\psi>

  REAL(kind=DP), ALLOCATABLE :: psi_r(:), psi_v(:), psi_w(:)
  COMPLEX(kind=DP), ALLOCATABLE :: psi_g(:)
  REAL(kind=DP), ALLOCATABLE :: prod(:)
  INTEGER :: iv

  allocate(psi_r(dffts%nnr),psi_g(npw),psi_v(dffts%nnr))
  allocate(prod(numv),psi_w(dffts%nnr))

!fourier transform psi to R space

  opsi(1:npw)=(0.d0,0.d0)

  psic(:)=(0.d0,0.d0)
  psic(dffts%nl(igk_k(1:npw,1)))  = psi(1:npw)
  psic(dffts%nlm(igk_k(1:npw,1))) = CONJG( psi(1:npw) )
  CALL invfft ('Wave', psic, dffts)
  psi_v(1:dffts%nnr)= DBLE(psic(1:dffts%nnr))
  psi_w(:)=0.d0
!loop on v
  do iv=1,numv

!!product with psi_v
     psi_r(1:dffts%nnr)=psi_v(1:dffts%nnr)*v_states(1:dffts%nnr, iv)
!!project on conduction manifold
     call dgemm('T','N',numv,1,dffts%nnr,1.d0,v_states,dffts%nnr,psi_r,dffts%nnr,0.d0,prod,numv)
     call mp_sum(prod(1:numv), world_comm)
     prod(:)=prod(:)/dble(dffts%nr1*dffts%nr2*dffts%nr3)
     call dgemm('N','N',dffts%nnr,1,numv,-1.d0,v_states,dffts%nnr,prod,numv,1.d0, psi_r,dffts%nnr)
!


     psi_r(1:dffts%nnr)=psi_r(1:dffts%nnr)*v_states(1:dffts%nnr,iv)

!add up result (with sign)
     psi_w(:)=psi_w(:)-psi_r(:)



  enddo
!!fourier transform in G space


  psic(:)=cmplx(psi_w(:),0.d0)
  CALL fwfft ('Wave', psic, dffts)
  opsi(1:npw)=psic(dffts%nl(igk_k(1:npw,1)))


  if(gstart==2) opsi(1)=dble(opsi(1))
  !
  deallocate(psi_r, psi_g,psi_v)
  deallocate(prod,psi_w)
  !
  RETURN
  !
END SUBROUTINE o_1psi_gamma_real



 SUBROUTINE o_basis_test(numv,v_states,numpw, lcutoff,ecutoff)

!this subroutines writes the basis of the polarization on file      
   USE io_global,            ONLY : stdout, ionode, ionode_id
   USE kinds,    ONLY : DP
   USE wvfct,    ONLY : npwx, npw, nbnd
   USE wavefunctions, ONLY : evc, psic
   USE gvecs,              ONLY : doublegrid
   USE wavefunctions, ONLY : psic
   USE io_files,  ONLY : prefix, tmp_dir, diropn
   USE gvect,     ONLY : ngm, gg,gstart
   USE cell_base, ONLY: tpiba2
   USE wannier_gw, ONLY : max_ngm
   USE mp, ONLY : mp_sum
   USE mp_world, ONLY : world_comm
   USE fft_base,             ONLY : dfftp, dffts
   USE fft_interfaces,       ONLY : fwfft, invfft
   USE klist, ONLY : igk_k



   implicit none

   INTEGER, EXTERNAL :: find_free_unit
   INTEGER, INTENT(in) :: numv!number of valence states
   REAL(kind=DP), INTENT(in) :: v_states(dffts%nnr,numv)!valence states in real space             
   INTEGER, INTENT(in) :: numpw!dimension of the polarization basis
   REAL(kind=DP), INTENT(in) :: ecutoff!cutoff in Rydberg for g sum
   LOGICAL, INTENT(in) :: lcutoff !if true uses cutoff on G defined by ecutoff    

   INTEGER :: iw, iungprod, ig,ngm_max
   LOGICAL :: exst
   COMPLEX(kind=DP), ALLOCATABLE :: tmp_g(:), psi1(:),psi2(:)
   REAL(kind=DP) :: sca

   allocate(tmp_g(max_ngm),psi1(npw),psi2(npw))
   
   if(lcutoff) then
      ngm_max=0
      do ig=1,ngm
         if(gg(ig)*tpiba2 >= ecutoff) exit
         ngm_max=ngm_max+1
      enddo
   else
      ngm_max=ngm
   endif

   write(stdout,*) 'NGM MAX:', ngm_max, ngm

   iungprod = find_free_unit()
   CALL diropn( iungprod, 'wiwjwfc_red', max_ngm*2, exst )

   do iw=1,numpw
      CALL davcio(tmp_g, max_ngm*2,iungprod,iw,-1)
      psic(:)=(0.d0,0.d0)
      do ig=1,max_ngm
         psic(dffts%nl(ig))=tmp_g(ig)
         psic(dffts%nlm(ig))=conjg(tmp_g(ig))
      enddo
      do ig=1,npw
         psi1(ig)=psic(dffts%nl(igk_k(ig,1)))
      enddo

      call o_1psi_gamma_real( numv, v_states, psi1, psi2)
      sca=0.d0
      do ig=1,npw
         sca=sca+2.d0*dble(conjg(psi2(ig))*psi2(ig))
      enddo
      if(gstart==2) sca=sca-dble(conjg(psi2(1))*psi2(1))
      call mp_sum(sca,world_comm)
      sca=dsqrt(sca)
      psi2(:)=psi2(:)/sca
      sca=0.d0
      do ig=1,npw
         sca=sca+2.d0*dble(conjg(psi1(ig))*psi2(ig))
      enddo
      if(gstart==2) sca=sca-dble(conjg(psi1(1))*psi2(1))
      call mp_sum(sca,world_comm)
      write(stdout,*) 'o basis test:',iw,sca

   enddo


   close(iungprod)
   deallocate(tmp_g,psi1,psi2)

   return

 END SUBROUTINE o_basis_test

