! ! 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 = = ) ! ! ... 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 = / ensures that ! ... = 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 (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 ! 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 ! ... is not 0. In fact : ! ... = sin(theta)* ! 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 , where : ! ... |y(t)> = cos(t)|y> + sin(t)/cg0 |cg> ! ... Note that = 1, = 0 , ! ... = cg0^2 ! ... so that the result is correctly normalized : ! ... = 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= 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