!============================================================================
!
! (1) read_eps_grid_sizes_hdf5
!
!============================================================================

#include "f_defs.h"

module epsread_hdf5_m
#ifdef HDF5

  use global_m
  use hdf5
  implicit none

  private

  public :: &
    read_eps_grid_sizes_hdf5, &
    read_eps_matrix_diagonal_hdf5, &
    read_eps_qgrid_hdf5, &
    read_eps_freqgrid_hdf5, &
    read_eps_old_gvecs_hdf5, &
    read_eps_gvecsofq_hdf5, &
    read_eps_matrix_col_f_hdf5, &
    read_eps_matrix_col_hdf5, &
    read_eps_matrix_ser_hdf5, &
    read_eps_matrix_par_hdf5, &
    read_eps_matrix_par_f_hdf5

contains

subroutine read_eps_grid_sizes_hdf5(nold,nq,gmax_in,nFreq,nmtxmax,qgrid,name)
  integer, intent(out) :: nold
  integer, intent(out) :: nq
  real(DP), intent(out) :: gmax_in
  integer, intent(out) :: nFreq
  integer, intent(out) :: nmtxmax
  integer, intent(out) :: qgrid(3)
  character(len=*), intent(in) :: name

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: info_id       ! Property list identifier
  integer(HID_T) :: infospace     ! Property list identifier
  integer :: error,complexflag
  integer :: imetadata(9)
  real(DP) :: dmetadata(1)
  integer(HSIZE_T) :: imetacount(1), dmetacount(1)

  PUSH_SUB(read_eps_grid_sizes_hdf5)

  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)
  call h5dopen_f(file_id, 'intinfo', info_id, error)
  call h5dget_space_f(info_id,infospace,error)

  imetacount(1) = 9

  call h5dread_f(info_id, H5T_NATIVE_INTEGER, imetadata, imetacount, error)

  complexflag = imetadata(1)
  nq = imetadata(2)
  nFreq = imetadata(4)
  nold = imetadata(5)
  nmtxmax = imetadata(6)
  qgrid(1) = imetadata(7)
  qgrid(2) = imetadata(8)
  qgrid(3) = imetadata(9)

#ifdef CPLX
  if (complexflag .eq. 0) call die("Using real epsilon in complex code")
#else
  if (complexflag .eq. 1) call die("Using complex epsilon in real code")
#endif

  call h5sclose_f(infospace,error)
  call h5dclose_f(info_id,error)

  call h5dopen_f(file_id, 'dblinfo', info_id, error)
  call h5dget_space_f(info_id,infospace,error)

  dmetacount(1) = 1

  call h5dread_f(info_id, H5T_NATIVE_DOUBLE, dmetadata, dmetacount, error)

  gmax_in = dmetadata(1)

  call h5sclose_f(infospace,error)
  call h5dclose_f(info_id,error)
  call h5fclose_f(file_id,error)

  POP_SUB(read_eps_grid_sizes_hdf5)

end subroutine read_eps_grid_sizes_hdf5

!====================================================================================

subroutine read_eps_matrix_diagonal_hdf5(nmtx, isize, iq, epsdiag, name)
  integer, intent(in) :: nmtx
  integer, intent(in) :: isize
  integer, intent(in) :: iq
  real(DP), intent(out) :: epsdiag(:,:,:) !< (isize,nmtx,1)
  character(len=*), intent(in) :: name

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: data_id       ! Property list identifier
  integer(HID_T) :: dataspace        ! Property list identifier
  integer(HID_T) :: memspace        ! Property list identifier
  integer :: error, rank
  integer(HSIZE_T) :: ranks(3), offset(3)

  PUSH_SUB(read_eps_matrix_diagonal_hdf5)

  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)
  call h5dopen_f(file_id, 'matrix-diagonal', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  rank = 3
  ranks(1) = isize
  ranks(2) = nmtx
  ranks(3) = 1

  call h5screate_simple_f(rank, ranks, memspace, error)

  offset(1)=0
  offset(2)=0
  offset(3)=iq-1

! Select hyperslab

  call h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F, offset, ranks, error)

  call h5dread_f(data_id, H5T_NATIVE_DOUBLE, epsdiag, ranks, error, memspace, dataspace)

  call h5sclose_f(dataspace,error)
  call h5dclose_f(data_id,error)
  call h5fclose_f(file_id,error)

  POP_SUB(read_eps_matrix_diagonal_hdf5)

end subroutine read_eps_matrix_diagonal_hdf5

!====================================================================================

subroutine read_eps_qgrid_hdf5(nq,q,nmtx_of_q,name)
  integer, intent(in) :: nq
  real(DP), intent(inout) :: q(:,:) !< (3,nq)
  integer, intent(out) :: nmtx_of_q(:) !< (nq)
  character(len=*), intent(in) :: name

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: data_id       ! Property list identifier
  integer(HID_T) :: dataspace        ! Property list identifier
  integer :: error
  integer(HSIZE_T) :: ranks(2), nmranks(1)

  PUSH_SUB(read_eps_qgrid_hdf5)

  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)
  call h5dopen_f(file_id, 'qpoints', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  ranks(1) = 3
  ranks(2) = nq

  call h5dread_f(data_id, H5T_NATIVE_DOUBLE, q, ranks, error)

  call h5sclose_f(dataspace,error)
  call h5dclose_f(data_id,error)

  call h5dopen_f(file_id, 'nmtx-of-q', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  nmranks(1) = nq

  call h5dread_f(data_id, H5T_NATIVE_INTEGER, nmtx_of_q, nmranks, error)

  call h5sclose_f(dataspace,error)
  call h5dclose_f(data_id,error)
  call h5fclose_f(file_id,error)

  POP_SUB(read_eps_qgrid_hdf5)

end subroutine read_eps_qgrid_hdf5

!===================================================================================

subroutine read_eps_freqgrid_hdf5(nFreq,dFreqGrid,dFreqBrd,name)
  integer, intent(in) :: nFreq
  real(DP), intent(out) :: dFreqGrid(:) !< (nFreq)
  complex(DPC), intent(out) :: dFreqBrd(:) !< (nFreq)
  character(len=*), intent(in) :: name

  real(DP), allocatable :: tmp(:,:)

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: data_id       ! Property list identifier
  integer(HID_T) :: dataspace        ! Property list identifier
  integer :: error
  integer(HSIZE_T) :: ranks(1),branks(2)

  PUSH_SUB(read_eps_freqgrid_hdf5)

  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)

  call h5dopen_f(file_id, 'freqs', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  ranks(1) = nFreq

  call h5dread_f(data_id, H5T_NATIVE_DOUBLE, dFreqGrid, ranks, error)

  call h5sclose_f(dataspace,error)
  call h5dclose_f(data_id,error)

  call h5dopen_f(file_id, 'freqbrds', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  branks(1) = 2
  branks(2) = nFreq

  SAFE_ALLOCATE(tmp,(2,nFreq))

  call h5dread_f(data_id, H5T_NATIVE_DOUBLE, tmp, branks, error)

  dFreqBrd(:) = CMPLX(tmp(1,:),tmp(2,:))

  call h5sclose_f(dataspace,error)
  call h5dclose_f(data_id,error)
  call h5fclose_f(file_id,error)

  SAFE_DEALLOCATE(tmp)

  POP_SUB(read_eps_freqgrid_hdf5)

end subroutine read_eps_freqgrid_hdf5

!=================================================================================

subroutine read_eps_old_gvecs_hdf5(nold,old,name)
  integer, intent(in) :: nold
  integer, intent(out) :: old(:,:) !< (3,nold)
  character(len=*), intent(in) :: name

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: data_id       ! Property list identifier
  integer(HID_T) :: dataspace        ! Property list identifier
  integer :: error
  integer(HSIZE_T) :: ranks(2)

  PUSH_SUB(read_eps_old_gvecs_hdf5)

  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)

  call h5dopen_f(file_id, 'gvecs', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  ranks(1) = 3
  ranks(2) = nold

  call h5dread_f(data_id, H5T_NATIVE_INTEGER, old, ranks, error)

  call h5sclose_f(dataspace,error)
  call h5dclose_f(data_id,error)
  call h5fclose_f(file_id,error)

  POP_SUB(read_eps_old_gvecs_hdf5)

end subroutine read_eps_old_gvecs_hdf5

!====================================================================================

subroutine read_eps_gvecsofq_hdf5(ngq,isrtold,isrtold_inv,ekold,iq,name)
  integer, intent(in) :: ngq
  integer, intent(out) :: isrtold(:) !< (ngq)
  integer, intent(out) :: isrtold_inv(:) !< (ngq)
  real(DP), intent(out) :: ekold(:) !< (ngq)
  integer, intent(in) :: iq
  character(len=*), intent(in) :: name

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: data_id       ! Property list identifier
  integer(HID_T) :: dataspace        ! Property list identifier
  integer(HID_T) :: memspace        ! Property list identifier
  integer :: idata(ngq,2,1)
  real(DP) :: data(ngq,1)
  integer :: error
  integer :: rank
  integer(HSIZE_T) :: count(2), offset(2)
  integer(HSIZE_T) :: icount(3), ioffset(3)

  PUSH_SUB(read_eps_gvecsofq_hdf5)

  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)

! READ ISRTOLD

  call h5dopen_f(file_id, 'q-gvec-index', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  rank = 3
  icount(1) = ngq
  icount(2) = 2
  icount(3) = 1

  call h5screate_simple_f(rank, icount, memspace, error)

! Construct data and offset

  ioffset(1)=0
  ioffset(2)=0
  ioffset(3)=iq-1

! Select hyperslab

  call h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F, ioffset, icount, error)

! Collectively read the file
! Serial for now

  call h5dread_f(data_id, H5T_NATIVE_INTEGER, idata, icount, error, memspace, dataspace)
  isrtold(:) = idata(:,1,1)
  isrtold_inv(:) = idata(:,2,1)

  call h5sclose_f(memspace, error)
  call h5sclose_f(dataspace, error)
  call h5dclose_f(data_id,error)

! READ EKOLD

  call h5dopen_f(file_id, 'q-gvec-ekin', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  rank = 2
  count(1) = ngq
  count(2) = 1

  call h5screate_simple_f(rank, count, memspace, error)

! Construct data and offset

  offset(1)=0
  offset(2)=iq-1

! Select hyperslab

  call h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F, offset, count, error)

! Collectively read the file
! Serial for now

  call h5dread_f(data_id, H5T_NATIVE_DOUBLE, data, count, error, memspace, dataspace)
  ekold(:) = data(:,1)

  call h5sclose_f(memspace, error)
  call h5sclose_f(dataspace, error)
  call h5dclose_f(data_id,error)
  
  call h5fclose_f(file_id,error)

  POP_SUB(read_eps_gvecsofq_hdf5)

end subroutine read_eps_gvecsofq_hdf5

!===========================================================================================

subroutine read_eps_matrix_col_f_hdf5(epsR,&
#ifdef CPLX 
   epsA,&
#endif
   nFreq,j,nmtx,iq,is,name)
  integer, intent(in) :: iq
  integer, intent(in) :: is
  integer, intent(in) :: nFreq
  integer, intent(in) :: nmtx
  integer, intent(in) :: j
  complex(DPC), intent(out) :: epsR(:,:) !< (nFreq,nmtx)
#ifdef CPLX
  complex(DPC), intent(out) :: epsA(:,:) !< (nFreq,nmtx)
#endif
  character(len=*), intent(in) :: name

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: data_id       ! Property list identifier
  integer(HID_T) :: dataspace        ! Property list identifier
  integer(HID_T) :: memspace        ! Property list identifier
  integer :: error, rank
  integer(HSIZE_T) :: count(6), offset(6)

  real(DP), allocatable :: data(:,:,:,:,:,:)

  PUSH_SUB(read_eps_matrix_col_f_hdf5)

  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)

  call h5dopen_f(file_id, 'matrix', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  rank = 6
  count(1) = 2
  count(2) = nFreq
  count(3) = nmtx
  count(4) = 1
  count(5) = SCALARSIZE
  count(6) = 1 !iq

  call h5screate_simple_f(rank, count, memspace, error)

  offset(:) = 0
  offset(4) = j - 1
  offset(5) = SCALARSIZE*(is-1)
  offset(6) = iq - 1

  call h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F, offset, count, error)

! XXX - this is bad because we double memory usage. Oh well.
  SAFE_ALLOCATE(data,(count(1),count(2),count(3),count(4),count(5),count(6)))
  call h5dread_f(data_id, H5T_NATIVE_DOUBLE, data, count, error, memspace, dataspace)
  epsR(1:nFreq,1:nmtx) = CMPLX(data(1,1:nFreq,1:nmtx,1,1,1),data(2,1:nFreq,1:nmtx,1,1,1))
#ifdef CPLX
  epsA(1:nFreq,1:nmtx) = CMPLX(data(1,1:nFreq,1:nmtx,1,2,1),data(2,1:nFreq,1:nmtx,1,2,1))
#endif
  SAFE_DEALLOCATE(data)

  call h5sclose_f(memspace, error)
  call h5sclose_f(dataspace, error)
  call h5dclose_f(data_id,error)  
  call h5fclose_f(file_id,error)

  POP_SUB(read_eps_matrix_col_f_hdf5)

end subroutine read_eps_matrix_col_f_hdf5

!===========================================================================================

subroutine read_eps_matrix_col_hdf5(eps,j,nmtx,iq,is,name)
  integer, intent(in) :: iq
  integer, intent(in) :: is
  integer, intent(in) :: nmtx
  integer, intent(in) :: j
  SCALAR, intent(out) :: eps(:) !< (nmtx)
  character(len=*), intent(in) :: name

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: data_id       ! Property list identifier
  integer(HID_T) :: dataspace        ! Property list identifier
  integer(HID_T) :: memspace        ! Property list identifier
  integer :: error, rank
  integer(HSIZE_T) :: count(6), offset(6)

  real(DP), allocatable :: data(:,:,:,:,:,:)

  PUSH_SUB(read_eps_matrix_col_hdf5)

  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)

  call h5dopen_f(file_id, 'matrix', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  rank = 6
#ifdef CPLX
  count(1) = 2
#else
  count(1) = 1
#endif
  count(2) = 1
  count(3) = nmtx
  count(4) = 1
  count(5) = 1 !mat
  count(6) = 1 !iq

  call h5screate_simple_f(rank, count, memspace, error)

  offset(:) = 0
  offset(4) = j - 1
  offset(5) = is - 1
  offset(6) = iq - 1

  call h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F, offset, count, error)

! XXX - this is bad because we double memory usage. Oh well.
  SAFE_ALLOCATE(data,(count(1),count(2),count(3),count(4),count(5),count(6)))
  call h5dread_f(data_id, H5T_NATIVE_DOUBLE, data, count, error, memspace, dataspace)
!  write(6,*) 'About to die?', nmtx, data(1,1,:,1,1,1)
  eps(1:nmtx) = SCALARIFY2(data(1,1,1:nmtx,1,1,1),data(2,1,1:nmtx,1,1,1))
  SAFE_DEALLOCATE(data)

  call h5sclose_f(memspace, error)
  call h5sclose_f(dataspace, error)
  call h5dclose_f(data_id,error)  
  call h5fclose_f(file_id,error)

  POP_SUB(read_eps_matrix_col_hdf5)

end subroutine read_eps_matrix_col_hdf5

!===========================================================================================

subroutine read_eps_matrix_ser_hdf5(eps,nmtx,iq,is,name)
  integer, intent(in) :: iq
  integer, intent(in) :: is
  integer, intent(in) :: nmtx
  SCALAR, intent(out) :: eps(:,:) !< (nmtx,nmtx)
  character(len=*), intent(in) :: name

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: data_id       ! Property list identifier
  integer(HID_T) :: dataspace        ! Property list identifier
  integer(HID_T) :: memspace        ! Property list identifier
  integer :: error, rank
  integer(HSIZE_T) :: count(6), offset(6)

  real(DP), allocatable :: data(:,:,:,:,:,:)

  PUSH_SUB(read_eps_matrix_ser_hdf5)

  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)

  call h5dopen_f(file_id, 'matrix', data_id, error)
  call h5dget_space_f(data_id,dataspace,error)

  rank = 6
#ifdef CPLX
  count(1) = 2
#else
  count(1) = 1
#endif
  count(2) = 1
  count(3) = nmtx
  count(4) = nmtx
  count(5) = 1 !mat
  count(6) = 1 !iq

  call h5screate_simple_f(rank, count, memspace, error)

  offset(:) = 0
  offset(5) = is - 1
  offset(6) = iq - 1

  call h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F, offset, count, error)

! XXX - this is bad because we double memory usage. Oh well.
  SAFE_ALLOCATE(data,(count(1),count(2),count(3),count(4),count(5),count(6)))
  call h5dread_f(data_id, H5T_NATIVE_DOUBLE, data, count, error, memspace, dataspace)
  eps(1:nmtx,1:nmtx) = SCALARIFY2(data(1,1,1:nmtx,1:nmtx,1,1),data(2,1,1:nmtx,1:nmtx,1,1))
  SAFE_DEALLOCATE(data)

  call h5sclose_f(memspace, error)
  call h5sclose_f(dataspace, error)
  call h5dclose_f(data_id,error)  
  call h5fclose_f(file_id,error)

  POP_SUB(read_eps_matrix_ser_hdf5)

end subroutine read_eps_matrix_ser_hdf5

!===========================================================================================

subroutine read_eps_matrix_par_hdf5(eps,ngpown,&
   ngpown_max,inv_igp_index,nmtx,iq,is,name)
  SCALAR, intent(inout) :: eps(:,:) !< (neps,ngpown)
  integer, intent(in) :: ngpown
  integer, intent(in) :: ngpown_max
  integer, intent(in) :: inv_igp_index(:) !< (ngpown_max)
  integer, intent(in) :: nmtx
  integer, intent(in) :: iq
  integer, intent(in) :: is
  character(len=*), intent(in) :: name

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: data_id       ! Property list identifier
  integer(HID_T) :: plist_id       ! Property list identifier
  integer(HID_T) :: dataspace        ! Property list identifier
  integer(HID_T) :: memspace        ! Property list identifier
  integer :: error
  integer :: rank, comm, info
  integer(HSIZE_T) :: count(6), offset(6), countm(6)

  real(DP), allocatable :: data(:,:,:,:,:,:)

  integer ijk, my_igp

  PUSH_SUB(read_eps_matrix_par_hdf5)

  !write(6,*) "In par read", ngpown, ngpown_max, nmtx, ubound(eps, 1), iq

  !if (ngpown .ne. 0) then
#ifdef CPLX
    SAFE_ALLOCATE(data,(2,1,nmtx,1,1,1))
    !SAFE_ALLOCATE(data,(2,1,nmtx,ngpown,1,1))
#else
    SAFE_ALLOCATE(data,(1,1,nmtx,1,1,1))
    !SAFE_ALLOCATE(data,(1,1,nmtx,ngpown,1,1))
#endif
  !else
  !  SAFE_ALLOCATE(data,(1,1,1,1,1,1))
  !endif

#ifdef MPI
  comm = MPI_COMM_WORLD
  info = MPI_INFO_NULL

  call h5pcreate_f(H5P_FILE_ACCESS_F, plist_id, error)
  call h5pset_fapl_mpio_f(plist_id, comm, info, error)
  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error, access_prp = plist_id)
  call h5pclose_f(plist_id,error)
#else
  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)
#endif


  do ijk = 1, ngpown_max

    my_igp = 0
    !if (ngpown .ne. 0) my_igp = inv_igp_index(1)
    if (ngpown .ne. 0) my_igp = inv_igp_index(ijk)

    call h5dopen_f(file_id, 'matrix', data_id, error)
    call h5dget_space_f(data_id,dataspace,error)

    rank = 6

! JRD: The commented code in this routine represents efforts to use a single HDF5 read call
! with an appropriate block and stride for each proc. In general, it currently appears to 
! perform worse (though this may be related to size of matrix. So, it is commented until
! further investigation.

    countm(1) = SCALARSIZE
    countm(2) = 1
    countm(3) = nmtx
    countm(4) = 1
    !countm(4) = ngpown
    countm(5) = 1
    countm(6) = 1

    call h5screate_simple_f(rank, countm, memspace, error)

    count(1) = SCALARSIZE
    !count(1) = 1
    count(2) = 1
    count(3) = nmtx
    !count(3) = 1
    count(4) = 1
    !count(4) = ngpown
    count(5) = 1
    count(6) = 1

! Construct data and offset

    if (ijk .le. ngpown .and. my_igp .le. nmtx) then
    !if (ngpown .ne. 0 .and. my_igp .le. nmtx) then

      offset(1)=0
      offset(2)=0
      offset(3)=0
      offset(4)=my_igp-1
      offset(5)=is-1
      offset(6)=iq-1

!      stride(1)=1
!      stride(2)=1
!      stride(3)=1
!      stride(4)=nprocs
!      stride(5)=1
!      stride(6)=1

!      block(1)=SCALARSIZE
!      block(2)=1
!      block(3)=nmtx
!      block(4)=1
!      block(5)=1
!      block(6)=1

! Select hyperslab

      call h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F, offset, count, error)
!      call h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F, offset, count, error, stride, block)

    else

      call H5sselect_none_f(memspace,error);
      call H5sselect_none_f(dataspace,error);

    endif

! Create property list for collective dataset read

#ifdef MPI
    call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, error)
    call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, error)

! Collectively read the file

    call h5dread_f(data_id, H5T_NATIVE_DOUBLE, data, countm, error, memspace, dataspace, &
                      xfer_prp = plist_id)
# else
    call h5dread_f(data_id, H5T_NATIVE_DOUBLE, data, countm, error, memspace, dataspace)
#endif

    if (ijk .le. ngpown .and. my_igp .le. nmtx) then
!    if (ngpown .ne. 0 .and. my_igp .le. nmtx) then
!XXX PROBABLY NEED THREADED LOOP HERE
      eps(1:nmtx,ijk) = SCALARIFY2(data(1,1,1:nmtx,1,1,1),data(2,1,1:nmtx,1,1,1))
!      eps(1:nmtx,1:ngpown) = SCALARIFY2(data(1,1,1:nmtx,1:ngpown,1,1),data(2,1,1:nmtx,1:ngpown,1,1))
    endif

    call h5sclose_f(memspace, error)
    call h5sclose_f(dataspace, error)
    call h5dclose_f(data_id, error)

  enddo

  call h5fclose_f(file_id,error)

  SAFE_DEALLOCATE(data)

  POP_SUB(read_eps_matrix_par_hdf5)

end subroutine read_eps_matrix_par_hdf5

!==========================================================================================

subroutine read_eps_matrix_par_f_hdf5(epsR, &
#ifdef CPLX
  epsA, &
#endif
  ngpown,ngpown_max,inv_igp_index,nmtx,nFreq,iq,is,name)
  complex(DPC), intent(inout) :: epsR(:,:,:) !< (nFreq,neps,ngpown)
#ifdef CPLX
  complex(DPC), intent(inout) :: epsA(:,:,:) !< (nFreq,neps,ngpown)
#endif
  integer, intent(in) :: ngpown
  integer, intent(in) :: ngpown_max
  integer, intent(in) :: inv_igp_index(:) !< (ngpown_max)
  integer, intent(in) :: nmtx
  integer, intent(in) :: nFreq
  integer, intent(in) :: iq
  integer, intent(in) :: is
  character(len=*), intent(in) :: name

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: data_id       ! Property list identifier
  integer(HID_T) :: plist_id       ! Property list identifier
  integer(HID_T) :: dataspace        ! Property list identifier
  integer(HID_T) :: memspace        ! Property list identifier
  integer :: error
  integer :: rank,comm,info
  integer(HSIZE_T) :: count(6), offset(6)

  real(DP), allocatable :: data(:,:,:,:,:,:)

  integer ijk, my_igp

  PUSH_SUB(read_eps_matrix_par_f_hdf5)

#ifdef CPLX
  SAFE_ALLOCATE(data,(2,nFreq,nmtx,1,2,1))
#else
  SAFE_ALLOCATE(data,(2,nFreq,nmtx,1,1,1))
#endif

#ifdef MPI
  comm = MPI_COMM_WORLD
  info = MPI_INFO_NULL

  call h5pcreate_f(H5P_FILE_ACCESS_F, plist_id, error)
  call h5pset_fapl_mpio_f(plist_id, comm, info, error)
  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error, access_prp = plist_id)
  call h5pclose_f(plist_id,error)
#else
  call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)
#endif

  do ijk = 1, ngpown_max

    if (ijk .le. ngpown) my_igp = inv_igp_index(ijk)

    call h5dopen_f(file_id, 'matrix', data_id, error)
    call h5dget_space_f(data_id,dataspace,error)

    rank = 6
    count(1) = 2
    count(2) = nFreq
    count(3) = nmtx
    count(4) = 1
    count(5) = SCALARSIZE
    count(6) = 1 !iq

    call h5screate_simple_f(rank, count, memspace, error)

! Construct data and offset

    if (ijk .le. ngpown .and. my_igp .le. nmtx) then

      offset(1)=0
      offset(2)=0
      offset(3)=0
      offset(4)=my_igp-1
      offset(5)=SCALARSIZE*(is-1)
      offset(6)=iq-1

! Select hyperslab

      call h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F, offset, count, error)

    else

      call H5sselect_none_f(memspace,error);
      call H5sselect_none_f(dataspace,error);

    endif

! Create property list for collective dataset read
! Read is serial for now

#ifdef MPI
    call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, error)
    call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, error)

! Collectively read the file

    call h5dread_f(data_id, H5T_NATIVE_DOUBLE, data, count, error, memspace, dataspace, &
                      xfer_prp = plist_id)
#else
    call h5dread_f(data_id, H5T_NATIVE_DOUBLE, data, count, error, memspace, dataspace)
#endif

    if (ijk .le. ngpown .and. my_igp .le. nmtx) then
      epsR(1:nFreq,1:nmtx,ijk) = CMPLX(data(1,1:nFreq,1:nmtx,1,1,1),data(2,1:nFreq,1:nmtx,1,1,1))
#ifdef CPLX
      epsA(1:nFreq,1:nmtx,ijk) = CMPLX(data(1,1:nFreq,1:nmtx,1,2,1),data(2,1:nFreq,1:nmtx,1,2,1))
#endif
    endif

    call h5sclose_f(memspace, error)
    call h5sclose_f(dataspace, error)
    call h5dclose_f(data_id, error)

  enddo

  call h5fclose_f(file_id,error)

  SAFE_DEALLOCATE(data)

  POP_SUB(read_eps_matrix_par_f_hdf5)

end subroutine read_eps_matrix_par_f_hdf5

!==========================================================================================

#endif
end module epsread_hdf5_m
