!#########################################################################
!		
!    Copyright (C) 2003-2012 Department of Physics and Astronomy,
!                            University of Rochester,
!                            Rochester, NY
!
!    hdf5_declarations.f90 is part of AstroBEAR.
!
!    AstroBEAR is free software: you can redistribute it and/or modify	  
!    it under the terms of the GNU General Public License as published by 
!    the Free Software Foundation, either version 3 of the License, or    
!    (at your option) any later version.
!
!    AstroBEAR is distributed in the hope that it will be useful, 
!    but WITHOUT ANY WARRANTY; without even the implied warranty of
!    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
!    GNU General Public License for more details.
!
!    You should have received a copy of the GNU General Public License
!    along with AstroBEAR.  If not, see <http://www.gnu.org/licenses/>.
!
!#########################################################################
!> @file hdf5_declarations.f90
!! @brief Main file for module HDF5Declarations

!> @defgroup HDF5Declarations HDF5 Declarations
!! @ingroup IOChomboGroup
!! @brief Declarations file for the Chombo output format.

!> Declarations file for the Chombo output format.
!! @author Brandon D. Shroyer
!! @date 10-12-2010
!! @ingroup HDF5Declarations
#if defined _HDF5
MODULE HDF5Declarations

   USE HDF5
   USE GlobalDeclarations
   USE TreeDeclarations

   IMPLICIT NONE
   SAVE
   PUBLIC

   ! Chombo Parameter Declarations    
   CHARACTER(LEN = 1), PARAMETER :: S_ROOT_GROUP = '/'
   REAL(KIND = qPrec), PARAMETER :: DBL_TEST_REAL_DAT = 1.0
   INTEGER(HID_T), PARAMETER :: HID_ATTRIBUTE_RANK = 0
   INTEGER(HSIZE_T), DIMENSION(1), PARAMETER :: IA_SCALAR_ATTRIB_DIMS = (/1/)
   INTEGER, PARAMETER :: I_MAX_COMPONENTS = 100
   INTEGER, PARAMETER :: I_MAX_CNAME_LENGTH = 100
   INTEGER, PARAMETER :: I_MAX_LEVELNAME_LENGTH = 12
   INTEGER, PARAMETER :: I_FILENAME_LENGTH = 19
   INTEGER, PARAMETER :: I_DATASET_RANK = 1
   INTEGER, PARAMETER :: I_DEFLATE_LEVEL=6

   ! A coordinate box requires six integers worth of space.
   INTEGER, PARAMETER :: I_CHOMBO_BOX_SIZE = 6

   ! The size of dataset chunks.
   ! HDF5 currently can't handle chunk sizes above 4 GB.  We'll do 1 GB to play it safe.
   INTEGER, PARAMETER :: I_MAX_CHUNK_SIZE = 1073741824  ! 1 GB

   INTEGER(HID_T) :: hid_intvect_id
   INTEGER(HID_T) :: hid_floatvect_id
   INTEGER(HID_T) :: hid_box_id

   LOGICAL, PARAMETER :: L_EXTENSIBLE = .TRUE.
   LOGICAL, PARAMETER :: L_NON_EXTENSIBLE = .FALSE.

   INTERFACE Read_Slab_From_Dataset_Double
      MODULE PROCEDURE Read_Slab_From_Dataset_Double_array, Read_Slab_From_Dataset_Double_scalar
   END INTERFACE

   INTERFACE Write_Slab_To_Dataset_Double
      MODULE PROCEDURE Write_Slab_To_Dataset_Double_array, Write_Slab_To_Dataset_Double_scalar
   END INTERFACE

   INTERFACE Read_Slab_From_Dataset_Int
      MODULE PROCEDURE Read_Slab_From_Dataset_Int_array, Read_Slab_From_Dataset_Int_scalar
   END INTERFACE

   INTERFACE Write_Slab_To_Dataset_Int
      MODULE PROCEDURE Write_Slab_To_Dataset_Int_array, Write_Slab_To_Dataset_Int_scalar
   END INTERFACE

   INTERFACE Initialize_HDF5_Dataset_Double
      MODULE PROCEDURE Initialize_HDF5_Dataset_Double_1,  Initialize_HDF5_Dataset_Double_2
   END INTERFACE

   INTERFACE Initialize_HDF5_Dataset_Int
      MODULE PROCEDURE Initialize_HDF5_Dataset_Int_1,  Initialize_HDF5_Dataset_Int_2
   END INTERFACE

   INTERFACE Initialize_HDF5_Dataset_Box
      MODULE PROCEDURE Initialize_HDF5_Dataset_Box_1,  Initialize_HDF5_Dataset_Box_2
   END INTERFACE

CONTAINS


   !> kills the program upon detecting an HDF5 error.
   !! @param s_function_name An error string containing the name of the function being checked.
   !! @param i_err the error value being tested.
   !! @param target_code An optional integer value that becomes the condition for success or failure.
   SUBROUTINE CatchHDF5Error(s_function_name, i_err, target_code) !used

      CHARACTER(LEN=*), INTENT(IN) :: s_function_name
      INTEGER :: i_err
      INTEGER, OPTIONAL :: target_code

      INTEGER :: success_code


      ! The default success code for most HDF5 calls is 0.  If there is no designated success
      ! code, then just set it to 0.
      IF (.NOT. PRESENT(target_code)) THEN
         success_code = 0
      ELSE
         success_code = target_code
      END IF

      IF (i_err /= success_code) THEN
         PRINT *, "HDF5 error:  function ", s_function_name, " failed with error code ", i_err, "."
         STOP
      END IF

   END SUBROUTINE CatchHDF5Error

   !> A combination function that initializes all relevant chombo data types.
   SUBROUTINE HDF5Init()
      IMPLICIT NONE
      INTEGER :: i_err

      ! Initializes the HDF5 library.  This function is safe to call
      ! even if it has already been called.
      CALL h5open_f(i_err)
      CALL CreateHDF5IntVector(hid_intvect_id)
      CALL CreateHDF5FloatVector(hid_floatvect_id)
      CALL CreateHDF5BoxType(hid_box_id)

   END SUBROUTINE HDF5Init

   !> Closes down data types
   SUBROUTINE HDF5Finalize()

      INTEGER :: i_err

      CALL h5tclose_f(hid_intvect_id, i_err)
      CALL h5tclose_f(hid_floatvect_id, i_err)
      CALL h5tclose_f(hid_box_id, i_err)

      CALL h5close_f(i_err)

   END SUBROUTINE HDF5Finalize

   !> Returns true if the input is a valid (open) HDF5 handle.
   !! @param handle An integer of type HID_T--the HDF5 handle being tested.
   LOGICAL FUNCTION HandleIsValid(handle)

      INTEGER(HID_T) :: handle

      INTEGER :: i_err
      LOGICAL :: result


      CALL h5iis_valid_f(handle, result, i_err)

      HandleIsValid = result

   END FUNCTION HandleIsValid

   !=============================== Begin HDF5 Type Definitions ==============================
   !> @name HDF5 Type Definitions
   !! @{

   !> Initializes the IntVector type used in the chombo specification.
   !! @param hid_intvect_id A chombo handle that will be associated with the type.
   SUBROUTINE CreateHDF5IntVector(hid_intvect_id)

      USE HDF5

      INTEGER(HID_T) :: hid_intvect_id

      INTEGER(size_t) :: i_h5int_type_size
      INTEGER(size_t) :: hid_intvectid_type_size
      INTEGER(size_t) :: i_offset
      INTEGER :: i_err


      i_err = 0
      ! Get size of H5T_NATIVE_INTEGER data type.
      CALL h5tget_size_f(H5T_NATIVE_INTEGER, i_h5int_type_size, i_err)

      ! Generate size of vector type
      hid_intvectid_type_size = 3 * i_h5int_type_size

      ! Create the intvectid data type.
      CALL h5tcreate_f(H5T_COMPOUND_F, hid_intvectid_type_size, hid_intvect_id, i_err)

      ! Clear i_offset.
      i_offset = 0

      ! Insert the three directional fields <i, j, k> into the integer vector data type.

      CALL h5tinsert_f(hid_intvect_id, "intvecti", i_offset, H5T_NATIVE_INTEGER, i_err)
      i_offset = i_offset + i_h5int_type_size

      CALL h5tinsert_f(hid_intvect_id, "intvectj", i_offset, H5T_NATIVE_INTEGER, i_err)
      i_offset = i_offset + i_h5int_type_size

      CALL h5tinsert_f(hid_intvect_id, "intvectk", i_offset, H5T_NATIVE_INTEGER, i_err)

      ! Die if unable to insert all three directional fields into intvectid.


   END SUBROUTINE CreateHDF5IntVector

   !> Initializes the FloatVector type used in the chombo specification.
   !! @param hid_floatvect_id A chombo handle that will be associated with the type.
   SUBROUTINE CreateHDF5FloatVector(hid_floatvect_id)

      INTEGER(HID_T) :: hid_floatvect_id

      INTEGER(SIZE_T) :: i_h5dbl_type_size
      INTEGER(SIZE_T) :: hid_floatvectid_type_size
      INTEGER(SIZE_T) :: i_offset
      INTEGER :: i_err


      ! Get size of H5T_NATIVE_DOUBLE data type.
      CALL h5tget_size_f(H5T_NATIVE_DOUBLE, i_h5dbl_type_size, i_err)

      hid_floatvectid_type_size = 3 * i_h5dbl_type_size

      ! Create the floatvectid data type.
      CALL h5tcreate_f(H5T_COMPOUND_F, hid_floatvectid_type_size, hid_floatvect_id, i_err)

      ! Clear i_offset
      i_offset = 0

      ! Insert the three directional fields <i, j, k> into the floating-point vector
      ! data type.
      CALL h5tinsert_f(hid_floatvect_id, "x", i_offset, H5T_NATIVE_DOUBLE, i_err)
      i_offset = i_offset + i_h5dbl_type_size

      CALL h5tinsert_f(hid_floatvect_id, "y", i_offset, H5T_NATIVE_DOUBLE, i_err)
      i_offset = i_offset + i_h5dbl_type_size

      CALL h5tinsert_f(hid_floatvect_id, "z", i_offset, H5T_NATIVE_DOUBLE, i_err)

      ! Die if unable to insert all three directional fields into floatvectid.

   END SUBROUTINE CreateHDF5FloatVector

   !> Initializes the Box type used in the chombo specification.
   !! @param hid_box_id A chombo handle that will be associated with the type.
   SUBROUTINE CreateHDF5BoxType(hid_box_id)

      INTEGER(HID_T) :: hid_box_id

      INTEGER(size_t) :: i_h5int_type_size
      INTEGER(size_t) :: hid_boxid_type_size
      INTEGER(size_t) :: i_offset
      INTEGER :: i_err


      ! Get size of H5T_NATIVE_INTEGER data type.
      CALL h5tget_size_f(H5T_NATIVE_INTEGER, i_h5int_type_size, i_err)

      ! Set box data size
      hid_boxid_type_size = I_CHOMBO_BOX_SIZE * i_h5int_type_size

      ! Get size of box type.
      CALL h5tcreate_f(H5T_COMPOUND_F, hid_boxid_type_size, hid_box_id, i_err)

      ! Clear i_offset
      i_offset = 0

      ! Insert the six boundary-descriptors into the box data type.
      CALL h5tinsert_f(hid_box_id, "lo_i", i_offset, H5T_NATIVE_INTEGER, i_err)
      i_offset = i_offset + i_h5int_type_size

      CALL h5tinsert_f(hid_box_id, "lo_j", i_offset, H5T_NATIVE_INTEGER, i_err)
      i_offset = i_offset + i_h5int_type_size

      CALL h5tinsert_f(hid_box_id, "lo_k", i_offset, H5T_NATIVE_INTEGER, i_err)
      i_offset = i_offset + i_h5int_type_size

      CALL h5tinsert_f(hid_box_id, "hi_i", i_offset, H5T_NATIVE_INTEGER, i_err)
      i_offset = i_offset + i_h5int_type_size

      CALL h5tinsert_f(hid_box_id, "hi_j", i_offset, H5T_NATIVE_INTEGER, i_err)
      i_offset = i_offset + i_h5int_type_size

      CALL h5tinsert_f(hid_box_id, "hi_k", i_offset, H5T_NATIVE_INTEGER, i_err)

      ! Die if unable to insert all six directional fields into hid_box_id.

   END SUBROUTINE CreateHDF5BoxType

   !> @}
   !================================ End HDF5 Type Definitions ===============================

   !================================ Begin HDF5 Read Functions ===============================

   !> @name HDF5 Read Function
   !! @{

   !> Reads in a slab of data from a a Chombo dataset of type Box.
   !! @param s_name The relative name of the Chombo dataset.
   !! @param hid_group_id The group within the HDF5 file containing the desired dataset.
   !! @param box_data A pointer to the six-element integer array that will store the read-in data.
   !! @param i_offset The offset of the target data section (hyperslab) within the Chombo dataset.
   SUBROUTINE Read_Slab_From_Dataset_Box(s_name, hid_group_id, box_data, i_offset)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name								! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id							! Group identifier.
      INTEGER, DIMENSION(:), INTENT(OUT) :: box_data	! Data input
      INTEGER(HSIZE_T), INTENT(IN) :: i_offset

      INTEGER(HID_T) :: hid_dataset_id				! Dataset handle.
      INTEGER(HID_T) :: hid_dataspace_id              ! Dataspace handle.
      INTEGER(HID_T) :: hid_memspace_id               ! Dataspace handle for hyperslab reference.
      INTEGER(HID_T) :: hid_property_list_id
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_dims		! Array to hold the size of the input.
      INTEGER :: i_err
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_data_offset
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_slab_size


      ! Set the size of the hyperslab.
      ia_slab_size(1) = SIZE(box_data) / I_CHOMBO_BOX_SIZE

      ! Store the size of the offset in a dimension array.
      ia_data_offset(1) = i_offset

      !PRINT *, "Read_Slab_From_Dataset_Box::s_name = ", s_name
      !PRINT *, "Read_Slab_From_Dataset_Box::slab size = ", ia_slab_size(1)
      !PRINT *, "Read_Slab_From_Dataset_Box::offset size = ", i_offset

      ! Open the dataset in the HDF5 file.
      CALL h5dopen_f(hid_group_id, s_name, hid_dataset_id, i_err)

      ! Retrieve the total dataspace for the dataset.
      CALL h5dget_space_f(hid_dataset_id, hid_dataspace_id, i_err)

      CALL h5sselect_hyperslab_f(hid_dataspace_id, H5S_SELECT_SET_F, ia_data_offset, ia_slab_size, i_err) 

      ! Create dataspace for the upcoming hyperslab.
      IF (size(box_data) > 0) CALL h5screate_simple_f(I_DATASET_RANK, ia_slab_size, hid_memspace_id, i_err)


# if defined _PHDF5
      IF (lParallelHDF5) THEN
         !
         ! Create property list for collective dataset write
         !
         CALL h5pcreate_f(H5P_DATASET_XFER_F, hid_property_list_id, i_err)

         CALL h5pset_dxpl_mpio_f(hid_property_list_id, H5FD_MPIO_INDEPENDENT_F, i_err)
         !
         ! Read the dataset collectively.
         !

         ! Read data into newly-allocated array.
         IF (size(box_data) > 0) CALL h5dread_f(hid_dataset_id, hid_box_id, box_data, ia_dims, i_err, hid_memspace_id, hid_dataspace_id, xfer_prp=hid_property_list_id)
         CALL h5pclose_f(hid_property_list_id, i_err)
      ELSE
         ! Read data into newly-allocated array.
         CALL h5dread_f(hid_dataset_id, hid_box_id, box_data, ia_dims, i_err, hid_memspace_id, hid_dataspace_id)

      END IF
# else        
      ! Read data into newly-allocated array.
      CALL h5dread_f(hid_dataset_id, hid_box_id, box_data, ia_dims, i_err, hid_memspace_id, hid_dataspace_id)

# endif


      ! Close HDF5 handles.
      IF (size(box_data) > 0) CALL h5sclose_f(hid_memspace_id, i_err)

      CALL h5sclose_f(hid_dataspace_id, i_err)

      CALL h5dclose_f(hid_dataset_id, i_err)

   END SUBROUTINE Read_Slab_From_Dataset_Box


   SUBROUTINE Read_Slab_From_Dataset_Double_scalar(s_name, hid_group_id, dbla_data, i_offset)
      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name								! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id							! Group identifier.
      REAL(KIND=qPREC), INTENT(OUT) :: dbla_data
      REAL(KIND=qPrec), POINTER, DIMENSION(:) :: dbla_data_vec	! Data input
      INTEGER(HSIZE_T), INTENT(IN) :: i_offset
      REAL(KIND=qPrec), DIMENSION(1), TARGET :: dbl_buffer_array
      dbla_data_vec => dbl_buffer_array
      CALL Read_Slab_From_Dataset_Double_array(s_name, hid_group_id, dbla_data_vec, i_offset)
      dbla_data=dbla_data_vec(1)
   END SUBROUTINE Read_Slab_From_Dataset_Double_scalar



   SUBROUTINE Read_Slab_From_Dataset_Int_scalar(s_name, hid_group_id, dbla_data, i_offset)
      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name								! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id							! Group identifier.
      INTEGER, INTENT(OUT) :: dbla_data
      INTEGER, POINTER, DIMENSION(:) :: dbla_data_vec	! Data input
      INTEGER(HSIZE_T), INTENT(IN) :: i_offset
      INTEGER, DIMENSION(1), TARGET :: dbl_buffer_array
      dbla_data_vec => dbl_buffer_array
      CALL Read_Slab_From_Dataset_Int_array(s_name, hid_group_id, dbla_data_vec, i_offset)
      dbla_data=dbla_data_vec(1)
   END SUBROUTINE Read_Slab_From_Dataset_Int_scalar


   !> Reads in a slab of data from a a Chombo dataset of type Double.
   !! @param s_name The relative name of the Chombo dataset.
   !! @param hid_group_id The group within the HDF5 file containing the desired dataset.
   !! @param dbla_data A pointer to the 1D double array that will store the read-in data.
   !! @param i_offset The offset of the target data section (hyperslab) within the Chombo dataset.
   SUBROUTINE Read_Slab_From_Dataset_Double_array(s_name, hid_group_id, dbla_data, i_offset)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name								! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id							! Group identifier.
      REAL(KIND=qPrec), POINTER, DIMENSION(:), INTENT(OUT) :: dbla_data	! Data input
      INTEGER(HSIZE_T), INTENT(IN) :: i_offset

      INTEGER(HID_T) :: hid_dataset_id				! Dataset handle.
      INTEGER(HID_T) :: hid_dataspace_id              ! Dataspace handle.
      INTEGER(HID_T) :: hid_memspace_id               ! Dataspace handle for hyperslab reference.
      INTEGER(HID_T) :: hid_property_list_id
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_dims		! Array to hold the size of the input.
      INTEGER :: i_err
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_data_offset
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_slab_size


      ! Set the size of the hyperslab.
      ia_slab_size(1) = SIZE(dbla_data)

      ! Store the size of the offset in a dimension array.
      ia_data_offset(1) = i_offset

      ! Open the dataset in the HDF5 file.
      CALL h5dopen_f(hid_group_id, s_name, hid_dataset_id, i_err)


      ! Retrieve the total dataspace for the dataset.
      CALL h5dget_space_f(hid_dataset_id, hid_dataspace_id, i_err)


      CALL h5sselect_hyperslab_f(hid_dataspace_id, H5S_SELECT_SET_F, ia_data_offset, ia_slab_size, i_err) 

      ! Create dataspace for the upcoming hyperslab.
      IF (size(dbla_data) > 0) CALL h5screate_simple_f(I_DATASET_RANK, ia_slab_size, hid_memspace_id, i_err)

# if defined _PHDF5
      IF (lParallelHDF5) THEN
         !
         ! Create property list for collective dataset read
         !
         CALL h5pcreate_f(H5P_DATASET_XFER_F, hid_property_list_id, i_err)

         CALL h5pset_dxpl_mpio_f(hid_property_list_id, H5FD_MPIO_INDEPENDENT_F, i_err)
         !
         ! Read the dataset collectively.
         !

         IF (SIZE(dbla_data) > 0) CALL h5dread_f(hid_dataset_id, H5T_NATIVE_DOUBLE, dbla_data, ia_dims, i_err, hid_memspace_id, hid_dataspace_id, xfer_prp=hid_property_list_id)
         CALL h5pclose_f(hid_property_list_id, i_err)
      ELSE
         ! Read data into newly-allocated array.
         CALL h5dread_f(hid_dataset_id, H5T_NATIVE_DOUBLE, dbla_data, ia_dims, i_err, hid_memspace_id, hid_dataspace_id)
      END IF
# else        
      ! Read data into newly-allocated array.
      CALL h5dread_f(hid_dataset_id, H5T_NATIVE_DOUBLE, dbla_data, ia_dims, i_err, hid_memspace_id, hid_dataspace_id)
# endif

      ! Close HDF5 handles.
      IF (size(dbla_data) > 0) CALL h5sclose_f(hid_memspace_id, i_err)
      CALL h5sclose_f(hid_dataspace_id, i_err)
      CALL h5dclose_f(hid_dataset_id, i_err)

   END SUBROUTINE Read_Slab_From_Dataset_Double_array

   !> Reads in a slab of data from a a Chombo dataset of type Integer.
   !! @param s_name The relative name of the Chombo dataset.
   !! @param hid_group_id The group within the HDF5 file containing the desired dataset.
   !! @param int_data A pointer to the 1D integer array that will store the read-in data.
   !! @param i_offset The offset of the target data section (hyperslab) within the Chombo dataset.
   SUBROUTINE Read_Slab_From_Dataset_Int_array(s_name, hid_group_id, int_data, i_offset)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name								! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id							! Group identifier.
      INTEGER, DIMENSION(:), INTENT(OUT) :: int_data	! Data input
      INTEGER(HSIZE_T), INTENT(IN) :: i_offset

      INTEGER(HID_T) :: hid_dataset_id				! Dataset handle.
      INTEGER(HID_T) :: hid_dataspace_id              ! Dataspace handle.
      INTEGER(HID_T) :: hid_memspace_id               ! Dataspace handle for hyperslab reference.
      INTEGER(HID_T) :: hid_property_list_id
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_dims		! Array to hold the size of the input.
      INTEGER :: i_err
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_data_offset
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_slab_size


      ! Set the size of the hyperslab.
      ia_slab_size(1) = SIZE(int_data)

      ! Store the size of the offset in a dimension array.
      ia_data_offset(1) = i_offset

      ! Open the dataset in the HDF5 file.
      CALL h5dopen_f(hid_group_id, s_name, hid_dataset_id, i_err)


      ! Retrieve the total dataspace for the dataset.
      CALL h5dget_space_f(hid_dataset_id, hid_dataspace_id, i_err)


      CALL h5sselect_hyperslab_f(hid_dataspace_id, H5S_SELECT_SET_F, ia_data_offset, ia_slab_size, i_err) 


      ! Create dataspace for the upcoming hyperslab.
      IF (size(int_data) > 0) CALL h5screate_simple_f(I_DATASET_RANK, ia_slab_size, hid_memspace_id, i_err)


# if defined _PHDF5
      IF (lParallelHDF5) THEN
         !
         ! Create property list for collective dataset write
         !
         CALL h5pcreate_f(H5P_DATASET_XFER_F, hid_property_list_id, i_err)

         CALL h5pset_dxpl_mpio_f(hid_property_list_id, H5FD_MPIO_INDEPENDENT_F, i_err)
         !
         ! Read the dataset collectively.
         !

         ! Read data into newly-allocated array.
         IF (size(int_data) > 0) CALL h5dread_f(hid_dataset_id, H5T_NATIVE_INTEGER, int_data, ia_dims, i_err, hid_memspace_id, hid_dataspace_id, xfer_prp=hid_property_list_id)
         CALL h5pclose_f(hid_property_list_id, i_err)
      ELSE
         ! Read data into newly-allocated array.
         CALL h5dread_f(hid_dataset_id, H5T_NATIVE_INTEGER, int_data, ia_dims, i_err, hid_memspace_id, hid_dataspace_id)
      END IF
# else        
      CALL h5dread_f(hid_dataset_id, H5T_NATIVE_INTEGER, int_data, ia_dims, i_err, hid_memspace_id, hid_dataspace_id)
# endif

      ! Close HDF5 handles.
      IF (size(int_data) > 0) CALL h5sclose_f(hid_memspace_id, i_err)
      CALL h5sclose_f(hid_dataspace_id, i_err)
      CALL h5dclose_f(hid_dataset_id, i_err)


   END SUBROUTINE Read_Slab_From_Dataset_Int_array

   !> Reads in an Integer attribute from an HDF5 file.
   !! @param s_name The relative name within the HDF5 file.
   !! @param hid_group_id The group within the HDF5 file containing the desired attribute.
   INTEGER FUNCTION Read_HDF5_Attribute_Int(s_name, hid_group_id)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name		! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id	! Group identifier.

      ! Variable declarations
      INTEGER(HID_T) :: hid_attribute_id		! Dataset handle.
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_dims	! Array to hold the size of the input.
      INTEGER :: i_output				! Used to store output from HDF5 API.
      INTEGER :: i_err


      ! Open the attribute in the HDF5 file.
      CALL h5aopen_name_f(hid_group_id, s_name, hid_attribute_id, i_err)

      ! Die if unable to open dataset.
      IF (i_err < 0) THEN
         PRINT *, "Read_HDF5_Attribute_Int error ", i_err, ": unable to open attribute" , s_name, "."
         STOP
      END IF


      ! Initializing dimension array with size of chombo array.
      ia_dims(1) = 1

      ! Read data into newly-allocated array.
      CALL h5aread_f(hid_attribute_id, H5T_NATIVE_INTEGER, i_output, ia_dims, i_err)

      ! Die if unable to read data in from dataset.
      IF (i_err < 0) THEN
         PRINT *, "Read_HDF5_Attribute_Int error ", i_err, ": unable to read value from attribute ", s_name, "."
         STOP 
      END IF

      ! Close dataset.
      CALL h5aclose_f(hid_attribute_id, i_err)

      ! Die if unable to close dataset.
      IF (i_err < 0) THEN
         PRINT *, "Read_HDF5_Attribute_Int error ", i_err, ": unable to close attribute ", s_name, "."
         STOP
      END IF

      Read_HDF5_Attribute_Int = i_output

   END FUNCTION Read_HDF5_Attribute_Int



   !> Reads in a double-precision attribute from an HDF5 file.
   !! @param s_name The relative name within the HDF5 file.
   !! @param hid_group_id The group within the HDF5 file containing the desired attribute.
   REAL(KIND=xPrec) FUNCTION Read_HDF5_Attribute_Double(s_name, hid_group_id)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name		! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id	! Group identifier.

      ! Variable declarations
      INTEGER(HID_T) :: hid_attribute_id		! Dataset handle.
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_dims	! Array to hold the size of the input.
      REAL(KIND=xPrec) :: dbl_output				! Used to store output from HDF5 API.
      INTEGER :: i_err


      ! Open the attribute in the HDF5 file.
      CALL h5aopen_name_f(hid_group_id, s_name, hid_attribute_id, i_err)

      ! Die if unable to open dataset.
      IF (i_err < 0) THEN
         PRINT *, "Read_HDF5_Attribute_Double error ", i_err, ": unable to open attribute ", s_name, "."	
         STOP
      END IF


      ! Initializing dimension array with size of chombo array.
      ia_dims(1) = 1

      ! Read data into newly-allocated array.
      CALL h5aread_f(hid_attribute_id, H5T_NATIVE_DOUBLE, dbl_output, ia_dims, i_err)

      ! Die if unable to read data in from dataset.
      IF (i_err < 0) THEN
         PRINT *, "Read_HDF5_Attribute_Double error ", i_err, ": unable to read value from attribute ", s_name, "."
         STOP 
      END IF

      ! Close dataset.
      CALL h5aclose_f(hid_attribute_id, i_err)

      ! Die if unable to close dataset.
      IF (i_err < 0) THEN
         PRINT *, "Read_HDF5_Attribute_Double error ", i_err, ": unable to close attribute ", s_name, "."
         STOP
      END IF

      Read_HDF5_Attribute_Double = dbl_output

   END FUNCTION Read_HDF5_Attribute_Double

   !> Returns the number of elements in a Chombo HDF5 dataset.
   !! @param group_id An integer of type HID_T (a group handle).
   !! @param s_name The name of the dataset being queried.
   INTEGER FUNCTION IO_GetDatasetElementCount(group_id, s_name)

      INTEGER(HID_T) :: group_id
      CHARACTER(LEN=*) :: s_name

      INTEGER(HSIZE_T), DIMENSION(1) :: dims, maxdims
      INTEGER :: i_err
      INTEGER(HID_T) :: dataset_id
      INTEGER(HID_T) :: dataspace_id

      ! Open the dataset in the Chombo file.
      CALL h5dopen_f(group_id, s_name, dataset_id, i_err)

      ! Get the associated dataspace.
      CALL h5dget_space_f(dataset_id, dataspace_id, i_err)

      ! Extract the dimensions of said dataspace.
      CALL h5sget_simple_extent_dims_f(dataspace_id, dims, maxdims, i_err)

      ! Close the dataspace.
      CALL h5sclose_f(dataspace_id, i_err)

      ! close the dataset.
      CALL h5dclose_f(dataset_id, i_err)

      IO_GetDatasetElementCount = dims(1)

   END FUNCTION IO_GetDatasetElementCount
   !> @}
   !=================================End HDF5 Read Functions ===============================

   !============================= Begin HDF5 Write Functions ===============================
   !> @name HDF5 Write Functions
   !! @{

   !> Creates a new group in an HDF5 file.
   !! @param s_name The new group's name.
   !! @param location_id The ID of the file or group in which the new group will be created.
   !! @param hid_group_id The group ID to which the new group will be assigned.
   SUBROUTINE CreateHDF5Group(s_name, location_id, hid_group_id)

      CHARACTER(LEN=*) :: s_name
      INTEGER(HID_T) :: location_id
      INTEGER(HID_T) :: hid_group_id

      INTEGER :: iErr

      ! Test if the given handle is valid.  This will fail on handles from unopened files
      ! and handles that are already opened.
      IF (.NOT. HandleIsValid(hid_group_id)) THEN
         PRINT *, "CreateHDF5Group() error: invalid target handle for group '", s_name, "'."
         STOP
      ELSE IF (.NOT. HandleIsValid(location_id)) THEN
         PRINT *, "CreateHDF5Group() error: invalid location handle for group '", s_name, "'."
         STOP
      END IF

      ! Create a new group within the file.
      CALL h5gcreate_f(location_id, s_name, hid_group_id, iErr)

   END SUBROUTINE CreateHDF5Group

   !> Adds an integer attribute to an HDF5 file.
   !! @param s_name The attribute's name.
   !! @param hid_group_id The group ID within the file where the attribute will reside.
   !! @param i_value The value of the attribute.
   SUBROUTINE Add_HDF5_Attribute_Int(s_name, hid_group_id, i_value) !used

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new attribute.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      INTEGER :: i_value                                ! Data input

      ! Variable declarations
      INTEGER(HID_T) :: hid_dataspace_id
      INTEGER(HID_T) :: hid_attribute_id

      INTEGER :: i_err


      ! Create a new dataspace.
      CALL h5screate_simple_f(HID_ATTRIBUTE_RANK, IA_SCALAR_ATTRIB_DIMS, hid_dataspace_id, i_err)


      ! Create new attribute within dataspace.
      CALL h5acreate_f(hid_group_id, s_name, H5T_NATIVE_INTEGER, hid_dataspace_id, hid_attribute_id, i_err)


      ! Write the datavalue to the dataset.
      CALL h5awrite_f(hid_attribute_id, H5T_NATIVE_INTEGER, i_value, IA_SCALAR_ATTRIB_DIMS, i_err)


      ! Close the attribute object.
      CALL h5aclose_f(hid_attribute_id, i_err)

      ! Close the dataspace object.
      CALL h5sclose_f(hid_dataspace_id, i_err)

   END SUBROUTINE Add_HDF5_Attribute_Int



   !> Adds an double-precision attribute to an HDF5 file.
   !! @param s_name The attribute's name.
   !! @param hid_group_id The group ID within the file where the attribute will reside.
   !! @param dbl_value The value of the attribute.
   SUBROUTINE Add_HDF5_Attribute_Double(s_name, hid_group_id, dbl_value) !used

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new attribute.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      REAL(8) :: dbl_value                    ! Data input

      ! Variable declarations
      INTEGER(HID_T) :: hid_dataspace_id
      INTEGER(HID_T) :: hid_attribute_id

      INTEGER :: i_err



      ! Create a new dataspace.
      CALL h5screate_simple_f(HID_ATTRIBUTE_RANK, IA_SCALAR_ATTRIB_DIMS, hid_dataspace_id, i_err)

      ! Create new attribute within dataspace.
      CALL h5acreate_f(hid_group_id, s_name, H5T_NATIVE_DOUBLE, hid_dataspace_id, hid_attribute_id, i_err)

      ! Write the datavalue to the dataset.
      CALL h5awrite_f(hid_attribute_id, H5T_NATIVE_DOUBLE, dbl_value, IA_SCALAR_ATTRIB_DIMS, i_err)

      ! Close the attribute object.
      CALL h5aclose_f(hid_attribute_id, i_err)

      ! Close the dataspace object.
      CALL h5sclose_f(hid_dataspace_id, i_err)

   END SUBROUTINE Add_HDF5_Attribute_Double


   !> Adds a three-element integer vector attribute to an HDF5 file.
   !! @param s_name The attribute's name.
   !! @param hid_type_id The integer vector data type handle.
   !! @param hid_group_id The group ID within the file where the attribute will reside.
   !! @param ia_value The value(s) of the attribute.
   !! @param i_size (optional) the size of the data type.
   SUBROUTINE Add_HDF5_Attribute_IntVector(s_name, hid_type_id, hid_group_id, ia_value, i_size)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new attribute.
      INTEGER(HID_T), INTENT(IN) :: hid_type_id        ! Describes the type of v_value.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      INTEGER, DIMENSION(3) :: ia_value                ! Data input
      INTEGER(size_t), INTENT(IN), OPTIONAL :: i_size    ! Size of input type.

      ! Variable declarations
      INTEGER(HID_T) :: hid_dataspace_id
      INTEGER(HID_T) :: hid_attribute_id

      INTEGER :: i_err

      ! If a size value was passed in, then set the type's size value to that.
      IF (PRESENT(i_size)) THEN
         CALL h5tset_size_f(hid_type_id, i_size ,i_err)
      END IF

      ! Create a new dataspace.
      CALL h5screate_simple_f(HID_ATTRIBUTE_RANK, IA_SCALAR_ATTRIB_DIMS, hid_dataspace_id, i_err)

      ! Create new attribute within dataspace.
      CALL h5acreate_f(hid_group_id, s_name, hid_type_id, hid_dataspace_id, hid_attribute_id, i_err)

      ! Write the datavalue to the dataset.
      CALL h5awrite_f(hid_attribute_id, hid_type_id, ia_value, IA_SCALAR_ATTRIB_DIMS, i_err)

      ! Close the attribute object.
      CALL h5aclose_f(hid_attribute_id, i_err)

      ! Close the dataspace object.
      CALL h5sclose_f(hid_dataspace_id, i_err)

   END SUBROUTINE Add_HDF5_Attribute_IntVector



   !> Adds a three-element double-precision vector attribute to an HDF5 file.
   !! @param s_name The attribute's name.
   !! @param hid_group_id The group ID within the file where the attribute will reside.
   !! @param dbla_value The value(s) of the attribute.
   !! @param i_size (optional) the size of the data type.
   SUBROUTINE Add_HDF5_Attribute_FloatVector(s_name, hid_group_id, dbla_value, i_size)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new attribute.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      REAL(KIND=qPrec), DIMENSION(3) :: dbla_value    ! Data input
      INTEGER(size_t), INTENT(IN), OPTIONAL :: i_size    ! Size of input type.

      ! Variable declarations
      INTEGER(HID_T) :: hid_dataspace_id
      INTEGER(HID_T) :: hid_attribute_id

      INTEGER :: i_err


      ! If a size value was passed in, then set the type's size value to that.
      IF (PRESENT(i_size)) THEN
         CALL h5tset_size_f(hid_floatvect_id, i_size ,i_err)
      END IF

      ! Create a new dataspace.
      CALL h5screate_simple_f(HID_ATTRIBUTE_RANK, IA_SCALAR_ATTRIB_DIMS, hid_dataspace_id, i_err)

      ! Create new attribute within dataspace.
      CALL h5acreate_f(hid_group_id, s_name, hid_floatvect_id, hid_dataspace_id, hid_attribute_id, i_err)

      ! Write the datavalue to the dataset.
      CALL h5awrite_f(hid_attribute_id, hid_floatvect_id, dbla_value, IA_SCALAR_ATTRIB_DIMS, i_err)

      ! Close the attribute object.
      CALL h5aclose_f(hid_attribute_id, i_err)

      ! Close the dataspace object.
      CALL h5sclose_f(hid_dataspace_id, i_err)

   END SUBROUTINE Add_HDF5_Attribute_FloatVector

   !> Adds a string object to an HDF5 file
   !! @param s_name The attribute's name.
   !! @param hid_group_id The group ID within the file where the attribute will reside.
   !! @param s_value The value of the attribute.
   SUBROUTINE Add_HDF5_Attribute_String(s_name, hid_group_id, s_value)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new attribute.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      CHARACTER(LEN=*) :: s_value                        ! Data input

      ! Variable declarations
      INTEGER(HID_T) :: hid_type_id
      INTEGER(HID_T) :: hid_dataspace_id
      INTEGER(HID_T) :: hid_attribute_id

      INTEGER :: i_err

      ! Copy the H5T_NATIVE_CHARACTER data type to hid_h5string_type_id.
      CALL h5tcopy_f(H5T_NATIVE_CHARACTER, hid_type_id, i_err)

      ! Set the type's size value.
      CALL h5tset_size_f(hid_type_id, INT(LEN(TRIM(s_value)), size_t), i_err)

      ! Create a new dataspace.
      CALL h5screate_simple_f(HID_ATTRIBUTE_RANK, IA_SCALAR_ATTRIB_DIMS, hid_dataspace_id, i_err)

      ! Create new attribute within dataspace.
      CALL h5acreate_f(hid_group_id, s_name, hid_type_id, hid_dataspace_id, hid_attribute_id, i_err)

      ! Write the datavalue to the dataset.
      CALL h5awrite_f(hid_attribute_id, hid_type_id, s_value, IA_SCALAR_ATTRIB_DIMS, i_err)

      ! Close the type object.
      CALL h5tclose_f(hid_type_id, i_err)

      ! Close the attribute object.
      CALL h5aclose_f(hid_attribute_id, i_err)

      ! Close the dataspace object.
      CALL h5sclose_f(hid_dataspace_id, i_err)

   END SUBROUTINE Add_HDF5_Attribute_String


   !> Adds a Box (six-element integer) attribute to an HDF5 file.
   !! @param s_name The attribute's name.
   !! @param hid_type_id The box data type handle.
   !! @param hid_group_id The group ID within the file where the attribute will reside.
   !! @param ia_value The value(s) of the attribute.
   !! @param i_size (optional) the size of the data type.
   SUBROUTINE Add_HDF5_Attribute_Box(s_name, hid_type_id, hid_group_id, ia_value, i_size)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new attribute.
      INTEGER(HID_T), INTENT(IN) :: hid_type_id        ! Used to set the string size.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      INTEGER, DIMENSION(I_CHOMBO_BOX_SIZE) :: ia_value                ! Data input
      INTEGER(size_t), INTENT(IN), OPTIONAL :: i_size    ! Size of input type.

      ! Variable declarations
      INTEGER(HID_T) :: hid_dataspace_id
      INTEGER(HID_T) :: hid_attribute_id

      INTEGER :: i_err


      ! If a size value was passed in, then set the type's size value to that.
      IF (PRESENT(i_size)) THEN
         CALL h5tset_size_f(hid_type_id, i_size ,i_err)
      END IF

      ! Create a new dataspace.
      CALL h5screate_simple_f(HID_ATTRIBUTE_RANK, IA_SCALAR_ATTRIB_DIMS, hid_dataspace_id, i_err)

      ! Create new attribute within dataspace.
      CALL h5acreate_f(hid_group_id, s_name, hid_type_id, hid_dataspace_id, hid_attribute_id, i_err)

      ! Write the datavalue to the dataset.
      CALL h5awrite_f(hid_attribute_id, hid_type_id, ia_value, IA_SCALAR_ATTRIB_DIMS, i_err)

      ! Close the attribute object.
      CALL h5aclose_f(hid_attribute_id, i_err)

      ! Close the dataspace object.
      CALL h5sclose_f(hid_dataspace_id, i_err)

   END SUBROUTINE Add_HDF5_Attribute_Box



   SUBROUTINE Initialize_HDF5_Dataset_Double_2(s_name, hid_group_id, raw_data_size, lExtensible)
      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      INTEGER(8) :: raw_data_size8
      INTEGER :: raw_data_size
      LOGICAL, OPTIONAL :: lExtensible
      LOGICAL :: l_extend

      IF (PRESENT(lExtensible)) THEN
         l_extend = lExtensible
      ELSE
         l_extend = .TRUE.
      END IF
      raw_data_size8=raw_data_size
      CALL Initialize_HDF5_Dataset_Double_1(s_name, hid_group_id, raw_data_size8, l_extend)
   END SUBROUTINE Initialize_HDF5_Dataset_Double_2



   !> Initializes a double-precision dataset within a HDF5 file.
   !! @param s_name The dataset's name.
   !! @param hid_group_id The group ID within the file where the dataset will reside.
   !! @param i_dataset_size The size of the dataset.
   !! @param lExtensible An optional logical flag indicating whether or not the dataset will be extensible.
   SUBROUTINE Initialize_HDF5_Dataset_Double_1(s_name, hid_group_id, raw_data_size, lExtensible)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      INTEGER(8) :: raw_data_size
      LOGICAL, OPTIONAL :: lExtensible
      !     initialize the dataspace.

      INTEGER(HSIZE_T) :: i_dataset_size               ! Size of forthcoming data array, used to
      INTEGER(HID_T) :: hid_dataspace_id                ! Dataspace handle.
      INTEGER(HID_T) :: hid_dataset_id                ! Dataset handle.
      INTEGER(HID_T) :: hid_property_list_id                ! Property list handle.
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_dataset_dims    ! Array to hold the size of the input.
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_chunk_dims    ! Array to hold the size of the dataset chunks.
      INTEGER(HSIZE_T), PARAMETER :: one_hst=1
      INTEGER :: i_err
      LOGICAL :: l_extend


      i_dataset_size = raw_data_size

      IF (PRESENT(lExtensible)) THEN
         l_extend = lExtensible
      ELSE
         l_extend = .TRUE.
      END IF

      ia_dataset_dims(1) = i_dataset_size

      ! The dataset chunk size is whatever is smaller--the dataset size, or the maximum dataset
      ! chunk size in doubles.  Under no circumstances should the chunk size be less than 1.
      ia_chunk_dims(1) = MAX(MIN(i_dataset_size, GetChunkSize(H5T_NATIVE_DOUBLE)), INT(1, HSIZE_T))

      ! Create the new dataspace.  The H5S_UNLIMITED_F maxdims value is required for extensibility.
      IF (l_extend) THEN
         CALL h5screate_simple_f(I_DATASET_RANK, ia_dataset_dims, hid_dataspace_id, i_err, (/INT(H5S_UNLIMITED_F, HSIZE_T) /))
      ELSE
         CALL h5screate_simple_f(I_DATASET_RANK, ia_dataset_dims, hid_dataspace_id, i_err)
      END IF


      ! Create the property list for this dataset.
      CALL h5pcreate_f(H5P_DATASET_CREATE_F, hid_property_list_id, i_err)

      ! Chunk the dataset for compression.
      CALL h5pset_chunk_f(hid_property_list_id, I_DATASET_RANK, ia_chunk_dims, i_err)

      ! Forces the dataset to allocate the space at creation time.
      CALL h5pset_alloc_time_f(hid_property_list_id, H5D_ALLOC_TIME_EARLY_F, i_err)

      ! Set the dataset to use gzip compression (default for deflate option).
      !    CALL h5pset_deflate_f(hid_property_list_id,I_DEFLATE_LEVEL,i_err)

      ! Create the new dataset.
      CALL h5dcreate_f(hid_group_id, s_name, H5T_NATIVE_DOUBLE, hid_dataspace_id, hid_dataset_id, i_err, hid_property_list_id)

      CALL h5dclose_f(hid_dataset_id, i_err)        ! Close the dataset.

      CALL h5pclose_f(hid_property_list_id, i_err)    ! Close the property list.

      CALL h5sclose_f(hid_dataspace_id, i_err)    ! Close the dataspace.

   END SUBROUTINE Initialize_HDF5_Dataset_Double_1



   SUBROUTINE Write_Slab_To_Dataset_Double_scalar(s_dataset_name, hid_group_id, dbla_data, i_offset)

      CHARACTER(LEN=*), INTENT(IN) :: s_dataset_name
      INTEGER(HID_T) :: hid_group_id
      REAL(KIND=qPrec)  :: dbla_data        ! Data input
      INTEGER(HSIZE_T) :: i_offset
      REAL(KIND=qPREC), TARGET, DIMENSION(1) :: dbla_buffer
      REAL(KIND=qPREC), POINTER, DIMENSION(:) :: dbla_data_vec
      dbla_buffer(1)=dbla_data
      dbla_data_vec=>dbla_buffer
      CALL Write_Slab_To_Dataset_Double_array(s_dataset_name, hid_group_id, dbla_data_vec, i_offset)

   END SUBROUTINE Write_Slab_To_Dataset_Double_scalar
   !> Writes a slab of data to a dataset.
   !! @param s_dataset_name The dataset's name.
   !! @param hid_group_id The group ID within the file where the dataset will reside.
   !! @param dbla_data The slab of data to be written to the dataset.
   !! @param i_offset The offset within the dataset to where the hyperslab should begin writing.
   SUBROUTINE Write_Slab_To_Dataset_Double_array(s_dataset_name, hid_group_id, dbla_data, i_offset)

      CHARACTER(LEN=*), INTENT(IN) :: s_dataset_name
      INTEGER(HID_T) :: hid_group_id
      REAL(KIND=qPrec), DIMENSION(:) :: dbla_data        ! Data input
      INTEGER(HSIZE_T) :: i_offset

      INTEGER(HID_T) :: hid_dataset_id
      INTEGER(HID_T) :: hid_dataspace_id
      INTEGER(HID_T) :: hid_memspace_id
      INTEGER(HID_T) :: hid_property_list_id                ! Property list handle.
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_data_offset
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_slab_size
      INTEGER(HSIZE_T), DIMENSION(1) :: dims
      INTEGER(HSIZE_T), DIMENSION(1) :: maxdims
      INTEGER :: i_err


      i_err = 0

      ! Set the size of the hyperslab.
      ia_slab_size(1) = SIZE(dbla_data)

      ! Store the size of the offset in a dimension array.
      ia_data_offset(1) = i_offset

      ! Open the dataset in the HDF5 file.
      CALL h5dopen_f(hid_group_id, s_dataset_name, hid_dataset_id, i_err)

      CALL h5dget_space_f(hid_dataset_id, hid_dataspace_id, i_err)

      ! Extract the dimensions of said dataspace.
      CALL h5sget_simple_extent_dims_f(hid_dataspace_id, dims, maxdims, i_err)

      ! If the dataset is extensible and is about to overflow, then extend the dataset
      ! to accomodate the new size.
      IF ((maxdims(1) == H5S_UNLIMITED_F) .AND. (ia_slab_size(1) + ia_data_offset(1) > dims(1))) THEN

         ! Extend the dataspace.
         CALL h5sset_extent_simple_f(hid_dataspace_id, I_DATASET_RANK, ia_slab_size + ia_data_offset, maxdims, i_err)

         CALL h5dset_extent_f(hid_dataset_id, ia_slab_size + ia_data_offset, i_err)

      END IF

      ! Extract the dimensions of said dataspace.
      CALL h5sget_simple_extent_dims_f(hid_dataspace_id, dims, maxdims, i_err)

      ! Select hyperslab in the dataset (specifically, the dimensions of the input array).
      CALL h5sselect_hyperslab_f(hid_dataspace_id, H5S_SELECT_SET_F, ia_data_offset, ia_slab_size, i_err) 

      ! Create dataspace for the upcoming hyperslab.
      IF (size(dbla_data) > 0) CALL h5screate_simple_f(I_DATASET_RANK, ia_slab_size, hid_memspace_id, i_err)


# if defined _PHDF5
      IF (lParallelHDF5) THEN

         ! Create property list for collective dataset write
         !
         CALL h5pcreate_f(H5P_DATASET_XFER_F, hid_property_list_id, i_err)
         CALL h5pset_dxpl_mpio_f(hid_property_list_id, H5FD_MPIO_INDEPENDENT_F, i_err)

         !
         ! Write the dataset collectively.
         !
         IF (size(dbla_data) > 0) CALL h5dwrite_f(hid_dataset_id, H5T_NATIVE_DOUBLE, dbla_data, ia_slab_size,i_err, hid_memspace_id, hid_dataspace_id, xfer_prp = hid_property_list_id) 
         CALL h5pclose_f(hid_property_list_id, i_err)
      ELSE
         CALL h5dwrite_f(hid_dataset_id, H5T_NATIVE_DOUBLE, dbla_data, ia_slab_size, i_err, hid_memspace_id, hid_dataspace_id)

      END IF
# else
      ! Write the HDF5 data to the dataset.
      CALL h5dwrite_f(hid_dataset_id, H5T_NATIVE_DOUBLE, dbla_data, ia_slab_size, i_err, hid_memspace_id, hid_dataspace_id)
# endif



      IF (size(dbla_data) > 0) CALL h5sclose_f(hid_memspace_id,i_err)

      ! Close main file memory dataspace.
      CALL h5sclose_f(hid_dataspace_id, i_err)

      CALL h5dclose_f(hid_dataset_id, i_err)

   END SUBROUTINE Write_Slab_To_Dataset_Double_array



   SUBROUTINE Initialize_HDF5_Dataset_Box_2(s_name, hid_group_id, raw_data_size, lExtensible)
      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      INTEGER(8) :: raw_data_size8
      INTEGER :: raw_data_size
      LOGICAL, OPTIONAL :: lExtensible
      LOGICAL :: l_extend

      IF (PRESENT(lExtensible)) THEN
         l_extend = lExtensible
      ELSE
         l_extend = .TRUE.
      END IF
      raw_data_size8=raw_data_size
      CALL Initialize_HDF5_Dataset_Box_1(s_name, hid_group_id, raw_data_size8, l_extend)
   END SUBROUTINE Initialize_HDF5_Dataset_Box_2

   !> Initializes a Box-type dataset within a HDF5 file.
   !! @param s_name The dataset's name.
   !! @param hid_group_id The group ID within the file where the dataset will reside.
   !! @param i_dataset_size The size of the dataset.
   !! @param lExtensible An optional parameter controlling the extensibility of the dataset.
   SUBROUTINE Initialize_HDF5_Dataset_Box_1(s_name, hid_group_id, raw_data_size, lExtensible)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new dataset.
      INTEGER(8) :: raw_data_size
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      !     initialize the dataspace.
      LOGICAL, OPTIONAL :: lExtensible

      INTEGER(HSIZE_T) :: i_dataset_size               ! Size of forthcoming data array, used to
      INTEGER(HID_T) :: hid_dataspace_id                ! Dataspace handle.
      INTEGER(HID_T) :: hid_dataset_id                ! Dataset handle.
      INTEGER(HID_T) :: hid_property_list_id                ! Property list handle.
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_dataset_dims    ! Array to hold the size of the input.
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_chunk_dims
      LOGICAL :: l_extend
      INTEGER :: i_err


      i_dataset_size = raw_data_size

      IF (PRESENT(lExtensible)) THEN
         l_extend = lExtensible
      ELSE
         l_extend = .TRUE.
      END IF

      ia_dataset_dims(1) = i_dataset_size

      ! The dataset chunk size is whatever is smaller--the dataset size, or the maximum dataset
      ! chunk size in doubles.  Under no circumstances should the chunk size be less than 1.
      ia_chunk_dims(1) = MAX(MIN(i_dataset_size, GetChunkSize(hid_box_id)), INT(1, HSIZE_T))

      ! Create the new dataspace.  The H5S_UNLIMITED_F maxdims value is required for extensibility.
      IF (l_extend) THEN
         CALL h5screate_simple_f(I_DATASET_RANK, ia_dataset_dims, hid_dataspace_id, i_err, (/INT(H5S_UNLIMITED_F, HSIZE_T) /))
      ELSE
         CALL h5screate_simple_f(I_DATASET_RANK, ia_dataset_dims, hid_dataspace_id, i_err)
      END IF


      ! Create the property list for this dataset.
      CALL h5pcreate_f(H5P_DATASET_CREATE_F, hid_property_list_id, i_err)

      ! Chunk the dataset for compression.
      CALL h5pset_chunk_f(hid_property_list_id, I_DATASET_RANK, ia_chunk_dims, i_err)

      ! Forces the dataset to allocate the space at creation time.
      CALL h5pset_alloc_time_f(hid_property_list_id, H5D_ALLOC_TIME_EARLY_F, i_err)

      ! Set the dataset to use gzip compression (default for deflate option).
      !    CALL h5pset_deflate_f(hid_property_list_id,I_DEFLATE_LEVEL,i_err)

      ! Create the new dataset.
      CALL h5dcreate_f(hid_group_id, s_name, hid_box_id, hid_dataspace_id, hid_dataset_id, i_err, hid_property_list_id)

      CALL h5dclose_f(hid_dataset_id, i_err)        ! Close the dataset.

      CALL h5pclose_f(hid_property_list_id, i_err)    ! Close the property list.

      CALL h5sclose_f(hid_dataspace_id, i_err)    ! Close the dataspace.

   END SUBROUTINE Initialize_HDF5_Dataset_Box_1


   !> Writes a slab of data to a Box-type dataset.
   !! @param s_dataset_name The dataset's name.
   !! @param hid_group_id The group ID within the file where the dataset will reside.
   !! @param box_data The slab of data to be written to the dataset.
   !! @param i_offset The offset within the dataset to where the hyperslab should begin writing.
   SUBROUTINE Write_Slab_To_Dataset_Box(s_dataset_name, hid_group_id, data, i_offset)
      CHARACTER(LEN=*), INTENT(IN) :: s_dataset_name
      INTEGER(HID_T) :: hid_group_id
      INTEGER, DIMENSION(:) :: data        ! Data input
      INTEGER(HSIZE_T) :: i_offset

      INTEGER(HID_T) :: hid_dataset_id
      INTEGER(HID_T) :: hid_dataspace_id
      INTEGER(HID_T) :: hid_memspace_id
      INTEGER(HID_T) :: hid_property_list_id

      INTEGER(HSIZE_T), DIMENSION(1) :: ia_data_offset
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_slab_size
      INTEGER(HSIZE_T), DIMENSION(1) :: dims
      INTEGER(HSIZE_T), DIMENSION(1) :: maxdims
      INTEGER :: i_err

      i_err = 0

      ! Set the size of the hyperslab.
      ia_slab_size(1) = SIZE(data) / I_CHOMBO_BOX_SIZE

      ! Store the size of the offset in a dimension array.
      ia_data_offset(1) = i_offset

      ! Open the dataset in the HDF5 file.
      CALL h5dopen_f(hid_group_id, s_dataset_name, hid_dataset_id, i_err)

      CALL h5dget_space_f(hid_dataset_id, hid_dataspace_id, i_err)

      ! Select hyperslab in the dataset (specifically, the dimensions of the input array).
      CALL h5sselect_hyperslab_f(hid_dataspace_id, H5S_SELECT_SET_F, ia_data_offset, ia_slab_size, i_err) 

      ! Extract the dimensions of said dataspace.
      CALL h5sget_simple_extent_dims_f(hid_dataspace_id, dims, maxdims, i_err)

      ! If the dataset is extensible and is about to overflow, then extend the dataset
      ! to accomodate the new size.
      IF ((maxdims(1) == H5S_UNLIMITED_F) .AND. (ia_slab_size(1) + ia_data_offset(1) > dims(1))) THEN

         ! Extend the dataspace.
         CALL h5sset_extent_simple_f(hid_dataspace_id, I_DATASET_RANK, ia_slab_size + ia_data_offset, maxdims, i_err)

         CALL h5dset_extent_f(hid_dataset_id, ia_slab_size + ia_data_offset, i_err)

      END IF

      ! Extract the dimensions of said dataspace.
      CALL h5sget_simple_extent_dims_f(hid_dataspace_id, dims, maxdims, i_err)


      ! Create dataspace for the upcoming hyperslab.
      IF (size(data) > 0) CALL h5screate_simple_f(I_DATASET_RANK, ia_slab_size, hid_memspace_id, i_err)


# if defined _PHDF5
      IF (lParallelHDF5) THEN
         !
         ! Create property list for collective dataset write
         !
         CALL h5pcreate_f(H5P_DATASET_XFER_F, hid_property_list_id, i_err)

         CALL h5pset_dxpl_mpio_f(hid_property_list_id, H5FD_MPIO_INDEPENDENT_F, i_err)
         !
         ! Write the dataset collectively.
         !

         IF (size(data) > 0) CALL h5dwrite_f(hid_dataset_id, hid_box_id, data, ia_slab_size, i_err, hid_memspace_id, hid_dataspace_id, xfer_prp = hid_property_list_id)
         CALL h5pclose_f(hid_property_list_id, i_err)
      ELSE
         CALL h5dwrite_f(hid_dataset_id, hid_box_id, data, ia_slab_size, i_err, hid_memspace_id, hid_dataspace_id)

      END IF
# else
      ! Write the HDF5 data to the dataset.
      CALL h5dwrite_f(hid_dataset_id, hid_box_id, data, ia_slab_size, i_err, hid_memspace_id, hid_dataspace_id)
# endif


      IF (size(data) > 0) CALL h5sclose_f(hid_memspace_id,i_err)

      ! Close main file memory dataspace.
      CALL h5sclose_f(hid_dataspace_id, i_err)

      CALL h5dclose_f(hid_dataset_id, i_err)
   END SUBROUTINE Write_Slab_To_Dataset_Box

   SUBROUTINE Initialize_HDF5_Dataset_Int_2(s_name, hid_group_id, raw_data_size, lExtensible)
      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      INTEGER(8) :: raw_data_size8
      INTEGER :: raw_data_size
      LOGICAL, OPTIONAL :: lExtensible
      LOGICAL :: l_extend

      IF (PRESENT(lExtensible)) THEN
         l_extend = lExtensible
      ELSE
         l_extend = .TRUE.
      END IF

      raw_data_size8=raw_data_size
      CALL Initialize_HDF5_Dataset_Int_1(s_name, hid_group_id, raw_data_size8, l_extend)
   END SUBROUTINE Initialize_HDF5_Dataset_Int_2

   !> Initializes an integer dataset within the HDF5 file.
   !! @param s_name The dataset's name.
   !! @param hid_group_id The group ID within the file where the dataset will reside.
   !! @param raw_data_size The size of the dataset.
   !! @param lExtensible An optional parameter controlling the extensibility of the dataset.
   SUBROUTINE Initialize_HDF5_Dataset_Int_1(s_name, hid_group_id, raw_data_size, lExtensible)

      IMPLICIT NONE

      ! Input parameter declarations
      CHARACTER(LEN=*), INTENT(IN) :: s_name            ! Name of new dataset.
      INTEGER(HID_T), INTENT(IN) :: hid_group_id        ! Group identifier.
      INTEGER(8) :: raw_data_size
      !     initialize the dataspace.
      LOGICAL, OPTIONAL :: lExtensible

      INTEGER(HSIZE_T) :: i_dataset_size               ! Size of forthcoming data array, used to
      INTEGER(HID_T) :: hid_dataspace_id                ! Dataspace handle.
      INTEGER(HID_T) :: hid_dataset_id                ! Dataset handle.
      INTEGER(HID_T) :: hid_property_list_id                ! Property list handle.
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_dataset_dims    ! Array to hold the size of the input.
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_chunk_dims
      LOGICAL :: l_extend
      INTEGER :: i_err


      i_dataset_size = raw_data_size

      IF (PRESENT(lExtensible)) THEN
         l_extend = lExtensible
      ELSE
         l_extend = .TRUE.
      END IF

      ia_dataset_dims(1) = i_dataset_size

      ! The dataset chunk size is whatever is smaller--the dataset size, or the maximum dataset
      ! chunk size in doubles.  Under no circumstances should the chunk size be less than 1.
      ia_chunk_dims(1) = MAX(MIN(i_dataset_size, GetChunkSize(H5T_NATIVE_INTEGER)), INT(1, HSIZE_T))

      ! Create the new dataspace.  The H5S_UNLIMITED_F maxdims value is required for extensibility.
      IF (l_extend) THEN
         CALL h5screate_simple_f(I_DATASET_RANK, ia_dataset_dims, hid_dataspace_id, i_err, (/INT(H5S_UNLIMITED_F, HSIZE_T) /))
      ELSE
         CALL h5screate_simple_f(I_DATASET_RANK, ia_dataset_dims, hid_dataspace_id, i_err)
      END IF


      ! Create the property list for this dataset.
      CALL h5pcreate_f(H5P_DATASET_CREATE_F, hid_property_list_id, i_err)

      ! Chunk the dataset for compression.
      CALL h5pset_chunk_f(hid_property_list_id, I_DATASET_RANK, ia_chunk_dims, i_err)

      ! Forces the dataset to allocate the space at creation time.
      CALL h5pset_alloc_time_f(hid_property_list_id, H5D_ALLOC_TIME_EARLY_F, i_err)

      ! Set the dataset to use gzip compression (default for deflate option).
      !    CALL h5pset_deflate_f(hid_property_list_id,I_DEFLATE_LEVEL,i_err)

      ! Create the new dataset.
      CALL h5dcreate_f(hid_group_id, s_name, H5T_NATIVE_INTEGER, hid_dataspace_id, hid_dataset_id, i_err, hid_property_list_id)

      CALL h5dclose_f(hid_dataset_id, i_err)        ! Close the dataset.

      CALL h5pclose_f(hid_property_list_id, i_err)    ! Close the property list.

      CALL h5sclose_f(hid_dataspace_id, i_err)    ! Close the dataspace.

   END SUBROUTINE Initialize_HDF5_Dataset_Int_1


   SUBROUTINE Write_Slab_To_Dataset_Int_scalar(s_dataset_name, hid_group_id, dbla_data, i_offset)

      CHARACTER(LEN=*), INTENT(IN) :: s_dataset_name
      INTEGER(HID_T) :: hid_group_id
      INTEGER  :: dbla_data        ! Data input
      INTEGER(HSIZE_T) :: i_offset
      INTEGER, TARGET, DIMENSION(1) :: dbla_buffer
      INTEGER, POINTER, DIMENSION(:) :: dbla_data_vec
      dbla_buffer(1)=dbla_data
      dbla_data_vec=>dbla_buffer
      CALL Write_Slab_To_Dataset_Int_array(s_dataset_name, hid_group_id, dbla_data_vec, i_offset)
   END SUBROUTINE Write_Slab_To_Dataset_Int_scalar

   !> Writes a slab of data to a dataset.
   !! @param s_dataset_name The dataset's name.
   !! @param hid_group_id The group ID within the file where the dataset will reside.
   !! @param int_data The slab of data to be written to the dataset.
   !! @param i_offset The offset within the dataset to where the hyperslab should begin writing.
   SUBROUTINE Write_Slab_To_Dataset_Int_array(s_dataset_name, hid_group_id, int_data, i_offset)

      CHARACTER(LEN=*), INTENT(IN) :: s_dataset_name
      INTEGER(HID_T) :: hid_group_id
      INTEGER, DIMENSION(:) :: int_data        ! Data input
      INTEGER(HSIZE_T) :: i_offset

      INTEGER(HID_T) :: hid_dataset_id
      INTEGER(HID_T) :: hid_dataspace_id
      INTEGER(HID_T) :: hid_memspace_id
      INTEGER(HID_T) :: hid_property_list_id

      INTEGER(HSIZE_T), DIMENSION(1) :: ia_data_offset
      INTEGER(HSIZE_T), DIMENSION(1) :: ia_slab_size
      INTEGER(HSIZE_T), DIMENSION(1) :: dims
      INTEGER(HSIZE_T), DIMENSION(1) :: maxdims
      INTEGER :: i_err


      i_err = 0

      ! Set the size of the hyperslab.
      ia_slab_size(1) = SIZE(int_data)

      ! Store the size of the offset in a dimension array.
      ia_data_offset(1) = i_offset

      ! Open the dataset in the HDF5 file.
      CALL h5dopen_f(hid_group_id, s_dataset_name, hid_dataset_id, i_err)

      CALL h5dget_space_f(hid_dataset_id, hid_dataspace_id, i_err)

      ! Extract the dimensions of said dataspace.
      CALL h5sget_simple_extent_dims_f(hid_dataspace_id, dims, maxdims, i_err)

      ! If the dataset is extensible and is about to overflow, then extend the dataset
      ! to accomodate the new size.
      IF ((maxdims(1) == H5S_UNLIMITED_F) .AND. (ia_slab_size(1) + ia_data_offset(1) > dims(1))) THEN

         ! Extend the dataspace.
         CALL h5sset_extent_simple_f(hid_dataspace_id, I_DATASET_RANK, ia_slab_size + ia_data_offset, maxdims, i_err)


         CALL h5dset_extent_f(hid_dataset_id, ia_slab_size + ia_data_offset, i_err)

      END IF

      ! Select hyperslab in the dataset (specifically, the dimensions of the input array).
      CALL h5sselect_hyperslab_f(hid_dataspace_id, H5S_SELECT_SET_F, ia_data_offset, ia_slab_size, i_err) 

      ! Create dataspace for the upcoming hyperslab.
      IF (SIZE(int_data) > 0) CALL h5screate_simple_f(I_DATASET_RANK, ia_slab_size, hid_memspace_id, i_err)


# if defined _PHDF5
      IF (lParallelHDF5) THEN
         !
         ! Create property list for collective dataset write
         !
         CALL h5pcreate_f(H5P_DATASET_XFER_F, hid_property_list_id, i_err)

         CALL h5pset_dxpl_mpio_f(hid_property_list_id, H5FD_MPIO_INDEPENDENT_F, i_err)
         !
         ! Write the dataset collectively.
         !
         IF (size(int_data) > 0) CALL h5dwrite_f(hid_dataset_id, H5T_NATIVE_INTEGER, int_data, ia_slab_size, i_err, hid_memspace_id, hid_dataspace_id, xfer_prp = hid_property_list_id)
         CALL h5pclose_f(hid_property_list_id, i_err)
      ELSE
         CALL h5dwrite_f(hid_dataset_id, H5T_NATIVE_INTEGER, int_data, ia_slab_size, i_err, hid_memspace_id, hid_dataspace_id)

      END IF
# else
      ! Write the HDF5 data to the dataset.
      CALL h5dwrite_f(hid_dataset_id, H5T_NATIVE_INTEGER, int_data, ia_slab_size, i_err, hid_memspace_id, hid_dataspace_id)
# endif

      IF (size(int_data) > 0) CALL h5sclose_f(hid_memspace_id,i_err)

      ! Close main file memory dataspace.
      CALL h5sclose_f(hid_dataspace_id, i_err)

      CALL h5dclose_f(hid_dataset_id, i_err)

   END SUBROUTINE Write_Slab_To_Dataset_Int_array

   !> @}
   !================================= End write subroutines ===============================

   !> Returns the maximum chunk size in terms of the input type (I_MAX_CHUNK_SIZE is given in bytes).
   !! @param hid_type_id A chombo type ID handle.
   INTEGER(HSIZE_T) FUNCTION GetChunkSize(hid_type_id)

      INTEGER(HID_T) :: hid_type_id

      INTEGER(size_t) :: type_size
      INTEGER :: i_err


      ! Get the type's size in bytes.
      CALL h5tget_size_f(hid_type_id, type_size, i_err)

      ! Obtain the size of the chunk in type elements.
      GetChunkSize = FLOOR(I_MAX_CHUNK_SIZE * 1.0 / type_size)

   END FUNCTION GetChunkSize

END MODULE HDF5Declarations
#endif
