!============================================================================
!
! Routines:
!
! (1) mtxel()   Originally By ?         Last Modified 7/8/2008 (JRD)
!
!     Subroutine computes required matrix elements
!     of the form <nn,k|exp{i(q+g).r}|n1,k-q>
!
!     input   nn               band index
!     input   ncoul              number of matrix elements required
!     input   isrtrq             index array for g-vectors in
!                                <nk|exp(i(q+g).r)|n1k-q>
!     output  aqs                matrix elements required
!
!============================================================================

#include "f_defs.h"

subroutine mtxel(nn,gvec,wfnkq,wfnk,ncoul,isrtrq,aqs,ispin,kp)

  use global_m
  use fftw_m
  use misc_m
  implicit none

  integer, intent(in) :: nn
  type (gspace), intent(in) :: gvec
  type (wfnkqstates), intent(in) :: wfnkq
  type (wfnkstates), intent(in) :: wfnk
  type (kpoints), intent(inout) :: kp
  integer, intent(in) :: ncoul
  integer, intent(in) :: isrtrq(gvec%ng)
  SCALAR, intent(out) :: aqs(ncoul,peinf%ntband_max)
  integer, intent(in) :: ispin

  integer :: n1,jspinor,jspinormin,jspinormax

!-------------------------
! If we are using FFT to calculate matrix elements...

! We use FFT to compute <u_nn,k|e^(iG.r)|u_n1,k-q> elements where
! u_nk is the periodic part of the wave function.
! The calculation is done in real space, and integration over
! the grid is replaced by the sum over the grid points p:
!
! <u_nn,k|e^(iG.r)|u_n1,k-q>  =
!     Volume/Np * sum_p { conj(u_nn,k(p))*e^(iG.p)*u_n1k-q(p) }
!
! Since u_nk(p) = Volume^-0.5 * sum_G { cnk(G)*e^(iG.p) },
! and FFT is defined as FFT(cnk,+,p) = sum_G { cnk(G)*e^{+iG.p} },
! we must compute
!
! <u_nn,k|e^(iG.r)|u_n1,k-q>
!   = 1/Np * sum_p { conj(FFT(c_nn k,+,p))*e^(iG.p)*FFT(c_n1 k-q,+,p) }
!   = 1/Np * FFT(conj(FFT(c_nn k,+,:)).*FFT(c_n1 k-q,+,:),+,G)
!
! where .* is a point by point multiplication on the grid

  complex(DPC), dimension(:,:,:), allocatable :: fftbox1,fftbox2
  integer, dimension(3) :: Nfft
  real(DP) :: scale
  SCALAR, dimension(:), allocatable :: tmparray

! Compute size of FFT box we need and scale factor

  PUSH_SUB(mtxel)

  call setup_FFT_sizes(gvec%FFTgrid,Nfft,scale)

! Allocate FFT boxes

  SAFE_ALLOCATE(fftbox1, (Nfft(1),Nfft(2),Nfft(3)))
  SAFE_ALLOCATE(fftbox2, (Nfft(1),Nfft(2),Nfft(3)))

! Put the data for band nn into FFT box 1 and do the FFT,zk(:,1)

  call set_jspinor(jspinormin,jspinormax,ispin,kp%nspinor)

  SAFE_ALLOCATE(tmparray, (ncoul))

  do jspinor = jspinormin,jspinormax

    call put_into_fftbox(wfnk%nkpt,wfnk%zk((nn-1)*wfnk%nkpt+1:,jspinor),gvec%components,wfnk%isrtk,fftbox1,Nfft)
    call do_FFT(fftbox1,Nfft,1)

! We need the complex conjugate of the |nk> band actually

    call conjg_fftbox(fftbox1,Nfft)

! Now we loop over the n1 states and get the matrix elements:
!  Get n1 wave function and put it into box 2,
!  do FFT,
!  multiply by box1 contents,
!  do FFT again,
!  and extract the resulting matrix elements

    do n1=1,peinf%ntband_node
      call put_into_fftbox(wfnkq%nkpt,wfnkq%zkq((n1-1)*wfnkq%nkpt+1:,jspinor),gvec%components,wfnkq%isrtkq,fftbox2,Nfft)
      call do_FFT(fftbox2,Nfft,1)
      call multiply_fftboxes(fftbox1,fftbox2,Nfft)
      call do_FFT(fftbox2,Nfft,1)
      call get_from_fftbox(ncoul,tmparray,gvec%components,isrtrq,fftbox2,Nfft,scale)
      if (kp%nspinor.eq.1 .or. jspinor.eq. 1) then
        aqs(:,n1) = tmparray(:)
      else
        aqs(:,n1) = aqs(:,n1) + tmparray(:)
      endif

    enddo

  enddo

  SAFE_DEALLOCATE(tmparray)

! We are done, so deallocate FFT boxes

  SAFE_DEALLOCATE(fftbox1)
  SAFE_DEALLOCATE(fftbox2)
  
  POP_SUB(mtxel)
  
  return
end subroutine mtxel
