diff --git a/bindings/C/CMakeLists.txt b/bindings/C/CMakeLists.txt
index a7d3bddfdd0f1a6f04b738d53bbaa4b941a50905..75f35a43a93c6ff2a1e013e4ff5328b2bdf3e4d4 100644
--- a/bindings/C/CMakeLists.txt
+++ b/bindings/C/CMakeLists.txt
@@ -9,6 +9,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/adios2/adios2_c_adios.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/adios2/adios2_c_glue.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/adios2/adios2_c_io.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/adios2/adios2_c_engine.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/adios2/adios2_c_variable.cpp
 )
 
 target_include_directories(adios2
@@ -26,6 +27,7 @@ install(
         adios2/adios2_c_adios.h
         adios2/adios2_c_glue.h 
         adios2/adios2_c_io.h
+        adios2/adios2_c_variable.h
         adios2/adios2_c_engine.h
   DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/adios2
 )
diff --git a/bindings/C/adios2/adios2_c_engine.cpp b/bindings/C/adios2/adios2_c_engine.cpp
index d2d0880834b4201288021e4aa8b34529d7df8e44..cbdd0ab0846e4cda143dbdb116850e22b6505aa0 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 178905524681968a70ede719b4dbf2bfd7f2adae..7cb9af4d891dd0b9354ba9d2d0689765228bb04e 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_glue.h b/bindings/C/adios2/adios2_c_glue.h
index 3b1ffd65cdd4b6d33bf9f10d78e67410a7be140e..07058f294de04a4956eed554896dc251080caadf 100644
--- a/bindings/C/adios2/adios2_c_glue.h
+++ b/bindings/C/adios2/adios2_c_glue.h
@@ -3,7 +3,7 @@
  * accompanying file Copyright.txt for details.
  *
  * adios2_c_glue.h : used by languages other than C, using the C-bindings API
- * (e.g. Fortran), not meant to be for applications
+ * (e.g. Fortran), not meant to be used by applications
  *
  *  Created on: Nov 3, 2017
  *      Author: William F Godoy godoywf@ornl.gov
diff --git a/bindings/C/adios2/adios2_c_types.h b/bindings/C/adios2/adios2_c_types.h
index b567579aab61ac7231f141bc69580535316c390a..f20e03d901aa322f20fc567ae272354c41d1f67a 100644
--- a/bindings/C/adios2/adios2_c_types.h
+++ b/bindings/C/adios2/adios2_c_types.h
@@ -31,6 +31,7 @@ typedef enum {
 } adios2_constant_dims;
 
 typedef enum {
+    adios2_type_unknown = -1,
 
     adios2_type_char = 0,
     adios2_type_int = 1,
@@ -44,7 +45,9 @@ typedef enum {
     adios2_type_int32_t = 8,
     adios2_type_int64_t = 9,
 
-    adios2_type_string,
+    adios2_type_string = 10,
+    adios2_type_string_array = 11,
+
     adios2_type_signed_char,
 
     adios2_type_short,
diff --git a/bindings/C/adios2/adios2_c_variable.cpp b/bindings/C/adios2/adios2_c_variable.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0f4690a85d626605fa5fc70a20d6a0c6af0b713b
--- /dev/null
+++ b/bindings/C/adios2/adios2_c_variable.cpp
@@ -0,0 +1,204 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * adios2_c_variable.cpp
+ *
+ *  Created on: Nov 10, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include "adios2_c_variable.h"
+
+#include "adios2/core/Variable.h"
+#include "adios2/helper/adiosFunctions.h"
+
+const std::map<std::string, std::vector<adios2_type>> adios2_types_map = {
+    {"char", {adios2_type_char}},
+    {"int", {adios2_type_int, adios2_type_int32_t}},
+    {"float", {adios2_type_float}},
+    {"double", {adios2_type_double}},
+    {"float complex", {adios2_type_float_complex}},
+    {"double complex", {adios2_type_double_complex}},
+    {"signed char", {adios2_type_int8_t, adios2_type_signed_char}},
+    {"short", {adios2_type_int16_t, adios2_type_short}},
+    {"long int", {adios2_type_int64_t, adios2_type_long_int}},
+    {"long long int", {adios2_type_int64_t, adios2_type_long_long_int}},
+    {"string", {adios2_type_string}},
+    {"string array", {adios2_type_string_array}},
+    {"unsigned char", {adios2_type_unsigned_char, adios2_type_uint8_t}},
+    {"unsigned short", {adios2_type_unsigned_short, adios2_type_uint16_t}},
+    {"unsigned int", {adios2_type_unsigned_int, adios2_type_uint32_t}},
+    {"unsigned long int",
+     {adios2_type_unsigned_long_int, adios2_type_uint64_t}},
+    {"unsigned long long int",
+     {adios2_type_unsigned_long_long_int, adios2_type_uint64_t}},
+};
+
+const char *adios2_variable_name(const adios2_Variable *variable,
+                                 size_t *length)
+{
+    const adios2::VariableBase *variableBase =
+        reinterpret_cast<const adios2::VariableBase *>(variable);
+    if (length != nullptr)
+    {
+        *length = variableBase->m_Name.size();
+    }
+    return variableBase->m_Name.c_str();
+}
+
+adios2_type adios2_variable_type(const adios2_Variable *variable)
+{
+    const adios2::VariableBase *variableBase =
+        reinterpret_cast<const adios2::VariableBase *>(variable);
+
+    auto itType = adios2_types_map.find(variableBase->m_Type);
+
+    if (itType == adios2_types_map.end())
+    {
+        return adios2_type_unknown;
+    }
+
+    return itType->second.front();
+}
+
+int adios2_variable_is_constant_dims(const adios2_Variable *variable)
+{
+    const adios2::VariableBase *variableBase =
+        reinterpret_cast<const adios2::VariableBase *>(variable);
+    const int isConstantDims = (variableBase->m_ConstantDims) ? 1 : 0;
+    return isConstantDims;
+}
+
+const size_t adios2_variable_ndims(const adios2_Variable *variable)
+{
+    const adios2::VariableBase *variableBase =
+        reinterpret_cast<const adios2::VariableBase *>(variable);
+    return variableBase->m_Shape.size();
+}
+
+const size_t *adios2_variable_shape(const adios2_Variable *variable)
+{
+    const adios2::VariableBase *variableBase =
+        reinterpret_cast<const adios2::VariableBase *>(variable);
+    return variableBase->m_Shape.data();
+}
+
+const size_t *adios2_variable_start(const adios2_Variable *variable)
+{
+    const adios2::VariableBase *variableBase =
+        reinterpret_cast<const adios2::VariableBase *>(variable);
+    return variableBase->m_Start.data();
+}
+
+const size_t *adios2_variable_count(const adios2_Variable *variable)
+{
+    const adios2::VariableBase *variableBase =
+        reinterpret_cast<const adios2::VariableBase *>(variable);
+    return variableBase->m_Count.data();
+}
+
+const size_t
+adios2_variable_available_steps_start(const adios2_Variable *variable)
+{
+    const adios2::VariableBase *variableBase =
+        reinterpret_cast<const adios2::VariableBase *>(variable);
+    return variableBase->m_AvailableStepsStart;
+}
+
+const size_t
+adios2_variable_available_steps_count(const adios2_Variable *variable)
+{
+    const adios2::VariableBase *variableBase =
+        reinterpret_cast<const adios2::VariableBase *>(variable);
+    return variableBase->m_AvailableStepsCount;
+}
+
+void adios2_set_dimensions(adios2_Variable *variable, const size_t ndims,
+                           const size_t *shape, const size_t *start,
+                           const size_t *count)
+{
+    auto lf_Assign = [](const size_t ndims, const size_t *input,
+                        adios2::Dims &dims) {
+
+        if (input != nullptr)
+        {
+            dims.clear();
+            dims.assign(input, input + ndims);
+        }
+    };
+
+    adios2::VariableBase *variableBase =
+        reinterpret_cast<adios2::VariableBase *>(variable);
+
+    lf_Assign(ndims, shape, variableBase->m_Shape);
+    lf_Assign(ndims, start, variableBase->m_Start);
+    lf_Assign(ndims, count, variableBase->m_Count);
+    variableBase->CheckDimensions("in call to adios2_set_selection");
+}
+
+void adios2_set_selection(adios2_Variable *variable, const size_t ndims,
+                          const size_t *start, const size_t *count)
+{
+    adios2::VariableBase *variableBase =
+        reinterpret_cast<adios2::VariableBase *>(variable);
+
+    const adios2::Dims startV(start, start + ndims);
+    const adios2::Dims countV(count, count + ndims);
+    variableBase->SetSelection({startV, countV});
+    variableBase->CheckDimensions("in call to adios2_set_selection");
+}
+
+void adios2_set_step_selection(adios2_Variable *variable,
+                               const size_t step_start, const size_t step_count)
+{
+    adios2::VariableBase *variableBase =
+        reinterpret_cast<adios2::VariableBase *>(variable);
+    variableBase->SetStepSelection(adios2::Box<size_t>{step_start, step_count});
+}
+
+void *adios2_get_data(const adios2_Variable *variable)
+{
+    const adios2::VariableBase *variableBase =
+        reinterpret_cast<const adios2::VariableBase *>(variable);
+    const std::string type(variableBase->m_Type);
+
+    void *data = nullptr;
+    if (type == "compound")
+    {
+        // not supported
+    }
+#define declare_template_instantiation(T)                                      \
+    else if (type == adios2::GetType<T>())                                     \
+    {                                                                          \
+        const adios2::Variable<T> *variableCpp =                               \
+            reinterpret_cast<const adios2::Variable<T> *>(variable);           \
+        data = variableCpp->GetData();                                         \
+    }
+    ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+
+    return data;
+}
+
+void adios2_set_data(adios2_Variable *variable, const void *data)
+{
+    adios2::VariableBase *variableBase =
+        reinterpret_cast<adios2::VariableBase *>(variable);
+
+    const std::string type(variableBase->m_Type);
+
+    if (type == "compound")
+    {
+        // not supported
+    }
+#define declare_template_instantiation(T)                                      \
+    else if (type == adios2::GetType<T>())                                     \
+    {                                                                          \
+        adios2::Variable<T> *variableCpp =                                     \
+            reinterpret_cast<adios2::Variable<T> *>(variable);                 \
+        variableCpp->SetData(reinterpret_cast<const T *>(data));               \
+    }
+    ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
+#undef declare_template_instantiation
+}
diff --git a/bindings/C/adios2/adios2_c_variable.h b/bindings/C/adios2/adios2_c_variable.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f214a7913f65bd30d8d463fa68cab1ae25c24d6
--- /dev/null
+++ b/bindings/C/adios2/adios2_c_variable.h
@@ -0,0 +1,130 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * adios2_c_variable.h : exposes some members of the Variable handler
+ *
+ *  Created on: Nov 10, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef BINDINGS_C_ADIOS2_ADIOS2_C_VARIABLE_H_
+#define BINDINGS_C_ADIOS2_ADIOS2_C_VARIABLE_H_
+
+#include "adios2_c_types.h"
+
+#include <stddef.h> //size_t
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Retrieve variable name (read-only)
+ * @param variable handler
+ * @return name
+ */
+const char *adios2_variable_name(const adios2_Variable *variable,
+                                 size_t *length);
+
+/**
+ * Retrieve variable type (read-only)
+ * @param variable handler
+ * @return type
+ */
+adios2_type adios2_variable_type(const adios2_Variable *variable);
+
+/**
+ * Check if dimensions are constant
+ * @param variable
+ * @return 0: false (dimensions are not constant), 1: true dimensions are
+ * declared constant
+ */
+int adios2_variable_is_constant_dims(const adios2_Variable *variable);
+
+const size_t adios2_variable_ndims(const adios2_Variable *variable);
+
+/**
+ * Retrieve current variable shape (read-only)
+ * @param variable handler
+ * @return shape
+ */
+const size_t *adios2_variable_shape(const adios2_Variable *variable);
+
+/**
+ * Retrieve current variable start (read-only)
+ * @param variable handler
+ * @return
+ */
+const size_t *adios2_variable_start(const adios2_Variable *variable);
+
+/**
+ * Retrieve current variable shape (read-only)
+ * @param variable
+ * @return type
+ */
+const size_t *adios2_variable_count(const adios2_Variable *variable);
+
+const size_t
+adios2_variable_available_steps_start(const adios2_Variable *variable);
+
+const size_t
+adios2_variable_available_steps_count(const adios2_Variable *variable);
+
+/**
+ * Set new dimensions
+ * @param variable
+ * @param shape
+ * @param start
+ * @param count
+ */
+void adios2_set_dimensions(adios2_Variable *variable, const size_t ndims,
+                           const size_t *shape, const size_t *start,
+                           const size_t *count);
+
+/**
+ * Set new selection using start and count
+ * @param variable
+ * @param start
+ * @param count
+ */
+void adios2_set_selection(adios2_Variable *variable, const size_t ndims,
+                          const size_t *start, const size_t *count);
+
+/**
+ * Set new step selection using step_start and step_count
+ * @param variable
+ * @param step_start
+ * @param step_count
+ */
+void adios2_set_step_selection(adios2_Variable *variable,
+                               const size_t step_start,
+                               const size_t step_count);
+
+/**
+ * Returns the minimum required allocation (in number of elements of a certain
+ * type, not bytes)
+ * for the current selection
+ * @param variable
+ * @return memory size to be allocated by a pointer/vector to read this
+ */
+size_t adios2_selection_size(const adios2_Variable *variable);
+
+/**
+ * Get current data pointer, types must match
+ * @param variable
+ */
+void *adios2_get_data(const adios2_Variable *variable);
+
+/**
+ * Sets current data pointer, types must match
+ * @param variable
+ * @param data
+ */
+void adios2_set_data(adios2_Variable *variable, const void *data);
+
+#ifdef __cplusplus
+} // end extern C
+#endif
+
+#endif /* BINDINGS_C_ADIOS2_ADIOS2_C_VARIABLE_H_ */
diff --git a/bindings/C/adios2_c.h b/bindings/C/adios2_c.h
index 64cc07d32995449ecfb294ed3743c08b10dbec6e..2813ff6d0ec275278e51b88c234fa2a8ff9ada62 100644
--- a/bindings/C/adios2_c.h
+++ b/bindings/C/adios2_c.h
@@ -16,5 +16,6 @@
 #include "adios2/adios2_c_engine.h"
 #include "adios2/adios2_c_glue.h"
 #include "adios2/adios2_c_io.h"
+#include "adios2/adios2_c_variable.h"
 
 #endif /* ADIOS2_BINDINGS_C_ADIOS2_C_H_ */
diff --git a/bindings/fortran/CMakeLists.txt b/bindings/fortran/CMakeLists.txt
index d60df4ad5fbd54b46e5b3807bcfdfe4c796c1475..58a4191a4e6f7002cd119c32037cf516e8ad9914 100644
--- a/bindings/fortran/CMakeLists.txt
+++ b/bindings/fortran/CMakeLists.txt
@@ -11,6 +11,7 @@ FortranCInterface_VERIFY(CXX QUIET)
 set(F2C
      f2c/adios2_f2c_adios.cpp  
      f2c/adios2_f2c_io.cpp 
+     f2c/adios2_f2c_variable.cpp
      f2c/adios2_f2c_engine.cpp
 )
 
@@ -20,9 +21,12 @@ set(MODULES
      modules/adios2_parameters_mod.f90 
      modules/adios2_adios_mod.f90 
      modules/adios2_io_mod.f90 
+     modules/adios2_variable_mod.f90
      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/adios2_mod.f90 b/bindings/fortran/adios2_mod.f90
index 12b55387e5c289b3b1f1b003a8d6968d0edb253e..294222b4ade37136de4c1cdd46fe3d942ce83cd8 100644
--- a/bindings/fortran/adios2_mod.f90
+++ b/bindings/fortran/adios2_mod.f90
@@ -13,7 +13,7 @@ module adios2
     use adios2_parameters
     use adios2_adios
     use adios2_io
-!    TODO use adios2_variable
+    use adios2_variable
     use adios2_engine
 
 end module
diff --git a/bindings/fortran/f2c/adios2_f2c_engine.cpp b/bindings/fortran/f2c/adios2_f2c_engine.cpp
index 9a45a011be430f2e11f2d45456de87bcb138f168..3a9c8108b9547309e490f0be3ac23bac2783663a 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,
@@ -50,7 +51,68 @@ void FC_GLOBAL(adios2_put_deferred_f2c,
     *ierr = 0;
     try
     {
-        adios2_put_sync(*engine, *variable, values);
+        adios2_put_deferred(*engine, *variable, values);
+    }
+    catch (std::exception &e)
+    {
+        *ierr = 1;
+    }
+}
+
+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)
     {
diff --git a/bindings/fortran/f2c/adios2_f2c_engine.h b/bindings/fortran/f2c/adios2_f2c_engine.h
index 76b8551bf71544491696a38363f788b5b1a0ca36..bc3ee6250f2bd94f77bd66e1199a7155e9708cf1 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,15 +33,29 @@ 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);
 
 void FC_GLOBAL(adios2_close_f2c, ADIOS2_CLOSE_F2C)(adios2_Engine **engine,
                                                    int *ierr);
 
-void FC_GLOBAL(adios2_finalize_f2c, ADIOS2_FINALIZE_F2C)(adios2_ADIOS **adios,
-                                                         int *ierr);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/bindings/fortran/f2c/adios2_f2c_io.cpp b/bindings/fortran/f2c/adios2_f2c_io.cpp
index 615f2e2a4fb2b1884e6aa2232d2a9d4ff617cbc9..99113da382f5979ec52c035ede19b1248ca03221 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 0e73994df8b3b387e18fd73e994f26dd47bf6ed1..b5aa9b364549c0536fbf49721b5921f3c2c5a2ab 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
new file mode 100644
index 0000000000000000000000000000000000000000..799f6626ad5ada4d86bdbe452d0505e969192e69
--- /dev/null
+++ b/bindings/fortran/f2c/adios2_f2c_variable.cpp
@@ -0,0 +1,113 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * adios2_f2c_variable.cpp
+ *
+ *  Created on: Nov 12, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include "adios2_f2c_variable.h"
+
+#include <cstddef>
+#include <stdexcept>
+#include <string.h> //strcpy
+#include <vector>
+
+void FC_GLOBAL(adios2_variable_name_f2c,
+               ADIOS2_VARIABLE_NAME_F2C)(const adios2_Variable **variable,
+                                         char name[1024], int *length,
+                                         int *ierr)
+{
+    *ierr = 0;
+    try
+    {
+        size_t lengthC = 0;
+        const char *nameC = adios2_variable_name(*variable, &lengthC);
+
+        if (nameC == nullptr)
+        {
+            throw std::runtime_error("ERROR: null pointer\n");
+        }
+
+        for (size_t i = 0; i < lengthC; ++i)
+        {
+            name[i] = nameC[i];
+        }
+
+        *length = static_cast<int>(lengthC);
+    }
+    catch (std::exception &e)
+    {
+        *ierr = 1;
+    }
+}
+
+void FC_GLOBAL(adios2_variable_type_f2c,
+               ADIOS2_VARIABLE_TYPE_F2C)(const adios2_Variable **variable,
+                                         int *type, int *ierr)
+{
+    *ierr = 0;
+    try
+    {
+        *type = static_cast<int>(adios2_variable_type(*variable));
+    }
+    catch (std::exception &e)
+    {
+        *ierr = 1;
+    }
+}
+
+void FC_GLOBAL(adios2_set_selection_f2c,
+               ADIOS2_SET_SELECTION_F2C)(adios2_Variable **variable,
+                                         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)
+    {
+        *ierr = 1;
+        return;
+    }
+
+    std::vector<std::size_t> startV, countV;
+    lf_IntToSizeT(start, *ndims, startV, true);
+    lf_IntToSizeT(count, *ndims, countV, false);
+
+    try
+    {
+        adios2_set_selection(*variable, *ndims, startV.data(), countV.data());
+    }
+    catch (std::exception &e)
+    {
+        *ierr = 1;
+    }
+}
diff --git a/bindings/fortran/f2c/adios2_f2c_variable.h b/bindings/fortran/f2c/adios2_f2c_variable.h
new file mode 100644
index 0000000000000000000000000000000000000000..704bcf4869b903bae3709d6a637c20ba6e838ebb
--- /dev/null
+++ b/bindings/fortran/f2c/adios2_f2c_variable.h
@@ -0,0 +1,39 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * adios2_f2c_variable.h : variable handle functions
+ *
+ *  Created on: Nov 12, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+#ifndef BINDINGS_FORTRAN_F2C_ADIOS2_F2C_VARIABLE_H_
+#define BINDINGS_FORTRAN_F2C_ADIOS2_F2C_VARIABLE_H_
+
+#include "adios2/ADIOSConfig.h"
+#include <FC.h>
+#include <adios2_c.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void FC_GLOBAL(adios2_variable_name_f2c,
+               ADIOS2_VARIABLE_NAME_F2C)(const adios2_Variable **variable,
+                                         char name[1024], int *length,
+                                         int *ierr);
+
+void FC_GLOBAL(adios2_variable_type_f2c,
+               ADIOS2_VARIABLE_TYPE_F2C)(const adios2_Variable **variable,
+                                         int *c_type, int *ierr);
+
+void FC_GLOBAL(adios2_set_selection_f2c,
+               ADIOS2_SET_SELECTION_F2C)(adios2_Variable **variable,
+                                         const int *ndims, const int *start,
+                                         const int *count, int *ierr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BINDINGS_FORTRAN_F2C_ADIOS2_F2C_VARIABLE_H_ */
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 0000000000000000000000000000000000000000..44ac5b5039e961df44e5b146655cdf4f916d458a
--- /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 3bda71211d135e5f9722c221ac480d7fe077e0d4..9ff921673598c7718859518270b0b5f4c550c282 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 0000000000000000000000000000000000000000..220937e4fd9e4a39da59bd7c9331e67ff2a83a0c
--- /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_functions_mod.f90 b/bindings/fortran/modules/adios2_functions_mod.f90
index 82ccbd60880687cba8e7c2b65e455e700bd1f5ba..0c516468f0518711695001a9eb1284d37c9c25e2 100644
--- a/bindings/fortran/modules/adios2_functions_mod.f90
+++ b/bindings/fortran/modules/adios2_functions_mod.f90
@@ -1,4 +1,5 @@
 module adios2_functions
+    use adios2_parameters
     implicit none
 
 contains
@@ -13,4 +14,36 @@ contains
 
     end function
 
+
+    subroutine adios2_StringC2F( c_string, length, f_string )
+        character*(*), intent(in) :: c_string
+        integer, intent(in) :: length
+        character(len=:), allocatable, intent(out) :: f_string
+
+        if( allocated(f_string) ) deallocate(f_string)
+        if( length > 0 ) then
+            allocate( character(length) :: f_string )
+            f_string = c_string(1:length)
+        end if
+
+    end subroutine
+
+
+    subroutine adios2_TypeC2F( c_type, f_type )
+        integer, intent(in) :: c_type
+        integer, intent(out) :: f_type
+
+        integer :: i
+
+        f_type = adios2_type_unknown
+
+        do i=-1,11
+            if( c_type == i ) then
+                f_type = c_type
+                exit
+            end if
+        end do
+
+    end subroutine
+
 end module
diff --git a/bindings/fortran/modules/adios2_io_mod.f90 b/bindings/fortran/modules/adios2_io_mod.f90
index 9b349f82ca22bdbea889de4b5f45d67f6c42ae81..a70f69231ef150db74367a26d4e3b2637036c41a 100644
--- a/bindings/fortran/modules/adios2_io_mod.f90
+++ b/bindings/fortran/modules/adios2_io_mod.f90
@@ -2,7 +2,7 @@
 ! Distributed under the OSI-approved Apache License, Version 2.0.  See
 !  accompanying file Copyright.txt for details.
 !
-!  adios2_io.f90 : ADIOS2 Fortran bindings for IO class
+!  adios2_io_mod.f90 : ADIOS2 Fortran bindings for IO class
 !
 !   Created on: Mar 13, 2017
 !       Author: William F Godoy godoywf@ornl.gov
@@ -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 7c78942f396489f6d38b08190b7d31bf4085e505..997ba65b56fb84c9e6a864bb654151eda0ab833b 100644
--- a/bindings/fortran/modules/adios2_parameters_mod.f90
+++ b/bindings/fortran/modules/adios2_parameters_mod.f90
@@ -14,7 +14,8 @@ module adios2_parameters
     logical, parameter :: adios2_debug_mode_on = .true.
     logical, parameter :: adios2_debug_mode_off = .false.
 
-    ! Type
+    ! Types
+    integer, parameter :: adios2_type_unknown = -1
     integer, parameter :: adios2_type_character = 0
     integer, parameter :: adios2_type_integer = 1
     integer, parameter :: adios2_type_real = 2
@@ -27,10 +28,17 @@ module adios2_parameters
     integer, parameter :: adios2_type_integer4 = 8
     integer, parameter :: adios2_type_integer8 = 9
 
+    integer, parameter :: adios2_type_string = 10
+    integer, parameter :: adios2_type_string_array = 11
+
     ! Constant dims
     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/fortran/modules/adios2_variable_mod.f90 b/bindings/fortran/modules/adios2_variable_mod.f90
new file mode 100644
index 0000000000000000000000000000000000000000..c6cbe1df6befc1cae578713a1ffec861073dd94f
--- /dev/null
+++ b/bindings/fortran/modules/adios2_variable_mod.f90
@@ -0,0 +1,57 @@
+!
+! Distributed under the OSI-approved Apache License, Version 2.0.  See
+!  accompanying file Copyright.txt for details.
+!
+!  adios2_variable_mod.f90 : ADIOS2 Fortran bindings for Variable class
+!
+!   Created on: Mar 13, 2017
+!       Author: William F Godoy godoywf@ornl.gov
+!
+
+module adios2_variable
+    use adios2_functions
+    implicit none
+
+contains
+
+    subroutine adios2_variable_name(variable, name, ierr)
+        integer(kind=8), intent(out) :: variable
+        character(len = :), allocatable, intent(out) :: name
+        integer, intent(out) :: ierr
+
+        character(len = 1024) :: c_name
+        integer :: length, i
+
+        call adios2_variable_name_f2c( variable, c_name, length, ierr )
+        call adios2_StringC2F(c_name, length, name)
+
+    end subroutine
+
+
+    subroutine adios2_variable_type(variable, type, ierr)
+        integer(kind=8), intent(out) :: variable
+        integer, intent(out) :: type
+        integer, intent(out) :: ierr
+
+        integer :: c_type
+
+        call adios2_variable_type_f2c( variable, c_type, ierr )
+        call adios2_TypeC2F( c_type, type )
+
+    end subroutine
+
+
+    subroutine adios2_set_selection(variable, ndims, start_dims, count_dims, &
+        & ierr)
+        integer(kind=8), intent(out) :: variable
+        integer, intent(in) :: ndims
+        integer, dimension(:), intent(in) :: start_dims
+        integer, dimension(:), intent(in) :: count_dims
+        integer, intent(out) :: ierr
+
+        call adios2_set_selection_f2c(variable, ndims, start_dims, &
+            & count_dims, ierr)
+
+    end subroutine
+
+end module
diff --git a/bindings/python/EnginePy.cpp b/bindings/python/EnginePy.cpp
index a3e7b11800e13497b14894064af80282e033a6b8..3120be8a4f2445a43aa5112106494056bdc23340 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 e4b426345c488a559113ed1991178138999c836c..7ef45d27fdcaa1867dd651abdcba9fa4039e4ddf 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 ec8b28731a4f1ed5d13c291b8fccbbe423a08ef7..374b72a11313a8289d6215a0943a4164186b28cc 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/CMakeLists.txt b/examples/hello/bpReader/CMakeLists.txt
index 74235567d498bbcd972927c7f390ffb485151a2f..fd7a77a894968b341f704c2964e8e92c13125943 100644
--- a/examples/hello/bpReader/CMakeLists.txt
+++ b/examples/hello/bpReader/CMakeLists.txt
@@ -18,20 +18,17 @@ if(ADIOS2_HAVE_MPI)
   target_link_libraries(hello_bpReaderHeatMap3D ${MPI_C_LIBRARIES})
   target_link_libraries(hello_bpReaderHeatMap3D adios2)
   
+  if(ADIOS2_HAVE_Fortran)
+    add_executable(hello_bpReaderHeatMap3D_f helloBPReaderHeatMap3D.f90)
+    target_link_libraries(hello_bpReaderHeatMap3D_f MPI::MPI_Fortran)
+    target_link_libraries(hello_bpReaderHeatMap3D_f adios2_f)
+  endif()
+  
   
 #  add_executable(hello_bpReader_c helloBPReader.c)
 #  target_include_directories(hello_bpReader_c PRIVATE ${MPI_C_INCLUDE_PATH})
 #  target_link_libraries(hello_bpReader_c ${MPI_C_LIBRARIES})
-#  
-#  if(ADIOS2_HAVE_Fortran)
-#    add_executable(hello_bpReader_f helloBPReader.f90)
-#    target_include_directories(hello_bpReader_f 
-#                               PRIVATE ${MPI_Fortran_INCLUDE_PATH} 
-#                                       ${MPI_C_INCLUDE_PATH})
-#                                               
-#    target_link_libraries(hello_bpReader_f PRIVATE ${MPI_Fortran_LIBRARIES} 
-#                                                   ${MPI_C_LIBRARIES})
-#  endif()
+
   
 else()
   add_executable(hello_bpReader helloBPReader_nompi.cpp)
diff --git a/examples/hello/bpReader/helloBPReaderHeatMap2D.cpp b/examples/hello/bpReader/helloBPReaderHeatMap2D.cpp
index 86fc95ed6fb180be1752efe27b27191ec4d87aa9..3305d29f4e1486b42651699b03d7881f09269ad6 100644
--- a/examples/hello/bpReader/helloBPReaderHeatMap2D.cpp
+++ b/examples/hello/bpReader/helloBPReaderHeatMap2D.cpp
@@ -91,7 +91,7 @@ int main(int argc, char *argv[])
             if (inTemperature != nullptr)
             {
                 inTemperature->SetSelection({{2, 2}, {6, 1}});
-                size_t elementsSize = inTemperature->GetElementsSize();
+                size_t elementsSize = inTemperature->SelectionSize();
                 std::vector<unsigned int> inTemperatures(elementsSize);
                 std::cout << "Pre-allocated " << elementsSize << " elements, "
                           << elementsSize * sizeof(unsigned int) << " bytes\n";
diff --git a/examples/hello/bpReader/helloBPReaderHeatMap3D.cpp b/examples/hello/bpReader/helloBPReaderHeatMap3D.cpp
index 71cb73f486ade9a744127fdbec5d56ebe0f837de..d41d039c1a49b42717022192ce3d46db0078c2bc 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,13 +77,13 @@ 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>(
                 "temperature", shape, start, count, adios2::ConstantDims);
 
-        /** Will create HeatMap.bp */
+        /** Will create HeatMap3D.bp */
         adios2::Engine &bpWriter =
             putHeatMap.Open("HeatMap3D.bp", adios2::Mode::Write);
 
@@ -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);
 
@@ -100,14 +104,15 @@ int main(int argc, char *argv[])
             if (inTemperature != nullptr)
             {
                 inTemperature->SetSelection({{2, 2, 2}, {4, 4, 4}});
-                const size_t elementsSize = inTemperature->GetElementsSize();
+                const size_t elementsSize = inTemperature->SelectionSize();
                 std::vector<unsigned int> inTemperatures(elementsSize);
                 std::cout << "Pre-allocated " << elementsSize << " elements, "
                           << elementsSize * sizeof(unsigned int) << " bytes\n";
 
                 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
new file mode 100644
index 0000000000000000000000000000000000000000..89805866bb9d83d6b2079890d07fa73aec7da020
--- /dev/null
+++ b/examples/hello/bpReader/helloBPReaderHeatMap3D.f90
@@ -0,0 +1,104 @@
+program helloBPReaderHeatMap3D
+    use mpi
+    use adios2
+
+    implicit none
+
+    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, icounter
+
+    call MPI_INIT(ierr)
+    call MPI_COMM_RANK(MPI_COMM_WORLD, irank, ierr)
+    call MPI_COMM_SIZE(MPI_COMM_WORLD, isize, ierr)
+
+    inx = 10
+    iny = 10
+    inz = 10
+
+    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-1)-1
+                value = (k-1) * ishape(1) * ishape(2) + (j-1) * ishape(1) + &
+                &       iglobal
+                temperatures(i,j,k) = value
+            end do
+        end do
+    end do
+
+    ! Start adios2 Writer
+    call adios2_init( adios, MPI_COMM_WORLD, adios2_debug_mode_on, ierr )
+    call adios2_declare_io( ioPut, adios, 'HeatMapWrite', ierr )
+
+    call adios2_define_variable( var_temperatures, ioPut, 'temperatures', &
+        & adios2_type_integer, 3, ishape, istart, icount, &
+        & adios2_constant_dims_true, ierr )
+
+    call adios2_open( bpWriter, ioPut, 'HeatMap3D_f.bp', &
+                    & adios2_mode_write, ierr )
+
+    call adios2_write( bpWriter, var_temperatures, temperatures, ierr )
+
+    call adios2_close( bpWriter, ierr )
+
+
+    if( allocated(temperatures) ) deallocate(temperatures)
+
+    ! 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 6f485e1606291cec97678a19efa80c14c5c8f8ad..6ab37a388f24beb17266d3828f77a1df4a906028 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/examples/hello/bpWriter/helloBPWriter.c b/examples/hello/bpWriter/helloBPWriter.c
index a6f245d3d74e2c106c96f43f4290ddfe96e49771..268375e6999f0e306ffaa8e3d88e72720e5b3c99 100644
--- a/examples/hello/bpWriter/helloBPWriter.c
+++ b/examples/hello/bpWriter/helloBPWriter.c
@@ -46,6 +46,7 @@ int main(int argc, char *argv[])
     adios2_Variable *variableH =
         adios2_define_variable(ioH, "bpFloats", adios2_type_float, 1, shape,
                                start, count, adios2_constant_dims_true);
+
     adios2_Engine *engineH =
         adios2_open(ioH, "myVector_c.bp", adios2_mode_write);
 
diff --git a/examples/hello/bpWriter/helloBPWriter.f90 b/examples/hello/bpWriter/helloBPWriter.f90
index 3766bedbca4a35a796dc97ed72e9a946075a5a28..4b2b0b46e4b2587cabcb11ba8e2b449640612863 100644
--- a/examples/hello/bpWriter/helloBPWriter.f90
+++ b/examples/hello/bpWriter/helloBPWriter.f90
@@ -6,8 +6,10 @@ program helloBPWriter
 
     integer, dimension(1) :: shape_dims, start_dims, count_dims
     real, dimension(:), allocatable :: myArray
-    integer :: inx, irank, isize, ierr, i
+    integer :: inx, irank, isize, ierr, i, var1_type
     integer(kind=8) :: adios, io, var1, engine1
+    character(len=:), allocatable :: var1_name
+
 
     ! Launch MPI
     call MPI_Init(ierr)
@@ -37,6 +39,11 @@ program helloBPWriter
     call adios2_define_variable(var1, io, "myArray", adios2_type_real, 1, &
         & shape_dims, start_dims, count_dims, adios2_constant_dims_true, ierr)
 
+
+    call adios2_variable_name( var1, var1_name, ierr )
+    call adios2_variable_type( var1, var1_type, ierr )
+    write(*,*) 'Variable name: ', var1_name, '  type: ', var1_type
+
     ! Open myVector_f.bp in write mode, this launches an engine
     call adios2_open(engine1, io, "myVector_f.bp", adios2_mode_write, ierr)
 
@@ -49,7 +56,8 @@ program helloBPWriter
     ! Deallocates adios and calls its destructor
     call adios2_finalize(adios, ierr)
 
-    deallocate(myArray)
+    if( allocated(myArray) ) deallocate(myArray)
+    if( allocated(var1_name) ) deallocate(var1_name)
 
     call MPI_Finalize(ierr)
 
diff --git a/source/adios2/ADIOSMacros.h b/source/adios2/ADIOSMacros.h
index d95c2fab7c50a05c161641cd119e2e4435510fac..0d002d332d5702a107da96a6d8ef614193adf03c 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 0b00c1da889334b34e0557ee662465fcd81a1795..dc093d31f1696f68d35bfbcde6f239a4f589b59b 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 f780868b54439aa4e510524fadab13ceb43ce985..b4b0abf4537989875dee1ecc43a1a09b8b79fb8f 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/core/VariableBase.cpp b/source/adios2/core/VariableBase.cpp
index 591e5ca5bde74066d61c163bf93d36638abdc887..aa3c8fa5fea15b8c1df66a54e306358892efed7c 100644
--- a/source/adios2/core/VariableBase.cpp
+++ b/source/adios2/core/VariableBase.cpp
@@ -134,7 +134,7 @@ size_t VariableBase::GetAvailableStepsCount() const
     return m_AvailableStepsCount;
 }
 
-void VariableBase::SetStepSelection(const std::pair<size_t, size_t> &boxSteps)
+void VariableBase::SetStepSelection(const Box<size_t> &boxSteps)
 {
     if (boxSteps.second == 0)
     {
@@ -176,7 +176,7 @@ void VariableBase::ClearOperators() noexcept { m_OperatorsInfo.clear(); }
 
 void VariableBase::CheckDimensions(const std::string hint) const
 {
-    if (m_ShapeID == ShapeID::GlobalArray)
+    if (m_DebugMode && m_ShapeID == ShapeID::GlobalArray)
     {
         if (m_Start.empty() || m_Count.empty())
         {
@@ -192,7 +192,7 @@ void VariableBase::CheckDimensions(const std::string hint) const
     // TODO need to think more exceptions here
 }
 
-size_t VariableBase::GetElementsSize() const
+size_t VariableBase::SelectionSize() const
 {
     return GetTotalSize(m_Count) * m_StepsCount;
 }
@@ -204,7 +204,7 @@ void VariableBase::InitShapeType()
     {
         if (std::count(m_Shape.begin(), m_Shape.end(), JoinedDim) == 1)
         {
-            if (!m_Start.empty() &&
+            if (m_DebugMode && !m_Start.empty() &&
                 std::count(m_Start.begin(), m_Start.end(), 0) != m_Start.size())
             {
                 throw std::invalid_argument("ERROR: The Start array must be "
@@ -224,17 +224,15 @@ void VariableBase::InitShapeType()
             }
             else
             {
-                if (m_DebugMode)
+
+                if (m_DebugMode && m_ConstantDims)
                 {
-                    if (m_ConstantDims)
-                    {
-                        throw std::invalid_argument(
-                            "ERROR: isConstantShape (true) argument is invalid "
-                            "with empty start and count "
-                            "arguments in call to "
-                            "DefineVariable " +
-                            m_Name + "\n");
-                    }
+                    throw std::invalid_argument(
+                        "ERROR: isConstantShape (true) argument is invalid "
+                        "with empty start and count "
+                        "arguments in call to "
+                        "DefineVariable " +
+                        m_Name + "\n");
                 }
 
                 m_ShapeID = ShapeID::GlobalArray;
@@ -299,11 +297,14 @@ void VariableBase::InitShapeType()
         }
         else
         {
-            throw std::invalid_argument(
-                "ERROR: if the "
-                "shape is empty, start must be empty as well, in call to "
-                "DefineVariable " +
-                m_Name + "\n");
+            if (m_DebugMode)
+            {
+                throw std::invalid_argument(
+                    "ERROR: if the "
+                    "shape is empty, start must be empty as well, in call to "
+                    "DefineVariable " +
+                    m_Name + "\n");
+            }
         }
     }
 
@@ -317,6 +318,11 @@ void VariableBase::InitShapeType()
 
 void VariableBase::CheckDimensionsCommon(const std::string hint) const
 {
+    if (!m_DebugMode)
+    {
+        return;
+    }
+
     if (m_Type == "string")
     {
         if (!(m_Shape.empty() && m_Start.empty() && m_Count.empty()))
diff --git a/source/adios2/core/VariableBase.h b/source/adios2/core/VariableBase.h
index 39d6410578db70a1d820725262e8be7e78a18edf..c57b716908a142a48e709eeb88dd41ba5304c124 100644
--- a/source/adios2/core/VariableBase.h
+++ b/source/adios2/core/VariableBase.h
@@ -148,7 +148,7 @@ public:
      * @return memory size to be allocated by a pointer/vector to read this
      * variable
      */
-    size_t GetElementsSize() const;
+    size_t SelectionSize() const;
 
 protected:
     const bool m_DebugMode = false;
diff --git a/source/adios2/engine/bp/BPFileReader.cpp b/source/adios2/engine/bp/BPFileReader.cpp
index 207505d2932e2a10414e62e048c1c45a285cc94e..6900ccd06eda7f8a30d78db3da3b290c4d30401d 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 0e4ebe68b7905707e190bcf33e82d5cd94f7b194..81a5562f6b42d6f050acdfdc0008056b838695b4 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 a312d13335e80ec7267475bc5342e4eda9cc01ae..6bbf28df0886e482f01915d35d57fab9ea276a1a 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 5ee06cd03ec323d8c26e2273faf260409e055e5e..79c3a2bdbc5b9e7aa84d008764c95dc0bca37aba 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 4ca4140170db2a5211d98abe80eb8d019bada1f1..f5ab4bf9d2f2158606ac3a0e2123bbdcaa7d1d5d 100644
--- a/source/adios2/helper/adiosMath.h
+++ b/source/adios2/helper/adiosMath.h
@@ -120,7 +120,7 @@ Box<Dims> IntersectionBox(const Box<Dims> &box1,
                           const Box<Dims> &box2) noexcept;
 
 /**
- * Get a linear index for a point inside a localBox
+ * Get a linear index for a point inside a localBox depending on data layout
  * @param localBox start and count
  * @param point inside box
  * @param isRowMajor
@@ -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/helper/adiosSystem.cpp b/source/adios2/helper/adiosSystem.cpp
index 233f2d096cffde6bb1b482c75bcdcbbc5a36ee72..cac0a33421628d3bbe0963968da800fe021eb6be 100644
--- a/source/adios2/helper/adiosSystem.cpp
+++ b/source/adios2/helper/adiosSystem.cpp
@@ -21,7 +21,7 @@
 
 // remove ctime warning on Windows
 #ifdef _WIN32
-#pragma warning(disable : 4996)
+#pragma warning(disable : 4996) // ctime warning
 #endif
 
 namespace adios2
@@ -46,4 +46,26 @@ std::string LocalTimeDate() noexcept
     return std::string(ctime(&now));
 }
 
-} // end namespace adios
+bool IsRowMajor(const std::string hostLanguage) noexcept
+{
+    bool isRowMajor = true;
+
+    if (hostLanguage == "Fortran" || hostLanguage == "R")
+    {
+        isRowMajor = false;
+    }
+    return isRowMajor;
+}
+
+bool IsZeroIndexed(const std::string hostLanguage) noexcept
+{
+    bool isZeroIndexed = true;
+
+    if (hostLanguage == "Fortran" || hostLanguage == "R")
+    {
+        isZeroIndexed = false;
+    }
+    return isZeroIndexed;
+}
+
+} // end namespace adios2
diff --git a/source/adios2/helper/adiosSystem.h b/source/adios2/helper/adiosSystem.h
index e241e65164a1ccf89cf805f9721dc5863ce0a5c7..0a8c2cfb78ff5903777fe1fc0ad3431af2c1fc25 100644
--- a/source/adios2/helper/adiosSystem.h
+++ b/source/adios2/helper/adiosSystem.h
@@ -40,6 +40,22 @@ bool IsLittleEndian() noexcept;
  */
 std::string LocalTimeDate() noexcept;
 
-} // end namespace adios
+/**
+ * Support for language bindings, identify if data is row-major (C, C++) or not
+ * (Fortran, R)
+ * @param hostLanguage input host language
+ * @return true: row-major, false: column-major
+ */
+bool IsRowMajor(const std::string hostLanguage) noexcept;
+
+/**
+ * Support for language bindings, identify if data is zero-indexed (C, C++) or
+ * not (Fortran, R)
+ * @param hostLanguage input host language
+ * @return true: zero-indexed, false: one-indexed
+ */
+bool IsZeroIndexed(const std::string hostLanguage) noexcept;
+
+} // end namespace adios2
 
 #endif /* ADIOS2_HELPER_ADIOSSYSTEM_H_ */
diff --git a/source/adios2/toolkit/format/bp3/BP3Base.h b/source/adios2/toolkit/format/bp3/BP3Base.h
index 6f10ebdc7124afc67f17e6a48dfe4e6b13e47507..45bf3174e62fa95f2ce23eaf8e1052ce0fd1086a 100644
--- a/source/adios2/toolkit/format/bp3/BP3Base.h
+++ b/source/adios2/toolkit/format/bp3/BP3Base.h
@@ -207,10 +207,8 @@ protected:
     unsigned int m_Threads = 1;
     const bool m_DebugMode = false;
 
-    /** from host language */
-    bool m_IsRowMajor = true; // C, C++ defaults
-    /** from host language */
-    bool m_IsZeroIndex = true; // C, C++
+    /** from host language in data information */
+    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 1bfa4de39606f8cdcdfea9aa6df98ab9e19364dc..f614d90e320563be762f8e5714c5132fcb196fce 100644
--- a/source/adios2/toolkit/format/bp3/BP3Deserializer.cpp
+++ b/source/adios2/toolkit/format/bp3/BP3Deserializer.cpp
@@ -117,8 +117,15 @@ void BP3Deserializer::ParsePGIndex()
     position = m_Minifooter.PGIndexStart;
 
     m_MetadataSet.DataPGCount = ReadValue<uint64_t>(buffer, position);
-    const uint64_t pgLength =
-        ReadValue<uint64_t>(buffer, position); // not required
+    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;
+    }
 }
 
 void BP3Deserializer::ParseVariablesIndex(IO &io)
@@ -134,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;
         }
 
@@ -152,7 +159,11 @@ void BP3Deserializer::ParseVariablesIndex(IO &io)
 
         case (type_long):
         {
+#ifdef _WIN32
+            DefineVariableInIO<long long int>(header, io, buffer, position);
+#else
             DefineVariableInIO<long int>(header, io, buffer, position);
+#endif
             break;
         }
 
@@ -176,7 +187,12 @@ void BP3Deserializer::ParseVariablesIndex(IO &io)
 
         case (type_unsigned_long):
         {
+#ifdef _WIN32
+            DefineVariableInIO<unsigned long long int>(header, io, buffer,
+                                                       position);
+#else
             DefineVariableInIO<unsigned long int>(header, io, buffer, position);
+#endif
             break;
         }
 
diff --git a/source/adios2/toolkit/format/bp3/BP3Deserializer.h b/source/adios2/toolkit/format/bp3/BP3Deserializer.h
index 4bf14e3f5b692ffc6ab99cf869059d9858b2ed9b..b81107c04ce05ef9b01775ce086b9d8c86511e5a 100644
--- a/source/adios2/toolkit/format/bp3/BP3Deserializer.h
+++ b/source/adios2/toolkit/format/bp3/BP3Deserializer.h
@@ -70,8 +70,8 @@ private:
     void ParseAttributesIndex(IO &io);
 
     /**
-     * This function reads a variable index element (serialized) and calls IO
-     * DefineVariable to deserialize the data
+     * Reads a variable index element (serialized) and calls IO.DefineVariable
+     * to deserialize the Variable metadata
      * @param header serialize
      * @param io
      * @param buffer
@@ -91,8 +91,27 @@ private:
                                     const Box<Dims> &blockBox,
                                     const Box<Dims> &intersectionBox) const;
 
+    /**
+     * Row-major, zero-indexed data e.g. : C, C++
+     * @param variable
+     * @param contiguousMemory
+     * @param blockBox
+     * @param intersectionBox
+     */
+    template <class T>
+    void ClipContiguousMemoryCommonRow(
+        Variable<T> &variable, const std::vector<char> &contiguousMemory,
+        const Box<Dims> &blockBox, const Box<Dims> &intersectionBox) const;
+
+    /**
+     * Column-major, one indexed data e.g. : Fortran, R
+     * @param variable
+     * @param contiguousMemory
+     * @param blockBox
+     * @param intersectionBox
+     */
     template <class T>
-    void ClipContiguousMemoryCommonRowZero(
+    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 c0c0933815e9ee7d1875916eaccbba11064b601a..31600629260a90b5c282f11364499d77d28b13cc 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,15 +206,20 @@ void BP3Deserializer::ClipContiguousMemoryCommon(
         return;
     }
 
-    if (m_IsRowMajor && m_IsZeroIndex)
+    if (m_IsRowMajor) // stored with C, C++, Python
+    {
+        ClipContiguousMemoryCommonRow(variable, contiguousMemory, blockBox,
+                                      intersectionBox);
+    }
+    else // stored with Fortran, R
     {
-        ClipContiguousMemoryCommonRowZero(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
 {
@@ -242,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());
 
@@ -267,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)
                 {
@@ -288,6 +282,70 @@ void BP3Deserializer::ClipContiguousMemoryCommonRowZero(
     }     // run
 }
 
+template <class T>
+void BP3Deserializer::ClipContiguousMemoryCommonColumn(
+    Variable<T> &variable, const std::vector<char> &contiguousMemory,
+    const Box<Dims> &blockBox, const Box<Dims> &intersectionBox) const
+{
+    const Dims &start = intersectionBox.first;
+    const Dims &end = intersectionBox.second;
+    const size_t stride = (end.front() - start.front() + 1) * sizeof(T);
+
+    Dims currentPoint(start); // current point for memory copy
+
+    const Box<Dims> selectionBox =
+        StartEndBox(variable.m_Start, variable.m_Count);
+
+    const size_t dimensions = start.size();
+    bool run = true;
+
+    const size_t intersectionStart =
+        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) * sizeof(T) -
+            intersectionStart;
+
+        const size_t variableStart =
+            LinearIndex(selectionBox, currentPoint, false) * sizeof(T);
+
+        char *rawVariableData = reinterpret_cast<char *>(variable.GetData());
+
+        std::copy(&contiguousMemory[contiguousStart],
+                  &contiguousMemory[contiguousStart + stride],
+                  &rawVariableData[variableStart]);
+
+        // here update each index recursively, always starting from the 2nd
+        // fastest changing index, since fastest changing index is the
+        // continuous part in the previous std::copy
+        size_t p = 1;
+        while (true)
+        {
+            ++currentPoint[p];
+            if (currentPoint[p] > end[p])
+            {
+                if (p == dimensions - 1)
+                {
+                    run = false; // we are done
+                    break;
+                }
+                else
+                {
+                    currentPoint[p] = start[p];
+                    ++p;
+                }
+            }
+            else
+            {
+                break; // break inner p loop
+            }
+        } // dimension index update
+    }
+}
+
 } // end namespace format
 } // end namespace adios2
 
diff --git a/source/adios2/toolkit/transport/file/FileFStream.cpp b/source/adios2/toolkit/transport/file/FileFStream.cpp
index e119c15967a873272dd5bda1c235ee006d20ab93..4f33cd22930067a7a57f39c67e501667f50fff90 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 903c82992abb595fe8c6963826d43a33a076e3a1..c11b56824f89485aae66830b22912a10139f1230 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 21ed6773e81bb507543011f4b4bc9db6bf807843..4505a3b28d73fee972b689d3a3750e53bdc62542 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 a305236a7191576159dc55904bd9edf26ef54173..2b7f51f7269a3f8db02581966a06ac266c7c2b91 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 335444646db3a139ebd28f2018ad9e588fe8e732..3efc634435dbaea05c35eada09423f5ca00b0ea1 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 b70bace799f079f933093208d248d8d9009f17a8..55e8f14ea28d71667e82b61b9d4a7409be11afed 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 0000000000000000000000000000000000000000..e0d72e8078667aa3b5262cba35a22fbf8d0f6f14
--- /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, static_cast<int>(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, static_cast<int>(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, static_cast<int>(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, static_cast<int>(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, static_cast<int>(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, static_cast<int>(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;
+}