diff --git a/testing/adios2/engine/hdf5/CMakeLists.txt b/testing/adios2/engine/hdf5/CMakeLists.txt
index e13c17fb6760fe5169e6554696e403cd03a4de87..85a20cb648ae68c523f1ffe7c8b5a5a3873ba6b8 100644
--- a/testing/adios2/engine/hdf5/CMakeLists.txt
+++ b/testing/adios2/engine/hdf5/CMakeLists.txt
@@ -13,4 +13,13 @@ else()
 endif()
 target_link_libraries(TestHDF5WriteRead adios2 gtest ${HDF5_C_LIBRARIES})
 
-gtest_add_tests(TARGET TestHDF5WriteRead)
+if(ADIOS2_HAVE_MPI)
+  target_include_directories(TestHDF5WriteRead PRIVATE ${MPI_C_INCLUDE_PATH})
+  target_link_libraries(TestHDF5WriteRead ${MPI_C_LIBRARIES})
+  set(extra_test_args
+    EXEC_WRAPPER
+      ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS}
+  )
+endif()
+
+gtest_add_tests(TARGET TestHDF5WriteRead ${extra_test_args})
diff --git a/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp b/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp
index 3ad94d769a42466683778faefa76289ff29d60a5..d03c6558f9595c8861aa120a3210d185dfac7274 100644
--- a/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp
+++ b/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp
@@ -35,7 +35,11 @@ public:
 
     void GetVarInfo(const std::string varName, std::vector<hsize_t> &dims,
                     hid_t &h5Type);
-    void ReadVar(const std::string varName, void *dataArray);
+    // If offset, count and memspaceSize are provided, then variable would be
+    // read by selection
+    void ReadVar(const std::string varName, void *dataArray,
+                 hsize_t *offset = nullptr, hsize_t *count = nullptr,
+                 const size_t memsspaceSize = 0);
 
     int m_CurrentTimeStep;
     unsigned int m_TotalTimeSteps;
@@ -96,7 +100,8 @@ void HDF5NativeReader::GetVarInfo(const std::string varName,
     hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT);
     if (dataSetId < 0)
     {
-        throw std::runtime_error("Unable to open dataset " + varName);
+        throw std::runtime_error("Unable to open dataset " + varName +
+                                 " when getVarInfo");
     }
 
     hid_t fileSpaceId = H5Dget_space(dataSetId);
@@ -151,7 +156,9 @@ bool HDF5NativeReader::Advance()
     return true;
 }
 
-void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray)
+void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray,
+                               hsize_t *offset, hsize_t *count,
+                               const size_t memspaceSize)
 {
     if (m_GroupId < 0)
     {
@@ -162,7 +169,8 @@ void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray)
     hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT);
     if (dataSetId < 0)
     {
-        throw std::runtime_error("Unable to open dataset " + varName);
+        throw std::runtime_error("Unable to open dataset " + varName +
+                                 "when ReadVar");
     }
 
     hid_t fileSpace = H5Dget_space(dataSetId);
@@ -173,8 +181,35 @@ void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray)
     }
 
     hid_t h5type = H5Dget_type(dataSetId);
-    hid_t ret =
-        H5Dread(dataSetId, h5type, H5S_ALL, H5S_ALL, H5P_DEFAULT, dataArray);
+
+    // Extend reader to support read by hyperslab selection
+    // Reference link: https://support.hdfgroup.org/HDF5/Tutor/select.html
+    // Check if hyperspace is provided
+    if (offset && count)
+    {
+        // Get the dataspace
+        hid_t dataspace = H5Dget_space(dataSetId);
+        // Define hyperslab in the dataset
+        hid_t status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset,
+                                           NULL, count, NULL);
+        if (status < 0)
+        {
+            throw std::runtime_error(
+                "Unable to create a selection for dataset" + varName);
+        }
+
+        hsize_t dimsm[1];
+        dimsm[0] = memspaceSize;
+        hid_t memspace = H5Screate_simple(1, dimsm, NULL);
+
+        hid_t ret = H5Dread(dataSetId, h5type, memspace, dataspace, H5P_DEFAULT,
+                            dataArray);
+    }
+    else
+    {
+        hid_t ret = H5Dread(dataSetId, h5type, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                            dataArray);
+    }
 
     H5Sclose(fileSpace);
     H5Dclose(dataSetId);
@@ -187,44 +222,77 @@ void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray)
 // ADIOS2 write, native HDF5 read
 TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8)
 {
+    // Each process would write a 1x8 array and all processes would
+    // form a mpiSize * Nx 1D array
     std::string fname = "ADIOS2HDF5WriteHDF5Read1D8.h5";
 
+    int mpiRank = 0, mpiSize = 1;
+    // Number of rows
+    const std::size_t Nx = 8;
+
+    // Number of steps
+    const std::size_t NSteps = 3;
+
+#ifdef ADIOS2_HAVE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
     // Write test data using ADIOS2
     {
-        adios2::ADIOS adios(true); // moved up
+#ifdef ADIOS2_HAVE_MPI
+        adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON);
+#else
+        adios2::ADIOS adios(true);
+#endif
         adios2::IO &io = adios.DeclareIO("TestIO");
-        // Declare 1D variables
+
+        // Declare 1D variables (NumOfProcesses * Nx)
+        // The local process' part (start, count) can be defined now or later
+        // before Write().
         {
-            auto &var_i8 =
-                io.DefineVariable<int8_t>("i8", {}, {}, adios2::Dims{8});
+            adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)};
+            adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)};
+            adios2::Dims count{static_cast<unsigned int>(Nx)};
+            auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count);
             auto &var_i16 =
-                io.DefineVariable<int16_t>("i16", {}, {}, adios2::Dims{8});
+                io.DefineVariable<int16_t>("i16", shape, start, count);
             auto &var_i32 =
-                io.DefineVariable<int32_t>("i32", {}, {}, adios2::Dims{8});
+                io.DefineVariable<int32_t>("i32", shape, start, count);
             auto &var_i64 =
-                io.DefineVariable<int64_t>("i64", {}, {}, adios2::Dims{8});
+                io.DefineVariable<int64_t>("i64", shape, start, count);
             auto &var_u8 =
-                io.DefineVariable<uint8_t>("u8", {}, {}, adios2::Dims{8});
+                io.DefineVariable<uint8_t>("u8", shape, start, count);
             auto &var_u16 =
-                io.DefineVariable<uint16_t>("u16", {}, {}, adios2::Dims{8});
+                io.DefineVariable<uint16_t>("u16", shape, start, count);
             auto &var_u32 =
-                io.DefineVariable<uint32_t>("u32", {}, {}, adios2::Dims{8});
+                io.DefineVariable<uint32_t>("u32", shape, start, count);
             auto &var_u64 =
-                io.DefineVariable<uint64_t>("u64", {}, {}, adios2::Dims{8});
+                io.DefineVariable<uint64_t>("u64", shape, start, count);
             auto &var_r32 =
-                io.DefineVariable<float>("r32", {}, {}, adios2::Dims{8});
+                io.DefineVariable<float>("r32", shape, start, count);
             auto &var_r64 =
-                io.DefineVariable<double>("r64", {}, {}, adios2::Dims{8});
+                io.DefineVariable<double>("r64", shape, start, count);
         }
 
-        // Create the HDF5 Engine
+        // Create the ADIOS 1 Engine
         io.SetEngine("HDF5Writer");
 
+#ifdef ADIOS2_HAVE_MPI
+        io.AddTransport("file", {{"library", "MPI"}});
+#else
+        io.AddTransport("file");
+#endif
+
         auto engine = io.Open(fname, adios2::OpenMode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
-        for (size_t step = 0; step < 3; ++step)
+        for (size_t step = 0; step < NSteps; ++step)
         {
+            // Generate test data for each process uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
+
             // Retrieve the variables that previously went out of scope
             auto &var_i8 = io.GetVariable<int8_t>("i8");
             auto &var_i16 = io.GetVariable<int16_t>("i16");
@@ -237,17 +305,33 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8)
             auto &var_r32 = io.GetVariable<float>("r32");
             auto &var_r64 = io.GetVariable<double>("r64");
 
+            // Make a 1D selection to describe the local dimensions of the
+            // variable we write and its offsets in the global spaces
+            adios2::SelectionBoundingBox sel({mpiRank * Nx}, {Nx});
+            var_i8.SetSelection(sel);
+            var_i16.SetSelection(sel);
+            var_i32.SetSelection(sel);
+            var_i64.SetSelection(sel);
+            var_u8.SetSelection(sel);
+            var_u16.SetSelection(sel);
+            var_u32.SetSelection(sel);
+            var_u64.SetSelection(sel);
+            var_r32.SetSelection(sel);
+            var_r64.SetSelection(sel);
+
             // Write each one
-            engine->Write(var_i8, m_TestData.I8.data() + step);
-            engine->Write(var_i16, m_TestData.I16.data() + step);
-            engine->Write(var_i32, m_TestData.I32.data() + step);
-            engine->Write(var_i64, m_TestData.I64.data() + step);
-            engine->Write(var_u8, m_TestData.U8.data() + step);
-            engine->Write(var_u16, m_TestData.U16.data() + step);
-            engine->Write(var_u32, m_TestData.U32.data() + step);
-            engine->Write(var_u64, m_TestData.U64.data() + step);
-            engine->Write(var_r32, m_TestData.R32.data() + step);
-            engine->Write(var_r64, m_TestData.R64.data() + step);
+            // fill in the variable with values from starting index to
+            // starting index + count
+            engine->Write(var_i8, currentTestData.I8.data());
+            engine->Write(var_i16, currentTestData.I16.data());
+            engine->Write(var_i32, currentTestData.I32.data());
+            engine->Write(var_i64, currentTestData.I64.data());
+            engine->Write(var_u8, currentTestData.U8.data());
+            engine->Write(var_u16, currentTestData.U16.data());
+            engine->Write(var_u32, currentTestData.U32.data());
+            engine->Write(var_u64, currentTestData.U64.data());
+            engine->Write(var_r32, currentTestData.R32.data());
+            engine->Write(var_r64, currentTestData.R64.data());
 
             // Advance to the next time step
             engine->Advance();
@@ -257,113 +341,115 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8)
         engine->Close();
     }
 
-// 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
     {
-        std::array<int8_t, 8> I8;
-        std::array<int16_t, 8> I16;
-        std::array<int32_t, 8> I32;
-        std::array<int64_t, 8> I64;
-        std::array<uint8_t, 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;
+        const size_t arraySize = Nx;
+        std::array<int8_t, arraySize> I8;
+        std::array<int16_t, arraySize> I16;
+        std::array<int32_t, arraySize> I32;
+        std::array<int64_t, arraySize> I64;
+        std::array<uint8_t, arraySize> U8;
+        std::array<uint16_t, arraySize> U16;
+        std::array<uint32_t, arraySize> U32;
+        std::array<uint64_t, arraySize> U64;
+        std::array<float, arraySize> R32;
+        std::array<double, arraySize> R64;
 
         HDF5NativeReader hdf5Reader(fname);
-
-        // Read stuff
-        for (size_t t = 0; t < 3; ++t)
+        // 1D
+        hsize_t count[1], offset[1];
+        count[0] = mpiRank * Nx;
+        offset[0] = Nx;
+        size_t globalArraySize = Nx * mpiSize;
+
+        // For each variable, we would verify its global size and type.
+        // Then we would retrieve the data back which is written by the
+        // current process and validate the value
+        for (size_t t = 0; t < NSteps; ++t)
         {
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize);
+
             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());
+            ASSERT_EQ(gDims[0], globalArraySize);
+            hdf5Reader.ReadVar("i8", I8.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[0], globalArraySize);
+            hdf5Reader.ReadVar("i16", I16.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[0], globalArraySize);
+            hdf5Reader.ReadVar("i32", I32.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[0], globalArraySize);
+            hdf5Reader.ReadVar("i64", I64.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[0], globalArraySize);
+            hdf5Reader.ReadVar("u8", U8.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[0], globalArraySize);
+            hdf5Reader.ReadVar("u16", U16.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[0], globalArraySize);
+            hdf5Reader.ReadVar("u32", U32.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[0], globalArraySize);
+            hdf5Reader.ReadVar("u64", U64.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[0], globalArraySize);
+            hdf5Reader.ReadVar("r32", R32.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[0], globalArraySize);
+            hdf5Reader.ReadVar("r64", R64.data(), count, offset, arraySize);
 
             // Check if it's correct
-            for (size_t i = 0; i < 8; ++i)
+            for (size_t i = 0; i < Nx; ++i)
             {
                 std::stringstream ss;
-                ss << "t=" << t << " i=" << i;
+                ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
                 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;
+                EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
+                EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
+                EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
+                EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
+                EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
+                EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
+                EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
+                EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
+                EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
+                EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
             }
-
             hdf5Reader.Advance();
         }
     }
@@ -392,46 +478,83 @@ TEST_F(HDF5WriteReadTest, DISABLED_HDF5WriteADIOS2HDF5Read1D8)
 // ADIOS2 write, native HDF5 read
 TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4)
 {
+    // Each process would write a 2x4 array and all processes would
+    // form a 2D 2 * (numberOfProcess*Nx) matrix where Nx is 4 here
     std::string fname = "ADIOS2HDF5WriteHDF5Read2D2x4Test.h5";
 
+    int mpiRank = 0, mpiSize = 1;
+    // Number of rows
+    const std::size_t Nx = 4;
+
+    // Number of rows
+    const std::size_t Ny = 2;
+
+    // Number of steps
+    const std::size_t NSteps = 3;
+
+#ifdef ADIOS2_HAVE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
     // Write test data using ADIOS2
     {
+#ifdef ADIOS2_HAVE_MPI
+        adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON);
+#else
         adios2::ADIOS adios(true);
+#endif
         adios2::IO &io = adios.DeclareIO("TestIO");
 
-        // Declare 1D variables
+        // Declare 2D variables (Ny * (NumOfProcesses * Nx))
+        // The local process' part (start, count) can be defined now or later
+        // before Write().
         {
-            auto &var_i8 =
-                io.DefineVariable<int8_t>("i8", {}, {}, adios2::Dims{2, 4});
+            adios2::Dims shape{static_cast<unsigned int>(Ny),
+                               static_cast<unsigned int>(Nx * mpiSize)};
+            adios2::Dims start{static_cast<unsigned int>(0),
+                               static_cast<unsigned int>(mpiRank * Nx)};
+            adios2::Dims count{static_cast<unsigned int>(Ny),
+                               static_cast<unsigned int>(Nx)};
+            auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count);
             auto &var_i16 =
-                io.DefineVariable<int16_t>("i16", {}, {}, adios2::Dims{2, 4});
+                io.DefineVariable<int16_t>("i16", shape, start, count);
             auto &var_i32 =
-                io.DefineVariable<int32_t>("i32", {}, {}, adios2::Dims{2, 4});
+                io.DefineVariable<int32_t>("i32", shape, start, count);
             auto &var_i64 =
-                io.DefineVariable<int64_t>("i64", {}, {}, adios2::Dims{2, 4});
+                io.DefineVariable<int64_t>("i64", shape, start, count);
             auto &var_u8 =
-                io.DefineVariable<uint8_t>("u8", {}, {}, adios2::Dims{2, 4});
+                io.DefineVariable<uint8_t>("u8", shape, start, count);
             auto &var_u16 =
-                io.DefineVariable<uint16_t>("u16", {}, {}, adios2::Dims{2, 4});
+                io.DefineVariable<uint16_t>("u16", shape, start, count);
             auto &var_u32 =
-                io.DefineVariable<uint32_t>("u32", {}, {}, adios2::Dims{2, 4});
+                io.DefineVariable<uint32_t>("u32", shape, start, count);
             auto &var_u64 =
-                io.DefineVariable<uint64_t>("u64", {}, {}, adios2::Dims{2, 4});
+                io.DefineVariable<uint64_t>("u64", shape, start, count);
             auto &var_r32 =
-                io.DefineVariable<float>("r32", {}, {}, adios2::Dims{2, 4});
+                io.DefineVariable<float>("r32", shape, start, count);
             auto &var_r64 =
-                io.DefineVariable<double>("r64", {}, {}, adios2::Dims{2, 4});
+                io.DefineVariable<double>("r64", shape, start, count);
         }
 
+        // Create the ADIOS 1 Engine
         io.SetEngine("HDF5Writer");
+
+#ifdef ADIOS2_HAVE_MPI
+        io.AddTransport("file", {{"library", "MPI"}});
+#else
         io.AddTransport("file");
+#endif
 
-        // Create the HDF5 Engine
         auto engine = io.Open(fname, adios2::OpenMode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
-        for (size_t step = 0; step < 3; ++step)
+        for (size_t step = 0; step < NSteps; ++step)
         {
+            // Generate test data for each process uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
+
             // Retrieve the variables that previously went out of scope
             auto &var_i8 = io.GetVariable<int8_t>("i8");
             auto &var_i16 = io.GetVariable<int16_t>("i16");
@@ -444,17 +567,34 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4)
             auto &var_r32 = io.GetVariable<float>("r32");
             auto &var_r64 = io.GetVariable<double>("r64");
 
+            // Make a 2D selection to describe the local dimensions of the
+            // variable we write and its offsets in the global spaces
+            adios2::SelectionBoundingBox sel(
+                {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx});
+            var_i8.SetSelection(sel);
+            var_i16.SetSelection(sel);
+            var_i32.SetSelection(sel);
+            var_i64.SetSelection(sel);
+            var_u8.SetSelection(sel);
+            var_u16.SetSelection(sel);
+            var_u32.SetSelection(sel);
+            var_u64.SetSelection(sel);
+            var_r32.SetSelection(sel);
+            var_r64.SetSelection(sel);
+
             // Write each one
-            engine->Write(var_i8, m_TestData.I8.data() + step);
-            engine->Write(var_i16, m_TestData.I16.data() + step);
-            engine->Write(var_i32, m_TestData.I32.data() + step);
-            engine->Write(var_i64, m_TestData.I64.data() + step);
-            engine->Write(var_u8, m_TestData.U8.data() + step);
-            engine->Write(var_u16, m_TestData.U16.data() + step);
-            engine->Write(var_u32, m_TestData.U32.data() + step);
-            engine->Write(var_u64, m_TestData.U64.data() + step);
-            engine->Write(var_r32, m_TestData.R32.data() + step);
-            engine->Write(var_r64, m_TestData.R64.data() + step);
+            // fill in the variable with values from starting index to
+            // starting index + count
+            engine->Write(var_i8, currentTestData.I8.data());
+            engine->Write(var_i16, currentTestData.I16.data());
+            engine->Write(var_i32, currentTestData.I32.data());
+            engine->Write(var_i64, currentTestData.I64.data());
+            engine->Write(var_u8, currentTestData.U8.data());
+            engine->Write(var_u16, currentTestData.U16.data());
+            engine->Write(var_u32, currentTestData.U32.data());
+            engine->Write(var_u64, currentTestData.U64.data());
+            engine->Write(var_r32, currentTestData.R32.data());
+            engine->Write(var_r64, currentTestData.R64.data());
 
             // Advance to the next time step
             engine->Advance();
@@ -464,30 +604,36 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4)
         engine->Close();
     }
 
-// 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
     {
         HDF5NativeReader hdf5Reader(fname);
 
-        std::array<int8_t, 8> I8;
-        std::array<int16_t, 8> I16;
-        std::array<int32_t, 8> I32;
-        std::array<int64_t, 8> I64;
-        std::array<uint8_t, 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)
+        const size_t arraySize = Nx * Ny;
+        std::array<int8_t, arraySize> I8;
+        std::array<int16_t, arraySize> I16;
+        std::array<int32_t, arraySize> I32;
+        std::array<int64_t, arraySize> I64;
+        std::array<uint8_t, arraySize> U8;
+        std::array<uint16_t, arraySize> U16;
+        std::array<uint32_t, arraySize> U32;
+        std::array<uint64_t, arraySize> U64;
+        std::array<float, arraySize> R32;
+        std::array<double, arraySize> R64;
+        // 2D
+        hsize_t count[2], offset[2];
+        count[0] = 0;
+        count[1] = mpiRank * Nx;
+        offset[0] = Ny;
+        offset[1] = Nx;
+        size_t globalArraySize = Nx * mpiSize;
+
+        // For each variable, we would verify its global size and type.
+        // Then we would retrieve the data back which is written by the
+        // current process and validate the value
+        for (size_t t = 0; t < NSteps; ++t)
         {
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize);
+
             std::vector<hsize_t> gDims;
             hid_t h5Type;
 
@@ -495,89 +641,89 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4)
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("i8", I8.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("i16", I16.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("i32", I32.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("i64", I64.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("u8", U8.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("u16", U16.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("u32", U32.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("u64", U64.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("r32", R32.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("r64", R64.data(), count, offset, arraySize);
 
             // Check if it's correct
-            for (size_t i = 0; i < 8; ++i)
+            for (size_t i = 0; i < Nx; ++i)
             {
                 std::stringstream ss;
-                ss << "t=" << t << " i=" << i;
+                ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
                 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;
+                EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
+                EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
+                EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
+                EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
+                EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
+                EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
+                EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
+                EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
+                EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
+                EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
             }
             hdf5Reader.Advance();
         }
@@ -607,46 +753,83 @@ TEST_F(HDF5WriteReadTest, DISABLED_HDF5WriteADIOS2HDF5Read2D2x4)
 // ADIOS2 write, native HDF5 read
 TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2)
 {
+
+    // Each process would write a 4x2 array and all processes would
+    // form a 2D 4 * (NumberOfProcess * Nx) matrix where Nx is 2 here
     std::string fname = "ADIOS2HDF5WriteHDF5Read2D4x2Test.h5";
 
+    int mpiRank = 0, mpiSize = 1;
+    // Number of rows
+    const std::size_t Nx = 2;
+    // Number of cols
+    const std::size_t Ny = 4;
+
+    // Number of steps
+    const std::size_t NSteps = 3;
+
+#ifdef ADIOS2_HAVE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
     // Write test data using ADIOS2
     {
+#ifdef ADIOS2_HAVE_MPI
+        adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON);
+#else
         adios2::ADIOS adios(true);
+#endif
         adios2::IO &io = adios.DeclareIO("TestIO");
 
-        // Declare 1D variables
+        // Declare 2D variables (4 * (NumberOfProcess * Nx))
+        // The local process' part (start, count) can be defined now or later
+        // before Write().
         {
-            auto &var_i8 =
-                io.DefineVariable<int8_t>("i8", {}, {}, adios2::Dims{4, 2});
+            adios2::Dims shape{static_cast<unsigned int>(Ny),
+                               static_cast<unsigned int>(mpiSize * Nx)};
+            adios2::Dims start{static_cast<unsigned int>(0),
+                               static_cast<unsigned int>(mpiRank * Nx)};
+            adios2::Dims count{static_cast<unsigned int>(Ny),
+                               static_cast<unsigned int>(Nx)};
+            auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count);
             auto &var_i16 =
-                io.DefineVariable<int16_t>("i16", {}, {}, adios2::Dims{4, 2});
+                io.DefineVariable<int16_t>("i16", shape, start, count);
             auto &var_i32 =
-                io.DefineVariable<int32_t>("i32", {}, {}, adios2::Dims{4, 2});
+                io.DefineVariable<int32_t>("i32", shape, start, count);
             auto &var_i64 =
-                io.DefineVariable<int64_t>("i64", {}, {}, adios2::Dims{4, 2});
+                io.DefineVariable<int64_t>("i64", shape, start, count);
             auto &var_u8 =
-                io.DefineVariable<uint8_t>("u8", {}, {}, adios2::Dims{4, 2});
+                io.DefineVariable<uint8_t>("u8", shape, start, count);
             auto &var_u16 =
-                io.DefineVariable<uint16_t>("u16", {}, {}, adios2::Dims{4, 2});
+                io.DefineVariable<uint16_t>("u16", shape, start, count);
             auto &var_u32 =
-                io.DefineVariable<uint32_t>("u32", {}, {}, adios2::Dims{4, 2});
+                io.DefineVariable<uint32_t>("u32", shape, start, count);
             auto &var_u64 =
-                io.DefineVariable<uint64_t>("u64", {}, {}, adios2::Dims{4, 2});
+                io.DefineVariable<uint64_t>("u64", shape, start, count);
             auto &var_r32 =
-                io.DefineVariable<float>("r32", {}, {}, adios2::Dims{4, 2});
+                io.DefineVariable<float>("r32", shape, start, count);
             auto &var_r64 =
-                io.DefineVariable<double>("r64", {}, {}, adios2::Dims{4, 2});
+                io.DefineVariable<double>("r64", shape, start, count);
         }
 
-        // Create the HDF5 Engine
+        // Create the ADIOS 1 Engine
         io.SetEngine("HDF5Writer");
+
+#ifdef ADIOS2_HAVE_MPI
+        io.AddTransport("file", {{"library", "MPI"}});
+#else
         io.AddTransport("file");
+#endif
 
         auto engine = io.Open(fname, adios2::OpenMode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
-        for (size_t step = 0; step < 3; ++step)
+        for (size_t step = 0; step < NSteps; ++step)
         {
+            // Generate test data for each process uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
+
             // Retrieve the variables that previously went out of scope
             auto &var_i8 = io.GetVariable<int8_t>("i8");
             auto &var_i16 = io.GetVariable<int16_t>("i16");
@@ -659,17 +842,34 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2)
             auto &var_r32 = io.GetVariable<float>("r32");
             auto &var_r64 = io.GetVariable<double>("r64");
 
+            // Make a 2D selection to describe the local dimensions of the
+            // variable we write and its offsets in the global spaces
+            adios2::SelectionBoundingBox sel(
+                {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx});
+            var_i8.SetSelection(sel);
+            var_i16.SetSelection(sel);
+            var_i32.SetSelection(sel);
+            var_i64.SetSelection(sel);
+            var_u8.SetSelection(sel);
+            var_u16.SetSelection(sel);
+            var_u32.SetSelection(sel);
+            var_u64.SetSelection(sel);
+            var_r32.SetSelection(sel);
+            var_r64.SetSelection(sel);
+
             // Write each one
-            engine->Write(var_i8, m_TestData.I8.data() + step);
-            engine->Write(var_i16, m_TestData.I16.data() + step);
-            engine->Write(var_i32, m_TestData.I32.data() + step);
-            engine->Write(var_i64, m_TestData.I64.data() + step);
-            engine->Write(var_u8, m_TestData.U8.data() + step);
-            engine->Write(var_u16, m_TestData.U16.data() + step);
-            engine->Write(var_u32, m_TestData.U32.data() + step);
-            engine->Write(var_u64, m_TestData.U64.data() + step);
-            engine->Write(var_r32, m_TestData.R32.data() + step);
-            engine->Write(var_r64, m_TestData.R64.data() + step);
+            // fill in the variable with values from starting index to
+            // starting index + count
+            engine->Write(var_i8, currentTestData.I8.data());
+            engine->Write(var_i16, currentTestData.I16.data());
+            engine->Write(var_i32, currentTestData.I32.data());
+            engine->Write(var_i64, currentTestData.I64.data());
+            engine->Write(var_u8, currentTestData.U8.data());
+            engine->Write(var_u16, currentTestData.U16.data());
+            engine->Write(var_u32, currentTestData.U32.data());
+            engine->Write(var_u64, currentTestData.U64.data());
+            engine->Write(var_r32, currentTestData.R32.data());
+            engine->Write(var_r64, currentTestData.R64.data());
 
             // Advance to the next time step
             engine->Advance();
@@ -679,31 +879,37 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2)
         engine->Close();
     }
 
-// 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
     {
 
         HDF5NativeReader hdf5Reader(fname);
 
-        std::array<int8_t, 8> I8;
-        std::array<int16_t, 8> I16;
-        std::array<int32_t, 8> I32;
-        std::array<int64_t, 8> I64;
-        std::array<uint8_t, 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)
+        const size_t arraySize = Nx * Ny;
+        std::array<int8_t, arraySize> I8;
+        std::array<int16_t, arraySize> I16;
+        std::array<int32_t, arraySize> I32;
+        std::array<int64_t, arraySize> I64;
+        std::array<uint8_t, arraySize> U8;
+        std::array<uint16_t, arraySize> U16;
+        std::array<uint32_t, arraySize> U32;
+        std::array<uint64_t, arraySize> U64;
+        std::array<float, arraySize> R32;
+        std::array<double, arraySize> R64;
+        // 2D
+        hsize_t count[2], offset[2];
+        count[0] = 0;
+        count[1] = mpiRank * Nx;
+        offset[0] = Ny;
+        offset[1] = Nx;
+        size_t globalArraySize = Nx * mpiSize;
+
+        // For each variable, we would verify its global size and type.
+        // Then we would retrieve the data back which is written by the
+        // current process and validate the value
+        for (size_t t = 0; t < NSteps; ++t)
         {
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize);
+
             std::vector<hsize_t> gDims;
             hid_t h5Type;
 
@@ -711,88 +917,89 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2)
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("i8", I8.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("i16", I16.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("i32", I32.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("i64", I64.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("u8", U8.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("u16", U16.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("u32", U32.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("u64", U64.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("r32", R32.data(), count, offset, arraySize);
 
             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());
+            ASSERT_EQ(gDims[1], globalArraySize);
+            hdf5Reader.ReadVar("r64", R64.data(), count, offset, arraySize);
 
-            for (size_t i = 0; i < 8; ++i)
+            // Check if it's correct
+            for (size_t i = 0; i < Nx; ++i)
             {
                 std::stringstream ss;
-                ss << "t=" << t << " i=" << i;
+                ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
                 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;
+                EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
+                EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
+                EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
+                EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
+                EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
+                EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
+                EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
+                EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
+                EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
+                EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
             }
             hdf5Reader.Advance();
         }