From cd13a9ac963a9c3615e106ed16e0d5be64bd5cac Mon Sep 17 00:00:00 2001
From: William F Godoy <williamfgc@yahoo.com>
Date: Tue, 14 Nov 2017 10:46:19 -0500
Subject: [PATCH] Get functions in C, Fortran and Python bindings

Working on Fortran examples
Testing Row Major Reader
Debugging parallel read
Changed file open function
Added initial tests 1D and 2D
---
 bindings/C/adios2/adios2_c_engine.cpp         | 136 +++
 bindings/C/adios2/adios2_c_engine.h           |  25 +-
 bindings/C/adios2/adios2_c_variable.cpp       |   2 +-
 bindings/fortran/CMakeLists.txt               |   2 +
 bindings/fortran/f2c/adios2_f2c_engine.cpp    |  62 ++
 bindings/fortran/f2c/adios2_f2c_engine.h      |  18 +
 bindings/fortran/f2c/adios2_f2c_io.cpp        |  45 +-
 bindings/fortran/f2c/adios2_f2c_io.h          |   6 +
 bindings/fortran/f2c/adios2_f2c_variable.cpp  |  32 +-
 .../modules/adios2_engine_iread_mod.f90       | 660 +++++++++++++
 .../fortran/modules/adios2_engine_mod.f90     |  29 +
 .../modules/adios2_engine_read_mod.f90        | 660 +++++++++++++
 bindings/fortran/modules/adios2_io_mod.f90    |  12 +
 .../fortran/modules/adios2_parameters_mod.f90 |   4 +
 bindings/python/EnginePy.cpp                  | 206 +++-
 bindings/python/EnginePy.h                    |  18 +
 bindings/python/gluePyBind11.cpp              |  25 +-
 .../hello/bpReader/helloBPReaderHeatMap3D.cpp |  21 +-
 .../hello/bpReader/helloBPReaderHeatMap3D.f90 |  73 +-
 .../hello/bpTimeWriter/helloBPTimeWriter.cpp  | 132 ++-
 source/adios2/ADIOSMacros.h                   |  21 +
 source/adios2/core/ADIOS.h                    |  12 +-
 source/adios2/core/IO.cpp                     |  24 +-
 source/adios2/engine/bp/BPFileReader.cpp      |  17 +-
 source/adios2/helper/adiosMPIFunctions.h      |   4 +-
 source/adios2/helper/adiosMPIFunctions.tcc    |  49 +-
 source/adios2/helper/adiosMath.cpp            |  22 +-
 source/adios2/helper/adiosMath.h              |   2 +-
 source/adios2/toolkit/format/bp3/BP3Base.h    |   4 +-
 .../toolkit/format/bp3/BP3Deserializer.cpp    |   8 +-
 .../toolkit/format/bp3/BP3Deserializer.h      |   4 +-
 .../toolkit/format/bp3/BP3Deserializer.tcc    |  61 +-
 .../toolkit/transport/file/FileFStream.cpp    |   3 +-
 .../toolkit/transport/file/FilePOSIX.cpp      |   3 +-
 .../toolkit/transportman/TransportMan.cpp     |   6 +-
 .../toolkit/transportman/TransportMan.h       |  13 +-
 source/utils/bpls2/BPLS2.cpp                  |   8 +-
 testing/adios2/engine/bp/CMakeLists.txt       |  12 +-
 .../engine/bp/TestBPWriteReadADIOS2.cpp       | 912 ++++++++++++++++++
 39 files changed, 3122 insertions(+), 231 deletions(-)
 create mode 100644 bindings/fortran/modules/adios2_engine_iread_mod.f90
 create mode 100644 bindings/fortran/modules/adios2_engine_read_mod.f90
 create mode 100644 testing/adios2/engine/bp/TestBPWriteReadADIOS2.cpp

diff --git a/bindings/C/adios2/adios2_c_engine.cpp b/bindings/C/adios2/adios2_c_engine.cpp
index d2d088083..cbdd0ab08 100644
--- a/bindings/C/adios2/adios2_c_engine.cpp
+++ b/bindings/C/adios2/adios2_c_engine.cpp
@@ -156,6 +156,142 @@ void adios2_perform_puts(adios2_Engine *engine)
     engineCpp.PerformPuts();
 }
 
+void adios2_get_sync(adios2_Engine *engine, adios2_Variable *variable,
+                     void *values)
+{
+    adios2::VariableBase *variableBase =
+        reinterpret_cast<adios2::VariableBase *>(variable);
+    const std::string type(variableBase->m_Type);
+
+    adios2::Engine &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+
+    if (type == "compound")
+    {
+        // not supported
+    }
+#define declare_template_instantiation(T)                                      \
+    else if (type == adios2::GetType<T>())                                     \
+    {                                                                          \
+        engineCpp.GetSync(*dynamic_cast<adios2::Variable<T> *>(variableBase),  \
+                          reinterpret_cast<T *>(values));                      \
+    }
+    ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+}
+
+void adios2_get_sync_self(adios2_Engine *engine, adios2_Variable *variable)
+{
+    adios2::VariableBase *variableBase =
+        reinterpret_cast<adios2::VariableBase *>(variable);
+    const std::string type(variableBase->m_Type);
+
+    adios2::Engine &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+
+    if (type == "compound")
+    {
+        // not supported
+    }
+#define declare_template_instantiation(T)                                      \
+    else if (type == adios2::GetType<T>())                                     \
+    {                                                                          \
+        engineCpp.GetSync(*dynamic_cast<adios2::Variable<T> *>(variableBase)); \
+    }
+    ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+}
+
+void adios2_get_sync_by_name(adios2_Engine *engine, const char *variable_name,
+                             void *values)
+{
+    auto &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+    const std::string type(
+        engineCpp.GetIO().InquireVariableType(variable_name));
+
+    if (type == "compound")
+    {
+        // not supported
+    }
+#define declare_template_instantiation(T)                                      \
+    else if (type == adios2::GetType<T>())                                     \
+    {                                                                          \
+        engineCpp.GetSync(variable_name, reinterpret_cast<T *>(values));       \
+    }
+    ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+}
+
+void adios2_get_deferred(adios2_Engine *engine, adios2_Variable *variable,
+                         void *values)
+{
+    adios2::VariableBase *variableBase =
+        reinterpret_cast<adios2::VariableBase *>(variable);
+    const std::string type(variableBase->m_Type);
+
+    adios2::Engine &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+
+    if (type == "compound")
+    {
+        // not supported
+    }
+#define declare_template_instantiation(T)                                      \
+    else if (type == adios2::GetType<T>())                                     \
+    {                                                                          \
+        engineCpp.GetDeferred(                                                 \
+            *dynamic_cast<adios2::Variable<T> *>(variableBase),                \
+            reinterpret_cast<T *>(values));                                    \
+    }
+    ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+}
+
+void adios2_get_deferred_self(adios2_Engine *engine, adios2_Variable *variable)
+{
+    adios2::VariableBase *variableBase =
+        reinterpret_cast<adios2::VariableBase *>(variable);
+    const std::string type(variableBase->m_Type);
+
+    adios2::Engine &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+
+    if (type == "compound")
+    {
+        // not supported
+    }
+#define declare_template_instantiation(T)                                      \
+    else if (type == adios2::GetType<T>())                                     \
+    {                                                                          \
+        engineCpp.GetDeferred(                                                 \
+            *dynamic_cast<adios2::Variable<T> *>(variableBase));               \
+    }
+    ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+}
+
+void adios2_get_deferred_by_name(adios2_Engine *engine,
+                                 const char *variable_name, void *values)
+{
+    auto &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+    const std::string type(
+        engineCpp.GetIO().InquireVariableType(variable_name));
+
+    if (type == "compound")
+    {
+        // not supported
+    }
+#define declare_template_instantiation(T)                                      \
+    else if (type == adios2::GetType<T>())                                     \
+    {                                                                          \
+        engineCpp.GetDeferred(variable_name, reinterpret_cast<T *>(values));   \
+    }
+    ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+}
+
+void adios2_perform_gets(adios2_Engine *engine)
+{
+    auto &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+    engineCpp.PerformGets();
+}
+
 void adios2_end_step(adios2_Engine *engine)
 {
     auto &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
diff --git a/bindings/C/adios2/adios2_c_engine.h b/bindings/C/adios2/adios2_c_engine.h
index 178905524..7cb9af4d8 100644
--- a/bindings/C/adios2/adios2_c_engine.h
+++ b/bindings/C/adios2/adios2_c_engine.h
@@ -22,6 +22,8 @@ extern "C" {
  */
 void adios2_begin_step(adios2_Engine *engine);
 
+//***************** PUT *****************
+
 /**
  * Put a variable in IO using a adios2_Variable handler
  * @param engine handler for engine executing the write
@@ -33,7 +35,7 @@ void adios2_put_sync(adios2_Engine *engine, adios2_Variable *variable,
 
 void adios2_put_sync_self(adios2_Engine *engine, adios2_Variable *variable);
 
-void adios2_put_sync_by_name(adios2_Engine *engine, const char *variableName,
+void adios2_put_sync_by_name(adios2_Engine *engine, const char *variable_name,
                              const void *values);
 
 /**
@@ -48,10 +50,29 @@ void adios2_put_deferred(adios2_Engine *engine, adios2_Variable *variable,
 void adios2_put_deferred_self(adios2_Engine *engine, adios2_Variable *variable);
 
 void adios2_put_deferred_by_name(adios2_Engine *engine,
-                                 const char *variableName, const void *values);
+                                 const char *variable_name, const void *values);
 
 void adios2_perform_puts(adios2_Engine *engine);
 
+//***************** GET *****************
+void adios2_get_sync(adios2_Engine *engine, adios2_Variable *variable,
+                     void *values);
+
+void adios2_get_sync_self(adios2_Engine *engine, adios2_Variable *variable);
+
+void adios2_get_sync_by_name(adios2_Engine *engine, const char *variable_name,
+                             void *values);
+
+void adios2_get_deferred(adios2_Engine *engine, adios2_Variable *variable,
+                         void *values);
+
+void adios2_get_deferred_self(adios2_Engine *engine, adios2_Variable *variable);
+
+void adios2_get_deferred_by_name(adios2_Engine *engine,
+                                 const char *variable_name, void *values);
+
+void adios2_perform_gets(adios2_Engine *engine);
+
 /**
  * terminates interaction with current step
  * @param engine handler executing IO tasks
diff --git a/bindings/C/adios2/adios2_c_variable.cpp b/bindings/C/adios2/adios2_c_variable.cpp
index 405a1af08..798dd9784 100644
--- a/bindings/C/adios2/adios2_c_variable.cpp
+++ b/bindings/C/adios2/adios2_c_variable.cpp
@@ -144,7 +144,7 @@ void adios2_set_selection(adios2_Variable *variable, const size_t ndims,
         reinterpret_cast<adios2::VariableBase *>(variable);
 
     const adios2::Dims startV(start, start + ndims);
-    const adios2::Dims countV(start, start + ndims);
+    const adios2::Dims countV(count, count + ndims);
     variableBase->SetSelection({startV, countV});
     variableBase->CheckDimensions("in call to adios2_set_selection");
 }
diff --git a/bindings/fortran/CMakeLists.txt b/bindings/fortran/CMakeLists.txt
index acc3f72e6..58a4191a4 100644
--- a/bindings/fortran/CMakeLists.txt
+++ b/bindings/fortran/CMakeLists.txt
@@ -25,6 +25,8 @@ set(MODULES
      modules/adios2_engine_mod.f90 
      modules/adios2_engine_write_mod.f90 
      modules/adios2_engine_iwrite_mod.f90
+     modules/adios2_engine_read_mod.f90 
+     modules/adios2_engine_iread_mod.f90
 )
 
 add_library(adios2_f ${MODULES} ${F2C})
diff --git a/bindings/fortran/f2c/adios2_f2c_engine.cpp b/bindings/fortran/f2c/adios2_f2c_engine.cpp
index 67cc5cd5b..3a9c8108b 100644
--- a/bindings/fortran/f2c/adios2_f2c_engine.cpp
+++ b/bindings/fortran/f2c/adios2_f2c_engine.cpp
@@ -26,6 +26,7 @@ void FC_GLOBAL(adios2_begin_step_f2c,
     }
 }
 
+// ******** PUTS */
 void FC_GLOBAL(adios2_put_sync_f2c,
                ADIOS2_PUT_SYNC_F2C)(adios2_Engine **engine,
                                     adios2_Variable **variable,
@@ -58,6 +59,67 @@ void FC_GLOBAL(adios2_put_deferred_f2c,
     }
 }
 
+void FC_GLOBAL(adios2_perform_puts_f2c,
+               ADIOS2_PERFORM_PUTS_F2C)(adios2_Engine **engine, int *ierr)
+{
+    *ierr = 0;
+    try
+    {
+        adios2_perform_puts(*engine);
+    }
+    catch (std::exception &e)
+    {
+        *ierr = 1;
+    }
+}
+
+// ******** GETS */
+void FC_GLOBAL(adios2_get_sync_f2c,
+               ADIOS2_get_SYNC_F2C)(adios2_Engine **engine,
+                                    adios2_Variable **variable, void *values,
+                                    int *ierr)
+{
+    *ierr = 0;
+    try
+    {
+        adios2_get_sync(*engine, *variable, values);
+    }
+    catch (std::exception &e)
+    {
+        *ierr = 1;
+    }
+}
+
+void FC_GLOBAL(adios2_get_deferred_f2c,
+               ADIOS2_get_DEFERRED_F2C)(adios2_Engine **engine,
+                                        adios2_Variable **variable,
+                                        void *values, int *ierr)
+{
+    *ierr = 0;
+    try
+    {
+        adios2_get_deferred(*engine, *variable, values);
+    }
+    catch (std::exception &e)
+    {
+        *ierr = 1;
+    }
+}
+
+void FC_GLOBAL(adios2_perform_gets_f2c,
+               ADIOS2_PERFORM_GETS_F2C)(adios2_Engine **engine, int *ierr)
+{
+    *ierr = 0;
+    try
+    {
+        adios2_perform_gets(*engine);
+    }
+    catch (std::exception &e)
+    {
+        *ierr = 1;
+    }
+}
+
 void FC_GLOBAL(adios2_end_step_f2c, ADIOS2_END_STEP_F2C)(adios2_Engine **engine,
                                                          int *ierr)
 {
diff --git a/bindings/fortran/f2c/adios2_f2c_engine.h b/bindings/fortran/f2c/adios2_f2c_engine.h
index 0b481dbef..bc3ee6250 100644
--- a/bindings/fortran/f2c/adios2_f2c_engine.h
+++ b/bindings/fortran/f2c/adios2_f2c_engine.h
@@ -22,6 +22,7 @@ extern "C" {
 void FC_GLOBAL(adios2_begin_step_f2c,
                ADIOS2_BEGIN_STEP_F2C)(adios2_Engine **engine, int *ierr);
 
+// ************** PUT
 void FC_GLOBAL(adios2_put_sync_f2c,
                ADIOS2_PUT_SYNC_F2C)(adios2_Engine **engine,
                                     adios2_Variable **variable,
@@ -32,6 +33,23 @@ void FC_GLOBAL(adios2_put_deferred_f2c,
                                         adios2_Variable **variable,
                                         const void *values, int *ierr);
 
+void FC_GLOBAL(adios2_perform_puts_f2c,
+               ADIOS2_PERFORM_PUTS_F2C)(adios2_Engine **engine, int *ierr);
+
+// ************** GET
+void FC_GLOBAL(adios2_get_sync_f2c,
+               ADIOS2_get_SYNC_F2C)(adios2_Engine **engine,
+                                    adios2_Variable **variable, void *values,
+                                    int *ierr);
+
+void FC_GLOBAL(adios2_get_deferred_f2c,
+               ADIOS2_get_DEFERRED_F2C)(adios2_Engine **engine,
+                                        adios2_Variable **variable,
+                                        void *values, int *ierr);
+
+void FC_GLOBAL(adios2_perform_gets_f2c,
+               ADIOS2_PERFORM_GETS_F2C)(adios2_Engine **engine, int *ierr);
+
 void FC_GLOBAL(adios2_end_step_f2c, ADIOS2_END_STEP_F2C)(adios2_Engine **engine,
                                                          int *ierr);
 
diff --git a/bindings/fortran/f2c/adios2_f2c_io.cpp b/bindings/fortran/f2c/adios2_f2c_io.cpp
index 615f2e2a4..99113da38 100644
--- a/bindings/fortran/f2c/adios2_f2c_io.cpp
+++ b/bindings/fortran/f2c/adios2_f2c_io.cpp
@@ -78,7 +78,8 @@ void FC_GLOBAL(adios2_define_variable_f2c, ADIOS2_DEFINE_VARIABLE_F2C)(
     const int *count, const int *constant_dims, int *ierr)
 {
     auto lf_IntToSizeT = [](const int *dimensions, const int size,
-                            std::vector<std::size_t> &output) {
+                            std::vector<std::size_t> &output,
+                            const bool offset) {
 
         if (dimensions == nullptr)
         {
@@ -86,18 +87,29 @@ void FC_GLOBAL(adios2_define_variable_f2c, ADIOS2_DEFINE_VARIABLE_F2C)(
         }
 
         output.resize(size);
-        for (unsigned int d = 0; d < size; ++d)
+
+        if (offset)
+        {
+            for (unsigned int d = 0; d < size; ++d)
+            {
+                output[d] = dimensions[d] - 1;
+            }
+        }
+        else
         {
-            output[d] = dimensions[d];
+            for (unsigned int d = 0; d < size; ++d)
+            {
+                output[d] = dimensions[d];
+            }
         }
     };
 
     *ierr = 0;
 
     std::vector<std::size_t> shapeV, startV, countV;
-    lf_IntToSizeT(shape, *ndims, shapeV);
-    lf_IntToSizeT(start, *ndims, startV);
-    lf_IntToSizeT(count, *ndims, countV);
+    lf_IntToSizeT(shape, *ndims, shapeV, false);
+    lf_IntToSizeT(start, *ndims, startV, true);
+    lf_IntToSizeT(count, *ndims, countV, false);
 
     try
     {
@@ -112,6 +124,27 @@ void FC_GLOBAL(adios2_define_variable_f2c, ADIOS2_DEFINE_VARIABLE_F2C)(
     }
 }
 
+void FC_GLOBAL(adios2_inquire_variable_f2c,
+               ADIOS2_INQUIRE_VARIABLE_F2C)(adios2_Variable **variable,
+                                            adios2_IO **io,
+                                            const char *variable_name,
+                                            int *ierr)
+{
+    *ierr = 0;
+    try
+    {
+        *variable = adios2_inquire_variable(*io, variable_name);
+        if (*variable == nullptr)
+        {
+            *ierr = 2;
+        }
+    }
+    catch (std::exception &e)
+    {
+        *ierr = 1;
+    }
+}
+
 void FC_GLOBAL(adios2_open_f2c,
                ADIOS2_OPEN_F2C)(adios2_Engine **engine, adios2_IO **io,
                                 const char *name, const int *open_mode,
diff --git a/bindings/fortran/f2c/adios2_f2c_io.h b/bindings/fortran/f2c/adios2_f2c_io.h
index 0e73994df..b5aa9b364 100644
--- a/bindings/fortran/f2c/adios2_f2c_io.h
+++ b/bindings/fortran/f2c/adios2_f2c_io.h
@@ -39,6 +39,12 @@ void FC_GLOBAL(adios2_define_variable_f2c, ADIOS2_DEFINE_VARIABLE_F2C)(
     const int *type, const int *ndims, const int *shape, const int *start,
     const int *count, const int *constant_dims, int *ierr);
 
+void FC_GLOBAL(adios2_inquire_variable_f2c,
+               ADIOS2_INQUIRE_VARIABLE_F2C)(adios2_Variable **variable,
+                                            adios2_IO **io,
+                                            const char *variable_name,
+                                            int *ierr);
+
 void FC_GLOBAL(adios2_open_f2c,
                ADIOS2_OPEN_F2C)(adios2_Engine **engine, adios2_IO **io,
                                 const char *name, const int *open_mode,
diff --git a/bindings/fortran/f2c/adios2_f2c_variable.cpp b/bindings/fortran/f2c/adios2_f2c_variable.cpp
index 97d44bf79..799f6626a 100644
--- a/bindings/fortran/f2c/adios2_f2c_variable.cpp
+++ b/bindings/fortran/f2c/adios2_f2c_variable.cpp
@@ -64,6 +64,33 @@ void FC_GLOBAL(adios2_set_selection_f2c,
                                          const int *ndims, const int *start,
                                          const int *count, int *ierr)
 {
+    auto lf_IntToSizeT = [](const int *dimensions, const int size,
+                            std::vector<std::size_t> &output,
+                            const bool offset) {
+
+        if (dimensions == nullptr)
+        {
+            return;
+        }
+
+        output.resize(size);
+
+        if (offset)
+        {
+            for (unsigned int d = 0; d < size; ++d)
+            {
+                output[d] = dimensions[d] - 1;
+            }
+        }
+        else
+        {
+            for (unsigned int d = 0; d < size; ++d)
+            {
+                output[d] = dimensions[d];
+            }
+        }
+    };
+
     *ierr = 0;
     if (start == nullptr || count == nullptr)
     {
@@ -71,8 +98,9 @@ void FC_GLOBAL(adios2_set_selection_f2c,
         return;
     }
 
-    std::vector<std::size_t> startV(start, start + *ndims);
-    std::vector<std::size_t> countV(count, count + *ndims);
+    std::vector<std::size_t> startV, countV;
+    lf_IntToSizeT(start, *ndims, startV, true);
+    lf_IntToSizeT(count, *ndims, countV, false);
 
     try
     {
diff --git a/bindings/fortran/modules/adios2_engine_iread_mod.f90 b/bindings/fortran/modules/adios2_engine_iread_mod.f90
new file mode 100644
index 000000000..44ac5b503
--- /dev/null
+++ b/bindings/fortran/modules/adios2_engine_iread_mod.f90
@@ -0,0 +1,660 @@
+!
+! Distributed under the OSI-approved Apache License, Version 2.0.  See
+!  accompanying file Copyright.txt for details.
+!
+!  adios2_engine_iread_mod.f90 : ADIOS2 Fortran bindings for Engine generic
+!                                deferred READ (iread) functions
+!
+!   Created on: Aug 22, 2017
+!       Author: William F Godoy godoywf@ornl.gov
+!
+module adios2_engine_iread
+
+    interface adios2_iread
+
+        ! Single Value
+        module procedure adios2_iread_integer
+        module procedure adios2_iread_real
+        module procedure adios2_iread_dp
+        module procedure adios2_iread_complex
+        module procedure adios2_iread_complex_dp
+        module procedure adios2_iread_integer1
+        module procedure adios2_iread_integer2
+        module procedure adios2_iread_integer8
+
+        ! 1D Array
+        module procedure adios2_iread_integer_1d
+        module procedure adios2_iread_real_1d
+        module procedure adios2_iread_dp_1d
+        module procedure adios2_iread_complex_1d
+        module procedure adios2_iread_complex_dp_1d
+        module procedure adios2_iread_integer1_1d
+        module procedure adios2_iread_integer2_1d
+        module procedure adios2_iread_integer8_1d
+
+        ! 2D Array
+        module procedure adios2_iread_integer_2d
+        module procedure adios2_iread_real_2d
+        module procedure adios2_iread_dp_2d
+        module procedure adios2_iread_complex_2d
+        module procedure adios2_iread_complex_dp_2d
+        module procedure adios2_iread_integer1_2d
+        module procedure adios2_iread_integer2_2d
+        module procedure adios2_iread_integer8_2d
+
+        ! 3D Array
+        module procedure adios2_iread_integer_3d
+        module procedure adios2_iread_real_3d
+        module procedure adios2_iread_dp_3d
+        module procedure adios2_iread_complex_3d
+        module procedure adios2_iread_complex_dp_3d
+        module procedure adios2_iread_integer1_3d
+        module procedure adios2_iread_integer2_3d
+        module procedure adios2_iread_integer8_3d
+
+        ! 4D Array
+        module procedure adios2_iread_integer_4d
+        module procedure adios2_iread_real_4d
+        module procedure adios2_iread_dp_4d
+        module procedure adios2_iread_complex_4d
+        module procedure adios2_iread_complex_dp_4d
+        module procedure adios2_iread_integer1_4d
+        module procedure adios2_iread_integer2_4d
+        module procedure adios2_iread_integer8_4d
+
+        ! 5D Array
+        module procedure adios2_iread_integer_5d
+        module procedure adios2_iread_real_5d
+        module procedure adios2_iread_dp_5d
+        module procedure adios2_iread_complex_5d
+        module procedure adios2_iread_complex_dp_5d
+        module procedure adios2_iread_integer1_5d
+        module procedure adios2_iread_integer2_5d
+        module procedure adios2_iread_integer8_5d
+
+        ! 6D Array
+        module procedure adios2_iread_integer_6d
+        module procedure adios2_iread_real_6d
+        module procedure adios2_iread_dp_6d
+        module procedure adios2_iread_complex_6d
+        module procedure adios2_iread_complex_dp_6d
+        module procedure adios2_iread_integer1_6d
+        module procedure adios2_iread_integer2_6d
+        module procedure adios2_iread_integer8_6d
+
+    end interface
+
+contains
+
+    ! Single Value
+    subroutine adios2_iread_integer( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_real( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_dp( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_dp( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer1( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer2( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+
+    subroutine adios2_iread_integer8( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    ! 1D Array
+    subroutine adios2_iread_integer_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_real_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_dp_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_dp_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer1_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer2_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer8_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    ! 2D Array
+    subroutine adios2_iread_integer_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_real_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_dp_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_dp_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer1_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer2_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer8_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    ! 3D Array
+    subroutine adios2_iread_integer_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_real_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_dp_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_dp_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer1_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer2_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer8_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+
+    ! 4D Array
+    subroutine adios2_iread_integer_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_real_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_dp_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_dp_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer1_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer2_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer8_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+
+    ! 5D Array
+    subroutine adios2_iread_integer_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_real_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_dp_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_dp_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer1_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer2_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer8_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+
+    ! 6D Array
+    subroutine adios2_iread_integer_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_real_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_dp_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_complex_dp_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer1_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer2_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_iread_integer8_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_deferred_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+end module
diff --git a/bindings/fortran/modules/adios2_engine_mod.f90 b/bindings/fortran/modules/adios2_engine_mod.f90
index 3bda71211..9ff921673 100644
--- a/bindings/fortran/modules/adios2_engine_mod.f90
+++ b/bindings/fortran/modules/adios2_engine_mod.f90
@@ -10,10 +10,39 @@
 module adios2_engine
     use adios2_engine_write
     use adios2_engine_iwrite
+    use adios2_engine_read
+    use adios2_engine_iread
     implicit none
 
 contains
 
+    subroutine adios2_begin_step(engine, ierr)
+        integer(kind=8), intent(in) :: engine
+        integer, intent(out) :: ierr
+
+        call adios2_begin_step_f2c(engine, ierr)
+
+    end subroutine
+
+
+    subroutine adios2_perform_puts(engine, ierr)
+        integer(kind=8), intent(in) :: engine
+        integer, intent(out) :: ierr
+
+        call adios2_perform_puts_f2c(engine, ierr)
+
+    end subroutine
+
+
+    subroutine adios2_perform_gets(engine, ierr)
+        integer(kind=8), intent(in) :: engine
+        integer, intent(out) :: ierr
+
+        call adios2_perform_gets_f2c(engine, ierr)
+
+    end subroutine
+
+
     subroutine adios2_end_step(engine, ierr)
         integer(kind=8), intent(in) :: engine
         integer, intent(out) :: ierr
diff --git a/bindings/fortran/modules/adios2_engine_read_mod.f90 b/bindings/fortran/modules/adios2_engine_read_mod.f90
new file mode 100644
index 000000000..220937e4f
--- /dev/null
+++ b/bindings/fortran/modules/adios2_engine_read_mod.f90
@@ -0,0 +1,660 @@
+!
+! Distributed under the OSI-approved Apache License, Version 2.0.  See
+!  accompanying file Copyright.txt for details.
+!
+!  adios2_engine_read_mod.f90 : ADIOS2 Fortran bindings for Engine generic
+!                               Read functions
+!
+!   Created on: Aug 22, 2017
+!       Author: William F Godoy godoywf@ornl.gov
+!
+module adios2_engine_read
+
+    interface adios2_read
+
+        ! Single Value
+        module procedure adios2_read_integer
+        module procedure adios2_read_real
+        module procedure adios2_read_dp
+        module procedure adios2_read_complex
+        module procedure adios2_read_complex_dp
+        module procedure adios2_read_integer1
+        module procedure adios2_read_integer2
+        module procedure adios2_read_integer8
+
+        ! 1D Array
+        module procedure adios2_read_integer_1d
+        module procedure adios2_read_real_1d
+        module procedure adios2_read_dp_1d
+        module procedure adios2_read_complex_1d
+        module procedure adios2_read_complex_dp_1d
+        module procedure adios2_read_integer1_1d
+        module procedure adios2_read_integer2_1d
+        module procedure adios2_read_integer8_1d
+
+        ! 2D Array
+        module procedure adios2_read_integer_2d
+        module procedure adios2_read_real_2d
+        module procedure adios2_read_dp_2d
+        module procedure adios2_read_complex_2d
+        module procedure adios2_read_complex_dp_2d
+        module procedure adios2_read_integer1_2d
+        module procedure adios2_read_integer2_2d
+        module procedure adios2_read_integer8_2d
+
+        ! 3D Array
+        module procedure adios2_read_integer_3d
+        module procedure adios2_read_real_3d
+        module procedure adios2_read_dp_3d
+        module procedure adios2_read_complex_3d
+        module procedure adios2_read_complex_dp_3d
+        module procedure adios2_read_integer1_3d
+        module procedure adios2_read_integer2_3d
+        module procedure adios2_read_integer8_3d
+
+        ! 4D Array
+        module procedure adios2_read_integer_4d
+        module procedure adios2_read_real_4d
+        module procedure adios2_read_dp_4d
+        module procedure adios2_read_complex_4d
+        module procedure adios2_read_complex_dp_4d
+        module procedure adios2_read_integer1_4d
+        module procedure adios2_read_integer2_4d
+        module procedure adios2_read_integer8_4d
+
+        ! 5D Array
+        module procedure adios2_read_integer_5d
+        module procedure adios2_read_real_5d
+        module procedure adios2_read_dp_5d
+        module procedure adios2_read_complex_5d
+        module procedure adios2_read_complex_dp_5d
+        module procedure adios2_read_integer1_5d
+        module procedure adios2_read_integer2_5d
+        module procedure adios2_read_integer8_5d
+
+        ! 6D Array
+        module procedure adios2_read_integer_6d
+        module procedure adios2_read_real_6d
+        module procedure adios2_read_dp_6d
+        module procedure adios2_read_complex_6d
+        module procedure adios2_read_complex_dp_6d
+        module procedure adios2_read_integer1_6d
+        module procedure adios2_read_integer2_6d
+        module procedure adios2_read_integer8_6d
+
+    end interface
+
+contains
+
+    ! Single Value
+    subroutine adios2_read_integer( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_real( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_dp( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_dp( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer1( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer2( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+
+    subroutine adios2_read_integer8( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    ! 1D Array
+    subroutine adios2_read_integer_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_real_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_dp_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_dp_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer1_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer2_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer8_1d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    ! 2D Array
+    subroutine adios2_read_integer_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_real_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_dp_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_dp_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer1_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer2_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer8_2d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    ! 3D Array
+    subroutine adios2_read_integer_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_real_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_dp_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_dp_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer1_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer2_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer8_3d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+
+    ! 4D Array
+    subroutine adios2_read_integer_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_real_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_dp_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_dp_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer1_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer2_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer8_4d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+
+    ! 5D Array
+    subroutine adios2_read_integer_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_real_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_dp_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_dp_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer1_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer2_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer8_5d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+
+    ! 6D Array
+    subroutine adios2_read_integer_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer, dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_real_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real, dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_dp_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        real(kind=8), dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex, dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_complex_dp_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        complex(kind=8), dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer1_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=1), dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer2_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=2), dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+    subroutine adios2_read_integer8_6d( engine, variable, values, ierr )
+        integer(kind=8), intent(in):: engine
+        integer(kind=8), intent(in):: variable
+        integer(kind=8), dimension(:,:,:,:,:,:), intent(out):: values
+        integer, intent(out):: ierr
+
+        call adios2_get_sync_f2c(engine, variable, values, ierr)
+
+    end subroutine
+
+end module
diff --git a/bindings/fortran/modules/adios2_io_mod.f90 b/bindings/fortran/modules/adios2_io_mod.f90
index a0a1169fd..8ac098bd8 100644
--- a/bindings/fortran/modules/adios2_io_mod.f90
+++ b/bindings/fortran/modules/adios2_io_mod.f90
@@ -80,4 +80,16 @@ contains
     end subroutine
 
 
+    subroutine adios2_inquire_variable(variable, io, variable_name, ierr)
+        integer(kind=8), intent(out) :: variable
+        integer(kind=8), intent(in) :: io
+        character*(*), intent(in) :: variable_name
+        integer, intent(out) :: ierr
+
+        call adios2_inquire_variable_f2c(variable, io, &
+            & TRIM(ADJUSTL(variable_name))//char(0), ierr)
+
+    end subroutine
+
+
 end module
diff --git a/bindings/fortran/modules/adios2_parameters_mod.f90 b/bindings/fortran/modules/adios2_parameters_mod.f90
index 442901564..997ba65b5 100644
--- a/bindings/fortran/modules/adios2_parameters_mod.f90
+++ b/bindings/fortran/modules/adios2_parameters_mod.f90
@@ -35,6 +35,10 @@ module adios2_parameters
     logical, parameter :: adios2_constant_dims_true = .true.
     logical, parameter :: adios2_constant_dims_false = .false.
 
+    ! Found or not found, ierr value
+    integer, parameter :: adios2_found = 0
+    integer, parameter :: adios2_not_found = 2
+
     ! Mode
     integer, parameter :: adios2_mode_undefined = 0
     integer, parameter :: adios2_mode_write = 1
diff --git a/bindings/python/EnginePy.cpp b/bindings/python/EnginePy.cpp
index a3e7b1180..3120be8a4 100644
--- a/bindings/python/EnginePy.cpp
+++ b/bindings/python/EnginePy.cpp
@@ -5,7 +5,7 @@
  * EnginePy.cpp
  *
  *  Created on: Mar 15, 2017
- *      Author: wgodoy
+ *      Author: William F Godoy godoywf@ornl.gov
  */
 
 #include "EnginePy.h"
@@ -25,35 +25,12 @@ EnginePy::EnginePy(IO &io, const std::string &name, const Mode openMode,
 {
 }
 
+void EnginePy::BeginStep() { m_Engine.BeginStep(); }
+
 void EnginePy::PutSync(VariableBase *variable, const pybind11::array &array)
 {
-    if (variable->m_Type.empty()) // Define in IO
-    {
-        auto &io = m_Engine.GetIO();
+    DefineInIO(variable, array);
 
-        if (array.is(pybind11::array()))
-        {
-            if (m_DebugMode)
-            {
-                throw std::invalid_argument(
-                    "ERROR: passing an empty numpy array for variable " +
-                    variable->m_Name + ", in call to PutSync");
-            }
-        }
-#define declare_type(T)                                                        \
-    else if (pybind11::isinstance<                                             \
-                 pybind11::array_t<T, pybind11::array::c_style>>(array))       \
-    {                                                                          \
-        variable = &io.DefineVariable<T>(variable->m_Name, variable->m_Shape,  \
-                                         variable->m_Start, variable->m_Count, \
-                                         variable->m_ConstantDims);            \
-        m_VariablesPlaceholder.erase(variable->m_Name);                        \
-    }
-        ADIOS2_FOREACH_NUMPY_TYPE_1ARG(declare_type)
-#undef declare_type
-    }
-
-    // PutSync
     if (variable->m_Type == "compound")
     {
         // not supported
@@ -80,10 +57,143 @@ void EnginePy::PutSync(VariableBase *variable, const pybind11::array &array)
 
 void EnginePy::PutSync(VariableBase *variable, const std::string &string)
 {
+    DefineInIO(variable, string);
     m_Engine.PutSync(*dynamic_cast<adios2::Variable<std::string> *>(variable),
                      string);
 }
 
+void EnginePy::PutDeferred(VariableBase *variable, const pybind11::array &array)
+{
+    DefineInIO(variable, array);
+
+    if (variable->m_Type == "compound")
+    {
+        // not supported
+    }
+#define declare_type(T)                                                        \
+    else if (variable->m_Type == GetType<T>())                                 \
+    {                                                                          \
+        m_Engine.PutDeferred(*dynamic_cast<adios2::Variable<T> *>(variable),   \
+                             reinterpret_cast<const T *>(array.data()));       \
+    }
+    ADIOS2_FOREACH_NUMPY_TYPE_1ARG(declare_type)
+#undef declare_type
+    else
+    {
+        if (m_DebugMode)
+        {
+            throw std::invalid_argument("ERROR: variable " + variable->m_Name +
+                                        " numpy array type is not supported or "
+                                        "is not memory contiguous "
+                                        ", in call to PutDeferred\n");
+        }
+    }
+}
+
+void EnginePy::PutDeferred(VariableBase *variable, const std::string &string)
+{
+    DefineInIO(variable, string);
+    m_Engine.PutDeferred(
+        *dynamic_cast<adios2::Variable<std::string> *>(variable), string);
+}
+
+void EnginePy::PerformPuts() { m_Engine.PerformPuts(); }
+
+void EnginePy::GetSync(VariableBase *variable, pybind11::array &array)
+{
+    if (variable->m_Type == "compound")
+    {
+        // not supported
+    }
+#define declare_type(T)                                                        \
+    else if (variable->m_Type == GetType<T>())                                 \
+    {                                                                          \
+        m_Engine.GetSync(                                                      \
+            *dynamic_cast<adios2::Variable<T> *>(variable),                    \
+            reinterpret_cast<T *>(const_cast<void *>(array.data())));          \
+    }
+    ADIOS2_FOREACH_NUMPY_TYPE_1ARG(declare_type)
+#undef declare_type
+    else
+    {
+        if (m_DebugMode)
+        {
+            throw std::invalid_argument(
+                "ERROR: in variable " + variable->m_Name + " of type " +
+                variable->m_Type +
+                ", numpy array type is 1) not supported, 2) a type mismatch or"
+                "3) is not memory contiguous "
+                ", in call to GetSync\n");
+        }
+    }
+}
+
+void EnginePy::GetSync(VariableBase *variable, std::string &string)
+{
+    if (variable->m_Type == GetType<std::string>())
+    {
+        m_Engine.GetSync(
+            *dynamic_cast<adios2::Variable<std::string> *>(variable), string);
+    }
+    else
+    {
+        if (m_DebugMode)
+        {
+            throw std::invalid_argument("ERROR: variable " + variable->m_Name +
+                                        " of type " + variable->m_Type +
+                                        " is not string, in call to GetSync");
+        }
+    }
+}
+
+void EnginePy::GetDeferred(VariableBase *variable, pybind11::array &array)
+{
+    if (variable->m_Type == "compound")
+    {
+        // not supported
+    }
+#define declare_type(T)                                                        \
+    else if (variable->m_Type == GetType<T>())                                 \
+    {                                                                          \
+        m_Engine.GetDeferred(                                                  \
+            *dynamic_cast<adios2::Variable<T> *>(variable),                    \
+            reinterpret_cast<T *>(const_cast<void *>(array.data())));          \
+    }
+    ADIOS2_FOREACH_NUMPY_TYPE_1ARG(declare_type)
+#undef declare_type
+    else
+    {
+        if (m_DebugMode)
+        {
+            throw std::invalid_argument(
+                "ERROR: in variable " + variable->m_Name + " of type " +
+                variable->m_Type +
+                ", numpy array type is 1) not supported, 2) a type mismatch or"
+                "3) is not memory contiguous "
+                ", in call to GetSync\n");
+        }
+    }
+}
+
+void EnginePy::GetDeferred(VariableBase *variable, std::string &string)
+{
+    if (variable->m_Type == GetType<std::string>())
+    {
+        m_Engine.GetDeferred(
+            *dynamic_cast<adios2::Variable<std::string> *>(variable), string);
+    }
+    else
+    {
+        if (m_DebugMode)
+        {
+            throw std::invalid_argument(
+                "ERROR: variable " + variable->m_Name + " of type " +
+                variable->m_Type + " is not string, in call to GetDeferred");
+        }
+    }
+}
+void EnginePy::PerformGets() { m_Engine.PerformGets(); }
+
 void EnginePy::EndStep() { m_Engine.EndStep(); }
 
 void EnginePy::Close(const int transportIndex)
@@ -91,4 +201,46 @@ void EnginePy::Close(const int transportIndex)
     m_Engine.Close(transportIndex);
 }
 
+// PRIVATE
+void EnginePy::DefineInIO(VariableBase *variable, const pybind11::array &array)
+{
+    if (variable->m_Type.empty()) // Define in IO
+    {
+        auto &io = m_Engine.GetIO();
+
+        if (array.is(pybind11::array()))
+        {
+            if (m_DebugMode)
+            {
+                throw std::invalid_argument(
+                    "ERROR: passing an empty numpy array for variable " +
+                    variable->m_Name + ", in call to Put/Get");
+            }
+        }
+#define declare_type(T)                                                        \
+    else if (pybind11::isinstance<                                             \
+                 pybind11::array_t<T, pybind11::array::c_style>>(array))       \
+    {                                                                          \
+        variable = &io.DefineVariable<T>(variable->m_Name, variable->m_Shape,  \
+                                         variable->m_Start, variable->m_Count, \
+                                         variable->m_ConstantDims);            \
+        m_VariablesPlaceholder.erase(variable->m_Name);                        \
+    }
+        ADIOS2_FOREACH_NUMPY_TYPE_1ARG(declare_type)
+#undef declare_type
+    }
+}
+
+void EnginePy::DefineInIO(VariableBase *variable, const std::string &string)
+{
+    if (variable->m_Type.empty()) // Define in IO
+    {
+        auto &io = m_Engine.GetIO();
+        variable = &io.DefineVariable<std::string>(
+            variable->m_Name, variable->m_Shape, variable->m_Start,
+            variable->m_Count, variable->m_ConstantDims);
+        m_VariablesPlaceholder.erase(variable->m_Name);
+    }
+}
+
 } // end namespace adios2
diff --git a/bindings/python/EnginePy.h b/bindings/python/EnginePy.h
index e4b426345..7ef45d27f 100644
--- a/bindings/python/EnginePy.h
+++ b/bindings/python/EnginePy.h
@@ -32,9 +32,24 @@ public:
 
     ~EnginePy() = default;
 
+    void BeginStep();
+
     void PutSync(VariableBase *variable, const pybind11::array &array);
     void PutSync(VariableBase *variable, const std::string &string);
 
+    void PutDeferred(VariableBase *variable, const pybind11::array &array);
+    void PutDeferred(VariableBase *variable, const std::string &string);
+
+    void PerformPuts();
+
+    void GetSync(VariableBase *variable, pybind11::array &array);
+    void GetSync(VariableBase *variable, std::string &string);
+
+    void GetDeferred(VariableBase *variable, pybind11::array &array);
+    void GetDeferred(VariableBase *variable, std::string &string);
+
+    void PerformGets();
+
     void EndStep();
 
     void Close(const int transportIndex = -1);
@@ -43,6 +58,9 @@ private:
     Engine &m_Engine;
     std::map<std::string, VariableBase> &m_VariablesPlaceholder;
     const bool m_DebugMode;
+
+    void DefineInIO(VariableBase *variable, const pybind11::array &array);
+    void DefineInIO(VariableBase *variable, const std::string &string);
 };
 
 } // end namespace adios2
diff --git a/bindings/python/gluePyBind11.cpp b/bindings/python/gluePyBind11.cpp
index ec8b28731..374b72a11 100644
--- a/bindings/python/gluePyBind11.cpp
+++ b/bindings/python/gluePyBind11.cpp
@@ -134,7 +134,8 @@ PYBIND11_MODULE(adios2, m)
         .def("DeclareIO", &adios2::ADIOSPy::DeclareIO);
 
     pybind11::class_<adios2::VariableBase>(m, "Variable")
-        .def("SetSelection", &adios2::VariableBase::SetSelection);
+        .def("SetSelection", &adios2::VariableBase::SetSelection)
+        .def("SelectionSize", &adios2::VariableBase::SelectionSize);
 
     pybind11::class_<adios2::IOPy>(m, "IOPy")
         .def("SetEngine", &adios2::IOPy::SetEngine)
@@ -158,12 +159,34 @@ PYBIND11_MODULE(adios2, m)
                          adios2::IOPy::Open);
 
     pybind11::class_<adios2::EnginePy>(m, "EnginePy")
+        .def("BeginStep", &adios2::EnginePy::BeginStep)
         .def("PutSync", (void (adios2::EnginePy::*)(adios2::VariableBase *,
                                                     const pybind11::array &)) &
                             adios2::EnginePy::PutSync)
         .def("PutSync", (void (adios2::EnginePy::*)(adios2::VariableBase *,
                                                     const std::string &)) &
                             adios2::EnginePy::PutSync)
+        .def("PutDeferred",
+             (void (adios2::EnginePy::*)(adios2::VariableBase *,
+                                         const pybind11::array &)) &
+                 adios2::EnginePy::PutDeferred)
+        .def("PutDeferred", (void (adios2::EnginePy::*)(adios2::VariableBase *,
+                                                        const std::string &)) &
+                                adios2::EnginePy::PutDeferred)
+        .def("PerformPuts", &adios2::EnginePy::PerformPuts)
+        .def("GetSync", (void (adios2::EnginePy::*)(adios2::VariableBase *,
+                                                    pybind11::array &)) &
+                            adios2::EnginePy::GetSync)
+        .def("GetSync", (void (adios2::EnginePy::*)(adios2::VariableBase *,
+                                                    std::string &)) &
+                            adios2::EnginePy::GetSync)
+        .def("GetDeferred", (void (adios2::EnginePy::*)(adios2::VariableBase *,
+                                                        pybind11::array &)) &
+                                adios2::EnginePy::GetDeferred)
+        .def("GetDeferred", (void (adios2::EnginePy::*)(adios2::VariableBase *,
+                                                        std::string &)) &
+                                adios2::EnginePy::GetDeferred)
+        .def("PerformGets", &adios2::EnginePy::PerformGets)
         .def("EndStep", &adios2::EnginePy::EndStep)
         .def("Close", &adios2::EnginePy::Close,
              pybind11::arg("transportIndex") = -1);
diff --git a/examples/hello/bpReader/helloBPReaderHeatMap3D.cpp b/examples/hello/bpReader/helloBPReaderHeatMap3D.cpp
index 1085571c4..d41d039c1 100644
--- a/examples/hello/bpReader/helloBPReaderHeatMap3D.cpp
+++ b/examples/hello/bpReader/helloBPReaderHeatMap3D.cpp
@@ -2,17 +2,21 @@
  * Distributed under the OSI-approved Apache License, Version 2.0.  See
  * accompanying file Copyright.txt for details.
  *
- * helloBPReaderHeatMap.cpp : Writes a heat map in a regular 2D mesh,
+ * helloBPReaderHeatMap3D.cpp : Writes a heat map in a regular 3D mesh,
  * values grow from 0 in increments of 1
  *
- * temperature[gNx, Ny]
+ * temperature[gNx, Ny, Nz]
  * where: gNx = MPI_size_x * Nx
  *
- * 0                1       2  ...     Ny-1
- * Ny            Ny+1    Ny+2  ...   2*Ny-1
+ * k Map:
+ *    k= Nz-1  .          .       .             .
+ *   k=1      .          .       .             .
+ *  k=0      .          .       .             .
+ *        0          1       2  ...     Nz-1
+ *       Nz        Nz+1    Nz+2  ...   2*Nz-1
  * ...
  * ...
- * (gNx-1)*Ny   ...                  gNx*Ny-1
+ *(Ny-1)*Nz   ...                      Ny*Nz-1
  *
  *
  *  Created on: Nov 1, 2017
@@ -73,7 +77,7 @@ int main(int argc, char *argv[])
         // ************************** WRITE
         /*** IO class object: settings and factory of Settings: Variables,
          * Parameters, Transports, and Execution: Engines */
-        adios2::IO &putHeatMap = adios.DeclareIO("HeatMapWriter");
+        adios2::IO &putHeatMap = adios.DeclareIO("HeatMapWrite");
 
         adios2::Variable<unsigned int> &outTemperature =
             putHeatMap.DefineVariable<unsigned int>(
@@ -89,7 +93,7 @@ int main(int argc, char *argv[])
         // ************************** READ
         if (rank == 0)
         {
-            adios2::IO &getHeatMap = adios.DeclareIO("HeatMapReader");
+            adios2::IO &getHeatMap = adios.DeclareIO("HeatMapRead");
             adios2::Engine &bpReader =
                 getHeatMap.Open("HeatMap3D.bp", adios2::Mode::Read);
 
@@ -107,7 +111,8 @@ int main(int argc, char *argv[])
 
                 bpReader.GetSync(*inTemperature, inTemperatures.data());
 
-                std::cout << "Incoming temperature map:\n";
+                std::cout << "Temperature map selection: ";
+                std::cout << "{ start = [2,2,2], count = [4,4,4] }\n";
 
                 for (auto i = 0; i < inTemperatures.size(); ++i)
                 {
diff --git a/examples/hello/bpReader/helloBPReaderHeatMap3D.f90 b/examples/hello/bpReader/helloBPReaderHeatMap3D.f90
index 1f79e7fcd..89805866b 100644
--- a/examples/hello/bpReader/helloBPReaderHeatMap3D.f90
+++ b/examples/hello/bpReader/helloBPReaderHeatMap3D.f90
@@ -4,11 +4,14 @@ program helloBPReaderHeatMap3D
 
     implicit none
 
-    integer(kind=8) :: adios, io, var_temperatures, engine
-    integer, dimension(:,:,:), allocatable :: temperatures
+    integer(kind=8) :: adios
+    integer(kind=8) :: ioPut, var_temperatures, bpWriter
+    integer(kind=8) :: ioGet, var_temperaturesIn, bpReader
+    integer, dimension(:,:,:), allocatable :: temperatures, sel_temperatures
     integer, dimension(3) :: ishape, istart, icount
+    integer, dimension(3) :: sel_start, sel_count
     integer :: ierr, irank, isize, inx, iny, inz
-    integer :: i, j, k, iglobal, value, ilinear
+    integer :: i, j, k, iglobal, value, ilinear, icounter
 
     call MPI_INIT(ierr)
     call MPI_COMM_RANK(MPI_COMM_WORLD, irank, ierr)
@@ -18,17 +21,17 @@ program helloBPReaderHeatMap3D
     iny = 10
     inz = 10
 
-    icount = (/         inx, iny, inz  /)
-    istart = (/ irank * inx,   1,   1  /)
-    ishape = (/ isize * inx, iny, inz  /)
+    icount = (/         inx,   iny, inz  /)
+    istart = (/ irank * inx+1,   1,   1  /)
+    ishape = (/ isize * inx,   iny, inz  /)
 
     allocate( temperatures( inx, iny, inz ) )
     ! populate temperature
     do k=1, icount(3)
         do j=1, icount(2)
             do i=1, icount(1)
-                iglobal = istart(1) + i
-                value = k * ishape(2) * ishape(1) + j * ishape(1) + &
+                iglobal = istart(1) + (i-1)-1
+                value = (k-1) * ishape(1) * ishape(2) + (j-1) * ishape(1) + &
                 &       iglobal
                 temperatures(i,j,k) = value
             end do
@@ -37,23 +40,65 @@ program helloBPReaderHeatMap3D
 
     ! Start adios2 Writer
     call adios2_init( adios, MPI_COMM_WORLD, adios2_debug_mode_on, ierr )
-    call adios2_declare_io( io, adios, "bpFileIO", ierr )
+    call adios2_declare_io( ioPut, adios, 'HeatMapWrite', ierr )
 
-    call adios2_define_variable( var_temperatures, io, "temperatures", &
+    call adios2_define_variable( var_temperatures, ioPut, 'temperatures', &
         & adios2_type_integer, 3, ishape, istart, icount, &
         & adios2_constant_dims_true, ierr )
 
-    call adios2_open( engine, io, "HeatMap3D_f.bp", adios2_mode_write, ierr )
+    call adios2_open( bpWriter, ioPut, 'HeatMap3D_f.bp', &
+                    & adios2_mode_write, ierr )
 
-    call adios2_write( engine, var_temperatures, temperatures, ierr )
+    call adios2_write( bpWriter, var_temperatures, temperatures, ierr )
 
-    call adios2_close( engine, ierr )
+    call adios2_close( bpWriter, ierr )
 
 
     if( allocated(temperatures) ) deallocate(temperatures)
 
-    ! Start adios2 Reader
+    ! Start adios2 Reader in rank 0
+    if( irank == 0 ) then
 
+        call adios2_declare_io( ioGet, adios, 'HeatMapRead', ierr )
 
+        call adios2_open( bpReader, ioGet, 'HeatMap3D_f.bp', &
+                        & adios2_mode_read, ierr)
+
+        call adios2_inquire_variable( var_temperaturesIn, ioGet, &
+                                    & 'temperatures', ierr )
+
+        if( ierr == adios2_found ) then
+
+            sel_start = (/ 3, 3, 3 /)
+            sel_count = (/ 4, 4, 4 /)
+            allocate( sel_temperatures( sel_count(1), sel_count(2), &
+                                      & sel_count(3) ) )
+
+            call adios2_set_selection( var_temperaturesIn, 3, sel_start, &
+                                     & sel_count, ierr )
+
+            call adios2_read( bpReader, var_temperaturesIn, sel_temperatures, &
+                            & ierr )
+
+            write(*,'(A,3(I1,A),A,3(I1,A),A)') 'Temperature map selection  &
+                      & [ start = (', (sel_start(i),',',i=1,3) , ') &
+                      &  count =  (', (sel_count(i),',',i=1,3) , ') ]'
+
+
+            do k=1,sel_count(3)
+              do j=1,sel_count(2)
+                do i=1,sel_count(1)
+                    write(6,'(I4) ', advance="no") sel_temperatures(i,j,k)
+                end do
+                write(*,*)
+              end do
+            end do
+
+
+            if( allocated(sel_temperatures) ) deallocate(sel_temperatures)
+
+        end if
+
+    end if
 
 end program helloBPReaderHeatMap3D
diff --git a/examples/hello/bpTimeWriter/helloBPTimeWriter.cpp b/examples/hello/bpTimeWriter/helloBPTimeWriter.cpp
index 6f485e160..6ab37a388 100644
--- a/examples/hello/bpTimeWriter/helloBPTimeWriter.cpp
+++ b/examples/hello/bpTimeWriter/helloBPTimeWriter.cpp
@@ -36,69 +36,109 @@ int main(int argc, char *argv[])
          * recommended */
         adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON);
 
-        /*** IO class object: settings and factory of Settings: Variables,
-         * Parameters, Transports, and Execution: Engines */
-        adios2::IO &bpIO = adios.DeclareIO("BPFile_N2N");
-        bpIO.SetParameters({{"Threads", "2"}});
+        /// WRITE
+        {
+            /*** IO class object: settings and factory of Settings: Variables,
+             * Parameters, Transports, and Execution: Engines */
+            adios2::IO &bpIO = adios.DeclareIO("BPFile_N2N");
+            bpIO.SetParameters({{"Threads", "2"}});
 
-        /** global array: name, { shape (total dimensions) }, { start
-         * (local) },
-         * { count (local) }, all are constant dimensions */
-        const unsigned int variablesSize = 1;
-        std::vector<adios2::Variable<float> *> bpFloats(variablesSize);
+            /** global array: name, { shape (total dimensions) }, { start
+             * (local) },
+             * { count (local) }, all are constant dimensions */
+            const unsigned int variablesSize = 1;
+            std::vector<adios2::Variable<float> *> bpFloats(variablesSize);
 
-        adios2::Variable<std::string> &bpString =
-            bpIO.DefineVariable<std::string>("bpString");
+            adios2::Variable<std::string> &bpString =
+                bpIO.DefineVariable<std::string>("bpString");
 
-        for (unsigned int v = 0; v < variablesSize; ++v)
-        {
-            std::string namev("bpFloats");
-            if (v < 10)
+            for (unsigned int v = 0; v < variablesSize; ++v)
             {
-                namev += "00";
+                std::string namev("bpFloats");
+                if (v < 10)
+                {
+                    namev += "00";
+                }
+                else if (v < 100)
+                {
+                    namev += "0";
+                }
+                namev += std::to_string(v);
+
+                bpFloats[v] =
+                    &bpIO.DefineVariable<float>(namev, {size * Nx}, {rank * Nx},
+                                                {Nx}, adios2::ConstantDims);
             }
-            else if (v < 100)
+
+            /** global single value variable: name */
+            adios2::Variable<unsigned int> &bpTimeStep =
+                bpIO.DefineVariable<unsigned int>("timeStep");
+
+            /** Engine derived class, spawned to start IO operations */
+            adios2::Engine &bpWriter =
+                bpIO.Open("myVector.bp", adios2::Mode::Write);
+
+            for (unsigned int timeStep = 0; timeStep < 3; ++timeStep)
             {
-                namev += "0";
+                // bpWriter.BeginStep();
+                if (rank == 0) // global single value, only saved by rank 0
+                {
+                    bpWriter.PutSync<unsigned int>(bpTimeStep, timeStep);
+                }
+
+                // template type is optional, but recommended
+                for (unsigned int v = 0; v < variablesSize; ++v)
+                {
+                    myFloats[0] = static_cast<float>(v + timeStep);
+                    bpWriter.PutSync(*bpFloats[v], myFloats.data());
+                }
+                const std::string myString(
+                    "Hello from rank: " + std::to_string(rank) +
+                    " and timestep: " + std::to_string(timeStep));
+
+                bpWriter.PutSync(bpString, myString);
+
+                bpWriter.EndStep();
             }
-            namev += std::to_string(v);
 
-            bpFloats[v] = &bpIO.DefineVariable<float>(
-                namev, {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
+            bpWriter.Close();
         }
+        MPI_Barrier(MPI_COMM_WORLD);
 
-        /** global single value variable: name */
-        adios2::Variable<unsigned int> &bpTimeStep =
-            bpIO.DefineVariable<unsigned int>("timeStep");
+        { /////////////////////READ
+            //            if (rank == 0)
+            //            {
+            adios2::IO &ioReader = adios.DeclareIO("bpReader");
 
-        /** Engine derived class, spawned to start IO operations */
-        adios2::Engine &bpWriter =
-            bpIO.Open("myVector.bp", adios2::Mode::Write);
+            adios2::Engine &bpReader =
+                ioReader.Open("myVector.bp", adios2::Mode::Read);
 
-        for (unsigned int timeStep = 0; timeStep < 3; ++timeStep)
-        {
-            // bpWriter.BeginStep();
-            if (rank == 0) // global single value, only saved by rank 0
+            adios2::Variable<float> *bpFloats000 =
+                ioReader.InquireVariable<float>("bpFloats000");
+
+            if (bpFloats000 != nullptr)
             {
-                bpWriter.PutSync<unsigned int>(bpTimeStep, timeStep);
+                bpFloats000->SetSelection({{rank * Nx}, {Nx}});
+                bpFloats000->SetStepSelection({3, 1});
+
+                std::vector<float> data(bpFloats000->SelectionSize());
+                bpReader.GetSync(*bpFloats000, data.data());
+
+                std::cout << "Data timestep " << bpFloats000->m_StepsStart
+                          << " from rank " << rank << "\n";
+                for (const auto datum : data)
+                {
+                    std::cout << datum << " ";
+                }
+                std::cout << "\n";
             }
-
-            // template type is optional, but recommended
-            for (unsigned int v = 0; v < variablesSize; ++v)
+            else
             {
-                myFloats[0] = static_cast<float>(v + timeStep);
-                bpWriter.PutSync(*bpFloats[v], myFloats.data());
+                std::cout << "Variable bpFloats000 not found\n";
             }
-            const std::string myString(
-                "Hello from rank: " + std::to_string(rank) + " and timestep: " +
-                std::to_string(timeStep));
-
-            bpWriter.PutSync(bpString, myString);
-
-            bpWriter.EndStep();
+            bpReader.Close();
+            //}
         }
-
-        bpWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/source/adios2/ADIOSMacros.h b/source/adios2/ADIOSMacros.h
index d95c2fab7..0d002d332 100644
--- a/source/adios2/ADIOSMacros.h
+++ b/source/adios2/ADIOSMacros.h
@@ -70,6 +70,27 @@
     MACRO(std::complex<double>)                                                \
     MACRO(std::complex<long double>)
 
+#define ADIOS2_FOREACH_CHAR_TYPE_1ARG(MACRO)                                   \
+    MACRO(char)                                                                \
+    MACRO(signed char)                                                         \
+    MACRO(unsigned char)
+
+#define ADIOS2_FOREACH_NUMERIC_TYPE_1ARG(MACRO)                                \
+    MACRO(short)                                                               \
+    MACRO(unsigned short)                                                      \
+    MACRO(int)                                                                 \
+    MACRO(unsigned int)                                                        \
+    MACRO(long int)                                                            \
+    MACRO(long long int)                                                       \
+    MACRO(unsigned long int)                                                   \
+    MACRO(unsigned long long int)                                              \
+    MACRO(float)                                                               \
+    MACRO(double)                                                              \
+    MACRO(long double)                                                         \
+    MACRO(std::complex<float>)                                                 \
+    MACRO(std::complex<double>)                                                \
+    MACRO(std::complex<long double>)
+
 #define ADIOS2_FOREACH_ZFP_TYPE_1ARG(MACRO)                                    \
     MACRO(int32_t)                                                             \
     MACRO(int64_t)                                                             \
diff --git a/source/adios2/core/ADIOS.h b/source/adios2/core/ADIOS.h
index 0b00c1da8..dc093d31f 100644
--- a/source/adios2/core/ADIOS.h
+++ b/source/adios2/core/ADIOS.h
@@ -2,8 +2,7 @@
  * Distributed under the OSI-approved Apache License, Version 2.0.  See
  * accompanying file Copyright.txt for details.
  *
- * ADIOS.h : ADIOS library starting point, factory class for IO and
- * (polymorphic) Engines
+ * ADIOS.h : ADIOS library starting point, factory class for IO objects
  *  Created on: Oct 3, 2016
  *      Author: William F Godoy godoywf@ornl.gov
  */
@@ -107,11 +106,18 @@ public:
      * @param name must be unique for each operator created with DefineOperator
      * @param type from derived class
      * @param parameters optional parameters
-     * @return
+     * @return reference to Operator object
      */
     Operator &DefineOperator(const std::string name, const std::string type,
                              const Params &parameters = Params());
 
+    /**
+     * Signature for passing Callback functions as operators
+     * @param name unique operator name
+     * @param function callable function
+     * @param parameters
+     * @return reference to Operator object
+     */
     template <class R, class... Args>
     Operator &DefineOperator(const std::string name,
                              const std::function<R(Args...)> &function,
diff --git a/source/adios2/core/IO.cpp b/source/adios2/core/IO.cpp
index f780868b5..b4b0abf45 100644
--- a/source/adios2/core/IO.cpp
+++ b/source/adios2/core/IO.cpp
@@ -173,6 +173,26 @@ std::map<std::string, Params> IO::GetAvailableVariables() noexcept
         if (type == "compound")
         {
         }
+// TODO : enable string, add dimensions
+#define declare_template_instantiation(C)                                      \
+    else if (type == GetType<C>())                                             \
+    {                                                                          \
+        Variable<C> &variable = *InquireVariable<C>(name);                     \
+                                                                               \
+        const int min = static_cast<int>(variable.m_Min);                      \
+        variablesInfo[name]["Min"] = std::to_string(min);                      \
+                                                                               \
+        const int max = static_cast<int>(variable.m_Max);                      \
+        variablesInfo[name]["Max"] = std::to_string(max);                      \
+                                                                               \
+        variablesInfo[name]["StepsStart"] =                                    \
+            std::to_string(variable.m_AvailableStepsStart);                    \
+        variablesInfo[name]["StepsCount"] =                                    \
+            std::to_string(variable.m_AvailableStepsCount);                    \
+    }
+        ADIOS2_FOREACH_CHAR_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+
 #define declare_template_instantiation(T)                                      \
     else if (type == GetType<T>())                                             \
     {                                                                          \
@@ -188,10 +208,10 @@ std::map<std::string, Params> IO::GetAvailableVariables() noexcept
         variablesInfo[name]["StepsCount"] =                                    \
             std::to_string(variable.m_AvailableStepsCount);                    \
     }
-        ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
+        ADIOS2_FOREACH_NUMERIC_TYPE_1ARG(declare_template_instantiation)
 #undef declare_template_instantiation
     }
-    // TODO: add dimensions
+
     return variablesInfo;
 }
 
diff --git a/source/adios2/engine/bp/BPFileReader.cpp b/source/adios2/engine/bp/BPFileReader.cpp
index 207505d29..6900ccd06 100644
--- a/source/adios2/engine/bp/BPFileReader.cpp
+++ b/source/adios2/engine/bp/BPFileReader.cpp
@@ -8,6 +8,8 @@
  *      Author: William F Godoy godoywf@ornl.gov
  */
 
+#include <iostream> //TODO will go away
+
 #include "BPFileReader.h"
 #include "BPFileReader.tcc"
 
@@ -27,8 +29,9 @@ BPFileReader::BPFileReader(IO &io, const std::string &name, const Mode mode,
 
 void BPFileReader::PerformGets()
 {
-    const auto variablesSubFileInfo =
+    const std::map<std::string, SubFileInfoMap> variablesSubfileInfo =
         m_BP3Deserializer.PerformGetsVariablesSubFileInfo(m_IO);
+    ReadVariables(m_IO, variablesSubfileInfo);
 }
 
 void BPFileReader::Close(const int transportIndex)
@@ -89,8 +92,7 @@ void BPFileReader::InitBuffer()
                                fileSize);
     }
     // broadcast buffer to all ranks from zero
-    m_BP3Deserializer.m_Metadata.m_Buffer =
-        BroadcastVector(m_BP3Deserializer.m_Metadata.m_Buffer, m_MPIComm);
+    BroadcastVector(m_BP3Deserializer.m_Metadata.m_Buffer, m_MPIComm);
 
     // fills IO with Variables and Attributes
     m_BP3Deserializer.ParseMetadata(m_IO);
@@ -127,13 +129,14 @@ void BPFileReader::ReadVariables(
         for (const auto &subFileIndexPair : variableNamePair.second)
         {
             const size_t subFileIndex = subFileIndexPair.first;
-            const std::string subFile(
-                m_BP3Deserializer.GetBPSubFileName(m_Name, subFileIndex));
 
             if (m_SubFileManager.m_Transports.count(subFileIndex) == 0)
             {
-                m_SubFileManager.OpenFiles({subFile}, adios2::Mode::Read,
-                                           {{{"transport", "File"}}}, profile);
+                const std::string subFile(
+                    m_BP3Deserializer.GetBPSubFileName(m_Name, subFileIndex));
+
+                m_SubFileManager.OpenFileID(subFile, subFileIndex, Mode::Read,
+                                            {{"transport", "File"}}, profile);
             }
 
             for (const auto &stepPair : subFileIndexPair.second) // step
diff --git a/source/adios2/helper/adiosMPIFunctions.h b/source/adios2/helper/adiosMPIFunctions.h
index 0e4ebe68b..81a5562f6 100644
--- a/source/adios2/helper/adiosMPIFunctions.h
+++ b/source/adios2/helper/adiosMPIFunctions.h
@@ -25,8 +25,8 @@ template <class T>
 T BroadcastValue(const T &input, MPI_Comm mpiComm, const int rankSource = 0);
 
 template <class T>
-std::vector<T> BroadcastVector(const std::vector<T> &input, MPI_Comm mpiComm,
-                               const int rankSource = 0);
+void BroadcastVector(std::vector<T> &vector, MPI_Comm mpiComm,
+                     const int rankSource = 0);
 
 template <class T>
 T ReduceValues(const T source, MPI_Comm mpiComm, MPI_Op operation = MPI_SUM,
diff --git a/source/adios2/helper/adiosMPIFunctions.tcc b/source/adios2/helper/adiosMPIFunctions.tcc
index a312d1333..6bbf28df0 100644
--- a/source/adios2/helper/adiosMPIFunctions.tcc
+++ b/source/adios2/helper/adiosMPIFunctions.tcc
@@ -105,56 +105,29 @@ unsigned long long int ReduceValues(const unsigned long long int source,
 
 // BroadcastVector specializations
 template <>
-std::vector<char> BroadcastVector(const std::vector<char> &input,
-                                  MPI_Comm mpiComm, const int rankSource)
+void BroadcastVector(std::vector<char> &vector, MPI_Comm mpiComm,
+                     const int rankSource)
 {
-    // First Broadcast the size, then the contents
-    size_t inputSize = BroadcastValue(input.size(), mpiComm, rankSource);
-    int rank;
-    MPI_Comm_rank(mpiComm, &rank);
-    std::vector<char> output;
+    int size;
+    MPI_Comm_size(mpiComm, &size);
 
-    if (rank == rankSource)
+    if (size == 1)
     {
-        MPI_Bcast(const_cast<char *>(input.data()), static_cast<int>(inputSize),
-                  MPI_CHAR, rankSource, mpiComm);
-        return input; // no copy
-    }
-    else
-    {
-        output.resize(inputSize);
-        MPI_Bcast(output.data(), static_cast<int>(inputSize), MPI_CHAR,
-                  rankSource, mpiComm);
+        return;
     }
 
-    return output;
-}
-
-template <>
-std::vector<size_t> BroadcastVector(const std::vector<size_t> &input,
-                                    MPI_Comm mpiComm, const int rankSource)
-{
     // First Broadcast the size, then the contents
-    size_t inputSize = BroadcastValue(input.size(), mpiComm, rankSource);
+    size_t inputSize = BroadcastValue(vector.size(), mpiComm, rankSource);
     int rank;
     MPI_Comm_rank(mpiComm, &rank);
-    std::vector<size_t> output;
 
-    if (rank == rankSource)
+    if (rank != rankSource)
     {
-        MPI_Bcast(const_cast<size_t *>(input.data()),
-                  static_cast<int>(inputSize), ADIOS2_MPI_SIZE_T, rankSource,
-                  mpiComm);
-        return input; // no copy in rankSource
-    }
-    else
-    {
-        output.resize(inputSize);
-        MPI_Bcast(output.data(), static_cast<int>(inputSize), ADIOS2_MPI_SIZE_T,
-                  rankSource, mpiComm);
+        vector.resize(inputSize);
     }
 
-    return output;
+    MPI_Bcast(vector.data(), static_cast<int>(inputSize), MPI_CHAR, rankSource,
+              mpiComm);
 }
 
 // GatherArrays specializations
diff --git a/source/adios2/helper/adiosMath.cpp b/source/adios2/helper/adiosMath.cpp
index 5ee06cd03..79c3a2bdb 100644
--- a/source/adios2/helper/adiosMath.cpp
+++ b/source/adios2/helper/adiosMath.cpp
@@ -135,10 +135,10 @@ Box<Dims> IntersectionBox(const Box<Dims> &box1, const Box<Dims> &box2) noexcept
 }
 
 size_t LinearIndex(const Box<Dims> &localBox, const Dims &point,
-                   const bool isRowMajor, const bool isZeroIndex) noexcept
+                   const bool isRowMajor) noexcept
 {
-    auto lf_RowZero = [](const Dims &count,
-                         const Dims &normalizedPoint) -> size_t {
+    auto lf_RowMajor = [](const Dims &count,
+                          const Dims &normalizedPoint) -> size_t {
 
         const size_t countSize = count.size();
         size_t linearIndex = 0;
@@ -154,8 +154,8 @@ size_t LinearIndex(const Box<Dims> &localBox, const Dims &point,
         return linearIndex;
     };
 
-    auto lf_ColumnOne = [](const Dims &count,
-                           const Dims &normalizedPoint) -> size_t {
+    auto lf_ColumnMajor = [](const Dims &count,
+                             const Dims &normalizedPoint) -> size_t {
 
         const size_t countSize = count.size();
         size_t linearIndex = 0;
@@ -164,10 +164,10 @@ size_t LinearIndex(const Box<Dims> &localBox, const Dims &point,
 
         for (size_t p = 1; p < countSize; ++p)
         {
-            linearIndex += (normalizedPoint[countSize - p] - 1) * product;
+            linearIndex += (normalizedPoint[countSize - p]) * product;
             product /= count[countSize - p];
         }
-        linearIndex += (normalizedPoint[0] - 1); // fastest
+        linearIndex += normalizedPoint[0]; // fastest
         return linearIndex;
     };
 
@@ -190,13 +190,13 @@ size_t LinearIndex(const Box<Dims> &localBox, const Dims &point,
 
     size_t linearIndex = MaxSizeT - 1;
 
-    if (isRowMajor && isZeroIndex)
+    if (isRowMajor)
     {
-        linearIndex = lf_RowZero(count, normalizedPoint);
+        linearIndex = lf_RowMajor(count, normalizedPoint);
     }
-    else if (!isRowMajor && !isZeroIndex)
+    else
     {
-        linearIndex = lf_ColumnOne(count, normalizedPoint);
+        linearIndex = lf_ColumnMajor(count, normalizedPoint);
     }
 
     return linearIndex;
diff --git a/source/adios2/helper/adiosMath.h b/source/adios2/helper/adiosMath.h
index d8dd481fc..f5ab4bf9d 100644
--- a/source/adios2/helper/adiosMath.h
+++ b/source/adios2/helper/adiosMath.h
@@ -128,7 +128,7 @@ Box<Dims> IntersectionBox(const Box<Dims> &box1,
  * @return linear index for contiguous memory
  */
 size_t LinearIndex(const Box<Dims> &localBox, const Dims &point,
-                   const bool isRowMajor, const bool isZeroIndex) noexcept;
+                   const bool isRowMajor) noexcept;
 
 } // end namespace adios2
 
diff --git a/source/adios2/toolkit/format/bp3/BP3Base.h b/source/adios2/toolkit/format/bp3/BP3Base.h
index a5d5d0c72..45bf3174e 100644
--- a/source/adios2/toolkit/format/bp3/BP3Base.h
+++ b/source/adios2/toolkit/format/bp3/BP3Base.h
@@ -208,9 +208,7 @@ protected:
     const bool m_DebugMode = false;
 
     /** from host language in data information */
-    bool m_IsRowMajor = true; // C, C++ defaults
-    /** from host language in data information */
-    bool m_IsZeroIndex = true; // C, C++
+    bool m_IsRowMajor = true;
 
     /** method type for file I/O */
     enum IO_METHOD
diff --git a/source/adios2/toolkit/format/bp3/BP3Deserializer.cpp b/source/adios2/toolkit/format/bp3/BP3Deserializer.cpp
index eae06acfc..47f680981 100644
--- a/source/adios2/toolkit/format/bp3/BP3Deserializer.cpp
+++ b/source/adios2/toolkit/format/bp3/BP3Deserializer.cpp
@@ -117,14 +117,14 @@ void BP3Deserializer::ParsePGIndex()
     position = m_Minifooter.PGIndexStart;
 
     m_MetadataSet.DataPGCount = ReadValue<uint64_t>(buffer, position);
-    position += 10;                                        // skipping lengths
-    position += 2 + ReadValue<uint16_t>(buffer, position); // skipping name
+    position += 10; // skipping lengths
+    const uint16_t nameLength = ReadValue<uint16_t>(buffer, position);
+    position += static_cast<size_t>(nameLength); // skipping name
     const char isFortran = ReadValue<char>(buffer, position);
 
     if (isFortran == 'y')
     {
         m_IsRowMajor = false;
-        m_IsZeroIndex = false;
     }
 }
 
@@ -141,7 +141,7 @@ void BP3Deserializer::ParseVariablesIndex(IO &io)
 
         case (type_byte):
         {
-            DefineVariableInIO<char>(header, io, buffer, position);
+            DefineVariableInIO<signed char>(header, io, buffer, position);
             break;
         }
 
diff --git a/source/adios2/toolkit/format/bp3/BP3Deserializer.h b/source/adios2/toolkit/format/bp3/BP3Deserializer.h
index 01f829dcb..b81107c04 100644
--- a/source/adios2/toolkit/format/bp3/BP3Deserializer.h
+++ b/source/adios2/toolkit/format/bp3/BP3Deserializer.h
@@ -99,7 +99,7 @@ private:
      * @param intersectionBox
      */
     template <class T>
-    void ClipContiguousMemoryCommonRowZero(
+    void ClipContiguousMemoryCommonRow(
         Variable<T> &variable, const std::vector<char> &contiguousMemory,
         const Box<Dims> &blockBox, const Box<Dims> &intersectionBox) const;
 
@@ -111,7 +111,7 @@ private:
      * @param intersectionBox
      */
     template <class T>
-    void ClipContiguousMemoryCommonColumnOne(
+    void ClipContiguousMemoryCommonColumn(
         Variable<T> &variable, const std::vector<char> &contiguousMemory,
         const Box<Dims> &blockBox, const Box<Dims> &intersectionBox) const;
 };
diff --git a/source/adios2/toolkit/format/bp3/BP3Deserializer.tcc b/source/adios2/toolkit/format/bp3/BP3Deserializer.tcc
index 8e90253ee..316006292 100644
--- a/source/adios2/toolkit/format/bp3/BP3Deserializer.tcc
+++ b/source/adios2/toolkit/format/bp3/BP3Deserializer.tcc
@@ -84,10 +84,7 @@ void BP3Deserializer::DefineVariableInIO(const ElementIndexHeader &header,
 
     position = initialPosition;
 
-    size_t currentStep = 1;
-
-    std::vector<size_t> subsetPositions; // per step
-    subsetPositions.reserve(1);          // expecting one subset per step
+    size_t currentStep = 0; // Starts at 1 in bp file
 
     while (position < endPosition)
     {
@@ -100,14 +97,6 @@ void BP3Deserializer::DefineVariableInIO(const ElementIndexHeader &header,
                 buffer, position, static_cast<DataTypes>(header.DataType),
                 false);
 
-        if (subsetCharacteristics.Statistics.Step > currentStep)
-        {
-            currentStep = subsetCharacteristics.Statistics.Step;
-            variable->m_IndexStepBlockStarts[currentStep] = subsetPositions;
-            ++variable->m_AvailableStepsCount;
-            subsetPositions.clear();
-        }
-
         if (subsetCharacteristics.Statistics.Min < variable->m_Min)
         {
             variable->m_Min = subsetCharacteristics.Statistics.Min;
@@ -118,14 +107,14 @@ void BP3Deserializer::DefineVariableInIO(const ElementIndexHeader &header,
             variable->m_Max = subsetCharacteristics.Statistics.Max;
         }
 
-        subsetPositions.push_back(subsetPosition);
-        position = subsetPosition + subsetCharacteristics.EntryLength + 5;
-
-        if (position == endPosition) // check if last one
+        if (subsetCharacteristics.Statistics.Step > currentStep)
         {
-            variable->m_IndexStepBlockStarts[currentStep] = subsetPositions;
-            break;
+            currentStep = subsetCharacteristics.Statistics.Step;
+            variable->m_AvailableStepsCount =
+                subsetCharacteristics.Statistics.Step;
         }
+        variable->m_IndexStepBlockStarts[currentStep].push_back(subsetPosition);
+        position = subsetPosition + subsetCharacteristics.EntryLength + 5;
     }
 }
 
@@ -178,13 +167,13 @@ BP3Deserializer::GetSubFileInfo(const Variable<T> &variable) const
             info.Seeks.first =
                 blockCharacteristics.Statistics.PayloadOffset +
                 LinearIndex(info.BlockBox, info.IntersectionBox.first,
-                            m_IsRowMajor, m_IsZeroIndex) *
+                            m_IsRowMajor) *
                     sizeof(T);
 
             info.Seeks.second =
                 blockCharacteristics.Statistics.PayloadOffset +
                 (LinearIndex(info.BlockBox, info.IntersectionBox.second,
-                             m_IsRowMajor, m_IsZeroIndex) +
+                             m_IsRowMajor) +
                  1) *
                     sizeof(T);
 
@@ -217,20 +206,20 @@ void BP3Deserializer::ClipContiguousMemoryCommon(
         return;
     }
 
-    if (m_IsRowMajor && m_IsZeroIndex) // C, C++, Python
+    if (m_IsRowMajor) // stored with C, C++, Python
     {
-        ClipContiguousMemoryCommonRowZero(variable, contiguousMemory, blockBox,
-                                          intersectionBox);
+        ClipContiguousMemoryCommonRow(variable, contiguousMemory, blockBox,
+                                      intersectionBox);
     }
-    else if (!m_IsRowMajor && !m_IsZeroIndex) // Fortran, R
+    else // stored with Fortran, R
     {
-        ClipContiguousMemoryCommonColumnOne(variable, contiguousMemory,
-                                            blockBox, intersectionBox);
+        ClipContiguousMemoryCommonColumn(variable, contiguousMemory, blockBox,
+                                         intersectionBox);
     }
 }
 
 template <class T>
-void BP3Deserializer::ClipContiguousMemoryCommonRowZero(
+void BP3Deserializer::ClipContiguousMemoryCommonRow(
     Variable<T> &variable, const std::vector<char> &contiguousMemory,
     const Box<Dims> &blockBox, const Box<Dims> &intersectionBox) const
 {
@@ -247,17 +236,17 @@ void BP3Deserializer::ClipContiguousMemoryCommonRowZero(
     bool run = true;
 
     const size_t intersectionStart =
-        LinearIndex(blockBox, intersectionBox.first, true, true) * sizeof(T);
+        LinearIndex(blockBox, intersectionBox.first, true) * sizeof(T);
 
     while (run)
     {
         // here copy current linear memory between currentPoint and end
         const size_t contiguousStart =
-            LinearIndex(blockBox, currentPoint, true, true) * sizeof(T) -
+            LinearIndex(blockBox, currentPoint, true) * sizeof(T) -
             intersectionStart;
 
         const size_t variableStart =
-            LinearIndex(selectionBox, currentPoint, true, true) * sizeof(T);
+            LinearIndex(selectionBox, currentPoint, true) * sizeof(T);
 
         char *rawVariableData = reinterpret_cast<char *>(variable.GetData());
 
@@ -272,7 +261,7 @@ void BP3Deserializer::ClipContiguousMemoryCommonRowZero(
         while (true)
         {
             ++currentPoint[p];
-            if (currentPoint[p] > end[p]) // TODO: check end condition
+            if (currentPoint[p] > end[p])
             {
                 if (p == 0)
                 {
@@ -294,7 +283,7 @@ void BP3Deserializer::ClipContiguousMemoryCommonRowZero(
 }
 
 template <class T>
-void BP3Deserializer::ClipContiguousMemoryCommonColumnOne(
+void BP3Deserializer::ClipContiguousMemoryCommonColumn(
     Variable<T> &variable, const std::vector<char> &contiguousMemory,
     const Box<Dims> &blockBox, const Box<Dims> &intersectionBox) const
 {
@@ -311,17 +300,17 @@ void BP3Deserializer::ClipContiguousMemoryCommonColumnOne(
     bool run = true;
 
     const size_t intersectionStart =
-        LinearIndex(blockBox, intersectionBox.first, false, false) * sizeof(T);
+        LinearIndex(blockBox, intersectionBox.first, false) * sizeof(T);
 
     while (run)
     {
         // here copy current linear memory between currentPoint and end
         const size_t contiguousStart =
-            LinearIndex(blockBox, currentPoint, false, false) * sizeof(T) -
+            LinearIndex(blockBox, currentPoint, false) * sizeof(T) -
             intersectionStart;
 
         const size_t variableStart =
-            LinearIndex(selectionBox, currentPoint, false, false) * sizeof(T);
+            LinearIndex(selectionBox, currentPoint, false) * sizeof(T);
 
         char *rawVariableData = reinterpret_cast<char *>(variable.GetData());
 
@@ -336,7 +325,7 @@ void BP3Deserializer::ClipContiguousMemoryCommonColumnOne(
         while (true)
         {
             ++currentPoint[p];
-            if (currentPoint[p] > end[p]) // TODO: check end condition
+            if (currentPoint[p] > end[p])
             {
                 if (p == dimensions - 1)
                 {
diff --git a/source/adios2/toolkit/transport/file/FileFStream.cpp b/source/adios2/toolkit/transport/file/FileFStream.cpp
index e119c1596..4f33cd229 100644
--- a/source/adios2/toolkit/transport/file/FileFStream.cpp
+++ b/source/adios2/toolkit/transport/file/FileFStream.cpp
@@ -34,7 +34,8 @@ void FileFStream::Open(const std::string &name, const Mode openMode)
     case (Mode::Write):
         ProfilerStart("open");
         MkDir(m_Name);
-        m_FileStream.open(name, std::fstream::out | std::fstream::binary);
+        m_FileStream.open(name, std::fstream::out | std::fstream::binary |
+                                    std::fstream::trunc);
         ProfilerStop("open");
         break;
 
diff --git a/source/adios2/toolkit/transport/file/FilePOSIX.cpp b/source/adios2/toolkit/transport/file/FilePOSIX.cpp
index 903c82992..c11b56824 100644
--- a/source/adios2/toolkit/transport/file/FilePOSIX.cpp
+++ b/source/adios2/toolkit/transport/file/FilePOSIX.cpp
@@ -49,7 +49,8 @@ void FilePOSIX::Open(const std::string &name, const Mode openMode)
     case (Mode::Write):
         ProfilerStart("open");
         MkDir(m_Name);
-        m_FileDescriptor = open(m_Name.c_str(), O_WRONLY | O_CREAT, 0777);
+        m_FileDescriptor =
+            open(m_Name.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0777);
         ProfilerStop("open");
         break;
 
diff --git a/source/adios2/toolkit/transportman/TransportMan.cpp b/source/adios2/toolkit/transportman/TransportMan.cpp
index 21ed6773e..4505a3b28 100644
--- a/source/adios2/toolkit/transportman/TransportMan.cpp
+++ b/source/adios2/toolkit/transportman/TransportMan.cpp
@@ -54,12 +54,12 @@ void TransportMan::OpenFiles(const std::vector<std::string> &fileNames,
     }
 }
 
-void TransportMan::OpenFileID(const std::string &name, const unsigned int id,
-                              const Mode openMode, const Params &parameters,
+void TransportMan::OpenFileID(const std::string &name, const size_t id,
+                              const Mode mode, const Params &parameters,
                               const bool profile)
 {
     std::shared_ptr<Transport> file =
-        OpenFileTransport(name, openMode, parameters, profile);
+        OpenFileTransport(name, mode, parameters, profile);
     m_Transports.insert({id, file});
 }
 
diff --git a/source/adios2/toolkit/transportman/TransportMan.h b/source/adios2/toolkit/transportman/TransportMan.h
index a305236a7..2b7f51f72 100644
--- a/source/adios2/toolkit/transportman/TransportMan.h
+++ b/source/adios2/toolkit/transportman/TransportMan.h
@@ -61,9 +61,16 @@ public:
                    const std::vector<Params> &parametersVector,
                    const bool profile);
 
-    void OpenFileID(const std::string &name, const unsigned int id,
-                    const Mode openMode, const Params &parameters,
-                    const bool profile);
+    /**
+     * Used for sub-files defined by index
+     * @param name
+     * @param id
+     * @param openMode
+     * @param parameters
+     * @param profile
+     */
+    void OpenFileID(const std::string &name, const size_t id, const Mode mode,
+                    const Params &parameters, const bool profile);
 
     /**
      * Gets each transport base name from either baseName at Open or name
diff --git a/source/utils/bpls2/BPLS2.cpp b/source/utils/bpls2/BPLS2.cpp
index 335444646..3efc63443 100644
--- a/source/utils/bpls2/BPLS2.cpp
+++ b/source/utils/bpls2/BPLS2.cpp
@@ -238,8 +238,8 @@ void BPLS2::ProcessTransport() const
         for (const auto &variablePair : variablesMap)
         {
             const std::string name(variablePair.first);
-            const Params &parameters = variablePair.second;
-            const std::string type(parameters.at("Type"));
+            const Params &variableParameters = variablePair.second;
+            const std::string type(variableParameters.at("Type"));
 
             std::cout << "  ";
             std::cout << std::left << std::setw(maxTypeSize) << type << "  ";
@@ -248,8 +248,8 @@ void BPLS2::ProcessTransport() const
             // print min max
             if (m_Parameters.count("long") == 1)
             {
-                std::cout << parameters.at("Min") << " / "
-                          << parameters.at("Max");
+                std::cout << variableParameters.at("Min") << " / "
+                          << variableParameters.at("Max");
             }
             std::cout << "\n";
         }
diff --git a/testing/adios2/engine/bp/CMakeLists.txt b/testing/adios2/engine/bp/CMakeLists.txt
index b70bace79..55e8f14ea 100644
--- a/testing/adios2/engine/bp/CMakeLists.txt
+++ b/testing/adios2/engine/bp/CMakeLists.txt
@@ -3,8 +3,16 @@
 # accompanying file Copyright.txt for details.
 #------------------------------------------------------------------------------#
 
-# MPI versions of the test are not properly implemented at the moment
+add_executable(TestBPWriteReadADIOS2 TestBPWriteReadADIOS2.cpp)
+target_link_libraries(TestBPWriteReadADIOS2 adios2 gtest gtest_main)
 
+if(ADIOS2_HAVE_MPI)
+  target_link_libraries(TestBPWriteReadADIOS2 MPI::MPI_C)
+  set(extra_test_args EXEC_WRAPPER ${MPIEXEC_COMMAND})
+endif()
+
+gtest_add_tests(TARGET TestBPWriteReadADIOS2 ${extra_test_args})
+  
 if (ADIOS2_HAVE_ADIOS1)
   add_executable(TestBPWriteRead TestBPWriteRead.cpp)
   target_link_libraries(TestBPWriteRead adios2 gtest adios1::adios)
@@ -29,8 +37,6 @@ if (ADIOS2_HAVE_ADIOS1)
     target_link_libraries(TestBPWriteReadstdio MPI::MPI_C)
     target_link_libraries(TestBPWriteReadfstream MPI::MPI_C)
     target_link_libraries(TestBPWriteProfilingJSON MPI::MPI_C)
-
-    set(extra_test_args EXEC_WRAPPER ${MPIEXEC_COMMAND})
   endif()
 
   gtest_add_tests(TARGET TestBPWriteRead ${extra_test_args})
diff --git a/testing/adios2/engine/bp/TestBPWriteReadADIOS2.cpp b/testing/adios2/engine/bp/TestBPWriteReadADIOS2.cpp
new file mode 100644
index 000000000..1515c2702
--- /dev/null
+++ b/testing/adios2/engine/bp/TestBPWriteReadADIOS2.cpp
@@ -0,0 +1,912 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ */
+#include <cstdint>
+#include <cstring>
+
+#include <iostream>
+#include <stdexcept>
+
+#include <adios2.h>
+
+#include <gtest/gtest.h>
+
+#include "../SmallTestData.h"
+
+class BPWriteReadTestADIOS2 : public ::testing::Test
+{
+public:
+    BPWriteReadTestADIOS2() = default;
+
+    SmallTestData m_TestData;
+};
+
+//******************************************************************************
+// 1D 1x8 test data
+//******************************************************************************
+
+// ADIOS2 BP write, native ADIOS1 read
+TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
+{
+    // Each process would write a 1x8 array and all processes would
+    // form a mpiSize * Nx 1D array
+    const std::string fname("ADIOS2BPWriteRead1D8.bp");
+
+    int mpiRank = 0, mpiSize = 1;
+    // Number of rows
+    const size_t Nx = 8;
+
+    // Number of steps
+    const 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 BP
+
+#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 (NumOfProcesses * Nx)
+        // The local process' part (start, count) can be defined now or later
+        // before Write().
+        {
+            const adios2::Dims shape{static_cast<size_t>(Nx * mpiSize)};
+            const adios2::Dims start{static_cast<size_t>(Nx * mpiRank)};
+            const adios2::Dims count{Nx};
+
+            auto &var_iString = io.DefineVariable<std::string>("iString");
+            auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count);
+            auto &var_i16 =
+                io.DefineVariable<int16_t>("i16", shape, start, count);
+            auto &var_i32 =
+                io.DefineVariable<int32_t>("i32", shape, start, count);
+            auto &var_i64 =
+                io.DefineVariable<int64_t>("i64", shape, start, count);
+            auto &var_u8 =
+                io.DefineVariable<uint8_t>("u8", shape, start, count);
+            auto &var_u16 =
+                io.DefineVariable<uint16_t>("u16", shape, start, count);
+            auto &var_u32 =
+                io.DefineVariable<uint32_t>("u32", shape, start, count);
+            auto &var_u64 =
+                io.DefineVariable<uint64_t>("u64", shape, start, count);
+            auto &var_r32 =
+                io.DefineVariable<float>("r32", shape, start, count);
+            auto &var_r64 =
+                io.DefineVariable<double>("r64", shape, start, count);
+        }
+
+        // Create the BP Engine
+        io.SetEngine("BPFileWriter");
+
+        io.AddTransport("file");
+
+        // QUESTION: It seems that BPFilterWriter cannot overwrite existing
+        // files
+        // Ex. if you tune Nx and NSteps, the test would fail. But if you clear
+        // the cache in
+        // ${adios2Build}/testing/adios2/engine/bp/ADIOS2BPWriteADIOS1Read1D8.bp.dir,
+        // then it works
+        adios2::Engine &bpWriter = io.Open(fname, adios2::Mode::Write);
+
+        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_iString = *io.InquireVariable<std::string>("iString");
+            auto &var_i8 = *io.InquireVariable<int8_t>("i8");
+            auto &var_i16 = *io.InquireVariable<int16_t>("i16");
+            auto &var_i32 = *io.InquireVariable<int32_t>("i32");
+            auto &var_i64 = *io.InquireVariable<int64_t>("i64");
+            auto &var_u8 = *io.InquireVariable<uint8_t>("u8");
+            auto &var_u16 = *io.InquireVariable<uint16_t>("u16");
+            auto &var_u32 = *io.InquireVariable<uint32_t>("u32");
+            auto &var_u64 = *io.InquireVariable<uint64_t>("u64");
+            auto &var_r32 = *io.InquireVariable<float>("r32");
+            auto &var_r64 = *io.InquireVariable<double>("r64");
+
+            // Make a 1D selection to describe the local dimensions of the
+            // variable we write and its offsets in the global spaces
+            adios2::Box<adios2::Dims> sel({mpiRank * Nx}, {Nx});
+
+            EXPECT_THROW(var_iString.SetSelection(sel), std::invalid_argument);
+            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
+            // fill in the variable with values from starting index to
+            // starting index + count
+            bpWriter.BeginStep();
+            bpWriter.PutSync(var_iString, currentTestData.S1);
+            bpWriter.PutSync(var_i8, currentTestData.I8.data());
+            bpWriter.PutSync(var_i16, currentTestData.I16.data());
+            bpWriter.PutSync(var_i32, currentTestData.I32.data());
+            bpWriter.PutSync(var_i64, currentTestData.I64.data());
+            bpWriter.PutSync(var_u8, currentTestData.U8.data());
+            bpWriter.PutSync(var_u16, currentTestData.U16.data());
+            bpWriter.PutSync(var_u32, currentTestData.U32.data());
+            bpWriter.PutSync(var_u64, currentTestData.U64.data());
+            bpWriter.PutSync(var_r32, currentTestData.R32.data());
+            bpWriter.PutSync(var_r64, currentTestData.R64.data());
+            bpWriter.EndStep();
+        }
+
+        // Close the file
+        bpWriter.Close();
+    }
+
+    {
+        adios2::IO &io = adios.DeclareIO("ReadIO");
+
+        adios2::Engine &bpReader = io.Open(fname, adios2::Mode::Read);
+
+        //        auto var_iString = io.InquireVariable<std::string>("iString");
+        //        ASSERT_NE(var_iString, nullptr);
+        // ASSERT_EQ(var_iString->m_Shape.size(), 0);
+        // ASSERT_EQ(var_iString->m_AvailableStepsCount, NSteps);
+
+        auto var_i8 = io.InquireVariable<int8_t>("i8");
+        ASSERT_NE(var_i8, nullptr);
+        ASSERT_EQ(var_i8->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i8->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i8->m_Shape[0], mpiSize * Nx);
+
+        auto var_i16 = io.InquireVariable<int16_t>("i16");
+        ASSERT_NE(var_i16, nullptr);
+        ASSERT_EQ(var_i16->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i16->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i16->m_Shape[0], mpiSize * Nx);
+
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        ASSERT_NE(var_i32, nullptr);
+        ASSERT_EQ(var_i32->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i32->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i32->m_Shape[0], mpiSize * Nx);
+
+        auto var_i64 = io.InquireVariable<int64_t>("i64");
+        ASSERT_NE(var_i64, nullptr);
+        ASSERT_EQ(var_i64->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i64->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i64->m_Shape[0], mpiSize * Nx);
+
+        auto var_u8 = io.InquireVariable<uint8_t>("u8");
+        ASSERT_NE(var_u8, nullptr);
+        ASSERT_EQ(var_u8->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u8->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u8->m_Shape[0], mpiSize * Nx);
+
+        auto var_u16 = io.InquireVariable<uint16_t>("u16");
+        ASSERT_NE(var_u16, nullptr);
+        ASSERT_EQ(var_u16->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u16->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u16->m_Shape[0], mpiSize * Nx);
+
+        auto var_u32 = io.InquireVariable<uint32_t>("u32");
+        ASSERT_NE(var_u32, nullptr);
+        ASSERT_EQ(var_u32->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u32->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u32->m_Shape[0], mpiSize * Nx);
+
+        auto var_u64 = io.InquireVariable<uint64_t>("u64");
+        ASSERT_NE(var_u64, nullptr);
+        ASSERT_EQ(var_u64->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u64->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u64->m_Shape[0], mpiSize * Nx);
+
+        auto var_r32 = io.InquireVariable<float>("r32");
+        ASSERT_NE(var_r32, nullptr);
+        ASSERT_EQ(var_r32->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r32->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_r32->m_Shape[0], mpiSize * Nx);
+
+        auto var_r64 = io.InquireVariable<double>("r64");
+        ASSERT_NE(var_r64, nullptr);
+        ASSERT_EQ(var_r64->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r64->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_r64->m_Shape[0], mpiSize * Nx);
+
+        // TODO: other types
+
+        SmallTestData testData;
+        std::vector<char> IString(testData.S1.size());
+        std::array<int8_t, Nx> I8;
+        std::array<int16_t, Nx> I16;
+        std::array<int32_t, Nx> I32;
+        std::array<int64_t, Nx> I64;
+        std::array<uint8_t, Nx> U8;
+        std::array<uint16_t, Nx> U16;
+        std::array<uint32_t, Nx> U32;
+        std::array<uint64_t, Nx> U64;
+        std::array<float, Nx> R32;
+        std::array<double, Nx> R64;
+
+        const adios2::Dims start{mpiRank * Nx};
+        const adios2::Dims count{Nx};
+
+        const adios2::Box<adios2::Dims> sel(start, count);
+
+        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);
+
+        for (size_t t = 0; t < NSteps; ++t)
+        {
+            var_i8->SetStepSelection({t + 1, 1});
+            var_i16->SetStepSelection({t + 1, 1});
+            var_i32->SetStepSelection({t + 1, 1});
+            var_i64->SetStepSelection({t + 1, 1});
+
+            var_u8->SetStepSelection({t + 1, 1});
+            var_u16->SetStepSelection({t + 1, 1});
+            var_u32->SetStepSelection({t + 1, 1});
+            var_u64->SetStepSelection({t + 1, 1});
+
+            var_r32->SetStepSelection({t + 1, 1});
+            var_r64->SetStepSelection({t + 1, 1});
+
+            // Generate test data for each rank uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize);
+
+            bpReader.GetDeferred(*var_i8, I8.data());
+            bpReader.GetDeferred(*var_i16, I16.data());
+            bpReader.GetDeferred(*var_i32, I32.data());
+            bpReader.GetDeferred(*var_i64, I64.data());
+
+            bpReader.GetDeferred(*var_u8, U8.data());
+            bpReader.GetDeferred(*var_u16, U16.data());
+            bpReader.GetDeferred(*var_u32, U32.data());
+            bpReader.GetDeferred(*var_u64, U64.data());
+
+            bpReader.GetDeferred(*var_r32, R32.data());
+            bpReader.GetDeferred(*var_r64, R64.data());
+
+            bpReader.PerformGets();
+
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                std::stringstream ss;
+                ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
+                std::string msg = ss.str();
+
+                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;
+            }
+        }
+        bpReader.Close();
+    }
+}
+
+//******************************************************************************
+// 2D 2x4 test data
+//******************************************************************************
+
+// ADIOS2 BP write, native ADIOS1 read
+TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead2D2x4)
+{
+    // Each process would write a 2x4 array and all processes would
+    // form a 2D 2 * (numberOfProcess*Nx) matrix where Nx is 4 here
+    const std::string fname("ADIOS2BPWriteRead2D2x4Test.bp");
+
+    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 2D variables (Ny * (NumOfProcesses * Nx))
+        // The local process' part (start, count) can be defined now or later
+        // before Write().
+        {
+            const adios2::Dims shape{Ny, static_cast<size_t>(Nx * mpiSize)};
+            const adios2::Dims start{0, static_cast<size_t>(mpiRank * Nx)};
+            const adios2::Dims count{Ny, Nx};
+
+            auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count);
+            auto &var_i16 =
+                io.DefineVariable<int16_t>("i16", shape, start, count);
+            auto &var_i32 =
+                io.DefineVariable<int32_t>("i32", shape, start, count);
+            auto &var_i64 =
+                io.DefineVariable<int64_t>("i64", shape, start, count);
+            auto &var_u8 =
+                io.DefineVariable<uint8_t>("u8", shape, start, count);
+            auto &var_u16 =
+                io.DefineVariable<uint16_t>("u16", shape, start, count);
+            auto &var_u32 =
+                io.DefineVariable<uint32_t>("u32", shape, start, count);
+            auto &var_u64 =
+                io.DefineVariable<uint64_t>("u64", shape, start, count);
+            auto &var_r32 =
+                io.DefineVariable<float>("r32", shape, start, count);
+            auto &var_r64 =
+                io.DefineVariable<double>("r64", shape, start, count);
+        }
+
+        // Create the BP Engine
+        io.SetEngine("BPFileWriter");
+        io.AddTransport("file");
+
+        adios2::Engine &bpWriter = io.Open(fname, adios2::Mode::Write);
+
+        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.InquireVariable<int8_t>("i8");
+            auto &var_i16 = *io.InquireVariable<int16_t>("i16");
+            auto &var_i32 = *io.InquireVariable<int32_t>("i32");
+            auto &var_i64 = *io.InquireVariable<int64_t>("i64");
+            auto &var_u8 = *io.InquireVariable<uint8_t>("u8");
+            auto &var_u16 = *io.InquireVariable<uint16_t>("u16");
+            auto &var_u32 = *io.InquireVariable<uint32_t>("u32");
+            auto &var_u64 = *io.InquireVariable<uint64_t>("u64");
+            auto &var_r32 = *io.InquireVariable<float>("r32");
+            auto &var_r64 = *io.InquireVariable<double>("r64");
+
+            // Make a 2D selection to describe the local dimensions of the
+            // variable we write and its offsets in the global spaces
+            adios2::Box<adios2::Dims> sel(
+                {0, static_cast<size_t>(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
+            // fill in the variable with values from starting index to
+            // starting index + count
+            bpWriter.BeginStep();
+            bpWriter.PutSync(var_i8, currentTestData.I8.data());
+            bpWriter.PutSync(var_i16, currentTestData.I16.data());
+            bpWriter.PutSync(var_i32, currentTestData.I32.data());
+            bpWriter.PutSync(var_i64, currentTestData.I64.data());
+            bpWriter.PutSync(var_u8, currentTestData.U8.data());
+            bpWriter.PutSync(var_u16, currentTestData.U16.data());
+            bpWriter.PutSync(var_u32, currentTestData.U32.data());
+            bpWriter.PutSync(var_u64, currentTestData.U64.data());
+            bpWriter.PutSync(var_r32, currentTestData.R32.data());
+            bpWriter.PutSync(var_r64, currentTestData.R64.data());
+            bpWriter.EndStep();
+        }
+
+        // Close the file
+        bpWriter.Close();
+    }
+
+    {
+        adios2::IO &io = adios.DeclareIO("ReadIO");
+
+        adios2::Engine &bpReader = io.Open(fname, adios2::Mode::Read);
+
+        auto var_i8 = io.InquireVariable<int8_t>("i8");
+        ASSERT_NE(var_i8, nullptr);
+        ASSERT_EQ(var_i8->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i8->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i8->m_Shape[0], Ny);
+        ASSERT_EQ(var_i8->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_i16 = io.InquireVariable<int16_t>("i16");
+        ASSERT_NE(var_i16, nullptr);
+        ASSERT_EQ(var_i16->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i16->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i16->m_Shape[0], Ny);
+        ASSERT_EQ(var_i16->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        ASSERT_NE(var_i32, nullptr);
+        ASSERT_EQ(var_i32->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i32->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i32->m_Shape[0], Ny);
+        ASSERT_EQ(var_i32->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_i64 = io.InquireVariable<int64_t>("i64");
+        ASSERT_NE(var_i64, nullptr);
+        ASSERT_EQ(var_i64->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i64->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i64->m_Shape[0], Ny);
+        ASSERT_EQ(var_i64->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_u8 = io.InquireVariable<uint8_t>("u8");
+        ASSERT_NE(var_u8, nullptr);
+        ASSERT_EQ(var_u8->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u8->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u8->m_Shape[0], Ny);
+        ASSERT_EQ(var_u8->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_u16 = io.InquireVariable<uint16_t>("u16");
+        ASSERT_NE(var_u16, nullptr);
+        ASSERT_EQ(var_u16->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u16->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u16->m_Shape[0], Ny);
+        ASSERT_EQ(var_u16->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_u32 = io.InquireVariable<uint32_t>("u32");
+        ASSERT_NE(var_u32, nullptr);
+        ASSERT_EQ(var_u32->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u32->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u32->m_Shape[0], Ny);
+        ASSERT_EQ(var_u32->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_u64 = io.InquireVariable<uint64_t>("u64");
+        ASSERT_NE(var_u64, nullptr);
+        ASSERT_EQ(var_u64->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u64->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u64->m_Shape[0], Ny);
+        ASSERT_EQ(var_u64->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_r32 = io.InquireVariable<float>("r32");
+        ASSERT_NE(var_r32, nullptr);
+        ASSERT_EQ(var_r32->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r32->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_r32->m_Shape[0], Ny);
+        ASSERT_EQ(var_r32->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_r64 = io.InquireVariable<double>("r64");
+        ASSERT_NE(var_r64, nullptr);
+        ASSERT_EQ(var_r64->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r64->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_r64->m_Shape[0], Ny);
+        ASSERT_EQ(var_r64->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        // If the size of the array is smaller than the data
+        // the result is weird... double and uint64_t would get
+        // completely garbage data
+        std::array<int8_t, Nx * Ny> I8;
+        std::array<int16_t, Nx * Ny> I16;
+        std::array<int32_t, Nx * Ny> I32;
+        std::array<int64_t, Nx * Ny> I64;
+        std::array<uint8_t, Nx * Ny> U8;
+        std::array<uint16_t, Nx * Ny> U16;
+        std::array<uint32_t, Nx * Ny> U32;
+        std::array<uint64_t, Nx * Ny> U64;
+        std::array<float, Nx * Ny> R32;
+        std::array<double, Nx * Ny> R64;
+
+        const adios2::Dims start{0, static_cast<size_t>(mpiRank * Nx)};
+        const adios2::Dims count{Ny, Nx};
+
+        const adios2::Box<adios2::Dims> sel(start, count);
+
+        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);
+
+        for (size_t t = 0; t < NSteps; ++t)
+        {
+            var_i8->SetStepSelection({t + 1, 1});
+            var_i16->SetStepSelection({t + 1, 1});
+            var_i32->SetStepSelection({t + 1, 1});
+            var_i64->SetStepSelection({t + 1, 1});
+
+            var_u8->SetStepSelection({t + 1, 1});
+            var_u16->SetStepSelection({t + 1, 1});
+            var_u32->SetStepSelection({t + 1, 1});
+            var_u64->SetStepSelection({t + 1, 1});
+
+            var_r32->SetStepSelection({t + 1, 1});
+            var_r64->SetStepSelection({t + 1, 1});
+
+            bpReader.GetDeferred(*var_i8, I8.data());
+            bpReader.GetDeferred(*var_i16, I16.data());
+            bpReader.GetDeferred(*var_i32, I32.data());
+            bpReader.GetDeferred(*var_i64, I64.data());
+
+            bpReader.GetDeferred(*var_u8, U8.data());
+            bpReader.GetDeferred(*var_u16, U16.data());
+            bpReader.GetDeferred(*var_u32, U32.data());
+            bpReader.GetDeferred(*var_u64, U64.data());
+
+            bpReader.GetDeferred(*var_r32, R32.data());
+            bpReader.GetDeferred(*var_r64, R64.data());
+
+            bpReader.PerformGets();
+
+            // Generate test data for each rank uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize);
+
+            for (size_t i = 0; i < Nx * Ny; ++i)
+            {
+                std::stringstream ss;
+                ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
+                std::string msg = ss.str();
+
+                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;
+            }
+        }
+        bpReader.Close();
+    }
+}
+
+//******************************************************************************
+// 2D 4x2 test data
+//******************************************************************************
+
+TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead2D4x2)
+{
+    // Each process would write a 4x2 array and all processes would
+    // form a 2D 4 * (NumberOfProcess * Nx) matrix where Nx is 2 here
+    const std::string fname("ADIOS2BPWriteRead2D4x2Test.bp");
+
+    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 2D variables (4 * (NumberOfProcess * Nx))
+        // The local process' part (start, count) can be defined now or later
+        // before Write().
+        {
+            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", shape, start, count);
+            auto &var_i32 =
+                io.DefineVariable<int32_t>("i32", shape, start, count);
+            auto &var_i64 =
+                io.DefineVariable<int64_t>("i64", shape, start, count);
+            auto &var_u8 =
+                io.DefineVariable<uint8_t>("u8", shape, start, count);
+            auto &var_u16 =
+                io.DefineVariable<uint16_t>("u16", shape, start, count);
+            auto &var_u32 =
+                io.DefineVariable<uint32_t>("u32", shape, start, count);
+            auto &var_u64 =
+                io.DefineVariable<uint64_t>("u64", shape, start, count);
+            auto &var_r32 =
+                io.DefineVariable<float>("r32", shape, start, count);
+            auto &var_r64 =
+                io.DefineVariable<double>("r64", shape, start, count);
+        }
+
+        // Create the BP Engine
+        io.SetEngine("BPFileWriter");
+
+        io.AddTransport("file");
+
+        adios2::Engine &bpWriter = io.Open(fname, adios2::Mode::Write);
+
+        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.InquireVariable<int8_t>("i8");
+            auto &var_i16 = *io.InquireVariable<int16_t>("i16");
+            auto &var_i32 = *io.InquireVariable<int32_t>("i32");
+            auto &var_i64 = *io.InquireVariable<int64_t>("i64");
+            auto &var_u8 = *io.InquireVariable<uint8_t>("u8");
+            auto &var_u16 = *io.InquireVariable<uint16_t>("u16");
+            auto &var_u32 = *io.InquireVariable<uint32_t>("u32");
+            auto &var_u64 = *io.InquireVariable<uint64_t>("u64");
+            auto &var_r32 = *io.InquireVariable<float>("r32");
+            auto &var_r64 = *io.InquireVariable<double>("r64");
+
+            // Make a 2D selection to describe the local dimensions of the
+            // variable we write and its offsets in the global spaces
+            adios2::Box<adios2::Dims> 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
+            // fill in the variable with values from starting index to
+            // starting index + count
+            bpWriter.BeginStep();
+            bpWriter.PutSync(var_i8, currentTestData.I8.data());
+            bpWriter.PutSync(var_i16, currentTestData.I16.data());
+            bpWriter.PutSync(var_i32, currentTestData.I32.data());
+            bpWriter.PutSync(var_i64, currentTestData.I64.data());
+            bpWriter.PutSync(var_u8, currentTestData.U8.data());
+            bpWriter.PutSync(var_u16, currentTestData.U16.data());
+            bpWriter.PutSync(var_u32, currentTestData.U32.data());
+            bpWriter.PutSync(var_u64, currentTestData.U64.data());
+            bpWriter.PutSync(var_r32, currentTestData.R32.data());
+            bpWriter.PutSync(var_r64, currentTestData.R64.data());
+            bpWriter.EndStep();
+        }
+
+        // Close the file
+        bpWriter.Close();
+    }
+
+    {
+        adios2::IO &io = adios.DeclareIO("ReadIO");
+
+        adios2::Engine &bpReader = io.Open(fname, adios2::Mode::Read);
+
+        auto var_i8 = io.InquireVariable<int8_t>("i8");
+        ASSERT_NE(var_i8, nullptr);
+        ASSERT_EQ(var_i8->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i8->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i8->m_Shape[0], Ny);
+        ASSERT_EQ(var_i8->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_i16 = io.InquireVariable<int16_t>("i16");
+        ASSERT_NE(var_i16, nullptr);
+        ASSERT_EQ(var_i16->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i16->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i16->m_Shape[0], Ny);
+        ASSERT_EQ(var_i16->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        ASSERT_NE(var_i32, nullptr);
+        ASSERT_EQ(var_i32->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i32->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i32->m_Shape[0], Ny);
+        ASSERT_EQ(var_i32->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_i64 = io.InquireVariable<int64_t>("i64");
+        ASSERT_NE(var_i64, nullptr);
+        ASSERT_EQ(var_i64->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i64->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_i64->m_Shape[0], Ny);
+        ASSERT_EQ(var_i64->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_u8 = io.InquireVariable<uint8_t>("u8");
+        ASSERT_NE(var_u8, nullptr);
+        ASSERT_EQ(var_u8->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u8->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u8->m_Shape[0], Ny);
+        ASSERT_EQ(var_u8->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_u16 = io.InquireVariable<uint16_t>("u16");
+        ASSERT_NE(var_u16, nullptr);
+        ASSERT_EQ(var_u16->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u16->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u16->m_Shape[0], Ny);
+        ASSERT_EQ(var_u16->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_u32 = io.InquireVariable<uint32_t>("u32");
+        ASSERT_NE(var_u32, nullptr);
+        ASSERT_EQ(var_u32->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u32->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u32->m_Shape[0], Ny);
+        ASSERT_EQ(var_u32->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_u64 = io.InquireVariable<uint64_t>("u64");
+        ASSERT_NE(var_u64, nullptr);
+        ASSERT_EQ(var_u64->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u64->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_u64->m_Shape[0], Ny);
+        ASSERT_EQ(var_u64->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_r32 = io.InquireVariable<float>("r32");
+        ASSERT_NE(var_r32, nullptr);
+        ASSERT_EQ(var_r32->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r32->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_r32->m_Shape[0], Ny);
+        ASSERT_EQ(var_r32->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        auto var_r64 = io.InquireVariable<double>("r64");
+        ASSERT_NE(var_r64, nullptr);
+        ASSERT_EQ(var_r64->m_ShapeID, adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r64->m_AvailableStepsCount, NSteps);
+        ASSERT_EQ(var_r64->m_Shape[0], Ny);
+        ASSERT_EQ(var_r64->m_Shape[1], static_cast<size_t>(mpiSize * Nx));
+
+        // If the size of the array is smaller than the data
+        // the result is weird... double and uint64_t would get
+        // completely garbage data
+        std::array<int8_t, Nx * Ny> I8;
+        std::array<int16_t, Nx * Ny> I16;
+        std::array<int32_t, Nx * Ny> I32;
+        std::array<int64_t, Nx * Ny> I64;
+        std::array<uint8_t, Nx * Ny> U8;
+        std::array<uint16_t, Nx * Ny> U16;
+        std::array<uint32_t, Nx * Ny> U32;
+        std::array<uint64_t, Nx * Ny> U64;
+        std::array<float, Nx * Ny> R32;
+        std::array<double, Nx * Ny> R64;
+
+        const adios2::Dims start{0, static_cast<size_t>(mpiRank * Nx)};
+        const adios2::Dims count{Ny, Nx};
+
+        const adios2::Box<adios2::Dims> sel(start, count);
+
+        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);
+
+        for (size_t t = 0; t < NSteps; ++t)
+        {
+            var_i8->SetStepSelection({t + 1, 1});
+            var_i16->SetStepSelection({t + 1, 1});
+            var_i32->SetStepSelection({t + 1, 1});
+            var_i64->SetStepSelection({t + 1, 1});
+
+            var_u8->SetStepSelection({t + 1, 1});
+            var_u16->SetStepSelection({t + 1, 1});
+            var_u32->SetStepSelection({t + 1, 1});
+            var_u64->SetStepSelection({t + 1, 1});
+
+            var_r32->SetStepSelection({t + 1, 1});
+            var_r64->SetStepSelection({t + 1, 1});
+
+            bpReader.GetDeferred(*var_i8, I8.data());
+            bpReader.GetDeferred(*var_i16, I16.data());
+            bpReader.GetDeferred(*var_i32, I32.data());
+            bpReader.GetDeferred(*var_i64, I64.data());
+
+            bpReader.GetDeferred(*var_u8, U8.data());
+            bpReader.GetDeferred(*var_u16, U16.data());
+            bpReader.GetDeferred(*var_u32, U32.data());
+            bpReader.GetDeferred(*var_u64, U64.data());
+
+            bpReader.GetDeferred(*var_r32, R32.data());
+            bpReader.GetDeferred(*var_r64, R64.data());
+
+            bpReader.PerformGets();
+
+            // Generate test data for each rank uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize);
+
+            for (size_t i = 0; i < Nx * Ny; ++i)
+            {
+                std::stringstream ss;
+                ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
+                std::string msg = ss.str();
+
+                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;
+            }
+        }
+        bpReader.Close();
+    }
+}
+
+//******************************************************************************
+// main
+//******************************************************************************
+
+int main(int argc, char **argv)
+{
+#ifdef ADIOS2_HAVE_MPI
+    MPI_Init(nullptr, nullptr);
+#endif
+
+    ::testing::InitGoogleTest(&argc, argv);
+    int result = RUN_ALL_TESTS();
+
+#ifdef ADIOS2_HAVE_MPI
+    MPI_Finalize();
+#endif
+
+    return result;
+}
-- 
GitLab