!=================================================================================
!
! Routines:
!
! (1) epsinv()          Originally By (?)                Last Modified 5/1/2008 (JRD)
!
!     This routine:
!
!     1. Calculates epsilon based on chi.
!     2. Inverts epsilon.
!     3. Writes the result to unit=12 if q0="zero" and unit 13 otherwise.
!
!=================================================================================

#include "f_defs.h"

subroutine epsinv(gvec,pol,ekin,q0,is_q0,crys,scal,kp,omega_plasma,iq)
  
  use global_m
  use inversion_m
  use misc_m
  use scalapack_m
  use vcoul_generator_m
  use write_matrix_m
  implicit none

  type (gspace), intent(in) :: gvec
  type (polarizability), intent(in) :: pol
  real(DP), intent(in) :: ekin(gvec%ng)
  real(DP), intent(in) :: q0(3)
  logical, intent(in) :: is_q0
  type (crystal), intent(in) :: crys
  type (scalapack), intent(in) :: scal
  type (kpoints), intent(in) :: kp
  real(DP), intent(in) :: omega_plasma
  integer, intent(in) :: iq

  integer :: qgrid(3)
  real(DP) :: q0vec(3)
  type (twork_scell) :: work_scell
  integer :: i,j,jj,ii,is,js,iunit,my_iq,ifreq
  integer :: irow, icol, icurr, irowm, icolm
  integer, allocatable :: isorti(:)
  integer :: iscreen, nfk, iparallel, isize,ifreq_para,freq_grp_ind
  real(DP) :: vc, oneoverq, avgcut
  real(DP) :: epssum1R, epssum2R, epssum1R_rel,epssum2R_rel
#ifdef CPLX
  real(DP) :: epssum1A, epssum2A, epssum1A_rel,epssum2A_rel
#endif
  SCALAR :: chitmp
  SCALAR, allocatable :: eps(:,:),ewng(:)
  real(DP), allocatable :: epsdiag(:,:,:),epsdiagt(:,:,:)
  real(DP), allocatable :: vcoul(:)
  complex(DPC), allocatable :: chiRDyntmp(:), chiADyntmp(:)
  complex(DPC), allocatable :: epsRDyn(:,:,:), epsADyn(:,:,:)
  complex(DPC), allocatable :: epsRDyn_head(:),epsADyn_head(:),epsRDyn_head_temp(:),epsADyn_head_temp(:)
  ! Auxiliary matrix for inversion
  complex(DPC), allocatable :: eps1Aux(:,:)
  SCALAR :: epsheaddummy, wcoul0
  character*80 :: filename

  PUSH_SUB(epsinv)

  SAFE_ALLOCATE(vcoul, (pol%nmtx))
  
  if(pol%freq_dep .eq. 0) then
    SAFE_ALLOCATE(eps, (scal%npr,scal%npc))
    SAFE_ALLOCATE(ewng, (pol%nmtx))
  endif

  if(pol%freq_dep .eq. 2) then
    SAFE_ALLOCATE(chiRDyntmp, (pol%os_nfreq_para))
    SAFE_ALLOCATE(epsRDyn, (pol%os_nfreq_para,scal%npr,scal%npc))
#ifdef CPLX
    SAFE_ALLOCATE(chiADyntmp, (pol%os_nfreq_para))
    SAFE_ALLOCATE(epsADyn, (pol%os_nfreq_para,scal%npr,scal%npc))
#endif
    SAFE_ALLOCATE(eps1Aux, (scal%npr,scal%npc))
  endif

  if(pol%freq_dep .eq. 3) then
    SAFE_ALLOCATE(chiRDyntmp, (pol%os_nfreq_para))
    SAFE_ALLOCATE(epsRDyn, (pol%os_nfreq_para,scal%npr,scal%npc))
    SAFE_ALLOCATE(eps1Aux, (scal%npr,scal%npc))
  endif

  
  SAFE_ALLOCATE(isorti, (gvec%ng))
      
!------------------------------
! Invert isrtx

!
! SIB: isorti is the inverse sort order for pol%isrtx.
! pol%isrtx has the sort indices for |q0+gvec%components|^2
!

  if(pol%freq_dep .eq. 0) then
    eps(:,:)=ZERO
  endif
  
  if(pol%freq_dep .eq. 2) then
    epsRDyn(:,:,:)=(0.d0,0.d0)
#ifdef CPLX
    epsADyn(:,:,:)=(0.d0,0.d0)
#endif
  endif

  if(pol%freq_dep .eq. 3) then
    epsRDyn(:,:,:)=(0.d0,0.d0)
  endif
  
  
  vcoul(:)=0.0d0
  do i=1,gvec%ng
    isorti(pol%isrtx(i)) = i
  end do


!-------------- Construct Dielectric Matrix ---------------------------

!
! e(q+g,q+g`) = del(g,g`) - (8pi/(q+g)**2) chi(q+g,q+g`).  For spin-polarized
! calc., e(G+q,G`+q)=del(G,G`)- (8PI/(G+q)^2) SUM_spin chi(G+q,G`+q,ispin)
! Which is pol%chi(j,1) as compiled in epsilon_main.f90.  If q--> 0 , we have to treat
! the wings separately
!
! SIB:  using the Rydberg as our unit of energy
! if pol%icutv is on (coulomb cutoff) then we multiply the coulomb
! interaction by the appropriate factor (1-cos(vcut*|q0+g|))
!

!      if (peinf%inode .eq. 0) then
!        write(6,*) ' '
!        write(6,*) 'Calculating Coulomb Potential'
!      endif

  icurr=0

! Generator Coulomb Interaction Array Vcoul

! For Epsilon, We want to treat all types of screening the same for vcoul.  Because
! we calculate it exactly

  avgcut=TOL_ZERO
  iscreen=0
  nfk=product(kp%kgrid(1:3))
  q0vec=0d0
  iparallel=1

  if(peinf%inode.eq.0) call timacc(18,1)
  
  qgrid(:)=1

  epsheaddummy=0.0d0
  wcoul0=0.0d0

  call vcoul_generator(pol%icutv,pol%truncval,gvec,crys%bdot, &
    nfk,pol%nmtx,pol%isrtx,iscreen,q0,q0vec,vcoul, &
    pol%iwritecoul,iparallel,avgcut,oneoverq,qgrid,epsheaddummy, &
    work_scell,.false.,wcoul0)

  if(peinf%inode.eq.0) call timacc(18,2)

!      write(6,*) 'Done VCoul'

  if(pol%freq_dep .eq. 0) then
    do i=1,pol%nmtx
      
      irow=MOD(INT(((i-1)/scal%nbl)+TOL_SMALL),scal%nprow)
      if(irow.ne.scal%myprow) cycle
      
      vc = vcoul(i)

!-------------------------
! Actually Construct eps

      do j=1,pol%nmtx
        icol=MOD(INT(((j-1)/scal%nbl)+TOL_SMALL),scal%npcol)
        if(icol .eq. scal%mypcol) then
          icurr=icurr+1
          irowm=INT((icurr-1)/scal%npc+TOL_SMALL)+1
          icolm=MOD((icurr-1),scal%npc)+1

          eps(irowm,icolm) = ZERO
          if (i.eq.j) eps(irowm,icolm) = ONE
          chitmp = pol%chi(irowm,icolm,1)
          eps(irowm,icolm) = eps(irowm,icolm) - vc*chitmp
        endif
      end do
    end do
  endif
  
  if(pol%freq_dep .eq. 2 .or. pol%freq_dep .eq. 3) then
    do i=1,pol%nmtx

!          if (peinf%inode .eq. 0) then
!            write(6,*) 'Starting loop', i
!          endif

      irow=MOD(INT(((i-1)/scal%nbl)+TOL_SMALL),scal%nprow)
      if(irow.ne.scal%myprow) cycle
      
      vc = vcoul(i)

!-------------------------
! Actually Construct eps

      do j=1,pol%nmtx

!            if (peinf%inode .eq. 0) then
!              write(6,*) 'Starting loop', i, j, pol%nmtx
!            endif

        icol=MOD(INT(((j-1)/scal%nbl)+TOL_SMALL),scal%npcol)
        if(icol .eq. scal%mypcol) then
          icurr=icurr+1
          irowm=INT((icurr-1)/scal%npc+TOL_SMALL)+1
          icolm=MOD((icurr-1),scal%npc)+1
          
          epsRDyn(:,irowm,icolm) = (0.0,0.0)
#ifdef CPLX
          if(pol%freq_dep.ne.3) then
            epsADyn(:,irowm,icolm) = (0.0,0.0)
          endif
#endif
          
          if (i.eq.j) then
            epsRDyn(:,irowm,icolm) = (1.0,0.0)
#ifdef CPLX
            if(pol%freq_dep.ne.3) then
              epsADyn(:,irowm,icolm) = (1.0,0.0)
            endif
#endif
          endif
          
          chiRDyntmp(:) = pol%chiRDyn(:,irowm,icolm,1)
#ifdef CPLX
          if(pol%freq_dep.ne.3) then
            chiADyntmp(:) = pol%chiADyn(:,irowm,icolm,1)
          endif
#endif

!              if (.not.is_q0 .or. pol%icutv .ne. 0) then
          epsRDyn(:,irowm,icolm) = epsRDyn(:,irowm,icolm)- &
            vc*chiRDyntmp(:)
#ifdef CPLX
          if(pol%freq_dep.ne.3) then
            epsADyn(:,irowm,icolm) = epsADyn(:,irowm,icolm)- &
              vc*chiADyntmp(:)
          endif
#endif
!              else
!                if (i .eq. 1 .and. j .eq. 1) then
!                  epsRDyn(:,irowm,icolm) = epsRDyn(:,irowm,icolm)- &
!                   vc*chiRDyntmp(:)*q0norm*q0norm
!#ifdef CPLX
!                  epsADyn(:,irowm,icolm) = epsADyn(:,irowm,icolm)- &
!                   vc*chiADyntmp(:)*q0norm*q0norm
!#endif
!                else if (i .eq. 1 .or. j .eq. 1) then
!                  epsRDyn(:,irowm,icolm) = epsRDyn(:,irowm,icolm)- &
!                   vc*chiRDyntmp(:)*q0norm
!#ifdef CPLX
!                  epsADyn(:,irowm,icolm) = epsADyn(:,irowm,icolm)- &
!                   vc*chiADyntmp(:)*q0norm
!#endif
!                else
!                  epsRDyn(:,irowm,icolm) = epsRDyn(:,irowm,icolm)- &
!                   vc*chiRDyntmp(:)
!#ifdef CPLX
!                  epsADyn(:,irowm,icolm) = epsADyn(:,irowm,icolm)- &
!                   vc*chiADyntmp(:)
!#endif
!                end if
!              endif
        endif
      end do
    end do
  endif

!      write(6,*) 'Created Eps'


!------------- Take Care of the Wings for q--> 0 -------------------------
!
! JRD: This section was removed and deleted (rev 184)
! because we now invert the matrix completely (i.e. wings included)
!
! End treatment of wings for q--> 0
!----------------------------------------------------------------------------


3999 format(a,i6,a,2es25.15e3)
  if (peinf%inode .eq. 0 .and. pol%freq_dep .eq. 0) then
    write(6,3999) 'q-pt ', iq, ': Head of Epsilon         = ', eps(1,1)
  end if
  if (peinf%inode .eq. 0 .and. pol%freq_dep .eq. 2) then
    write(6,3999) 'q-pt ', iq, ': Retarded Head of Epsilon         = ', epsRDyn(1,1,1)
    write(6,3999) 'q-pt ', iq, ': Retarded Epsilon(2,2)            = ', epsRDyn(1,2,2)
#ifdef CPLX
    write(6,3999) 'q-pt ', iq, ': Advanced Head of Epsilon         = ', epsADyn(1,1,1)
    write(6,3999) 'q-pt ', iq, ': Advanced Epsilon(2,2)            = ', epsADyn(1,2,2)
#endif
  if (peinf%inode .eq. 0 .and. pol%freq_dep .eq. 3) then
    write(6,3999) 'q-pt ', iq, ': Head of Epsilon         = ', epsRDyn(1,1,1)
    write(6,3999) 'q-pt ', iq, ': Epsilon(2,2)            = ', epsRDyn(1,2,2)
  endif

  end if

!-------------------------------------------------------------
! Print head versus frequency 


  if(pol%os_para_freqs .eq. 1 .and. peinf%rank_f .eq. 0 .and. pol%freq_dep .eq. 2) then

    SAFE_ALLOCATE(epsRDyn_head, (pol%nfreq))
    epsRDyn_head=CMPLX(0d0,0d0)
#ifdef CPLX
    SAFE_ALLOCATE(epsADyn_head, (pol%nfreq))
    epsADyn_head=CMPLX(0d0,0d0)
#endif

    epsRDyn_head(:)=epsRDyn(:,1,1)
#ifdef CPLX
    epsADyn_head(:)=epsADyn(:,1,1)
#endif

  elseif(pol%os_para_freqs > 1 .and. peinf%rank_f .eq. 0 .and. pol%freq_dep .eq. 2) then
    SAFE_ALLOCATE(epsRDyn_head, (pol%nfreq))
    SAFE_ALLOCATE(epsRDyn_head_temp, (pol%nfreq))
    epsRDyn_head=CMPLX(0d0,0d0)
    epsRDyn_head_temp=CMPLX(0d0,0d0)
#ifdef CPLX
    SAFE_ALLOCATE(epsADyn_head, (pol%nfreq))
    SAFE_ALLOCATE(epsADyn_head_temp, (pol%nfreq))
    epsADyn_head=CMPLX(0d0,0d0)
    epsADyn_head_temp=CMPLX(0d0,0d0)
#endif
    do ifreq=1,pol%nfreq
      freq_grp_ind=mod(ifreq-1,pol%os_para_freqs)
      ifreq_para=(ifreq+pol%os_para_freqs-1)/pol%os_para_freqs
      if(freq_grp_ind .eq. peinf%rank_mtxel) then
        epsRDyn_head_temp(ifreq)=epsRDyn(ifreq_para,1,1)
#ifdef CPLX
        epsADyn_head_temp(ifreq)=epsADyn(ifreq_para,1,1)
#endif
      endif
    enddo
#ifdef MPI
    call MPI_REDUCE(epsRDyn_head_temp(1),epsRDyn_head(1),pol%nfreq,MPI_COMPLEX_DPC,MPI_SUM, 0, &
     peinf%mtxel_comm,mpierr)
#ifdef CPLX
    call MPI_REDUCE(epsADyn_head_temp(1),epsADyn_head(1),pol%nfreq,MPI_COMPLEX_DPC,MPI_SUM, 0, &
     peinf%mtxel_comm,mpierr)
#endif
#endif
  endif

  if (peinf%rank_mtxel .eq. 0 .and. peinf%rank_f .eq. 0 .and. pol%freq_dep .eq. 2) then
    write(52,'("# q= ",3f12.5," nmtx=",i6)') q0(:),pol%nmtx
    write(52,*)
    do jj=1,pol%nfreq
      write(52,'(5f12.6)') pol%dFreqGrid(jj), &
        dble(epsRDyn_head(jj)),aimag(epsRDyn_head(jj) &
#ifdef CPLX
        ), dble(epsADyn_head(jj)),aimag(epsADyn_head(jj) &
#endif
        )
    enddo
  endif

!------------ Here we invert the epsilon matrix -----------------------------
!
! JRD: May 2008.  Now we actually invert the whole matrix with wings included.

  if(peinf%inode.eq.0) call timacc(46,1)

#if defined USESCALAPACK

  if(pol%freq_dep .eq. 0) then
    call X(invert_with_scalapack)(pol%nmtx, scal, eps)
  endif
  
  if(pol%freq_dep .eq. 2 .or. pol%freq_dep .eq. 3) then
    do jj=1,pol%os_nfreq_para
      eps1Aux(:,:) = epsRDyn(jj,:,:)
      call zinvert_with_scalapack(pol%nmtx, scal, eps1Aux)
      epsRDyn(jj,:,:) = eps1Aux(:,:)
#ifdef CPLX
      if(pol%freq_dep .ne. 3) then
        eps1Aux(:,:) = epsADyn(jj,:,:)
        call zinvert_with_scalapack(pol%nmtx, scal, eps1Aux)
        epsADyn(jj,:,:) = eps1Aux(:,:)
      endif
#endif
    enddo
  endif

#else

! Serial Version

  if(pol%freq_dep .eq. 0) then
    call X(invert_serial)(pol%nmtx,eps)
  endif
  
  if(pol%freq_dep .eq. 2 .or. pol%freq_dep .eq. 3) then
    do jj=1,pol%os_nfreq_para
      eps1Aux(:,:) = epsRDyn(jj,:,:)
      call zinvert_serial(pol%nmtx,eps1Aux)
      epsRDyn(jj,:,:) = eps1Aux(:,:)
#ifdef CPLX
      if( pol%freq_dep .ne. 3) then
        eps1Aux(:,:) = epsADyn(jj,:,:)
        call zinvert_serial(pol%nmtx,eps1Aux)
        epsADyn(jj,:,:) = eps1Aux(:,:)
      endif
#endif
    enddo
  endif

#endif

  if(peinf%inode.eq.0) call timacc(46,2)

! Done inverting
!-----------------------------------------------------------------------------


  if (peinf%inode .eq. 0 .and. pol%freq_dep .eq. 0) then
    write(6,3999) 'q-pt ', iq, ': Head of Epsilon Inverse = ', eps(1,1)
  end if
  if (peinf%inode .eq. 0 .and. pol%freq_dep .eq. 2) then
    write(6,3999) 'q-pt ', iq, ': Retarded Head of Epsilon Inverse = ', epsRDyn(1,1,1)
#ifdef CPLX
    write(6,3999) 'q-pt ', iq, ': Advanced Head of Epsilon Inverse = ', epsADyn(1,1,1)
#endif
    write(6,3999) 'q-pt ', iq, ': Retarded Epsilon Inverse(2,2)    = ', epsRDyn(1,2,2)
#ifdef CPLX
    write(6,3999) 'q-pt ', iq, ': Advanced Epsilon Inverse(2,2)    = ', epsADyn(1,2,2)
#endif
  end if
  if (peinf%inode .eq. 0 .and. pol%freq_dep .eq. 3) then
    write(6,3999) 'q-pt ', iq, ': Head of Epsilon Inverse = ', epsRDyn(1,1,1)
    write(6,3999) 'q-pt ', iq, ': Epsilon Inverse(2,2)    = ', epsRDyn(1,2,2)
  endif

!--------  put in the effects of the wings  for  q--> 0 ----------------------
!
! JRD: We don`t do this anymore because we now invert entire matrix (wings included)
!
!--------end treatment of the wings  for  q--> 0 -----------------------------


!----------- Print out independent matrix elements ---------------------------

  if(pol%os_para_freqs .eq. 1 .and. peinf%rank_f .eq. 0 .and. pol%freq_dep .eq. 2) then

    epsRDyn_head(:)=epsRDyn(:,1,1)
#ifdef CPLX
    epsADyn_head(:)=epsADyn(:,1,1)
#endif

  elseif(pol%os_para_freqs > 1 .and. peinf%rank_f .eq. 0 .and. pol%freq_dep .eq. 2) then
    epsRDyn_head=CMPLX(0d0,0d0)
    epsRDyn_head_temp=CMPLX(0d0,0d0)
#ifdef CPLX
    epsADyn_head=CMPLX(0d0,0d0)
    epsADyn_head_temp=CMPLX(0d0,0d0)
#endif
    do ifreq=1,pol%nfreq
      freq_grp_ind=mod(ifreq-1,pol%os_para_freqs)
      ifreq_para=(ifreq+pol%os_para_freqs-1)/pol%os_para_freqs
      if(freq_grp_ind .eq. peinf%rank_mtxel) then
        epsRDyn_head_temp(ifreq)=epsRDyn(ifreq_para,1,1)
#ifdef CPLX
        epsADyn_head_temp(ifreq)=epsADyn(ifreq_para,1,1)
#endif
      endif
    enddo
#ifdef MPI
    call MPI_REDUCE(epsRDyn_head_temp(1),epsRDyn_head(1),pol%nfreq,MPI_COMPLEX_DPC,MPI_SUM, 0, &
     peinf%mtxel_comm,mpierr)
#ifdef CPLX
    call MPI_REDUCE(epsADyn_head_temp(1),epsADyn_head(1),pol%nfreq,MPI_COMPLEX_DPC,MPI_SUM, 0, &
     peinf%mtxel_comm,mpierr)
#endif
#endif
  endif

  if (peinf%inode.eq.0.and.pol%freq_dep .eq. 2) then
    write(51,'("# q= ",3f12.5," nmtx=",i6)') q0(:),pol%nmtx
    write(51,*)
    do jj=1,pol%nfreq
      write(51,'(5f12.6)') pol%dFreqGrid(jj), &
        dble(epsRDyn_head(jj)),aimag(epsRDyn_head(jj) &
#ifdef CPLX
        ), dble(epsADyn_head(jj)),aimag(epsADyn_head(jj) &
#endif
        )
    enddo
  endif

!      if (pol%freq_dep .eq. 0) then
  if (peinf%inode.eq.0 .and. pol%freq_dep .eq. 0) then
  
    ! JRD Warn User about possible lack of symmetry
    if (is_q0) then
      write(7,*)
      write(7,*) 'For q0 points, you should check the symmetry (eps(G,G'') = eps*(-G,-G'')) by'
      write(7,*) 'using the eps0sym code. Wavefunction convergence, as well as a finite q-shift'
      write(7,*) 'may cause this property of eps(G,G'') to be broken.'
      write(6,*)
      write(6,*) 'For q0 points, you should check the symmetry (eps(G,G'') = eps*(-G,-G'')) by'
      write(6,*) 'using the eps0sym code. Wavefunction convergence, as well as a finite q-shift'
      write(6,*) 'may cause this property of eps(G,G'') to be broken.'
    endif
    
    write(7,4000) kp%nspin
    do i=1,scal%npr
      is=scal%isrtxrow(i)
      do j=1,scal%npc
        js=scal%isrtxcol(j)
        if (i .eq. j .or. i .eq. j+1) then
          write(7,4200) gvec%components(1:3,is), gvec%components(1:3,js), eps(i,j)
        endif
      end do
    end do
  end if

  if (peinf%inode.eq.0 .and. pol%freq_dep .eq. 2) then
    write(7,4001) kp%nspin
    do jj=1,pol%os_nfreq_para
      do i=1,scal%npr
        is=scal%isrtxrow(i)
        do j=1,scal%npc
          js=scal%isrtxcol(j)
          if (i .eq. j .or. i .eq. j+1) then
            write(7,4300) gvec%components(1:3,is), gvec%components(1:3,js), epsRDyn(jj,i,j &
#ifdef CPLX
              ),epsADyn(jj,i,j)
#else
            )
#endif
          endif
        end do
      end do
    end do
  end if

  if (peinf%inode.eq.0 .and. pol%freq_dep .eq. 3) then
    write(7,4000) kp%nspin
    do jj=1,pol%os_nfreq_para
      do i=1,scal%npr
        is=scal%isrtxrow(i)
        do j=1,scal%npc
          js=scal%isrtxcol(j)
          if (i .eq. j .or. i .eq. j+1) then
            write(7,4200) gvec%components(1:3,is), gvec%components(1:3,js), epsRDyn(jj,i,j)
          endif
        end do
      end do
    end do
  end if


4000 format(/ /,13x,'g',19x,'gp',9x, &
       'inverse epsilon           nspin= ',1i1)
4001 format(/ /,13x,'g',19x,'gp',9x, &
#ifdef CPLX
       'inverse epsilon RDyn/ADyn nspin= ',1i1)
#else
  'inverse epsilon RDyn      nspin= ',1i1)
#endif

4200 format(5x,3i5,5x,3i5,5x,2f13.8)
4300 format(5x,3i5,5x,3i5,5x,4f13.8)

!---------- Full-Frequency Sum-Rule -----------------------------------------

  epssum1R=0D0
  epssum2R=0D0

#ifdef CPLX
  epssum1A=0D0
  epssum2A=0D0
#endif
  
  if (peinf%inode.eq.0 .and. pol%freq_dep .eq. 2) then
    do jj=2,pol%nFreq
      
      epssum1R=epssum1R+(1D0*Ryd/pol%dFreqGrid(jj))* &
        IMAG(epsRDyn_head(jj))*(pol%dFreqGrid(jj)-pol%dFreqGrid(jj-1))/Ryd
#ifdef CPLX
      epssum1A=epssum1A+(1D0*Ryd/pol%dFreqGrid(jj))* &
        IMAG(epsADyn_head(jj))*(pol%dFreqGrid(jj)-pol%dFreqGrid(jj-1))/Ryd
#endif
      
      epssum2R=epssum2R+(pol%dFreqGrid(jj)/Ryd)* &
        IMAG(epsRDyn_head(jj))*(pol%dFreqGrid(jj)-pol%dFreqGrid(jj-1))/Ryd
#ifdef CPLX
      epssum2A=epssum2A+(pol%dFreqGrid(jj)/Ryd)* &
        IMAG(epsADyn_head(jj))*(pol%dFreqGrid(jj)-pol%dFreqGrid(jj-1))/Ryd
#endif
    enddo
    
    epssum1R=(2D0*epssum1R/Pi_D)+1D0
    epssum1R_rel=(epssum1R)/dble(epsRDyn(1,1,1))
    
#ifdef CPLX
    epssum1A=(-2D0*epssum1A/Pi_D)+1D0
    epssum1A_rel=(epssum1A)/dble(epsADyn(1,1,1))
#endif

    epssum2R_rel=(-1D0*epssum2R)/((Pi_D/2D0)*omega_plasma**2)
#ifdef CPLX
    epssum2A_rel=(epssum2A)/((Pi_D/2D0)*omega_plasma**2)
#endif
    
! Ref: Hybertsen & Louie PRB 34, 5390 (1986), eq. 29 and Appendix A
    write(6,*) ' '
    write(6,*) 'Full Frequency: Sum rules for head:'
    write(6,*) 'Retarded Int((1/w)*Im(eps^-1(w))) =', epssum1R_rel*100D0, ' % of exact'
#ifdef CPLX
    write(6,*) 'Advanced Int((1/w)*Im(eps^-1(w))) =', epssum1A_rel*100D0, ' % of exact'
#endif
    write(6,*) 'Retarded Int((w)*Im(eps^-1(w))) =', epssum2R_rel*100D0, ' % of exact'
#ifdef CPLX
    write(6,*) 'Advanced Int((w)*Im(eps^-1(w))) =', epssum2A_rel*100D0, ' % of exact'
#endif
  endif


!---------- Write inverse dielectric matrices to file -----------------------

  if(peinf%inode.eq.0) call timacc(45,1)
  
  if (is_q0) then
    filename = 'eps0mat.h5'
  else
    filename = 'epsmat.h5'
  endif

#ifdef HDF5
  if (pol%use_hdf5) then
    my_iq = iq
    ! If this is not a q->0 point, write to (iq-nq0) q-point
    if (.not.is_q0) my_iq = iq - pol%nq0
    if (peinf%inode .eq. 0) then
      call write_gvec_indices_hdf(gvec%ng,pol%isrtx,isorti,ekin,my_iq,filename)
    endif

! JRD: Write diagonal elements of Matrix

    if (pol%freq_dep .ne. 2) then 
      isize=SCALARSIZE
    else
      isize=2
    endif

    SAFE_ALLOCATE(epsdiag,(isize,pol%nmtx,1))
    epsdiag=0D0

#ifdef USESCALAPACK
    SAFE_ALLOCATE(epsdiagt,(isize,pol%nmtx,1))
    epsdiagt=0D0
    do jj = 1, pol%nmtx
      icol=MOD(INT(((jj-1)/scal%nbl)+TOL_SMALL),scal%npcol)
      if (icol .eq. scal%mypcol) then
        ii = jj
        irow=MOD(INT(((ii-1)/scal%nbl)+TOL_SMALL),scal%nprow)
        if (irow .eq. scal%myprow) then
          if (pol%freq_dep .ne. 2) then
            epsdiagt(1,jj,1)=dble(eps(scal%imyrowinv(jj),scal%imycolinv(jj)))
#ifdef CPLX
            epsdiagt(2,jj,1)=IMAG(eps(scal%imyrowinv(jj),scal%imycolinv(jj)))
#endif
          else
            epsdiagt(1,jj,1)=dble(epsRDyn(1,scal%imyrowinv(jj),scal%imycolinv(jj)))
            epsdiagt(2,jj,1)=IMAG(epsRDyn(1,scal%imyrowinv(jj),scal%imycolinv(jj)))
          endif
        endif
      endif
    enddo
    call MPI_reduce(epsdiagt,epsdiag,pol%nmtx,MPI_SCALAR,MPI_SUM,0,MPI_COMM_WORLD,mpierr)
    SAFE_DEALLOCATE(epsdiagt)
#else
    if (peinf%inode .eq. 0) then
      do jj = 1, pol%nmtx
        if (pol%freq_dep .ne. 2) then
          epsdiag(1,jj,1) = dble(eps(jj,jj))
#ifdef CPLX
          epsdiag(2,jj,1) = IMAG(eps(jj,jj))
#endif
        else
          epsdiag(1,jj,1) = dble(epsRDyn(1,jj,jj))
          epsdiag(2,jj,1) = IMAG(epsRDyn(2,jj,jj))
        endif
      enddo
    endif    
#endif

    if (peinf%inode .eq. 0) then
      call write_matrix_diagonal_hdf(epsdiag,pol%nmtx,my_iq,isize,filename)
    endif
    SAFE_DEALLOCATE(epsdiag)

  else
#endif
    iunit=13
    if (is_q0) iunit=12
    if (peinf%inode .eq. 0) then
      write(iunit) gvec%ng,pol%nmtx, &
        (pol%isrtx(i),isorti(i),i=1,gvec%ng)
      write(iunit) (ekin(i),i=1,gvec%ng)
      write(iunit) (q0(i),i=1,3)
    endif
#ifdef HDF5
  endif
#endif

  if (pol%freq_dep .eq. 0) then
#ifdef HDF5
    if (pol%use_hdf5) then
#ifdef USESCALAPACK
      call write_matrix_d_par_hdf(scal,eps,pol%nmtx,my_iq,1,filename)
#else
      call write_matrix_d_hdf(scal,eps,pol%nmtx,my_iq,1,filename)
#endif
    else
#endif
      call write_matrix_d(scal,eps,pol%nmtx,iunit)
#ifdef HDF5
    endif
#endif
  endif
  
  if(pol%freq_dep .eq. 2) then
#ifdef HDF5
    if (pol%use_hdf5) then
#ifdef USESCALAPACK
      call write_matrix_f_par_hdf(scal,pol%nFreq,epsRDyn,ONLYIFCPLX(epsADyn)pol%nmtx,my_iq,1,filename)
#else
      call write_matrix_f_hdf(scal,pol%nFreq,epsRDyn,ONLYIFCPLX(epsADyn)pol%nmtx,my_iq,1,filename)
#endif
    else
#endif
      call write_matrix_f(scal,pol%nFreq,epsRDyn,ONLYIFCPLX(epsADyn)pol%nmtx,iunit,pol%os_para_freqs)
#ifdef HDF5
    endif
#endif
  endif

  if(pol%freq_dep .eq. 3) then
#ifdef HDF5
    if (pol%use_hdf5) then
#ifdef USESCALAPACK
      call write_matrix_f_par_hdf(scal,pol%nFreq,epsRDyn,ONLYIFCPLX(epsRDyn)pol%nmtx,my_iq,1,filename)
#else
      call write_matrix_f_hdf(scal,pol%nFreq,epsRDyn,ONLYIFCPLX(epsRDyn)pol%nmtx,my_iq,1,filename)
#endif
    else
#endif
      call write_matrix_f(scal,pol%nFreq,epsRDyn,ONLYIFCPLX(epsRDyn)pol%nmtx,iunit,pol%os_para_freqs)
#ifdef HDF5
    endif
#endif
  endif

  if(peinf%inode.eq.0) call timacc(45,2)

! Finished writing eps
!------------------------------------------------------------------------


  SAFE_DEALLOCATE(vcoul)
  SAFE_DEALLOCATE(isorti)
  
  if(pol%freq_dep .eq. 0) then
    SAFE_DEALLOCATE(eps)
    SAFE_DEALLOCATE(ewng)
  endif
  
  if(pol%freq_dep .eq. 2) then
    SAFE_DEALLOCATE(chiRDyntmp)
    SAFE_DEALLOCATE(epsRDyn)
#ifdef CPLX
    SAFE_DEALLOCATE(chiADyntmp)
    SAFE_DEALLOCATE(epsADyn)
#endif
    SAFE_DEALLOCATE(eps1Aux)
  endif

  if(pol%freq_dep .eq. 3) then
    SAFE_DEALLOCATE(chiRDyntmp)
    SAFE_DEALLOCATE(epsRDyn)
    SAFE_DEALLOCATE(eps1Aux)
  endif
  
  
  POP_SUB(epsinv)
  
  return
end subroutine epsinv
