diff --git a/examples/hello/hdf5Writer/helloHDF5Writer.cpp b/examples/hello/hdf5Writer/helloHDF5Writer.cpp
index ecfe1b940a2bf105f93f4477a23a4d02e5f02b88..07088fb2ee76ab6276b5214960cb3836ce153c80 100644
--- a/examples/hello/hdf5Writer/helloHDF5Writer.cpp
+++ b/examples/hello/hdf5Writer/helloHDF5Writer.cpp
@@ -8,10 +8,10 @@
 #include <iostream>
 #include <vector>
 
-#include <mpi.h>
-
 #include <adios2.h>
 
+#include <mpi.h>
+
 int main(int argc, char *argv[])
 {
     MPI_Init(&argc, &argv);
@@ -65,6 +65,11 @@ int main(int argc, char *argv[])
         intCountDim1 = intDim1 - rank * (intDim1 / size);
     }
 
+    std::cout << " rank=" << rank << " of " << size
+              << ",  dim1 count: " << intCountDim1
+              << ", offset: " << intOffsetDim1 << std::endl;
+    std::cout << " intOffsetDim2=" << intOffsetDim2 << " " << intDim2
+              << std::endl;
     try
     {
         // Define variable and local size
@@ -83,7 +88,7 @@ int main(int argc, char *argv[])
 
         // Define method for engine creation, it is basically straight-forward
         // parameters
-        adios::Method &HDF5Settings = adios.DeclareMethod("w");
+        adios::Method &HDF5Settings = adios.DeclareMethod("hdf5");
         HDF5Settings.SetEngine("HDF5Writer");
         HDF5Settings.SetParameters("chunck=yes", "collectiveIO=yes");
         // HDF5Settings.AddTransport( "Mdtm", "localIP=128.0.0.0.1",
@@ -98,19 +103,36 @@ int main(int argc, char *argv[])
             throw std::ios_base::failure(
                 "ERROR: failed to create HDF5 I/O engine at Open\n");
 
-        HDF5Writer->Write(ioMyDoubles, myDoubles.data() +
-                                           doubleVOffset); // Base class Engine
-                                                           // own the Write<T>
-                                                           // that will call
-                                                           // overloaded Write
-                                                           // from Derived
-        HDF5Writer->Write(ioMyInts,
-                          myInts.data() + (intOffsetDim1 * intDim2 * rank));
-
-        HDF5Writer->Write(ioMyCFloats, myCFloats.data() + complexOffset);
-        HDF5Writer->Write(ioMyCDoubles, myCDoubles.data() + complexOffset);
-        HDF5Writer->Write(ioMyCLongDoubles,
-                          myCLongDoubles.data() + complexOffset);
+        int ts = 0;
+        int totalts = 3;
+        while (true)
+        {
+            if (rank == 0)
+            {
+                std::cout << " total timesteps: " << totalts << " curr: " << ts
+                          << " th" << std::endl;
+            }
+            HDF5Writer->Write(ioMyDoubles,
+                              myDoubles.data() +
+                                  doubleVOffset); // Base class Engine
+            // own the Write<T>
+            // that will call
+            // overloaded Write
+            // from Derived
+            HDF5Writer->Write(ioMyInts,
+                              myInts.data() + (intOffsetDim1 * intDim2));
+
+            HDF5Writer->Write(ioMyCFloats, myCFloats.data() + complexOffset);
+            HDF5Writer->Write(ioMyCDoubles, myCDoubles.data() + complexOffset);
+            HDF5Writer->Write(ioMyCLongDoubles,
+                              myCLongDoubles.data() + complexOffset);
+            ts++;
+            if (ts >= totalts)
+            {
+                break;
+            }
+            HDF5Writer->Advance();
+        }
         HDF5Writer->Close();
     }
     catch (std::invalid_argument &e)
diff --git a/source/adios2/ADIOS.cpp b/source/adios2/ADIOS.cpp
index ac4725a53e4257fe58e1a06bef1e10578db4fb52..8fd661a80b0c3f3a15446728afa25955965cd928 100644
--- a/source/adios2/ADIOS.cpp
+++ b/source/adios2/ADIOS.cpp
@@ -194,7 +194,16 @@ std::shared_ptr<Engine> ADIOS::Open(const std::string &name,
                                     "HDF5 library, can't use HDF5\n");
 #endif
     }
-
+    else if (type == "HDF5Reader") // -Junmin
+    {
+#ifdef ADIOS2_HAVE_HDF5
+        return std::make_shared<HDF5Reader>(*this, name, accessMode, mpiComm,
+                                            method);
+#else
+        throw std::invalid_argument("ERROR: this version didn't compile with "
+                                    "HDF5 library, can't use HDF5\n");
+#endif
+    }
     else
     {
         if (m_DebugMode == true)
diff --git a/source/adios2/CMakeLists.txt b/source/adios2/CMakeLists.txt
index 7099e25b265fc69134904739ca277005eaceaac7..98e2c4ac25dcdc10b65df177971933d7c0b6d46f 100644
--- a/source/adios2/CMakeLists.txt
+++ b/source/adios2/CMakeLists.txt
@@ -106,6 +106,7 @@ if(ADIOS_USE_HDF5)
   target_sources(adios2 PRIVATE
     engine/hdf5/HDF5ReaderP.cpp
     engine/hdf5/HDF5WriterP.cpp
+    engine/hdf5/HDF5Common.cpp
   )
   target_link_libraries(adios2 PRIVATE ${HDF5_C_LIBRARIES})
 endif()
diff --git a/source/adios2/engine/hdf5/HDF5Common.cpp b/source/adios2/engine/hdf5/HDF5Common.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e2a9c521ee6b08d50094910ea43e85920d395350
--- /dev/null
+++ b/source/adios2/engine/hdf5/HDF5Common.cpp
@@ -0,0 +1,223 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * HDF5Common.cpp
+ *
+ *  Created on: April 20, 2017
+ *      Author: Junmin
+ */
+
+#include "HDF5Common.h"
+
+#include <complex>
+#include <iostream>
+
+#include "adios2/ADIOSMPI.h"
+
+namespace adios
+{
+
+#define H5_ERROR std::cout << "[ADIOS H5 ERROR] "
+
+HDF5Common::HDF5Common()
+: m_WriteMode(false), m_CurrentTimeStep(0), m_NumTimeSteps(0)
+{
+    m_DefH5TypeComplexFloat =
+        H5Tcreate(H5T_COMPOUND, sizeof(std::complex<float>));
+    H5Tinsert(m_DefH5TypeComplexFloat, "freal", 0, H5T_NATIVE_FLOAT);
+    H5Tinsert(m_DefH5TypeComplexFloat, "fimg", H5Tget_size(H5T_NATIVE_FLOAT),
+              H5T_NATIVE_FLOAT);
+
+    m_DefH5TypeComplexDouble =
+        H5Tcreate(H5T_COMPOUND, sizeof(std::complex<double>));
+    H5Tinsert(m_DefH5TypeComplexDouble, "dreal", 0, H5T_NATIVE_DOUBLE);
+    H5Tinsert(m_DefH5TypeComplexDouble, "dimg", H5Tget_size(H5T_NATIVE_DOUBLE),
+              H5T_NATIVE_DOUBLE);
+
+    m_DefH5TypeComplexLongDouble =
+        H5Tcreate(H5T_COMPOUND, sizeof(std::complex<long double>));
+    H5Tinsert(m_DefH5TypeComplexLongDouble, "ldouble real", 0,
+              H5T_NATIVE_LDOUBLE);
+    H5Tinsert(m_DefH5TypeComplexLongDouble, "ldouble img",
+              H5Tget_size(H5T_NATIVE_LDOUBLE), H5T_NATIVE_LDOUBLE);
+}
+
+void HDF5Common::Init(const std::string name, MPI_Comm comm, bool toWrite)
+{
+    m_WriteMode = toWrite;
+
+    //
+    m_PropertyListId = H5Pcreate(H5P_FILE_ACCESS);
+
+#ifdef ADIOS2_HAVE_MPI
+    H5Pset_fapl_mpio(m_PropertyListId, comm, MPI_INFO_NULL);
+#endif
+
+    std::string ts0 = "/TimeStep0";
+
+    if (toWrite)
+    {
+        /*
+         * Create a new file collectively and release property list identifier.
+         */
+        m_FileId = H5Fcreate(name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT,
+                             m_PropertyListId);
+        if (m_FileId >= 0)
+        {
+            m_GroupId = H5Gcreate2(m_FileId, ts0.c_str(), H5P_DEFAULT,
+                                   H5P_DEFAULT, H5P_DEFAULT);
+            if (m_GroupId < 0)
+            {
+                std::clog << "H5Common::Init: ERROR" << std::endl;
+                throw std::runtime_error("HDF5: Unable to create group " + ts0);
+            }
+        }
+    }
+    else
+    {
+        // read a file collectively
+        m_FileId = H5Fopen(name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
+        if (m_FileId >= 0)
+        {
+            m_GroupId = H5Gopen(m_FileId, ts0.c_str(), H5P_DEFAULT);
+        }
+    }
+
+    H5Pclose(m_PropertyListId);
+}
+
+void HDF5Common::WriteTimeSteps()
+{
+    if (m_FileId < 0)
+    {
+        // std::cerr<<"[ADIOS HDF5Error]: Invalid file to record timestep
+        // to."<<std::endl;
+        H5_ERROR << "Invalid file to record timestep to." << std::endl;
+        return;
+    }
+
+    if (!m_WriteMode)
+    {
+        return;
+    }
+
+    hid_t s = H5Screate(H5S_SCALAR);
+
+    hid_t attr = H5Acreate(m_FileId, "NumTimeSteps", H5T_NATIVE_UINT, s,
+                           H5P_DEFAULT, H5P_DEFAULT);
+    uint totalTimeSteps = m_CurrentTimeStep + 1;
+
+    if (m_GroupId < 0)
+    {
+        totalTimeSteps = m_CurrentTimeStep;
+    }
+
+    H5Awrite(attr, H5T_NATIVE_UINT, &totalTimeSteps);
+
+    H5Sclose(s);
+    H5Aclose(attr);
+}
+
+unsigned int HDF5Common::GetNumTimeSteps()
+{
+    if (m_WriteMode)
+    {
+        return -1;
+    }
+
+    if (m_FileId < 0)
+    {
+        std::cerr
+            << "[ADIOS HDF5Error]: Invalid file to read timestep attribute."
+            << std::endl;
+        return -1;
+    }
+
+    if (m_NumTimeSteps <= 0)
+    {
+        hid_t attr = H5Aopen(m_FileId, "NumTimeSteps", H5P_DEFAULT);
+
+        H5Aread(attr, H5T_NATIVE_UINT, &m_NumTimeSteps);
+        H5Aclose(attr);
+    }
+
+    return m_NumTimeSteps;
+}
+
+void HDF5Common::Close()
+{
+    if (m_FileId < 0)
+    {
+        return;
+    }
+
+    WriteTimeSteps();
+
+    if (m_GroupId >= 0)
+    {
+        H5Gclose(m_GroupId);
+    }
+
+    H5Fclose(m_FileId);
+    m_FileId = -1;
+    m_GroupId = -1;
+}
+
+void HDF5Common::Advance()
+{
+    if (m_GroupId >= 0)
+    {
+        H5Gclose(m_GroupId);
+        m_GroupId = -1;
+    }
+
+    if (m_WriteMode)
+    {
+        // m_GroupId = H5Gcreate2(m_FileId, tsname.c_str(), H5P_DEFAULT,
+        //                       H5P_DEFAULT, H5P_DEFAULT);
+    }
+    else
+    {
+        if (m_NumTimeSteps == 0)
+        {
+            GetNumTimeSteps();
+        }
+        if (m_CurrentTimeStep + 1 >= m_NumTimeSteps)
+        {
+            return;
+        }
+
+        std::string timeStepName =
+            "/TimeStep" + std::to_string(m_CurrentTimeStep + 1);
+        m_GroupId = H5Gopen(m_FileId, timeStepName.c_str(), H5P_DEFAULT);
+        if (m_GroupId < 0)
+        {
+            throw std::runtime_error("HDF5: Unable to open group " +
+                                     timeStepName);
+        }
+    }
+    ++m_CurrentTimeStep;
+}
+
+void HDF5Common::CheckWriteGroup()
+{
+    if (!m_WriteMode)
+    {
+        return;
+    }
+    if (m_GroupId >= 0)
+    {
+        return;
+    }
+
+    std::string timeStepName = "/TimeStep" + std::to_string(m_CurrentTimeStep);
+    m_GroupId = H5Gcreate2(m_FileId, timeStepName.c_str(), H5P_DEFAULT,
+                           H5P_DEFAULT, H5P_DEFAULT);
+    if (m_GroupId < 0)
+    {
+        throw std::runtime_error("HDF5: Unable to create group " +
+                                 timeStepName);
+    }
+}
+}
diff --git a/source/adios2/engine/hdf5/HDF5Common.h b/source/adios2/engine/hdf5/HDF5Common.h
new file mode 100644
index 0000000000000000000000000000000000000000..d5a6a77190b1ed2465bf62b82073835b061afe27
--- /dev/null
+++ b/source/adios2/engine/hdf5/HDF5Common.h
@@ -0,0 +1,57 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * HDF5CommonP.h
+ *
+ *  Created on: March 20, 2017
+ *      Author: Junmin
+ */
+
+#ifndef ADIOS2_ENGINE_HDF5_HDF5COMMON_P_H_
+#define ADIOS2_ENGINE_HDF5_HDF5COMMON_P_H_
+
+#include <string>
+
+#include "adios2/ADIOSMPICommOnly.h"
+
+#include <hdf5.h>
+
+namespace adios
+{
+
+class HDF5Common
+{
+
+public:
+    /**
+     * Constructor for HDF5 file
+     */
+    HDF5Common();
+
+    void Init(const std::string name, MPI_Comm comm, bool toWrite);
+    void Close();
+    void Advance();
+
+    unsigned int GetNumTimeSteps();
+    void WriteTimeSteps();
+
+    hid_t m_PropertyListId, m_FileId;
+    hid_t m_GroupId;
+
+    hid_t m_DefH5TypeComplexDouble;
+    hid_t m_DefH5TypeComplexFloat;
+    hid_t m_DefH5TypeComplexLongDouble;
+
+    unsigned int m_CurrentTimeStep;
+
+    void CheckWriteGroup();
+
+private:
+    bool m_WriteMode;
+    unsigned int m_NumTimeSteps;
+};
+
+} // end namespace adios
+
+#endif /* ADIOS2_ENGINE_HDF5_HDF5COMMON_P_H_ */
diff --git a/source/adios2/engine/hdf5/HDF5ReaderP.cpp b/source/adios2/engine/hdf5/HDF5ReaderP.cpp
index 782135c00da4f7ef2e0f18fd2aa17e48277e97ea..7f3ead729cae47aaa634e6a0d2365a2294584a06 100644
--- a/source/adios2/engine/hdf5/HDF5ReaderP.cpp
+++ b/source/adios2/engine/hdf5/HDF5ReaderP.cpp
@@ -10,4 +10,249 @@
 
 #include "HDF5ReaderP.h"
 
-#include <iostream> //needs to go away, this is just for demo purposes
+#include "adios2/ADIOSMPI.h"
+
+namespace adios
+{
+
+HDF5Reader::HDF5Reader(ADIOS &adios, const std::string name,
+                       const std::string accessMode, MPI_Comm mpiComm,
+                       const Method &method)
+: Engine(adios, "HDF5Reader", name, accessMode, mpiComm, method,
+         " HDF5Reader constructor (or call to ADIOS Open).\n")
+
+{
+    Init();
+}
+
+HDF5Reader::~HDF5Reader() { Close(); }
+
+bool HDF5Reader::isValid()
+{
+    if (m_AccessMode != "r" && m_AccessMode != "read")
+    {
+        return false;
+    }
+    if (m_H5File.m_FileId >= 0)
+    {
+        return true;
+    }
+}
+void HDF5Reader::Init()
+{
+    if (m_AccessMode != "r" && m_AccessMode != "read")
+    {
+        throw std::invalid_argument(
+            "ERROR: HDF5Reader doesn't support access mode " + m_AccessMode +
+            ", in call to ADIOS Open or HDF5Reader constructor\n");
+    }
+
+    m_H5File.Init(m_Name, m_MPIComm, false);
+    m_H5File.GetNumTimeSteps();
+}
+
+Variable<void> *HDF5Reader::InquireVariable(const std::string &variableName,
+                                            const bool readIn)
+{
+    std::cout << "Not implemented: HDF5Reader::InquireVariable()" << std::endl;
+    return nullptr;
+}
+
+Variable<char> *HDF5Reader::InquireVariableChar(const std::string &variableName,
+                                                const bool readIn)
+{
+    return nullptr;
+}
+
+Variable<unsigned char> *
+HDF5Reader::InquireVariableUChar(const std::string &variableName,
+                                 const bool readIn)
+{
+    return nullptr;
+}
+
+Variable<short> *
+HDF5Reader::InquireVariableShort(const std::string &variableName,
+                                 const bool readIn)
+{
+    return nullptr;
+}
+
+Variable<unsigned short> *
+HDF5Reader::InquireVariableUShort(const std::string &variableName,
+                                  const bool readIn)
+{
+    return nullptr;
+}
+
+Variable<int> *HDF5Reader::InquireVariableInt(const std::string &variableName,
+                                              const bool)
+{
+    return nullptr;
+}
+
+Variable<unsigned int> *
+HDF5Reader::InquireVariableUInt(const std::string &variableName, const bool)
+{
+    return nullptr;
+}
+
+Variable<long int> *
+HDF5Reader::InquireVariableLInt(const std::string &variableName, const bool)
+{
+    return nullptr;
+}
+
+Variable<unsigned long int> *
+HDF5Reader::InquireVariableULInt(const std::string &variableName, const bool)
+{
+    return nullptr;
+}
+
+Variable<long long int> *
+HDF5Reader::InquireVariableLLInt(const std::string &variableName, const bool)
+{
+    return nullptr;
+}
+
+Variable<unsigned long long int> *
+HDF5Reader::InquireVariableULLInt(const std::string &variableName, const bool)
+{
+    return nullptr;
+}
+
+Variable<float> *
+HDF5Reader::InquireVariableFloat(const std::string &variableName, const bool)
+{
+    return nullptr;
+}
+
+Variable<double> *
+HDF5Reader::InquireVariableDouble(const std::string &variableName, const bool)
+{
+
+    if (m_RankMPI == 0)
+    {
+        std::cout << " ... reading var: " << variableName << std::endl;
+    }
+    int totalts = m_H5File.GetNumTimeSteps();
+
+    if (m_RankMPI == 0)
+    {
+        std::cout << " ... I saw total timesteps: " << totalts << std::endl;
+    }
+
+    return nullptr;
+}
+
+Variable<long double> *
+HDF5Reader::InquireVariableLDouble(const std::string &variableName, const bool)
+{
+    return nullptr;
+}
+
+Variable<std::complex<float>> *
+HDF5Reader::InquireVariableCFloat(const std::string &variableName, const bool)
+{
+    return nullptr;
+}
+
+Variable<std::complex<double>> *
+HDF5Reader::InquireVariableCDouble(const std::string &variableName, const bool)
+{
+    return nullptr;
+}
+
+Variable<std::complex<long double>> *
+HDF5Reader::InquireVariableCLDouble(const std::string &variableName, const bool)
+{
+    return nullptr;
+}
+
+VariableCompound *
+HDF5Reader::InquireVariableCompound(const std::string &variableName,
+                                    const bool readIn)
+{
+    return nullptr;
+}
+
+template <class T>
+void HDF5Reader::UseHDFRead(const std::string &variableName, T *values,
+                            hid_t h5Type)
+{
+    hid_t dataSetId =
+        H5Dopen(m_H5File.m_GroupId, variableName.c_str(), H5P_DEFAULT);
+    if (m_RankMPI == 0)
+    {
+        std::cout << " opened to read: " << variableName << std::endl;
+    }
+
+    if (dataSetId < 0)
+    {
+        return;
+    }
+    hid_t fileSpace = H5Dget_space(dataSetId);
+
+    if (fileSpace < 0)
+    {
+        return;
+    }
+    int ndims = H5Sget_simple_extent_ndims(fileSpace);
+    hsize_t dims[ndims];
+    herr_t status_n = H5Sget_simple_extent_dims(fileSpace, dims, NULL);
+
+    hsize_t start[ndims] = {0}, count[ndims] = {0}, stride[ndims] = {1};
+
+    int totalElements = 1;
+    for (int i = 0; i < ndims; i++)
+    {
+        std::cout << " [" << i << "] th dimension: " << dims[i] << std::endl;
+        count[i] = dims[i];
+        totalElements *= dims[i];
+    }
+
+    start[0] = m_RankMPI * dims[0] / m_SizeMPI;
+    count[0] = dims[0] / m_SizeMPI;
+    if (m_RankMPI == m_SizeMPI - 1)
+    {
+        count[0] = dims[0] - count[0] * (m_SizeMPI - 1);
+        std::cout << " rank = " << m_RankMPI << ", count=" << count[0]
+                  << std::endl;
+    }
+
+    hid_t ret = H5Sselect_hyperslab(fileSpace, H5S_SELECT_SET, start, stride,
+                                    count, NULL);
+    if (ret < 0)
+    {
+        return;
+    }
+
+    hid_t memDataSpace = H5Screate_simple(ndims, count, NULL);
+
+    int elementsRead = 1;
+    for (int i = 0; i < ndims; i++)
+    {
+        elementsRead *= count[i];
+    }
+
+    T data_array[elementsRead];
+    ret = H5Dread(dataSetId, h5Type, memDataSpace, fileSpace, H5P_DEFAULT,
+                  data_array);
+
+    for (int i = 0; i < elementsRead; i++)
+    {
+        std::cout << "... rank " << m_RankMPI << "   , " << data_array[i]
+                  << std::endl;
+    }
+
+    H5Sclose(memDataSpace);
+
+    H5Sclose(fileSpace);
+    H5Dclose(dataSetId);
+}
+
+void HDF5Reader::Advance(float timeoutSec) { m_H5File.Advance(); }
+
+void HDF5Reader::Close(const int transportIndex) { m_H5File.Close(); }
+
+} // end namespace adios
diff --git a/source/adios2/engine/hdf5/HDF5ReaderP.h b/source/adios2/engine/hdf5/HDF5ReaderP.h
index 42e4dab6be48f5fdda07b7fcd5aac35bb135e63e..70c71137b5c6a4f7edc92600cae66a2ec67fb07d 100644
--- a/source/adios2/engine/hdf5/HDF5ReaderP.h
+++ b/source/adios2/engine/hdf5/HDF5ReaderP.h
@@ -11,4 +11,115 @@
 #ifndef ADIOS2_ENGINE_HDF5_HDF5READERP_H_
 #define ADIOS2_ENGINE_HDF5_HDF5READERP_H_
 
+#include "HDF5Common.h"
+
+#include "adios2/ADIOSMPICommOnly.h"
+#include "adios2/core/Engine.h"
+
+namespace adios
+{
+
+class HDF5Reader : public Engine
+{
+
+public:
+    /**
+     * Constructor for single HDF5 reader engine, reads from HDF5 format
+     * @param name unique name given to the engine
+     * @param accessMode
+     * @param mpiComm
+     * @param method
+     */
+    HDF5Reader(ADIOS &adios, const std::string name,
+               const std::string accessMode, MPI_Comm mpiComm,
+               const Method &method);
+
+    virtual ~HDF5Reader();
+
+    bool isValid();
+
+    Variable<void> *InquireVariable(const std::string &variableName,
+                                    const bool readIn = true);
+
+    Variable<char> *InquireVariableChar(const std::string &variableName,
+                                        const bool readIn = true);
+
+    Variable<unsigned char> *
+    InquireVariableUChar(const std::string &variableName,
+                         const bool readIn = true);
+
+    Variable<short> *InquireVariableShort(const std::string &variableName,
+                                          const bool readIn = true);
+
+    Variable<unsigned short> *
+    InquireVariableUShort(const std::string &variableName,
+                          const bool readIn = true);
+
+    Variable<int> *InquireVariableInt(const std::string &variableName,
+                                      const bool readIn = true);
+
+    Variable<unsigned int> *InquireVariableUInt(const std::string &variableName,
+                                                const bool readIn = true);
+
+    Variable<long int> *InquireVariableLInt(const std::string &variableName,
+                                            const bool readIn = true);
+
+    Variable<unsigned long int> *
+    InquireVariableULInt(const std::string &variableName,
+                         const bool readIn = true);
+
+    Variable<long long int> *
+    InquireVariableLLInt(const std::string &variableName,
+                         const bool readIn = true);
+
+    Variable<unsigned long long int> *
+    InquireVariableULLInt(const std::string &variableName,
+                          const bool readIn = true);
+
+    Variable<float> *InquireVariableFloat(const std::string &variableName,
+                                          const bool readIn = true);
+
+    Variable<double> *InquireVariableDouble(const std::string &variableName,
+                                            const bool readIn = true);
+    Variable<long double> *
+    InquireVariableLDouble(const std::string &variableName,
+                           const bool readIn = true);
+
+    Variable<std::complex<float>> *
+    InquireVariableCFloat(const std::string &variableName,
+                          const bool readIn = true);
+
+    Variable<std::complex<double>> *
+    InquireVariableCDouble(const std::string &variableName,
+                           const bool readIn = true);
+
+    Variable<std::complex<long double>> *
+    InquireVariableCLDouble(const std::string &variableName,
+                            const bool readIn = true);
+
+    /**
+     * Not implemented
+     * @param name
+     * @param readIn
+     * @return
+     */
+    VariableCompound *InquireVariableCompound(const std::string &variableName,
+                                              const bool readIn = true);
+
+    void Advance(float timeoutSecc = 0.0);
+
+    void Close(const int transportIndex = -1);
+
+    template <typename T>
+    void UseHDFRead(const std::string &variableName, T *values, hid_t h5Type);
+
+    /*
+    template <class T>
+    void ReadMe(Variable<T> &variable, T *values, hid_t h5type);
+    */
+private:
+    HDF5Common m_H5File;
+    void Init();
+};
+};
 #endif /* ADIOS2_ENGINE_HDF5_HDF5READERP_H_ */
diff --git a/source/adios2/engine/hdf5/HDF5WriterP.cpp b/source/adios2/engine/hdf5/HDF5WriterP.cpp
index bb01c6301ed4328fedff18a525645372c91680b5..784f1aea4267c84f47d071637f93a936bd6d6a51 100644
--- a/source/adios2/engine/hdf5/HDF5WriterP.cpp
+++ b/source/adios2/engine/hdf5/HDF5WriterP.cpp
@@ -10,8 +10,6 @@
 
 #include "HDF5WriterP.h"
 
-#include <iostream> //needs to go away, this is just for demo purposes
-
 #include "adios2/ADIOSMPI.h"
 #include "adios2/core/Support.h"
 #include "adios2/core/adiosFunctions.h" //CSVToVector
@@ -27,40 +25,10 @@ HDF5Writer::HDF5Writer(ADIOS &adios, const std::string name,
          " HDF5Writer constructor (or call to ADIOS Open).\n"),
   m_Buffer(m_DebugMode)
 {
-    //
-    //  16, 4 vs: 8
-    // std::cout<<sizeof(std::complex<double>)<<",
-    // "<<sizeof(H5T_NATIVE_DOUBLE)<<" vs:
-    // "<<H5Tget_size(H5T_NATIVE_DOUBLE)<<std::endl;
-    //  8, 4 vs: 4
-    // std::cout<<sizeof(std::complex<float>)<<", "<<sizeof(H5T_NATIVE_FLOAT)<<"
-    // vs: "<<H5Tget_size(H5T_NATIVE_FLOAT)<<std::endl;
-    //  32, 4 vs: 16
-    // std::cout<<sizeof(std::complex<long double>)<<",
-    // "<<sizeof(H5T_NATIVE_LDOUBLE)<<" vs:
-    // "<<H5Tget_size(H5T_NATIVE_LDOUBLE)<<std::endl;
-
-    DefH5T_COMPLEX_FLOAT = H5Tcreate(H5T_COMPOUND, sizeof(std::complex<float>));
-    H5Tinsert(DefH5T_COMPLEX_FLOAT, "freal", 0, H5T_NATIVE_FLOAT);
-    H5Tinsert(DefH5T_COMPLEX_FLOAT, "fimg", H5Tget_size(H5T_NATIVE_FLOAT),
-              H5T_NATIVE_FLOAT);
-
-    DefH5T_COMPLEX_DOUBLE =
-        H5Tcreate(H5T_COMPOUND, sizeof(std::complex<double>));
-    H5Tinsert(DefH5T_COMPLEX_DOUBLE, "dreal", 0, H5T_NATIVE_DOUBLE);
-    H5Tinsert(DefH5T_COMPLEX_DOUBLE, "dimg", H5Tget_size(H5T_NATIVE_DOUBLE),
-              H5T_NATIVE_DOUBLE);
-
-    DefH5T_COMPLEX_LongDOUBLE =
-        H5Tcreate(H5T_COMPOUND, sizeof(std::complex<long double>));
-    H5Tinsert(DefH5T_COMPLEX_LongDOUBLE, "ldouble real", 0, H5T_NATIVE_LDOUBLE);
-    H5Tinsert(DefH5T_COMPLEX_LongDOUBLE, "ldouble img",
-              H5Tget_size(H5T_NATIVE_LDOUBLE), H5T_NATIVE_LDOUBLE);
-
     Init();
 }
 
-HDF5Writer::~HDF5Writer() {}
+HDF5Writer::~HDF5Writer() { Close(); }
 
 void HDF5Writer::Init()
 {
@@ -71,23 +39,8 @@ void HDF5Writer::Init()
             "ERROR: HDF5Writer doesn't support access mode " + m_AccessMode +
             ", in call to ADIOS Open or HDF5Writer constructor\n");
     }
-    // std::cout << "method: # of inputs:" << m_Method.m_Parameters.size() <<
-    // std::endl;
-
-    // std::cout << "::Init hdf5 parallel writer. File name:" << m_Name <<
-    // std::endl;
-
-    _plist_id = H5Pcreate(H5P_FILE_ACCESS);
-
-#ifdef ADIOS2_HAVE_MPI
-    H5Pset_fapl_mpio(_plist_id, m_MPIComm, MPI_INFO_NULL);
-#endif
 
-    /*
-     * Create a new file collectively and release property list identifier.
-     */
-    _file_id = H5Fcreate(m_Name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, _plist_id);
-    H5Pclose(_plist_id);
+    m_H5File.Init(m_Name, m_MPIComm, true);
 }
 
 void HDF5Writer::Write(Variable<char> &variable, const char *values)
@@ -165,19 +118,19 @@ void HDF5Writer::Write(Variable<long double> &variable,
 void HDF5Writer::Write(Variable<std::complex<float>> &variable,
                        const std::complex<float> *values)
 {
-    UseHDFWrite(variable, values, DefH5T_COMPLEX_FLOAT);
+    UseHDFWrite(variable, values, m_H5File.m_DefH5TypeComplexFloat);
 }
 
 void HDF5Writer::Write(Variable<std::complex<double>> &variable,
                        const std::complex<double> *values)
 {
-    UseHDFWrite(variable, values, DefH5T_COMPLEX_DOUBLE);
+    UseHDFWrite(variable, values, m_H5File.m_DefH5TypeComplexDouble);
 }
 
 void HDF5Writer::Write(Variable<std::complex<long double>> &variable,
                        const std::complex<long double> *values)
 {
-    UseHDFWrite(variable, values, DefH5T_COMPLEX_LongDOUBLE);
+    UseHDFWrite(variable, values, m_H5File.m_DefH5TypeComplexLongDouble);
 }
 
 // String version
@@ -269,87 +222,96 @@ void HDF5Writer::Write(const std::string variableName,
                        const std::complex<float> *values)
 {
     UseHDFWrite(m_ADIOS.GetVariable<std::complex<float>>(variableName), values,
-                DefH5T_COMPLEX_FLOAT);
+                m_H5File.m_DefH5TypeComplexFloat);
 }
 
 void HDF5Writer::Write(const std::string variableName,
                        const std::complex<double> *values)
 {
     UseHDFWrite(m_ADIOS.GetVariable<std::complex<double>>(variableName), values,
-                DefH5T_COMPLEX_DOUBLE);
+                m_H5File.m_DefH5TypeComplexDouble);
 }
 
 void HDF5Writer::Write(const std::string variableName,
                        const std::complex<long double> *values)
 {
     UseHDFWrite(m_ADIOS.GetVariable<std::complex<long double>>(variableName),
-                values, DefH5T_COMPLEX_LongDOUBLE);
+                values, m_H5File.m_DefH5TypeComplexLongDouble);
 }
 
-void HDF5Writer::Close(const int transportIndex)
-{
-    // std::cout << " ===> CLOSING HDF5 <===== " << std::endl;
-    // H5Dclose(_dset_id);
-    // H5Sclose(_filespace);
-    // H5Sclose(_memspace);
-    // H5Pclose(_plist_id);
-    H5Fclose(_file_id);
-}
+void HDF5Writer::Advance(float timeoutSec) { m_H5File.Advance(); }
+
+void HDF5Writer::Close(const int transportIndex) { m_H5File.Close(); }
 
 template <class T>
 void HDF5Writer::UseHDFWrite(Variable<T> &variable, const T *values,
-                             hid_t h5type)
+                             hid_t h5Type)
 {
+    m_H5File.CheckWriteGroup();
     // here comes your magic at Writing now variable.m_UserValues has the data
     // passed by the user
     // set variable
     variable.m_AppValues = values;
     m_WrittenVariables.insert(variable.m_Name);
 
-    int dimSize = variable.m_GlobalDimensions.size();
-    /*
-    std::cout << "writting : " << variable.m_Name
-              << " dim size:" << variable.m_GlobalDimensions.size() <<
-    std::endl;
+    int dimSize = std::max(variable.m_GlobalDimensions.size(),
+                           variable.m_LocalDimensions.size());
 
-    for (int i = 0; i < dimSize; i++) {
-      std::cout << " dim: " << i << ", size:" << variable.m_GlobalDimensions[i]
-                << " offset=" << variable.m_Offsets[i]
-                << " count=" << variable.m_LocalDimensions[i] << std::endl;
-    }
-    */
     std::vector<hsize_t> dimsf, count, offset;
 
     for (int i = 0; i < dimSize; i++)
     {
-        dimsf.push_back(variable.m_GlobalDimensions[i]);
-        count.push_back(variable.m_LocalDimensions[i]);
-        offset.push_back(variable.m_Offsets[i]);
+        if (variable.m_GlobalDimensions.size() == dimSize)
+        {
+            dimsf.push_back(variable.m_GlobalDimensions[i]);
+        }
+        else
+        {
+            dimsf.push_back(variable.m_LocalDimensions[i]);
+        }
+
+        if (variable.m_LocalDimensions.size() == dimSize)
+        {
+            count.push_back(variable.m_LocalDimensions[i]);
+            if (variable.m_Offsets.size() == dimSize)
+            {
+                offset.push_back(variable.m_Offsets[i]);
+            }
+            else
+            {
+                offset.push_back(0);
+            }
+        }
+        else
+        {
+            count.push_back(variable.m_GlobalDimensions[i]);
+            offset.push_back(0);
+        }
     }
 
-    _filespace = H5Screate_simple(dimSize, dimsf.data(), NULL);
+    hid_t fileSpace = H5Screate_simple(dimSize, dimsf.data(), NULL);
 
-    _dset_id = H5Dcreate(_file_id, variable.m_Name.c_str(), h5type, _filespace,
-                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
-    // H5Sclose(_filespace);
+    hid_t dsetID =
+        H5Dcreate(m_H5File.m_GroupId, variable.m_Name.c_str(), h5Type,
+                  fileSpace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+    // H5Sclose(fileSpace);
 
-    _memspace = H5Screate_simple(dimSize, count.data(), NULL);
+    hid_t memSpace = H5Screate_simple(dimSize, count.data(), NULL);
 
     // Select hyperslab
-    _filespace = H5Dget_space(_dset_id);
-    H5Sselect_hyperslab(_filespace, H5S_SELECT_SET, offset.data(), NULL,
+    fileSpace = H5Dget_space(dsetID);
+    H5Sselect_hyperslab(fileSpace, H5S_SELECT_SET, offset.data(), NULL,
                         count.data(), NULL);
 
     //  Create property list for collective dataset write.
 
-    _plist_id = H5Pcreate(H5P_DATASET_XFER);
+    hid_t plistID = H5Pcreate(H5P_DATASET_XFER);
 #ifdef ADIOS2_HAVE_MPI
-    H5Pset_dxpl_mpio(_plist_id, H5FD_MPIO_COLLECTIVE);
+    H5Pset_dxpl_mpio(plistID, H5FD_MPIO_COLLECTIVE);
 #endif
     herr_t status;
 
-    status =
-        H5Dwrite(_dset_id, h5type, _memspace, _filespace, _plist_id, values);
+    status = H5Dwrite(dsetID, h5Type, memSpace, fileSpace, plistID, values);
 
     if (status < 0)
     {
@@ -357,13 +319,10 @@ void HDF5Writer::UseHDFWrite(Variable<T> &variable, const T *values,
         std::cerr << " Write failed. " << std::endl;
     }
 
-    // std::cout << " ==> User is responsible for freeing the data " <<
-    // std::endl;
-
-    H5Dclose(_dset_id);
-    H5Sclose(_filespace);
-    H5Sclose(_memspace);
-    H5Pclose(_plist_id);
+    H5Dclose(dsetID);
+    H5Sclose(fileSpace);
+    H5Sclose(memSpace);
+    H5Pclose(plistID);
 }
 
 } // end namespace adios
diff --git a/source/adios2/engine/hdf5/HDF5WriterP.h b/source/adios2/engine/hdf5/HDF5WriterP.h
index cca6b53ee38edc4b55ca5613b7889a9654a4ed9c..21151a18ab648cab1b8d389436a13dfb3518c3ef 100644
--- a/source/adios2/engine/hdf5/HDF5WriterP.h
+++ b/source/adios2/engine/hdf5/HDF5WriterP.h
@@ -12,6 +12,8 @@
 #ifndef ADIOS2_ENGINE_HDF5_HDF5WRITERP_H__
 #define ADIOS2_ENGINE_HDF5_HDF5WRITERP_H__
 
+#include "HDF5Common.h"
+
 #include "adios2/ADIOSConfig.h"
 #include "adios2/ADIOSMPICommOnly.h"
 #include "adios2/capsule/heap/STLVector.h"
@@ -27,14 +29,11 @@ class HDF5Writer : public Engine
 
 public:
     /**
-     * Constructor for single BP capsule engine, writes in BP format into a
-     * single
-     * heap capsule
+     * Constructor for HDF5 writer engine, writes in hdf5 format
      * @param name unique name given to the engine
      * @param accessMode
      * @param mpiComm
      * @param method
-     * @param debugMode
      */
     HDF5Writer(ADIOS &adios, const std::string name,
                const std::string accessMode, MPI_Comm mpiComm,
@@ -86,6 +85,8 @@ public:
     void Write(const std::string variableName,
                const std::complex<long double> *values);
 
+    void Advance(float timeoutSec = 0.0);
+
     void Close(const int transportIndex = -1);
 
 private:
@@ -93,17 +94,11 @@ private:
     capsule::STLVector m_Buffer;
 
     void Init();
-    void clean();
-
-    hid_t _plist_id, _file_id, _dset_id;
-    hid_t _memspace, _filespace;
 
-    hid_t DefH5T_COMPLEX_DOUBLE;
-    hid_t DefH5T_COMPLEX_FLOAT;
-    hid_t DefH5T_COMPLEX_LongDOUBLE;
+    HDF5Common m_H5File;
 
     template <class T>
-    void UseHDFWrite(Variable<T> &variable, const T *values, hid_t h5type);
+    void UseHDFWrite(Variable<T> &variable, const T *values, hid_t h5Type);
 };
 
 } // end namespace adios
diff --git a/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp b/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp
index bac7570fbc6230ed915f2c33645e738f5a7b61e0..3f2b6a69f8ab11257cb14674feb1a174bf23d8ef 100644
--- a/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp
+++ b/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp
@@ -9,6 +9,7 @@
 #include <stdexcept>
 
 #include <adios2.h>
+
 #include <hdf5.h>
 
 #include <gtest/gtest.h>
@@ -23,6 +24,162 @@ public:
     SmallTestData m_TestData;
 };
 
+class HDF5NativeReader
+{
+
+public:
+    HDF5NativeReader(const std::string fileName);
+    ~HDF5NativeReader();
+
+    bool Advance();
+
+    void GetVarInfo(const std::string varName, std::vector<hsize_t> &dims,
+                    hid_t &h5Type);
+    void ReadVar(const std::string varName, void *dataArray);
+
+    int m_CurrentTimeStep;
+    unsigned int m_TotalTimeSteps;
+
+private:
+    hid_t m_FilePropertyListId;
+    hid_t m_FileId;
+    hid_t m_GroupId;
+};
+
+HDF5NativeReader::HDF5NativeReader(const std::string fileName)
+: m_CurrentTimeStep(0), m_TotalTimeSteps(0)
+{
+    m_FilePropertyListId = H5Pcreate(H5P_FILE_ACCESS);
+
+#ifdef ADIOS2_HAVE_MPI
+    // read a file collectively
+    H5Pset_fapl_mpio(m_FilePropertyListId, MPI_COMM_WORLD, MPI_INFO_NULL);
+#endif
+
+    m_FileId = H5Fopen(fileName.c_str(), H5F_ACC_RDONLY, m_FilePropertyListId);
+    if (m_FileId < 0)
+    {
+        throw std::runtime_error("Unable to open " + fileName + " for reading");
+    }
+
+    std::string ts0 = "/TimeStep0";
+    m_GroupId = H5Gopen(m_FileId, ts0.c_str(), H5P_DEFAULT);
+    if (m_GroupId < 0)
+    {
+        throw std::runtime_error("Unable to open group " + ts0 +
+                                 " for reading");
+    }
+
+    hid_t attrId = H5Aopen(m_FileId, "NumTimeSteps", H5P_DEFAULT);
+    if (attrId < 0)
+    {
+        throw std::runtime_error("Unable to open attribute NumTimeSteps");
+    }
+    H5Aread(attrId, H5T_NATIVE_UINT, &m_TotalTimeSteps);
+    H5Aclose(attrId);
+}
+
+HDF5NativeReader::~HDF5NativeReader()
+{
+    if (m_GroupId >= 0)
+    {
+        H5Gclose(m_GroupId);
+    }
+
+    H5Fclose(m_FileId);
+    H5Pclose(m_FilePropertyListId);
+}
+
+void HDF5NativeReader::GetVarInfo(const std::string varName,
+                                  std::vector<hsize_t> &dims, hid_t &h5Type)
+{
+    hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT);
+    if (dataSetId < 0)
+    {
+        throw std::runtime_error("Unable to open dataset " + varName);
+    }
+
+    hid_t fileSpaceId = H5Dget_space(dataSetId);
+    if (fileSpaceId < 0)
+    {
+        throw std::runtime_error("Unable to get filespace for dataset " +
+                                 varName);
+    }
+
+    const int ndims = H5Sget_simple_extent_ndims(fileSpaceId);
+    if (ndims < 0)
+    {
+        throw std::runtime_error(
+            "Unable to get number of dimensions for dataset " + varName);
+    }
+
+    dims.resize(ndims);
+    if (H5Sget_simple_extent_dims(fileSpaceId, dims.data(), NULL) != ndims)
+    {
+        throw std::runtime_error("Unable to get dimensions for dataset " +
+                                 varName);
+    }
+
+    h5Type = H5Dget_type(dataSetId);
+
+    H5Sclose(fileSpaceId);
+    H5Dclose(dataSetId);
+}
+
+bool HDF5NativeReader::Advance()
+{
+    if (m_GroupId >= 0)
+    {
+        H5Gclose(m_GroupId);
+        m_GroupId = -1;
+    }
+
+    if (m_CurrentTimeStep + 1 >= m_TotalTimeSteps)
+    {
+        return false;
+    }
+
+    std::string tsName = "/TimeStep" + std::to_string(m_CurrentTimeStep + 1);
+    m_GroupId = H5Gopen(m_FileId, tsName.c_str(), H5P_DEFAULT);
+    if (m_GroupId < 0)
+    {
+        throw std::runtime_error("Unable to open group " + tsName +
+                                 " for reading");
+    }
+    ++m_CurrentTimeStep;
+
+    return true;
+}
+
+void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray)
+{
+    if (m_GroupId < 0)
+    {
+        throw std::runtime_error("Can't read variable " + varName +
+                                 " since a group is not currently open");
+    }
+
+    hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT);
+    if (dataSetId < 0)
+    {
+        throw std::runtime_error("Unable to open dataset " + varName);
+    }
+
+    hid_t fileSpace = H5Dget_space(dataSetId);
+    if (fileSpace < 0)
+    {
+        throw std::runtime_error("Unable to get filespace for dataset " +
+                                 varName);
+    }
+
+    hid_t h5type = H5Dget_type(dataSetId);
+    hid_t ret =
+        H5Dread(dataSetId, h5type, H5S_ALL, H5S_ALL, H5P_DEFAULT, dataArray);
+
+    H5Sclose(fileSpace);
+    H5Dclose(dataSetId);
+}
+
 //******************************************************************************
 // 1D 1x8 test data
 //******************************************************************************
@@ -34,8 +191,7 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8)
 
     // Write test data using ADIOS2
     {
-        adios::ADIOS adios(adios::Verbose::WARN, true);
-
+        adios::ADIOS adios(adios::Verbose::WARN, true); // moved up
         // Declare 1D variables
         {
             auto &var_i8 = adios.DefineVariable<char>("i8", adios::Dims{8});
@@ -96,10 +252,115 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8)
         engine->Close();
     }
 
-    // Read test data using HDF5
+// Read test data using HDF5
+#ifdef ADIOS2_HAVE_MPI
+    // Read everything from rank 0
+    int rank;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    if (rank == 0)
+#endif
     {
-        ASSERT_TRUE(false)
-            << "Native HDF5 read validation is not yet implemented";
+        std::array<char, 8> I8;
+        std::array<int16_t, 8> I16;
+        std::array<int32_t, 8> I32;
+        std::array<int64_t, 8> I64;
+        std::array<unsigned char, 8> U8;
+        std::array<uint16_t, 8> U16;
+        std::array<uint32_t, 8> U32;
+        std::array<uint64_t, 8> U64;
+        std::array<float, 8> R32;
+        std::array<double, 8> R64;
+
+        HDF5NativeReader hdf5Reader(fname);
+
+        // Read stuff
+        for (size_t t = 0; t < 3; ++t)
+        {
+            std::vector<hsize_t> gDims;
+            hid_t h5Type;
+
+            hdf5Reader.GetVarInfo("i8", gDims, h5Type);
+
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_CHAR), 1);
+            ASSERT_EQ(gDims.size(), 1);
+            ASSERT_EQ(gDims[0], 8);
+            hdf5Reader.ReadVar("i8", I8.data());
+
+            hdf5Reader.GetVarInfo("i16", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_SHORT), 1);
+            ASSERT_EQ(gDims.size(), 1);
+            ASSERT_EQ(gDims[0], 8);
+            hdf5Reader.ReadVar("i16", I16.data());
+
+            hdf5Reader.GetVarInfo("i32", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT), 1);
+            ASSERT_EQ(gDims.size(), 1);
+            ASSERT_EQ(gDims[0], 8);
+            hdf5Reader.ReadVar("i32", I32.data());
+
+            hdf5Reader.GetVarInfo("i64", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_LONG), 1);
+            ASSERT_EQ(gDims.size(), 1);
+            ASSERT_EQ(gDims[0], 8);
+            hdf5Reader.ReadVar("i64", I64.data());
+
+            hdf5Reader.GetVarInfo("u8", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UCHAR), 1);
+            ASSERT_EQ(gDims.size(), 1);
+            ASSERT_EQ(gDims[0], 8);
+            hdf5Reader.ReadVar("u8", U8.data());
+
+            hdf5Reader.GetVarInfo("u16", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_USHORT), 1);
+            ASSERT_EQ(gDims.size(), 1);
+            ASSERT_EQ(gDims[0], 8);
+            hdf5Reader.ReadVar("u16", U16.data());
+
+            hdf5Reader.GetVarInfo("u32", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UINT), 1);
+            ASSERT_EQ(gDims.size(), 1);
+            ASSERT_EQ(gDims[0], 8);
+            hdf5Reader.ReadVar("u32", U32.data());
+
+            hdf5Reader.GetVarInfo("u64", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_ULONG), 1);
+            ASSERT_EQ(gDims.size(), 1);
+            ASSERT_EQ(gDims[0], 8);
+            hdf5Reader.ReadVar("u64", U64.data());
+
+            hdf5Reader.GetVarInfo("r32", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_FLOAT), 1);
+            ASSERT_EQ(gDims.size(), 1);
+            ASSERT_EQ(gDims[0], 8);
+            hdf5Reader.ReadVar("r32", R32.data());
+
+            hdf5Reader.GetVarInfo("r64", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_DOUBLE), 1);
+            ASSERT_EQ(gDims.size(), 1);
+            ASSERT_EQ(gDims[0], 8);
+            hdf5Reader.ReadVar("r64", R64.data());
+
+            // Check if it's correct
+            for (size_t i = 0; i < 8; ++i)
+            {
+                std::stringstream ss;
+                ss << "t=" << t << " i=" << i;
+                std::string msg = ss.str();
+
+                EXPECT_EQ(I8[i], m_TestData.I8[i + t]) << msg;
+                EXPECT_EQ(I16[i], m_TestData.I16[i + t]) << msg;
+                EXPECT_EQ(I32[i], m_TestData.I32[i + t]) << msg;
+                EXPECT_EQ(I64[i], m_TestData.I64[i + t]) << msg;
+                EXPECT_EQ(U8[i], m_TestData.U8[i + t]) << msg;
+                EXPECT_EQ(U16[i], m_TestData.U16[i + t]) << msg;
+                EXPECT_EQ(U32[i], m_TestData.U32[i + t]) << msg;
+                EXPECT_EQ(U64[i], m_TestData.U64[i + t]) << msg;
+                EXPECT_EQ(R32[i], m_TestData.R32[i + t]) << msg;
+                EXPECT_EQ(R64[i], m_TestData.R64[i + t]) << msg;
+            }
+
+            hdf5Reader.Advance();
+        }
     }
 }
 
@@ -196,10 +457,123 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4)
         engine->Close();
     }
 
-    // Read test data using HDF5
+// Read test data using HDF5
+#ifdef ADIOS2_HAVE_MPI
+    // Read everything from rank 0
+    int rank;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    if (rank == 0)
+#endif
     {
-        ASSERT_TRUE(false)
-            << "Native HDF5 read validation is not yet implemented";
+        HDF5NativeReader hdf5Reader(fname);
+
+        std::array<char, 8> I8;
+        std::array<int16_t, 8> I16;
+        std::array<int32_t, 8> I32;
+        std::array<int64_t, 8> I64;
+        std::array<unsigned char, 8> U8;
+        std::array<uint16_t, 8> U16;
+        std::array<uint32_t, 8> U32;
+        std::array<uint64_t, 8> U64;
+        std::array<float, 8> R32;
+        std::array<double, 8> R64;
+
+        // Read stuff
+        for (size_t t = 0; t < 3; ++t)
+        {
+            std::vector<hsize_t> gDims;
+            hid_t h5Type;
+
+            hdf5Reader.GetVarInfo("i8", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_CHAR), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 2);
+            ASSERT_EQ(gDims[1], 4);
+            hdf5Reader.ReadVar("i8", I8.data());
+
+            hdf5Reader.GetVarInfo("i16", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_SHORT), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 2);
+            ASSERT_EQ(gDims[1], 4);
+            hdf5Reader.ReadVar("i16", I16.data());
+
+            hdf5Reader.GetVarInfo("i32", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 2);
+            ASSERT_EQ(gDims[1], 4);
+            hdf5Reader.ReadVar("i32", I32.data());
+
+            hdf5Reader.GetVarInfo("i64", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_LONG), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 2);
+            ASSERT_EQ(gDims[1], 4);
+            hdf5Reader.ReadVar("i64", I64.data());
+
+            hdf5Reader.GetVarInfo("u8", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UCHAR), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 2);
+            ASSERT_EQ(gDims[1], 4);
+            hdf5Reader.ReadVar("u8", U8.data());
+
+            hdf5Reader.GetVarInfo("u16", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_USHORT), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 2);
+            ASSERT_EQ(gDims[1], 4);
+            hdf5Reader.ReadVar("u16", U16.data());
+
+            hdf5Reader.GetVarInfo("u32", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UINT), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 2);
+            ASSERT_EQ(gDims[1], 4);
+            hdf5Reader.ReadVar("u32", U32.data());
+
+            hdf5Reader.GetVarInfo("u64", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_ULONG), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 2);
+            ASSERT_EQ(gDims[1], 4);
+            hdf5Reader.ReadVar("u64", U64.data());
+
+            hdf5Reader.GetVarInfo("r32", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_FLOAT), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 2);
+            ASSERT_EQ(gDims[1], 4);
+            hdf5Reader.ReadVar("r32", R32.data());
+
+            hdf5Reader.GetVarInfo("r64", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_DOUBLE), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 2);
+            ASSERT_EQ(gDims[1], 4);
+            hdf5Reader.ReadVar("r64", R64.data());
+
+            // Check if it's correct
+            for (size_t i = 0; i < 8; ++i)
+            {
+                std::stringstream ss;
+                ss << "t=" << t << " i=" << i;
+                std::string msg = ss.str();
+
+                EXPECT_EQ(I8[i], m_TestData.I8[i + t]) << msg;
+                EXPECT_EQ(I16[i], m_TestData.I16[i + t]) << msg;
+                EXPECT_EQ(I32[i], m_TestData.I32[i + t]) << msg;
+                EXPECT_EQ(I64[i], m_TestData.I64[i + t]) << msg;
+                EXPECT_EQ(U8[i], m_TestData.U8[i + t]) << msg;
+                EXPECT_EQ(U16[i], m_TestData.U16[i + t]) << msg;
+                EXPECT_EQ(U32[i], m_TestData.U32[i + t]) << msg;
+                EXPECT_EQ(U64[i], m_TestData.U64[i + t]) << msg;
+                EXPECT_EQ(R32[i], m_TestData.R32[i + t]) << msg;
+                EXPECT_EQ(R64[i], m_TestData.R64[i + t]) << msg;
+            }
+            hdf5Reader.Advance();
+        }
     }
 }
 
@@ -296,10 +670,123 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2)
         engine->Close();
     }
 
-    // Read test data using HDF5
+// Read test data using HDF5
+#ifdef ADIOS2_HAVE_MPI
+    // Read everything from rank 0
+    int rank;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    if (rank == 0)
+#endif
     {
-        ASSERT_TRUE(false)
-            << "Native HDF5 read validation is not yet implemented";
+
+        HDF5NativeReader hdf5Reader(fname);
+
+        std::array<char, 8> I8;
+        std::array<int16_t, 8> I16;
+        std::array<int32_t, 8> I32;
+        std::array<int64_t, 8> I64;
+        std::array<unsigned char, 8> U8;
+        std::array<uint16_t, 8> U16;
+        std::array<uint32_t, 8> U32;
+        std::array<uint64_t, 8> U64;
+        std::array<float, 8> R32;
+        std::array<double, 8> R64;
+
+        // Read stuff
+        for (size_t t = 0; t < 3; ++t)
+        {
+            std::vector<hsize_t> gDims;
+            hid_t h5Type;
+
+            hdf5Reader.GetVarInfo("i8", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_CHAR), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 4);
+            ASSERT_EQ(gDims[1], 2);
+            hdf5Reader.ReadVar("i8", I8.data());
+
+            hdf5Reader.GetVarInfo("i16", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_SHORT), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 4);
+            ASSERT_EQ(gDims[1], 2);
+            hdf5Reader.ReadVar("i16", I16.data());
+
+            hdf5Reader.GetVarInfo("i32", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 4);
+            ASSERT_EQ(gDims[1], 2);
+            hdf5Reader.ReadVar("i32", I32.data());
+
+            hdf5Reader.GetVarInfo("i64", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_LONG), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 4);
+            ASSERT_EQ(gDims[1], 2);
+            hdf5Reader.ReadVar("i64", I64.data());
+
+            hdf5Reader.GetVarInfo("u8", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UCHAR), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 4);
+            ASSERT_EQ(gDims[1], 2);
+            hdf5Reader.ReadVar("u8", U8.data());
+
+            hdf5Reader.GetVarInfo("u16", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_USHORT), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 4);
+            ASSERT_EQ(gDims[1], 2);
+            hdf5Reader.ReadVar("u16", U16.data());
+
+            hdf5Reader.GetVarInfo("u32", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UINT), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 4);
+            ASSERT_EQ(gDims[1], 2);
+            hdf5Reader.ReadVar("u32", U32.data());
+
+            hdf5Reader.GetVarInfo("u64", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_ULONG), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 4);
+            ASSERT_EQ(gDims[1], 2);
+            hdf5Reader.ReadVar("u64", U64.data());
+
+            hdf5Reader.GetVarInfo("r32", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_FLOAT), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 4);
+            ASSERT_EQ(gDims[1], 2);
+            hdf5Reader.ReadVar("r32", R32.data());
+
+            hdf5Reader.GetVarInfo("r64", gDims, h5Type);
+            ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_DOUBLE), 1);
+            ASSERT_EQ(gDims.size(), 2);
+            ASSERT_EQ(gDims[0], 4);
+            ASSERT_EQ(gDims[1], 2);
+            hdf5Reader.ReadVar("r64", R64.data());
+
+            for (size_t i = 0; i < 8; ++i)
+            {
+                std::stringstream ss;
+                ss << "t=" << t << " i=" << i;
+                std::string msg = ss.str();
+
+                EXPECT_EQ(I8[i], m_TestData.I8[i + t]) << msg;
+                EXPECT_EQ(I16[i], m_TestData.I16[i + t]) << msg;
+                EXPECT_EQ(I32[i], m_TestData.I32[i + t]) << msg;
+                EXPECT_EQ(I64[i], m_TestData.I64[i + t]) << msg;
+                EXPECT_EQ(U8[i], m_TestData.U8[i + t]) << msg;
+                EXPECT_EQ(U16[i], m_TestData.U16[i + t]) << msg;
+                EXPECT_EQ(U32[i], m_TestData.U32[i + t]) << msg;
+                EXPECT_EQ(U64[i], m_TestData.U64[i + t]) << msg;
+                EXPECT_EQ(R32[i], m_TestData.R32[i + t]) << msg;
+                EXPECT_EQ(R64[i], m_TestData.R64[i + t]) << msg;
+            }
+            hdf5Reader.Advance();
+        }
     }
 }