diff --git a/bindings/C/adios2/adios2_c_enums.h b/bindings/C/adios2/adios2_c_enums.h
index 3ea471ee62f4013d8ef8702c6d44083d8737a2c2..836b8b6f2d0e426b9cb052d2354205d720da4496 100644
--- a/bindings/C/adios2/adios2_c_enums.h
+++ b/bindings/C/adios2/adios2_c_enums.h
@@ -64,7 +64,6 @@ typedef enum {
     adios2_open_mode_write,
     adios2_open_mode_read,
     adios2_open_mode_append,
-    adios2_open_mode_read_write
 } adios2_open_mode;
 
 #ifdef __cplusplus
diff --git a/bindings/C/adios2_c.cpp b/bindings/C/adios2_c.cpp
index fb13516feffa1031645f1e229dfe2723581295a3..c898ca3c4e2a3f88defd769e2ef4922c424965b5 100644
--- a/bindings/C/adios2_c.cpp
+++ b/bindings/C/adios2_c.cpp
@@ -257,11 +257,6 @@ void adios2_set_transport_param(adios2_IO *io,
         transport_index, key, value);
 }
 
-struct adios2_Engine
-{
-    std::shared_ptr<adios2::Engine> EngineCpp;
-};
-
 adios2_Engine *adios2_open(adios2_IO *io, const char *name,
                            const adios2_open_mode open_mode)
 {
@@ -274,27 +269,21 @@ adios2_Engine *adios2_open_new_comm(adios2_IO *io, const char *name,
                                     MPI_Comm mpi_comm)
 {
     auto &ioCpp = *reinterpret_cast<adios2::IO *>(io);
-    adios2_Engine *engine = new adios2_Engine;
+    adios2::Engine *engine = nullptr;
 
     switch (open_mode)
     {
 
     case adios2_open_mode_write:
-        engine->EngineCpp = ioCpp.Open(name, adios2::OpenMode::Write, mpi_comm);
+        engine = &ioCpp.Open(name, adios2::Mode::Write, mpi_comm);
         break;
 
     case adios2_open_mode_read:
-        engine->EngineCpp = ioCpp.Open(name, adios2::OpenMode::Read, mpi_comm);
+        engine = &ioCpp.Open(name, adios2::Mode::Read, mpi_comm);
         break;
 
     case adios2_open_mode_append:
-        engine->EngineCpp =
-            ioCpp.Open(name, adios2::OpenMode::Append, mpi_comm);
-        break;
-
-    case adios2_open_mode_read_write:
-        engine->EngineCpp =
-            ioCpp.Open(name, adios2::OpenMode::ReadWrite, mpi_comm);
+        engine = &ioCpp.Open(name, adios2::Mode::Append, mpi_comm);
         break;
 
     case adios2_open_mode_undefined:
@@ -302,7 +291,7 @@ adios2_Engine *adios2_open_new_comm(adios2_IO *io, const char *name,
         break;
     }
 
-    return engine;
+    return reinterpret_cast<adios2_Engine *>(engine);
 }
 
 void adios2_write(adios2_Engine *engine, adios2_Variable *variable,
@@ -315,21 +304,27 @@ void adios2_write(adios2_Engine *engine, adios2_Variable *variable,
 void adios2_write_by_name(adios2_Engine *engine, const char *variable_name,
                           const void *values)
 {
-    engine->EngineCpp->Write(variable_name, values);
+    auto &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+    engineCpp.Write(variable_name, values);
 }
 
-void adios2_advance(adios2_Engine *engine) { engine->EngineCpp->Advance(); }
+void adios2_advance(adios2_Engine *engine)
+{
+    auto &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+    engineCpp.Advance();
+}
 
 void adios2_close(adios2_Engine *engine)
 {
-    engine->EngineCpp->Close();
-    delete engine;
+    auto &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+    engineCpp.Close();
 }
 
 void adios2_close_by_index(adios2_Engine *engine,
                            const unsigned int transport_index)
 {
-    engine->EngineCpp->Close(transport_index);
+    auto &engineCpp = *reinterpret_cast<adios2::Engine *>(engine);
+    engineCpp.Close(transport_index);
 }
 
 void adios2_finalize(adios2_ADIOS *adios)
diff --git a/bindings/fortran/adios2_params_mod.f90 b/bindings/fortran/adios2_params_mod.f90
index 59f934e3e0aa499b9f411f9500b266675dbb0df0..fb22985afbdeee486d4421d2bcc9bcd59598f937 100644
--- a/bindings/fortran/adios2_params_mod.f90
+++ b/bindings/fortran/adios2_params_mod.f90
@@ -36,6 +36,5 @@ module adios2_params
     integer, parameter :: adios2_open_mode_write = 1
     integer, parameter :: adios2_open_mode_read = 2
     integer, parameter :: adios2_open_mode_append = 3
-    integer, parameter :: adios2_open_mode_read_write = 4
 
 end module
diff --git a/bindings/python/EnginePy.cpp b/bindings/python/EnginePy.cpp
index 3a203a5d6552a43b34573fc2618abe61510d3e47..12da987ccac15960e39d286e72882ec15771936a 100644
--- a/bindings/python/EnginePy.cpp
+++ b/bindings/python/EnginePy.cpp
@@ -15,7 +15,7 @@
 namespace adios2
 {
 
-EnginePy::EnginePy(IO &io, const std::string &name, const OpenMode openMode,
+EnginePy::EnginePy(IO &io, const std::string &name, const Mode openMode,
                    MPI_Comm mpiComm)
 : m_IO(io), m_Engine(m_IO.Open(name, openMode, mpiComm)),
   m_DebugMode(m_IO.m_DebugMode)
@@ -56,12 +56,12 @@ void EnginePy::Write(VariablePy &variable, const pyArray &array)
 
 void EnginePy::Advance(const float timeoutSeconds)
 {
-    m_Engine->Advance(timeoutSeconds);
+    m_Engine.Advance(timeoutSeconds);
 }
 
 void EnginePy::Close(const int transportIndex)
 {
-    m_Engine->Close(transportIndex);
+    m_Engine.Close(transportIndex);
 }
 
-} // end namespace adios
+} // end namespace adios2
diff --git a/bindings/python/EnginePy.h b/bindings/python/EnginePy.h
index 10046b3a65699660e3764c866448d7e5c8ffaf4b..ff5bb679d98307f2e40912399a5307069c76a3b9 100644
--- a/bindings/python/EnginePy.h
+++ b/bindings/python/EnginePy.h
@@ -28,7 +28,7 @@ class EnginePy
 {
 
 public:
-    EnginePy(IO &io, const std::string &name, const OpenMode openMode,
+    EnginePy(IO &io, const std::string &name, const Mode openMode,
              MPI_Comm mpiComm);
 
     ~EnginePy() = default;
@@ -41,7 +41,7 @@ public:
 
 private:
     IO &m_IO;
-    std::shared_ptr<Engine> m_Engine;
+    Engine &m_Engine;
     const bool m_DebugMode;
 
     template <class T>
diff --git a/bindings/python/EnginePy.inl b/bindings/python/EnginePy.inl
index eea3e71aa32fad6d3f4b7ce502d562c57b3374d2..9e82af68f4a9e04f9844dc3481ab1dff4134ba6b 100644
--- a/bindings/python/EnginePy.inl
+++ b/bindings/python/EnginePy.inl
@@ -34,10 +34,10 @@ void EnginePy::DefineVariableInIO(VariablePy &variable)
 template <class T>
 void EnginePy::WriteInIO(VariablePy &variable, const pyArray &array)
 {
-    m_Engine->Write(*dynamic_cast<Variable<T> *>(variable.m_VariableBase),
-                    reinterpret_cast<const T *>(array.data()));
+    m_Engine.Write(*dynamic_cast<Variable<T> *>(variable.m_VariableBase),
+                   reinterpret_cast<const T *>(array.data()));
 }
 
-} // end namespace adios
+} // end namespace adios2
 
-#endif /* BINDINGS_PYTHON_SOURCE_ENGINEPY_TCC_ */
+#endif /* BINDINGS_PYTHON_SOURCE_ENGINEPY_INL_ */
diff --git a/bindings/python/IOPy.cpp b/bindings/python/IOPy.cpp
index 1ae9475b1f5a2dea518390d7af54f2a8a497d567..da69d9c55b759275fc9819521554ecc09daf0fee 100644
--- a/bindings/python/IOPy.cpp
+++ b/bindings/python/IOPy.cpp
@@ -69,7 +69,7 @@ VariablePy &IOPy::GetVariable(const std::string &name)
 
 EnginePy IOPy::Open(const std::string &name, const int openMode)
 {
-    return EnginePy(m_IO, name, static_cast<adios2::OpenMode>(openMode),
+    return EnginePy(m_IO, name, static_cast<adios2::Mode>(openMode),
                     m_IO.m_MPIComm);
 }
 
diff --git a/bindings/python/gluePyBind11.cpp b/bindings/python/gluePyBind11.cpp
index 85f5ec219461a07de5c4a89ce690b5f426f100dd..cc42f332b8dbd28461b715e1c0e95926207cdbfb 100644
--- a/bindings/python/gluePyBind11.cpp
+++ b/bindings/python/gluePyBind11.cpp
@@ -91,10 +91,9 @@ PYBIND11_PLUGIN(adios2)
     m.attr("DebugON") = true;
     m.attr("DebugOFF") = false;
     m.attr("ConstantDims") = true;
-    m.attr("OpenModeWrite") = static_cast<int>(adios2::OpenMode::Write);
-    m.attr("OpenModeRead") = static_cast<int>(adios2::OpenMode::Read);
-    m.attr("OpenModeAppend") = static_cast<int>(adios2::OpenMode::Append);
-    m.attr("OpenModeReadWrite") = static_cast<int>(adios2::OpenMode::ReadWrite);
+    m.attr("ModeWrite") = static_cast<int>(adios2::Mode::Write);
+    m.attr("ModeRead") = static_cast<int>(adios2::Mode::Read);
+    m.attr("ModeAppend") = static_cast<int>(adios2::Mode::Append);
     m.def("ADIOS", &ADIOSPyInit, "Function that creates an ADIOS class object");
     m.def("ADIOS", &ADIOSPyInitConfig,
           "Function that creates an ADIOS class object using a config file");
diff --git a/examples/basics/globalArray/globalArray_write.cpp b/examples/basics/globalArray/globalArray_write.cpp
index 7a1b98ac36012be999362d19227b37a12aba3583..a53074375b98ec520013d83e9bc01c463f4b7380 100644
--- a/examples/basics/globalArray/globalArray_write.cpp
+++ b/examples/basics/globalArray/globalArray_write.cpp
@@ -75,11 +75,7 @@ int main(int argc, char *argv[])
 
         // Open file. "w" means we overwrite any existing file on disk,
         // but Advance() will append steps to the same file.
-        auto writer = io.Open("globalArray.bp", adios2::OpenMode::Write);
-
-        if (!writer)
-            throw std::ios_base::failure(
-                "ERROR: failed to open file with ADIOS\n");
+        adios2::Engine &writer = io.Open("globalArray.bp", adios2::Mode::Write);
 
         for (int step = 0; step < NSTEPS; step++)
         {
@@ -90,18 +86,19 @@ int main(int argc, char *argv[])
 
             // Make a 2D selection to describe the local dimensions of the
             // variable we write and its offsets in the global spaces
-            adios2::SelectionBoundingBox sel({(unsigned int)rank, 0}, {1, Nx});
-            varGlobalArray.SetSelection(sel);
-            writer->Write<double>(varGlobalArray, row.data());
+            // adios2::SelectionBoundingBox sel();
+            varGlobalArray.SetSelection(adios2::Box<adios2::Dims>(
+                {static_cast<size_t>(rank), 0}, {1, static_cast<size_t>(Nx)}));
+            writer.Write<double>(varGlobalArray, row.data());
 
             // Indicate we are done for this step.
             // Disk I/O will be performed during this call unless
             // time aggregation postpones all of that to some later step
-            writer->Advance();
+            writer.Advance();
         }
 
         // Called once: indicate that we are done with this output for the run
-        writer->Close();
+        writer.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/basics/joinedArray/joinedArray_write.cpp b/examples/basics/joinedArray/joinedArray_write.cpp
index d22438dda7dfe985b869d9abc8c9911efc186ad0..a2939b6f9739c0ae640db32008362836fa54a86d 100644
--- a/examples/basics/joinedArray/joinedArray_write.cpp
+++ b/examples/basics/joinedArray/joinedArray_write.cpp
@@ -83,11 +83,7 @@ int main(int argc, char *argv[])
 
         // Open file. "w" means we overwrite any existing file on disk,
         // but Advance() will append steps to the same file.
-        auto writer = io.Open("joinedArray.bp", adios2::OpenMode::Write);
-
-        if (writer == nullptr)
-            throw std::ios_base::failure(
-                "ERROR: failed to open file with ADIOS\n");
+        adios2::Engine &writer = io.Open("joinedArray.bp", adios2::Mode::Write);
 
         for (int step = 0; step < NSTEPS; step++)
         {
@@ -100,12 +96,12 @@ int main(int argc, char *argv[])
                 }
             }
 
-            writer->Write<double>(varTable, mytable.data());
+            writer.Write<double>(varTable, mytable.data());
 
-            writer->Advance();
+            writer.Advance();
         }
 
-        writer->Close();
+        writer.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/basics/localArray/localArray_write.cpp b/examples/basics/localArray/localArray_write.cpp
index 7a0e741eb2d29979d305d79be5b46b22e585dd5e..761c4a35f7f1a304965b452c7745bf3739c9174b 100644
--- a/examples/basics/localArray/localArray_write.cpp
+++ b/examples/basics/localArray/localArray_write.cpp
@@ -85,11 +85,7 @@ int main(int argc, char *argv[])
 
         // Open file. "w" means we overwrite any existing file on disk,
         // but Advance() will append steps to the same file.
-        auto writer = io.Open("localArray.bp", adios2::OpenMode::Write);
-
-        if (writer == nullptr)
-            throw std::ios_base::failure(
-                "ERROR: failed to open file with ADIOS\n");
+        adios2::Engine &writer = io.Open("localArray.bp", adios2::Mode::Write);
 
         for (int step = 0; step < NSTEPS; step++)
         {
@@ -98,7 +94,7 @@ int main(int argc, char *argv[])
                 v1[i] = rank * 1.0 + step * 0.1;
             }
 
-            writer->Write<double>(varV1, v1.data());
+            writer.Write<double>(varV1, v1.data());
 
             // random size per process per step, 5..10 each
             Nelems = rand() % 6 + 5;
@@ -110,13 +106,13 @@ int main(int argc, char *argv[])
 
             // Set the size of the array now because we did not know
             // the size at the time of definition
-            varV2.SetSelection({}, {Nelems});
-            writer->Write<double>(varV2, v2.data());
+            varV2.SetSelection(adios2::Box<adios2::Dims>({}, {Nelems}));
+            writer.Write<double>(varV2, v2.data());
 
-            writer->Advance();
+            writer.Advance();
         }
 
-        writer->Close();
+        writer.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/basics/values/values_write.cpp b/examples/basics/values/values_write.cpp
index 6ba9acf3d72d57a823830f4fad161c8818b04af3..22e80453bf00ed9e5a97e99f8248b878f6a0bfe6 100644
--- a/examples/basics/values/values_write.cpp
+++ b/examples/basics/values/values_write.cpp
@@ -86,11 +86,7 @@ int main(int argc, char *argv[])
 
         // Open file. "w" means we overwrite any existing file on disk,
         // but Advance() will append steps to the same file.
-        auto writer = io.Open("values.bp", adios2::OpenMode::Write);
-
-        if (!writer)
-            throw std::ios_base::failure(
-                "ERROR: failed to open file with ADIOS\n");
+        adios2::Engine &writer = io.Open("values.bp", adios2::Mode::Write);
 
         for (int step = 0; step < NSTEPS; step++)
         {
@@ -103,27 +99,27 @@ int main(int argc, char *argv[])
                 // 1. Writing a global constant value only once
                 if (step == 0)
                 {
-                    writer->Write<int>("Nproc", nproc);
+                    writer.Write<int>("Nproc", nproc);
                 }
-                writer->Write<int>(varStep, step);
+                writer.Write<int>(varStep, step);
             }
 
             // 3. and 4. Writing a local value on every process. Will be shown
             // at reading as a 1D array
             if (step == 0)
             {
-                writer->Write<int>(varProcessID, rank);
+                writer.Write<int>(varProcessID, rank);
             }
-            writer->Write<unsigned int>(varNparts, Nparts);
+            writer.Write<unsigned int>(varNparts, Nparts);
 
             // Indicate we are done for this step.
             // Disk I/O will be performed during this call unless
             // time aggregation postpones all of that to some later step
-            writer->Advance();
+            writer.Advance();
         }
 
         // Called once: indicate that we are done with this output for the run
-        writer->Close();
+        writer.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/experimental/api/FileDeferredRead.cpp b/examples/experimental/api/FileDeferredRead.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e9c8fe8627f8703b16bba66184f60864560a8329
--- /dev/null
+++ b/examples/experimental/api/FileDeferredRead.cpp
@@ -0,0 +1,98 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileReadAPIDeferred.cpp :
+ *
+ *  Created on: Sep 22, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include <adios2.h>
+#include <mpi.h>
+
+#include <vector>
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /** Application variable */
+    const std::size_t Nx = 10;
+    std::vector<float> myFloats(Nx);
+    std::vector<int> myInts(Nx);
+
+    try
+    {
+        /** ADIOS class factory of IO class objects, DebugON is 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("ReadBP");
+
+        /**
+         * Engine derived class, spawned to start IO operations
+         * Deferred expects a "Get" to execute all the Reads
+         */
+        adios2::Engine &bpReader = bpIO.Open(
+            "myVector.bp", adios2::Mode::Read | adios2::Mode::Deferred);
+
+        /** Write variable for buffering */
+        adios2::Variable<float> *bpFloats =
+            bpReader.InquireVariable<float>("bpFloats");
+        adios2::Variable<int> *bpInts = bpReader.InquireVariable<int>("bpInts");
+
+        // Set selection
+        /** Dimensions Bounding Box {start}, {count} */
+        adios2::Box<adios2::Dims> boxDims({0}, {5});
+
+        /** Steps Bounding Box {start}, {count} */
+        adios2::Box<adios2::Steps> boxSteps({1}, {2});
+
+        if (bpFloats != nullptr)
+        {
+            bpFloats->SetSelection(boxDims, boxSteps);
+            bpReader.Read<float>(*bpFloats, myFloats.data());
+            // myFloats.data() is not available
+        }
+
+        if (bpInts != nullptr)
+        {
+            bpFloats->SetSelection(boxDims, boxSteps);
+            bpReader.Read<int>(*bpInts, myInts.data());
+            // myInts.data() is not available
+        }
+
+        /** execute all the deferred Read instructions */
+        bpReader.Get();
+
+        /** Close bp file, engine becomes unreachable after this */
+        bpReader.Close();
+    }
+    catch (std::invalid_argument &e)
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::ios_base::failure &e)
+    {
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+
+    MPI_Finalize();
+
+    return 0;
+}
diff --git a/examples/experimental/api/FileDeferredWrite.cpp b/examples/experimental/api/FileDeferredWrite.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..03300b20531b4d4ab219becb08d6735d9cf5e874
--- /dev/null
+++ b/examples/experimental/api/FileDeferredWrite.cpp
@@ -0,0 +1,104 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileDeferredWrite.cpp
+ *
+ *  Created on: Sep 22, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include <ios>      //std::ios_base::failure
+#include <iostream> //std::cout
+#include <mpi.h>
+#include <stdexcept> //std::invalid_argument std::exception
+#include <vector>
+
+#include <adios2.h>
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /** Application variable */
+    std::vector<float> myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    std::vector<int> myInts = {0, -1, -2, -3, -4, -5, -6, -7, -8, -9};
+    const std::size_t Nx = myFloats.size();
+
+    try
+    {
+        /** ADIOS class factory of IO class objects, DebugON is 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");
+
+        /// Setting flush policy
+        // the user can set the memory explicitly for ADIOS (more advance users)
+        bpIO.SetSingleParameter("MaxBufferSize", "100Mb");
+        // or by number of steps (naively trying to allocate "N=3" steps before
+        // flushing
+        // bpIO.SetSingleParameter("StepsToBuffer", "3");
+
+        /** global array : name, { shape (total) }, { start (local) }, {
+         * count
+         * (local) }, all are constant dimensions */
+        adios2::Variable<float> &bpFloats = bpIO.DefineVariable<float>(
+            "bpFloats", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
+
+        adios2::Variable<int> &bpInts = bpIO.DefineVariable<int>(
+            "bpInts", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
+
+        /** Engine derived class, spawned to start IO operations */
+        /** Deferred Mode: Write buffering will be done at Put(), the user makes
+         *  the commitment that pointers passed at Write won't be reused */
+        auto bpWriter = bpIO.Open("myVector.bp",
+                                  adios2::Mode::Write | adios2::Mode::Deferred);
+
+        // default = 0, in bp1 format this is translated to 1, but user should
+        // be able to start at any step
+        bpWriter.SetStep(1);
+
+        /** Write variable for buffering */
+        for (unsigned int t = 0; t < 100; ++t)
+        {
+            bpWriter.Write<float>(bpFloats, myFloats.data());
+            bpWriter.Write<int>(bpInts, myInts.data());
+            bpWriter.Advance(); // advances step
+
+            if (t % 10 == 0) // checkpoint/restart every 10 steps, force flush
+            {
+                bpWriter.Flush();
+            }
+        }
+
+        /** Engine becomes unreachable after Close */
+        bpWriter.Close();
+    }
+    catch (std::invalid_argument &e)
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::ios_base::failure &e)
+    {
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+
+    MPI_Finalize();
+
+    return 0;
+}
diff --git a/examples/experimental/api/FileRead.cpp b/examples/experimental/api/FileRead.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..03fbe4c0d944ddfdb8f35d37d0ad105dd3172c4b
--- /dev/null
+++ b/examples/experimental/api/FileRead.cpp
@@ -0,0 +1,91 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileReadAPI.cpp
+ *
+ *  Created on: Sep 22, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include <adios2.h>
+#include <mpi.h>
+
+#include <vector>
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /** Application variable */
+    const std::size_t Nx = 10;
+    std::vector<float> myFloats(Nx);
+    std::vector<int> myInts(Nx);
+
+    try
+    {
+        /** ADIOS class factory of IO class objects, DebugON is 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("ReadBP");
+
+        /** Engine derived class, spawned to start IO operations */
+        auto bpReader = bpIO.Open("myVector.bp", adios2::Mode::Read);
+
+        /** Write variable for buffering */
+        adios2::Variable<float> *bpFloats =
+            bpReader.InquireVariable<float>("bpFloats");
+        adios2::Variable<int> *bpInts = bpReader.InquireVariable<int>("bpInts");
+
+        // Set selection
+        /** Dimensions Bounding Box {start}, {count} */
+        adios2::Box<adios2::Dims> boxDims({0}, {5});
+
+        /** Steps Bounding Box {start}, {count} */
+        adios2::Box<adios2::Steps> boxSteps({1}, {2});
+
+        if (bpFloats != nullptr)
+        {
+            bpFloats->SetSelection(boxDims, boxSteps);
+            bpReader.Read<float>(*bpFloats, myFloats.data());
+            // myFloats.data() is available
+        }
+
+        if (bpInts != nullptr)
+        {
+            bpFloats->SetSelection(boxDims, boxSteps);
+            bpReader.Read<int>(*bpInts, myInts.data());
+            // myInts.data() is available
+        }
+
+        /** Close bp file, engine becomes unreachable after this */
+        bpReader.Close();
+    }
+    catch (std::invalid_argument &e)
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::ios_base::failure &e)
+    {
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+
+    MPI_Finalize();
+
+    return 0;
+}
diff --git a/examples/experimental/api/FileTransientDeferredRead.cpp b/examples/experimental/api/FileTransientDeferredRead.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1e8b94ab7743bacaceae0381bd97ee2b32e0abfa
--- /dev/null
+++ b/examples/experimental/api/FileTransientDeferredRead.cpp
@@ -0,0 +1,116 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileTransientDeferredRead.cpp
+ *
+ *  Created on: Sep 25, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include <adios2.h>
+#include <mpi.h>
+
+#include <vector>
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /** Application variable */
+    const std::size_t Nx = 10;
+    std::vector<float> myFloats(Nx);
+    std::vector<int> myInts(Nx);
+
+    try
+    {
+        /** ADIOS class factory of IO class objects, DebugON is 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("ReadBP");
+
+        /**
+         * Engine derived class, spawned to start IO operations
+         * Deferred expects a "Get" to execute all the Reads
+         */
+        adios2::Engine &bpReader = bpIO.Open(
+            "myVector.bp", adios2::Mode::Read | adios2::Mode::Deferred);
+
+        /** Find variables for reading */
+        adios2::Variable<float> *bpFloats =
+            bpReader.InquireVariable<float>("bpFloats");
+
+        if (bpFloats == nullptr)
+        {
+            throw std::runtime_error("ERROR: variable " + bpFloats->m_Name +
+                                     " not found\n");
+        }
+
+        adios2::Variable<int> *bpInts = bpReader.InquireVariable<int>("bpInts");
+
+        if (bpInts == nullptr)
+        {
+            throw std::runtime_error("ERROR: variable " + bpInts->m_Name +
+                                     " not found\n");
+        }
+
+        /** Dimensions Bounding Box {start}, {count} assume constant across time
+         * iterations */
+        adios2::Box<adios2::Dims> boxDims({0}, {5});
+        bpFloats->SetSelection(boxDims);
+        bpInts->SetSelection(boxDims);
+
+        for (unsigned int t = 0; t < 100; ++t)
+        {
+            // Set time selection
+            /** Steps Bounding Box {start}, {count} */
+            adios2::Box<adios2::Steps> boxSteps({static_cast<std::size_t>(t)},
+                                                {1});
+
+            bpFloats->SetStepSelection(boxSteps);
+            bpInts->SetStepSelection(boxSteps);
+
+            bpReader.Read<float>(*bpFloats, myFloats.data());
+            bpReader.Read<int>(*bpInts, myInts.data());
+
+            /** execute all the deferred Read instructions within step, pointer
+             * data is only ready at Get */
+            if (bpReader.GetAdvanceStatus() == adios2::AdvanceStatus::OK)
+            {
+                bpReader.Get();
+            }
+
+            // do tasks here with the pointers ...
+        }
+
+        /** Close bp file, engine becomes unreachable after this */
+        bpReader.Close();
+    }
+    catch (std::invalid_argument &e)
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::ios_base::failure &e)
+    {
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+
+    MPI_Finalize();
+
+    return 0;
+}
diff --git a/examples/experimental/api/FileTransientDeferredWrite.cpp b/examples/experimental/api/FileTransientDeferredWrite.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..65a4a01d6d7b0267d980235b0615842515482238
--- /dev/null
+++ b/examples/experimental/api/FileTransientDeferredWrite.cpp
@@ -0,0 +1,88 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileTransientDeferredWrite.cpp : deferred write in a transient (time
+ * aggregation) loop. Buffering is done at Flush
+ *
+ *  Created on: Sep 25, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include <adios2.h>
+#include <mpi.h>
+
+#include <vector>
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /** Application variable */
+    std::vector<float> myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    std::vector<int> myInts = {0, -1, -2, -3, -4, -5, -6, -7, -8, -9};
+    const std::size_t Nx = myFloats.size();
+
+    try
+    {
+        /** ADIOS class factory of IO class objects, DebugON is 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");
+
+        /** global array : name, { shape (total) }, { start (local) }, {
+         * count
+         * (local) }, all are constant dimensions */
+        adios2::Variable<float> &bpFloats = bpIO.DefineVariable<float>(
+            "bpFloats", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
+
+        adios2::Variable<int> &bpInts = bpIO.DefineVariable<int>(
+            "bpInts", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
+
+        /** Engine derived class, spawned to start IO operations */
+        /** Deferred Mode: Write buffering will be done at Flush().
+         *  The user must be the one enforcing the commitment that pointers
+         * passed at Write won't be reused between Write and Flush */
+        auto bpWriter = bpIO.Open("myVector.bp",
+                                  adios2::Mode::Write | adios2::Mode::Deferred);
+
+        for (unsigned int t = 0; t < 100; ++t)
+        {
+
+            /** Write variable for buffering */
+            bpWriter.Write<float>(bpFloats, myFloats.data());
+            bpWriter.Write<int>(bpInts, myInts.data());
+            bpWriter.Flush();
+        }
+
+        /** Create bp file, engine becomes unreachable after this*/
+        bpWriter.Close();
+    }
+    catch (std::invalid_argument &e)
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::ios_base::failure &e)
+    {
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+
+    MPI_Finalize();
+
+    return 0;
+}
diff --git a/examples/experimental/api/FileTransientRead.cpp b/examples/experimental/api/FileTransientRead.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..adebe2f1f93c4cdf128085530cff913e8b62a1ee
--- /dev/null
+++ b/examples/experimental/api/FileTransientRead.cpp
@@ -0,0 +1,113 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileTransientRead.cpp
+ *
+ *  Created on: Sep 25, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include <adios2.h>
+#include <mpi.h>
+
+#include <vector>
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /** Application variable */
+    const std::size_t Nx = 10;
+    std::vector<float> myFloats(Nx);
+    std::vector<int> myInts(Nx);
+
+    try
+    {
+        /** ADIOS class factory of IO class objects, DebugON is 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("ReadBP");
+
+        /**
+         * Engine derived class, spawned to start IO operations
+         */
+        adios2::Engine &bpReader = bpIO.Open("myVector.bp", adios2::Mode::Read);
+
+        /** Find variables for reading */
+        adios2::Variable<float> *bpFloats =
+            bpReader.InquireVariable<float>("bpFloats");
+
+        if (bpFloats == nullptr)
+        {
+            throw std::runtime_error("ERROR: variable " + bpFloats->m_Name +
+                                     " not found\n");
+        }
+
+        adios2::Variable<int> *bpInts = bpReader.InquireVariable<int>("bpInts");
+
+        if (bpInts == nullptr)
+        {
+            throw std::runtime_error("ERROR: variable " + bpInts->m_Name +
+                                     " not found\n");
+        }
+
+        /** Dimensions Bounding Box {start}, {count} assume constant across time
+         * iterations */
+        adios2::Box<adios2::Dims> boxDims({0}, {5});
+        bpFloats->SetSelection(boxDims);
+        bpInts->SetSelection(boxDims);
+
+        for (unsigned int t = 0; t < 100; ++t)
+        {
+            // Set time selection
+            /** Steps Bounding Box {start}, {count} */
+            adios2::Box<adios2::Steps> boxSteps({static_cast<std::size_t>(t)},
+                                                {1});
+
+            bpFloats->SetStepSelection(boxSteps);
+            bpInts->SetStepSelection(boxSteps);
+
+            /** execute Read instructions within step one by one, pointer data
+             * is available after Read*/
+            if (bpReader.GetAdvanceStatus() == adios2::AdvanceStatus::OK)
+            {
+                bpReader.Read<float>(*bpFloats, myFloats.data());
+                bpReader.Read<int>(*bpInts, myInts.data());
+            }
+
+            // do tasks here with the variables
+            // ...
+        }
+
+        /** Close bp file, engine becomes unreachable after this */
+        bpReader.Close();
+    }
+    catch (std::invalid_argument &e)
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::ios_base::failure &e)
+    {
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+
+    MPI_Finalize();
+
+    return 0;
+}
diff --git a/examples/experimental/api/FileTransientWrite.cpp b/examples/experimental/api/FileTransientWrite.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9fe4c1a05a46b84c455e5cf4a709b6a8ff8138a3
--- /dev/null
+++ b/examples/experimental/api/FileTransientWrite.cpp
@@ -0,0 +1,104 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileTransientWrite.cpp
+ *
+ *  Created on: Sep 22, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include <ios>      //std::ios_base::failure
+#include <iostream> //std::cout
+#include <mpi.h>
+#include <stdexcept> //std::invalid_argument std::exception
+#include <vector>
+
+#include <adios2.h>
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /** Application variable */
+    std::vector<float> myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    std::vector<int> myInts = {0, -1, -2, -3, -4, -5, -6, -7, -8, -9};
+    const std::size_t Nx = myFloats.size();
+
+    try
+    {
+        /** ADIOS class factory of IO class objects, DebugON is 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");
+
+        /// Setting flush policy
+        // the user can set the memory explicitly for ADIOS2
+        bpIO.SetSingleParameter("MaxBufferSize", "100Mb");
+        // or by number of steps (naively trying to allocate "N=3" steps before
+        // flushing
+        // bpIO.SetSingleParameter("StepsToBuffer", "3");
+
+        /** global array : name, { shape (total) }, { start (local) }, {
+         * count
+         * (local) }, all are constant dimensions */
+        adios2::Variable<float> &bpFloats = bpIO.DefineVariable<float>(
+            "bpFloats", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
+
+        adios2::Variable<int> &bpInts = bpIO.DefineVariable<int>(
+            "bpInts", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
+
+        /** Engine derived class, spawned to start IO operations */
+        /**  Buffering is done at every Write */
+        auto bpWriter = bpIO.Open("myVector.bp", adios2::Mode::Write);
+
+        // default = 0, in bp1 format this is translated to 1, but user should
+        // be able to start at any step
+        bpWriter.SetStep(1);
+
+        /** Write variable for buffering */
+        for (unsigned int t = 0; t < 100; ++t)
+        {
+            bpWriter.Write<float>(bpFloats, myFloats.data());
+            bpWriter.Write<int>(bpInts, myInts.data());
+            bpWriter.Advance(); // advances step
+
+            // checkpoint/restart every 10 steps, force flush regardless of
+            // buffer status
+            if (t % 10 == 0)
+            {
+                bpWriter.Flush();
+            }
+        }
+
+        /** Engine becomes unreachable after Close */
+        bpWriter.Close();
+    }
+    catch (std::invalid_argument &e)
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::ios_base::failure &e)
+    {
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+
+    MPI_Finalize();
+
+    return 0;
+}
diff --git a/examples/experimental/api/StreamingAsyncWrite.cpp b/examples/experimental/api/StreamingAsyncWrite.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9c6cb435672911c27ea40357b29da55979a5359a
--- /dev/null
+++ b/examples/experimental/api/StreamingAsyncWrite.cpp
@@ -0,0 +1,142 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * StreamingAsyncWrite.cpp
+ *
+ *  Created on: Sep 22, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include <future>
+#include <ios>      //std::ios_base::failure
+#include <iostream> //std::cout
+#include <mpi.h>
+#include <stdexcept> //std::invalid_argument std::exception
+#include <vector>
+
+#include <adios2.h>
+
+void Acquire(adios2::VariableBase &variable, std::vector<float> &data)
+{
+    // can be anything to set time and data
+}
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /** Application variable */
+    std::vector<float> myTime = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    std::vector<float> mySound = {0, -1, -2, -3, -4, -5, -6, -7, -8, -9};
+    const std::size_t Nx = myTime.size();
+
+    try
+    {
+        /** ADIOS class factory of IO class objects, DebugON is 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 &streamingIO = adios.DeclareIO("StreamingWrite");
+        streamingIO.SetEngine("DataManWriter");
+
+        auto wanStream = streamingIO.AddTransport(
+            "WAN", {{"IPAddress", "127.0.0.1"}, {"Port", "22"}});
+
+        /// Setting flush policy
+        // the user can set the memory explicitly for ADIOS2
+        streamingIO.SetSingleParameter("MaxBufferSize", "100Mb");
+        // or by number of steps (naively trying to allocate "N=3" steps
+        // before
+        // flushing
+        // bpIO.SetSingleParameter("StepsToBuffer", "3");
+
+        /** global array : name, { shape (total) }, { start (local) },
+         *  { count (local) }, all are constant dimensions */
+        adios2::Variable<float> &bpSound = streamingIO.DefineVariable<float>(
+            "bpSound", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
+
+        adios2::Variable<float> &bpTime = streamingIO.DefineVariable<int>(
+            "bpTime", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
+
+        /** Engine derived class, spawned to start IO operations */
+        /**  Buffering is done at every Write */
+        // we can choose between deferred and synch (default)
+        auto bpStreamWriter =
+            streamingIO.Open("myVector.bp", adios2::Mode::Write);
+
+        /** Write variable for buffering */
+        bool acquiringData = true;
+        bool launchedAsync = false;
+        std::future<void> advanceFuture;
+
+        // infinite loop, unless error is detected
+        while (acquiringData)
+        {
+            try
+            {
+                // can be anything depending on the data coming in
+                Acquire(bpSound, mySound);
+                Acquire(bpTime, myTime);
+
+                bpStreamWriter.Write<float>(bpTime, myTime.data());
+                bpStreamWriter.Write<float>(bpSound, mySound.data());
+
+                if (launchedAsync)
+                {
+                    advanceFuture.get();
+                }
+
+                // if buffer is full it will flush, otherwise it only updates
+                // step "batch"...bpTime and bpSound might have different "time
+                // steps"
+                advanceFuture = bpStreamWriter.AdvanceAsync();
+                launchedAsync = true;
+            }
+            catch (std::exception &e)
+            {
+                if (rank == 0)
+                {
+                    std::cout << "Detected runtime error, stopping streaming\n";
+                }
+                acquiringData = false;
+            }
+        }
+
+        // wait for last Advance if still buffering
+        if (advanceFuture.valid())
+        {
+            advanceFuture.wait();
+        }
+
+        /** Engine becomes unreachable after Close */
+        bpStreamWriter.Close();
+    }
+    catch (std::invalid_argument &e)
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::ios_base::failure &e)
+    {
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+
+    MPI_Finalize();
+
+    return 0;
+}
diff --git a/examples/experimental/api/StreamingRead.cpp b/examples/experimental/api/StreamingRead.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ffabc3ae53979b96c3a51e858b14bab1104427af
--- /dev/null
+++ b/examples/experimental/api/StreamingRead.cpp
@@ -0,0 +1,141 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileStreamingRead.cpp : Reads from a stream of bp self-describing variables,
+ * extract variables of unknown and known type, flush to disk
+ *
+ *  Created on: Sep 25, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include <adios2.h>
+#include <mpi.h>
+
+#include <vector>
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /** Application variable */
+    const std::size_t Nx = 10;
+    std::vector<float> myFloats;
+    int *myInts = nullptr;
+    void *myAnyType = nullptr;
+
+    try
+    {
+        /** ADIOS class factory of IO class objects, DebugON is 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 &streamingIO = adios.DeclareIO("ReadBP");
+        streamingIO.SetEngine("DataManReader");
+        streamingIO.SetParameters({{"MaxBufferMemory", "1Gb"}});
+
+        auto wanStream =
+            streamingIO.AddTransport("WAN", {{"IPAddress", "127.0.0.1"},
+                                             {"Port", "22"},
+                                             {"MaxWaitingTime", "1hr"}});
+        auto fileStream = streamingIO.AddTransport(
+            "File", {{"Library", "POSIX"}, {"Name", "TelescopeImages1"}});
+
+        // assumes we know what variables we are receiving
+
+        /**
+         * Engine starts listening
+         */
+        adios2::Engine &bpStreamReader =
+            streamingIO.Open("myVector.bp", adios2::Mode::Read);
+
+        while (bpStreamReader.GetAdvanceStatus() == adios2::AdvanceStatus::OK)
+        {
+            // Gets data until buffer is full (1Gb from SetParameters)
+            bpStreamReader.Get(wanStream);
+
+            /// EXTRACT data duplicating memory
+            adios2::Variable<float> *bpFloats =
+                bpStreamReader.InquireVariable<float>("bpFloats");
+
+            // pre-allocate, this will duplicate memory (just like file Write)
+            if (bpFloats != nullptr)
+            {
+                for (unsigned int t = 0; t < bpFloats->GetAvailableStepsCount();
+                     ++t)
+                {
+                    myFloats.reserve(bpFloats->TotalSize());
+                    myFloats.resize(0);
+
+                    adios2::Box<std::size_t> stepBox(
+                        {bpFloats->GetAvailableStepsStart() + t}, {1});
+                    bpFloats->SetStepSelection(stepBox);
+                    bpStreamReader.Read<float>(*bpFloats, myFloats.data());
+                }
+            }
+
+            adios2::Variable<int> *bpInts =
+                bpStreamReader.InquireVariable<int>("bpInts");
+
+            /// EXTRACT data without duplicating memory
+            // this will not duplicate memory, internal reference to current bp
+            // buffer
+            if (bpFloats != nullptr)
+            {
+                bpStreamReader.Read<int>(*bpInts, myInts);
+            }
+
+            /// EXTRACT any type data (this demotes to void*), without
+            /// duplicating memory
+            adios2::VariableBase *bpAny =
+                bpStreamReader.InquireVariableAny("bpUnknown");
+
+            if (bpAny != nullptr)
+            {
+                // by now we must know the type
+                if (bpAny->m_Type == "int")
+                {
+                    bpStreamReader.Read<int>(
+                        *dynamic_cast<adios2::Variable<int> *>(bpAny),
+                        reinterpret_cast<int *>(myAnyType));
+                }
+            }
+
+            bpStreamReader.Flush(fileStream);
+        }
+
+        bpStreamReader.Close(wanStream); // release wanStream
+
+        // do more tasks with data in-memory...
+
+        /** Close all opened transports (in this case only fileStream), engine
+         * becomes unreachable after
+         * this call */
+        bpStreamReader.Close();
+    }
+    catch (std::invalid_argument &e)
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::ios_base::failure &e)
+    {
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+
+    MPI_Finalize();
+    return 0;
+}
diff --git a/examples/experimental/multistep/reader_allsteps.cpp b/examples/experimental/multistep/reader_allsteps.cpp
index 84020d2f4d9c030ec9c8aa8b64ba72b832b85b21..50ef831f82405b3847a91412923525c9993a2d0b 100644
--- a/examples/experimental/multistep/reader_allsteps.cpp
+++ b/examples/experimental/multistep/reader_allsteps.cpp
@@ -123,7 +123,7 @@ int main(int argc, char *argv[])
         // auto bpReader = adios.Open( "myNumbers.bp", "r" );
         // this would just open with a default transport, which is "BP"
         auto bpReader =
-            bpReaderSettings.Open("myNumbers.bp", adios2::OpenMode::Read);
+            bpReaderSettings.Open("myNumbers.bp", adios2::Mode::Read);
 
         if (!bpReader)
             throw std::ios_base::failure(
diff --git a/examples/experimental/multistep/reader_stepping.cpp b/examples/experimental/multistep/reader_stepping.cpp
index e8c8decc6f56cfedea0569c4b26b9c3b188ce09a..35322ebfd7253604d8149d21d3f78402ad06b270 100644
--- a/examples/experimental/multistep/reader_stepping.cpp
+++ b/examples/experimental/multistep/reader_stepping.cpp
@@ -71,7 +71,7 @@ int main(int argc, char *argv[])
         }
 
         auto bpReader =
-            bpReaderSettings.Open("myNumbers.bp", adios2::OpenMode::Read);
+            bpReaderSettings.Open("myNumbers.bp", adios2::Mode::Read);
         if (!bpReader)
         {
             int step = 0;
diff --git a/examples/experimental/multistep/writer_multistep.cpp b/examples/experimental/multistep/writer_multistep.cpp
index 43216e1728b73a770e215996afe1568c6f3ef49f..48e3f55cee20c81b5e6ca741f179da161cca9b9e 100644
--- a/examples/experimental/multistep/writer_multistep.cpp
+++ b/examples/experimental/multistep/writer_multistep.cpp
@@ -151,7 +151,7 @@ int main(int argc, char *argv[])
         // will
         // append steps later.
         auto bpWriter =
-            bpWriterSettings.Open("myNumbers.bp", adios2::OpenMode::Write);
+            bpWriterSettings.Open("myNumbers.bp", adios2::Mode::Write);
 
         if (!bpWriter)
         {
diff --git a/examples/experimental/runtimeconfig/hello/helloBPWriterXML.cpp b/examples/experimental/runtimeconfig/hello/helloBPWriterXML.cpp
index dc34fa06e381e70e8563142cd24bd3905c497073..d0ac5222f83f6802fd918b5ae98e787269b61cc3 100644
--- a/examples/experimental/runtimeconfig/hello/helloBPWriterXML.cpp
+++ b/examples/experimental/runtimeconfig/hello/helloBPWriterXML.cpp
@@ -74,7 +74,7 @@ int main(int argc, char *argv[])
             "bpFloats", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
 
         /** Engine derived class, spawned to start IO operations */
-        auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write);
+        auto bpWriter = bpIO.Open("myVector.bp", adios2::Mode::Write);
 
         if (!bpWriter)
         {
diff --git a/examples/experimental/runtimeconfig/hello/helloBPWriterXML_nompi.cpp b/examples/experimental/runtimeconfig/hello/helloBPWriterXML_nompi.cpp
index 50cf93e0016aec9456e5eaec23efdd68eb041b54..c9c7a7dd978025b40ff34444201415110355a500 100644
--- a/examples/experimental/runtimeconfig/hello/helloBPWriterXML_nompi.cpp
+++ b/examples/experimental/runtimeconfig/hello/helloBPWriterXML_nompi.cpp
@@ -61,7 +61,7 @@ int main(int argc, char *argv[])
             "bpFloats", {}, {}, {Nx}, adios2::ConstantDims);
 
         /** Engine derived class, spawned to start IO operations */
-        auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write);
+        auto bpWriter = bpIO.Open("myVector.bp", adios2::Mode::Write);
 
         if (!bpWriter)
         {
diff --git a/examples/heatTransfer/read/heatRead_adios2.cpp b/examples/heatTransfer/read/heatRead_adios2.cpp
index 35ec668372a3c950002659d1487cac773a4515c7..18fafc9299739302b52537200781a160e8b4c4ea 100644
--- a/examples/heatTransfer/read/heatRead_adios2.cpp
+++ b/examples/heatTransfer/read/heatRead_adios2.cpp
@@ -62,14 +62,8 @@ int main(int argc, char *argv[])
         bpReaderIO.AddTransport("File", {{"verbose", "4"}});
     }
 
-    auto bpReader =
-        bpReaderIO.Open(inputfile, adios2::OpenMode::Read, mpiReaderComm);
-
-    if (!bpReader)
-    {
-        throw std::ios_base::failure("ERROR: failed to open " +
-                                     std::string(inputfile) + "\n");
-    }
+    adios2::Engine &bpReader =
+        bpReaderIO.Open(inputfile, adios2::Mode::Read, mpiReaderComm);
 
     unsigned int gndx;
     unsigned int gndy;
@@ -77,19 +71,20 @@ int main(int argc, char *argv[])
     // bpReader->Read<unsigned int>("gndy", &gndy);
 
     adios2::Variable<unsigned int> *vgndx =
-        bpReader->InquireVariable<unsigned int>("gndx");
+        bpReader.InquireVariable<unsigned int>("gndx");
 
     gndx = vgndx->m_Data[0];
 
     adios2::Variable<unsigned int> *vgndy =
-        bpReader->InquireVariable<unsigned int>("gndy");
+        bpReader.InquireVariable<unsigned int>("gndy");
     gndy = vgndy->m_Data[0];
 
     if (rank == 0)
     {
         std::cout << "gndx       = " << gndx << std::endl;
         std::cout << "gndy       = " << gndy << std::endl;
-        std::cout << "# of steps = " << vgndy->m_AvailableSteps << std::endl;
+        std::cout << "# of steps = " << vgndy->GetAvailableStepsCount()
+                  << std::endl;
     }
 
     // 1D decomposition of the columns, which is inefficient for reading!
@@ -104,21 +99,24 @@ int main(int argc, char *argv[])
     std::cout << "rank " << rank << " reads " << readsize[1]
               << " columns from offset " << offset[1] << std::endl;
 
-    adios2::Variable<double> *vT = bpReader->InquireVariable<double>("T");
+    adios2::Variable<double> *vT = bpReader.InquireVariable<double>("T");
 
-    double *T = new double[vT->m_AvailableSteps * readsize[0] * readsize[1]];
+    double *T =
+        new double[vT->GetAvailableStepsCount() * readsize[0] * readsize[1]];
 
     // Create a 2D selection for the subset
-    vT->SetSelection(offset, readsize);
-    vT->SetStepSelection(0, vT->m_AvailableSteps);
+    vT->SetSelection(adios2::Box<adios2::Dims>(offset, readsize));
+    vT->SetStepSelection(
+        adios2::Box<std::size_t>(0, vT->GetAvailableStepsCount()));
 
     // Arrays are read by scheduling one or more of them
     // and performing the reads at once
-    bpReader->ScheduleRead<double>(*vT, T);
-    bpReader->PerformReads(adios2::ReadMode::Blocking);
+    // bpReader->ScheduleRead<double>(*vT, T);
+    // bpReader->PerformReads(adios2::ReadMode::Blocking);
 
-    printData(T, readsize.data(), offset.data(), rank, vT->m_AvailableSteps);
-    bpReader->Close();
+    printData(T, readsize.data(), offset.data(), rank,
+              vT->GetAvailableStepsCount());
+    bpReader.Close();
     delete[] T;
     MPI_Finalize();
     return 0;
diff --git a/examples/heatTransfer/write/IO_adios2.cpp b/examples/heatTransfer/write/IO_adios2.cpp
index e795d5976ef61e74f0c7613c5b41b411f1bb50d5..c3d9a22e73e72140e1ae54f5a9ea40a62e53e0b0 100644
--- a/examples/heatTransfer/write/IO_adios2.cpp
+++ b/examples/heatTransfer/write/IO_adios2.cpp
@@ -23,7 +23,7 @@
 
 static int rank_saved;
 adios2::ADIOS *ad = nullptr;
-std::shared_ptr<adios2::Engine> bpWriter;
+adios2::Engine *bpWriter = nullptr;
 adios2::Variable<double> *varT = nullptr;
 adios2::Variable<unsigned int> *varGndx = nullptr;
 
@@ -65,12 +65,7 @@ IO::IO(const Settings &s, MPI_Comm comm)
     // varT.AddTransform( tr, "" );
     // varT.AddTransform( tr,"accuracy=0.001" );  // for ZFP
 
-    bpWriter = bpio.Open(m_outputfilename, adios2::OpenMode::Write, comm);
-
-    if (!bpWriter)
-    {
-        throw std::ios_base::failure("ERROR: failed to open ADIOS bpWriter\n");
-    }
+    bpWriter = &bpio.Open(m_outputfilename, adios2::Mode::Write, comm);
 }
 
 IO::~IO()
@@ -90,8 +85,8 @@ void IO::write(int step, const HeatTransfer &ht, const Settings &s,
     // Make a selection to describe the local dimensions of the variable we
     // write and its offsets in the global spaces. This could have been done in
     // adios.DefineVariable()
-    adios2::SelectionBoundingBox sel({s.offsx, s.offsy}, {s.ndx, s.ndy});
-    varT->SetSelection(sel);
+    varT->SetSelection(
+        adios2::Box<adios2::Dims>({s.offsx, s.offsy}, {s.ndx, s.ndy}));
 
     /* Select the area that we want to write from the data pointer we pass to
        the
@@ -104,9 +99,7 @@ void IO::write(int step, const HeatTransfer &ht, const Settings &s,
        above.
        Default memspace is always the full selection.
     */
-    adios2::SelectionBoundingBox memspace =
-        adios2::SelectionBoundingBox({1, 1}, {s.ndx, s.ndy});
-    varT->SetMemorySelection(memspace);
+    varT->SetMemorySelection(adios2::Box<adios2::Dims>({1, 1}, {s.ndx, s.ndy}));
 
     bpWriter->Write<unsigned int>(*varGndx, s.gndx);
     bpWriter->Write<unsigned int>("gndy", s.gndy);
diff --git a/examples/heatTransfer/write/IO_ph5_adios2.cpp b/examples/heatTransfer/write/IO_ph5_adios2.cpp
index e4ce15343f77fa9d6a9a0c0bacc6245c036747e7..b2d57eefd07223f7a3cebadd27afbc571c282f4f 100644
--- a/examples/heatTransfer/write/IO_ph5_adios2.cpp
+++ b/examples/heatTransfer/write/IO_ph5_adios2.cpp
@@ -55,7 +55,7 @@ IO::IO(const Settings &s, MPI_Comm comm)
     // varT.AddTransform( tr, "" );
     // varT.AddTransform( tr,"accuracy=0.001" );  // for ZFP
 
-    h5writer = h5io.Open(m_outputfilename, adios2::OpenMode::Write, comm);
+    h5writer = h5io.Open(m_outputfilename, adios2::Mode::Write, comm);
 
     if (h5writer == nullptr)
         throw std::ios_base::failure("ERROR: failed to open ADIOS h5writer\n");
diff --git a/examples/hello/adios1Writer/helloADIOS1Writer.cpp b/examples/hello/adios1Writer/helloADIOS1Writer.cpp
index aa4a075b3eab992899094967aba67c8a5bb52407..b2daad010d1d58d1599fa632ef22fa7db9a97087 100644
--- a/examples/hello/adios1Writer/helloADIOS1Writer.cpp
+++ b/examples/hello/adios1Writer/helloADIOS1Writer.cpp
@@ -51,7 +51,7 @@ int main(int argc, char *argv[])
 
         /** Engine derived class, spawned to start IO operations */
         auto adios1Writer =
-            adios1IO.Open("myVector.bp", adios2::OpenMode::Write);
+            adios1IO.Open("myVector.bp", adios2::Mode::Write);
 
         if (!adios1Writer)
         {
diff --git a/examples/hello/adios1Writer/helloADIOS1Writer_nompi.cpp b/examples/hello/adios1Writer/helloADIOS1Writer_nompi.cpp
index 72231d5dbb051e96b49a2febd2a87b80a91e3f59..269579613db21907825a94172bdf6abae9ea0c75 100644
--- a/examples/hello/adios1Writer/helloADIOS1Writer_nompi.cpp
+++ b/examples/hello/adios1Writer/helloADIOS1Writer_nompi.cpp
@@ -37,7 +37,7 @@ int main(int argc, char *argv[])
 
         /** Engine derived class, spawned to start IO operations */
         auto adios1Writer =
-            adios1IO.Open("myVector.bp", adios2::OpenMode::Write);
+            adios1IO.Open("myVector.bp", adios2::Mode::Write);
 
         if (!adios1Writer)
         {
diff --git a/examples/hello/bpAttributeWriter/helloBPAttributeWriter.cpp b/examples/hello/bpAttributeWriter/helloBPAttributeWriter.cpp
index 7061f1db3a7ffdc19c96bb5afe47e4c2f3c28288..896589f264c0c9c8de2dfa43f6ddce78e707e327 100644
--- a/examples/hello/bpAttributeWriter/helloBPAttributeWriter.cpp
+++ b/examples/hello/bpAttributeWriter/helloBPAttributeWriter.cpp
@@ -56,19 +56,14 @@ int main(int argc, char *argv[])
                                      myDoubles.size());
 
         /** Engine derived class, spawned to start IO operations */
-        auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write);
-
-        if (!bpWriter)
-        {
-            throw std::ios_base::failure(
-                "ERROR: bpWriter not created at Open\n");
-        }
+        adios2::Engine &bpWriter =
+            bpIO.Open("myVector.bp", adios2::Mode::Write);
 
         /** Write variable for buffering */
-        bpWriter->Write<float>(bpFloats, myFloats.data());
+        bpWriter.Write<float>(bpFloats, myFloats.data());
 
         /** Create bp file, engine becomes unreachable after this*/
-        bpWriter->Close();
+        bpWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/bpAttributeWriter/helloBPAttributeWriter_nompi.cpp b/examples/hello/bpAttributeWriter/helloBPAttributeWriter_nompi.cpp
index 850d907ea325fa9348c29c910c1b074030c36716..6587f5e21338572637e26b0826d25f54bf4ea5af 100644
--- a/examples/hello/bpAttributeWriter/helloBPAttributeWriter_nompi.cpp
+++ b/examples/hello/bpAttributeWriter/helloBPAttributeWriter_nompi.cpp
@@ -49,7 +49,8 @@ int main(int argc, char *argv[])
                                      myDoubles.size());
 
         /** Engine derived class, spawned to start IO operations */
-        auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write);
+        adios2::Engine &bpWriter =
+            bpIO.Open("myVector.bp", adios2::Mode::Write);
 
         if (!bpWriter)
         {
@@ -58,10 +59,10 @@ int main(int argc, char *argv[])
         }
 
         /** Write variable for buffering */
-        bpWriter->Write<float>(bpFloats, myFloats.data());
+        bpWriter.Write<float>(bpFloats, myFloats.data());
 
         /** Create bp file, engine becomes unreachable after this*/
-        bpWriter->Close();
+        bpWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/bpFlushWriter/helloBPFlushWriter.cpp b/examples/hello/bpFlushWriter/helloBPFlushWriter.cpp
index 9309811c7016a4df7aec82f052962c53fc6601a7..5c70b863e03e23721268c56218506b73af9c264c 100644
--- a/examples/hello/bpFlushWriter/helloBPFlushWriter.cpp
+++ b/examples/hello/bpFlushWriter/helloBPFlushWriter.cpp
@@ -50,24 +50,19 @@ int main(int argc, char *argv[])
             "bpFloats", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
 
         /** Engine derived class, spawned to start IO operations */
-        auto bpWriter = bpIO.Open("myVectorFlush.bp", adios2::OpenMode::Write);
-
-        if (!bpWriter)
-        {
-            throw std::ios_base::failure(
-                "ERROR: bpWriter not created at Open\n");
-        }
+        adios2::Engine &bpWriter =
+            bpIO.Open("myVectorFlush.bp", adios2::Mode::Write);
 
         for (unsigned int t = 0; t < 100; ++t)
         {
             /** values to time step */
             myFloats.assign(myFloats.size(), t);
             /** Write variable for buffering */
-            bpWriter->Write<float>(bpFloats, myFloats.data());
+            bpWriter.Write<float>(bpFloats, myFloats.data());
         }
 
         /** Create bp file, engine becomes unreachable after this*/
-        bpWriter->Close();
+        bpWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/bpFlushWriter/helloBPFlushWriter_nompi.cpp b/examples/hello/bpFlushWriter/helloBPFlushWriter_nompi.cpp
index 0a08af072a9e949079e48b2172e46c266368a1c1..02d47d2d8b00f162b8e8ee3626d9c945232aef24 100644
--- a/examples/hello/bpFlushWriter/helloBPFlushWriter_nompi.cpp
+++ b/examples/hello/bpFlushWriter/helloBPFlushWriter_nompi.cpp
@@ -36,19 +36,14 @@ int main(int argc, char *argv[])
             "bpFloats", {}, {}, {Nx}, adios2::ConstantDims);
 
         /** Engine derived class, spawned to start IO operations */
-        auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write);
-
-        if (!bpWriter)
-        {
-            throw std::ios_base::failure(
-                "ERROR: bpWriter not created at Open\n");
-        }
+        adios2::Engine &bpWriter =
+            bpIO.Open("myVector.bp", adios2::Mode::Write);
 
         /** Write variable for buffering */
-        bpWriter->Write<float>(bpFloats, myFloats.data());
+        bpWriter.Write<float>(bpFloats, myFloats.data());
 
         /** Create bp file, engine becomes unreachable after this*/
-        bpWriter->Close();
+        bpWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/bpReader/helloBPReader.cpp b/examples/hello/bpReader/helloBPReader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bd3b81368574e378e0fc2ee78359f58d7d0a050b
--- /dev/null
+++ b/examples/hello/bpReader/helloBPReader.cpp
@@ -0,0 +1,94 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * helloBPReader.cpp: Simple self-descriptive example of how to read a variable
+ * to a BP File.
+ *
+ *  Created on: Feb 16, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include <ios>      //std::ios_base::failure
+#include <iostream> //std::cout
+#include <mpi.h>
+#include <stdexcept> //std::invalid_argument std::exception
+#include <vector>
+
+#include <adios2.h>
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /** Application variable */
+    const std::size_t Nx = 10;
+    std::vector<float> myFloats(Nx);
+    std::vector<int> myInts(Nx);
+
+    try
+    {
+        /** ADIOS class factory of IO class objects, DebugON is 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("ReadBP");
+
+        /** Engine derived class, spawned to start IO operations */
+        auto bpReader = bpIO.Open("myVector.bp", adios2::Mode::Read);
+
+        if (!bpReader)
+        {
+            throw std::ios_base::failure(
+                "ERROR: bpWriter not created at Open\n");
+        }
+
+        /** Write variable for buffering */
+        adios2::Variable<float> *bpFloats =
+            bpReader->InquireVariable<float>("bpFloats");
+        adios2::Variable<int> *bpInts =
+            bpReader->InquireVariable<int>("bpInts");
+
+        /** Set selection */
+        adios2::Box
+
+            if (bpFloats != nullptr)
+        {
+            bpReader->Read<float>(*bpFloats, myFloats.data());
+        }
+
+        if (bpFloats != nullptr)
+        {
+            bpReader->Read<int>(*bpInts, myInts.data());
+        }
+
+        /** Create bp  file, engine becomes unreachable after this*/
+        bpReader->Close();
+    }
+    catch (std::invalid_argument &e)
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::ios_base::failure &e)
+    {
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n";
+        std::cout << e.what() << "\n";
+    }
+
+    MPI_Finalize();
+
+    return 0;
+}
diff --git a/examples/hello/bpTimeWriter/helloBPTimeWriter.cpp b/examples/hello/bpTimeWriter/helloBPTimeWriter.cpp
index 6404d2061861a3b6937b48cd25f5ff629aea2448..7c5228626b8ed47f93ad96b709444c45411783a1 100644
--- a/examples/hello/bpTimeWriter/helloBPTimeWriter.cpp
+++ b/examples/hello/bpTimeWriter/helloBPTimeWriter.cpp
@@ -49,29 +49,24 @@ int main(int argc, char *argv[])
             bpIO.DefineVariable<unsigned int>("timeStep");
 
         /** Engine derived class, spawned to start IO operations */
-        auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write);
-
-        if (!bpWriter)
-        {
-            throw std::ios_base::failure(
-                "ERROR: bpWriter not created at Open\n");
-        }
+        adios2::Engine &bpWriter =
+            bpIO.Open("myVector.bp", adios2::Mode::Write);
 
         for (unsigned int timeStep = 0; timeStep < 10; ++timeStep)
         {
             if (rank == 0) // global single value, only saved by rank 0
             {
-                bpWriter->Write<unsigned int>(bpTimeStep, timeStep);
+                bpWriter.Write<unsigned int>(bpTimeStep, timeStep);
             }
 
             myFloats[0] = timeStep;
 
             // template type is optional, but recommended
-            bpWriter->Write<float>(bpFloats, myFloats.data());
-            bpWriter->Advance();
+            bpWriter.Write<float>(bpFloats, myFloats.data());
+            bpWriter.Advance();
         }
 
-        bpWriter->Close();
+        bpWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/bpTimeWriter/helloBPTimeWriter_nompi.cpp b/examples/hello/bpTimeWriter/helloBPTimeWriter_nompi.cpp
index eb0007caccbc75b8b2b0754dd18f4b3cdddbc205..0b1a8d38f80447c1a4fcf71d1ae7e08227e3ff3c 100644
--- a/examples/hello/bpTimeWriter/helloBPTimeWriter_nompi.cpp
+++ b/examples/hello/bpTimeWriter/helloBPTimeWriter_nompi.cpp
@@ -39,7 +39,8 @@ int main(int argc, char *argv[])
             bpIO.DefineVariable<unsigned int>("timeStep");
 
         /** Engine derived class, spawned to start IO operations */
-        auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write);
+        adios2::Engine &bpWriter =
+            bpIO.Open("myVector.bp", adios2::Mode::Write);
 
         if (!bpWriter)
         {
@@ -50,14 +51,14 @@ int main(int argc, char *argv[])
         for (unsigned int timeStep = 0; timeStep < 10; ++timeStep)
         {
             // template type is optional but recommended
-            bpWriter->Write<unsigned int>(bpTimeStep, timeStep);
+            bpWriter.Write<unsigned int>(bpTimeStep, timeStep);
 
             myFloats[0] = timeStep;
-            bpWriter->Write<float>(bpFloats, myFloats.data());
-            bpWriter->Advance();
+            bpWriter.Write<float>(bpFloats, myFloats.data());
+            bpWriter.Advance();
         }
 
-        bpWriter->Close();
+        bpWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/bpWriter/helloBPWriter.cpp b/examples/hello/bpWriter/helloBPWriter.cpp
index e2ff7da7ecc4b2cb1353202e0ab85a6e1bf437e2..d394152500006b9abd36a9e63716baaa56087f57 100644
--- a/examples/hello/bpWriter/helloBPWriter.cpp
+++ b/examples/hello/bpWriter/helloBPWriter.cpp
@@ -26,6 +26,7 @@ int main(int argc, char *argv[])
 
     /** Application variable */
     std::vector<float> myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    std::vector<int> myInts = {0, -1, -2, -3, -4, -5, -6, -7, -8, -9};
     const std::size_t Nx = myFloats.size();
 
     try
@@ -36,26 +37,27 @@ int main(int argc, char *argv[])
         /*** 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) }, { start (local) }, { count
+        /** global array : name, { shape (total) }, { start (local) }, {
+         * count
          * (local) }, all are constant dimensions */
         adios2::Variable<float> &bpFloats = bpIO.DefineVariable<float>(
             "bpFloats", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
 
-        /** Engine derived class, spawned to start IO operations */
-        auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write);
+        adios2::Variable<int> &bpInts = bpIO.DefineVariable<int>(
+            "bpInts", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
 
-        if (!bpWriter)
-        {
-            throw std::ios_base::failure(
-                "ERROR: bpWriter not created at Open\n");
-        }
+        /** Engine derived class, spawned to start IO operations */
+        adios2::Engine &bpWriter =
+            bpIO.Open("myVector.bp", adios2::Mode::Write);
 
         /** Write variable for buffering */
-        bpWriter->Write<float>(bpFloats, myFloats.data());
+        bpWriter.Write<float>(bpFloats, myFloats.data());
+        bpWriter.Write<int>(bpInts, myInts.data());
 
         /** Create bp file, engine becomes unreachable after this*/
-        bpWriter->Close();
+        bpWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
@@ -65,9 +67,9 @@ int main(int argc, char *argv[])
     }
     catch (std::ios_base::failure &e)
     {
-        std::cout
-            << "IO System base failure exception, STOPPING PROGRAM from rank "
-            << rank << "\n";
+        std::cout << "IO System base failure exception, STOPPING PROGRAM "
+                     "from rank "
+                  << rank << "\n";
         std::cout << e.what() << "\n";
     }
     catch (std::exception &e)
diff --git a/examples/hello/bpWriter/helloBPWriter.py b/examples/hello/bpWriter/helloBPWriter.py
index 7332f5e7333b159d00187035f4d3911c239a3f53..2e430ef423b7a25783de8e15455ee87b32b70596 100644
--- a/examples/hello/bpWriter/helloBPWriter.py
+++ b/examples/hello/bpWriter/helloBPWriter.py
@@ -16,7 +16,7 @@ rank = comm.Get_rank()
 size = comm.Get_size()
 
 # User data
-myArray = numpy.array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
+myArray = numpy.array([0, 1., 2., 3., 4., 5., 6., 7., 8., 9.])
 Nx = myArray.size
 
 # ADIOS MPI Communicator, debug mode
@@ -31,5 +31,6 @@ ioArray = bpIO.DefineVariable(
 
 # ADIOS Engine
 bpFileWriter = bpIO.Open("npArray.bp", adios2.OpenModeWrite)
+# doesn't work: bpFileWriter = bpIO.Open("npArray.bp", adios2.OpenModeWrite, newcomm)
 bpFileWriter.Write(ioArray, myArray)
 bpFileWriter.Close()
diff --git a/examples/hello/bpWriter/helloBPWriter_nompi.cpp b/examples/hello/bpWriter/helloBPWriter_nompi.cpp
index 0a08af072a9e949079e48b2172e46c266368a1c1..02d47d2d8b00f162b8e8ee3626d9c945232aef24 100644
--- a/examples/hello/bpWriter/helloBPWriter_nompi.cpp
+++ b/examples/hello/bpWriter/helloBPWriter_nompi.cpp
@@ -36,19 +36,14 @@ int main(int argc, char *argv[])
             "bpFloats", {}, {}, {Nx}, adios2::ConstantDims);
 
         /** Engine derived class, spawned to start IO operations */
-        auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write);
-
-        if (!bpWriter)
-        {
-            throw std::ios_base::failure(
-                "ERROR: bpWriter not created at Open\n");
-        }
+        adios2::Engine &bpWriter =
+            bpIO.Open("myVector.bp", adios2::Mode::Write);
 
         /** Write variable for buffering */
-        bpWriter->Write<float>(bpFloats, myFloats.data());
+        bpWriter.Write<float>(bpFloats, myFloats.data());
 
         /** Create bp file, engine becomes unreachable after this*/
-        bpWriter->Close();
+        bpWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/datamanReader/helloDataManReader.cpp b/examples/hello/datamanReader/helloDataManReader.cpp
index 89f3e8472f3bca26141747913b7c0c1cdb18e6a9..cec8ccebb7fbb4c1f91b334baf3e52f73dd32f90 100644
--- a/examples/hello/datamanReader/helloDataManReader.cpp
+++ b/examples/hello/datamanReader/helloDataManReader.cpp
@@ -49,16 +49,10 @@ int main(int argc, char *argv[])
                                  {"method_type", "stream"},
                                  {"method", "dump"}});
 
-        auto dataManReader =
-            dataManIO.Open("myDoubles.bp", adios2::OpenMode::Read);
+        adios2::Engine &dataManReader =
+            dataManIO.Open("myDoubles.bp", adios2::Mode::Read);
 
-        if (!dataManReader)
-        {
-            throw std::ios_base::failure(
-                "ERROR: failed to create DataMan I/O engine at Open\n");
-        }
-
-        dataManReader->SetCallBack(UserCallBack);
+        dataManReader.SetCallBack(UserCallBack);
 
         for (unsigned int i = 0; i < 3; ++i)
         {
@@ -66,14 +60,14 @@ int main(int argc, char *argv[])
         }
 
         adios2::Variable<double> *ioMyDoubles =
-            dataManReader->InquireVariable<double>("ioMyDoubles");
+            dataManReader.InquireVariable<double>("ioMyDoubles");
 
         if (ioMyDoubles == nullptr)
         {
             std::cout << "Variable ioMyDoubles not read...yet\n";
         }
 
-        dataManReader->Close();
+        dataManReader.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/datamanReader/helloDataManReader_nompi.cpp b/examples/hello/datamanReader/helloDataManReader_nompi.cpp
index c4516296031171f4cbde6c794a5104fcd5a7c65b..0e66cd99d396201941f5008152c79aa67c4f6403 100644
--- a/examples/hello/datamanReader/helloDataManReader_nompi.cpp
+++ b/examples/hello/datamanReader/helloDataManReader_nompi.cpp
@@ -44,7 +44,7 @@ int main(int argc, char *argv[])
                                  {"method_type", "stream"},
                                  {"method", "dump"}});
         auto dataManReader =
-            dataManIO.Open("myDoubles.bp", adios2::OpenMode::Read);
+            dataManIO.Open("myDoubles.bp", adios2::Mode::Read);
 
         if (!dataManReader)
         {
diff --git a/examples/hello/datamanWriter/helloDataManWriter.cpp b/examples/hello/datamanWriter/helloDataManWriter.cpp
index b22b90a5e0fa0019e666b4ecd12c3e12377dbea8..3b0a28ace10e89cc7ddb8619171068233cda0368 100644
--- a/examples/hello/datamanWriter/helloDataManWriter.cpp
+++ b/examples/hello/datamanWriter/helloDataManWriter.cpp
@@ -42,17 +42,11 @@ int main(int argc, char *argv[])
 
         // Create engine smart pointer to DataMan Engine due to polymorphism,
         // Open returns a smart pointer to Engine containing the Derived class
-        auto dataManWriter =
-            dataManIO.Open("myFloats.bp", adios2::OpenMode::Write);
+        adios2::Engine &dataManWriter =
+            dataManIO.Open("myFloats.bp", adios2::Mode::Write);
 
-        if (!dataManWriter)
-        {
-            throw std::ios_base::failure(
-                "ERROR: failed to create DataMan I/O engine at Open\n");
-        }
-
-        dataManWriter->Write<float>(bpFloats, myFloats.data());
-        dataManWriter->Close();
+        dataManWriter.Write<float>(bpFloats, myFloats.data());
+        dataManWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/datamanWriter/helloDataManWriter_nompi.cpp b/examples/hello/datamanWriter/helloDataManWriter_nompi.cpp
index 65c0ce4e87352b3110b908e3dd02099778f663a6..61f9f5bfb1c21032d845da86b611f0c1e08642ce 100644
--- a/examples/hello/datamanWriter/helloDataManWriter_nompi.cpp
+++ b/examples/hello/datamanWriter/helloDataManWriter_nompi.cpp
@@ -35,17 +35,11 @@ int main(int argc, char *argv[])
 
         // Create engine smart pointer to DataMan Engine due to polymorphism,
         // Open returns a smart pointer to Engine containing the Derived class
-        auto dataManWriter =
-            dataManIO.Open("myFloats.bp", adios2::OpenMode::Write);
+        adios2::Engine &dataManWriter =
+            dataManIO.Open("myFloats.bp", adios2::Mode::Write);
 
-        if (!dataManWriter)
-        {
-            throw std::ios_base::failure(
-                "ERROR: failed to create DataMan I/O engine at Open\n");
-        }
-
-        dataManWriter->Write<float>(bpFloats, myFloats.data());
-        dataManWriter->Close();
+        dataManWriter.Write<float>(bpFloats, myFloats.data());
+        dataManWriter.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/hdf5Writer/helloHDF5Writer.cpp b/examples/hello/hdf5Writer/helloHDF5Writer.cpp
index f67e27c10a7a8c6c49d7f64a80c35cb638a942fc..06cbcf57dde83d955c07eb93da0b74b472bea5e7 100644
--- a/examples/hello/hdf5Writer/helloHDF5Writer.cpp
+++ b/examples/hello/hdf5Writer/helloHDF5Writer.cpp
@@ -45,7 +45,8 @@ int main(int argc, char *argv[])
             "bpFloats", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims);
 
         /** Engine derived class, spawned to start IO operations */
-        auto hdf5Writer = hdf5IO.Open("myVector.h5", adios2::OpenMode::Write);
+        adios2::Engine &hdf5Writer =
+            hdf5IO.Open("myVector.h5", adios2::Mode::Write);
 
         if (!hdf5Writer)
         {
@@ -54,10 +55,10 @@ int main(int argc, char *argv[])
         }
 
         /** Write variable for buffering */
-        hdf5Writer->Write<float>(bpFloats, myFloats.data());
+        hdf5Writer.Write<float>(bpFloats, myFloats.data());
 
         /** Create bp file, engine becomes unreachable after this*/
-        hdf5Writer->Close();
+        hdf5Writer.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/hello/hdf5Writer/helloHDF5Writer_nompi.cpp b/examples/hello/hdf5Writer/helloHDF5Writer_nompi.cpp
index 1890da58acad3c2cbaca23d823669f404bd1267e..44f428bfefb52f04d500fad05dfb9cf7ecc84b5d 100644
--- a/examples/hello/hdf5Writer/helloHDF5Writer_nompi.cpp
+++ b/examples/hello/hdf5Writer/helloHDF5Writer_nompi.cpp
@@ -38,19 +38,14 @@ int main(int argc, char *argv[])
             "bpFloats", {}, {}, {Nx}, adios2::ConstantDims);
 
         /** Engine derived class, spawned to start IO operations */
-        auto hdf5Writer = hdf5IO.Open("myVector.h5", adios2::OpenMode::Write);
-
-        if (!hdf5Writer)
-        {
-            throw std::ios_base::failure(
-                "ERROR: hdf5Writer not created at Open\n");
-        }
+        adios2::Engine &hdf5Writer =
+            hdf5IO.Open("myVector.h5", adios2::Mode::Write);
 
         /** Write variable for buffering */
-        hdf5Writer->Write<float>(bpFloats, myFloats.data());
+        hdf5Writer.Write<float>(bpFloats, myFloats.data());
 
         /** Create bp file, engine becomes unreachable after this*/
-        hdf5Writer->Close();
+        hdf5Writer.Close();
     }
     catch (std::invalid_argument &e)
     {
diff --git a/examples/plugins/CMakeLists.txt b/examples/plugins/CMakeLists.txt
index bd9914576866a2c9a4c1c4a6d7766e3d65acde19..e19355773a92d099fe98eb57e584169d1cd024b2 100644
--- a/examples/plugins/CMakeLists.txt
+++ b/examples/plugins/CMakeLists.txt
@@ -1 +1 @@
-add_subdirectory(engine)
+#add_subdirectory(engine)
diff --git a/examples/plugins/engine/ExampleEnginePlugin.cpp b/examples/plugins/engine/ExampleEnginePlugin.cpp
index 09d55a509900e074eccb0df05b258f9b52dee8ba..01d12372720e92bfce88e806274d28301da6408e 100644
--- a/examples/plugins/engine/ExampleEnginePlugin.cpp
+++ b/examples/plugins/engine/ExampleEnginePlugin.cpp
@@ -54,7 +54,7 @@ namespace adios2
 {
 
 ExampleEnginePlugin::ExampleEnginePlugin(IO &io, const std::string &name,
-                                         const OpenMode openMode,
+                                         const Mode openMode,
                                          MPI_Comm mpiComm)
 : adios2::PluginEngineInterface(io, name, openMode, mpiComm)
 {
diff --git a/examples/plugins/engine/ExampleEnginePlugin.h b/examples/plugins/engine/ExampleEnginePlugin.h
index aa81d0a1aa1c9e906d0dcaeb4ca91a7ab710e446..5cbd653f4034714e71812bd9bf6aca1692ba1eae 100644
--- a/examples/plugins/engine/ExampleEnginePlugin.h
+++ b/examples/plugins/engine/ExampleEnginePlugin.h
@@ -29,7 +29,7 @@ class ExampleEnginePlugin : public PluginEngineInterface
 {
 public:
     ExampleEnginePlugin(IO &io, const std::string &name,
-                        const OpenMode openMode, MPI_Comm mpiComm);
+                        const Mode openMode, MPI_Comm mpiComm);
     virtual ~ExampleEnginePlugin();
 
     void Close(const int transportIndex = -1) override;
diff --git a/examples/plugins/engine/examplePluginEngine_class.cpp b/examples/plugins/engine/examplePluginEngine_class.cpp
index e8a65905dd72e905b3284e07c3f3919558fb1a73..e09a9a137e76edb37bddf84e9be0288e1a187801 100644
--- a/examples/plugins/engine/examplePluginEngine_class.cpp
+++ b/examples/plugins/engine/examplePluginEngine_class.cpp
@@ -44,7 +44,7 @@ int main(int argc, char *argv[])
         /** Engine derived class, spawned to start IO operations */
         io.SetEngine("PluginEngine");
         io.SetParameters({{"PluginName", "MyPlugin"}});
-        auto writer = io.Open("TestPlugin", adios2::OpenMode::Write);
+        auto writer = io.Open("TestPlugin", adios2::Mode::Write);
 
         if (!writer)
         {
diff --git a/source/adios2.h b/source/adios2.h
index 035df18888de4b63ebba0879f6c3783c10de971e..a3492f8d7f0a4372c724152490727e88f2df37c0 100644
--- a/source/adios2.h
+++ b/source/adios2.h
@@ -12,8 +12,6 @@
 #include "adios2/core/ADIOS.h"
 #include "adios2/core/Engine.h"
 #include "adios2/core/IO.h"
-#include "adios2/core/SelectionBoundingBox.h"
-#include "adios2/core/SelectionPoints.h"
 #include "adios2/core/Transform.h"
 
 #endif /* ADIOS2_H_ */
diff --git a/source/adios2/ADIOSMacros.h b/source/adios2/ADIOSMacros.h
index 1f01f9ea600594a77b764181b90a504aa3fd4174..d0bb9cbc67d570c7daf506782c0f6294764a9153 100644
--- a/source/adios2/ADIOSMacros.h
+++ b/source/adios2/ADIOSMacros.h
@@ -2,28 +2,35 @@
  * Distributed under the OSI-approved Apache License, Version 2.0.  See
  * accompanying file Copyright.txt for details.
  *
- * ADIOSMacros.h
- *   This contains a set of helper macros used internally
+ * ADIOSMacros.h : a set of helper macros used internally
+ *
+ * Created on: March 23, 2017
+ *     Author: Chuck Atkins chuck.atkins@kitware.com
  */
+
 #ifndef ADIOS2_ADIOSMACROS_H
 #define ADIOS2_ADIOSMACROS_H
 
 #include <string>
 
 #include "adios2/ADIOSTypes.h"
-// The ADIOS_FOREACH_TYPE_1ARG macro assumes the given argument is a macro which
-// takes a single argument that is a type and then inserts the given MACRO for
-// each of the known primitive types
-//
-// An example of this might be to instantiate a template function for each
-// known type.  For example:
-//
-//   template<typename T> int foo() { /* some implementation of foo */ }
-//
-//   #define instantiate_foo(T) template int foo<T>();
-//   ADIOS_FOREACH_TYPE_1ARG(instantiate_foo)
-//   #undef instantiate_foo
-//
+
+/**
+ <pre>
+ The ADIOS_FOREACH_TYPE_1ARG macro assumes the given argument is a macro which
+ takes a single argument that is a type and then inserts the given MACRO for
+ each of the known primitive types
+
+ An example of this might be to instantiate a template function for each
+ known type.  For example:
+
+   template<typename T> int foo() { // some implementation of foo  }
+
+   #define instantiate_foo(T) template int foo<T>();
+   ADIOS_FOREACH_TYPE_1ARG(instantiate_foo)
+   #undef instantiate_foo
+ </pre>
+*/
 #define ADIOS2_FOREACH_TYPE_1ARG(MACRO)                                        \
     MACRO(char)                                                                \
     MACRO(signed char)                                                         \
@@ -60,7 +67,8 @@
 
 #define ADIOS2_FOREACH_COMPLEX_TYPE_1ARG(MACRO)                                \
     MACRO(float)                                                               \
-    MACRO(double)
+    MACRO(double)                                                              \
+    MACRO(long double)
 
 #define ADIOS2_FOREACH_ZFP_TYPE_1ARG(MACRO)                                    \
     MACRO(int32_t)                                                             \
@@ -85,29 +93,33 @@
     MACRO(double)                                                              \
     MACRO(long double)
 
-// The ADIOS_FOREACH_TYPE_2ARGS macro assumes the given argument is a macro
-// which takes two arguments, the first being a type, and the second being a
-// label for that type, i.e. std::complex<float> and CFloat.
-//
-// An example of this might be to define a virtual method for each known
-// type, and since the method is virtual then it cannot be a template.
-// For example:
-//
-//   #define declare_foo(T,L) virtual const T& foo ## L (std::string bar);
-//   ADIOS_FOREACH_TYPE_2ARGS(declare_foo)
-//   #undef declare_foo
-//
-//   is equivalent to:
-//
-//   virtual           char& foo_Char(std::string bar);
-//   virtual unsigned  char& foo_UChar(std::string bar);
-//   virtual          short& foo_Short(std::string bar);
-//   virtual unsigned short& foo_UShort(std::string bar);
-//   ...
-//   virtual std::complex<long double>& foo_CLDouble(std::string bar);
-//
+/**
+ <pre>
+ The ADIOS_FOREACH_TYPE_2ARGS macro assumes the given argument is a macro
+ which takes two arguments, the first being a type, and the second being a
+ label for that type, i.e. std::complex<float> and CFloat.
+
+ An example of this might be to define a virtual method for each known
+ type, and since the method is virtual then it cannot be a template.
+ For example:
+
+   #define declare_foo(T,L) virtual const T& foo ## L (std::string bar);
+   ADIOS_FOREACH_TYPE_2ARGS(declare_foo)
+   #undef declare_foo
+
+   is equivalent to:
+
+   virtual           char& foo_Char(std::string bar);
+   virtual unsigned  char& foo_UChar(std::string bar);
+   virtual          short& foo_Short(std::string bar);
+   virtual unsigned short& foo_UShort(std::string bar);
+   ...
+   virtual std::complex<long double>& foo_CLDouble(std::string bar);
+  </pre>
+*/
 #define ADIOS2_FOREACH_TYPE_2ARGS(MACRO)                                       \
     MACRO(char, Char)                                                          \
+    MACRO(signed char, SChar)                                                  \
     MACRO(unsigned char, UChar)                                                \
     MACRO(short, Short)                                                        \
     MACRO(unsigned short, UShort)                                              \
@@ -126,6 +138,7 @@
 
 #define ADIOS2_FOREACH_PRIMITIVE_TYPE_2ARGS(MACRO)                             \
     MACRO(char, Char)                                                          \
+    MACRO(signed char, Char)                                                   \
     MACRO(unsigned char, UChar)                                                \
     MACRO(short, Short)                                                        \
     MACRO(unsigned short, UShort)                                              \
@@ -136,10 +149,12 @@
     MACRO(unsigned long int, ULInt)                                            \
     MACRO(unsigned long long int, ULLInt)                                      \
     MACRO(float, Float)                                                        \
-    MACRO(double, Double)
+    MACRO(double, Double)                                                      \
+    MACRO(long double, LDouble)
 
 #define ADIOS2_FOREACH_COMPLEX_TYPE_2ARGS(MACRO)                               \
     MACRO(std::complex<float>, CFloat)                                         \
-    MACRO(std::complex<double>, CDouble)
+    MACRO(std::complex<double>, CDouble)                                       \
+    MACRO(std::complex<long double>, CLDouble)
 
 #endif /* ADIOS2_ADIOSMACROS_H */
diff --git a/source/adios2/ADIOSTypes.h b/source/adios2/ADIOSTypes.h
index 0078b66b855ec5728cae3e43ad883c0d27fa1ddb..d05948c15d33848609a7d58d627b56bc8d853ebf 100644
--- a/source/adios2/ADIOSTypes.h
+++ b/source/adios2/ADIOSTypes.h
@@ -9,7 +9,6 @@
  *      Author: Chuck Atkins chuck.atkins@kitware.com
  *              Norbert Podhorszki pnorbert@ornl.gov
  *              William F Godoy godoywf@ornl.gov
- *
  */
 
 #ifndef ADIOS2_ADIOSTYPES_H_
@@ -24,6 +23,7 @@
 #include <map>
 #include <string>
 #include <type_traits>
+#include <utility> //std::pair
 #include <vector>
 /// \endcond
 
@@ -51,13 +51,14 @@ enum class IOMode
 };
 
 /** OpenMode in IO Open */
-enum class OpenMode
+enum class Mode
 {
     Undefined,
     Write,
     Read,
     Append,
-    ReadWrite,
+
+    Deferred
 };
 
 enum class ReadMultiplexPattern
@@ -134,14 +135,35 @@ enum class TimeUnit
 /** Type of selection */
 enum class SelectionType
 {
-    BoundingBox, ///< Contiguous block of data defined by offsets and counts per
-                 /// dimension
+    BoundingBox, ///< Contiguous block of data defined by offsets and counts
+                 /// per dimension
     Points,      ///< List of individual points
     WriteBlock,  ///< Selection of an individual block written by a writer
                  /// process
     Auto         ///< Let the engine decide what to return
 };
 
+// Types
+using std::size_t;
+
+using std::int8_t;
+using std::int16_t;
+using std::int32_t;
+using std::int64_t;
+
+using std::uint8_t;
+using std::uint16_t;
+using std::uint32_t;
+using std::uint64_t;
+
+// Complex
+using cfloat = std::complex<float>;
+using cdouble = std::complex<double>;
+using cldouble = std::complex<long double>;
+
+// Limit
+constexpr size_t MaxSizeT = std::numeric_limits<size_t>::max();
+
 // adios defaults
 #ifdef _WIN32
 const std::string DefaultFileLibrary("fstream");
@@ -152,19 +174,19 @@ const std::string DefaultTimeUnit("Microseconds");
 constexpr TimeUnit DefaultTimeUnitEnum(TimeUnit::Microseconds);
 
 /** default initial bp buffer size, 16Kb, in bytes */
-constexpr size_t DefaultInitialBufferSize(16 * 1024);
+constexpr size_t DefaultInitialBufferSize = 16 * 1024;
 
 /** default maximum bp buffer size, unlimited, in bytes.
  *  Needs to be studied for optimizing applications */
-constexpr size_t DefaultMaxBufferSize(std::numeric_limits<size_t>::max() - 1);
+constexpr size_t DefaultMaxBufferSize = MaxSizeT - 1;
 
 /** default buffer growth factor. Needs to be studied
  * for optimizing applications*/
-constexpr float DefaultBufferGrowthFactor(1.05f);
+constexpr float DefaultBufferGrowthFactor = 1.05f;
 
 /** default size for writing/reading files using POSIX/fstream/stdio write
  *  2Gb - 100Kb (tolerance)*/
-constexpr size_t DefaultMaxFileBatchSize(2147381248);
+constexpr size_t DefaultMaxFileBatchSize = 2147381248;
 
 constexpr char PathSeparator =
 #ifdef _WIN32
@@ -177,34 +199,17 @@ constexpr char PathSeparator =
 constexpr bool DebugON = true;
 constexpr bool DebugOFF = false;
 constexpr size_t UnknownDim = 0;
-constexpr size_t JoinedDim = std::numeric_limits<size_t>::max() - 1;
-constexpr size_t LocalValueDim = std::numeric_limits<size_t>::max() - 2;
-constexpr size_t IrregularDim = std::numeric_limits<size_t>::max() - 3;
+constexpr size_t JoinedDim = MaxSizeT - 1;
+constexpr size_t LocalValueDim = MaxSizeT - 2;
+constexpr size_t IrregularDim = MaxSizeT - 3;
 constexpr bool ConstantDims = true;
-constexpr bool ReadIn = true;
-
-using std::size_t;
 
 using Dims = std::vector<size_t>;
 using Params = std::map<std::string, std::string>;
+using Steps = size_t;
 
-// Primitives
-// using schar = signed char;
-using std::int8_t;
-using std::int16_t;
-using std::int32_t;
-using std::int64_t;
-
-// using uchar = unsigned char;
-using std::uint8_t;
-using std::uint16_t;
-using std::uint32_t;
-using std::uint64_t;
-
-// Complex
-using cfloat = std::complex<float>;
-using cdouble = std::complex<double>;
-using cldouble = std::complex<long double>;
+template <class T>
+using Box = std::pair<T, T>;
 
 // Get a fixed width integer type from a size specification
 template <size_t Bytes, bool Signed>
@@ -279,6 +284,6 @@ struct TypeInfo<T, typename std::enable_if<std::is_same<
     using ValueType = typename T::value_type;
 };
 
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_ADIOSTYPES_H_ */
diff --git a/source/adios2/CMakeLists.txt b/source/adios2/CMakeLists.txt
index 5cca920095ce3fcb6c74e737182a4590a58d50b9..9d9e03b68ade5abd9ca5dc9d4910251721254476 100644
--- a/source/adios2/CMakeLists.txt
+++ b/source/adios2/CMakeLists.txt
@@ -9,9 +9,6 @@ add_library(adios2
   core/ADIOS.cpp
   core/Engine.cpp
   core/IO.cpp core/IO.tcc
-  core/Selection.cpp
-  core/SelectionBoundingBox.cpp
-  core/SelectionPoints.cpp
   core/Transform.cpp core/Transform.tcc
   core/Variable.cpp core/Variable.tcc
   core/VariableBase.cpp
@@ -26,25 +23,25 @@ add_library(adios2
   helper/adiosType.cpp
   helper/adiosXML.cpp
   
-#  engine/bp/BPFileReader.cpp
+  engine/bp/BPFileReader.cpp engine/bp/BPFileReader.tcc
   engine/bp/BPFileWriter.cpp engine/bp/BPFileWriter.tcc
 
-  engine/plugin/PluginEngine.h engine/plugin/PluginEngine.inl
-  engine/plugin/PluginEngine.cpp
-  engine/plugin/PluginEngineInterface.h engine/plugin/PluginEngineInterface.cpp
+#  engine/plugin/PluginEngine.h engine/plugin/PluginEngine.inl
+#  engine/plugin/PluginEngine.cpp
+#  engine/plugin/PluginEngineInterface.h engine/plugin/PluginEngineInterface.cpp
 
-  toolkit/capsule/Capsule.cpp
-  toolkit/capsule/heap/STLVector.cpp 
- 
+  toolkit/format/BufferSTL.cpp
+  
   toolkit/format/bp1/BP1Base.cpp toolkit/format/bp1/BP1Base.tcc
   toolkit/format/bp1/BP1Aggregator.cpp
   toolkit/format/bp1/BP1Writer.cpp toolkit/format/bp1/BP1Writer.tcc
+  toolkit/format/bp1/BP1Reader.cpp toolkit/format/bp1/BP1Reader.tcc
 
   toolkit/profiling/iochrono/Timer.cpp
 
   toolkit/transport/Transport.cpp
-  toolkit/transport/file/FilePointer.cpp
-  toolkit/transport/file/FileStream.cpp
+  toolkit/transport/file/FileStdio.cpp
+  toolkit/transport/file/FileFStream.cpp
   
   toolkit/transportman/TransportMan.cpp
   
@@ -59,11 +56,11 @@ target_link_libraries(adios2 PRIVATE adios2sys pugixml)
 target_link_libraries(adios2 PUBLIC ${CMAKE_THREAD_LIBS_INIT})
 
 if(UNIX)
-  target_sources(adios2 PRIVATE toolkit/transport/file/FileDescriptor.cpp)
+  target_sources(adios2 PRIVATE toolkit/transport/file/FilePOSIX.cpp)
 endif()
 
 if(ADIOS2_HAVE_SysVShMem)
-  target_sources(adios2 PRIVATE toolkit/capsule/shmem/ShmSystemV.cpp)
+  target_sources(adios2 PRIVATE toolkit/transport/shm/ShmSystemV.cpp)
 endif()
 
 if(ADIOS2_HAVE_DataMan)
diff --git a/source/adios2/core/ADIOS.cpp b/source/adios2/core/ADIOS.cpp
index d4853c603d064962abc543a8caa94dfc36a01643..fadeb893a2276d8b99453d777eed95ea0e8c60c0 100644
--- a/source/adios2/core/ADIOS.cpp
+++ b/source/adios2/core/ADIOS.cpp
@@ -158,4 +158,4 @@ void ADIOS::CheckMPI() const
     }
 }
 
-} // end namespace adios
+} // end namespace adios2
diff --git a/source/adios2/core/ADIOS.h b/source/adios2/core/ADIOS.h
index eba4e72430fa5b313253fb1fc8793c0f0adeef29..0a10b8f568bb0cb33cc169cfbb66bba94bbc422e 100644
--- a/source/adios2/core/ADIOS.h
+++ b/source/adios2/core/ADIOS.h
@@ -123,6 +123,6 @@ private:
     void CheckMPI() const;
 };
 
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_ADIOS_H_ */
diff --git a/source/adios2/core/Engine.cpp b/source/adios2/core/Engine.cpp
index 9d19e892b7d357e35e1bbe3ef2de05ff4377df5c..8915ba5a73cb11dfd4b068a96c0e52def6907fc5 100644
--- a/source/adios2/core/Engine.cpp
+++ b/source/adios2/core/Engine.cpp
@@ -22,7 +22,7 @@ namespace adios2
 {
 
 Engine::Engine(const std::string engineType, IO &io, const std::string &name,
-               const OpenMode openMode, MPI_Comm mpiComm)
+               const Mode openMode, MPI_Comm mpiComm)
 : m_EngineType(engineType), m_IO(io), m_Name(name), m_OpenMode(openMode),
   m_MPIComm(mpiComm), m_DebugMode(io.m_DebugMode)
 {
@@ -47,10 +47,11 @@ void Engine::Write(const std::string &variableName, const void *values)
 
 void Engine::Advance(const float /*timeout_sec*/) {}
 void Engine::Advance(const AdvanceMode /*mode*/, const float /*timeout_sec*/) {}
-void Engine::AdvanceAsync(
-    AdvanceMode /*mode*/,
+std::future<void> Engine::AdvanceAsync(
+    AdvanceMode mode,
     std::function<void(std::shared_ptr<adios2::Engine>)> /*callback*/)
 {
+    return std::future<void>();
 }
 
 AdvanceStatus Engine::GetAdvanceStatus() { return m_AdvanceStatus; }
@@ -59,7 +60,6 @@ void Engine::Close(const int /*transportIndex*/) {}
 
 // READ
 void Engine::Release() {}
-void Engine::PerformReads(ReadMode /*mode*/){};
 
 // PROTECTED
 void Engine::Init() {}
@@ -78,7 +78,8 @@ ADIOS2_FOREACH_TYPE_1ARG(declare_type)
 #undef declare_type
 
 void Engine::DoWrite(VariableCompound &variable, const void *values)
-{ // TODO
+{
+    ThrowUp("Write Compound");
 }
 
 void Engine::DoWrite(const std::string &variableName, const void *values)
@@ -123,34 +124,30 @@ void Engine::DoWrite(const std::string &variableName, const void *values)
 } // end DoWrite
 
 // READ
-VariableBase *Engine::InquireVariableUnknown(const std::string &name,
-                                             const bool readIn)
-{
-    return nullptr;
-}
-
-#define define(T, L)                                                           \
-    Variable<T> *Engine::InquireVariable##L(const std::string &name,           \
-                                            const bool readIn)                 \
+#define declare(T, L)                                                          \
+    Variable<T> *Engine::DoInquireVariable##L(                                 \
+        const std::string & /*variableName*/)                                  \
     {                                                                          \
+        ThrowUp("DoInquireVariable");                                          \
         return nullptr;                                                        \
     }
-ADIOS2_FOREACH_TYPE_2ARGS(define)
-#undef define
 
-#define declare_type(T)                                                        \
-    void Engine::DoScheduleRead(Variable<T> &variable, const T *values)        \
-    {                                                                          \
-        ThrowUp("ScheduleRead");                                               \
-    }                                                                          \
-                                                                               \
-    void Engine::DoScheduleRead(const std::string &variableName,               \
-                                const T *values)                               \
-    {                                                                          \
-        ThrowUp("ScheduleRead");                                               \
-    }
-ADIOS2_FOREACH_TYPE_1ARG(declare_type)
-#undef declare_type
+ADIOS2_FOREACH_TYPE_2ARGS(declare)
+#undef declare
+
+void Engine::Flush(const int transportIndex) {}
+
+void Engine::Get(const int transportIndex) {}
+
+std::future<void> Engine::FlushAsync(const int transportIndex)
+{
+    return std::future<void>();
+}
+
+std::future<void> Engine::GetAsync(const int transportIndex)
+{
+    return std::future<void>();
+}
 
 // PRIVATE
 void Engine::ThrowUp(const std::string function) const
diff --git a/source/adios2/core/Engine.h b/source/adios2/core/Engine.h
index 3a405452f07e5dd2c381d3e6884eb0974900f5ec..a55e45e07a0c53aef8c033194920f475b266e823 100644
--- a/source/adios2/core/Engine.h
+++ b/source/adios2/core/Engine.h
@@ -16,6 +16,7 @@
 
 /// \cond EXCLUDE_FROM_DOXYGEN
 #include <functional> //std::function
+#include <future>
 #include <map>
 #include <memory> //std::shared_ptr
 #include <set>
@@ -25,6 +26,7 @@
 
 #include "adios2/ADIOSConfig.h"
 #include "adios2/ADIOSMPICommOnly.h"
+#include "adios2/ADIOSMacros.h"
 #include "adios2/ADIOSTypes.h"
 #include "adios2/core/IO.h"
 #include "adios2/core/Variable.h"
@@ -50,10 +52,12 @@ public:
      * @param mpiComm new communicator passed at Open or from ADIOS class
      */
     Engine(const std::string engineType, IO &io, const std::string &name,
-           const OpenMode openMode, MPI_Comm mpiComm);
+           const Mode openMode, MPI_Comm mpiComm);
 
     virtual ~Engine() = default;
 
+    void SetStep(const size_t step = 0);
+
     /**
      * Write function that adds static checking on the variable to be passed by
      * values
@@ -106,13 +110,16 @@ public:
     void Write(const std::string &variableName, const void *values);
 
     /**
-     *
-     * @param variableName
-     * @return
+     * Inquires if a variable of a certain type exists.
+     * Returns a pointer reference, not need to manage memory.
+     * @param variableName input to search
+     * @return pointer reference to existing variable, nullptr if variable
+     * doesn't exist
      */
     template <class T>
-    Variable<T> *InquireVariable(const std::string &variableName,
-                                 const bool readIn = false);
+    Variable<T> *InquireVariable(const std::string &variableName);
+
+    VariableBase *InquireVariableAny(const std::string &variableName);
 
     /**
      * Read function that adds static checking on the variable to be passed by
@@ -124,56 +131,7 @@ public:
      * must use Read(variable) instead intentionally
      */
     template <class T>
-    void Read(Variable<T> &variable, T *values);
-
-    /**
-     * String version
-     * @param variableName
-     * @param values
-     */
-    template <class T>
-    void Read(const std::string &variableName, T *values);
-
-    /**
-     * Single value version
-     * @param variable
-     * @param values
-     */
-    template <class T>
-    void Read(Variable<T> &variable, T &values);
-
-    /**
-     * Single value version using string as variable handlers
-     * @param variableName
-     * @param values
-     */
-    template <class T>
-    void Read(const std::string &variableName, T &values);
-
-    /**
-     * Unallocated version, ADIOS will allocate space for incoming data
-     * @param variable
-     */
-    template <class T>
-    void Read(Variable<T> &variable);
-
-    /**
-     * Unallocated version, ADIOS will allocate space for incoming data
-     * @param variableName
-     */
-    template <class T>
-    void Read(const std::string &variableName);
-
-    /**
-     * Read function that adds static checking on the variable to be passed by
-     * values
-     * It then calls its corresponding derived class virtual function
-     * This version uses m_Group to look for the variableName.
-     * @param variable name of variable to the written
-     * @param values pointer passed from the application
-     */
-    template <class T>
-    void ScheduleRead(Variable<T> &variable, T *values);
+    void Read(Variable<T> &variable, T *values = nullptr);
 
     /**
      * String version
@@ -181,43 +139,7 @@ public:
      * @param values
      */
     template <class T>
-    void ScheduleRead(const std::string &variableName, T *values);
-
-    /**
-     * Single value version
-     * @param variable
-     * @param values
-     */
-    template <class T>
-    void ScheduleRead(Variable<T> &variable, T &values);
-
-    /**
-     * Single value version using string as variable handlers
-     * @param variableName
-     * @param values
-     */
-    template <class T>
-    void ScheduleRead(const std::string &variableName, T &values);
-
-    /**
-     * Unallocated version, ADIOS will allocate space for incoming data
-     * @param variableName
-     */
-    // virtual void ScheduleRead(const std::string &variableName);
-
-    /**
-     * Unallocated unspecified version, ADIOS will receive any variable and will
-     * allocate space for incoming data
-     */
-    // virtual void ScheduleRead();
-
-    /**
-     * Perform all scheduled reads, either blocking until all reads completed,
-     * or
-     * return immediately.
-     * @param mode Blocking or non-blocking modes
-     */
-    virtual void PerformReads(ReadMode mode);
+    void Read(const std::string &variableName, T *values = nullptr);
 
     /**
      * Reader application indicates that no more data will be read from the
@@ -250,37 +172,14 @@ public:
      * readers
      * @param callback Will be called when advance is completed.
      */
-    virtual void AdvanceAsync(const AdvanceMode mode,
-                              AdvanceAsyncCallback callback);
+    //    virtual void AdvanceAsync(const AdvanceMode mode,
+    //                              AdvanceAsyncCallback callback);
+    std::future<void> AdvanceAsync(
+        AdvanceMode mode,
+        std::function<void(std::shared_ptr<adios2::Engine>)> /*callback*/);
 
     AdvanceStatus GetAdvanceStatus();
 
-    /**
-     * @brief Let ADIOS allocate memory for a variable in the buffer (bp),
-     * to be populated by the user. Variable dimensions are fixed.
-     * To decrease the cost of copying memory, a user may let ADIOS allocate
-     * the memory for a user-variable,
-     * according to the definition of an ADIOS-variable. The memory will be
-     * part
-     * of the ADIOS buffer used
-     * by the engine and it lives until the engine (file, stream) is closed.
-     * A variable that has been allocated this way (cannot have its local
-     * dimensions changed, and AdvanceAsync() should be
-     * used instead of Advance() and the user-variable must not be modified
-     * by
-     * the application until the notification arrives.
-     * This is required so that any reader can access the written data
-     * before
-     * the application overwrites it.
-     * @param var Variable with defined local dimensions and offsets in
-     * global
-     * space
-     * @param fillValue Fill the allocated array with this value
-     * @return A constant pointer reference to the allocated array.
-     */
-    template <class T>
-    T *AllocateVariable(Variable<T> &var, T fillValue = 0);
-
     /**
      * Needed for DataMan Engine
      * @param callback function passed from the user
@@ -294,7 +193,7 @@ public:
      * reading
      * @return a vector of strings
      */
-    std::vector<std::string> VariableNames();
+    std::map<std::string, std::string> Variables();
 
     /**
      * Closes a particular transport, or all if -1
@@ -302,6 +201,12 @@ public:
      */
     virtual void Close(const int transportIndex = -1) = 0;
 
+    virtual void Flush(const int transportIndex = -1);
+    virtual void Get(const int transportIndex = -1);
+
+    virtual std::future<void> FlushAsync(const int transportIndex = -1);
+    virtual std::future<void> GetAsync(const int transportIndex = -1);
+
 protected:
     /** from derived class */
     const std::string m_EngineType;
@@ -313,7 +218,7 @@ protected:
     const std::string m_Name;
 
     /** open mode from ADIOSTypes.h OpenMode */
-    const OpenMode m_OpenMode;
+    const Mode m_OpenMode;
 
     /** from ADIOS class passed to Engine created with Open
      *  if no new communicator is passed */
@@ -355,30 +260,18 @@ protected:
      */
     void DoWrite(const std::string &variableName, const void *values);
 
-    // READ
-    virtual VariableBase *InquireVariableUnknown(const std::string &name,
-                                                 const bool readIn);
+// READ
 #define declare(T, L)                                                          \
-    virtual Variable<T> *InquireVariable##L(const std::string &name,           \
-                                            const bool readIn);
+    virtual Variable<T> *DoInquireVariable##L(const std::string &variableName);
+
     ADIOS2_FOREACH_TYPE_2ARGS(declare)
 #undef declare
 
-// Known-type
-#define declare_type(T)                                                        \
-    virtual void DoScheduleRead(Variable<T> &variable, const T *values);       \
-    virtual void DoScheduleRead(const std::string &variableName,               \
-                                const T *values);
-    ADIOS2_FOREACH_TYPE_1ARG(declare_type)
-#undef declare_type
-
-    void DoScheduleRead(const std::string &variableName, void *values);
-
 private:
     /** Throw exception by Engine virtual functions not implemented by a derived
      * class */
     void ThrowUp(const std::string function) const;
-};
+}; // END OF CLASS
 
 #define declare_template_instantiation(T)                                      \
     extern template void Engine::Write<T>(Variable<T> &, const T *);           \
diff --git a/source/adios2/core/Engine.inl b/source/adios2/core/Engine.inl
index 486df9c53c150d2a4d2813f5db81d85d9fcf5257..0a527ab664f92141f8956e9acf3405fbeed0b58c 100644
--- a/source/adios2/core/Engine.inl
+++ b/source/adios2/core/Engine.inl
@@ -17,80 +17,6 @@
 namespace adios2
 {
 
-template <class T>
-T *Engine::AllocateVariable(Variable<T> &variable, T fillValue)
-{
-    throw std::invalid_argument("ERROR: type not supported for variable " +
-                                variable.m_Name + " in call to \n");
-}
-
-template <class T>
-void Engine::Read(Variable<T> &variable, T *values)
-{
-    DoScheduleRead(variable, values);
-    PerformReads(ReadMode::Blocking);
-}
-
-template <class T>
-void Engine::Read(const std::string &variableName, T *values)
-{
-    DoScheduleRead(variableName, values);
-    PerformReads(ReadMode::Blocking);
-}
-
-template <class T>
-void Engine::Read(Variable<T> &variable, T &values)
-{
-    DoScheduleRead(variable, &values);
-    PerformReads(ReadMode::Blocking);
-}
-
-template <class T>
-void Engine::Read(const std::string &variableName, T &values)
-{
-    DoScheduleRead(variableName, &values);
-    PerformReads(ReadMode::Blocking);
-}
-
-template <class T>
-void Engine::Read(Variable<T> &variable)
-{
-    DoScheduleRead(variable);
-    PerformReads(ReadMode::Blocking);
-}
-
-template <class T>
-void Engine::Read(const std::string &variableName)
-{
-    // TODO
-    // DoScheduleRead(variableName);
-    // PerformReads(PerformReadMode::BLOCKINGREAD);
-}
-
-template <class T>
-void Engine::ScheduleRead(Variable<T> &variable, T *values)
-{
-    DoScheduleRead(variable, values);
-}
-
-template <class T>
-void Engine::ScheduleRead(const std::string &variableName, T *values)
-{
-    DoScheduleRead(variableName, values);
-}
-
-template <class T>
-void Engine::ScheduleRead(Variable<T> &variable, T &values)
-{
-    DoScheduleRead(variable, &values);
-}
-
-template <class T>
-void Engine::ScheduleRead(const std::string &variableName, T &values)
-{
-    DoScheduleRead(variableName, &values);
-}
-
 } // end namespace adios2
 
 #endif /* ADIOS2_CORE_ENGINE_INL_ */
diff --git a/source/adios2/core/Engine.tcc b/source/adios2/core/Engine.tcc
index 74666c7324f17e0fef9ee6ec6174763991883ece..d7d989e02712adf7435253de24008ebd53244b21 100644
--- a/source/adios2/core/Engine.tcc
+++ b/source/adios2/core/Engine.tcc
@@ -47,130 +47,16 @@ void Engine::Write(const std::string &variableName, const T values)
     Write(m_IO.GetVariable<T>(variableName), &values);
 }
 
-template <>
-Variable<char> *Engine::InquireVariable<char>(const std::string &variableName,
-                                              const bool readIn)
-{
-    return InquireVariableChar(variableName, readIn);
-}
-
-template <>
-Variable<unsigned char> *
-Engine::InquireVariable<unsigned char>(const std::string &variableName,
-                                       const bool readIn)
-{
-    return InquireVariableUChar(variableName, readIn);
-}
-
-template <>
-Variable<short> *Engine::InquireVariable<short>(const std::string &variableName,
-                                                const bool readIn)
-{
-    return InquireVariableShort(variableName, readIn);
-}
-
-template <>
-Variable<unsigned short> *
-Engine::InquireVariable<unsigned short>(const std::string &variableName,
-                                        const bool readIn)
-{
-    return InquireVariableUShort(variableName, readIn);
-}
-
-template <>
-Variable<int> *Engine::InquireVariable<int>(const std::string &variableName,
-                                            const bool readIn)
-{
-    return InquireVariableInt(variableName, readIn);
-}
-
-template <>
-Variable<unsigned int> *
-Engine::InquireVariable<unsigned int>(const std::string &variableName,
-                                      const bool readIn)
-{
-    return InquireVariableUInt(variableName, readIn);
-}
-
-template <>
-Variable<long int> *
-Engine::InquireVariable<long int>(const std::string &variableName,
-                                  const bool readIn)
-{
-    return InquireVariableLInt(variableName, readIn);
-}
-
-template <>
-Variable<long long int> *
-Engine::InquireVariable<long long int>(const std::string &variableName,
-                                       const bool readIn)
-{
-    return InquireVariableLLInt(variableName, readIn);
-}
-
-template <>
-Variable<unsigned long int> *
-Engine::InquireVariable<unsigned long int>(const std::string &variableName,
-                                           const bool readIn)
-{
-    return InquireVariableULInt(variableName, readIn);
-}
-
-template <>
-Variable<unsigned long long int> *
-Engine::InquireVariable<unsigned long long int>(const std::string &variableName,
-                                                const bool readIn)
-{
-    return InquireVariableULLInt(variableName, readIn);
-}
-
-template <>
-Variable<float> *Engine::InquireVariable<float>(const std::string &variableName,
-                                                const bool readIn)
-{
-    return InquireVariableFloat(variableName, readIn);
-}
-
-template <>
-Variable<double> *
-Engine::InquireVariable<double>(const std::string &variableName,
-                                const bool readIn)
-{
-    return InquireVariableDouble(variableName, readIn);
-}
-
-template <>
-Variable<long double> *
-Engine::InquireVariable<long double>(const std::string &variableName,
-                                     const bool readIn)
-{
-    return InquireVariableLDouble(variableName, readIn);
-}
-
-template <>
-Variable<cfloat> *
-Engine::InquireVariable<cfloat>(const std::string &variableName,
-                                const bool readIn)
-{
-    return InquireVariableCFloat(variableName, readIn);
-}
-
-template <>
-Variable<cdouble> *
-Engine::InquireVariable<cdouble>(const std::string &variableName,
-                                 const bool readIn)
-{
-    return InquireVariableCDouble(variableName, readIn);
-}
-
-template <>
-Variable<cldouble> *
-Engine::InquireVariable<cldouble>(const std::string &variableName,
-                                  const bool readIn)
-{
-    return InquireVariableCLDouble(variableName, readIn);
-}
+// READ
+#define define(T, L)                                                           \
+    template <>                                                                \
+    Variable<T> *Engine::InquireVariable<T>(const std::string &name)           \
+    {                                                                          \
+        return DoInquireVariable##L(name);                                     \
+    }
+ADIOS2_FOREACH_TYPE_2ARGS(define)
+#undef define
 
-} // end namespace adios
+} // end namespace adios2
 
 #endif /** ADIOS2_CORE_ENGINE_TCC_ */
diff --git a/source/adios2/core/IO.cpp b/source/adios2/core/IO.cpp
index e635a100863235e804bc300dae48218382ededc5..f36f87103b4fd2fab314a406dd965478cbdb511a 100644
--- a/source/adios2/core/IO.cpp
+++ b/source/adios2/core/IO.cpp
@@ -12,8 +12,9 @@
 #include "IO.tcc"
 
 #include "adios2/ADIOSMPI.h"
+#include "adios2/engine/bp/BPFileReader.h"
 #include "adios2/engine/bp/BPFileWriter.h"
-#include "adios2/engine/plugin/PluginEngine.h"
+//#include "adios2/engine/plugin/PluginEngine.h"
 #include "adios2/helper/adiosFunctions.h" //BuildParametersMap
 
 #ifdef ADIOS2_HAVE_DATAMAN // external dependencies
@@ -191,34 +192,27 @@ bool IO::RemoveVariable(const std::string &name) noexcept
     return isRemoved;
 }
 
-std::shared_ptr<Engine> IO::Open(const std::string &name,
-                                 const OpenMode openMode, MPI_Comm mpiComm)
+Engine &IO::Open(const std::string &name, const Mode openMode, MPI_Comm mpiComm)
 {
     if (m_DebugMode)
     {
-        // Check if Engine already exists
-        if (m_EngineNames.count(name) == 1)
+        if (m_Engines.count(name) == 1)
         {
-            throw std::invalid_argument(
-                "ERROR: IO Engine with name " + name +
-                " already created by Open, in call from Open.\n");
+            throw std::invalid_argument("ERROR: IO Engine with name " + name +
+                                        " already created, in call to Open.\n");
         }
     }
 
     std::shared_ptr<Engine> engine;
-    m_EngineNames.insert(name);
 
     const bool isDefaultWriter =
         m_EngineType.empty() &&
-                (openMode == OpenMode::Write || openMode == OpenMode::Append)
+                (openMode == Mode::Write || openMode == Mode::Append)
             ? true
             : false;
 
     const bool isDefaultReader =
-        m_EngineType.empty() &&
-                (openMode == OpenMode::Read || openMode == OpenMode::ReadWrite)
-            ? true
-            : false;
+        m_EngineType.empty() && (openMode == Mode::Read) ? true : false;
 
     if (isDefaultWriter || m_EngineType == "BPFileWriter")
     {
@@ -226,8 +220,7 @@ std::shared_ptr<Engine> IO::Open(const std::string &name,
     }
     else if (isDefaultReader || m_EngineType == "BPFileReader")
     {
-        // engine = std::make_shared<BPFileReader>(*this, name, openMode,
-        // mpiComm);
+        engine = std::make_shared<BPFileReader>(*this, name, openMode, mpiComm);
     }
     else if (m_EngineType == "DataManWriter")
     {
@@ -291,7 +284,8 @@ std::shared_ptr<Engine> IO::Open(const std::string &name,
     }
     else if (m_EngineType == "PluginEngine")
     {
-        engine = std::make_shared<PluginEngine>(*this, name, openMode, mpiComm);
+        // engine = std::make_shared<PluginEngine>(*this, name, openMode,
+        // mpiComm);
     }
     else
     {
@@ -304,11 +298,22 @@ std::shared_ptr<Engine> IO::Open(const std::string &name,
         }
     }
 
-    return engine;
+    auto itEngine = m_Engines.emplace(name, std::move(engine));
+
+    if (m_DebugMode)
+    {
+        if (!itEngine.second)
+        {
+            throw std::invalid_argument(
+                "ERROR: engine of type " + m_EngineType + " and name " + name +
+                " could not be created, in call to Open\n");
+        }
+    }
+    // return a reference
+    return *itEngine.first->second.get();
 }
 
-std::shared_ptr<Engine> IO::Open(const std::string &name,
-                                 const OpenMode openMode)
+Engine &IO::Open(const std::string &name, const Mode openMode)
 {
     return Open(name, openMode, m_MPIComm);
 }
diff --git a/source/adios2/core/IO.h b/source/adios2/core/IO.h
index f29191dac387e7d9b97b44d9ee8b8b5d3cca1ce1..1e58801725c60281df64c2d0aef93d16db31e112 100644
--- a/source/adios2/core/IO.h
+++ b/source/adios2/core/IO.h
@@ -14,8 +14,8 @@
 /// \cond EXCLUDE_FROM_DOXYGEN
 #include <map>
 #include <memory> //std:shared_ptr
-#include <set>
 #include <string>
+#include <unordered_set>
 #include <utility> //std::pair
 #include <vector>
 /// \endcond
@@ -260,8 +260,8 @@ public:
      * @param mpiComm assigns a new communicator to the Engine
      * @return a smart pointer to a derived object of the Engine class
      */
-    std::shared_ptr<Engine> Open(const std::string &name,
-                                 const OpenMode openMode, MPI_Comm mpiComm);
+    Engine &Open(const std::string &name, const Mode openMode,
+                 MPI_Comm mpiComm);
 
     /**
      * Overloaded version that reuses the MPI_Comm object passed
@@ -271,8 +271,7 @@ public:
      * @param openMode write, read, append from ADIOSTypes.h OpenMode
      * @return a smart pointer to a derived object of the Engine class
      */
-    std::shared_ptr<Engine> Open(const std::string &name,
-                                 const OpenMode openMode);
+    Engine &Open(const std::string &name, const Mode openMode);
 
     // READ FUNCTIONS:
     void SetReadMultiplexPattern(const ReadMultiplexPattern pattern);
@@ -354,6 +353,8 @@ private:
     template <class T>
     std::map<unsigned int, Attribute<T>> &GetAttributeMap();
 
+    std::map<std::string, std::shared_ptr<Engine>> m_Engines;
+
     /**
      * Gets map index for Variables or Attributes
      * @param name
@@ -368,8 +369,6 @@ private:
      * signatures */
     void CheckAttributeCommon(const std::string &name) const;
 
-    std::set<std::string> m_EngineNames;
-
     /**
      * Checks if iterator points to end. Used for Variables and Attributes.
      * @param itDataMap iterator to be tested
diff --git a/source/adios2/core/Selection.cpp b/source/adios2/core/Selection.cpp
deleted file mode 100644
index c531a823a307cb6213fb42139a54083939ee2196..0000000000000000000000000000000000000000
--- a/source/adios2/core/Selection.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * Selection.cpp
- *
- *  Created on: May 19, 2017
- *      Author: Norbert Podhorszki pnorbert@ornl.gov
- *              William F Godoy godoywf@ornl.gov
- */
-
-#include "Selection.h"
-
-namespace adios2
-{
-
-Selection::Selection(const SelectionType type, const bool debugMode)
-: m_Type(type), m_DebugMode(debugMode)
-{
-}
-
-} // end namespace adios
diff --git a/source/adios2/core/Selection.h b/source/adios2/core/Selection.h
deleted file mode 100644
index cb7e915d19464d81f4cabfbd7c26f8d95d3119dc..0000000000000000000000000000000000000000
--- a/source/adios2/core/Selection.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- *  Created on: May 17, 2017
- *      Author: Norbert Podhorszki pnorbert@ornl.gov
- *              William F Godoy godoywf@ornl.gov
- */
-
-/*
- *   Selection API in C++
- *
- *   A SELECTION is the data ranges resulting from a QUERY over a file and
- * variable(s).
- *
- *   A SELECTION can be a list of bounding boxes and point-sets. Other data
- * structures
- *   are not supported. Any query will result in such a selection.
- *   Other selections are the write-block and auto.
- *
- *   Write block is a block of data written
- *   by a writer process, it is identified by an index. If each writer outputs
- * one block
- *   then the index equals to the rank of the write process. With multi-var
- * writing and
- *   multiple steps in a file, index runs from 0 as rank 0 process' first block.
- *
- *   Auto selection lets the read method to automatically choose what to return.
- * It will
- *   be a block / blocks of selected writers.
- *
- *   If a query is a simple bounding box, the selection is the bounding box
- * itself, so
- *   the application does not need to retrieve the selection to work on the read
- * data.
- */
-
-#ifndef ADIOS2_CORE_SELECTION_H_
-#define ADIOS2_CORE_SELECTION_H_
-
-#include "adios2/ADIOSConfig.h"
-#include "adios2/ADIOSTypes.h"
-
-namespace adios2
-{
-/** Base class for Selection (query) types */
-class Selection
-{
-public:
-    /** from derived class */
-    const SelectionType m_Type;
-
-    /**
-     * Unique constructor
-     * @param type derived class type
-     */
-    Selection(const SelectionType type, const bool debugMode = false);
-
-    virtual ~Selection() = default;
-
-protected:
-    /** true: extra checks (recommended) */
-    const bool m_DebugMode;
-};
-
-} // namespace adios
-
-#endif /* ADIOS2_CORE_SELECTION_H_ */
diff --git a/source/adios2/core/SelectionBoundingBox.cpp b/source/adios2/core/SelectionBoundingBox.cpp
deleted file mode 100644
index 8af89532538bab99d90f683f38fc9997b57a84d2..0000000000000000000000000000000000000000
--- a/source/adios2/core/SelectionBoundingBox.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * SelectionBoundingBox.cpp
- *
- *  Created on: May 17, 2017
- *      Author: Norbert Podhorszki pnorbert@ornl.gov
- *              William F Godoy godoywf@ornl.gov
- *
- */
-
-#include "SelectionBoundingBox.h"
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <stdexcept>
-/// \endcond
-
-#include "adios2/helper/adiosFunctions.h" //Uint64VectorToSizetVector
-
-namespace adios2
-{
-
-SelectionBoundingBox::SelectionBoundingBox(const Dims start, const Dims count,
-                                           const bool debugMode)
-: Selection(SelectionType::BoundingBox, debugMode), m_Start(start),
-  m_Count(count)
-{
-    if (m_DebugMode)
-    {
-        CheckBoundingBox();
-    }
-}
-
-void SelectionBoundingBox::CheckBoundingBox() const
-{
-
-    auto lf_Throw = [](const std::string &message) {
-        throw std::invalid_argument(
-            "ERROR: " + message +
-            ", in call to SelectionBoundingBox constructor\n");
-    };
-
-    if (m_Start.size() != m_Count.size())
-    {
-        lf_Throw("start and count must have the same size");
-    }
-
-    if (m_Start.empty())
-    {
-        lf_Throw("start is empty");
-    }
-
-    if (m_Count.empty())
-    {
-        lf_Throw("count is empty");
-    }
-}
-
-} // end namespace adios
diff --git a/source/adios2/core/SelectionBoundingBox.h b/source/adios2/core/SelectionBoundingBox.h
deleted file mode 100644
index b59b3d8aa1544610d05aa99b8f31b502009394c4..0000000000000000000000000000000000000000
--- a/source/adios2/core/SelectionBoundingBox.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * SelectionBoundingBox.h
- *
- *  Created on: May 17, 2017
- *      Author: Norbert Podhorszki pnorbert@ornl.gov
- *              William F Godoy godoywf@ornl.gov
- */
-
-#ifndef ADIOS2_CORE_SELECTIONBOUNDINGBOX_H_
-#define ADIOS2_CORE_SELECTIONBOUNDINGBOX_H_
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <vector>
-/// \endcond
-
-#include "adios2/ADIOSConfig.h"
-#include "adios2/core/Selection.h"
-
-namespace adios2
-{
-
-/** Bounding box selection to read a subset of a non-scalar variable.
- *  @param start     array of offsets to start reading in each dimension
- *  @param count     number of data elements to read in each dimension
- */
-class SelectionBoundingBox : public Selection
-{
-public:
-    /** Starting coodinates of bounding box */
-    Dims m_Start;
-    /** From start of bounding box */
-    Dims m_Count;
-
-    /**
-     * Constructor using uint64_t vectors
-     * @param start of bounding box
-     * @param count from start of bounding box
-     */
-    //    SelectionBoundingBox(const std::vector<uint64_t> start,
-    //                         const std::vector<uint64_t> count,
-    //                         const bool debugMode = false);
-
-    /**
-     * Constructor using size_t vectors
-     * @param start of bounding box
-     * @param count from start of bounding box
-     */
-    SelectionBoundingBox(const Dims start, const Dims count,
-                         const bool debugMode = false);
-
-    ~SelectionBoundingBox() = default;
-
-private:
-    /** Check in debug mode to make sure bounding box is valid */
-    void CheckBoundingBox() const;
-};
-
-} // end namespace adios
-
-#endif /* ADIOS2_CORE_SELECTIONBOUNDINGBOX_H_ */
diff --git a/source/adios2/core/SelectionPoints.cpp b/source/adios2/core/SelectionPoints.cpp
deleted file mode 100644
index 271d5256de9c62004ff42cbeb6ada3a2638c997a..0000000000000000000000000000000000000000
--- a/source/adios2/core/SelectionPoints.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * SelectionPoints.cpp
- *
- *  Created on: May 17, 2017
- *      Author: Norbert Podhorszki pnorbert@ornl.gov
- *              William F Godoy godoywf@ornl.gov
- */
-
-#include "SelectionPoints.h"
-
-namespace adios2
-{
-
-SelectionPoints::SelectionPoints(size_t dimensionsSize,
-                                 std::vector<uint64_t> &points)
-: Selection(SelectionType::Points), m_DimensionsSize(dimensionsSize),
-  m_PointsVec(&points), m_PointsSize(points.size())
-{
-}
-
-SelectionPoints::SelectionPoints(size_t dimensionsSize, size_t pointsSize,
-                                 uint64_t *points)
-: Selection(SelectionType::Points), m_DimensionsSize(dimensionsSize),
-  m_PointsSize(pointsSize), m_PointsPointer(points)
-{
-}
-
-} // end namespace adios
diff --git a/source/adios2/core/SelectionPoints.h b/source/adios2/core/SelectionPoints.h
deleted file mode 100644
index 04999ac994d7fa888b7a2def2271ac76ee052a8e..0000000000000000000000000000000000000000
--- a/source/adios2/core/SelectionPoints.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * SelectionPoints.h
- *
- *  Created on: May 17, 2017
- *      Author: Norbert Podhorszki pnorbert@ornl.gov
- *              William F Godoy godoywf@ornl.gov
- */
-
-#ifndef ADIOS2_CORE_SELECTIONPOINTS_H_
-#define ADIOS2_CORE_SELECTIONPOINTS_H_
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <vector>
-/// \endcond
-
-#include "adios2/ADIOSConfig.h"
-#include "adios2/ADIOSTypes.h"
-#include "adios2/core/Selection.h"
-
-namespace adios2
-{
-
-/** Selection for a selection of an enumeration of positions.
- *  @param     ndim      Number of dimensions
- *  @param     npoints   Number of points of the selection
- *  @param     points    1D array of indices, compacted for all dimension
- *              (e.g.  [i1,j1,k1,i2,j2,k2,...,in,jn,kn] for
- *              n points in a 3D space.
- */
-class SelectionPoints : public Selection
-{
-public:
-    /** number of dimensions from constructor */
-    const size_t m_DimensionsSize;
-
-    /** reference to points in constructor, must use a pointer as nullptr is
-     * valid if an array is passed in the constructor instead */
-    std::vector<uint64_t> *m_PointsVec = nullptr;
-
-    /** pointer based applications needed size*/
-    const size_t m_PointsSize;
-    /** pointer based applications needed array*/
-    uint64_t *m_PointsPointer = nullptr;
-
-    /**
-     * Constructor that takes a vector<uint64_t> for points
-     * @param dimensionsSize
-     * @param pointsSize
-     * @param points
-     */
-    SelectionPoints(size_t dimensionsSize, std::vector<uint64_t> &points);
-
-    SelectionPoints(size_t dimensionsSize, size_t pointsSize, uint64_t *points);
-
-    virtual ~SelectionPoints() = default;
-};
-
-} // end namespace adios
-
-#endif /* ADIOS2_CORE_SELECTIONPOINTS_H_ */
diff --git a/source/adios2/core/Variable.h b/source/adios2/core/Variable.h
index dbf5ec2dc00f5754d098f8ef79c8cee44f971b3f..3ec670583695f7dabaa51cae60245f435e6f6b9c 100644
--- a/source/adios2/core/Variable.h
+++ b/source/adios2/core/Variable.h
@@ -53,8 +53,6 @@ public:
                 const bool debugMode);
 
     ~Variable<T>() = default;
-
-    void ApplyTransforms() final;
 };
 
 } // end namespace adios2
diff --git a/source/adios2/core/Variable.tcc b/source/adios2/core/Variable.tcc
index 0de077a2e58fc3dd66314eca48143213f82c335d..0680a34c2c1c58d1c0adaa3205014de27422a362 100644
--- a/source/adios2/core/Variable.tcc
+++ b/source/adios2/core/Variable.tcc
@@ -28,11 +28,6 @@ namespace adios2
     : VariableBase(name, GetType<T>(), sizeof(T), shape, start, count,         \
                    constantDims, debugMode)                                    \
     {                                                                          \
-    }                                                                          \
-                                                                               \
-    template <>                                                                \
-    void Variable<T>::ApplyTransforms()                                        \
-    {                                                                          \
     }
 
 ADIOS2_FOREACH_TYPE_1ARG(declare_type)
diff --git a/source/adios2/core/VariableBase.cpp b/source/adios2/core/VariableBase.cpp
index 775944e0a775fb2f0ff635c36b50ec790cdf54f0..5313929b7214eef6cf604eae97624a3e29cacae6 100644
--- a/source/adios2/core/VariableBase.cpp
+++ b/source/adios2/core/VariableBase.cpp
@@ -41,8 +41,12 @@ size_t VariableBase::TotalSize() const noexcept
     return GetTotalSize(m_Count);
 }
 
-void VariableBase::SetSelection(const Dims &start, const Dims &count)
+void VariableBase::SetSelection(const std::pair<Dims, Dims> &boxDims,
+                                const std::pair<size_t, size_t> &boxSteps)
 {
+    const Dims &start = boxDims.first;
+    const Dims &count = boxDims.second;
+
     if (m_DebugMode)
     {
         if (m_SingleValue)
@@ -82,17 +86,16 @@ void VariableBase::SetSelection(const Dims &start, const Dims &count)
         }
     }
 
-    m_Count = count;
     m_Start = start;
+    m_Count = count;
+    SetStepSelection(boxSteps);
 }
 
-void VariableBase::SetSelection(const SelectionBoundingBox &selection)
+void VariableBase::SetMemorySelection(const std::pair<Dims, Dims> &boxDims)
 {
-    SetSelection(selection.m_Start, selection.m_Count);
-}
+    const Dims &start = boxDims.first;
+    const Dims &count = boxDims.second;
 
-void VariableBase::SetMemorySelection(const SelectionBoundingBox &selection)
-{
     if (m_DebugMode)
     {
         if (m_SingleValue)
@@ -102,26 +105,35 @@ void VariableBase::SetMemorySelection(const SelectionBoundingBox &selection)
                                         m_Name +
                                         ", in call to SetMemorySelection\n");
         }
-        if (m_Shape.size() != selection.m_Count.size() ||
-            m_Shape.size() != selection.m_Start.size())
+
+        if (m_Shape.size() != start.size() || m_Shape.size() != count.size())
         {
             throw std::invalid_argument(
-                "ERROR: selection argument m_Count and m_Start sizes must be "
-                "the "
-                "same as variable " +
+                "ERROR: selection Dims start, count sizes must be "
+                "the same as variable " +
                 m_Name + " m_Shape, in call to SetMemorySelction\n");
         }
     }
 
-    m_MemoryCount = selection.m_Count;
-    m_MemoryStart = selection.m_Start;
+    m_MemoryStart = start;
+    m_MemoryCount = count;
 }
 
-void VariableBase::SetStepSelection(const unsigned int startStep,
-                                    const unsigned int countStep)
+size_t VariableBase::GetAvailableStepsStart() { return m_AvailableStepsStart; }
+size_t VariableBase::GetAvailableStepsCount() { return m_AvailableStepsCount; }
+
+void VariableBase::SetStepSelection(const std::pair<size_t, size_t> &boxSteps)
 {
-    m_ReadFromStep = startStep;
-    m_ReadNSteps = countStep;
+    if (boxSteps.second == 0)
+    {
+        throw std::invalid_argument("ERROR: boxSteps.second count argument "
+                                    " can't be zero, from variable " +
+                                    m_Name +
+                                    ", in call to Setting Step Selection\n");
+    }
+
+    m_StepStart = boxSteps.first;
+    m_StepCount = boxSteps.second;
 }
 
 // transforms related functions
@@ -232,7 +244,7 @@ void VariableBase::InitShapeType()
                                         m_Name + "\n");
         }
     }
-    else //(m_Shape.empty())
+    else
     {
         if (m_Start.empty())
         {
@@ -258,7 +270,9 @@ void VariableBase::InitShapeType()
 
     /* Extra checks for invalid settings */
     if (m_DebugMode)
+    {
         CheckDimsCommon("DefineVariable(" + m_Name + ")");
+    }
 }
 
 void VariableBase::CheckDimsCommon(const std::string hint) const
@@ -311,4 +325,4 @@ void VariableBase::CheckDimsBeforeWrite(const std::string hint) const
     // TODO need to think more exceptions here
 }
 
-} // end namespace adios
+} // end namespace adios2
diff --git a/source/adios2/core/VariableBase.h b/source/adios2/core/VariableBase.h
index f169a3299d8251eda7f6d599e6ec2b042673c15d..2acecc7edbcb4843f90364760faea7b0bbfd9993 100644
--- a/source/adios2/core/VariableBase.h
+++ b/source/adios2/core/VariableBase.h
@@ -20,7 +20,6 @@
 
 #include "adios2/ADIOSConfig.h"
 #include "adios2/ADIOSTypes.h"
-#include "adios2/core/SelectionBoundingBox.h"
 #include "adios2/core/Transform.h"
 
 namespace adios2
@@ -47,20 +46,24 @@ public:
     Dims m_Start; ///< starting point (offsets) in global shape
     Dims m_Count; ///< dimensions from m_Start in global shape
 
-    Dims m_MemoryStart; ///< offset of memory selection
-    Dims m_MemoryCount; ///< subset of m_Shape (e.g. remove ghost points)
-
-    /** Read from this step (must be 0 in staging) */
-    unsigned int m_ReadFromStep = 0;
-    /** Read this many steps at once (must be 1 in staging) */
-    unsigned int m_ReadNSteps = 1;
     /** Global array was written as Joined array, so read accordingly */
     bool m_ReadAsJoined = false;
     /** Global array was written as Local value, so read accordingly */
     bool m_ReadAsLocalValue = false;
-    /** number of steps available in a file (or 1 in staging) filled by
-     * InquireVariable*/
-    unsigned int m_AvailableSteps = 1;
+
+    /** Transforms metadata info */
+    struct TransformInfo
+    {
+        /** reference to object derived from Transform class */
+        Transform &Operator;
+        /** parameters from AddTransform */
+        Params Parameters;
+        /** resulting sizes from transformation */
+        Dims Sizes;
+    };
+
+    /** Registered transforms */
+    std::vector<TransformInfo> m_TransformsInfo;
 
     VariableBase(const std::string &name, const std::string type,
                  const size_t elementSize, const Dims &shape, const Dims &start,
@@ -81,29 +84,28 @@ public:
      */
     size_t TotalSize() const noexcept;
 
-    /** Set the local dimension and global offset of the variable */
-    void SetSelection(const Dims &start, const Dims &count);
+    /** Set Dims and Time start and count */
+    void SetSelection(const std::pair<Dims, Dims> &boxDims,
+                      const std::pair<size_t, size_t> &boxSteps =
+                          std::pair<size_t, size_t>(0, 1));
 
-    /** Overloaded version of SetSelection using a SelectionBoundingBox */
-    void SetSelection(const SelectionBoundingBox &selection);
+    /**
+     * Set the steps for the variable. The pointer passed at
+     * reading must be able to hold enough memory to store multiple steps in a
+     * single read. For writing it changes the time step
+     * @param boxSteps {startStep, countStep}
+     */
+    void SetStepSelection(const std::pair<size_t, size_t> &boxSteps);
 
     /**
      * Set the local dimension and global offset of the variable using a
      * selection
      * Only bounding boxes are allowed
      */
-    void SetMemorySelection(const SelectionBoundingBox &selection);
+    void SetMemorySelection(const std::pair<Dims, Dims> &boxDims);
 
-    /**
-     * Set the steps for the variable to read from. The pointer passed at
-     * reading must be able to hold enough memory to store multiple steps in a
-     * single read.
-     * @param startStep  The first step to read. Steps start from 0
-     * @param countStep    Number of consecutive steps to read at once.
-     *
-     */
-    void SetStepSelection(const unsigned int startStep,
-                          const unsigned int countStep);
+    size_t GetAvailableStepsStart();
+    size_t GetAvailableStepsCount();
 
     /**
      * Pushed a new transform to a sequence of transports
@@ -120,28 +122,6 @@ public:
     /** Clears out the transform sequence defined by AddTransform */
     void ClearTransforms() noexcept;
 
-    /** Apply current sequence of transforms defined by AddTransform */
-    virtual void ApplyTransforms() = 0;
-
-    /** Transforms metadata info */
-    struct TransformInfo
-    {
-        /** reference to object derived from Transform class */
-        Transform &Operator;
-        /** parameters from AddTransform */
-        Params Parameters;
-        /** resulting sizes from transformation */
-        Dims Sizes;
-    };
-
-    /** Registered transforms */
-    std::vector<TransformInfo> m_TransformsInfo;
-
-    /** Self-check dims according to type, called right after DefineVariable and
-     * SetSelection.
-     * @param hint extra debugging info for the exception */
-    void CheckDimsCommon(const std::string hint) const;
-
     /** Self-check dims according to type, called from Engine before Write
      * @param hint extra debugging info for the exception */
     void CheckDimsBeforeWrite(const std::string hint) const;
@@ -149,9 +129,23 @@ public:
 private:
     const bool m_DebugMode = false;
 
+    Dims m_MemoryStart; ///< offset of memory selection
+    Dims m_MemoryCount; ///< subset of m_Shape (e.g. remove ghost points)
+
+    size_t m_StepStart = 0;
+    size_t m_StepCount = 1;
+
+    size_t m_AvailableStepsCount = 1;
+    size_t m_AvailableStepsStart = 0;
+
     void InitShapeType();
+
+    /** Self-check dims according to type, called right after DefineVariable and
+     *  SetSelection.
+     * @param hint extra debugging info for the exception */
+    void CheckDimsCommon(const std::string hint) const;
 };
 
-} // end namespace
+} // end namespace adios2
 
 #endif /* ADIOS2_CORE_VARIABLEBASE_H_ */
diff --git a/source/adios2/core/VariableCompound.cpp b/source/adios2/core/VariableCompound.cpp
index 8fee9b54b27b93878ec858c3fab41717249bb6bc..4a5147d2c2322ec756b3510a07ee99e8c75e3a56 100644
--- a/source/adios2/core/VariableCompound.cpp
+++ b/source/adios2/core/VariableCompound.cpp
@@ -26,8 +26,6 @@ VariableCompound::VariableCompound(const std::string name,
 {
 }
 
-void VariableCompound::ApplyTransforms() {}
-
 #define declare_template_instantiation(T)                                      \
     template void VariableCompound::InsertMember<T>(const std::string,         \
                                                     const size_t);
diff --git a/source/adios2/core/VariableCompound.h b/source/adios2/core/VariableCompound.h
index 70494e0e6968f6ee96dbfea8a41569510e31fc43..01b50db073ce06c0756e470dc61c305e766a8489 100644
--- a/source/adios2/core/VariableCompound.h
+++ b/source/adios2/core/VariableCompound.h
@@ -45,8 +45,6 @@ public:
 
     ~VariableCompound() = default;
 
-    void ApplyTransforms() final;
-
     /**
      * Inserts an Element into the compound struct definition
      * @param name
diff --git a/source/adios2/core/VariableCompound.tcc b/source/adios2/core/VariableCompound.tcc
index e53385ef3e546aec68ed51e9278cc75abe2860bb..c7f63c52d1de3611fa9825c8115a6b9ec894efb9 100644
--- a/source/adios2/core/VariableCompound.tcc
+++ b/source/adios2/core/VariableCompound.tcc
@@ -24,6 +24,6 @@ void VariableCompound::InsertMember(const std::string name, const size_t offset)
     m_Elements.push_back(Element{name, GetType<T>(), offset});
 }
 
-} // end namespace
+} // end namespace adios2
 
 #endif /* ADIOS2_CORE_VARIABLECOMPOUND_TCC_ */
diff --git a/source/adios2/engine/adios1/ADIOS1Reader.cpp b/source/adios2/engine/adios1/ADIOS1Reader.cpp
index ee2a068e1a09ad6c46e1a3c21a41199f9005838f..05ca115bb30db2369e9581a102d86dc07ce6fb18 100644
--- a/source/adios2/engine/adios1/ADIOS1Reader.cpp
+++ b/source/adios2/engine/adios1/ADIOS1Reader.cpp
@@ -9,6 +9,7 @@
  */
 
 #include "ADIOS1Reader.h"
+#include "ADIOS1Reader.tcc"
 
 #include <adios_error.h>
 
@@ -18,7 +19,7 @@ namespace adios2
 {
 
 ADIOS1Reader::ADIOS1Reader(IO &io, const std::string &name,
-                           const OpenMode openMode, MPI_Comm mpiComm)
+                           const Mode openMode, MPI_Comm mpiComm)
 : Engine("ADIOS1Reader", io, name, openMode, mpiComm)
 {
     m_EndMessage = " in call to IO Open ADIOS1Reader " + m_Name + "\n";
@@ -39,137 +40,13 @@ ADIOS1Reader::ADIOS1Reader(IO &io, const std::string &name,
 ADIOS1Reader::~ADIOS1Reader()
 {
     if (m_fh != nullptr)
+    {
         adios_read_close(m_fh);
+    }
     adios_read_finalize_method(m_ReadMethod);
 }
 
 // PRIVATE
-VariableBase *
-ADIOS1Reader::InquireVariableUnknown(const std::string &variableName,
-                                     const bool readIn)
-{
-    return nullptr; // not yet implemented
-}
-
-Variable<char> *
-ADIOS1Reader::InquireVariableChar(const std::string &variableName,
-                                  const bool readIn)
-{
-    return InquireVariableCommon<char>(variableName, readIn);
-}
-
-Variable<unsigned char> *
-ADIOS1Reader::InquireVariableUChar(const std::string &variableName,
-                                   const bool readIn)
-{
-    return InquireVariableCommon<unsigned char>(variableName, readIn);
-}
-
-Variable<short> *
-ADIOS1Reader::InquireVariableShort(const std::string &variableName,
-                                   const bool readIn)
-{
-    return InquireVariableCommon<short>(variableName, readIn);
-}
-
-Variable<unsigned short> *
-ADIOS1Reader::InquireVariableUShort(const std::string &variableName,
-                                    const bool readIn)
-{
-    return InquireVariableCommon<unsigned short>(variableName, readIn);
-}
-
-Variable<int> *ADIOS1Reader::InquireVariableInt(const std::string &variableName,
-                                                const bool readIn)
-{
-    return InquireVariableCommon<int>(variableName, readIn);
-}
-
-Variable<unsigned int> *
-ADIOS1Reader::InquireVariableUInt(const std::string &variableName,
-                                  const bool readIn)
-{
-    return InquireVariableCommon<unsigned int>(variableName, readIn);
-}
-
-Variable<long int> *
-ADIOS1Reader::InquireVariableLInt(const std::string &variableName,
-                                  const bool readIn)
-{
-    return InquireVariableCommon<long int>(variableName, readIn);
-}
-
-Variable<unsigned long int> *
-ADIOS1Reader::InquireVariableULInt(const std::string &variableName,
-                                   const bool readIn)
-{
-    return InquireVariableCommon<unsigned long int>(variableName, readIn);
-}
-
-Variable<long long int> *
-ADIOS1Reader::InquireVariableLLInt(const std::string &variableName,
-                                   const bool readIn)
-{
-    return InquireVariableCommon<long long int>(variableName, readIn);
-}
-
-Variable<unsigned long long int> *
-ADIOS1Reader::InquireVariableULLInt(const std::string &variableName,
-                                    const bool readIn)
-{
-    return InquireVariableCommon<unsigned long long int>(variableName, readIn);
-}
-
-Variable<float> *
-ADIOS1Reader::InquireVariableFloat(const std::string &variableName,
-                                   const bool readIn)
-{
-    return InquireVariableCommon<float>(variableName, readIn);
-}
-
-Variable<double> *
-ADIOS1Reader::InquireVariableDouble(const std::string &variableName,
-                                    const bool readIn)
-{
-    return InquireVariableCommon<double>(variableName, readIn);
-}
-
-Variable<long double> *
-ADIOS1Reader::InquireVariableLDouble(const std::string &variableName,
-                                     const bool readIn)
-{
-    return InquireVariableCommon<long double>(variableName, readIn);
-}
-
-Variable<std::complex<float>> *
-ADIOS1Reader::InquireVariableCFloat(const std::string &variableName,
-                                    const bool readIn)
-{
-    return InquireVariableCommon<std::complex<float>>(variableName, readIn);
-}
-
-Variable<std::complex<double>> *
-ADIOS1Reader::InquireVariableCDouble(const std::string &variableName,
-                                     const bool readIn)
-{
-    return InquireVariableCommon<std::complex<double>>(variableName, readIn);
-}
-
-Variable<std::complex<long double>> *
-ADIOS1Reader::InquireVariableCLDouble(const std::string &variableName,
-                                      const bool readIn)
-{
-    return InquireVariableCommon<std::complex<long double>>(variableName,
-                                                            readIn);
-}
-
-VariableCompound *
-ADIOS1Reader::InquireVariableCompound(const std::string &variableName,
-                                      const bool readIn)
-{
-    return nullptr;
-}
-
 void ADIOS1Reader::ScheduleReadCommon(const std::string &name, const Dims &offs,
                                       const Dims &ldims, const int fromStep,
                                       const int nSteps,
@@ -299,7 +176,7 @@ void ADIOS1Reader::Init()
 {
     if (m_DebugMode)
     {
-        if (m_OpenMode != OpenMode::Read)
+        if (m_OpenMode != Mode::Read)
         {
             throw std::invalid_argument(
                 "ERROR: ADIOS1Reader only supports OpenMode::r (read) access "
diff --git a/source/adios2/engine/adios1/ADIOS1Reader.h b/source/adios2/engine/adios1/ADIOS1Reader.h
index cf6f4606f8c48beaf66ef4f1b6e519056a7f3cd4..db9dd1c315c534b2589a4f1b6d64f71a2b3412c4 100644
--- a/source/adios2/engine/adios1/ADIOS1Reader.h
+++ b/source/adios2/engine/adios1/ADIOS1Reader.h
@@ -13,8 +13,6 @@
 #ifndef ADIOS2_ENGINE_ADIOS1_ADIOS1READER_H_
 #define ADIOS2_ENGINE_ADIOS1_ADIOS1READER_H_
 
-#include <iostream> //this must go away
-
 #include "adios2/ADIOSConfig.h"
 #include "adios2/core/ADIOS.h"
 #include "adios2/core/Engine.h"
@@ -49,7 +47,7 @@ public:
      * @param debugMode
      * @param hostLanguage
      */
-    ADIOS1Reader(IO &adios, const std::string &name, const OpenMode openMode,
+    ADIOS1Reader(IO &adios, const std::string &name, const Mode openMode,
                  MPI_Comm mpiComm);
 
     ~ADIOS1Reader();
@@ -74,48 +72,19 @@ private:
     void InitParameters() final;
     void InitTransports() final;
 
-    VariableBase *InquireVariableUnknown(const std::string &name,
-                                         const bool readIn) final;
-    Variable<char> *InquireVariableChar(const std::string &name,
-                                        const bool readIn) final;
-    Variable<unsigned char> *InquireVariableUChar(const std::string &name,
-                                                  const bool readIn) final;
-    Variable<short> *InquireVariableShort(const std::string &name,
-                                          const bool readIn) final;
-    Variable<unsigned short> *InquireVariableUShort(const std::string &name,
-                                                    const bool readIn) final;
-    Variable<int> *InquireVariableInt(const std::string &name,
-                                      const bool readIn) final;
-    Variable<unsigned int> *InquireVariableUInt(const std::string &name,
-                                                const bool readIn) final;
-    Variable<long int> *InquireVariableLInt(const std::string &name,
-                                            const bool readIn) final;
-    Variable<unsigned long int> *InquireVariableULInt(const std::string &name,
-                                                      const bool readIn) final;
-    Variable<long long int> *InquireVariableLLInt(const std::string &name,
-                                                  const bool readIn) final;
-    Variable<unsigned long long int> *
-    InquireVariableULLInt(const std::string &name, const bool readIn) final;
-
-    Variable<float> *InquireVariableFloat(const std::string &name,
-                                          const bool readIn) final;
-    Variable<double> *InquireVariableDouble(const std::string &name,
-                                            const bool readIn) final;
-    Variable<long double> *InquireVariableLDouble(const std::string &name,
-                                                  const bool readIn) final;
-    Variable<cfloat> *InquireVariableCFloat(const std::string &name,
-                                            const bool readIn) final;
-    Variable<cdouble> *InquireVariableCDouble(const std::string &name,
-                                              const bool readIn) final;
-    Variable<cldouble> *InquireVariableCLDouble(const std::string &name,
-                                                const bool readIn) final;
+#define declare(T, L)                                                          \
+    virtual Variable<T> *DoInquireVariable##L(const std::string &variableName) \
+        final;
+
+    ADIOS2_FOREACH_TYPE_2ARGS(declare)
+#undef declare
+
     /** Not yet implemented */
     VariableCompound *InquireVariableCompound(const std::string &name,
                                               const bool readIn);
 
     template <class T>
-    Variable<T> *InquireVariableCommon(const std::string &name,
-                                       const bool readIn);
+    Variable<T> *InquireVariableCommon(const std::string &name);
 
 #define declare_type(T)                                                        \
     void DoScheduleRead(Variable<T> &variable, const T *values) final;         \
diff --git a/source/adios2/engine/adios1/ADIOS1Reader.inl b/source/adios2/engine/adios1/ADIOS1Reader.inl
index d89062cbc0c48d49d1527d4079e28e455199e31f..70fdc27d87bdfc94ac69e1febf325da95400b626 100644
--- a/source/adios2/engine/adios1/ADIOS1Reader.inl
+++ b/source/adios2/engine/adios1/ADIOS1Reader.inl
@@ -18,19 +18,20 @@ namespace adios2
 {
 
 template <class T>
-Variable<T> *ADIOS1Reader::InquireVariableCommon(const std::string &name,
-                                                 const bool readIn)
+Variable<T> *
+ADIOS1Reader::InquireVariableCommon(const std::string &variableName)
 {
     // here read variable metadata (dimensions, type, etc.)...then create a
     // Variable like below:
     // Variable<T>& variable = m_ADIOS.DefineVariable<T>( m_Name + "/" +
     // name, )
     // return &variable; //return address if success
-    ADIOS_VARINFO *vi = adios_inq_var(m_fh, name.c_str());
+    ADIOS_VARINFO *vi = adios_inq_var(m_fh, variableName.c_str());
     adios2::Variable<T> *var = nullptr;
     if (vi != nullptr)
     {
-        CheckADIOS1TypeCompatibility(name, GetType<T>(), vi->type); // throws
+        CheckADIOS1TypeCompatibility(variableName, GetType<T>(),
+                                     vi->type); // throws
 
         if (vi->ndim > 0)
         {
@@ -72,7 +73,7 @@ Variable<T> *ADIOS1Reader::InquireVariableCommon(const std::string &name,
                     }
                 }
             }
-            var = &m_IO.DefineVariable<T>(name, gdims);
+            var = &m_IO.DefineVariable<T>(variableName, gdims);
             if (joinedread)
             {
                 var->m_ReadAsJoined = true;
@@ -81,7 +82,7 @@ Variable<T> *ADIOS1Reader::InquireVariableCommon(const std::string &name,
         else /* Scalars */
         {
             /* scalar variable but global value or local value*/
-            std::string aname = name + "/ReadAsArray";
+            std::string aname = variableName + "/ReadAsArray";
             bool isLocalValue = false;
             for (int i = 0; i < vi->nattrs; ++i)
             {
@@ -102,19 +103,19 @@ Variable<T> *ADIOS1Reader::InquireVariableCommon(const std::string &name,
                 }
                 if (changingDims)
                 {
-                    var = &m_IO.DefineVariable<T>(name, {IrregularDim});
+                    var = &m_IO.DefineVariable<T>(variableName, {IrregularDim});
                 }
                 else
                 {
                     var = &m_IO.DefineVariable<T>(
-                        name, {(unsigned int)vi->nblocks[0]});
+                        variableName, {(unsigned int)vi->nblocks[0]});
                 }
                 var->m_ReadAsLocalValue = true;
             }
             else
             {
                 /* Global value: store only one value */
-                var = &m_IO.DefineVariable<T>(name);
+                var = &m_IO.DefineVariable<T>(variableName);
                 if (var)
                 {
                     var->m_Data = std::vector<T>(1);
@@ -128,6 +129,6 @@ Variable<T> *ADIOS1Reader::InquireVariableCommon(const std::string &name,
     return var;
 }
 
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_ENGINE_ADIOS1_ADIOS1READER_INL_ */
diff --git a/source/adios2/engine/adios1/ADIOS1Reader.tcc b/source/adios2/engine/adios1/ADIOS1Reader.tcc
new file mode 100644
index 0000000000000000000000000000000000000000..64eca75dc10842d60bd9fa1665fec170d2d2a7aa
--- /dev/null
+++ b/source/adios2/engine/adios1/ADIOS1Reader.tcc
@@ -0,0 +1,29 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * ADIOS1Reader.tcc
+ *
+ *  Created on: Sep 20, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_ENGINE_ADIOS1_ADIOS1READER_TCC_
+#define ADIOS2_ENGINE_ADIOS1_ADIOS1READER_TCC_
+
+#include "ADIOS1Reader.h"
+
+namespace adios2
+{
+
+#define declare(T, L)                                                          \
+    Variable<T> *ADIOS1Reader::DoInquireVariable##L(                           \
+        const std::string &variableName)                                       \
+    {                                                                          \
+        return InquireVariableCommon<T>(variableName);                         \
+    }
+
+ADIOS2_FOREACH_TYPE_2ARGS(declare)
+#undef declare
+
+} // end namespace adios2
diff --git a/source/adios2/engine/adios1/ADIOS1Writer.cpp b/source/adios2/engine/adios1/ADIOS1Writer.cpp
index dd1470e7aa8bd27a04f44431e32f26dd560fb59d..b7ed3c3024f773ed83b5f00e01431a0c242115fe 100644
--- a/source/adios2/engine/adios1/ADIOS1Writer.cpp
+++ b/source/adios2/engine/adios1/ADIOS1Writer.cpp
@@ -23,7 +23,7 @@ namespace adios2
 {
 
 ADIOS1Writer::ADIOS1Writer(IO &io, const std::string &name,
-                           const OpenMode openMode, MPI_Comm mpiComm)
+                           const Mode openMode, MPI_Comm mpiComm)
 : Engine("ADIOS1Writer", io, name, openMode, mpiComm),
   m_ADIOS1(io.m_Name, name, mpiComm, io.m_DebugMode)
 {
diff --git a/source/adios2/engine/adios1/ADIOS1Writer.h b/source/adios2/engine/adios1/ADIOS1Writer.h
index 7fd895a686f6bb0e7b2dab2c39d1544f18421453..9f4a8e30d86a2c761e222006b74cf73e0d67439e 100644
--- a/source/adios2/engine/adios1/ADIOS1Writer.h
+++ b/source/adios2/engine/adios1/ADIOS1Writer.h
@@ -32,7 +32,7 @@ public:
      * @param method
      * @param debugMode
      */
-    ADIOS1Writer(IO &adios, const std::string &name, const OpenMode openMode,
+    ADIOS1Writer(IO &adios, const std::string &name, const Mode openMode,
                  MPI_Comm mpiComm);
 
     ~ADIOS1Writer() = default;
diff --git a/source/adios2/engine/bp/BPFileReader.cpp b/source/adios2/engine/bp/BPFileReader.cpp
index 8d5897340aeeb4a321e4b5f1f6b3faa4dd47e5a9..d48e4ed631f7fe961bbdb560a6f9dce3766d41aa 100644
--- a/source/adios2/engine/bp/BPFileReader.cpp
+++ b/source/adios2/engine/bp/BPFileReader.cpp
@@ -9,15 +9,15 @@
  */
 
 #include "BPFileReader.h"
-
-#include "adios2/helper/adiosFunctions.h" // CSVToVector
+#include "BPFileReader.tcc"
 
 namespace adios2
 {
 
-BPFileReader::BPFileReader(IO &io, const std::string &name,
-                           const OpenMode openMode, MPI_Comm mpiComm)
-: Engine("BPFileReader", io, name, openMode, mpiComm)
+BPFileReader::BPFileReader(IO &io, const std::string &name, const Mode openMode,
+                           MPI_Comm mpiComm)
+: Engine("BPFileReader", io, name, openMode, mpiComm),
+  m_BP1Reader(mpiComm, m_DebugMode), m_FileManager(mpiComm, m_DebugMode)
 {
     Init();
 }
@@ -29,128 +29,43 @@ void BPFileReader::Init()
 {
     if (m_DebugMode)
     {
-        if (m_OpenMode != OpenMode::Read)
+        if (m_OpenMode != Mode::Read)
         {
             throw std::invalid_argument(
-                "ERROR: BPFileReader only supports OpenMode::r from" + m_Name +
-                " " + m_EndMessage);
+                "ERROR: BPFileReader only supports OpenMode::Read from" +
+                m_Name + " " + m_EndMessage);
         }
     }
 
     InitTransports();
+    InitBuffers();
 }
 
-void BPFileReader::InitTransports() {}
-
-VariableBase *BPFileReader::InquireVariableUnknown(const std::string & /*name*/,
-                                                   const bool /*readIn*/)
-{
-    // not yet implemented
-    return nullptr;
-}
-
-Variable<char> *BPFileReader::InquireVariableChar(const std::string &name,
-                                                  const bool readIn)
-{
-    return InquireVariableCommon<char>(name, readIn);
-}
-
-Variable<unsigned char> *
-BPFileReader::InquireVariableUChar(const std::string &name, const bool readIn)
-{
-    return InquireVariableCommon<unsigned char>(name, readIn);
-}
-
-Variable<short> *BPFileReader::InquireVariableShort(const std::string &name,
-                                                    const bool readIn)
-{
-    return InquireVariableCommon<short>(name, readIn);
-}
-
-Variable<unsigned short> *
-BPFileReader::InquireVariableUShort(const std::string &name, const bool readIn)
-{
-    return InquireVariableCommon<unsigned short>(name, readIn);
-}
-
-Variable<int> *BPFileReader::InquireVariableInt(const std::string &name,
-                                                const bool readIn)
-{
-    return InquireVariableCommon<int>(name, readIn);
-}
-
-Variable<unsigned int> *
-BPFileReader::InquireVariableUInt(const std::string &name, const bool readIn)
-{
-    return InquireVariableCommon<unsigned int>(name, readIn);
-}
-
-Variable<long int> *BPFileReader::InquireVariableLInt(const std::string &name,
-                                                      const bool readIn)
-{
-    return InquireVariableCommon<long int>(name, readIn);
-}
-
-Variable<unsigned long int> *
-BPFileReader::InquireVariableULInt(const std::string &name, const bool readIn)
-{
-    return InquireVariableCommon<unsigned long int>(name, readIn);
-}
-
-Variable<long long int> *
-BPFileReader::InquireVariableLLInt(const std::string &name, const bool readIn)
-{
-    return InquireVariableCommon<long long int>(name, readIn);
-}
-
-Variable<unsigned long long int> *
-BPFileReader::InquireVariableULLInt(const std::string &name, const bool readIn)
-{
-    return InquireVariableCommon<unsigned long long int>(name, readIn);
-}
-
-Variable<float> *BPFileReader::InquireVariableFloat(const std::string &name,
-                                                    const bool readIn)
-{
-    return InquireVariableCommon<float>(name, readIn);
-}
-
-Variable<double> *BPFileReader::InquireVariableDouble(const std::string &name,
-                                                      const bool readIn)
+void BPFileReader::InitTransports()
 {
-    return InquireVariableCommon<double>(name, readIn);
+    // for now just use the name
+    //    const std::string
+    //    metadataFile(m_BP1Reader.GetBPMetadataFileName(m_Name));
+    //    m_FileManager.OpenFileTransport(metadataFile, adios2::Mode::Read,
+    //    Params(),
+    //                                    true);
 }
 
-Variable<long double> *
-BPFileReader::InquireVariableLDouble(const std::string &name, const bool readIn)
+void BPFileReader::InitBuffers()
 {
-    return InquireVariableCommon<long double>(name, readIn);
+    // here read indices
+    // pg index
+    // variables index
+    // attributes index
 }
 
-Variable<std::complex<float>> *
-BPFileReader::InquireVariableCFloat(const std::string &name, const bool readIn)
-{
-    return InquireVariableCommon<std::complex<float>>(name, readIn);
-}
-
-Variable<std::complex<double>> *
-BPFileReader::InquireVariableCDouble(const std::string &name, const bool readIn)
-{
-    return InquireVariableCommon<std::complex<double>>(name, readIn);
-}
-
-Variable<std::complex<long double>> *
-BPFileReader::InquireVariableCLDouble(const std::string &name,
-                                      const bool readIn)
-{
-    return InquireVariableCommon<std::complex<long double>>(name, readIn);
-}
-
-VariableCompound *
-BPFileReader::InquireVariableCompound(const std::string & /*name*/,
-                                      const bool /*readIn*/)
-{
-    return nullptr;
-}
+#define declare(T, L)                                                          \
+    Variable<T> *BPFileReader::DoInquireVariable##L(                           \
+        const std::string &variableName)                                       \
+    {                                                                          \
+        return InquireVariableCommon<T>(variableName);                         \
+    }
+ADIOS2_FOREACH_TYPE_2ARGS(declare)
+#undef declare
 
-} // end namespace adios
+} // end namespace adios2
diff --git a/source/adios2/engine/bp/BPFileReader.h b/source/adios2/engine/bp/BPFileReader.h
index e1942a5421dfba2b817df55772a1455ecd44c421..8cdc15827d3dc7d37281cb4bab2fc281876593c9 100644
--- a/source/adios2/engine/bp/BPFileReader.h
+++ b/source/adios2/engine/bp/BPFileReader.h
@@ -13,6 +13,8 @@
 
 #include "adios2/ADIOSConfig.h"
 #include "adios2/core/Engine.h"
+#include "adios2/toolkit/format/bp1/BP1.h" //format::BP1Reader
+#include "adios2/toolkit/transportman/TransportMan.h"
 
 namespace adios2
 {
@@ -22,9 +24,13 @@ class BPFileReader : public Engine
 
 public:
     /**
-     *
+     * Unique constructor
+     * @param io
+     * @param name
+     * @param openMode only read
+     * @param mpiComm
      */
-    BPFileReader(IO &io, const std::string &name, const OpenMode openMode,
+    BPFileReader(IO &io, const std::string &name, const Mode openMode,
                  MPI_Comm mpiComm);
 
     virtual ~BPFileReader() = default;
@@ -32,94 +38,23 @@ public:
     void Close(const int transportIndex = -1);
 
 private:
-    void Init(); ///< calls InitCapsules and InitTransports based on Method,
-                 /// called from constructor
-
-    void InitTransports(); ///< from Transports
-
-    VariableBase *InquireVariableUnknown(const std::string &variableName,
-                                         const bool readIn = true);
-
-    Variable<char> *InquireVariableChar(const std::string &variableName,
-                                        const bool readIn = true);
-
-    Variable<unsigned char> *
-    InquireVariableUChar(const std::string &variableName,
-                         const bool readIn = true);
-
-    Variable<short> *InquireVariableShort(const std::string &variableName,
-                                          const bool readIn = true);
-
-    Variable<unsigned short> *
-    InquireVariableUShort(const std::string &variableName,
-                          const bool readIn = true);
-
-    Variable<int> *InquireVariableInt(const std::string &variableName,
-                                      const bool readIn = true);
-
-    Variable<unsigned int> *InquireVariableUInt(const std::string &variableName,
-                                                const bool readIn = true);
-
-    Variable<long int> *InquireVariableLInt(const std::string &variableName,
-                                            const bool readIn = true);
+    format::BP1Reader m_BP1Reader;
+    transportman::TransportMan m_FileManager;
 
-    Variable<unsigned long int> *
-    InquireVariableULInt(const std::string &variableName,
-                         const bool readIn = true);
+    void Init();
+    void InitTransports();
+    void InitBuffers();
 
-    Variable<long long int> *
-    InquireVariableLLInt(const std::string &variableName,
-                         const bool readIn = true);
+#define declare(T, L)                                                          \
+    Variable<T> *DoInquireVariable##L(const std::string &variableName) final;
 
-    Variable<unsigned long long int> *
-    InquireVariableULLInt(const std::string &variableName,
-                          const bool readIn = true);
-
-    Variable<float> *InquireVariableFloat(const std::string &variableName,
-                                          const bool readIn = true);
-
-    Variable<double> *InquireVariableDouble(const std::string &variableName,
-                                            const bool readIn = true);
-    Variable<long double> *
-    InquireVariableLDouble(const std::string &variableName,
-                           const bool readIn = true);
-
-    Variable<std::complex<float>> *
-    InquireVariableCFloat(const std::string &variableName,
-                          const bool readIn = true);
-
-    Variable<std::complex<double>> *
-    InquireVariableCDouble(const std::string &variableName,
-                           const bool readIn = true);
-
-    Variable<std::complex<long double>> *
-    InquireVariableCLDouble(const std::string &variableName,
-                            const bool readIn = true);
-
-    /**
-     * Not implemented
-     * @param name
-     * @param readIn
-     * @return
-     */
-    VariableCompound *InquireVariableCompound(const std::string &variableName,
-                                              const bool readIn = true);
+    ADIOS2_FOREACH_TYPE_2ARGS(declare)
+#undef declare
 
     template <class T>
-    Variable<T> *InquireVariableCommon(const std::string &name,
-                                       const bool readIn)
-    {
-        std::cout << "Hello BPReaderCommon\n";
-
-        // here read variable metadata (dimensions, type, etc.)...then create a
-        // Variable like below:
-        // Variable<T>& variable = m_ADIOS.DefineVariable<T>( m_Name + "/" +
-        // name, )
-        // return &variable; //return address if success
-        return nullptr; // on failure
-    }
+    Variable<T> *InquireVariableCommon(const std::string &variableName);
 };
 
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_ENGINE_BP_BPFILEREADER_H_ */
diff --git a/source/adios2/engine/bp/BPFileReader.tcc b/source/adios2/engine/bp/BPFileReader.tcc
new file mode 100644
index 0000000000000000000000000000000000000000..e1a6f543e920601fb5e64f70cdcb7f406b34319d
--- /dev/null
+++ b/source/adios2/engine/bp/BPFileReader.tcc
@@ -0,0 +1,28 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * BPFileReader.tcc
+ *
+ *  Created on: Feb 27, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_ENGINE_BP_BPFILEREADER_TCC_
+#define ADIOS2_ENGINE_BP_BPFILEREADER_TCC_
+
+#include "BPFileReader.h"
+
+namespace adios2
+{
+
+template <class T>
+Variable<T> *
+BPFileReader::InquireVariableCommon(const std::string &variableName)
+{
+    return nullptr;
+}
+
+} // end namespace adios2
+
+#endif /* ADIOS2_ENGINE_BP_BPFILEREADER_TCC_ */
diff --git a/source/adios2/engine/bp/BPFileWriter.cpp b/source/adios2/engine/bp/BPFileWriter.cpp
index 175d9975645db538748c467d26635aaeeced01d5..1b87b84ec70c19ba89d112f6be9a4ea6316901ad 100644
--- a/source/adios2/engine/bp/BPFileWriter.cpp
+++ b/source/adios2/engine/bp/BPFileWriter.cpp
@@ -10,20 +10,23 @@
 
 #include "BPFileWriter.h"
 #include "BPFileWriter.tcc"
+#include <adios2/toolkit/transport/file/FileFStream.h>
+
+#include <iostream>
 
 #include "adios2/ADIOSMPI.h"
 #include "adios2/ADIOSMacros.h"
 #include "adios2/core/IO.h"
 #include "adios2/helper/adiosFunctions.h" //CheckIndexRange
-#include "adios2/toolkit/transport/file/FileStream.h"
 
 namespace adios2
 {
 
-BPFileWriter::BPFileWriter(IO &io, const std::string &name,
-                           const OpenMode openMode, MPI_Comm mpiComm)
+BPFileWriter::BPFileWriter(IO &io, const std::string &name, const Mode openMode,
+                           MPI_Comm mpiComm)
 : Engine("BPFileWriter", io, name, openMode, mpiComm),
-  m_BP1Writer(mpiComm, m_DebugMode), m_TransportsManager(mpiComm, m_DebugMode)
+  m_BP1BuffersWriter(mpiComm, m_DebugMode),
+  m_FileManager(mpiComm, m_DebugMode)
 {
     m_EndMessage = " in call to IO Open BPFileWriter " + m_Name + "\n";
     Init();
@@ -48,16 +51,16 @@ ADIOS2_FOREACH_TYPE_1ARG(declare_type)
 
 void BPFileWriter::Advance(const float /*timeout_sec*/)
 {
-    m_BP1Writer.Advance(m_IO);
+    m_BP1BuffersWriter.Advance(m_IO);
 }
 
 void BPFileWriter::Close(const int transportIndex)
 {
     if (m_DebugMode)
     {
-        if (!m_TransportsManager.CheckTransportIndex(transportIndex))
+        if (!m_FileManager.CheckTransportIndex(transportIndex))
         {
-            auto transportsSize = m_TransportsManager.m_Transports.size();
+            auto transportsSize = m_FileManager.m_Transports.size();
             throw std::invalid_argument(
                 "ERROR: transport index " + std::to_string(transportIndex) +
                 " outside range, -1 (default) to " +
@@ -65,26 +68,32 @@ void BPFileWriter::Close(const int transportIndex)
         }
     }
 
-    // close bp buffer by flattening data and metadata
-    m_BP1Writer.Close(m_IO);
+    // close bp buffer by serializing data and metadata
+    m_BP1BuffersWriter.Close(m_IO);
     // send data to corresponding transports
-    m_TransportsManager.WriteFiles(m_BP1Writer.m_HeapBuffer.GetData(),
-                                   m_BP1Writer.m_HeapBuffer.m_DataPosition,
+    m_FileManager.WriteFiles(m_BP1BuffersWriter.m_Data.m_Buffer.data(),
+                                   m_BP1BuffersWriter.m_Data.m_Position,
                                    transportIndex);
 
-    m_TransportsManager.CloseFiles(transportIndex);
+    m_FileManager.CloseFiles(transportIndex);
 
-    if (m_BP1Writer.m_Profiler.IsActive &&
-        m_TransportsManager.AllTransportsClosed())
+    if (m_BP1BuffersWriter.m_Profiler.IsActive &&
+        m_FileManager.AllTransportsClosed())
     {
         WriteProfilingJSONFile();
     }
+
+    if (m_BP1BuffersWriter.m_CollectiveMetadata &&
+        m_FileManager.AllTransportsClosed())
+    {
+        m_BP1BuffersWriter.AggregateCollectiveMetadata();
+    }
 }
 
 // PRIVATE FUNCTIONS
 void BPFileWriter::InitParameters()
 {
-    m_BP1Writer.InitParameters(m_IO.m_Parameters);
+    m_BP1BuffersWriter.InitParameters(m_IO.m_Parameters);
 }
 
 void BPFileWriter::InitTransports()
@@ -98,19 +107,19 @@ void BPFileWriter::InitTransports()
     }
 
     // Names are std::vector<std::string>
-    auto transportsNames = m_TransportsManager.GetFilesBaseNames(
+    auto transportsNames = m_FileManager.GetFilesBaseNames(
         m_Name, m_IO.m_TransportsParameters);
-    auto bpBaseNames = m_BP1Writer.GetBPBaseNames(transportsNames);
-    auto bpNames = m_BP1Writer.GetBPNames(transportsNames);
+    auto bpBaseNames = m_BP1BuffersWriter.GetBPBaseNames(transportsNames);
+    auto bpNames = m_BP1BuffersWriter.GetBPNames(transportsNames);
 
-    m_TransportsManager.OpenFiles(bpBaseNames, bpNames, m_OpenMode,
+    m_FileManager.OpenFiles(bpBaseNames, bpNames, m_OpenMode,
                                   m_IO.m_TransportsParameters,
-                                  m_BP1Writer.m_Profiler.IsActive);
+                                  m_BP1BuffersWriter.m_Profiler.IsActive);
 }
 
 void BPFileWriter::InitBPBuffer()
 {
-    if (m_OpenMode == OpenMode::Append)
+    if (m_OpenMode == Mode::Append)
     {
         throw std::invalid_argument(
             "ADIOS2: OpenMode Append hasn't been implemented, yet");
@@ -118,31 +127,32 @@ void BPFileWriter::InitBPBuffer()
     }
     else
     {
-        m_BP1Writer.WriteProcessGroupIndex(
-            m_IO.m_HostLanguage, m_TransportsManager.GetTransportsTypes());
+        m_BP1BuffersWriter.WriteProcessGroupIndex(
+            m_IO.m_HostLanguage, m_FileManager.GetTransportsTypes());
     }
 }
 
 void BPFileWriter::WriteProfilingJSONFile()
 {
-    auto transportTypes = m_TransportsManager.GetTransportsTypes();
-    auto transportProfilers = m_TransportsManager.GetTransportsProfilers();
+    auto transportTypes = m_FileManager.GetTransportsTypes();
+    auto transportProfilers = m_FileManager.GetTransportsProfilers();
 
-    const std::string lineJSON(
-        m_BP1Writer.GetRankProfilingJSON(transportTypes, transportProfilers));
+    const std::string lineJSON(m_BP1BuffersWriter.GetRankProfilingJSON(
+                                   transportTypes, transportProfilers) +
+                               ",\n");
 
-    const std::string profilingJSON(
-        m_BP1Writer.AggregateProfilingJSON(lineJSON));
+    const std::vector<char> profilingJSON(
+        m_BP1BuffersWriter.AggregateProfilingJSON(lineJSON));
 
-    if (m_BP1Writer.m_BP1Aggregator.m_RankMPI == 0)
+    if (m_BP1BuffersWriter.m_BP1Aggregator.m_RankMPI == 0)
     {
-        transport::FileStream profilingJSONStream(m_MPIComm, m_DebugMode);
-        auto bpBaseNames = m_BP1Writer.GetBPBaseNames({m_Name});
+        transport::FileFStream profilingJSONStream(m_MPIComm, m_DebugMode);
+        auto bpBaseNames = m_BP1BuffersWriter.GetBPBaseNames({m_Name});
         profilingJSONStream.Open(bpBaseNames[0] + "/profiling.json",
-                                 OpenMode::Write);
-        profilingJSONStream.Write(profilingJSON.c_str(), profilingJSON.size());
+                                 Mode::Write);
+        profilingJSONStream.Write(profilingJSON.data(), profilingJSON.size());
         profilingJSONStream.Close();
     }
 }
 
-} // end namespace adios
+} // end namespace adios2
diff --git a/source/adios2/engine/bp/BPFileWriter.h b/source/adios2/engine/bp/BPFileWriter.h
index bb7d552650a6a70132522af22fc8d86595696211..38fddd63e26030b0b40d62d532afb3118fd075bd 100644
--- a/source/adios2/engine/bp/BPFileWriter.h
+++ b/source/adios2/engine/bp/BPFileWriter.h
@@ -29,7 +29,7 @@ public:
      * @param openMode w (supported), r, a from OpenMode in ADIOSTypes.h
      * @param mpiComm MPI communicator
      */
-    BPFileWriter(IO &io, const std::string &name, const OpenMode openMode,
+    BPFileWriter(IO &io, const std::string &name, const Mode openMode,
                  MPI_Comm mpiComm);
 
     ~BPFileWriter();
@@ -48,13 +48,10 @@ public:
 
 private:
     /** Single object controlling BP buffering */
-    format::BP1Writer m_BP1Writer;
+    format::BP1Writer m_BP1BuffersWriter;
 
-    /** single object controlling a vector of Transports from IO AddTransport */
-    transportman::TransportMan m_TransportsManager;
-
-    /** true: due to buffer overflow, move to transports manager */
-    bool m_DoTransportFlush = false;
+    /** Single object controlling a vector of Transports from IO AddTransport */
+    transportman::TransportMan m_FileManager;
 
     void Init() final;
 
@@ -62,7 +59,7 @@ private:
     void InitParameters() final;
     /** Parses transports and parameters from IO AddTransport */
     void InitTransports() final;
-
+    /** Allocates memory and starts a PG group */
     void InitBPBuffer();
 
 #define declare_type(T)                                                        \
@@ -83,6 +80,6 @@ private:
     void WriteProfilingJSONFile();
 };
 
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_ENGINE_BP_BPFILEWRITER_H_ */
diff --git a/source/adios2/engine/bp/BPFileWriter.tcc b/source/adios2/engine/bp/BPFileWriter.tcc
index d6ccde49cd61661e3bf1b5ec758e3306660c9292..7f012976a9795fdf6b872f708184ef8def88cfe2 100644
--- a/source/adios2/engine/bp/BPFileWriter.tcc
+++ b/source/adios2/engine/bp/BPFileWriter.tcc
@@ -7,6 +7,8 @@
  *  Created on: May 22, 2017
  *      Author: William F Godoy godoywf@ornl.gov
  */
+#ifndef ADIOS2_ENGINE_BP_BPFILEWRITER_TCC_
+#define ADIOS2_ENGINE_BP_BPFILEWRITER_TCC_
 
 #include "BPFileWriter.h"
 
@@ -21,40 +23,39 @@ void BPFileWriter::DoWriteCommon(Variable<T> &variable, const T *values)
     m_WrittenVariables.insert(variable.m_Name);
 
     // if first timestep Write create a new pg index
-    if (!m_BP1Writer.m_MetadataSet.DataPGIsOpen)
+    if (!m_BP1BuffersWriter.m_MetadataSet.DataPGIsOpen)
     {
-        m_BP1Writer.WriteProcessGroupIndex(
-            m_IO.m_HostLanguage, m_TransportsManager.GetTransportsTypes());
+        m_BP1BuffersWriter.WriteProcessGroupIndex(
+            m_IO.m_HostLanguage, m_FileManager.GetTransportsTypes());
     }
 
-    const size_t oldSize = m_BP1Writer.m_HeapBuffer.GetDataSize();
-
     format::BP1Base::ResizeResult resizeResult =
-        m_BP1Writer.ResizeBuffer(variable);
-
-    const size_t newSize = m_BP1Writer.m_HeapBuffer.GetDataSize();
+        m_BP1BuffersWriter.ResizeBuffer(variable);
 
     if (resizeResult == format::BP1Base::ResizeResult::Flush)
     {
-        m_BP1Writer.Flush(m_IO);
-        auto &heapBuffer = m_BP1Writer.m_HeapBuffer;
+        m_BP1BuffersWriter.Flush(m_IO);
+        auto &buffer = m_BP1BuffersWriter.m_Data.m_Buffer;
+        auto &position = m_BP1BuffersWriter.m_Data.m_Position;
 
-        m_TransportsManager.WriteFiles(heapBuffer.GetData(),
-                                       heapBuffer.m_DataPosition);
+        m_FileManager.WriteFiles(buffer.data(), position);
         // set relative position to zero
-        heapBuffer.m_DataPosition = 0;
-        // reset buffer to zero values
-        heapBuffer.m_Data.assign(heapBuffer.GetDataSize(), '\0');
+        position = 0;
+        // reset buffer to zero values to current size
+        buffer.assign(buffer.size(), '\0');
 
-        m_BP1Writer.WriteProcessGroupIndex(
-            m_IO.m_HostLanguage, m_TransportsManager.GetTransportsTypes());
+        // new group index
+        m_BP1BuffersWriter.WriteProcessGroupIndex(
+            m_IO.m_HostLanguage, m_FileManager.GetTransportsTypes());
     }
 
     // WRITE INDEX to data buffer and metadata structure (in memory)//
-    m_BP1Writer.WriteVariableMetadata(variable);
-    m_BP1Writer.WriteVariablePayload(variable);
+    m_BP1BuffersWriter.WriteVariableMetadata(variable);
+    m_BP1BuffersWriter.WriteVariablePayload(variable);
 
     variable.m_AppValues = nullptr; // not needed after write
 }
 
-} // end namespace adios
+} // end namespace adios2
+
+#endif /* ADIOS2_ENGINE_BP_BPFILEWRITER_TCC_ */
diff --git a/source/adios2/engine/dataman/DataManReader.cpp b/source/adios2/engine/dataman/DataManReader.cpp
index 2f7290e75d8c77a3818d6dc9b83d97a0f9437f91..65c0d99f7bb910c2b5b8cad7b14f37747468531c 100644
--- a/source/adios2/engine/dataman/DataManReader.cpp
+++ b/source/adios2/engine/dataman/DataManReader.cpp
@@ -16,7 +16,7 @@ namespace adios2
 {
 
 DataManReader::DataManReader(IO &io, const std::string &name,
-                             const OpenMode openMode, MPI_Comm mpiComm)
+                             const Mode openMode, MPI_Comm mpiComm)
 : Engine("DataManReader", io, name, openMode, mpiComm)
 {
     m_EndMessage = " in call to IO Open DataManReader " + m_Name + "\n";
diff --git a/source/adios2/engine/dataman/DataManReader.h b/source/adios2/engine/dataman/DataManReader.h
index 51b41e5ba2ad08291d66e10ec1e5448b1f1541fd..aa77895de25a2e37ff0e19472be31a5fffe73339 100644
--- a/source/adios2/engine/dataman/DataManReader.h
+++ b/source/adios2/engine/dataman/DataManReader.h
@@ -36,7 +36,7 @@ public:
      * @param nthreads
      */
     using json = nlohmann::json;
-    DataManReader(IO &io, const std::string &name, const OpenMode openMode,
+    DataManReader(IO &io, const std::string &name, const Mode openMode,
                   MPI_Comm mpiComm);
 
     virtual ~DataManReader() = default;
diff --git a/source/adios2/engine/dataman/DataManWriter.cpp b/source/adios2/engine/dataman/DataManWriter.cpp
index 34e61c34f65e2338c8f33b987a08d927771bb55a..2b23bd9f6615dcfe34f74e84883fb791907a75fa 100644
--- a/source/adios2/engine/dataman/DataManWriter.cpp
+++ b/source/adios2/engine/dataman/DataManWriter.cpp
@@ -19,7 +19,7 @@ namespace adios2
 {
 
 DataManWriter::DataManWriter(IO &io, const std::string &name,
-                             const OpenMode openMode, MPI_Comm mpiComm)
+                             const Mode openMode, MPI_Comm mpiComm)
 : Engine("DataManWriter", io, name, openMode, mpiComm)
 {
     m_EndMessage = ", in call to Open DataManWriter\n";
diff --git a/source/adios2/engine/dataman/DataManWriter.h b/source/adios2/engine/dataman/DataManWriter.h
index 2f829ec40beee06be296d1dc25ab189eaa308d87..a2357a35bb4e8e919d4dceef3bbea853958007d0 100644
--- a/source/adios2/engine/dataman/DataManWriter.h
+++ b/source/adios2/engine/dataman/DataManWriter.h
@@ -28,7 +28,7 @@ class DataManWriter : public Engine
 public:
     using json = nlohmann::json;
 
-    DataManWriter(IO &io, const std::string &name, const OpenMode openMode,
+    DataManWriter(IO &io, const std::string &name, const Mode openMode,
                   MPI_Comm mpiComm);
 
     virtual ~DataManWriter() = default;
diff --git a/source/adios2/engine/hdf5/HDF5ReaderP.cpp b/source/adios2/engine/hdf5/HDF5ReaderP.cpp
index 985514e9bdc0a640dc631b974c06230fd87c790f..c210acafd2b4cb6ff908ca0a1efdb0899c95bd50 100644
--- a/source/adios2/engine/hdf5/HDF5ReaderP.cpp
+++ b/source/adios2/engine/hdf5/HDF5ReaderP.cpp
@@ -16,7 +16,7 @@ namespace adios2
 {
 
 HDF5ReaderP::HDF5ReaderP(IO &io, const std::string &name,
-                         const OpenMode openMode, MPI_Comm mpiComm)
+                         const Mode openMode, MPI_Comm mpiComm)
 : Engine("HDF5Reader", io, name, openMode, mpiComm), m_H5File(io.m_DebugMode)
 {
     m_EndMessage = ", in call to IO HDF5Reader Open " + m_Name + "\n";
@@ -29,7 +29,7 @@ bool HDF5ReaderP::IsValid()
 {
     bool isValid = false;
 
-    if (m_OpenMode != OpenMode::Read)
+    if (m_OpenMode != Mode::Read)
     {
         return isValid;
     }
@@ -41,7 +41,7 @@ bool HDF5ReaderP::IsValid()
 }
 void HDF5ReaderP::Init()
 {
-    if (m_OpenMode != OpenMode::Read)
+    if (m_OpenMode != Mode::Read)
     {
         throw std::invalid_argument(
             "ERROR: HDF5Reader only supports OpenMode::Read "
diff --git a/source/adios2/engine/hdf5/HDF5ReaderP.h b/source/adios2/engine/hdf5/HDF5ReaderP.h
index 28e16631f3cf53c23b2bf5c8a2c68186cee92263..3365185c5c545096a1816057cfbe1324bc34973c 100644
--- a/source/adios2/engine/hdf5/HDF5ReaderP.h
+++ b/source/adios2/engine/hdf5/HDF5ReaderP.h
@@ -29,7 +29,7 @@ public:
      * @param mpiComm
      * @param method
      */
-    HDF5ReaderP(IO &adios, const std::string &name, const OpenMode openMode,
+    HDF5ReaderP(IO &adios, const std::string &name, const Mode openMode,
                 MPI_Comm mpiComm);
 
     ~HDF5ReaderP();
diff --git a/source/adios2/engine/hdf5/HDF5WriterP.cpp b/source/adios2/engine/hdf5/HDF5WriterP.cpp
index 9c3979477e423a016c4fd7a8c4e1f8597beed42b..e4948ba4958495554fe12317e09a5bc1694a4de1 100644
--- a/source/adios2/engine/hdf5/HDF5WriterP.cpp
+++ b/source/adios2/engine/hdf5/HDF5WriterP.cpp
@@ -17,7 +17,7 @@ namespace adios2
 {
 
 HDF5WriterP::HDF5WriterP(IO &io, const std::string &name,
-                         const OpenMode openMode, MPI_Comm mpiComm)
+                         const Mode openMode, MPI_Comm mpiComm)
 : Engine("HDF5Writer", io, name, openMode, mpiComm), m_H5File(io.m_DebugMode)
 {
     m_EndMessage = ", in call to IO HDF5Writer Open " + m_Name + "\n";
@@ -29,7 +29,7 @@ HDF5WriterP::~HDF5WriterP() { Close(); }
 // PRIVATE
 void HDF5WriterP::Init()
 {
-    if (m_OpenMode != OpenMode::Write && m_OpenMode != OpenMode::Append)
+    if (m_OpenMode != Mode::Write && m_OpenMode != Mode::Append)
     {
         throw std::invalid_argument(
             "ERROR: HDF5Writer only support OpenMode::Write or "
diff --git a/source/adios2/engine/hdf5/HDF5WriterP.h b/source/adios2/engine/hdf5/HDF5WriterP.h
index 2bf07d4c9e2ac4fcc9bd5db4b87e028b9e35dd68..a573b24b052cf77c25e634bd0421d7360197310c 100644
--- a/source/adios2/engine/hdf5/HDF5WriterP.h
+++ b/source/adios2/engine/hdf5/HDF5WriterP.h
@@ -33,7 +33,7 @@ public:
      * @param mpiComm
      * @param method
      */
-    HDF5WriterP(IO &io, const std::string &name, const OpenMode openMode,
+    HDF5WriterP(IO &io, const std::string &name, const Mode openMode,
                 MPI_Comm mpiComm);
 
     ~HDF5WriterP();
diff --git a/source/adios2/engine/plugin/PluginEngine.cpp b/source/adios2/engine/plugin/PluginEngine.cpp
index c81aa060fa61b6e8b135d801f9e1682f0b57eb6d..ee55eced0f36d20c1490248042aa7a16faf8056f 100644
--- a/source/adios2/engine/plugin/PluginEngine.cpp
+++ b/source/adios2/engine/plugin/PluginEngine.cpp
@@ -51,7 +51,7 @@ void PluginEngine::RegisterPlugin(const std::string pluginName,
 /******************************************************************************/
 
 PluginEngine::PluginEngine(IO &io, const std::string &name,
-                           const OpenMode openMode, MPI_Comm mpiComm)
+                           const Mode openMode, MPI_Comm mpiComm)
 : Engine("Plugin", io, name, openMode, mpiComm), m_Impl(new Impl)
 {
     Init();
diff --git a/source/adios2/engine/plugin/PluginEngine.h b/source/adios2/engine/plugin/PluginEngine.h
index 290f04efdab7b4d213ffb12dea2451e8b149f2b2..b4d74e368a531f683c3d68c6c9eacf7e2817f5cf 100644
--- a/source/adios2/engine/plugin/PluginEngine.h
+++ b/source/adios2/engine/plugin/PluginEngine.h
@@ -37,7 +37,7 @@ public:
     // Function pointers used for the plugin factory methods
 
     using EngineCreatePtr = std::add_pointer<PluginEngineInterface *(
-        IO &, const std::string &, const OpenMode, MPI_Comm)>::type;
+        IO &, const std::string &, const Mode, MPI_Comm)>::type;
     using EngineDestroyPtr =
         std::add_pointer<void(PluginEngineInterface *)>::type;
     using EngineCreateFun =
@@ -62,7 +62,7 @@ public:
     static void RegisterPlugin(const std::string name);
 
 public:
-    PluginEngine(IO &io, const std::string &name, const OpenMode openMode,
+    PluginEngine(IO &io, const std::string &name, const Mode openMode,
                  MPI_Comm mpiComm);
     virtual ~PluginEngine();
 
diff --git a/source/adios2/engine/plugin/PluginEngine.inl b/source/adios2/engine/plugin/PluginEngine.inl
index e28cbd8b327c306a64cb57bc4b83bc830ee74653..f38cc97c5aa4261acf99eb88e0d42e980c8643c2 100644
--- a/source/adios2/engine/plugin/PluginEngine.inl
+++ b/source/adios2/engine/plugin/PluginEngine.inl
@@ -23,7 +23,7 @@ template <typename T>
 void PluginEngine::RegisterPlugin(const std::string name)
 {
     EngineCreateFun createFun =
-        [](IO &io, const std::string &name, const OpenMode openMode,
+        [](IO &io, const std::string &name, const Mode openMode,
            MPI_Comm mpiComm) -> PluginEngineInterface * {
         return new T(io, name, openMode, mpiComm);
     };
diff --git a/source/adios2/engine/plugin/PluginEngineInterface.cpp b/source/adios2/engine/plugin/PluginEngineInterface.cpp
index a6e20d69668f2e31f41c4deabe0319c130abeed4..6cbc955e718f00fb83ab571bf2bc9d122a9c2d0f 100644
--- a/source/adios2/engine/plugin/PluginEngineInterface.cpp
+++ b/source/adios2/engine/plugin/PluginEngineInterface.cpp
@@ -14,7 +14,7 @@ namespace adios2
 {
 
 PluginEngineInterface::PluginEngineInterface(IO &io, const std::string &name,
-                                             const OpenMode openMode,
+                                             const Mode openMode,
                                              MPI_Comm mpiComm)
 : Engine("PluginInterface", io, name, openMode, mpiComm)
 {
diff --git a/source/adios2/engine/plugin/PluginEngineInterface.h b/source/adios2/engine/plugin/PluginEngineInterface.h
index 20d9e9c144f6b348528cf142856826b66ce24623..b89846adb5274ae0bdd0516ea8a9e8e5e9c022ba 100644
--- a/source/adios2/engine/plugin/PluginEngineInterface.h
+++ b/source/adios2/engine/plugin/PluginEngineInterface.h
@@ -32,7 +32,7 @@ class PluginEngineInterface : public Engine
 
 public:
     PluginEngineInterface(IO &io, const std::string &name,
-                          const OpenMode openMode, MPI_Comm mpiComm);
+                          const Mode openMode, MPI_Comm mpiComm);
     virtual ~PluginEngineInterface() = default;
 };
 
diff --git a/source/adios2/helper/adiosMPIFunctions.cpp b/source/adios2/helper/adiosMPIFunctions.cpp
index bd550b00ef5c2e1fb0f4baaa9f83a3a8da49cbd3..48696edfd11a6cca9d58aaa4feabe5ef9249f23b 100644
--- a/source/adios2/helper/adiosMPIFunctions.cpp
+++ b/source/adios2/helper/adiosMPIFunctions.cpp
@@ -8,6 +8,7 @@
  *      Author: William F Godoy godoywf@ornl.gov
  */
 #include "adiosMPIFunctions.h"
+#include "adiosMPIFunctions.tcc"
 
 #include "adios2/ADIOSMPI.h"
 #include "adios2/ADIOSTypes.h"
@@ -15,32 +16,17 @@
 namespace adios2
 {
 
-std::string BroadcastString(const std::string &input, MPI_Comm mpiComm,
-                            const int rankSource)
+std::vector<int> GetGathervDisplacements(const size_t *counts,
+                                         const size_t countsSize)
 {
-    int rank;
-    MPI_Comm_rank(mpiComm, &rank);
-    size_t length = 0;
-    std::string output;
+    std::vector<int> displacements(countsSize);
+    displacements[0] = 0;
 
-    if (rank == rankSource)
+    for (size_t i = 1; i < countsSize; ++i)
     {
-        length = input.size();
-        MPI_Bcast(&length, 1, ADIOS2_MPI_SIZE_T, rankSource, mpiComm);
-
-        MPI_Bcast(const_cast<char *>(input.data()), length, MPI_CHAR,
-                  rankSource, mpiComm);
-
-        return input;
-    }
-    else
-    {
-        MPI_Bcast(&length, 1, ADIOS2_MPI_SIZE_T, rankSource, mpiComm);
-        output.resize(length);
-        MPI_Bcast(const_cast<char *>(output.data()), length, MPI_CHAR,
-                  rankSource, mpiComm);
+        displacements[i] = displacements[i - 1] + counts[i - 1];
     }
-    return output;
+    return displacements;
 }
 
 } // end namespace adios2
diff --git a/source/adios2/helper/adiosMPIFunctions.h b/source/adios2/helper/adiosMPIFunctions.h
index a79345d6af4b735a57f718887c6d21f38b8878bb..320ae41a8d320cd8b5207f7d2306034b1e28dacc 100644
--- a/source/adios2/helper/adiosMPIFunctions.h
+++ b/source/adios2/helper/adiosMPIFunctions.h
@@ -8,11 +8,12 @@
  *      Author: William F Godoy godoywf@ornl.gov
  */
 
-#ifndef ADIOS2_HELPER_ADIOMPIFUNCTIONS_H_
-#define ADIOS2_HELPER_ADIOMPIFUNCTIONS_H_
+#ifndef ADIOS2_HELPER_ADIOSMPIFUNCTIONS_H_
+#define ADIOS2_HELPER_ADIOSMPIFUNCTIONS_H_
 
 /// \cond EXCLUDE_FROM_DOXYGEN
 #include <string>
+#include <vector>
 /// \endcond
 
 #include "adios2/ADIOSMPICommOnly.h"
@@ -20,17 +21,76 @@
 namespace adios2
 {
 
+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);
+
+template <class T>
+T ReduceValues(const T source, MPI_Comm mpiComm, MPI_Op operation = MPI_SUM,
+               const int rankDestination = 0);
+
 /**
- * rankSource: owns a string and broadcast to all other ranks
- * Others: receive std::vector<char> and copy to a string
+ * Gather a single source value from each ranks and forms a vector in
+ * rankDestination
+ * @param sourceSize input from each rank
  * @param mpiComm MPI communicator defining all ranks and size domain
- * @param input string input from rankSource
- * @param rankSource rank that broadcast the string, (default = 0)
- * @return input contents for each rank
+ * @param rankDestination root, where all sizes are gathered in the returned
+ * vector
+ * @return in rankDestination: aggregated vector<T>, others: empty
+ */
+template <class T>
+std::vector<T> GatherValues(const T source, MPI_Comm mpiComm,
+                            const int rankDestination = 0);
+
+/**
+ * Gather equal size arrays
+ * @param source
+ * @param sourceCount
+ * @param destination
+ * @param mpiComm
+ * @param rankDestination
+ */
+template <class T>
+void GatherArrays(const T *source, const size_t sourceCount, T *destination,
+                  MPI_Comm mpiComm, const int rankDestination = 0);
+
+/**
+ * Gather arrays of the same type into a destination (must be pre-allocated)
+ * if countsSize == 1, calls MPI_Gather, otherwise calls MPI_Gatherv.
+ * This function must be specialized for each MPI_Type.
+ * @param source  input from each rank
+ * @param counts  counts for each source
+ * @param countsSize number of counts
+ * @param destination resulting gathered buffer in rankDestination, unchaged in
+ * others
+ * @param mpiComm communicator establishing the domain
+ * @param rankDestination rank in which arrays are gathered (root)
  */
-std::string BroadcastString(const std::string &input, MPI_Comm mpiComm,
-                            const int rankSource = 0);
+template <class T>
+void GathervArrays(const T *source, const size_t sourceCount,
+                   const size_t *counts, const size_t countsSize,
+                   T *destination, MPI_Comm mpiComm,
+                   const int rankDestination = 0);
+
+template <class T>
+void GathervVectors(const std::vector<T> &in, std::vector<T> &out,
+                    size_t &position, MPI_Comm mpiComm,
+                    const int rankDestination = 0);
+
+/**
+ * Gets the displacements (offsets, start) for each
+ * @param counts
+ * @param countsSize
+ * @return
+ */
+std::vector<int> GetGathervDisplacements(const size_t *counts,
+                                         const size_t countsSize);
 
 } // end namespace adios2
 
+#include "adiosMPIFunctions.inl"
+
 #endif /* ADIOS2_HELPER_ADIOMPIFUNCTIONS_H_ */
diff --git a/source/adios2/helper/adiosMPIFunctions.inl b/source/adios2/helper/adiosMPIFunctions.inl
new file mode 100644
index 0000000000000000000000000000000000000000..cb0992549a677ed3101ad379179db45551ff3fea
--- /dev/null
+++ b/source/adios2/helper/adiosMPIFunctions.inl
@@ -0,0 +1,70 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * adiosMPIFunctions.inl
+ *
+ *  Created on: Sep 7, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_HELPER_ADIOSMPIFUNCTIONS_INL_
+#define ADIOS2_HELPER_ADIOSMPIFUNCTIONS_INL_
+#ifndef ADIOS2_HELPER_ADIOSMPIFUNCTIONS_H_
+#error "Inline file should only be included from it's header, never on it's own"
+#endif
+
+#include <numeric> //std::accumulate
+
+namespace adios2
+{
+// GatherValues specializations
+template <class T>
+std::vector<T> GatherValues(const T source, MPI_Comm mpiComm,
+                            const int rankDestination)
+{
+    constexpr size_t count = 1;
+    int rank, size;
+    MPI_Comm_rank(mpiComm, &rank);
+    MPI_Comm_size(mpiComm, &size);
+
+    std::vector<T> output;
+
+    if (rank == rankDestination) // pre-allocate in destination rank
+    {
+        output.resize(size);
+    }
+
+    T sourceCopy = source; // so we can have an address for rvalues
+    GatherArrays(&sourceCopy, 1, output.data(), mpiComm, rankDestination);
+
+    return output;
+}
+
+template <class T>
+void GathervVectors(const std::vector<T> &in, std::vector<T> &out,
+                    size_t &position, MPI_Comm mpiComm,
+                    const int rankDestination)
+{
+    const size_t inSize = in.size();
+    std::vector<size_t> counts = GatherValues(inSize, mpiComm, rankDestination);
+
+    size_t gatheredSize = 0;
+
+    int rank;
+    MPI_Comm_rank(mpiComm, &rank);
+
+    if (rank == rankDestination) // pre-allocate vector
+    {
+        gatheredSize = std::accumulate(counts.begin(), counts.end(), 0);
+        out.resize(out.size() + gatheredSize);
+        position += gatheredSize;
+    }
+
+    GathervArrays(in.data(), in.size(), counts.data(), counts.size(),
+                  out.data(), mpiComm);
+}
+
+} // end namespace adios2
+
+#endif /* ADIOS2_HELPER_ADIOSMPIFUNCTIONS_INL_ */
diff --git a/source/adios2/helper/adiosMPIFunctions.tcc b/source/adios2/helper/adiosMPIFunctions.tcc
new file mode 100644
index 0000000000000000000000000000000000000000..4f6eb6585b250a06afd8a892d2eeb1db735f0e4f
--- /dev/null
+++ b/source/adios2/helper/adiosMPIFunctions.tcc
@@ -0,0 +1,253 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * adiosMPIFunctions.tcc : specialization of template functions defined in
+ * adiosMPIFunctions.h
+ *
+ *  Created on: Aug 30, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_HELPER_ADIOSMPIFUNCTIONS_TCC_
+#define ADIOS2_HELPER_ADIOSMPIFUNCTIONS_TCC_
+
+#include "adiosMPIFunctions.h"
+
+#include <algorithm> //std::foreach
+#include <iostream>  //TODO: remove
+#include <numeric>   //std::accumulate
+
+#include "adios2/ADIOSMPI.h"
+#include "adios2/ADIOSTypes.h"
+#include "adios2/helper/adiosType.h"
+
+namespace adios2
+{
+// BroadcastValue specializations
+template <>
+size_t BroadcastValue(const size_t &input, MPI_Comm mpiComm,
+                      const int rankSource)
+{
+    int rank;
+    MPI_Comm_rank(mpiComm, &rank);
+    size_t output = 0;
+
+    if (rank == rankSource)
+    {
+        output = input;
+    }
+
+    MPI_Bcast(&output, 1, ADIOS2_MPI_SIZE_T, rankSource, mpiComm);
+
+    return output;
+}
+
+template <>
+std::string BroadcastValue(const std::string &input, MPI_Comm mpiComm,
+                           const int rankSource)
+{
+    int rank;
+    MPI_Comm_rank(mpiComm, &rank);
+    const size_t inputSize = input.size();
+    size_t length = BroadcastValue(inputSize, mpiComm, rankSource);
+    std::string output;
+
+    if (rank == rankSource)
+    {
+        output = input;
+    }
+    else
+    {
+        output.resize(length);
+    }
+
+    MPI_Bcast(const_cast<char *>(output.data()), length, MPI_CHAR, rankSource,
+              mpiComm);
+
+    return output;
+}
+
+// ReduceValue specializations
+template <>
+unsigned int ReduceValues(const unsigned int source, MPI_Comm mpiComm,
+                          MPI_Op operation, const int rankDestination)
+{
+    const unsigned int sourceLocal = source;
+    unsigned int reduceValue = 0;
+    MPI_Reduce(&sourceLocal, &reduceValue, 1, MPI_UNSIGNED, operation,
+               rankDestination, mpiComm);
+    return reduceValue;
+}
+
+template <>
+unsigned long int ReduceValues(const unsigned long int source, MPI_Comm mpiComm,
+                               MPI_Op operation, const int rankDestination)
+{
+    const unsigned long int sourceLocal = source;
+    unsigned long int reduceValue = 0;
+    MPI_Reduce(&sourceLocal, &reduceValue, 1, MPI_UNSIGNED_LONG, operation,
+               rankDestination, mpiComm);
+    return reduceValue;
+}
+
+template <>
+unsigned long long int ReduceValues(const unsigned long long int source,
+                                    MPI_Comm mpiComm, MPI_Op operation,
+                                    const int rankDestination)
+{
+    const unsigned long long int sourceLocal = source;
+    unsigned long long int reduceValue = 0;
+    MPI_Reduce(&sourceLocal, &reduceValue, 1, MPI_UNSIGNED_LONG_LONG, operation,
+               rankDestination, mpiComm);
+    return reduceValue;
+}
+
+// BroadcastVector specializations
+template <>
+std::vector<char> BroadcastVector(const std::vector<char> &input,
+                                  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;
+
+    if (rank == rankSource)
+    {
+        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 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);
+    int rank;
+    MPI_Comm_rank(mpiComm, &rank);
+    std::vector<size_t> output;
+
+    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);
+    }
+
+    return output;
+}
+
+// GatherArrays specializations
+template <>
+void GatherArrays(const char *source, const size_t sourceCount,
+                  char *destination, MPI_Comm mpiComm,
+                  const int rankDestination)
+{
+    const int countsInt = static_cast<int>(sourceCount);
+    int result = MPI_Gather(source, countsInt, MPI_CHAR, destination, countsInt,
+                            MPI_CHAR, rankDestination, mpiComm);
+
+    if (result != MPI_SUCCESS)
+    {
+        throw std::runtime_error("ERROR: in ADIOS2 detected failure in MPI "
+                                 "Gather type MPI_CHAR function\n");
+    }
+}
+
+template <>
+void GatherArrays(const size_t *source, const size_t sourceCount,
+                  size_t *destination, MPI_Comm mpiComm,
+                  const int rankDestination)
+{
+    const int countsInt = static_cast<int>(sourceCount);
+    int result =
+        MPI_Gather(source, countsInt, ADIOS2_MPI_SIZE_T, destination, countsInt,
+                   ADIOS2_MPI_SIZE_T, rankDestination, mpiComm);
+
+    if (result != MPI_SUCCESS)
+    {
+        throw std::runtime_error("ERROR: in ADIOS2 detected failure in MPI "
+                                 "Gather type size_t function\n");
+    }
+}
+
+// GathervArrays specializations
+template <>
+void GathervArrays(const char *source, const size_t sourceCount,
+                   const size_t *counts, const size_t countsSize,
+                   char *destination, MPI_Comm mpiComm,
+                   const int rankDestination)
+{
+    int result = 0;
+    int rank;
+    MPI_Comm_rank(mpiComm, &rank);
+
+    std::vector<int> countsInt, displacementsInt;
+
+    if (rank == rankDestination)
+    {
+        countsInt = NewVectorTypeFromArray<size_t, int>(counts, countsSize);
+        displacementsInt = GetGathervDisplacements(counts, countsSize);
+    }
+
+    result = MPI_Gatherv(source, static_cast<int>(sourceCount), MPI_CHAR,
+                         destination, countsInt.data(), displacementsInt.data(),
+                         MPI_CHAR, rankDestination, mpiComm);
+
+    if (result != MPI_SUCCESS)
+    {
+        throw std::runtime_error("ERROR: in ADIOS2 detected failure in MPI "
+                                 "Gatherv type MPI_CHAR function\n");
+    }
+}
+
+template <>
+void GathervArrays(const size_t *source, const size_t sourceCount,
+                   const size_t *counts, const size_t countsSize,
+                   size_t *destination, MPI_Comm mpiComm,
+                   const int rankDestination)
+{
+    int result = 0;
+    int rank;
+    MPI_Comm_rank(mpiComm, &rank);
+
+    std::vector<int> countsInt =
+        NewVectorTypeFromArray<size_t, int>(counts, countsSize);
+
+    std::vector<int> displacementsInt =
+        GetGathervDisplacements(counts, countsSize);
+
+    result = MPI_Gatherv(source, sourceCount, ADIOS2_MPI_SIZE_T, destination,
+                         countsInt.data(), displacementsInt.data(),
+                         ADIOS2_MPI_SIZE_T, rankDestination, mpiComm);
+
+    if (result != MPI_SUCCESS)
+    {
+        throw std::runtime_error("ERROR: in ADIOS2 detected failure in MPI "
+                                 "Gather type size_t function\n");
+    }
+}
+
+} // end namespace adios2
+
+#endif /* ADIOS2_HELPER_ADIOSMPIFUNCTIONS_TCC_ */
diff --git a/source/adios2/helper/adiosMemory.h b/source/adios2/helper/adiosMemory.h
index ad5dd0116d123da9a885c99ca940efa1e825b969..8c67c7c8e565422d3047793f9f4618a3ca61eaa7 100644
--- a/source/adios2/helper/adiosMemory.h
+++ b/source/adios2/helper/adiosMemory.h
@@ -59,29 +59,16 @@ void CopyToBufferThreads(std::vector<char> &buffer, size_t &position,
                          const unsigned int threads = 1) noexcept;
 
 /**
- * Memcpy data to a specific location in the buffer updating position
- * Does not update vec.size().
- * @param buffer data destination used in memcpy
- * @param position starting position in buffer (in terms of T not bytes)
- * @param source pointer to source data
- * @param size number of bytes from source
+ * Copy memory from a buffer at a certain input position
+ * @param buffer data source
+ * @param position start position to copy from buffer, modified to final
+ * position
+ * @param destination pointer to destination
+ * @param elements  number of elements of destination type
  */
 template <class T>
-void MemcpyToBuffer(std::vector<char> &buffer, size_t &position,
-                    const T *source, size_t size) noexcept;
-
-/**
- * Threaded version of MemcpyToBuffer
- * @param buffer data destination used in memcpy
- * @param position starting position in buffer (in terms of T not bytes)
- * @param source pointer to source data
- * @param size number of bytes from source
- * @param threads number of threads sharing the memcpy load
- */
-template <class T>
-void MemcpyToBufferThreads(std::vector<char> &buffer, size_t &position,
-                           const T *source, size_t size,
-                           const unsigned int threads = 1);
+void CopyFromBuffer(const std::vector<char> &buffer, size_t &position,
+                    T *destination, const size_t elements = 1) noexcept;
 
 /**
  * Cast an element to uint64 and insert to a buffer
@@ -91,7 +78,10 @@ void MemcpyToBufferThreads(std::vector<char> &buffer, size_t &position,
 template <class T>
 void InsertU64(std::vector<char> &buffer, const T element) noexcept;
 
-} // end namespace adios
+template <class T>
+T ReadValue(const std::vector<char> &buffer, size_t &position) noexcept;
+
+} // end namespace adios2
 
 #include "adiosMemory.inl"
 
diff --git a/source/adios2/helper/adiosMemory.inl b/source/adios2/helper/adiosMemory.inl
index 0eaa2662a765b1e8e5523c624d5ce853b3194a10..001b1be57c2a38374a7b66bc3b80454dabdb950a 100644
--- a/source/adios2/helper/adiosMemory.inl
+++ b/source/adios2/helper/adiosMemory.inl
@@ -99,8 +99,8 @@ void CopyToBufferThreads(std::vector<char> &buffer, size_t &position,
 }
 
 template <class T>
-void CopyFromBuffer(T *destination, size_t elements,
-                    const std::vector<char> &buffer, size_t &position) noexcept
+void CopyFromBuffer(const std::vector<char> &buffer, size_t &position,
+                    T *destination, size_t elements) noexcept
 {
     std::copy(buffer.begin() + position,
               buffer.begin() + position + sizeof(T) * elements,
@@ -109,63 +109,20 @@ void CopyFromBuffer(T *destination, size_t elements,
 }
 
 template <class T>
-void MemcpyToBuffer(std::vector<char> &buffer, size_t &position,
-                    const T *source, size_t size) noexcept
-{
-    std::memcpy(&buffer[position], source, size);
-    position += size;
-}
-
-template <class T>
-void MemcpyToBufferThreads(std::vector<char> &buffer, size_t &position,
-                           const T *source, size_t size,
-                           const unsigned int threads)
+void InsertU64(std::vector<char> &buffer, const T element) noexcept
 {
-    if (threads == 1)
-    {
-        std::memcpy(&buffer[position], source, size);
-        return;
-    }
-
-    const size_t stride = size / threads;
-    const size_t remainder = size % threads;
-    const size_t last = stride + remainder;
-
-    std::vector<std::thread> memcpyThreads;
-    memcpyThreads.reserve(threads);
-
-    for (unsigned int t = 0; t < threads; ++t)
-    {
-        const size_t initialDestination = position + stride * t;
-        const size_t initialSource = stride * t / sizeof(T);
-
-        if (t == threads - 1)
-        {
-            memcpyThreads.push_back(std::thread(std::memcpy,
-                                                &buffer[initialDestination],
-                                                &source[initialSource], last));
-        }
-        else
-        {
-            memcpyThreads.push_back(
-                std::thread(std::memcpy, &buffer[initialDestination],
-                            &source[initialSource], stride));
-        }
-    }
-
-    for (auto &thread : memcpyThreads)
-    {
-        thread.join();
-    }
+    const uint64_t element64 = static_cast<const uint64_t>(element);
+    InsertToBuffer(buffer, &element64);
 }
 
 template <class T>
-void InsertU64(std::vector<char> &buffer, const T element) noexcept
+T ReadValue(const std::vector<char> &buffer, size_t &position) noexcept
 {
-    const uint64_t element64 = static_cast<const uint64_t>(element);
-    InsertToBuffer(buffer, &element64);
+    T value;
+    CopyFromBuffer(buffer, position, &value);
+    return value;
 }
 
-} // end namespace
+} // end namespace adios2
 
 #endif /* ADIOS2_HELPER_ADIOSMEMORY_INL_ */
diff --git a/source/adios2/helper/adiosType.cpp b/source/adios2/helper/adiosType.cpp
index 18d1b0c1c0723896b9dcdd7ec9155c5447bbe9ba..0df9afe85e7928ef82c79932ffb934d10c22f4df 100644
--- a/source/adios2/helper/adiosType.cpp
+++ b/source/adios2/helper/adiosType.cpp
@@ -93,14 +93,12 @@ std::vector<std::size_t> Uint64ArrayToSizetVector(const size_t nElements,
     return out;
 }
 
-std::vector<std::size_t>
+std::vector<size_t>
 Uint64VectorToSizetVector(const std::vector<uint64_t> &in) noexcept
 {
     std::vector<size_t> out(in.size());
-    out.resize(in.size());
     std::transform(in.begin(), in.end(), out.begin(),
                    [](uint64_t value) { return static_cast<size_t>(value); });
-
     return out;
 }
 
@@ -171,12 +169,12 @@ size_t BytesFactor(const std::string units, const bool debugMode)
     return factor;
 }
 
-std::string OpenModeToString(const OpenMode openMode,
+std::string OpenModeToString(const Mode openMode,
                              const bool oneLetter) noexcept
 {
     std::string openModeString;
 
-    if (openMode == OpenMode::Write)
+    if (openMode == Mode::Write)
     {
         if (oneLetter)
         {
@@ -187,7 +185,7 @@ std::string OpenModeToString(const OpenMode openMode,
             openModeString = "Write";
         }
     }
-    else if (openMode == OpenMode::Append)
+    else if (openMode == Mode::Append)
     {
         if (oneLetter)
         {
@@ -198,7 +196,7 @@ std::string OpenModeToString(const OpenMode openMode,
             openModeString = "Append";
         }
     }
-    else if (openMode == OpenMode::Read)
+    else if (openMode == Mode::Read)
     {
         if (oneLetter)
         {
diff --git a/source/adios2/helper/adiosType.h b/source/adios2/helper/adiosType.h
index 529ab97eede1b1098f121ce83d7cb5c57f3761b0..1c1bddb0f203e8836c1dc51e8a46f4fa43f4d875 100644
--- a/source/adios2/helper/adiosType.h
+++ b/source/adios2/helper/adiosType.h
@@ -105,8 +105,14 @@ size_t BytesFactor(const std::string units, const bool debugMode);
  * @param oneLetter if true returns a one letter version ("w", "a" or "r")
  * @return string with open mode
  */
-std::string OpenModeToString(const OpenMode openMode,
+std::string OpenModeToString(const Mode openMode,
                              const bool oneLetter = false) noexcept;
+
+template <class T, class U>
+std::vector<U> NewVectorType(const std::vector<T> &in);
+
+template <class T, class U>
+std::vector<U> NewVectorTypeFromArray(const T *in, const size_t inSize);
 }
 
 #include "adiosType.inl"
diff --git a/source/adios2/helper/adiosType.inl b/source/adios2/helper/adiosType.inl
index b81bb598183f5f11080ef293a61f3ed396366718..c32f2d7546bee4a207b356769195672d5278d1e1 100644
--- a/source/adios2/helper/adiosType.inl
+++ b/source/adios2/helper/adiosType.inl
@@ -14,6 +14,8 @@
 #error "Inline file should only be included from it's header, never on it's own"
 #endif
 
+#include <algorithm>
+
 namespace adios2
 {
 
@@ -139,6 +141,21 @@ bool IsTypeAlias(
     return isAlias;
 }
 
-} // end namespace adios
+template <class T, class U>
+std::vector<U> NewVectorType(const std::vector<T> &in)
+{
+    return NewVectorTypeFromArray(in.data(), in.size());
+}
+
+template <class T, class U>
+std::vector<U> NewVectorTypeFromArray(const T *in, const size_t inSize)
+{
+    std::vector<U> out(inSize);
+    std::transform(in, in + inSize, out.begin(),
+                   [](T value) { return static_cast<U>(value); });
+    return out;
+}
+
+} // end namespace adios2
 
 #endif /* ADIOS2_HELPER_ADIOSTYPE_INL_ */
diff --git a/source/adios2/helper/adiosXML.cpp b/source/adios2/helper/adiosXML.cpp
index 25bae1343c05e09b5776f9ca7af4ecf07f3ae6ae..1ceabae14021da9c406f8196bbddb457c2b52597 100644
--- a/source/adios2/helper/adiosXML.cpp
+++ b/source/adios2/helper/adiosXML.cpp
@@ -162,7 +162,7 @@ void InitXML(const std::string configXML, MPI_Comm mpiComm,
         fileContents = FileToString(configXML);
     }
 
-    fileContents = BroadcastString(fileContents, mpiComm);
+    fileContents = BroadcastValue(fileContents, mpiComm);
 
     pugi::xml_document doc;
     auto parse_result = doc.load_buffer_inplace(
diff --git a/source/adios2/mpidummy.cpp b/source/adios2/mpidummy.cpp
index 51a5dcf881e3c516d90adaee0388da69b9ccee91..e595ec052fc1edb6d92a04eb3fbb84920b7503d2 100644
--- a/source/adios2/mpidummy.cpp
+++ b/source/adios2/mpidummy.cpp
@@ -121,9 +121,18 @@ int MPI_Gather(const void *sendbuf, int sendcnt, MPI_Datatype sendtype,
 
     switch (sendtype)
     {
+    case MPI_CHAR:
+        n = sizeof(char);
+        break;
     case MPI_INT:
         n = sizeof(int);
         break;
+    case MPI_UNSIGNED:
+        n = sizeof(unsigned int);
+        break;
+    case MPI_UNSIGNED_LONG:
+        n = sizeof(unsigned long);
+        break;
     default:
         return MPI_ERR_TYPE;
     }
@@ -131,9 +140,18 @@ int MPI_Gather(const void *sendbuf, int sendcnt, MPI_Datatype sendtype,
 
     switch (recvtype)
     {
+    case MPI_CHAR:
+        nrecv = sizeof(char);
+        break;
     case MPI_INT:
         nrecv = sizeof(int);
         break;
+    case MPI_UNSIGNED:
+        nrecv = sizeof(unsigned int);
+        break;
+    case MPI_UNSIGNED_LONG:
+        nrecv = sizeof(unsigned long);
+        break;
     default:
         return MPI_ERR_TYPE;
     }
@@ -382,5 +400,12 @@ int MPI_Get_processor_name(char *name, int *resultlen)
     return 0;
 }
 
+int MPI_Reduce(const void *sendbuf, void *recvbuf, int count,
+               MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)
+{
+    *recvbuf = *sendbuf;
+    return 0;
+}
+
 } // end namespace mpi
 } // end namespace adios
diff --git a/source/adios2/mpidummy.h b/source/adios2/mpidummy.h
index 1194d2a1f9d2714d10cf6d4cd5a8496809c9431e..12438b078aea5c47bf0f9d6f2ee88bcd66242268 100644
--- a/source/adios2/mpidummy.h
+++ b/source/adios2/mpidummy.h
@@ -27,6 +27,7 @@ typedef int MPI_Info;
 typedef int MPI_Datatype; /* Store the byte size of a type in such vars */
 typedef long MPI_Offset;
 typedef int MPI_Fint;
+typedef int MPI_Op;
 
 #define MPI_SUCCESS 0
 #define MPI_ERR_BUFFER 1 /* Invalid buffer pointer */
@@ -125,6 +126,9 @@ int MPI_Get_processor_name(char *name, int *resultlen);
 
 double MPI_Wtime();
 
+int MPI_Reduce(const void *sendbuf, void *recvbuf, int count,
+               MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm);
+
 } // end namespace mpi
 } // end namespace adios
 
diff --git a/source/adios2/toolkit/capsule/Capsule.cpp b/source/adios2/toolkit/capsule/Capsule.cpp
deleted file mode 100644
index b9e4a309e0094c65533a857bd94237fe9914946c..0000000000000000000000000000000000000000
--- a/source/adios2/toolkit/capsule/Capsule.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * Capsule.cpp
- *
- *  Created on: Nov 11, 2016
- *      Author: wfg
- */
-
-#include "Capsule.h"
-
-namespace adios2
-{
-
-Capsule::Capsule(const std::string type, const bool debugMode)
-: m_Type(type), m_DebugMode(debugMode)
-{
-}
-
-size_t Capsule::GetAvailableDataSize() const
-{
-    return GetDataSize() - m_DataPosition;
-}
-
-void Capsule::ResizeData(size_t /*size*/) {}
-
-void Capsule::ResizeMetadata(size_t /*size*/) {}
-
-} // end namespace adios
diff --git a/source/adios2/toolkit/capsule/Capsule.h b/source/adios2/toolkit/capsule/Capsule.h
deleted file mode 100644
index 0534e75ec69912a4b012befb0249048c9fad2a12..0000000000000000000000000000000000000000
--- a/source/adios2/toolkit/capsule/Capsule.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * Capsule.h
- *
- *  Created on: Dec 7, 2016
- *      Author: William F Godoy godoywf@ornl.gov
- */
-
-#ifndef ADIOS2_TOOLKIT_CAPSULE_CAPSULE_H_
-#define ADIOS2_TOOLKIT_CAPSULE_CAPSULE_H_
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <string>
-/// \endcond
-
-#include "adios2/ADIOSConfig.h"
-#include "adios2/ADIOSTypes.h"
-
-namespace adios2
-{
-
-/**
- * Base class that raw data and metadata buffers, used by Engine.
- * Derived classes will allocate their own buffer in different memory spaces.
- * e.g. locally (heap) or in shared memory (virtual memory)
- */
-class Capsule
-{
-
-public:
-    /** Derived class ID */
-    const std::string m_Type;
-
-    /** position in current data buffer */
-    size_t m_DataPosition = 0;
-
-    /** position in current data buffer + bytes flushed in transports */
-    size_t m_DataAbsolutePosition = 0;
-
-    /** position in metadata buffer */
-    size_t m_MetadataPosition = 0;
-
-    /**
-     * Unique constructor
-     * @param type derived class
-     * @param debugMode true: extra exception checks
-     */
-    Capsule(const std::string type, const bool debugMode);
-
-    virtual ~Capsule() = default;
-
-    /** pointer to the raw data buffer */
-    virtual char *GetData() = 0;
-    /** pointer to the raw metadata buffer */
-    virtual char *GetMetadata() = 0;
-
-    virtual size_t GetDataSize() const = 0;     ///< data buffer memory size
-    virtual size_t GetMetadataSize() const = 0; ///< metadata buffer memory size
-
-    size_t GetAvailableDataSize() const;
-
-    virtual void ResizeData(const size_t size);     ///< resize data buffer
-    virtual void ResizeMetadata(const size_t size); ///< resize metadata buffer
-
-protected:
-    const bool m_DebugMode = false; ///< true: extra exception checks
-};
-
-} // end namespace
-
-#endif /* ADIOS2_TOOLKIT_CAPSULE_CAPSULE_H_ */
diff --git a/source/adios2/toolkit/capsule/heap/STLVector.cpp b/source/adios2/toolkit/capsule/heap/STLVector.cpp
deleted file mode 100644
index 5221f00faa3245c66a14d3dd44708d34a40b1f81..0000000000000000000000000000000000000000
--- a/source/adios2/toolkit/capsule/heap/STLVector.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * STLVector.cpp
- *
- *  Created on: Dec 22, 2016
- *      Author: wfg
- */
-
-#include "STLVector.h"
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <new>       //std::bad_alloc
-#include <stdexcept> //std::runtime_error
-/// \endcond
-
-namespace adios2
-{
-namespace capsule
-{
-
-STLVector::STLVector(const bool debugMode)
-: Capsule("heap/STLVector", debugMode)
-{
-}
-
-char *STLVector::GetData() { return m_Data.data(); }
-
-char *STLVector::GetMetadata() { return m_Metadata.data(); }
-
-size_t STLVector::GetDataSize() const { return m_Data.size(); }
-
-size_t STLVector::GetMetadataSize() const { return m_Metadata.size(); }
-
-void STLVector::ResizeData(const size_t size)
-{
-    if (m_DebugMode)
-    {
-        try
-        {
-            m_Data.resize(size);
-        }
-        catch (...)
-        {
-            std::throw_with_nested(
-                std::runtime_error("ERROR: possible overflow when resizing "
-                                   "data buffer with size " +
-                                   std::to_string(size) + "\n"));
-        }
-    }
-    else
-    {
-        m_Data.resize(size);
-    }
-}
-
-void STLVector::ResizeMetadata(const size_t size)
-{
-    if (m_DebugMode)
-    {
-        try
-        {
-            m_Metadata.resize(size);
-        }
-        catch (...)
-        {
-            std::throw_with_nested(
-                std::runtime_error("ERROR: possible overflow when resizing "
-                                   "metadata buffer with size " +
-                                   std::to_string(size) + "\n"));
-        }
-    }
-    else
-    {
-        m_Metadata.resize(size);
-    }
-}
-
-} // end namespace capsule
-} // end namespace adios
diff --git a/source/adios2/toolkit/capsule/heap/STLVector.h b/source/adios2/toolkit/capsule/heap/STLVector.h
deleted file mode 100644
index ffe091d8f260d99f65acd2ede07bba55e2470f82..0000000000000000000000000000000000000000
--- a/source/adios2/toolkit/capsule/heap/STLVector.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * Heap.h
- *
- *  Created on: Dec 19, 2016
- *      Author: wfg
- */
-
-#ifndef ADIOS2_TOOLKIT_CAPSULE_HEAP_STLVECTOR_H_
-#define ADIOS2_TOOLKIT_CAPSULE_HEAP_STLVECTOR_H_
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <vector>
-/// \endcond
-
-#include "adios2/ADIOSConfig.h"
-#include "adios2/toolkit/capsule/Capsule.h"
-
-namespace adios2
-{
-namespace capsule
-{
-
-/**
- * Data and Metadata buffers are allocated in the Heap
- */
-class STLVector : public Capsule
-{
-
-public:
-    /** data buffer allocated using the STL in heap */
-    std::vector<char> m_Data;
-    /** might be used in cases other than files */
-    std::vector<char> m_Metadata;
-
-    /**
-     * Unique constructor
-     * @param debugMode true: exceptions checks
-     */
-    STLVector(const bool debugMode = false);
-
-    ~STLVector() = default;
-
-    char *GetData();
-    char *GetMetadata();
-
-    size_t GetDataSize() const;
-    size_t GetMetadataSize() const;
-
-    void ResizeData(const size_t size);
-    void ResizeMetadata(const size_t size);
-};
-
-} // end namespace capsule
-} // end namespace
-
-#endif /* ADIOS2_CAPSULE_HEAP_STLVECTOR_H_ */
diff --git a/source/adios2/toolkit/capsule/shmem/ShmSystemV.cpp b/source/adios2/toolkit/capsule/shmem/ShmSystemV.cpp
deleted file mode 100644
index 21ba4efcd636c739cfa8a3517d03f4d7db9e14c5..0000000000000000000000000000000000000000
--- a/source/adios2/toolkit/capsule/shmem/ShmSystemV.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * ShmSystemV.cpp : implementation of ShmSystemV class
- *
- *  Created on: Dec 22, 2016
- *      Author: William F Godoy godoywf@ornl.gov
- */
-
-#include "ShmSystemV.h"
-
-#include <sys/shm.h> //shmget
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <ios> //std::ios_base::failure
-#include <utility>
-/// \endcond
-
-namespace adios2
-{
-
-ShmSystemV::ShmSystemV(const std::string &pathName, const int rankMPI,
-                       const size_t dataSize, const size_t metadataSize,
-                       const bool debugMode)
-: Capsule("ShmSystemV", debugMode), m_DataSize(dataSize),
-  m_MetadataSize(metadataSize)
-{
-    // Data Shared memory sector
-    const std::string dataPath(pathName + "/adios.shm.data." +
-                               std::to_string(rankMPI));
-
-    // 2nd field must be greater than zero and unique
-    m_DataKey = ftok(dataPath.c_str(), rankMPI + 1);
-    m_DataShmID = shmget(m_DataKey, m_DataSize, IPC_CREAT | 0666);
-    m_Data = static_cast<char *>(shmat(m_DataShmID, nullptr, 0));
-
-    // Metadata Shared memory sector
-    const std::string metadataPath(pathName + "/adios.shm.metadata." +
-                                   std::to_string(rankMPI));
-    // 2nd field must be greater than zero and unique
-    m_MetadataKey = ftok(metadataPath.c_str(), rankMPI + 1);
-    m_MetadataShmID = shmget(m_MetadataKey, m_MetadataSize, IPC_CREAT | 0666);
-    m_Metadata = static_cast<char *>(shmat(m_MetadataShmID, nullptr, 0));
-
-    if (m_DebugMode)
-    {
-        CheckShm();
-    }
-}
-
-char *ShmSystemV::GetData() { return m_Data; }
-
-char *ShmSystemV::GetMetadata() { return m_Metadata; }
-
-size_t ShmSystemV::GetDataSize() const { return m_DataSize; }
-
-size_t ShmSystemV::GetMetadataSize() const { return m_MetadataSize; }
-
-// PRIVATE
-void ShmSystemV::CheckShm() const
-{
-    if (m_DataShmID < 0)
-    {
-        throw std::ios_base::failure(
-            "ERROR: Failed to create data shm segment of size " +
-            std::to_string(m_DataSize) +
-            " from call to ShmSystemV constructor\n");
-    }
-
-    if (m_Data == nullptr)
-    {
-        throw std::ios_base::failure(
-            "ERROR: Failed to attach to data shm segment of size " +
-            std::to_string(m_DataSize) + " and id " +
-            std::to_string(m_DataShmID) +
-            ", from call to ShmSystemV constructor\n");
-    }
-
-    if (m_DataShmID < 0)
-    {
-        throw std::ios_base::failure(
-            "ERROR: Failed to create metadata shm segment of size " +
-            std::to_string(m_MetadataSize) +
-            " from call to ShmSystemV constructor\n");
-    }
-
-    if (m_Metadata == nullptr)
-    {
-        throw std::ios_base::failure(
-            "ERROR: Failed to attach to metadata shm segment of size " +
-            std::to_string(m_MetadataSize) + " and id " +
-            std::to_string(m_MetadataShmID) +
-            " from call to ShmSystemV constructor\n");
-    }
-}
-
-} // end namespace adios
diff --git a/source/adios2/toolkit/capsule/shmem/ShmSystemV.h b/source/adios2/toolkit/capsule/shmem/ShmSystemV.h
deleted file mode 100644
index b1bf0f48ea2c28a77c9571137c7e66d803b7eb09..0000000000000000000000000000000000000000
--- a/source/adios2/toolkit/capsule/shmem/ShmSystemV.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * ShmSystemV.h : ShmSystem class as a thin wrapper to a shared memory capsule
- *                using POSIX SystemV
- *
- * Created on: Dec 22, 2016
- *      Author: William F Godoy godoywf@ornl.gov
- */
-
-#ifndef ADIOS2_TOOLKIT_CAPSULE_SHMEM_SHMSYSTEMV_H_
-#define ADIOS2_TOOLKIT_CAPSULE_SHMEM_SHMSYSTEMV_H_
-
-#include <sys/ipc.h>
-#include <sys/types.h>
-
-#include "adios2/ADIOSConfig.h"
-#include "adios2/toolkit/capsule/Capsule.h"
-
-namespace adios2
-{
-
-/**
- * Buffer and Metadata are allocated in virtual memory using interprocess
- * communication (IPC) of Unix's System V
- */
-class ShmSystemV : public Capsule
-{
-
-public:
-    /**
-         * Create a Capsule in shared memory using System V shm API
-         * @param accessMode
-         * @param pathName used to create the key as a unique identifier
-         * @param dataSize size of allocated memory segment for data
-         * @param metadataSize size of allocated memory segment for metadata
-         * @param debugMode true: extra checks, slower
-         */
-    ShmSystemV(const std::string &pathName, const int rankMPI,
-               const size_t dataSize, const size_t metadataSize,
-               const bool debugMode = false);
-
-    ~ShmSystemV() = default;
-
-    char *GetData();     ///< return the pointer to the raw data buffer
-    char *GetMetadata(); ///< return the pointer to the raw metadata buffer
-
-    size_t GetDataSize() const;     ///< get current data buffer size
-    size_t GetMetadataSize() const; ///< get current metadata buffer size
-
-private:
-    /** reference to a shared memory data buffer */
-    char *m_Data = nullptr;
-    const size_t m_DataSize; ///< size of the allocated shared memory segment
-    key_t m_DataKey; ///< key associated with the data buffer, created with ftok
-    int m_DataShmID; ///< data shared memory buffer id
-
-    /** reference to a shared memory metadata buffer created with shmget */
-    char *m_Metadata = nullptr;
-    const size_t m_MetadataSize; ///< size of the allocated segment
-    key_t m_MetadataKey;         ///< ftok metadata buffer key
-    int m_MetadataShmID;         ///< metadata shared memory buffer id
-
-    /** checks if all shared memory allocations are correct, throws
-       std::bad_alloc, called from constructor if debug mode is true */
-    void CheckShm() const;
-};
-
-} // end namespace adios
-
-#endif /* ADIOS2_TOOLKIT_CAPSULE_SHMEM_SHMSYSTEMV_H_ */
diff --git a/source/adios2/toolkit/format/BufferSTL.cpp b/source/adios2/toolkit/format/BufferSTL.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b0d3c00bcade7b03372235c0b4d63ac3e824e125
--- /dev/null
+++ b/source/adios2/toolkit/format/BufferSTL.cpp
@@ -0,0 +1,35 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * BufferSTL.cpp
+ *
+ *  Created on: Sep 26, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include "BufferSTL.h"
+
+namespace adios2
+{
+
+void BufferSTL::Resize(const size_t size, const std::string hint)
+{
+    try
+    {
+        m_Buffer.resize(size, '\0');
+    }
+    catch (...)
+    {
+        std::throw_with_nested(std::runtime_error(
+            "ERROR: buffer overflow when resizing to " + std::to_string(size) +
+            " bytes, " + hint + "\n"));
+    }
+}
+
+size_t BufferSTL::GetAvailableSize() const
+{
+    return m_Buffer.size() - m_Position;
+}
+
+} // end namespace adios2
diff --git a/source/adios2/toolkit/format/BufferSTL.h b/source/adios2/toolkit/format/BufferSTL.h
new file mode 100644
index 0000000000000000000000000000000000000000..b7e7d9e02efb3704b0cf1ff3687610fb4c5a7f65
--- /dev/null
+++ b/source/adios2/toolkit/format/BufferSTL.h
@@ -0,0 +1,42 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * BufferSTL.h
+ *
+ *  Created on: Sep 26, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_TOOLKIT_FORMAT_BUFFERSTL_H_
+#define ADIOS2_TOOLKIT_FORMAT_BUFFERSTL_H_
+
+#include <string>
+#include <vector>
+
+#include "adios2/ADIOSTypes.h"
+
+namespace adios2
+{
+
+class BufferSTL
+{
+public:
+    std::vector<char> m_Buffer;
+    size_t m_Position = 0;
+    size_t m_AbsolutePosition = 0;
+
+    BufferSTL() = default;
+    ~BufferSTL() = default;
+
+    void Resize(const size_t size, const std::string hint);
+
+    size_t GetAvailableSize() const;
+
+private:
+    const bool m_DebugMode = false;
+};
+
+} // end namespace adios2
+
+#endif /* ADIOS2_TOOLKIT_FORMAT_STLBUFFER_H_ */
diff --git a/source/adios2/toolkit/format/bp1/BP1.h b/source/adios2/toolkit/format/bp1/BP1.h
index d2221030dca686cacc0df648d38617db3b668c08..7994fd9a86df315c5941e5d8ccea3d97c609ba9d 100644
--- a/source/adios2/toolkit/format/bp1/BP1.h
+++ b/source/adios2/toolkit/format/bp1/BP1.h
@@ -11,7 +11,7 @@
 #ifndef ADIOS2_TOOLKIT_FORMAT_BP1_BP1_H_
 #define ADIOS2_TOOLKIT_FORMAT_BP1_BP1_H_
 
+#include "adios2/toolkit/format/bp1/BP1Reader.h"
 #include "adios2/toolkit/format/bp1/BP1Writer.h"
-/** TODO  #include "adios2/toolkit/format/bp1/BP1Reader.h" */
 
 #endif /* ADIOS2_TOOLKIT_FORMAT_BP1_BP1_H_ */
diff --git a/source/adios2/toolkit/format/bp1/BP1Aggregator.cpp b/source/adios2/toolkit/format/bp1/BP1Aggregator.cpp
index 4962e70071899aa8d0770106b5e71d0f7fe7a5ad..663da16ede1411401d7b4e97fe9e210354e5e7f7 100644
--- a/source/adios2/toolkit/format/bp1/BP1Aggregator.cpp
+++ b/source/adios2/toolkit/format/bp1/BP1Aggregator.cpp
@@ -2,7 +2,7 @@
  * Distributed under the OSI-approved Apache License, Version 2.0.  See
  * accompanying file Copyright.txt for details.
  *
- * BP1Aggregator.cpp
+ * BP1Aggregator.cpp :
  *
  *  Created on: Mar 21, 2017
  *      Author: William F Godoy godoywf@ornl.gov
@@ -11,15 +11,12 @@
 #include "BP1Aggregator.h"
 
 /// \cond EXCLUDE_FROM_DOXYGEN
-#include <fstream>
-#include <ios>
-#include <stdexcept>
-#include <vector>
+#include <numeric> //std::accumulate
+#include <unordered_set>
 /// \endcond
 
-#include <iostream>
-
 #include "adios2/ADIOSMPI.h"
+#include "adios2/helper/adiosFunctions.h"
 
 namespace adios2
 {
@@ -33,81 +30,47 @@ BP1Aggregator::BP1Aggregator(MPI_Comm mpiComm, const bool debugMode)
     MPI_Comm_size(m_MPIComm, &m_SizeMPI);
 }
 
-std::string BP1Aggregator::GetGlobalProfilingJSON(const std::string &rankLog)
+std::vector<char>
+BP1Aggregator::SetCollectiveProfilingJSON(const std::string &rankLog) const
 {
-    std::string profilingJSON;
-
-    if (m_RankMPI == 0)
+    // Gather sizes
+    const size_t rankLogSize = rankLog.size();
+    std::vector<size_t> rankLogsSizes = GatherValues(rankLogSize, m_MPIComm);
+
+    // Gatherv JSON per rank
+    std::vector<char> profilingJSON(3);
+    const std::string header("[\n");
+    const std::string footer("\n]\n");
+    size_t gatheredSize = 0;
+    size_t position = 0;
+
+    if (m_RankMPI == 0) // pre-allocate in destination
     {
-        const unsigned int sizeMPI = static_cast<const unsigned int>(m_SizeMPI);
-        std::vector<std::vector<char>> rankLogs(sizeMPI - 1); // other ranks
-        std::vector<int> rankLogsSizes(sizeMPI - 1, -1);      // init with -1
-        std::vector<MPI_Request> requests(sizeMPI);
-        std::vector<MPI_Status> statuses(sizeMPI);
-
-        // first receive sizes
-        for (unsigned int i = 1; i < sizeMPI; ++i)
-        {
-            MPI_Irecv(&rankLogsSizes[i - 1], 1, MPI_INT, i, 0, m_MPIComm,
-                      &requests[i]);
-        }
+        gatheredSize =
+            std::accumulate(rankLogsSizes.begin(), rankLogsSizes.end(), 0);
 
-        for (unsigned int i = 1; i < sizeMPI; ++i)
-        {
-            MPI_Wait(&requests[i], &statuses[i]);
-            if (m_DebugMode)
-            {
-                if (rankLogsSizes[i - 1] == -1)
-                    throw std::runtime_error(
-                        "ERROR: couldn't get size from rank " +
-                        std::to_string(i) +
-                        ", in ADIOS aggregator for Profiling.log\n");
-            }
-            rankLogs[i - 1].resize(rankLogsSizes[i - 1]); // allocate with zeros
-        }
-
-        // receive rankLog from other ranks
-        for (unsigned int i = 1; i < sizeMPI; ++i)
-        {
-            MPI_Irecv(rankLogs[i - 1].data(), rankLogsSizes[i - 1], MPI_CHAR, i,
-                      1, m_MPIComm, &requests[i]);
-        }
-
-        for (unsigned int i = 1; i < sizeMPI; ++i)
-        {
-            MPI_Wait(&requests[i], &statuses[i]);
-        }
+        profilingJSON.resize(gatheredSize + header.size() + footer.size() - 2);
+        CopyToBuffer(profilingJSON, position, header.c_str(), header.size());
+    }
 
-        // write global string
-        // key is to reserve memory first
-        profilingJSON.reserve(rankLog.size() * m_SizeMPI);
+    GathervArrays(rankLog.c_str(), rankLog.size(), rankLogsSizes.data(),
+                  rankLogsSizes.size(), &profilingJSON[position], m_MPIComm);
 
-        profilingJSON += "[\n";
-        profilingJSON += rankLog;
-        for (unsigned int i = 1; i < sizeMPI; ++i)
-        {
-            profilingJSON += ",\n";
-            profilingJSON.append(rankLogs[i - 1].data(),
-                                 rankLogs[i - 1].size());
-        }
-        profilingJSON += "\n]\n"; // close json
-    }
-    else
+    if (m_RankMPI == 0) // add footer to close JSON
     {
-        const int rankLogSize = static_cast<const int>(rankLog.size());
-        MPI_Request requestSize;
-        MPI_Isend(const_cast<int *>(&rankLogSize), 1, MPI_INT, 0, 0, m_MPIComm,
-                  &requestSize);
-
-        MPI_Request requestRankLog;
-        MPI_Isend(const_cast<char *>(rankLog.c_str()), rankLogSize, MPI_CHAR, 0,
-                  1, m_MPIComm, &requestRankLog);
+        position += gatheredSize - 2;
+        CopyToBuffer(profilingJSON, position, footer.c_str(), footer.size());
     }
 
-    MPI_Barrier(m_MPIComm); // Barrier here?
-
     return profilingJSON;
 }
 
+void BP1Aggregator::GathervBuffers(const std::vector<char> &bufferIn,
+                                   std::vector<char> &bufferOut,
+                                   size_t &position) const
+{
+    GathervVectors(bufferIn, bufferOut, position, m_MPIComm);
+}
+
 } // end namespace format
-} // end namespace adios
+} // end namespace adios2
diff --git a/source/adios2/toolkit/format/bp1/BP1Aggregator.h b/source/adios2/toolkit/format/bp1/BP1Aggregator.h
index f18dcf47bd279d0c8895435098cef78cd9fb31d0..5d977b4b5366b54fe802b7995e15d4e1112e6fd7 100644
--- a/source/adios2/toolkit/format/bp1/BP1Aggregator.h
+++ b/source/adios2/toolkit/format/bp1/BP1Aggregator.h
@@ -2,7 +2,8 @@
  * Distributed under the OSI-approved Apache License, Version 2.0.  See
  * accompanying file Copyright.txt for details.
  *
- * BP1Aggregator.h
+ * BP1Aggregator.h : defines an object that manages MPI aggregation tasks in BP1
+ * format
  *
  *  Created on: Mar 1, 2017
  *      Author: William F Godoy godoywf@ornl.gov
@@ -13,6 +14,8 @@
 
 /// \cond EXCLUDE_FROM_DOXYGEN
 #include <string>
+#include <unordered_map>
+#include <vector>
 /// \endcond
 
 #include "adios2/ADIOSConfig.h"
@@ -36,6 +39,7 @@ public:
     /**
      * Unique constructor
      * @param mpiComm coming from engine
+     * @param debugMode true: extra exception checks
      */
     BP1Aggregator(MPI_Comm mpiComm, const bool debugMode = false);
 
@@ -46,13 +50,17 @@ public:
      * python dictionary format
      * @param rankLog contain rank profiling info to be aggregated
      */
-    std::string GetGlobalProfilingJSON(const std::string &rankLog);
+    std::vector<char>
+    SetCollectiveProfilingJSON(const std::string &rankLog) const;
+
+    void GathervBuffers(const std::vector<char> &bufferIn,
+                        std::vector<char> &bufferOut, size_t &position) const;
 
 private:
     const bool m_DebugMode = false;
 };
 
 } // end namespace format
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_UTILITIES_FORMAT_BP1_BP1AGGREGATOR_H_ */
diff --git a/source/adios2/toolkit/format/bp1/BP1Base.cpp b/source/adios2/toolkit/format/bp1/BP1Base.cpp
index 8d4e6a314d3e78031870d1f652c5da7cbc936f40..66515bdda6dfa23bc69b86062578c702da7f774e 100644
--- a/source/adios2/toolkit/format/bp1/BP1Base.cpp
+++ b/source/adios2/toolkit/format/bp1/BP1Base.cpp
@@ -12,7 +12,8 @@
 #include "BP1Base.tcc"
 
 #include "adios2/ADIOSTypes.h"            //PathSeparator
-#include "adios2/helper/adiosFunctions.h" //CreateDirectory, StringToTimeUnit
+#include "adios2/helper/adiosFunctions.h" //CreateDirectory, StringToTimeUnit,
+                                          // ReadValue
 
 namespace adios2
 {
@@ -20,8 +21,7 @@ namespace format
 {
 
 BP1Base::BP1Base(MPI_Comm mpiComm, const bool debugMode)
-: m_HeapBuffer(debugMode), m_BP1Aggregator(mpiComm, debugMode),
-  m_DebugMode(debugMode)
+: m_BP1Aggregator(mpiComm, debugMode), m_DebugMode(debugMode)
 {
     // default
     m_Profiler.IsActive = true;
@@ -68,6 +68,10 @@ void BP1Base::InitParameters(const Params &parameters)
         {
             InitParameterVerbose(value);
         }
+        else if (key == "CollectiveMetadata")
+        {
+            InitParameterCollectiveMetadata(value);
+        }
     }
 
     // default timer for buffering
@@ -82,7 +86,8 @@ void BP1Base::InitParameters(const Params &parameters)
 
     if (useDefaultInitialBufferSize)
     {
-        m_HeapBuffer.ResizeData(DefaultInitialBufferSize);
+        m_Data.Resize(DefaultInitialBufferSize, "in call to Open");
+        // m_HeapBuffer.ResizeData(DefaultInitialBufferSize);
     }
 }
 
@@ -105,6 +110,12 @@ BP1Base::GetBPBaseNames(const std::vector<std::string> &names) const noexcept
     return bpBaseNames;
 }
 
+std::string BP1Base::GetBPMetadataFileName(const std::string &name) const
+    noexcept
+{
+    return AddExtension(name, ".bp");
+}
+
 std::vector<std::string>
 BP1Base::GetBPNames(const std::vector<std::string> &baseNames) const noexcept
 {
@@ -137,28 +148,33 @@ BP1Base::GetBPNames(const std::vector<std::string> &baseNames) const noexcept
 }
 
 // PROTECTED
-void BP1Base::InitParameterProfile(const std::string value)
+void BP1Base::InitOnOffParameter(const std::string value, bool &parameter,
+                                 const std::string hint)
 {
     if (value == "off" || value == "Off")
     {
-        m_Profiler.IsActive = false;
+        parameter = false;
     }
     else if (value == "on" || value == "On")
     {
-        m_Profiler.IsActive = true; // default
+        parameter = true;
     }
     else
     {
         if (m_DebugMode)
         {
             throw std::invalid_argument("ERROR: IO SetParameters profile "
-                                        "invalid value, valid: "
-                                        "profile=on or "
-                                        "profile=off, in call to Open\n");
+                                        "invalid value, " +
+                                        hint + " in call to Open\n");
         }
     }
 }
 
+void BP1Base::InitParameterProfile(const std::string value)
+{
+    InitOnOffParameter(value, m_Profiler.IsActive, "valid: Profile On or Off");
+}
+
 void BP1Base::InitParameterProfileUnits(const std::string value)
 {
     TimeUnit timeUnit = StringToTimeUnit(value, m_DebugMode);
@@ -195,7 +211,8 @@ void BP1Base::InitParameterBufferGrowth(const std::string value)
         {
             throw std::invalid_argument(
                 "ERROR: BufferGrowthFactor value "
-                "can't be less or equal than 1 (default = 1.5), or couldn't "
+                "can't be less or equal than 1 (default = 1.5), or "
+                "couldn't "
                 "convert number,\n additional description:" +
                 description + "\n, in call to Open\n");
         }
@@ -213,9 +230,8 @@ void BP1Base::InitParameterInitBufferSize(const std::string value)
         if (value.size() < 2)
         {
             throw std::invalid_argument(
-                "ERROR: wrong value for InitialBufferSize, it must be larger "
-                "than "
-                "16Kb (minimum default), in call to Open\n");
+                "ERROR: wrong value for InitialBufferSize, it must be "
+                "larger than 16Kb (minimum default), in call to Open\n");
         }
     }
 
@@ -242,7 +258,8 @@ void BP1Base::InitParameterInitBufferSize(const std::string value)
         if (!success || bufferSize < DefaultInitialBufferSize) // 16384b
         {
             throw std::invalid_argument(
-                "ERROR: wrong value for InitialBufferSize, it must be larger "
+                "ERROR: wrong value for InitialBufferSize, it must be "
+                "larger "
                 "than "
                 "16Kb (minimum default), additional description: " +
                 description + " in call to Open\n");
@@ -253,7 +270,9 @@ void BP1Base::InitParameterInitBufferSize(const std::string value)
         bufferSize = static_cast<size_t>(std::stoul(number) * factor);
     }
 
-    m_HeapBuffer.ResizeData(bufferSize);
+    // m_HeapBuffer.ResizeData(bufferSize);
+    m_Data.Resize(bufferSize, "bufferSize " + std::to_string(bufferSize) +
+                                  ", in call to Open");
 }
 
 void BP1Base::InitParameterMaxBufferSize(const std::string value)
@@ -265,7 +284,8 @@ void BP1Base::InitParameterMaxBufferSize(const std::string value)
             throw std::invalid_argument(
                 "ERROR: couldn't convert value of max_buffer_size IO "
                 "SetParameter, valid syntax: MaxBufferSize=10Gb, "
-                "MaxBufferSize=1000Mb, MaxBufferSize=16Kb (minimum default), "
+                "MaxBufferSize=1000Mb, MaxBufferSize=16Kb (minimum "
+                "default), "
                 " in call to Open");
         }
     }
@@ -294,7 +314,8 @@ void BP1Base::InitParameterMaxBufferSize(const std::string value)
             throw std::invalid_argument(
                 "ERROR: couldn't convert value of max_buffer_size IO "
                 "SetParameter, valid syntax: MaxBufferSize=10Gb, "
-                "MaxBufferSize=1000Mb, MaxBufferSize=16Kb (minimum default), "
+                "MaxBufferSize=1000Mb, MaxBufferSize=16Kb (minimum "
+                "default), "
                 "\nadditional description: " +
                 description + " in call to Open");
         }
@@ -363,7 +384,8 @@ void BP1Base::InitParameterVerbose(const std::string value)
         {
             throw std::invalid_argument(
                 "ERROR: value in Verbose=value in IO SetParameters must be "
-                "an integer in the range [0,5], \nadditional description: " +
+                "an integer in the range [0,5], \nadditional "
+                "description: " +
                 description + "\n, in call to Open\n");
         }
     }
@@ -375,6 +397,12 @@ void BP1Base::InitParameterVerbose(const std::string value)
     m_Verbosity = static_cast<unsigned int>(verbosity);
 }
 
+void BP1Base::InitParameterCollectiveMetadata(const std::string value)
+{
+    InitOnOffParameter(value, m_CollectiveMetadata,
+                       "valid: CollectiveMetadata On or Off");
+}
+
 std::vector<uint8_t>
 BP1Base::GetTransportIDs(const std::vector<std::string> &transportsTypes) const
     noexcept
@@ -425,9 +453,62 @@ size_t BP1Base::GetProcessGroupIndexSize(const std::string name,
     return pgSize;
 }
 
+BP1Base::ElementIndexHeader
+BP1Base::ReadElementIndexHeader(const std::vector<char> &buffer,
+                                size_t &position) const noexcept
+{
+    ElementIndexHeader header;
+    header.Length = ReadValue<uint32_t>(buffer, position);
+    header.MemberID = ReadValue<uint32_t>(buffer, position);
+    header.GroupName = ReadBP1String(buffer, position);
+    header.Name = ReadBP1String(buffer, position);
+    header.Path = ReadBP1String(buffer, position);
+    header.DataType = ReadValue<int8_t>(buffer, position);
+    header.CharacteristicsSetsCount = ReadValue<uint64_t>(buffer, position);
+
+    return header;
+}
+
+std::string BP1Base::ReadBP1String(const std::vector<char> &buffer,
+                                   size_t &position) const noexcept
+{
+    const size_t size =
+        static_cast<size_t>(ReadValue<uint16_t>(buffer, position));
+
+    if (size == 0)
+    {
+        return std::string();
+    }
+
+    const std::string values(&buffer[position], size);
+    position += size;
+    return values;
+}
+
+void BP1Base::ProfilerStart(const std::string process)
+{
+    if (m_Profiler.IsActive)
+    {
+        m_Profiler.Timers.at(process).Resume();
+    }
+}
+
+void BP1Base::ProfilerStop(const std::string process)
+{
+    if (m_Profiler.IsActive)
+    {
+        m_Profiler.Timers.at(process).Pause();
+    }
+}
+
 #define declare_template_instantiation(T)                                      \
     template BP1Base::ResizeResult BP1Base::ResizeBuffer(                      \
-        const Variable<T> &variable);
+        const Variable<T> &variable);                                          \
+                                                                               \
+    template BP1Base::Characteristics<T>                                       \
+    BP1Base::ReadElementIndexCharacteristics(const std::vector<char> &buffer,  \
+                                             size_t &position,                 \
+                                             const bool untilTimeStep) const;
 
 ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
 #undef declare_template_instantiation
diff --git a/source/adios2/toolkit/format/bp1/BP1Base.h b/source/adios2/toolkit/format/bp1/BP1Base.h
index 083c3861ab20268ccfd283e07e389e3c96228bf6..92ac6b09e3e037d289c3fb63dba64db81e901f10 100644
--- a/source/adios2/toolkit/format/bp1/BP1Base.h
+++ b/source/adios2/toolkit/format/bp1/BP1Base.h
@@ -12,7 +12,7 @@
 #define ADIOS2_TOOLKIT_FORMAT_BP1_BP1BASE_H_
 
 /// \cond EXCLUDE_FROM_DOXYGEN
-#include <memory> //std::shared_ptr
+#include <string>
 #include <vector>
 /// \endcond
 
@@ -21,9 +21,8 @@
 #include "adios2/ADIOSMacros.h"
 #include "adios2/ADIOSTypes.h"
 #include "adios2/core/Variable.h"
-#include "adios2/toolkit/capsule/heap/STLVector.h"
+#include "adios2/toolkit/format/BufferSTL.h"
 #include "adios2/toolkit/format/bp1/BP1Aggregator.h"
-#include "adios2/toolkit/format/bp1/BP1Structs.h"
 #include "adios2/toolkit/profiling/iochrono/IOChrono.h"
 
 namespace adios2
@@ -38,11 +37,70 @@ class BP1Base
 {
 
 public:
+    /**
+     * Metadata index used for Variables and Attributes, needed in a
+     * container for characteristic sets merge independently for each Variable
+     * or Attribute
+     */
+    struct SerialElementIndex
+    {
+        /** buffer containing the metadata index, start with 500bytes */
+        std::vector<char> Buffer;
+        /** number of characteristics sets (time and spatial aggregation) */
+        uint64_t Count = 0;
+        /** unique ID assigned to each variable for counter */
+        const uint32_t MemberID;
+
+        SerialElementIndex(const uint32_t memberID,
+                           const size_t bufferSize = 500)
+        : MemberID(memberID)
+        {
+            Buffer.reserve(bufferSize);
+        }
+    };
+
+    struct MetadataSet
+    {
+        /**
+         * updated with advance step, if append it will be updated to last,
+         * starts with one in ADIOS1
+         */
+        uint32_t TimeStep = 1;
+
+        /** single buffer for PGIndex */
+        SerialElementIndex PGIndex = SerialElementIndex(0);
+
+        // no priority for now
+        /** @brief key: variable name, value: bp metadata variable index */
+        std::unordered_map<std::string, SerialElementIndex> VarsIndices;
+
+        /** @brief key: attribute name, value: bp metadata attribute index */
+        std::unordered_map<std::string, SerialElementIndex> AttributesIndices;
+
+        bool AreAttributesWritten = false;
+
+        /** Fixed size for mini footer */
+        const unsigned int MiniFooterSize = 28;
+
+        /** number of current PGs */
+        uint64_t DataPGCount = 0;
+        /** current PG initial ( relative ) position in data buffer */
+        size_t DataPGLengthPosition = 0;
+        /** number of variables in current PG */
+        uint32_t DataPGVarsCount = 0;
+        /** current PG variable count ( relative ) position */
+        size_t DataPGVarsCountPosition = 0;
+        /** true: currently writing to a pg, false: no current pg */
+        bool DataPGIsOpen = false;
+    };
+
     /** statistics verbosity, only 0 is supported */
     unsigned int m_Verbosity = 0;
 
     /** contains data buffer and position */
-    capsule::STLVector m_HeapBuffer;
+    // capsule::STLVector m_HeapBuffer;
+    BufferSTL m_Data;
+    BufferSTL m_Metadata;
 
     /** memory growth factor,s set by the user */
     float m_GrowthFactor = DefaultBufferGrowthFactor;
@@ -51,7 +109,7 @@ public:
     size_t m_MaxBufferSize = DefaultMaxBufferSize;
 
     /** contains bp1 format metadata indices*/
-    BP1MetadataSet m_MetadataSet;
+    MetadataSet m_MetadataSet;
 
     /** object that takes care of all MPI aggregation tasks */
     BP1Aggregator m_BP1Aggregator;
@@ -63,6 +121,9 @@ public:
     /** buffering and MPI aggregation profiling info, set by user */
     profiling::IOChrono m_Profiler;
 
+    /** Default: write collective metadata in Capsule metadata. */
+    bool m_CollectiveMetadata = true;
+
     /**
      * Unique constructor
      * @param mpiComm for m_BP1Aggregator
@@ -90,6 +151,8 @@ public:
     std::vector<std::string>
     GetBPNames(const std::vector<std::string> &baseNames) const noexcept;
 
+    std::string GetBPMetadataFileName(const std::string &name) const noexcept;
+
     /** Return type of the CheckAllocation function. */
     enum class ResizeResult
     {
@@ -193,7 +256,7 @@ protected:
     /**
      * Characteristic ID in variable metadata
      */
-    enum VariableCharacteristicID
+    enum CharacteristicID
     {
         characteristic_value = 0,      //!< characteristic_value
         characteristic_min = 1,        //!< Used to read in older bp file format
@@ -224,22 +287,46 @@ protected:
     template <class T>
     struct Stats
     {
-        T Min;
-        T Max;
         uint64_t Offset;
         uint64_t PayloadOffset;
-        uint32_t TimeIndex;
+        T Min;
+        T Max;
+        uint32_t TimeStep;
+        uint32_t FileIndex;
         uint32_t MemberID;
+    };
 
-        //      unsigned long int count;
-        //      long double sum;
-        //      long double sumSquare;
-        // unsigned long int histogram
-        // bool finite??
+    template <class T>
+    struct Characteristics
+    {
+        Stats<T> Statistics;
+        std::vector<uint64_t> Dimensions;
+        uint32_t Length;
+        uint8_t Count;
+    };
+
+    struct ElementIndexHeader
+    {
+        uint64_t CharacteristicsSetsCount;
+        uint32_t Length;
+        uint32_t MemberID;
+        std::string GroupName;
+        std::string Name;
+        std::string Path;
+        uint8_t DataType;
     };
 
+    /**
+     * Functions used for setting bool parameters of type On Off
+     * @param value
+     * @param parameter
+     * @param hint
+     */
+    void InitOnOffParameter(const std::string value, bool &parameter,
+                            const std::string hint);
+
     /** profile=on (default) generate profiling.log
-         *  profile=off */
+     *  profile=off */
     void InitParameterProfile(const std::string value);
 
     /** profile_units=s (default) (mus, ms, s,m,h) from ADIOSTypes.h TimeUnit */
@@ -259,9 +346,12 @@ protected:
     /** Set available number of threads for vector operations */
     void InitParameterThreads(const std::string value);
 
-    /** verbose file level=0 (default) */
+    /** verbose file level=0 (default), not active */
     void InitParameterVerbose(const std::string value);
 
+    /** verbose file level=0 (default) */
+    void InitParameterCollectiveMetadata(const std::string value);
+
     /**
      * Returns data type index from enum Datatypes
      * @param variable input variable
@@ -287,9 +377,40 @@ protected:
                                     const std::string timeStepName,
                                     const size_t transportsSize) const noexcept;
 
+    ElementIndexHeader ReadElementIndexHeader(const std::vector<char> &buffer,
+                                              size_t &position) const noexcept;
+
     /**
-     * Returns the estimated variable index size
-     * @param variable
+     * Read variable characteristics.
+     * @param buffer
+     * @param position
+     * @param untilTimeStep, stop if time step characteristic is found
+     * @return
+     */
+    template <class T>
+    Characteristics<T>
+    ReadElementIndexCharacteristics(const std::vector<char> &buffer,
+                                    size_t &position,
+                                    const bool untilTimeStep = false) const;
+
+    /**
+     * Common function to extract a bp string, 2 bytes for length + contents
+     * @param buffer
+     * @param position
+     * @return
+     */
+    std::string ReadBP1String(const std::vector<char> &buffer,
+                              size_t &position) const noexcept;
+
+    void ProfilerStart(const std::string process);
+
+    void ProfilerStop(const std::string process);
+
+private:
+    /**
+     * Returns the estimated variable index size. Used by ResizeBuffer public
+     * function
+     * @param variable input
      */
     template <class T>
     size_t GetVariableIndexSize(const Variable<T> &variable) const noexcept;
@@ -297,7 +418,12 @@ protected:
 
 #define declare_template_instantiation(T)                                      \
     extern template BP1Base::ResizeResult BP1Base::ResizeBuffer(               \
-        const Variable<T> &variable);
+        const Variable<T> &variable);                                          \
+                                                                               \
+    extern template BP1Base::Characteristics<T>                                \
+    BP1Base::ReadElementIndexCharacteristics(const std::vector<char> &buffer,  \
+                                             size_t &position,                 \
+                                             const bool untilTimeStep) const;
 
 ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
 #undef declare_template_instantiation
diff --git a/source/adios2/toolkit/format/bp1/BP1Base.tcc b/source/adios2/toolkit/format/bp1/BP1Base.tcc
index 58b361b465d985fbfa27db2e416824c45ea7ca2b..fa1f4dda2e2a4c14d42d21a8533a4c71d1ef4e7f 100644
--- a/source/adios2/toolkit/format/bp1/BP1Base.tcc
+++ b/source/adios2/toolkit/format/bp1/BP1Base.tcc
@@ -15,169 +15,274 @@
 
 #include <cmath> //std::min
 
-#include "adios2/helper/adiosMath.h" //NextExponentialSize
+#include "adios2/helper/adiosFunctions.h" //NextExponentialSize, CopyFromBuffer
 
 namespace adios2
 {
 namespace format
 {
 
+template <class T>
+BP1Base::ResizeResult BP1Base::ResizeBuffer(const Variable<T> &variable)
+{
+    size_t currentCapacity = m_Data.m_Buffer.capacity();
+    size_t variableData =
+        GetVariableIndexSize(variable) + variable.PayLoadSize();
+    size_t requiredCapacity = variableData + m_Data.m_Position;
+
+    ResizeResult result = ResizeResult::Unchanged;
+
+    if (variableData > m_MaxBufferSize)
+    {
+        throw std::runtime_error(
+            "ERROR: variable " + variable.m_Name + " data size: " +
+            std::to_string(static_cast<float>(variableData) / (1024. * 1024.)) +
+            " Mb is too large for adios2 bp MaxBufferSize=" +
+            std::to_string(static_cast<float>(m_MaxBufferSize) /
+                           (1024. * 1024.)) +
+            "Mb, try increasing MaxBufferSize in call to IO SetParameters, in "
+            "call to Write\n");
+    }
+
+    if (requiredCapacity <= currentCapacity)
+    {
+        // do nothing, unchanged is default
+    }
+    else if (requiredCapacity > m_MaxBufferSize)
+    {
+        if (currentCapacity < m_MaxBufferSize)
+        {
+            m_Data.Resize(m_MaxBufferSize, " when resizing buffer to " +
+                                               std::to_string(m_MaxBufferSize) +
+                                               "bytes, in call to variable " +
+                                               variable.m_Name + " Write");
+        }
+        result = ResizeResult::Flush;
+    }
+    else // buffer must grow
+    {
+        if (currentCapacity < m_MaxBufferSize)
+        {
+            const size_t nextSize =
+                std::min(m_MaxBufferSize,
+                         NextExponentialSize(requiredCapacity, currentCapacity,
+                                             m_GrowthFactor));
+            m_Data.Resize(nextSize, " when resizing buffer to " +
+                                        std::to_string(nextSize) +
+                                        "bytes, in call to variable " +
+                                        variable.m_Name + " Write");
+            result = ResizeResult::Success;
+        }
+    }
+
+    return result;
+}
+
+// PROTECTED
 template <>
 int8_t BP1Base::GetDataType<std::string>() const noexcept
 {
-    return type_string;
+    const int8_t type = static_cast<const int8_t>(type_string);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<char>() const noexcept
 {
-    return type_byte;
+    const int8_t type = static_cast<const int8_t>(type_byte);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<signed char>() const noexcept
 {
-    return type_byte;
+    const int8_t type = static_cast<const int8_t>(type_byte);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<short>() const noexcept
 {
-    return type_short;
+    const int8_t type = static_cast<const int8_t>(type_short);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<int>() const noexcept
 {
-    return type_integer;
+    const int8_t type = static_cast<const int8_t>(type_integer);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<long int>() const noexcept
 {
-    return type_long;
+    const int8_t type = static_cast<const int8_t>(type_long);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<long long int>() const noexcept
 {
-    return type_long;
+    const int8_t type = static_cast<const int8_t>(type_long);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<unsigned char>() const noexcept
 {
-    return type_unsigned_byte;
+    const int8_t type = static_cast<const int8_t>(type_unsigned_byte);
+    return type;
 }
+
 template <>
 int8_t BP1Base::GetDataType<unsigned short>() const noexcept
 {
-    return type_unsigned_short;
+    const int8_t type = static_cast<const int8_t>(type_unsigned_short);
+    return type;
 }
+
 template <>
 int8_t BP1Base::GetDataType<unsigned int>() const noexcept
 {
-    return type_unsigned_integer;
+    const int8_t type = static_cast<const int8_t>(type_unsigned_integer);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<unsigned long int>() const noexcept
 {
-    return type_unsigned_long;
+    const int8_t type = static_cast<const int8_t>(type_unsigned_long);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<unsigned long long int>() const noexcept
 {
-    return type_unsigned_long;
+    const int8_t type = static_cast<const int8_t>(type_unsigned_long);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<float>() const noexcept
 {
-    return type_real;
+    const int8_t type = static_cast<const int8_t>(type_real);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<double>() const noexcept
 {
-    return type_double;
+    const int8_t type = static_cast<const int8_t>(type_double);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<long double>() const noexcept
 {
-    return type_long_double;
+    const int8_t type = static_cast<const int8_t>(type_long_double);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<cfloat>() const noexcept
 {
-    return type_complex;
+    const int8_t type = static_cast<const int8_t>(type_complex);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<cdouble>() const noexcept
 {
-    return type_double_complex;
+    const int8_t type = static_cast<const int8_t>(type_double_complex);
+    return type;
 }
 
 template <>
 int8_t BP1Base::GetDataType<cldouble>() const noexcept
 {
-    return type_long_double_complex;
+    const int8_t type = static_cast<const int8_t>(type_long_double_complex);
+    return type;
 }
 
 template <class T>
-BP1Base::ResizeResult BP1Base::ResizeBuffer(const Variable<T> &variable)
+BP1Base::Characteristics<T>
+BP1Base::ReadElementIndexCharacteristics(const std::vector<char> &buffer,
+                                         size_t &position,
+                                         const bool untilTimeStep) const
 {
-    size_t currentCapacity = m_HeapBuffer.m_Data.capacity();
-    size_t variableData =
-        GetVariableIndexSize(variable) + variable.PayLoadSize();
-    size_t requiredCapacity = variableData + m_HeapBuffer.m_DataPosition;
+    Characteristics<T> characteristics;
+    characteristics.Count = ReadValue<uint8_t>(buffer, position);
+    characteristics.Length = ReadValue<uint32_t>(buffer, position);
 
-    ResizeResult result = ResizeResult::Unchanged;
+    bool foundTimeStep = false;
 
-    if (variableData > m_MaxBufferSize)
+    while (position < characteristics.Length + 5)
     {
-        throw std::runtime_error(
-            "ERROR: variable " + variable.m_Name + " data size: " +
-            std::to_string(static_cast<float>(variableData) / (1024. * 1024.)) +
-            " Mb is too large for adios2 bp MaxBufferSize=" +
-            std::to_string(static_cast<float>(m_MaxBufferSize) /
-                           (1024. * 1024.)) +
-            "Mb, try increasing MaxBufferSize in call to IO SetParameters, in "
-            "call to Write\n");
-    }
+        const uint8_t id = ReadValue<uint8_t>(buffer, position);
 
-    if (requiredCapacity <= currentCapacity)
-    {
-        // do nothing, unchanged is default
-    }
-    else if (requiredCapacity > m_MaxBufferSize)
-    {
-        if (currentCapacity < m_MaxBufferSize)
+        switch (id)
         {
-            m_HeapBuffer.ResizeData(m_MaxBufferSize);
+        case (characteristic_time_index):
+            characteristics.Statistics.TimeStep =
+                ReadValue<uint32_t>(buffer, position);
+            foundTimeStep = true;
+            break;
+
+        case (characteristic_file_index):
+            characteristics.Statistics.FileIndex =
+                ReadValue<uint32_t>(buffer, position);
+            break;
+
+        case (characteristic_value):
+            // TODO make sure it's string or string array
+            characteristics.Statistics.Min = ReadValue<T>(buffer, position);
+            break;
+
+        case (characteristic_min):
+            characteristics.Statistics.Min = ReadValue<T>(buffer, position);
+            break;
+
+        case (characteristic_max):
+            characteristics.Statistics.Max = ReadValue<T>(buffer, position);
+            break;
+
+        case (characteristic_offset):
+            characteristics.Statistics.Offset =
+                ReadValue<uint64_t>(buffer, position);
+            break;
+
+        case (characteristic_payload_offset):
+            characteristics.Statistics.PayloadOffset =
+                ReadValue<uint64_t>(buffer, position);
+            break;
+
+        case (characteristic_dimensions):
+            const uint8_t dimensionsCount =
+                ReadValue<uint8_t>(buffer, position);
+            characteristics.Dimensions.reserve(dimensionsCount * 3);
+
+            ReadValue<uint16_t>(buffer, position); // length (not used)
+
+            for (auto d = 0; d < dimensionsCount * 3; ++d)
+            {
+                characteristics.Dimensions.push_back(
+                    ReadValue<uint64_t>(buffer, position));
+            }
+            break;
+            // TODO: implement compression and BP1 Stats characteristics
         }
-        result = ResizeResult::Flush;
-    }
-    else // buffer must grow
-    {
-        if (currentCapacity < m_MaxBufferSize)
+
+        if (untilTimeStep && foundTimeStep)
         {
-            const size_t nextSize =
-                std::min(m_MaxBufferSize,
-                         NextExponentialSize(requiredCapacity, currentCapacity,
-                                             m_GrowthFactor));
-            m_HeapBuffer.ResizeData(nextSize);
-            result = ResizeResult::Success;
+            break;
         }
     }
 
-    return result;
+    return characteristics;
 }
 
+// PRIVATE
 template <class T>
 size_t BP1Base::GetVariableIndexSize(const Variable<T> &variable) const noexcept
 {
@@ -215,6 +320,6 @@ size_t BP1Base::GetVariableIndexSize(const Variable<T> &variable) const noexcept
 }
 
 } // end namespace format
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_TOOLKIT_FORMAT_BP1_BP1BASE_TCC_ */
diff --git a/source/adios2/toolkit/format/bp1/BP1Reader.cpp b/source/adios2/toolkit/format/bp1/BP1Reader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0401be9c3ad2e6911c71f5e0966d0d6f2b52d441
--- /dev/null
+++ b/source/adios2/toolkit/format/bp1/BP1Reader.cpp
@@ -0,0 +1,25 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * BP1Reader.cpp
+ *
+ *  Created on: Sep 7, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include "BP1Reader.h"
+#include "BP1Reader.tcc"
+
+namespace adios2
+{
+namespace format
+{
+
+BP1Reader::BP1Reader(MPI_Comm mpiComm, const bool debugMode)
+: BP1Base(mpiComm, debugMode)
+{
+}
+
+} // end namespace format
+} // end namespace adios2
diff --git a/source/adios2/toolkit/format/bp1/BP1Reader.h b/source/adios2/toolkit/format/bp1/BP1Reader.h
new file mode 100644
index 0000000000000000000000000000000000000000..5996af7135a7ad52683390830462264fa98d2b9d
--- /dev/null
+++ b/source/adios2/toolkit/format/bp1/BP1Reader.h
@@ -0,0 +1,44 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * BP1Reader.h
+ *
+ *  Created on: Sep 7, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_TOOLKIT_FORMAT_BP1_BP1READER_H_
+#define ADIOS2_TOOLKIT_FORMAT_BP1_BP1READER_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <vector>
+/// \endcond
+
+#include "adios2/ADIOSConfig.h"
+#include "adios2/ADIOSTypes.h"
+#include "adios2/toolkit/format/bp1/BP1Base.h"
+
+namespace adios2
+{
+namespace format
+{
+
+class BP1Reader : BP1Base
+{
+
+public:
+    /**
+     * Unique constructor
+     * @param mpiComm
+     * @param debug true: extra checks
+     */
+    BP1Reader(MPI_Comm mpiComm, const bool debugMode);
+
+    ~BP1Reader() = default;
+};
+
+} // end namespace format
+} // end namespace adios2
+
+#endif /* ADIOS2_TOOLKIT_FORMAT_BP1_BP1READER_H_ */
diff --git a/source/adios2/toolkit/format/bp1/BP1Reader.tcc b/source/adios2/toolkit/format/bp1/BP1Reader.tcc
new file mode 100644
index 0000000000000000000000000000000000000000..c9a63fe17940c9fca70cd4360c95ba1f23eb6767
--- /dev/null
+++ b/source/adios2/toolkit/format/bp1/BP1Reader.tcc
@@ -0,0 +1,24 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * BP1Reader.tcc
+ *
+ *  Created on: Sep 7, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_TOOLKIT_FORMAT_BP1_BP1READER_TCC_
+#define ADIOS2_TOOLKIT_FORMAT_BP1_BP1READER_TCC_
+
+#include "BP1Reader.h"
+
+namespace adios2
+{
+namespace format
+{
+
+} // end namespace format
+} // end namespace adios2
+
+#endif /* ADIOS2_TOOLKIT_FORMAT_BP1_BP1READER_TCC_ */
diff --git a/source/adios2/toolkit/format/bp1/BP1Structs.h b/source/adios2/toolkit/format/bp1/BP1Structs.h
deleted file mode 100644
index 9d1724c9f2210858fb063500ba5a1c3e03a26d57..0000000000000000000000000000000000000000
--- a/source/adios2/toolkit/format/bp1/BP1Structs.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * BP1Structs.h
- *
- *  Created on: Apr 3, 2017
- *      Author: William F Godoy godoywf@ornl.gov
- */
-
-#ifndef ADIOS2_TOOLKIT_FORMAT_BP1_BP1STRUCTS_H_
-#define ADIOS2_TOOLKIT_FORMAT_BP1_BP1STRUCTS_H_
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <cstdint>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-/// \endcond
-
-#include "adios2/ADIOSConfig.h"
-#include "adios2/ADIOSTypes.h"
-#include "adios2/toolkit/profiling/iochrono/IOChrono.h"
-
-namespace adios2
-{
-namespace format
-{
-
-/**
- * Metadata index used for Variables and Attributes, needed in a container for
- * characteristic
- * sets merge independently for each Variable or Attribute
- */
-struct BP1Index
-{
-    std::vector<char> Buffer; ///< metadata variable index, start with 100Kb
-    /** number of characteristics sets (time and spatial aggregation) */
-    uint64_t Count = 0;
-    /** unique ID assigned to each variable for counter */
-    const uint32_t MemberID;
-
-    BP1Index(const uint32_t memberID) : MemberID(memberID)
-    {
-        Buffer.reserve(500);
-    }
-};
-
-/**
- * Single struct that tracks metadata indices in bp format
- */
-struct BP1MetadataSet
-{
-    /**
-     * updated with advance step, if append it will be updated to last,
-     * starts with one in ADIOS1
-     */
-    uint32_t TimeStep = 1;
-
-    /** single buffer for PGIndex */
-    BP1Index PGIndex = BP1Index(0);
-
-    // no priority for now
-    /** @brief key: variable name, value: bp metadata variable index */
-    std::unordered_map<std::string, BP1Index> VarsIndices;
-
-    /** @brief key: attribute name, value: bp metadata attribute index */
-    std::unordered_map<std::string, BP1Index> AttributesIndices;
-
-    bool AreAttributesWritten = false;
-
-    /** Fixed size for mini footer */
-    const unsigned int MiniFooterSize = 28;
-
-    // PG (relative) positions in Data buffer, to be updated every advance step
-    // or init
-    /** number of current PGs */
-    uint64_t DataPGCount = 0;
-    /** current PG initial ( relative ) position in data buffer */
-    size_t DataPGLengthPosition = 0;
-    /** number of variables in current PG */
-    uint32_t DataPGVarsCount = 0;
-    /** current PG variable count ( relative ) position */
-    size_t DataPGVarsCountPosition = 0;
-
-    /** true: currently writing to a pg, false: no current pg */
-    bool DataPGIsOpen = false;
-};
-
-} // end namespace format
-} // end namespace adios2
-
-#endif /* ADIOS2_TOOLKIT_FORMAT_BP1_BP1STRUCTS_H_ */
diff --git a/source/adios2/toolkit/format/bp1/BP1Writer.cpp b/source/adios2/toolkit/format/bp1/BP1Writer.cpp
index 103d56e03a0b944ccd2c0a9d1c3d83eec097055d..e0f0586f63b9b738f05252bce74dbff2c1c95141 100644
--- a/source/adios2/toolkit/format/bp1/BP1Writer.cpp
+++ b/source/adios2/toolkit/format/bp1/BP1Writer.cpp
@@ -11,16 +11,21 @@
 #include "BP1Writer.h"
 #include "BP1Writer.tcc"
 
+#include <chrono>
+#include <future>
 #include <string>
 #include <vector>
 
-#include "adios2/helper/adiosFunctions.h" //GetType<T>
+#include "adios2/helper/adiosFunctions.h" //GetType<T>, ReadValue<T>,
+                                          // ReduceValue<T>
 
 namespace adios2
 {
 namespace format
 {
 
+std::mutex BP1Writer::m_Mutex;
+
 BP1Writer::BP1Writer(MPI_Comm mpiComm, const bool debugMode)
 : BP1Base(mpiComm, debugMode)
 {
@@ -30,15 +35,11 @@ void BP1Writer::WriteProcessGroupIndex(
     const std::string hostLanguage,
     const std::vector<std::string> &transportsTypes) noexcept
 {
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Resume();
-    }
-
+    ProfilerStart("buffering");
     std::vector<char> &metadataBuffer = m_MetadataSet.PGIndex.Buffer;
 
-    std::vector<char> &dataBuffer = m_HeapBuffer.m_Data;
-    size_t &dataPosition = m_HeapBuffer.m_DataPosition;
+    std::vector<char> &dataBuffer = m_Data.m_Buffer;
+    size_t &dataPosition = m_Data.m_Position;
 
     m_MetadataSet.DataPGLengthPosition = dataPosition;
     dataPosition += 8; // skip pg length (8)
@@ -74,7 +75,7 @@ void BP1Writer::WriteProcessGroupIndex(
     CopyToBuffer(dataBuffer, dataPosition, &m_MetadataSet.TimeStep);
 
     // offset to pg in data in metadata which is the current absolute position
-    InsertU64(metadataBuffer, m_HeapBuffer.m_DataAbsolutePosition);
+    InsertU64(metadataBuffer, m_Data.m_AbsolutePosition);
 
     // Back to writing metadata pg index length (length of group)
     const uint16_t metadataPGIndexLength = static_cast<const uint16_t>(
@@ -101,88 +102,61 @@ void BP1Writer::WriteProcessGroupIndex(
     }
 
     // update absolute position
-    m_HeapBuffer.m_DataAbsolutePosition +=
+    m_Data.m_AbsolutePosition +=
         dataPosition - m_MetadataSet.DataPGLengthPosition;
     // pg vars count and position
     m_MetadataSet.DataPGVarsCount = 0;
     m_MetadataSet.DataPGVarsCountPosition = dataPosition;
     // add vars count and length
     dataPosition += 12;
-    m_HeapBuffer.m_DataAbsolutePosition += 12; // add vars count and length
+    m_Data.m_AbsolutePosition += 12; // add vars count and length
 
     ++m_MetadataSet.DataPGCount;
     m_MetadataSet.DataPGIsOpen = true;
 
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Pause();
-    }
+    ProfilerStop("buffering");
 }
 
 void BP1Writer::Advance(IO &io)
 {
-    // enforce memory policy here to restrict buffer size for each timestep
-    // this is flushing
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Resume();
-    }
+    ProfilerStart("buffering");
 
     if (m_MaxBufferSize == DefaultMaxBufferSize)
     {
-        // current position + 1Kb chunk tolerance
-        m_MaxBufferSize = m_HeapBuffer.m_DataPosition + 64;
+        m_MaxBufferSize = m_Data.m_Position + 64;
     }
 
-    FlattenData(io);
+    SerializeData(io);
     ++m_MetadataSet.TimeStep;
-
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Pause();
-    }
+    ProfilerStop("buffering");
 }
 
 void BP1Writer::Flush(IO &io)
 {
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Resume();
-    }
-
-    FlattenData(io);
-
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Pause();
-    }
+    ProfilerStart("buffering");
+    SerializeData(io);
+    ProfilerStop("buffering");
 }
 
 void BP1Writer::Close(IO &io) noexcept
 {
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Resume();
-    }
+    ProfilerStart("buffering");
 
     if (!m_IsClosed)
     {
         if (m_MetadataSet.DataPGIsOpen)
         {
-            FlattenData(io);
+            SerializeData(io);
         }
 
-        FlattenMetadata();
+        SerializeMetadataInData();
 
-        m_Profiler.Bytes.at("buffering") += m_HeapBuffer.m_DataAbsolutePosition;
+        m_Profiler.Bytes.at("buffering") += m_Data.m_AbsolutePosition;
 
         m_IsClosed = true;
     }
 
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Pause();
-    }
+    ProfilerStop("buffering");
 }
 
 std::string BP1Writer::GetRankProfilingJSON(
@@ -242,10 +216,17 @@ std::string BP1Writer::GetRankProfilingJSON(
     return rankLog;
 }
 
-std::string
-BP1Writer::AggregateProfilingJSON(const std::string &rankProfilingLog) noexcept
+std::vector<char>
+BP1Writer::AggregateProfilingJSON(const std::string &rankProfilingLog)
+{
+    return m_BP1Aggregator.SetCollectiveProfilingJSON(rankProfilingLog);
+}
+
+void BP1Writer::AggregateCollectiveMetadata()
 {
-    return m_BP1Aggregator.GetGlobalProfilingJSON(rankProfilingLog);
+    AggregateIndex(m_MetadataSet.PGIndex, m_MetadataSet.DataPGCount);
+    AggregateMergeIndex(m_MetadataSet.VarsIndices);
+    AggregateMergeIndex(m_MetadataSet.AttributesIndices);
 }
 
 // PRIVATE FUNCTIONS
@@ -253,8 +234,9 @@ void BP1Writer::WriteAttributes(IO &io)
 {
     const auto attributesDataMap = io.GetAttributesDataMap();
 
-    auto &buffer = m_HeapBuffer.m_Data;
-    auto &position = m_HeapBuffer.m_DataPosition;
+    auto &buffer = m_Data.m_Buffer;
+    auto &position = m_Data.m_Position;
+    auto &absolutePosition = m_Data.m_AbsolutePosition;
 
     // used only to update m_HeapBuffer.m_DataAbsolutePosition;
     const size_t attributesCountPosition = position;
@@ -268,7 +250,7 @@ void BP1Writer::WriteAttributes(IO &io)
     const size_t attributesLengthPosition = position;
     position += 8; // skip attributes length
 
-    m_HeapBuffer.m_DataAbsolutePosition += position - attributesCountPosition;
+    absolutePosition += position - attributesCountPosition;
 
     uint32_t memberID = 0;
 
@@ -284,7 +266,7 @@ void BP1Writer::WriteAttributes(IO &io)
     else if (type == GetType<T>())                                             \
     {                                                                          \
         Stats<T> stats;                                                        \
-        stats.Offset = m_HeapBuffer.m_DataAbsolutePosition;                    \
+        stats.Offset = absolutePosition;                                       \
         stats.MemberID = memberID;                                             \
         Attribute<T> &attribute = io.GetAttribute<T>(name);                    \
         WriteAttributeInData(attribute, stats);                                \
@@ -395,15 +377,15 @@ void BP1Writer::WriteNameRecord(const std::string name,
     CopyToBuffer(buffer, position, name.c_str(), length);
 }
 
-BP1Index &
-BP1Writer::GetBP1Index(const std::string name,
-                       std::unordered_map<std::string, BP1Index> &indices,
-                       bool &isNew) const noexcept
+BP1Writer::SerialElementIndex &BP1Writer::GetSerialElementIndex(
+    const std::string &name,
+    std::unordered_map<std::string, SerialElementIndex> &indices,
+    bool &isNew) const noexcept
 {
     auto itName = indices.find(name);
     if (itName == indices.end())
     {
-        indices.emplace(name, BP1Index(indices.size()));
+        indices.emplace(name, SerialElementIndex(indices.size()));
         isNew = true;
         return indices.at(name);
     }
@@ -412,10 +394,11 @@ BP1Writer::GetBP1Index(const std::string name,
     return itName->second;
 }
 
-void BP1Writer::FlattenData(IO &io) noexcept
+void BP1Writer::SerializeData(IO &io) noexcept
 {
-    auto &buffer = m_HeapBuffer.m_Data;
-    auto &position = m_HeapBuffer.m_DataPosition;
+    auto &buffer = m_Data.m_Buffer;
+    auto &position = m_Data.m_Position;
+    auto &absolutePosition = m_Data.m_AbsolutePosition;
 
     // vars count and Length (only for PG)
     CopyToBuffer(buffer, m_MetadataSet.DataPGVarsCountPosition,
@@ -434,7 +417,7 @@ void BP1Writer::FlattenData(IO &io) noexcept
     else
     {
         position += 12;
-        m_HeapBuffer.m_DataAbsolutePosition += 12;
+        absolutePosition += 12;
     }
 
     // Finish writing pg group length without record itself
@@ -445,11 +428,11 @@ void BP1Writer::FlattenData(IO &io) noexcept
     m_MetadataSet.DataPGIsOpen = false;
 }
 
-void BP1Writer::FlattenMetadata() noexcept
+void BP1Writer::SerializeMetadataInData() noexcept
 {
     auto lf_SetIndexCountLength =
-        [](std::unordered_map<std::string, BP1Index> &indices, uint32_t &count,
-           uint64_t &length) {
+        [](std::unordered_map<std::string, SerialElementIndex> &indices,
+           uint32_t &count, uint64_t &length) {
 
             count = indices.size();
             length = 0;
@@ -466,7 +449,7 @@ void BP1Writer::FlattenMetadata() noexcept
 
     auto lf_FlattenIndices =
         [](const uint32_t count, const uint64_t length,
-           const std::unordered_map<std::string, BP1Index> &indices,
+           const std::unordered_map<std::string, SerialElementIndex> &indices,
            std::vector<char> &buffer, size_t &position) {
 
             CopyToBuffer(buffer, position, &count);
@@ -500,12 +483,14 @@ void BP1Writer::FlattenMetadata() noexcept
         (pgLength + 16) + (varsLength + 12) + (attributesLength + 12) +
         m_MetadataSet.MiniFooterSize);
 
-    auto &buffer = m_HeapBuffer.m_Data;
-    auto &position = m_HeapBuffer.m_DataPosition;
+    auto &buffer = m_Data.m_Buffer;
+    auto &position = m_Data.m_Position;
+    auto &absolutePosition = m_Data.m_AbsolutePosition;
 
     // reserve data to fit metadata,
     // must replace with growth buffer strategy?
-    m_HeapBuffer.ResizeData(position + footerSize);
+    m_Data.Resize(position + footerSize,
+                  " when writing metadata in bp data buffer");
 
     // write pg index
     CopyToBuffer(buffer, position, &pgCount);
@@ -522,7 +507,7 @@ void BP1Writer::FlattenMetadata() noexcept
 
     // getting absolute offsets, minifooter is 28 bytes for now
     const uint64_t offsetPGIndex =
-        static_cast<const uint64_t>(m_HeapBuffer.m_DataAbsolutePosition);
+        static_cast<const uint64_t>(absolutePosition);
     const uint64_t offsetVarsIndex =
         static_cast<const uint64_t>(offsetPGIndex + (pgLength + 16));
     const uint64_t offsetAttributeIndex =
@@ -544,12 +529,498 @@ void BP1Writer::FlattenMetadata() noexcept
     {
     }
 
-    m_HeapBuffer.m_DataAbsolutePosition += footerSize;
+    absolutePosition += footerSize;
 
     if (m_Profiler.IsActive)
     {
-        m_Profiler.Bytes.emplace("buffering",
-                                 m_HeapBuffer.m_DataAbsolutePosition);
+        m_Profiler.Bytes.emplace("buffering", absolutePosition);
+    }
+}
+
+void BP1Writer::AggregateIndex(const SerialElementIndex &index,
+                               const size_t count)
+{
+    auto &buffer = m_Metadata.m_Buffer;
+    auto &position = m_Metadata.m_Position;
+
+    size_t countPosition = position;
+    const size_t totalCount =
+        ReduceValues<size_t>(count, m_BP1Aggregator.m_MPIComm);
+
+    if (m_BP1Aggregator.m_RankMPI == 0)
+    {
+        // Write count
+        position += 16;
+        m_Metadata.Resize(position, " in call to AggregateIndex bp1 metadata");
+        const uint64_t totalCountU64 = static_cast<const uint64_t>(totalCount);
+        CopyToBuffer(buffer, countPosition, &totalCountU64);
+    }
+
+    // write contents
+    GathervVectors(index.Buffer, buffer, position, m_BP1Aggregator.m_MPIComm);
+
+    // get total length and write it after count and before index
+    if (m_BP1Aggregator.m_RankMPI == 0)
+    {
+        const uint64_t totalLengthU64 =
+            static_cast<const uint64_t>(position - countPosition - 8);
+        CopyToBuffer(buffer, countPosition, &totalLengthU64);
+    }
+}
+
+void BP1Writer::AggregateMergeIndex(
+    const std::unordered_map<std::string, SerialElementIndex> &indices) noexcept
+{
+    // first serialize index
+    std::vector<char> serializedIndices = SerializeIndices(indices);
+    // gather in rank 0
+    std::vector<char> gatheredSerialIndices;
+    size_t gatheredSerialIndicesPosition = 0;
+
+    GathervVectors(serializedIndices, gatheredSerialIndices,
+                   gatheredSerialIndicesPosition, m_BP1Aggregator.m_MPIComm);
+
+    // deallocate local serialized Indices
+    std::vector<char>().swap(serializedIndices);
+
+    // deserialize in [name][rank] order
+    const std::unordered_map<std::string, std::vector<SerialElementIndex>>
+        nameRankIndices =
+            DeserializeIndicesPerRankThreads(gatheredSerialIndices);
+
+    // deallocate gathered serial indices (full in rank 0 only)
+    std::vector<char>().swap(gatheredSerialIndices);
+
+    // to write count and length
+    auto &buffer = m_Metadata.m_Buffer;
+    auto &position = m_Metadata.m_Position;
+
+    size_t countPosition = position;
+
+    if (m_BP1Aggregator.m_RankMPI == 0)
+    {
+        // Write count
+        position += 12;
+        m_Metadata.Resize(position,
+                          ", in call to AggregateMergeIndex bp1 metadata");
+        const uint64_t totalCountU64 =
+            static_cast<const uint64_t>(nameRankIndices.size());
+        CopyToBuffer(buffer, countPosition, &totalCountU64);
+    }
+
+    MergeSerializeIndices(nameRankIndices);
+
+    if (m_BP1Aggregator.m_RankMPI == 0)
+    {
+        // Write length
+        const uint64_t totalLengthU64 =
+            static_cast<const uint64_t>(position - countPosition - 8);
+        CopyToBuffer(buffer, countPosition, &totalLengthU64);
+    }
+}
+
+std::vector<char> BP1Writer::SerializeIndices(
+    const std::unordered_map<std::string, SerialElementIndex> &indices) const
+    noexcept
+{
+    std::vector<char> serializedIndices;
+
+    for (const auto &indexPair : indices)
+    {
+        const SerialElementIndex &index = indexPair.second;
+
+        // add rank at the beginning
+        const uint32_t rankSource =
+            static_cast<const uint32_t>(m_BP1Aggregator.m_RankMPI);
+        InsertToBuffer(serializedIndices, &rankSource);
+
+        // insert buffer
+        InsertToBuffer(serializedIndices, index.Buffer.data(),
+                       index.Buffer.size());
+    }
+
+    return serializedIndices;
+}
+
+std::unordered_map<std::string, std::vector<BP1Base::SerialElementIndex>>
+BP1Writer::DeserializeIndicesPerRankThreads(
+    const std::vector<char> &serialized) const noexcept
+{
+    auto lf_Deserialize = [&](
+        const int rankSource, const std::vector<char> &serialized,
+        const size_t serializedPosition,
+        std::unordered_map<std::string, std::vector<SerialElementIndex>>
+            &deserialized) {
+
+        size_t localPosition = serializedPosition;
+        ElementIndexHeader header =
+            ReadElementIndexHeader(serialized, localPosition);
+
+        // mutex portion
+        {
+            std::lock_guard<std::mutex> lock(m_Mutex);
+            // inside mutex to avoid race condition
+            if (deserialized.count(header.Name) == 0)
+            {
+                deserialized[header.Name] = std::vector<SerialElementIndex>(
+                    m_BP1Aggregator.m_SizeMPI,
+                    SerialElementIndex(header.MemberID, 0));
+            }
+        }
+
+        const size_t bufferSize = static_cast<const size_t>(header.Length) + 4;
+        SerialElementIndex &index = deserialized[header.Name][rankSource];
+        InsertToBuffer(index.Buffer, &serialized[serializedPosition],
+                       bufferSize);
+    };
+
+    // BODY OF FUNCTION starts here
+    std::unordered_map<std::string, std::vector<SerialElementIndex>>
+        deserialized;
+    const size_t serializedSize = serialized.size();
+
+    if (m_BP1Aggregator.m_RankMPI != 0 || serializedSize < 8)
+    {
+        return deserialized;
+    }
+
+    size_t serializedPosition = 0;
+
+    std::vector<std::future<void>> asyncs(m_Threads);
+    std::vector<size_t> asyncPositions(m_Threads);
+    std::vector<int> asyncRankSources(m_Threads);
+
+    bool launched = false;
+
+    while (serializedPosition < serializedSize)
+    {
+        // extract rank and index buffer size
+        for (unsigned int t = 0; t < m_Threads; ++t)
+        {
+            const int rankSource = static_cast<const int>(
+                ReadValue<uint32_t>(serialized, serializedPosition));
+            asyncRankSources[t] = rankSource;
+            asyncPositions[t] = serializedPosition;
+
+            const size_t bufferSize = static_cast<const size_t>(
+                ReadValue<uint32_t>(serialized, serializedPosition));
+            serializedPosition += bufferSize;
+
+            if (launched)
+            {
+                asyncs[t].get();
+            }
+
+            if (serializedPosition <= serializedSize)
+            {
+                asyncs[t] =
+                    std::async(std::launch::async, lf_Deserialize,
+                               asyncRankSources[t], std::ref(serialized),
+                               asyncPositions[t], std::ref(deserialized));
+            }
+        }
+
+        launched = true;
+    }
+
+    for (auto &async : asyncs)
+    {
+        if (async.valid())
+        {
+            async.wait();
+        }
+    }
+
+    return deserialized;
+}
+
+void BP1Writer::MergeSerializeIndices(
+    const std::unordered_map<std::string, std::vector<SerialElementIndex>>
+        &nameRankIndices) noexcept
+{
+    auto lf_GetCharacteristics = [&](const std::vector<char> &buffer,
+                                     size_t &position, const uint8_t dataType,
+                                     uint8_t &count, uint32_t &length,
+                                     uint32_t &timeStep)
+
+    {
+        switch (dataType)
+        {
+
+        case (type_byte):
+        {
+            const auto characteristics =
+                ReadElementIndexCharacteristics<char>(buffer, position, true);
+            count = characteristics.Count;
+            length = characteristics.Length;
+            timeStep = characteristics.Statistics.TimeStep;
+            break;
+        }
+
+        case (type_short):
+        {
+            const auto characteristics =
+                ReadElementIndexCharacteristics<short>(buffer, position, true);
+            count = characteristics.Count;
+            length = characteristics.Length;
+            timeStep = characteristics.Statistics.TimeStep;
+            break;
+        }
+
+        case (type_integer):
+        {
+            const auto characteristics =
+                ReadElementIndexCharacteristics<int>(buffer, position, true);
+            count = characteristics.Count;
+            length = characteristics.Length;
+            timeStep = characteristics.Statistics.TimeStep;
+            break;
+        }
+
+        case (type_long):
+        {
+            const auto characteristics =
+                ReadElementIndexCharacteristics<long int>(buffer, position,
+                                                          true);
+            count = characteristics.Count;
+            length = characteristics.Length;
+            timeStep = characteristics.Statistics.TimeStep;
+            break;
+        }
+
+        case (type_unsigned_byte):
+        {
+            const auto characteristics =
+                ReadElementIndexCharacteristics<unsigned char>(buffer, position,
+                                                               true);
+            count = characteristics.Count;
+            length = characteristics.Length;
+            timeStep = characteristics.Statistics.TimeStep;
+            break;
+        }
+
+        case (type_unsigned_short):
+        {
+            const auto characteristics =
+                ReadElementIndexCharacteristics<unsigned short>(buffer,
+                                                                position, true);
+            count = characteristics.Count;
+            length = characteristics.Length;
+            timeStep = characteristics.Statistics.TimeStep;
+            break;
+        }
+
+        case (type_unsigned_integer):
+        {
+            const auto characteristics =
+                ReadElementIndexCharacteristics<unsigned int>(buffer, position,
+                                                              true);
+            count = characteristics.Count;
+            length = characteristics.Length;
+            timeStep = characteristics.Statistics.TimeStep;
+            break;
+        }
+
+        case (type_unsigned_long):
+        {
+            auto characteristics =
+                ReadElementIndexCharacteristics<unsigned long int>(
+                    buffer, position, true);
+            count = characteristics.Count;
+            length = characteristics.Length;
+            timeStep = characteristics.Statistics.TimeStep;
+            break;
+        }
+
+        case (type_real):
+        {
+            auto characteristics =
+                ReadElementIndexCharacteristics<float>(buffer, position, true);
+            count = characteristics.Count;
+            length = characteristics.Length;
+            timeStep = characteristics.Statistics.TimeStep;
+            break;
+        }
+
+        case (type_double):
+        {
+            auto characteristics =
+                ReadElementIndexCharacteristics<double>(buffer, position, true);
+            count = characteristics.Count;
+            length = characteristics.Length;
+            timeStep = characteristics.Statistics.TimeStep;
+            break;
+        }
+            // TODO: complex, string, string array, long double
+        }
+
+    };
+
+    auto lf_MergeRank = [&](const std::vector<SerialElementIndex> &indices) {
+
+        // extract header
+        ElementIndexHeader header;
+        // index non-empty buffer
+        size_t firstRank = 0;
+        // index positions per rank
+        std::vector<size_t> positions(indices.size(), 0);
+        // merge index length
+        uint32_t entryLength = 0;
+        size_t headerSize = 0;
+
+        for (size_t r = 0; r < indices.size(); ++r)
+        {
+            const auto &buffer = indices[r].Buffer;
+            if (buffer.empty())
+            {
+                continue;
+            }
+            size_t &position = positions[r];
+
+            header = ReadElementIndexHeader(buffer, position);
+            firstRank = r;
+            entryLength += position;
+            headerSize += position;
+            break;
+        }
+
+        uint64_t setsCount = 0;
+        unsigned int currentTimeStep = 1;
+        bool marching = true;
+        std::vector<char> sorted;
+
+        while (marching)
+        {
+            marching = false;
+
+            for (size_t r = firstRank; r < indices.size(); ++r)
+            {
+                const auto &buffer = indices[r].Buffer;
+                if (buffer.empty())
+                {
+                    continue;
+                }
+
+                auto &position = positions[r];
+                if (position < buffer.size())
+                {
+                    marching = true;
+                }
+                else
+                {
+                    continue;
+                }
+
+                uint8_t count = 0;
+                uint32_t length = 0;
+                uint32_t timeStep = static_cast<uint32_t>(currentTimeStep);
+
+                while (timeStep == currentTimeStep)
+                {
+                    size_t localPosition = position;
+                    lf_GetCharacteristics(buffer, localPosition,
+                                          header.DataType, count, length,
+                                          timeStep);
+
+                    if (timeStep != currentTimeStep)
+                    {
+                        break;
+                    }
+
+                    entryLength += length + 5;
+                    ++setsCount;
+
+                    // here copy to sorted buffer
+                    InsertToBuffer(sorted, &buffer[position], length + 5);
+                    position += length + 5;
+
+                    if (position >= buffer.size())
+                    {
+                        break;
+                    }
+                }
+            }
+            ++currentTimeStep;
+        }
+
+        // Copy header to metadata buffer, need mutex here
+        {
+            std::lock_guard<std::mutex> lock(m_Mutex);
+            auto &buffer = m_Metadata.m_Buffer;
+            auto &position = m_Metadata.m_Position;
+
+            m_Metadata.Resize(buffer.size() + headerSize + sorted.size(),
+                              "in call to MergeSerializeIndices bp1 metadata");
+
+            CopyToBuffer(buffer, position, indices[firstRank].Buffer.data(),
+                         headerSize);
+
+            CopyToBuffer(buffer, position, sorted.data(), sorted.size());
+        }
+    };
+
+    auto lf_MergeRankRange = [&](
+        const std::unordered_map<std::string, std::vector<SerialElementIndex>>
+            &nameRankIndices,
+        const std::vector<std::string> &names, const size_t start,
+        const size_t end)
+
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            auto itIndex = nameRankIndices.find(names[i]);
+            lf_MergeRank(itIndex->second);
+        }
+    };
+    // BODY OF FUNCTION STARTS HERE
+    if (m_Threads == 1) // serial version
+    {
+        for (const auto &rankIndices : nameRankIndices)
+        {
+            lf_MergeRank(rankIndices.second);
+        }
+        return;
+    }
+
+    // if threaded
+    const size_t elements = nameRankIndices.size();
+    const size_t stride = elements / m_Threads;        // elements per thread
+    const size_t last = stride + elements % m_Threads; // remainder to last
+
+    std::vector<std::thread> threads;
+    threads.reserve(m_Threads);
+
+    // copy names in order to use threads
+    std::vector<std::string> names;
+    names.reserve(nameRankIndices.size());
+
+    for (const auto &nameRankIndexPair : nameRankIndices)
+    {
+        names.push_back(nameRankIndexPair.first);
+    }
+
+    for (unsigned int t = 0; t < m_Threads; ++t)
+    {
+        const size_t start = stride * t;
+        size_t end;
+
+        if (t == m_Threads - 1)
+        {
+            end = start + stride;
+        }
+        else
+        {
+            end = start + last;
+        }
+
+        threads.push_back(std::thread(lf_MergeRankRange,
+                                      std::ref(nameRankIndices),
+                                      std::ref(names), start, end));
+    }
+
+    for (auto &thread : threads)
+    {
+        thread.join();
     }
 }
 
@@ -569,4 +1040,4 @@ ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
 //------------------------------------------------------------------------------
 
 } // end namespace format
-} // end namespace adios
+} // end namespace adios2
diff --git a/source/adios2/toolkit/format/bp1/BP1Writer.h b/source/adios2/toolkit/format/bp1/BP1Writer.h
index 5ba3fed6f527dbba902cfb4c9bfed640370319e7..7fec25cdb282c10ab9d98d45cbbcdc18266b9bb7 100644
--- a/source/adios2/toolkit/format/bp1/BP1Writer.h
+++ b/source/adios2/toolkit/format/bp1/BP1Writer.h
@@ -11,11 +11,7 @@
 #ifndef ADIOS2_TOOLKIT_FORMAT_BP1_BP1WRITER_H_
 #define ADIOS2_TOOLKIT_FORMAT_BP1_BP1WRITER_H_
 
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <algorithm> //std::count, std::copy, std::for_each
-#include <cmath>     //std::ceil
-#include <cstring>   //std::memcpy
-/// \endcond
+#include <mutex>
 
 #include "adios2/ADIOSConfig.h"
 #include "adios2/ADIOSMacros.h"
@@ -23,9 +19,7 @@
 #include "adios2/core/Attribute.h"
 #include "adios2/core/IO.h"
 #include "adios2/core/Variable.h"
-#include "adios2/toolkit/capsule/heap/STLVector.h"
 #include "adios2/toolkit/format/bp1/BP1Base.h"
-#include "adios2/toolkit/format/bp1/BP1Structs.h"
 
 namespace adios2
 {
@@ -97,13 +91,21 @@ public:
      * @param rankProfilingJSON
      * @return profiling.json
      */
-    std::string
-    AggregateProfilingJSON(const std::string &rankProfilingJSON) noexcept;
+    std::vector<char>
+    AggregateProfilingJSON(const std::string &rankProfilingJSON);
+
+    /**
+     * Creates the final collective Metadata buffer in m_HeapBuffer.m_Metadata
+     * from all ranks
+     */
+    void AggregateCollectiveMetadata();
 
 private:
     /** BP format version */
     const uint8_t m_Version = 3;
 
+    static std::mutex m_Mutex;
+
     /**
      * Writes in BP buffer all attributes defined in an IO object.
      * Called by FlattenData function
@@ -181,7 +183,7 @@ private:
     void WriteVariableMetadataInIndex(
         const Variable<T> &variable,
         const Stats<typename TypeInfo<T>::ValueType> &stats, const bool isNew,
-        BP1Index &index) noexcept;
+        SerialElementIndex &index) noexcept;
 
     template <class T>
     void WriteVariableCharacteristics(
@@ -269,7 +271,7 @@ private:
                                    size_t &position) noexcept;
 
     /**
-     * Returns corresponding index of type BP1Index, if doesn't exists creates a
+     * Returns corresponding serial index, if doesn't exists creates a
      * new one. Used for variables and attributes
      * @param name variable or attribute name to look for index
      * @param indices look up hash table of indices
@@ -277,24 +279,67 @@ private:
      * indices
      * @return reference to BP1Index in indices
      */
-    BP1Index &GetBP1Index(const std::string name,
-                          std::unordered_map<std::string, BP1Index> &indices,
-                          bool &isNew) const noexcept;
+    SerialElementIndex &GetSerialElementIndex(
+        const std::string &name,
+        std::unordered_map<std::string, SerialElementIndex> &indices,
+        bool &isNew) const noexcept;
 
     /**
-     * Flattens the data and fills the pg length, vars count, vars length and
-     * attributes
-     * @param metadataSet
-     * @param buffer
+     * Wraps up the data buffer serialization in m_HeapBuffer and fills the pg
+     * length, vars count, vars
+     * length and attributes count and attributes length
+     * @param io object containing all attributes
      */
-    void FlattenData(IO &io) noexcept;
+    void SerializeData(IO &io) noexcept;
 
     /**
-     * Flattens the metadata indices into a single metadata buffer in capsule
-     * @param metadataSet
-     * @param buffer
+     * Serializes the metadata indices appending it into the data buffer inside
+     * m_HeapBuffer
+     */
+    void SerializeMetadataInData() noexcept;
+
+    /**
+     * Used for PG index, aggregates without merging
+     * @param index input
+     * @param count total number of indices
+     */
+    void AggregateIndex(const SerialElementIndex &index, const size_t count);
+
+    /**
+     * Collective operation to aggregate and merge (sort) indices (variables and
+     * attributes)
+     * @param indices
+     */
+    void AggregateMergeIndex(
+        const std::unordered_map<std::string, SerialElementIndex>
+            &indices) noexcept;
+
+    /**
+     * Returns a serialized buffer with all indices with format:
+     * Rank (4 bytes), Buffer
+     * @param indices input of all indices to be serialized
+     * @return buffer with serialized indices
+     */
+    std::vector<char> SerializeIndices(
+        const std::unordered_map<std::string, SerialElementIndex> &indices)
+        const noexcept;
+
+    /**
+     * In rank=0, deserialize gathered indices
+     * @param serializedIndices input gathered indices
+     * @return hash[name][rank] = bp index buffer
+     */
+    std::unordered_map<std::string, std::vector<SerialElementIndex>>
+    DeserializeIndicesPerRankThreads(
+        const std::vector<char> &serializedIndices) const noexcept;
+
+    /**
+     * Merge indices by time step (default) and write to m_HeapBuffer.m_Metadata
+     * @param nameRankIndices
      */
-    void FlattenMetadata() noexcept;
+    void MergeSerializeIndices(
+        const std::unordered_map<std::string, std::vector<SerialElementIndex>>
+            &nameRankIndices) noexcept;
 };
 
 #define declare_template_instantiation(T)                                      \
diff --git a/source/adios2/toolkit/format/bp1/BP1Writer.tcc b/source/adios2/toolkit/format/bp1/BP1Writer.tcc
index 321edf743638cd0e293f5f64dd90e6bd6a1d36b6..ef8fa3f1cb6d680dbd9c09784108d9e8fefde309 100644
--- a/source/adios2/toolkit/format/bp1/BP1Writer.tcc
+++ b/source/adios2/toolkit/format/bp1/BP1Writer.tcc
@@ -7,6 +7,7 @@
  *  Created on: Apr 11, 2017
  *      Author: William F Godoy godoywf@ornl.gov
  */
+
 #ifndef ADIOS2_TOOLKIT_FORMAT_BP1_BP1WRITER_TCC_
 #define ADIOS2_TOOLKIT_FORMAT_BP1_BP1WRITER_TCC_
 
@@ -22,53 +23,43 @@ namespace format
 template <class T>
 void BP1Writer::WriteVariableMetadata(const Variable<T> &variable) noexcept
 {
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Resume();
-    }
+    ProfilerStart("buffering");
 
     Stats<typename TypeInfo<T>::ValueType> stats = GetStats(variable);
 
-    stats.TimeIndex = m_MetadataSet.TimeStep;
     // Get new Index or point to existing index
     bool isNew = true; // flag to check if variable is new
-    BP1Index &variableIndex =
-        GetBP1Index(variable.m_Name, m_MetadataSet.VarsIndices, isNew);
+    SerialElementIndex &variableIndex = GetSerialElementIndex(
+        variable.m_Name, m_MetadataSet.VarsIndices, isNew);
     stats.MemberID = variableIndex.MemberID;
 
+    auto &absolutePosition = m_Data.m_AbsolutePosition;
+
     // write metadata header in data and extract offsets
-    stats.Offset = static_cast<uint64_t>(m_HeapBuffer.m_DataAbsolutePosition);
+    stats.Offset = static_cast<uint64_t>(absolutePosition);
     WriteVariableMetadataInData(variable, stats);
-    stats.PayloadOffset = m_HeapBuffer.m_DataAbsolutePosition;
+    stats.PayloadOffset = absolutePosition;
 
     // write to metadata  index
     WriteVariableMetadataInIndex(variable, stats, isNew, variableIndex);
-
     ++m_MetadataSet.DataPGVarsCount;
 
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Pause();
-    }
+    ProfilerStop("buffering");
 }
 
 template <class T>
 void BP1Writer::WriteVariablePayload(const Variable<T> &variable) noexcept
 {
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Resume();
-    }
+    ProfilerStart("buffering");
+    auto &buffer = m_Data.m_Buffer;
+    auto &position = m_Data.m_Position;
+    CopyToBufferThreads(buffer, position, variable.m_AppValues,
+                        variable.TotalSize(), m_Threads);
 
-    CopyToBufferThreads(m_HeapBuffer.m_Data, m_HeapBuffer.m_DataPosition,
-                        variable.m_AppValues, variable.TotalSize(), m_Threads);
+    auto &absolutePosition = m_Data.m_AbsolutePosition;
+    absolutePosition += variable.PayLoadSize();
 
-    m_HeapBuffer.m_DataAbsolutePosition += variable.PayLoadSize();
-
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("buffering").Pause();
-    }
+    ProfilerStop("buffering");
 }
 
 // PRIVATE
@@ -76,8 +67,8 @@ template <class T>
 size_t BP1Writer::WriteAttributeHeaderInData(const Attribute<T> &attribute,
                                              Stats<T> &stats) noexcept
 {
-    auto &buffer = m_HeapBuffer.m_Data;
-    auto &position = m_HeapBuffer.m_DataPosition;
+    auto &buffer = m_Data.m_Buffer;
+    auto &position = m_Data.m_Position;
 
     // will go back to write length
     const size_t attributeLengthPosition = position;
@@ -99,8 +90,9 @@ void BP1Writer::WriteAttributeLengthInData(
     const Attribute<T> &attribute, Stats<T> &stats,
     const size_t attributeLengthPosition) noexcept
 {
-    auto &buffer = m_HeapBuffer.m_Data;
-    auto &position = m_HeapBuffer.m_DataPosition;
+    auto &buffer = m_Data.m_Buffer;
+    auto &position = m_Data.m_Position;
+    auto &absolutePosition = m_Data.m_AbsolutePosition;
 
     // back to attribute length
     const uint32_t attributeLength =
@@ -108,7 +100,7 @@ void BP1Writer::WriteAttributeLengthInData(
     size_t backPosition = attributeLengthPosition;
     CopyToBuffer(buffer, backPosition, &attributeLengthPosition);
 
-    m_HeapBuffer.m_DataAbsolutePosition += position - attributeLengthPosition;
+    absolutePosition += position - attributeLengthPosition;
 }
 
 template <>
@@ -119,8 +111,9 @@ BP1Writer::WriteAttributeInData(const Attribute<std::string> &attribute,
     const size_t attributeLengthPosition =
         WriteAttributeHeaderInData(attribute, stats);
 
-    auto &buffer = m_HeapBuffer.m_Data;
-    auto &position = m_HeapBuffer.m_DataPosition;
+    auto &buffer = m_Data.m_Buffer;
+    auto &position = m_Data.m_Position;
+    auto &absolutePosition = m_Data.m_AbsolutePosition;
 
     uint8_t dataType = GetDataType<std::string>();
     if (!attribute.m_IsSingleValue)
@@ -130,8 +123,7 @@ BP1Writer::WriteAttributeInData(const Attribute<std::string> &attribute,
     CopyToBuffer(buffer, position, &dataType);
 
     // here record payload offset
-    stats.PayloadOffset = m_HeapBuffer.m_DataAbsolutePosition + position -
-                          attributeLengthPosition;
+    stats.PayloadOffset = absolutePosition + position - attributeLengthPosition;
 
     if (dataType == type_string)
     {
@@ -170,15 +162,15 @@ void BP1Writer::WriteAttributeInData(const Attribute<T> &attribute,
     const size_t attributeLengthPosition =
         WriteAttributeHeaderInData(attribute, stats);
 
-    auto &buffer = m_HeapBuffer.m_Data;
-    auto &position = m_HeapBuffer.m_DataPosition;
+    auto &buffer = m_Data.m_Buffer;
+    auto &position = m_Data.m_Position;
+    auto &absolutePosition = m_Data.m_AbsolutePosition;
 
     uint8_t dataType = GetDataType<T>();
     CopyToBuffer(buffer, position, &dataType);
 
     // here record payload offset
-    stats.PayloadOffset = m_HeapBuffer.m_DataAbsolutePosition + position -
-                          attributeLengthPosition;
+    stats.PayloadOffset = absolutePosition + position - attributeLengthPosition;
 
     const uint32_t dataSize = attribute.m_Elements * sizeof(T);
     CopyToBuffer(buffer, position, &dataSize);
@@ -201,7 +193,8 @@ inline void BP1Writer::WriteAttributeCharacteristicValueInIndex(
     uint8_t &characteristicsCounter, const Attribute<std::string> &attribute,
     std::vector<char> &buffer) noexcept
 {
-    uint8_t characteristicID = characteristic_value;
+    const uint8_t characteristicID =
+        static_cast<const uint8_t>(CharacteristicID::characteristic_value);
 
     InsertToBuffer(buffer, &characteristicID);
 
@@ -235,7 +228,7 @@ void BP1Writer::WriteAttributeCharacteristicValueInIndex(
     uint8_t &characteristicsCounter, const Attribute<T> &attribute,
     std::vector<char> &buffer) noexcept
 {
-    uint8_t characteristicID = characteristic_value;
+    const uint8_t characteristicID = CharacteristicID::characteristic_value;
 
     InsertToBuffer(buffer, &characteristicID);
 
@@ -255,7 +248,7 @@ template <class T>
 void BP1Writer::WriteAttributeInIndex(const Attribute<T> &attribute,
                                       const Stats<T> &stats) noexcept
 {
-    BP1Index index(stats.MemberID);
+    SerialElementIndex index(stats.MemberID);
     auto &buffer = index.Buffer;
 
     buffer.insert(buffer.end(), 4, '\0'); // skip attribute length (4)
@@ -299,12 +292,10 @@ void BP1Writer::WriteAttributeInIndex(const Attribute<T> &attribute,
 
     // TIME Index
     WriteCharacteristicRecord(characteristic_time_index, characteristicsCounter,
-                              stats.TimeIndex, buffer);
+                              stats.TimeStep, buffer);
 
-    const uint32_t rankU32 =
-        static_cast<const uint32_t>(m_BP1Aggregator.m_RankMPI);
     WriteCharacteristicRecord(characteristic_file_index, characteristicsCounter,
-                              rankU32, buffer);
+                              stats.FileIndex, buffer);
 
     WriteCharacteristicRecord(characteristic_offset, characteristicsCounter,
                               stats.Offset, buffer);
@@ -340,6 +331,9 @@ BP1Writer::GetStats(const Variable<T> &variable) const noexcept
         GetMinMaxThreads(variable.m_AppValues, valuesSize, stats.Min, stats.Max,
                          m_Threads);
     }
+
+    stats.TimeStep = m_MetadataSet.TimeStep;
+    stats.FileIndex = static_cast<uint32_t>(m_BP1Aggregator.m_RankMPI);
     return stats;
 }
 
@@ -348,8 +342,9 @@ void BP1Writer::WriteVariableMetadataInData(
     const Variable<T> &variable,
     const Stats<typename TypeInfo<T>::ValueType> &stats) noexcept
 {
-    auto &buffer = m_HeapBuffer.m_Data;
-    auto &position = m_HeapBuffer.m_DataPosition;
+    auto &buffer = m_Data.m_Buffer;
+    auto &position = m_Data.m_Position;
+    auto &absolutePosition = m_Data.m_AbsolutePosition;
 
     // for writing length at the end
     const size_t varLengthPosition = position;
@@ -389,14 +384,14 @@ void BP1Writer::WriteVariableMetadataInData(
     size_t backPosition = varLengthPosition;
     CopyToBuffer(buffer, backPosition, &varLength);
 
-    m_HeapBuffer.m_DataAbsolutePosition += position - varLengthPosition;
+    absolutePosition += position - varLengthPosition;
 }
 
 template <class T>
 void BP1Writer::WriteVariableMetadataInIndex(
     const Variable<T> &variable,
     const Stats<typename TypeInfo<T>::ValueType> &stats, const bool isNew,
-    BP1Index &index) noexcept
+    SerialElementIndex &index) noexcept
 {
     auto &buffer = index.Buffer;
 
@@ -420,6 +415,7 @@ void BP1Writer::WriteVariableMetadataInIndex(
         if (m_Verbosity == 0)
         {
             ++index.Count;
+            // fixed since group and path are not printed
             size_t setsCountPosition = 15 + variable.m_Name.size();
             CopyToBuffer(buffer, setsCountPosition, &index.Count);
         }
@@ -435,7 +431,6 @@ void BP1Writer::WriteBoundsRecord(const bool isScalar, const Stats<T> &stats,
 {
     if (isScalar)
     {
-        // stats.min = stats.max = value, need to test
         WriteCharacteristicRecord(characteristic_value, characteristicsCounter,
                                   stats.Min, buffer);
     }
@@ -517,6 +512,15 @@ void BP1Writer::WriteVariableCharacteristics(
     uint8_t characteristicsCounter = 0;
 
     // DIMENSIONS
+    WriteCharacteristicRecord(characteristic_time_index, characteristicsCounter,
+                              stats.TimeStep, buffer);
+
+    WriteCharacteristicRecord(characteristic_file_index, characteristicsCounter,
+                              stats.FileIndex, buffer);
+
+    WriteBoundsRecord(variable.m_SingleValue, stats, characteristicsCounter,
+                      buffer);
+
     uint8_t characteristicID = characteristic_dimensions;
     InsertToBuffer(buffer, &characteristicID);
     const uint8_t dimensions =
@@ -529,17 +533,6 @@ void BP1Writer::WriteVariableCharacteristics(
                           buffer);
     ++characteristicsCounter;
 
-    WriteBoundsRecord(variable.m_SingleValue, stats, characteristicsCounter,
-                      buffer);
-
-    WriteCharacteristicRecord(characteristic_time_index, characteristicsCounter,
-                              stats.TimeIndex, buffer);
-
-    const uint32_t rankU32 =
-        static_cast<const uint32_t>(m_BP1Aggregator.m_RankMPI);
-    WriteCharacteristicRecord(characteristic_file_index, characteristicsCounter,
-                              rankU32, buffer);
-
     WriteCharacteristicRecord(characteristic_offset, characteristicsCounter,
                               stats.Offset, buffer);
 
diff --git a/source/adios2/toolkit/interop/adios1/ADIOS1Common.cpp b/source/adios2/toolkit/interop/adios1/ADIOS1Common.cpp
index b28ca77e78ff8c2810a7c08ae21163261ed0ef3b..c3937148753e138103d6438f6ab96da90f94bdfb 100644
--- a/source/adios2/toolkit/interop/adios1/ADIOS1Common.cpp
+++ b/source/adios2/toolkit/interop/adios1/ADIOS1Common.cpp
@@ -125,7 +125,7 @@ void ADIOS1Common::InitTransports(
     }
 }
 
-bool ADIOS1Common::Open(const OpenMode openMode)
+bool ADIOS1Common::Open(const Mode openMode)
 {
     adios_open(&m_ADIOSFile, m_GroupName.c_str(), m_FileName.c_str(),
                OpenModeToString(openMode, true).c_str(), m_MPIComm);
diff --git a/source/adios2/toolkit/interop/adios1/ADIOS1Common.h b/source/adios2/toolkit/interop/adios1/ADIOS1Common.h
index 0473c896b10954f2d7d0bb4b2878184cba25d9a0..bc60faf91ca40615264e5b4824c8e7f8134d3d68 100644
--- a/source/adios2/toolkit/interop/adios1/ADIOS1Common.h
+++ b/source/adios2/toolkit/interop/adios1/ADIOS1Common.h
@@ -60,7 +60,7 @@ public:
 
     void InitParameters(const Params &parameters);
     void InitTransports(const std::vector<Params> &transportsParameters);
-    bool Open(const OpenMode openMode); // return true if file is opened
+    bool Open(const Mode openMode); // return true if file is opened
     bool ReOpenAsNeeded(); // return true if file is open or reopened
 
     template <class T>
diff --git a/source/adios2/toolkit/transport/Transport.cpp b/source/adios2/toolkit/transport/Transport.cpp
index ab945b1bae5b8b0cd28cf2ea027c9d6e2cba71bd..a1a8ae762e26ea43c155c7f7342aab4ab2930172 100644
--- a/source/adios2/toolkit/transport/Transport.cpp
+++ b/source/adios2/toolkit/transport/Transport.cpp
@@ -23,27 +23,27 @@ Transport::Transport(const std::string type, const std::string library,
     MPI_Comm_size(m_MPIComm, &m_SizeMPI);
 }
 
-void Transport::InitProfiler(const OpenMode openMode, const TimeUnit timeUnit)
+void Transport::InitProfiler(const Mode openMode, const TimeUnit timeUnit)
 {
     m_Profiler.IsActive = true;
 
     m_Profiler.Timers.emplace(std::make_pair(
         "open", profiling::Timer("open", TimeUnit::Microseconds, m_DebugMode)));
 
-    if (openMode == OpenMode::Write)
+    if (openMode == Mode::Write)
     {
         m_Profiler.Timers.emplace(
             "write", profiling::Timer("write", timeUnit, m_DebugMode));
 
         m_Profiler.Bytes.emplace("write", 0);
     }
-    else if (openMode == OpenMode::Append)
+    else if (openMode == Mode::Append)
     {
         m_Profiler.Timers.emplace(
             "append", profiling::Timer("append", timeUnit, m_DebugMode));
         m_Profiler.Bytes.emplace("append", 0);
     }
-    else if (openMode == OpenMode::Read)
+    else if (openMode == Mode::Read)
     {
         m_Profiler.Timers.emplace(
             "read", profiling::Timer("read", timeUnit, m_DebugMode));
@@ -65,4 +65,39 @@ void Transport::SetBuffer(char * /*buffer*/, size_t /*size*/)
     }
 }
 
-} // end namespace adios
+void Transport::Flush()
+{
+    if (m_DebugMode)
+    {
+        std::invalid_argument("ERROR: " + m_Name + " transport type " + m_Type +
+                              " using library " + m_Library +
+                              " doesn't implement the Flush function\n");
+    }
+}
+
+void Transport::ProfilerStart(const std::string process) noexcept
+{
+    if (m_Profiler.IsActive)
+    {
+        m_Profiler.Timers.at(process).Resume();
+    }
+}
+
+void Transport::ProfilerStop(const std::string process) noexcept
+{
+    if (m_Profiler.IsActive)
+    {
+        m_Profiler.Timers.at(process).Pause();
+    }
+}
+
+void Transport::CheckName() const
+{
+    if (m_DebugMode && m_Name.empty())
+    {
+        throw std::invalid_argument("ERROR: name can't be empty for " +
+                                    m_Library + " transport \n");
+    }
+}
+
+} // end namespace adios2
diff --git a/source/adios2/toolkit/transport/Transport.h b/source/adios2/toolkit/transport/Transport.h
index cfca583afcf3167196edd1888803971270473c24..9c1dbb176b5949eb1997f0250590b2a75a4c3812 100644
--- a/source/adios2/toolkit/transport/Transport.h
+++ b/source/adios2/toolkit/transport/Transport.h
@@ -31,7 +31,7 @@ public:
     const std::string m_Type;    ///< transport type from derived class
     const std::string m_Library; ///< library implementation (POSIX, Mdtm, etc.)
     std::string m_Name; ///< from Open, unique identifier (e.g. filename)
-    OpenMode m_OpenMode = OpenMode::Undefined; ///< at Open from ADIOSTypes.h
+    Mode m_OpenMode = Mode::Undefined; ///< at Open from ADIOSTypes.h
     bool m_IsOpen = false; ///< true: open for communication, false: unreachable
     MPI_Comm m_MPIComm;    ///< current MPI communicator
     int m_RankMPI = 0;     ///< from MPI_Comm_Rank
@@ -49,14 +49,14 @@ public:
 
     virtual ~Transport() = default;
 
-    void InitProfiler(const OpenMode openMode, const TimeUnit timeUnit);
+    void InitProfiler(const Mode openMode, const TimeUnit timeUnit);
 
     /**
      * Opens transport, required before SetBuffer, Write, Read, Flush, Close
      * @param name
      * @param openMode
      */
-    virtual void Open(const std::string &name, const OpenMode openMode) = 0;
+    virtual void Open(const std::string &name, const Mode openMode) = 0;
 
     /**
      * If OS buffered (FILE* or fstream), sets the buffer size
@@ -66,14 +66,30 @@ public:
     virtual void SetBuffer(char *buffer, size_t size);
 
     /**
-     * Writes to file stream
-     * @param buffer raw data to be written to file stream
-     * @param size number of bytes to be written to file stream
+     * Writes to transport. Note that size is non-const due to the nature of
+     * underlying transport libraries
+     * @param buffer raw data to be written
+     * @param size number of bytes to be written
+     * @param start starting position for writing (to allow rewind), if not
+     * passed then start at current stream position
      */
-    virtual void Write(const char *buffer, size_t size) = 0;
+    virtual void Write(const char *buffer, size_t size,
+                       size_t start = MaxSizeT) = 0;
+
+    /**
+     * Reads from transport "size" bytes from a certain position. Note that size
+     * and position and non-const due to the nature of underlying transport
+     * libraries
+     * @param buffer raw data pointer to put the read bytes (must be
+     * preallocated)
+     * @param size number of bytes to be read
+     * @param start starting position for read, if not passed then start at
+     * current stream position
+     */
+    virtual void Read(char *buffer, size_t size, size_t start = MaxSizeT) = 0;
 
     /** flushes current contents to physical medium without closing */
-    virtual void Flush() = 0;
+    virtual void Flush();
 
     /** closes current file, after this file becomes unreachable */
     virtual void Close() = 0;
@@ -81,8 +97,14 @@ public:
 protected:
     /** true: turn on exceptions */
     const bool m_DebugMode = false;
+
+    void ProfilerStart(const std::string process) noexcept;
+
+    void ProfilerStop(const std::string process) noexcept;
+
+    void CheckName() const;
 };
 
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_TOOLKIT_TRANSPORT_TRANSPORT_H_ */
diff --git a/source/adios2/toolkit/transport/file/FileDescriptor.cpp b/source/adios2/toolkit/transport/file/FileDescriptor.cpp
deleted file mode 100644
index 879ca2b702f71392d3137a73f16f6b45c9101778..0000000000000000000000000000000000000000
--- a/source/adios2/toolkit/transport/file/FileDescriptor.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * FileDescriptor.cpp file I/O using POSIX I/O library
- *
- *  Created on: Oct 6, 2016
- *      Author: William F Godoy godoywf@ornl.gov
- */
-
-#include "FileDescriptor.h"
-
-#include <fcntl.h>     // open
-#include <stddef.h>    // write output
-#include <sys/stat.h>  // open
-#include <sys/types.h> // open
-#include <unistd.h>    // write, close
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <ios> //std::ios_base::failure
-#include <iostream>
-/// \endcond
-
-namespace adios2
-{
-namespace transport
-{
-
-FileDescriptor::FileDescriptor(MPI_Comm mpiComm, const bool debugMode)
-: Transport("File", "POSIX", mpiComm, debugMode)
-{
-}
-
-FileDescriptor::~FileDescriptor()
-{
-    if (m_IsOpen)
-    {
-        close(m_FileDescriptor);
-    }
-}
-
-void FileDescriptor::Open(const std::string &name, const OpenMode openMode)
-{
-    if (m_DebugMode)
-    {
-        if (name.empty())
-        {
-            throw std::invalid_argument(
-                "ERROR: file name is empty, in call to FilePointer Open\n");
-        }
-    }
-
-    m_Name = name;
-    m_OpenMode = openMode;
-
-    if (openMode == OpenMode::Write)
-    {
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("open").Resume();
-        }
-
-        m_FileDescriptor = open(m_Name.c_str(), O_WRONLY | O_CREAT, 0777);
-
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("open").Pause();
-        }
-    }
-    else if (openMode == OpenMode::Append)
-    {
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("open").Resume();
-        }
-
-        // TODO we need to change this to read/write
-        m_FileDescriptor = open(m_Name.c_str(), O_WRONLY | O_APPEND);
-
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("open").Pause();
-        }
-    }
-    else if (openMode == OpenMode::Read)
-    {
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("open").Resume();
-        }
-
-        m_FileDescriptor = open(m_Name.c_str(), O_RDONLY);
-
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("open").Pause();
-        }
-    }
-
-    if (m_DebugMode)
-    {
-        if (m_FileDescriptor == -1)
-        {
-            throw std::ios_base::failure("ERROR: couldn't open file " + m_Name +
-                                         ", check permissions or existence, in "
-                                         "call to FileDescriptor Open\n");
-        }
-    }
-
-    m_IsOpen = true;
-}
-
-void FileDescriptor::Write(const char *buffer, size_t size)
-{
-    auto lf_Write = [&](const char *buffer, size_t size) {
-
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("write").Resume();
-        }
-        auto writtenSize = write(m_FileDescriptor, buffer, size);
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("write").Pause();
-        }
-
-        if (writtenSize == -1)
-        {
-            throw std::ios_base::failure("ERROR: couldn't write to file " +
-                                         m_Name +
-                                         ", in call to FileDescriptor Write\n");
-        }
-
-        if (static_cast<size_t>(writtenSize) != size)
-        {
-            throw std::ios_base::failure(
-                "ERROR: written size + " + std::to_string(writtenSize) +
-                " is not equal to intended size " + std::to_string(size) +
-                " in file " + m_Name + ", in call to FileDescriptor Write\n");
-        }
-    };
-
-    if (size > DefaultMaxFileBatchSize)
-    {
-        const size_t batches = size / DefaultMaxFileBatchSize;
-        const size_t remainder = size % DefaultMaxFileBatchSize;
-
-        size_t position = 0;
-        for (size_t b = 0; b < batches; ++b)
-        {
-            lf_Write(&buffer[position], DefaultMaxFileBatchSize);
-            position += DefaultMaxFileBatchSize;
-        }
-        lf_Write(&buffer[position], remainder);
-    }
-    else
-    {
-        lf_Write(buffer, size);
-    }
-}
-
-void FileDescriptor::Flush() {}
-
-void FileDescriptor::Close()
-{
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("close").Resume();
-    }
-
-    const int status = close(m_FileDescriptor);
-
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("close").Pause();
-    }
-
-    if (status == -1)
-    {
-        throw std::ios_base::failure("ERROR: couldn't close file " + m_Name +
-                                     ", in call to FileDescriptor Close\n");
-    }
-
-    m_IsOpen = false;
-}
-
-} // end namespace transport
-} // end namespace adios
diff --git a/source/adios2/toolkit/transport/file/FileFStream.cpp b/source/adios2/toolkit/transport/file/FileFStream.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fbfa5cccac620553fade45a9fc43294fe22a838a
--- /dev/null
+++ b/source/adios2/toolkit/transport/file/FileFStream.cpp
@@ -0,0 +1,169 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileStream.cpp
+ *
+ *  Created on: Oct 24, 2016
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+#include "FileFStream.h"
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <ios> // std::ios_base::failure
+/// \endcond
+
+namespace adios2
+{
+namespace transport
+{
+
+FileFStream::FileFStream(MPI_Comm mpiComm, const bool debugMode)
+: Transport("File", "fstream", mpiComm, debugMode)
+{
+}
+
+void FileFStream::Open(const std::string &name, const Mode openMode)
+{
+    m_Name = name;
+    CheckName();
+    m_OpenMode = openMode;
+
+    switch (m_OpenMode)
+    {
+    case (Mode::Write):
+        ProfilerStart("open");
+        m_FileStream.open(name, std::fstream::out | std::fstream::binary);
+        ProfilerStop("open");
+        break;
+
+    case (Mode::Append):
+        ProfilerStart("open");
+        m_FileStream.open(name, std::fstream::in | std::fstream::out |
+                                    std::fstream::binary);
+        ProfilerStop("open");
+        break;
+
+    case (Mode::Read):
+        ProfilerStart("open");
+        m_FileStream.open(name, std::fstream::in | std::fstream::binary);
+        ProfilerStop("open");
+        break;
+
+    default:
+        CheckFile("unknown open mode for file " + m_Name +
+                  ", in call to stream open");
+    }
+
+    CheckFile("couldn't open file " + m_Name +
+              ", check permissions or path existence, in call to fstream open");
+    m_IsOpen = true;
+}
+
+void FileFStream::SetBuffer(char *buffer, size_t size)
+{
+    m_FileStream.rdbuf()->pubsetbuf(buffer, size);
+    CheckFile("couldn't set buffer in file " + m_Name +
+              ", in call to fstream rdbuf()->pubsetbuf");
+}
+
+void FileFStream::Write(const char *buffer, size_t size, size_t start)
+{
+    auto lf_Write = [&](const char *buffer, size_t size) {
+
+        ProfilerStart("write");
+        m_FileStream.write(buffer, static_cast<std::streamsize>(size));
+        ProfilerStop("write");
+        CheckFile("couldn't write from file " + m_Name +
+                  ", in call to fstream write");
+    };
+
+    if (start != MaxSizeT)
+    {
+        m_FileStream.seekp(start);
+        CheckFile("couldn't move to start position " + std::to_string(start) +
+                  " in file " + m_Name + ", in call to fstream seekp");
+    }
+
+    if (size > DefaultMaxFileBatchSize)
+    {
+        const size_t batches = size / DefaultMaxFileBatchSize;
+        const size_t remainder = size % DefaultMaxFileBatchSize;
+
+        size_t position = 0;
+        for (size_t b = 0; b < batches; ++b)
+        {
+            lf_Write(&buffer[position], DefaultMaxFileBatchSize);
+            position += DefaultMaxFileBatchSize;
+        }
+        lf_Write(&buffer[position], remainder);
+    }
+    else
+    {
+        lf_Write(buffer, size);
+    }
+}
+
+void FileFStream::Read(char *buffer, size_t size, size_t start)
+{
+    auto lf_Read = [&](char *buffer, size_t size) {
+        ProfilerStart("read");
+        m_FileStream.read(buffer, static_cast<std::streamsize>(size));
+        ProfilerStop("read");
+        CheckFile("couldn't read from file " + m_Name +
+                  ", in call to fstream read");
+    };
+
+    if (start != MaxSizeT)
+    {
+        m_FileStream.seekg(start);
+        CheckFile("couldn't move to start position " + std::to_string(start) +
+                  " in file " + m_Name + ", in call to fstream seekg");
+    }
+
+    if (size > DefaultMaxFileBatchSize)
+    {
+        const size_t batches = size / DefaultMaxFileBatchSize;
+        const size_t remainder = size % DefaultMaxFileBatchSize;
+
+        size_t position = 0;
+        for (size_t b = 0; b < batches; ++b)
+        {
+            lf_Read(&buffer[position], DefaultMaxFileBatchSize);
+            position += DefaultMaxFileBatchSize;
+        }
+        lf_Read(&buffer[position], remainder);
+    }
+    else
+    {
+        lf_Read(buffer, size);
+    }
+}
+
+void FileFStream::Flush()
+{
+    m_FileStream.flush();
+    CheckFile("couldn't flush to file " + m_Name +
+              ", in call to fstream flush");
+}
+
+void FileFStream::Close()
+{
+    ProfilerStart("close");
+    m_FileStream.close();
+    ProfilerStop("close");
+
+    CheckFile("couldn't close file " + m_Name + ", in call to fstream close");
+    m_IsOpen = false;
+}
+
+void FileFStream::CheckFile(const std::string hint) const
+{
+    if (!m_FileStream)
+    {
+        throw std::ios_base::failure("ERROR: " + hint + "\n");
+    }
+}
+
+} // end namespace transport
+} // end namespace adios2
diff --git a/source/adios2/toolkit/transport/file/FileStream.h b/source/adios2/toolkit/transport/file/FileFStream.h
similarity index 57%
rename from source/adios2/toolkit/transport/file/FileStream.h
rename to source/adios2/toolkit/transport/file/FileFStream.h
index 21df05a7241511128bd107db6799945155ac143c..2bd628bf8436afe7d507089b5c31a345536daedd 100644
--- a/source/adios2/toolkit/transport/file/FileStream.h
+++ b/source/adios2/toolkit/transport/file/FileFStream.h
@@ -2,7 +2,7 @@
  * Distributed under the OSI-approved Apache License, Version 2.0.  See
  * accompanying file Copyright.txt for details.
  *
- * FileStream.h wrapper of C++ fstream for file I/O
+ * FileFStream.h wrapper of C++ fstream for file I/O
  *
  *  Created on: Oct 18, 2016
  *      Author: William F Godoy godoywf@ornl.gov
@@ -22,19 +22,21 @@ namespace transport
 {
 
 /** File stream transport using C++ fstream */
-class FileStream : public Transport
+class FileFStream : public Transport
 {
 
 public:
-    FileStream(MPI_Comm mpiComm, const bool debugMode);
+    FileFStream(MPI_Comm mpiComm, const bool debugMode);
 
-    ~FileStream() = default;
+    ~FileFStream() = default;
 
-    void Open(const std::string &name, const OpenMode openMode) final;
+    void Open(const std::string &name, const Mode openMode) final;
 
     void SetBuffer(char *buffer, size_t size) final;
 
-    void Write(const char *buffer, size_t size) final;
+    void Write(const char *buffer, size_t size, size_t start = MaxSizeT) final;
+
+    void Read(char *buffer, size_t size, size_t start = MaxSizeT) final;
 
     void Flush() final;
 
@@ -43,9 +45,15 @@ public:
 private:
     /** file stream using fstream library */
     std::fstream m_FileStream;
+
+    /**
+     * Check if m_FileStream is false after an operation
+     * @param hint exception message
+     */
+    void CheckFile(const std::string hint) const;
 };
 
 } // end namespace transport
-} // end namespace adios
+} // end namespace adios2
 
 #endif /* ADIOS2_TOOLKIT_TRANSPORT_FILE_FILEPOINTER_H_ */
diff --git a/source/adios2/toolkit/transport/file/FilePOSIX.cpp b/source/adios2/toolkit/transport/file/FilePOSIX.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a792ab3e4f02aa39ae7a0f5c83e26785f1503a45
--- /dev/null
+++ b/source/adios2/toolkit/transport/file/FilePOSIX.cpp
@@ -0,0 +1,216 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileDescriptor.cpp file I/O using POSIX I/O library
+ *
+ *  Created on: Oct 6, 2016
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+#include "FilePOSIX.h"
+
+#include <fcntl.h>     // open
+#include <stddef.h>    // write output
+#include <sys/stat.h>  // open
+#include <sys/types.h> // open
+#include <unistd.h>    // write, close
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <ios> //std::ios_base::failure
+/// \endcond
+
+namespace adios2
+{
+namespace transport
+{
+
+FilePOSIX::FilePOSIX(MPI_Comm mpiComm, const bool debugMode)
+: Transport("File", "POSIX", mpiComm, debugMode)
+{
+}
+
+FilePOSIX::~FilePOSIX()
+{
+    if (m_IsOpen)
+    {
+        close(m_FileDescriptor);
+    }
+}
+
+void FilePOSIX::Open(const std::string &name, const Mode openMode)
+{
+    m_Name = name;
+    CheckName();
+    m_OpenMode = openMode;
+
+    switch (m_OpenMode)
+    {
+
+    case (Mode::Write):
+        ProfilerStart("open");
+        m_FileDescriptor = open(m_Name.c_str(), O_WRONLY | O_CREAT, 0777);
+        ProfilerStop("open");
+        break;
+
+    case (Mode::Append):
+        ProfilerStart("open");
+        m_FileDescriptor = open(m_Name.c_str(), O_RDWR | O_CREAT, 0777);
+        ProfilerStop("open");
+        break;
+
+    case (Mode::Read):
+        ProfilerStart("open");
+        m_FileDescriptor = open(m_Name.c_str(), O_RDONLY | O_CREAT, 0777);
+        ProfilerStop("open");
+        break;
+
+    default:
+        CheckFile("unknown open mode for file " + m_Name +
+                  ", in call to POSIX open");
+    }
+
+    CheckFile("couldn't open file " + m_Name +
+              ", check permissions or path existence, in call to POSIX open");
+
+    m_IsOpen = true;
+}
+
+void FilePOSIX::Write(const char *buffer, size_t size, size_t start)
+{
+    auto lf_Write = [&](const char *buffer, size_t size) {
+
+        ProfilerStart("write");
+        const auto writtenSize = write(m_FileDescriptor, buffer, size);
+        ProfilerStop("write");
+
+        if (writtenSize == -1)
+        {
+            throw std::ios_base::failure("ERROR: couldn't write to file " +
+                                         m_Name +
+                                         ", in call to FileDescriptor Write\n");
+        }
+
+        if (static_cast<size_t>(writtenSize) != size)
+        {
+            throw std::ios_base::failure(
+                "ERROR: written size + " + std::to_string(writtenSize) +
+                " is not equal to intended size " + std::to_string(size) +
+                " in file " + m_Name + ", in call to FileDescriptor Write\n");
+        }
+    };
+
+    if (start != MaxSizeT)
+    {
+        const auto newPosition = lseek(m_FileDescriptor, start, SEEK_SET);
+
+        if (static_cast<size_t>(newPosition) != start)
+        {
+            throw std::ios_base::failure(
+                "ERROR: couldn't move to start position " +
+                std::to_string(start) + " in file " + m_Name +
+                ", in call to POSIX lseek\n");
+        }
+    }
+
+    if (size > DefaultMaxFileBatchSize)
+    {
+        const size_t batches = size / DefaultMaxFileBatchSize;
+        const size_t remainder = size % DefaultMaxFileBatchSize;
+
+        size_t position = 0;
+        for (size_t b = 0; b < batches; ++b)
+        {
+            lf_Write(&buffer[position], DefaultMaxFileBatchSize);
+            position += DefaultMaxFileBatchSize;
+        }
+        lf_Write(&buffer[position], remainder);
+    }
+    else
+    {
+        lf_Write(buffer, size);
+    }
+}
+
+void FilePOSIX::Read(char *buffer, size_t size, size_t start)
+{
+    auto lf_Read = [&](char *buffer, size_t size) {
+
+        ProfilerStart("read");
+        const auto readSize = read(m_FileDescriptor, buffer, size);
+        ProfilerStop("read");
+
+        if (readSize == -1)
+        {
+            throw std::ios_base::failure("ERROR: couldn't read from file " +
+                                         m_Name +
+                                         ", in call to POSIX IO read\n");
+        }
+
+        if (static_cast<size_t>(readSize) != size)
+        {
+            throw std::ios_base::failure(
+                "ERROR: read size + " + std::to_string(readSize) +
+                " is not equal to intended size " + std::to_string(size) +
+                " in file " + m_Name + ", in call to POSIX IO read\n");
+        }
+    };
+
+    if (start != MaxSizeT)
+    {
+        const auto newPosition = lseek(m_FileDescriptor, start, SEEK_SET);
+
+        if (static_cast<size_t>(newPosition) != start)
+        {
+            throw std::ios_base::failure(
+                "ERROR: couldn't move to start position " +
+                std::to_string(start) + " in file " + m_Name +
+                ", in call to POSIX lseek\n");
+        }
+    }
+
+    if (size > DefaultMaxFileBatchSize)
+    {
+        const size_t batches = size / DefaultMaxFileBatchSize;
+        const size_t remainder = size % DefaultMaxFileBatchSize;
+
+        size_t position = 0;
+        for (size_t b = 0; b < batches; ++b)
+        {
+            lf_Read(&buffer[position], DefaultMaxFileBatchSize);
+            position += DefaultMaxFileBatchSize;
+        }
+        lf_Read(&buffer[position], remainder);
+    }
+    else
+    {
+        lf_Read(buffer, size);
+    }
+}
+
+void FilePOSIX::Flush() {}
+
+void FilePOSIX::Close()
+{
+    ProfilerStart("close");
+    const int status = close(m_FileDescriptor);
+    ProfilerStop("close");
+
+    if (status == -1)
+    {
+        throw std::ios_base::failure("ERROR: couldn't close file " + m_Name +
+                                     ", in call to POSIX IO close\n");
+    }
+
+    m_IsOpen = false;
+}
+
+void FilePOSIX::CheckFile(const std::string hint) const
+{
+    if (m_FileDescriptor == -1)
+    {
+        throw std::ios_base::failure("ERROR: " + hint + "\n");
+    }
+}
+
+} // end namespace transport
+} // end namespace adios2
diff --git a/source/adios2/toolkit/transport/file/FileDescriptor.h b/source/adios2/toolkit/transport/file/FilePOSIX.h
similarity index 58%
rename from source/adios2/toolkit/transport/file/FileDescriptor.h
rename to source/adios2/toolkit/transport/file/FilePOSIX.h
index fe010c6e3516e553da9f5fbb8f8793666191d176..ffc212067d117123893612049bdbfd2b148af4cc 100644
--- a/source/adios2/toolkit/transport/file/FileDescriptor.h
+++ b/source/adios2/toolkit/transport/file/FilePOSIX.h
@@ -19,18 +19,20 @@ namespace adios2
 namespace transport
 {
 
-/** File descriptor transport using the POSIX library */
-class FileDescriptor : public Transport
+/** File descriptor transport using the POSIX IO library */
+class FilePOSIX : public Transport
 {
 
 public:
-    FileDescriptor(MPI_Comm mpiComm, const bool debugMode);
+    FilePOSIX(MPI_Comm mpiComm, const bool debugMode);
 
-    ~FileDescriptor();
+    ~FilePOSIX();
 
-    void Open(const std::string &name, const OpenMode openMode) final;
+    void Open(const std::string &name, const Mode openMode) final;
 
-    void Write(const char *buffer, size_t size) final;
+    void Write(const char *buffer, size_t size, size_t start = MaxSizeT) final;
+
+    void Read(char *buffer, size_t size, size_t start = MaxSizeT) final;
 
     /** Does nothing, each write is supposed to flush */
     void Flush() final;
@@ -40,8 +42,15 @@ public:
 private:
     /** POSIX file handle returned by Open */
     int m_FileDescriptor = -1;
+
+    /**
+     * Check if m_FileDescriptor is -1 after an operation
+     * @param hint exception message
+     */
+    void CheckFile(const std::string hint) const;
 };
 
 } // end namespace transport
-} // end namespace
+} // end namespace adios2
+
 #endif /* ADIOS2_TRANSPORT_FILE_FILEDESCRIPTOR_H_ */
diff --git a/source/adios2/toolkit/transport/file/FilePointer.cpp b/source/adios2/toolkit/transport/file/FilePointer.cpp
deleted file mode 100644
index e11c4f9fb9dc17a6118f4cec5d8fc6f933061eb8..0000000000000000000000000000000000000000
--- a/source/adios2/toolkit/transport/file/FilePointer.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * FilePointer.cpp
- *
- *  Created on: Jan 6, 2017
- *      Author: William F Godoy godoywf@ornl.gov
- */
-
-#include "FilePointer.h"
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <ios> //std::ios_base::failure
-/// \endcond
-
-// removes fopen warning on Windows
-#ifdef _WIN32
-#pragma warning(disable : 4996) // fopen
-#endif
-
-namespace adios2
-{
-namespace transport
-{
-
-FilePointer::FilePointer(MPI_Comm mpiComm, const bool debugMode)
-: Transport("File", "stdio", mpiComm, debugMode)
-{
-}
-
-FilePointer::~FilePointer()
-{
-    if (m_IsOpen)
-    {
-        std::fclose(m_File);
-    }
-}
-
-void FilePointer::Open(const std::string &name, const OpenMode openMode)
-{
-    if (m_DebugMode)
-    {
-        if (name.empty())
-        {
-            throw std::invalid_argument(
-                "ERROR: file name is empty, in call to FilePointer Open\n");
-        }
-    }
-
-    m_Name = name;
-    m_OpenMode = openMode;
-
-    if (m_OpenMode == OpenMode::Write)
-    {
-        m_File = std::fopen(name.c_str(), "wb");
-    }
-    else if (m_OpenMode == OpenMode::Append)
-    {
-        // need to change when implemented
-        m_File = std::fopen(name.c_str(), "ab");
-    }
-    else if (m_OpenMode == OpenMode::Read)
-    {
-        m_File = std::fopen(name.c_str(), "rb");
-    }
-
-    if (ferror(m_File))
-    {
-        throw std::ios_base::failure("ERROR: couldn't open file " + name +
-                                     ", "
-                                     "in call to FilePointer Open\n");
-    }
-
-    m_IsOpen = true;
-}
-
-void FilePointer::SetBuffer(char *buffer, size_t size)
-{
-    const int status = std::setvbuf(m_File, buffer, _IOFBF, size);
-
-    if (!status)
-    {
-        throw std::ios_base::failure(
-            "ERROR: could not set FILE* buffer in file " + m_Name +
-            ", in call to FilePointer SetBuffer\n");
-    }
-}
-
-void FilePointer::Write(const char *buffer, size_t size)
-{
-    auto lf_Write = [&](const char *buffer, size_t size) {
-
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("write").Resume();
-        }
-        auto writtenSize = std::fwrite(buffer, sizeof(char), size, m_File);
-
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("write").Pause();
-        }
-
-        if (std::ferror(m_File))
-        {
-            throw std::ios_base::failure("ERROR: couldn't write to file " +
-                                         m_Name + ", in call to FILE* Write\n");
-        }
-
-        if (writtenSize != size)
-        {
-            throw std::ios_base::failure(
-                "ERROR: written size + " + std::to_string(writtenSize) +
-                " is not equal to intended size " + std::to_string(size) +
-                " in file " + m_Name + ", in call to FilePointer Write\n");
-        }
-    };
-
-    if (size > DefaultMaxFileBatchSize)
-    {
-        const size_t batches = size / DefaultMaxFileBatchSize;
-        const size_t remainder = size % DefaultMaxFileBatchSize;
-
-        size_t position = 0;
-        for (size_t b = 0; b < batches; ++b)
-        {
-            lf_Write(&buffer[position], DefaultMaxFileBatchSize);
-            position += DefaultMaxFileBatchSize;
-        }
-        lf_Write(&buffer[position], remainder);
-    }
-    else
-    {
-        lf_Write(buffer, size);
-    }
-}
-
-void FilePointer::Flush()
-{
-    const int status = std::fflush(m_File);
-
-    if (status == EOF)
-    {
-        throw std::ios_base::failure("ERROR: couldn't flush file " + m_Name +
-                                     ", in call to FilePointer Flush\n");
-    }
-}
-
-void FilePointer::Close()
-{
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("close").Resume();
-    }
-
-    const int status = std::fclose(m_File);
-
-    if (m_Profiler.IsActive)
-    {
-        m_Profiler.Timers.at("close").Pause();
-    }
-
-    if (status == EOF)
-    {
-        throw std::ios_base::failure("ERROR: couldn't close file " + m_Name +
-                                     ", in call to FilePointer Write\n");
-    }
-
-    m_IsOpen = false;
-}
-
-} // end namespace transport
-} // end namespace adios
diff --git a/source/adios2/toolkit/transport/file/FileStdio.cpp b/source/adios2/toolkit/transport/file/FileStdio.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0e283735e66337538afe5476ff0e11ceac91a832
--- /dev/null
+++ b/source/adios2/toolkit/transport/file/FileStdio.cpp
@@ -0,0 +1,206 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * FileStdio.cpp
+ *
+ *  Created on: Jan 6, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include "FileStdio.h"
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <ios> //std::ios_base::failure
+/// \endcond
+
+// removes fopen warning on Windows
+#ifdef _WIN32
+#pragma warning(disable : 4996) // fopen
+#endif
+
+namespace adios2
+{
+namespace transport
+{
+
+FileStdio::FileStdio(MPI_Comm mpiComm, const bool debugMode)
+: Transport("File", "stdio", mpiComm, debugMode)
+{
+}
+
+FileStdio::~FileStdio()
+{
+    if (m_IsOpen)
+    {
+        std::fclose(m_File);
+    }
+}
+
+void FileStdio::Open(const std::string &name, const Mode openMode)
+{
+    m_Name = name;
+    CheckName();
+    m_OpenMode = openMode;
+
+    switch (m_OpenMode)
+    {
+    case (Mode::Write):
+        m_File = std::fopen(name.c_str(), "wb");
+        break;
+    case (Mode::Append):
+        m_File = std::fopen(name.c_str(), "rwb");
+        break;
+    case (Mode::Read):
+        m_File = std::fopen(name.c_str(), "rb");
+        break;
+    default:
+        CheckFile("unknown open mode for file " + m_Name +
+                  ", in call to stdio fopen");
+    }
+
+    CheckFile("couldn't open file " + m_Name +
+              ", check permissions or path existence, in call to stdio open");
+    m_IsOpen = true;
+}
+
+void FileStdio::SetBuffer(char *buffer, size_t size)
+{
+    const int status = std::setvbuf(m_File, buffer, _IOFBF, size);
+
+    if (!status)
+    {
+        throw std::ios_base::failure(
+            "ERROR: could not set FILE* buffer in file " + m_Name +
+            ", in call to stdio setvbuf\n");
+    }
+}
+
+void FileStdio::Write(const char *buffer, size_t size, size_t start)
+{
+    auto lf_Write = [&](const char *buffer, size_t size) {
+
+        ProfilerStart("write");
+        auto writtenSize = std::fwrite(buffer, sizeof(char), size, m_File);
+        ProfilerStop("write");
+
+        CheckFile("couldn't write to file " + m_Name +
+                  ", in call to stdio fwrite");
+
+        if (writtenSize != size)
+        {
+            throw std::ios_base::failure(
+                "ERROR: written size + " + std::to_string(writtenSize) +
+                " is not equal to intended size " + std::to_string(size) +
+                " in file " + m_Name + ", in call to stdio fwrite\n");
+        }
+    };
+
+    if (start != MaxSizeT)
+    {
+        std::fseek(m_File, static_cast<long int>(start), SEEK_SET);
+        CheckFile("couldn't move to start position " + std::to_string(start) +
+                  " in file " + m_Name + ", in call to stdio fseek at write ");
+    }
+
+    if (size > DefaultMaxFileBatchSize)
+    {
+        const size_t batches = size / DefaultMaxFileBatchSize;
+        const size_t remainder = size % DefaultMaxFileBatchSize;
+
+        size_t position = 0;
+        for (size_t b = 0; b < batches; ++b)
+        {
+            lf_Write(&buffer[position], DefaultMaxFileBatchSize);
+            position += DefaultMaxFileBatchSize;
+        }
+        lf_Write(&buffer[position], remainder);
+    }
+    else
+    {
+        lf_Write(buffer, size);
+    }
+}
+
+void FileStdio::Read(char *buffer, size_t size, size_t start)
+{
+    auto lf_Read = [&](char *buffer, size_t size) {
+
+        ProfilerStart("read");
+        auto readSize = std::fread(buffer, sizeof(char), size, m_File);
+        ProfilerStop("read");
+
+        CheckFile("couldn't read to file " + m_Name +
+                  ", in call to stdio fread");
+
+        if (readSize != size)
+        {
+            throw std::ios_base::failure(
+                "ERROR: read size + " + std::to_string(readSize) +
+                " is not equal to intended size " + std::to_string(size) +
+                " in file " + m_Name + ", in call to stdio fread\n");
+        }
+    };
+
+    if (start != MaxSizeT)
+    {
+        std::fseek(m_File, static_cast<long int>(start), SEEK_SET);
+        CheckFile("couldn't move to start position " + std::to_string(start) +
+                  " in file " + m_Name + ", in call to stdio fseek for read");
+    }
+
+    if (size > DefaultMaxFileBatchSize)
+    {
+        const size_t batches = size / DefaultMaxFileBatchSize;
+        const size_t remainder = size % DefaultMaxFileBatchSize;
+
+        size_t position = 0;
+        for (size_t b = 0; b < batches; ++b)
+        {
+            lf_Read(&buffer[position], DefaultMaxFileBatchSize);
+            position += DefaultMaxFileBatchSize;
+        }
+        lf_Read(&buffer[position], remainder);
+    }
+    else
+    {
+        lf_Read(buffer, size);
+    }
+}
+
+void FileStdio::Flush()
+{
+    const int status = std::fflush(m_File);
+
+    if (status == EOF)
+    {
+        throw std::ios_base::failure("ERROR: couldn't flush file " + m_Name +
+                                     ", in call to stdio fflush\n");
+    }
+}
+
+void FileStdio::Close()
+{
+    ProfilerStart("close");
+    const int status = std::fclose(m_File);
+    ProfilerStop("close");
+
+    if (status == EOF)
+    {
+        throw std::ios_base::failure("ERROR: couldn't close file " + m_Name +
+                                     ", in call to stdio fclose\n");
+    }
+
+    m_IsOpen = false;
+}
+
+void FileStdio::CheckFile(const std::string hint) const
+{
+    if (std::ferror(m_File))
+    {
+        throw std::ios_base::failure("ERROR: " + hint + "\n");
+    }
+}
+
+} // end namespace transport
+} // end namespace adios2
diff --git a/source/adios2/toolkit/transport/file/FilePointer.h b/source/adios2/toolkit/transport/file/FileStdio.h
similarity index 51%
rename from source/adios2/toolkit/transport/file/FilePointer.h
rename to source/adios2/toolkit/transport/file/FileStdio.h
index 6d1521a3d5d99fff26f00806871194f9461fa5a8..75dac7a6766e833fd26dcbec5ab5d836673ae90d 100644
--- a/source/adios2/toolkit/transport/file/FilePointer.h
+++ b/source/adios2/toolkit/transport/file/FileStdio.h
@@ -2,7 +2,7 @@
  * Distributed under the OSI-approved Apache License, Version 2.0.  See
  * accompanying file Copyright.txt for details.
  *
- * FilePointer.h wrapper of C/C++ stdio.h for file I/O
+ * FileStdio.h wrapper of C/C++ stdio.h for file I/O
  *
  *  Created on: Jan 6, 2017
  *      Author: William F Godoy godoywf@ornl.gov
@@ -20,24 +20,22 @@ namespace adios2
 namespace transport
 {
 
-/**
- * Class that defines a transport method using C file pointer (FP) to
- * streams
- * FILE*
- */
-class FilePointer : public Transport
+/** File transport using C stdio FILE* */
+class FileStdio : public Transport
 {
 
 public:
-    FilePointer(MPI_Comm mpiComm, const bool debugMode);
+    FileStdio(MPI_Comm mpiComm, const bool debugMode);
 
-    ~FilePointer();
+    ~FileStdio();
 
-    void Open(const std::string &name, const OpenMode openMode) final;
+    void Open(const std::string &name, const Mode openMode) final;
 
     void SetBuffer(char *buffer, size_t size) final;
 
-    void Write(const char *buffer, size_t size) final;
+    void Write(const char *buffer, size_t size, size_t start = MaxSizeT) final;
+
+    void Read(char *buffer, size_t size, size_t start = MaxSizeT) final;
 
     void Flush() final;
 
@@ -45,10 +43,16 @@ public:
 
 private:
     /** C File pointer */
-    FILE *m_File = nullptr; // NULL or nullptr?
+    FILE *m_File = nullptr;
+
+    /**
+     * Check for std::ferror and throw an exception if true
+     * @param hint exception message
+     */
+    void CheckFile(const std::string hint) const;
 };
 
 } // end namespace transport
-} // end namespace
+} // end namespace adios2
 
 #endif /* ADIOS2_TOOLKIT_TRANSPORT_FILE_FILEPOINTER_H_ */
diff --git a/source/adios2/toolkit/transport/file/FileStream.cpp b/source/adios2/toolkit/transport/file/FileStream.cpp
deleted file mode 100644
index 3609394539420b2a3c3333bc31506f45b05b76a7..0000000000000000000000000000000000000000
--- a/source/adios2/toolkit/transport/file/FileStream.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Distributed under the OSI-approved Apache License, Version 2.0.  See
- * accompanying file Copyright.txt for details.
- *
- * FileStream.cpp
- *
- *  Created on: Oct 24, 2016
- *      Author: William F Godoy godoywf@ornl.gov
- */
-
-#include "FileStream.h"
-
-/// \cond EXCLUDE_FROM_DOXYGEN
-#include <ios> // std::ios_base::failure
-/// \endcond
-
-namespace adios2
-{
-namespace transport
-{
-
-FileStream::FileStream(MPI_Comm mpiComm, const bool debugMode)
-: Transport("File", "fstream", mpiComm, debugMode)
-{
-}
-
-void FileStream::Open(const std::string &name, const OpenMode openMode)
-{
-    if (m_DebugMode)
-    {
-        if (name.empty())
-        {
-            throw std::invalid_argument(
-                "ERROR: file name is empty, in call to FilePointer Open\n");
-        }
-    }
-
-    m_Name = name;
-    m_OpenMode = openMode;
-
-    if (m_OpenMode == OpenMode::Write)
-    {
-        m_FileStream.open(name, std::fstream::out | std::fstream::binary);
-    }
-    else if (m_OpenMode == OpenMode::Append)
-    {
-        // to be changed to rw?
-        m_FileStream.open(name, std::fstream::out | std::fstream::app |
-                                    std::fstream::binary);
-    }
-    else if (m_OpenMode == OpenMode::Read)
-    {
-        m_FileStream.open(name, std::fstream::in | std::fstream::binary);
-    }
-
-    if (!m_FileStream)
-    {
-        throw std::ios_base::failure("ERROR: couldn't open file " + m_Name +
-                                     ", in call to FileStream Open\n");
-    }
-
-    m_IsOpen = true;
-}
-
-void FileStream::SetBuffer(char *buffer, size_t size)
-{
-    m_FileStream.rdbuf()->pubsetbuf(buffer, size);
-
-    if (!m_FileStream)
-    {
-        throw std::ios_base::failure("ERROR: couldn't set buffer in file " +
-                                     m_Name +
-                                     ", in call to FileStream SetBuffer\n");
-    }
-}
-
-void FileStream::Write(const char *buffer, size_t size)
-{
-    auto lf_Write = [&](const char *buffer, size_t size) {
-
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("write").Resume();
-        }
-        m_FileStream.write(buffer, static_cast<std::streamsize>(size));
-
-        if (m_Profiler.IsActive)
-        {
-            m_Profiler.Timers.at("write").Pause();
-        }
-
-        if (!m_FileStream)
-        {
-            throw std::ios_base::failure("ERROR: couldn't write to file " +
-                                         m_Name + ", in call to FILE* Write\n");
-        }
-    };
-
-    if (size > DefaultMaxFileBatchSize)
-    {
-        const size_t batches = size / DefaultMaxFileBatchSize;
-        const size_t remainder = size % DefaultMaxFileBatchSize;
-
-        size_t position = 0;
-        for (size_t b = 0; b < batches; ++b)
-        {
-            lf_Write(&buffer[position], DefaultMaxFileBatchSize);
-            position += DefaultMaxFileBatchSize;
-        }
-        lf_Write(&buffer[position], remainder);
-    }
-    else
-    {
-        lf_Write(buffer, size);
-    }
-}
-
-void FileStream::Flush()
-{
-    m_FileStream.flush();
-    if (!m_FileStream)
-    {
-        throw std::ios_base::failure("ERROR: couldn't flush to file " + m_Name +
-                                     ", in call to FileStream Flush\n");
-    }
-}
-
-void FileStream::Close()
-{
-    m_FileStream.close();
-    if (!m_FileStream)
-    {
-        throw std::ios_base::failure("ERROR: couldn't close file " + m_Name +
-                                     ", in call to FileStream Close\n");
-    }
-
-    m_IsOpen = false;
-}
-
-} // end namespace transport
-} // end namespace adios
diff --git a/source/adios2/toolkit/transport/shm/ShmSystemV.cpp b/source/adios2/toolkit/transport/shm/ShmSystemV.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..77043f75c197659b62a7c08f29f5d74836d129ed
--- /dev/null
+++ b/source/adios2/toolkit/transport/shm/ShmSystemV.cpp
@@ -0,0 +1,174 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * ShmSystemV.cpp
+ *
+ *  Created on: Sep 26, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#include "ShmSystemV.h"
+
+#include <cstring> //std::memcpy
+
+#include <sys/ipc.h>   //ftok
+#include <sys/shm.h>   //shmget, shmmat
+#include <sys/types.h> //key_t
+
+namespace adios2
+{
+namespace transport
+{
+
+ShmSystemV::ShmSystemV(const unsigned int projectID, const size_t size,
+                       MPI_Comm mpiComm, const bool debugMode,
+                       const bool removeAtClose)
+: Transport("Shm", "SystemV", mpiComm, debugMode), m_ProjectID(projectID),
+  m_Size(size), m_RemoveAtClose(removeAtClose)
+{
+    if (m_DebugMode && projectID == 0)
+    {
+        throw std::invalid_argument(
+            "ERROR: projectID can't be zero, in shared memory segment\n");
+    }
+}
+
+ShmSystemV::~ShmSystemV() // this might not be correct
+{
+    if (m_IsOpen)
+    {
+        shmdt(m_Buffer);
+
+        if (m_RemoveAtClose)
+        {
+            shmctl(m_ShmID, IPC_RMID, NULL);
+        }
+    }
+}
+
+void ShmSystemV::Open(const std::string &name, const Mode openMode)
+{
+    m_Name = name;
+    CheckName();
+    m_OpenMode = openMode;
+
+    // not using const
+    key_t key = ftok(m_Name.c_str(), static_cast<int>(m_ProjectID));
+
+    switch (m_OpenMode)
+    {
+    case (Mode::Write):
+        ProfilerStart("open");
+        m_ShmID = shmget(key, m_Size, IPC_CREAT | 0666);
+        ProfilerStop("open");
+        break;
+
+    case (Mode::Append):
+        ProfilerStart("open");
+        m_ShmID = shmget(key, m_Size, 0);
+        ProfilerStop("open");
+        break;
+
+    case (Mode::Read):
+        ProfilerStart("open");
+        m_ShmID = shmget(key, m_Size, 0);
+        ProfilerStop("open");
+        break;
+
+    default:
+        throw std::invalid_argument(
+            "ERROR: unknown open mode for shared memory segment " + m_Name +
+            ", in call to SystemV Open");
+    }
+
+    CheckShmID("in call to ShmSystemV shmget at Open");
+
+    m_Buffer = static_cast<char *>(shmat(m_ShmID, nullptr, 0));
+    CheckBuffer("in call to SystemV shmat at Open");
+    m_IsOpen = false;
+}
+
+void ShmSystemV::Write(const char *buffer, size_t size, size_t start)
+{
+    CheckSizes(size, start, "in call to Write");
+    ProfilerStart("write");
+    std::memcpy(&m_Buffer[start], buffer, size);
+    ProfilerStop("write");
+}
+
+void ShmSystemV::Read(char *buffer, size_t size, size_t start)
+{
+    CheckSizes(size, start, "in call to Read");
+    ProfilerStart("read");
+    std::memcpy(buffer, &m_Buffer[start], size);
+    ProfilerStop("read");
+}
+
+void ShmSystemV::Close()
+{
+    ProfilerStart("close");
+    int result = shmdt(m_Buffer);
+    ProfilerStop("close");
+    if (result < 1)
+    {
+        throw std::ios_base::failure(
+            "ERROR: failed to detach shared memory segment of size " +
+            std::to_string(m_Size) + " and name " + m_Name +
+            ", in call to SystemV shmdt Close\n");
+    }
+
+    if (m_RemoveAtClose)
+    {
+        ProfilerStart("close");
+        int remove = shmctl(m_ShmID, IPC_RMID, NULL);
+        ProfilerStop("close");
+        if (result < 1)
+        {
+            throw std::ios_base::failure(
+                "ERROR: failed to remove shared memory segment of size " +
+                std::to_string(m_Size) + " and name " + m_Name +
+                ", in call to SystemV shmctl Close\n");
+        }
+    }
+
+    m_IsOpen = false;
+}
+
+// PRIVATE
+void ShmSystemV::CheckShmID(const std::string hint) const
+{
+    if (m_ShmID < 0)
+    {
+        throw std::ios_base::failure(
+            "ERROR: Failed shared memory segment of size " +
+            std::to_string(m_Size) + " and name " + m_Name + ", " + hint +
+            "\n");
+    }
+}
+
+void ShmSystemV::CheckBuffer(const std::string hint) const
+{
+    if (m_Buffer == nullptr)
+    {
+        throw std::ios_base::failure(
+            "ERROR: nullptr shared memory segment of size " +
+            std::to_string(m_Size) + " and name " + m_Name + " " + hint + "\n");
+    }
+}
+
+void ShmSystemV::CheckSizes(const size_t start, const size_t size,
+                            const std::string hint) const
+{
+    if (m_DebugMode && start + size > m_Size)
+    {
+        throw std::invalid_argument(
+            "ERROR: final position (start + size) = (" + std::to_string(start) +
+            " + " + std::to_string(size) +
+            " ) exceeding shared memory pre-allocated size:" +
+            std::to_string(m_Size) + "," + hint + "\n");
+    }
+}
+
+} // end namespace transport
+} // end namespace adios2
diff --git a/source/adios2/toolkit/transport/shm/ShmSystemV.h b/source/adios2/toolkit/transport/shm/ShmSystemV.h
new file mode 100644
index 0000000000000000000000000000000000000000..b16751d39b426d99c25753e7c54cb82b65105496
--- /dev/null
+++ b/source/adios2/toolkit/transport/shm/ShmSystemV.h
@@ -0,0 +1,79 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ *
+ * ShmSystemV.h
+ *
+ *  Created on: Sep 26, 2017
+ *      Author: William F Godoy godoywf@ornl.gov
+ */
+
+#ifndef ADIOS2_TOOLKIT_TRANSPORT_SHMEM_SHMEMSYSTEMV_H_
+#define ADIOS2_TOOLKIT_TRANSPORT_SHMEM_SHMEMSYSTEMV_H_
+
+#include "adios2/toolkit/transport/Transport.h"
+
+namespace adios2
+{
+namespace transport
+{
+
+class ShmSystemV : public Transport
+{
+
+public:
+    /**
+     * Unique constructor
+     * @param pathName ftok input to create unique shared-memory key
+     * @param projectID  ftok input to create unique shared-memory key. Must be
+     * greater than zero.
+     * @param size shared-memory pre-allocated data size
+     * @param debugMode true: extra checks
+     */
+    ShmSystemV(const unsigned int projectID, const size_t size,
+               MPI_Comm mpiComm, const bool debugMode = false,
+               const bool removeAtClose = false);
+
+    ~ShmSystemV();
+
+    void Open(const std::string &name, const Mode openMode) final;
+
+    void Write(const char *buffer, size_t size, size_t start = MaxSizeT) final;
+
+    void Read(char *buffer, size_t size, size_t start = MaxSizeT) final;
+
+    void Close() final;
+
+private:
+    /** 1st argument of ftok to create shared memory segment key, from Open */
+    std::string m_PathName;
+
+    /** 2nd argument of ftok to create shared memory segment key, must be
+     * greater than zero, from constructor */
+    const unsigned int m_ProjectID;
+
+    /** shared memory segment ID from shmget */
+    int m_ShmID = -1;
+
+    /** reference to a shared memory data buffer */
+    char *m_Buffer = nullptr;
+
+    /** size of the pre-allocated shared memory segment, non-const due to
+     * SystemV API */
+    size_t m_Size;
+
+    /** remove shared-memory segment at close (will be manually cleaned later)*/
+    const bool m_RemoveAtClose = false;
+
+    void CheckShmID(const std::string hint) const;
+
+    void CheckBuffer(const std::string hint) const;
+
+    void CheckSizes(const size_t start, const size_t size,
+                    const std::string hint) const;
+};
+
+} // end namespace transport
+} // end namespace adios2
+
+#endif /* ADIOS2_TOOLKIT_TRANSPORT_SHMEM_SHMEMSYSTEMV_H_ */
diff --git a/source/adios2/toolkit/transport/wan/WANZmq.cpp b/source/adios2/toolkit/transport/wan/WANZmq.cpp
index 6627a6372c42ddebaab36572825787cabbfa29e2..c3292b8c6870662447e78baf2f685fe625f5d2a5 100644
--- a/source/adios2/toolkit/transport/wan/WANZmq.cpp
+++ b/source/adios2/toolkit/transport/wan/WANZmq.cpp
@@ -37,12 +37,12 @@ WANZmq::~WANZmq()
     }
 }
 
-void WANZmq::Open(const std::string &name, const OpenMode openMode)
+void WANZmq::Open(const std::string &name, const Mode openMode)
 {
     m_Name = name;
     m_OpenMode = openMode;
 
-    if (m_OpenMode == OpenMode::Write)
+    if (m_OpenMode == Mode::Write)
     {
         if (m_Profiler.IsActive)
         {
@@ -58,7 +58,7 @@ void WANZmq::Open(const std::string &name, const OpenMode openMode)
             m_Profiler.Timers.at("open").Pause();
         }
     }
-    else if (m_OpenMode == OpenMode::Append)
+    else if (m_OpenMode == Mode::Append)
     {
         if (m_DebugMode)
         {
@@ -69,7 +69,7 @@ void WANZmq::Open(const std::string &name, const OpenMode openMode)
                 "OpenMode:r (read/receiver), in call to Open\n");
         }
     }
-    else if (m_OpenMode == OpenMode::Read)
+    else if (m_OpenMode == Mode::Read)
     {
         if (m_Profiler.IsActive)
         {
diff --git a/source/adios2/toolkit/transport/wan/WANZmq.h b/source/adios2/toolkit/transport/wan/WANZmq.h
index 7249f963cc31d0fd464c4c9d92c594c2ee600408..e303e4cc3fcc570d12a025dc1623234c1415fecc 100644
--- a/source/adios2/toolkit/transport/wan/WANZmq.h
+++ b/source/adios2/toolkit/transport/wan/WANZmq.h
@@ -34,7 +34,7 @@ public:
 
     ~WANZmq();
 
-    void Open(const std::string &name, const OpenMode openMode) final;
+    void Open(const std::string &name, const Mode openMode) final;
 
     void SetBuffer(char *buffer, size_t size) final;
 
diff --git a/source/adios2/toolkit/transportman/TransportMan.cpp b/source/adios2/toolkit/transportman/TransportMan.cpp
index efbd4f21dab25948c18477b01b30eeb776312370..b368e3259976310445bc8f1dc90624b7f75a703b 100644
--- a/source/adios2/toolkit/transportman/TransportMan.cpp
+++ b/source/adios2/toolkit/transportman/TransportMan.cpp
@@ -15,13 +15,15 @@
 /// \endcond
 
 #include "adios2/helper/adiosFunctions.h" //CreateDirectory
-#include "adios2/toolkit/transport/file/FilePointer.h"
-#include "adios2/toolkit/transport/file/FileStream.h"
 
+/// transports
 #ifndef _WIN32
-#include "adios2/toolkit/transport/file/FileDescriptor.h"
+#include "adios2/toolkit/transport/file/FilePOSIX.h"
 #endif
 
+#include "adios2/toolkit/transport/file/FileFStream.h"
+#include "adios2/toolkit/transport/file/FileStdio.h"
+
 namespace adios2
 {
 namespace transportman
@@ -34,7 +36,7 @@ TransportMan::TransportMan(MPI_Comm mpiComm, const bool debugMode)
 
 void TransportMan::OpenFiles(const std::vector<std::string> &baseNames,
                              const std::vector<std::string> &names,
-                             const OpenMode openMode,
+                             const Mode openMode,
                              const std::vector<Params> &parametersVector,
                              const bool profile)
 {
@@ -47,7 +49,10 @@ void TransportMan::OpenFiles(const std::vector<std::string> &baseNames,
 
         if (type == "File" || type == "file") // need to create directory
         {
-            CreateDirectory(baseNames[i]);
+            if (openMode == Mode::Write || openMode == Mode::Append)
+            {
+                CreateDirectory(baseNames[i]);
+            }
             OpenFileTransport(names[i], openMode, parameters, profile);
         }
     }
@@ -201,7 +206,7 @@ bool TransportMan::AllTransportsClosed() const noexcept
 
 // PRIVATE
 void TransportMan::OpenFileTransport(const std::string &fileName,
-                                     const OpenMode openMode,
+                                     const Mode openMode,
                                      const Params &parameters,
                                      const bool profile)
 {
@@ -209,19 +214,19 @@ void TransportMan::OpenFileTransport(const std::string &fileName,
                                    std::shared_ptr<Transport> &transport) {
         if (library == "stdio")
         {
-            transport = std::make_shared<transport::FilePointer>(m_MPIComm,
-                                                                 m_DebugMode);
+            transport =
+                std::make_shared<transport::FileStdio>(m_MPIComm, m_DebugMode);
         }
         else if (library == "fstream")
         {
-            transport =
-                std::make_shared<transport::FileStream>(m_MPIComm, m_DebugMode);
+            transport = std::make_shared<transport::FileFStream>(m_MPIComm,
+                                                                 m_DebugMode);
         }
 #ifndef _WIN32
         else if (library == "POSIX")
         {
-            transport = std::make_shared<transport::FileDescriptor>(
-                m_MPIComm, m_DebugMode);
+            transport =
+                std::make_shared<transport::FilePOSIX>(m_MPIComm, m_DebugMode);
         }
 #endif
         else
diff --git a/source/adios2/toolkit/transportman/TransportMan.h b/source/adios2/toolkit/transportman/TransportMan.h
index 07efcdbfc9daec7b44d701d25a47e9a36531244e..99252a3e084313dcebccd644425baafc9aee7640 100644
--- a/source/adios2/toolkit/transportman/TransportMan.h
+++ b/source/adios2/toolkit/transportman/TransportMan.h
@@ -57,7 +57,7 @@ public:
      */
     void OpenFiles(const std::vector<std::string> &baseNames,
                    const std::vector<std::string> &names,
-                   const OpenMode openMode,
+                   const Mode openMode,
                    const std::vector<Params> &parametersVector,
                    const bool profile);
 
@@ -103,6 +103,16 @@ public:
     void WriteFiles(const char *buffer, const size_t size,
                     const int transportIndex = -1);
 
+    /**
+     * Read contents from a single file and assign it to buffer
+     * @param buffer
+     * @param size
+     * @param start
+     * @param transportIndex
+     */
+    void ReadFile(char *buffer, const size_t size, const size_t start,
+                  const int transportIndex);
+
     /**
      * Close file or files depending on transport index. Throws an exception
      * if transport is not a file when transportIndex > -1.
@@ -117,7 +127,7 @@ protected:
     MPI_Comm m_MPIComm;
     const bool m_DebugMode = false;
 
-    void OpenFileTransport(const std::string &fileName, const OpenMode openMode,
+    void OpenFileTransport(const std::string &fileName, const Mode openMode,
                            const Params &parameters, const bool profile);
 };
 
diff --git a/source/adios2/toolkit/transportman/dataman/DataMan.cpp b/source/adios2/toolkit/transportman/dataman/DataMan.cpp
index c30344df544dda4bd5010467047e8634accb8223..6bb2e19a74dfd51fdcfa1c99873898adbba6bc7b 100644
--- a/source/adios2/toolkit/transportman/dataman/DataMan.cpp
+++ b/source/adios2/toolkit/transportman/dataman/DataMan.cpp
@@ -21,7 +21,7 @@ DataMan::DataMan(MPI_Comm mpiComm, const bool debugMode)
 }
 
 void DataMan::OpenWANTransports(const std::string &name,
-                                const OpenMode openMode,
+                                const Mode openMode,
                                 const std::vector<Params> &parametersVector,
                                 const bool profile)
 {
diff --git a/source/adios2/toolkit/transportman/dataman/DataMan.h b/source/adios2/toolkit/transportman/dataman/DataMan.h
index c0e009f67fe84268f8b56519bebdd6878654543e..3609b3e568e1ba96af25362ce5fc4fab40c67387 100644
--- a/source/adios2/toolkit/transportman/dataman/DataMan.h
+++ b/source/adios2/toolkit/transportman/dataman/DataMan.h
@@ -28,7 +28,7 @@ public:
 
     virtual ~DataMan() = default;
 
-    void OpenWANTransports(const std::string &name, const OpenMode openMode,
+    void OpenWANTransports(const std::string &name, const Mode openMode,
                            const std::vector<Params> &parametersVector,
                            const bool profile);
 
diff --git a/source/adios2/transform/compress/CompressZfp.h b/source/adios2/transform/compress/CompressZfp.h
index 251d14b455a86b8d7dd86b8bf4cc756e912cd312..ec340e93fcfa4b1b1060ee9a79608f4f5476a37f 100644
--- a/source/adios2/transform/compress/CompressZfp.h
+++ b/source/adios2/transform/compress/CompressZfp.h
@@ -17,7 +17,6 @@
 
 namespace adios2
 {
-
 namespace transform
 {
 
diff --git a/testing/adios2/engine/adios1/TestADIOS1WriteRead.cpp b/testing/adios2/engine/adios1/TestADIOS1WriteRead.cpp
index 99fc439bccb5667a190bba1d7553518f34418b71..31e6d3656401d56120d84bfba2b038e8ee07534b 100644
--- a/testing/adios2/engine/adios1/TestADIOS1WriteRead.cpp
+++ b/testing/adios2/engine/adios1/TestADIOS1WriteRead.cpp
@@ -97,7 +97,7 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read1D8)
         io.AddTransport("file");
 #endif
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < NSteps; ++step)
@@ -393,7 +393,7 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read2D2x4)
         io.AddTransport("file");
 #endif
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < NSteps; ++step)
@@ -702,7 +702,7 @@ TEST_F(ADIOS1WriteReadTest, _ADIOS2ADIOS1WriteADIOS1Read2D4x2)
         io.AddTransport("file");
 #endif
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < NSteps; ++step)
diff --git a/testing/adios2/engine/bp/TestBPWriteProfilingJSON.cpp b/testing/adios2/engine/bp/TestBPWriteProfilingJSON.cpp
index c032ab98d40d8b1b24cac35e07ab6e9a9ab55329..c246a927c3a5938507e8cabe2b59fd0ff88a8a1f 100644
--- a/testing/adios2/engine/bp/TestBPWriteProfilingJSON.cpp
+++ b/testing/adios2/engine/bp/TestBPWriteProfilingJSON.cpp
@@ -76,7 +76,7 @@ TEST_F(BPWriteProfilingJSONTest, ADIOS2BPWriteProfilingJSON)
         io.SetParameters({{"Threads", "2"}});
         io.AddTransport("File", {{"Library", "POSIX"}});
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
diff --git a/testing/adios2/engine/bp/TestBPWriteRead.cpp b/testing/adios2/engine/bp/TestBPWriteRead.cpp
index 57eeafa21fcab4ad38a1264e25b3266ffc7c3822..ab90881c3ec0819c81a3590e2f007df6ef7bd0b0 100644
--- a/testing/adios2/engine/bp/TestBPWriteRead.cpp
+++ b/testing/adios2/engine/bp/TestBPWriteRead.cpp
@@ -65,7 +65,7 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8)
         io.SetEngine("BPFileWriter");
         io.AddTransport("File");
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
@@ -281,7 +281,7 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4)
         io.SetEngine("BPFileWriter");
         io.AddTransport("file");
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
@@ -507,7 +507,7 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2)
         io.SetEngine("BPFileWriter");
         io.AddTransport("file");
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
diff --git a/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp b/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp
index 8e8ce0704bdad98bdfdb40c11e966cc1ea292ccf..caa19224a5a8828999a1b7a8d32b643b6ef7f4d7 100644
--- a/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp
+++ b/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp
@@ -58,7 +58,7 @@ TEST_F(BPWriteReadAttributeTest, ADIOS2BPWriteADIOS1ReadSingleTypes)
         io.SetEngine("BPFileWriter");
         io.AddTransport("File");
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         // Close the file
@@ -200,7 +200,7 @@ TEST_F(BPWriteReadAttributeTest, ADIOS2BPWriteADIOS1ReadArrayTypes)
         io.SetEngine("BPFileWriter");
         io.AddTransport("File");
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         // Close the file
diff --git a/testing/adios2/engine/bp/TestBPWriteReadfstream.cpp b/testing/adios2/engine/bp/TestBPWriteReadfstream.cpp
index 33164aae4921b79d6afc68e92e20a9a7fa1c6e74..4fc0cb9a8d9510adfca4009338ecf8571003e1d1 100644
--- a/testing/adios2/engine/bp/TestBPWriteReadfstream.cpp
+++ b/testing/adios2/engine/bp/TestBPWriteReadfstream.cpp
@@ -65,7 +65,7 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8fstream)
         io.SetEngine("BPFileWriter");
         io.AddTransport("File", {{"Library", "fstream"}});
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
@@ -281,7 +281,7 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4fstream)
         io.SetEngine("BPFileWriter");
         io.AddTransport("file", {{"Library", "fstream"}});
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
@@ -507,7 +507,7 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2fstream)
         io.SetEngine("BPFileWriter");
         io.AddTransport("file", {{"Library", "fstream"}});
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
diff --git a/testing/adios2/engine/bp/TestBPWriteReadstdio.cpp b/testing/adios2/engine/bp/TestBPWriteReadstdio.cpp
index b55d6f4290ad7d96580947d5bbe49a5378cf3e61..b50177ea26bd8c1447e6b612ba9bfe284031db8f 100644
--- a/testing/adios2/engine/bp/TestBPWriteReadstdio.cpp
+++ b/testing/adios2/engine/bp/TestBPWriteReadstdio.cpp
@@ -65,7 +65,7 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8stdio)
         io.SetEngine("BPFileWriter");
         io.AddTransport("File", {{"Library", "stdio"}});
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
@@ -281,7 +281,7 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4stdio)
         io.SetEngine("BPFileWriter");
         io.AddTransport("file", {{"Library", "stdio"}});
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
@@ -507,7 +507,7 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2stdio)
         io.SetEngine("BPFileWriter");
         io.AddTransport("file", {{"Library", "stdio"}});
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
diff --git a/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp b/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp
index 3ad94d769a42466683778faefa76289ff29d60a5..094ff5907738e2edbfb9bc7eefd2c7113dd9988b 100644
--- a/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp
+++ b/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp
@@ -220,7 +220,7 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8)
         // Create the HDF5 Engine
         io.SetEngine("HDF5Writer");
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
@@ -427,7 +427,7 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4)
         io.AddTransport("file");
 
         // Create the HDF5 Engine
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
@@ -642,7 +642,7 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2)
         io.SetEngine("HDF5Writer");
         io.AddTransport("file");
 
-        auto engine = io.Open(fname, adios2::OpenMode::Write);
+        auto engine = io.Open(fname, adios2::Mode::Write);
         ASSERT_NE(engine.get(), nullptr);
 
         for (size_t step = 0; step < 3; ++step)
diff --git a/testing/adios2/interface/TestADIOSDefineVariable.cpp b/testing/adios2/interface/TestADIOSDefineVariable.cpp
index 100f05fc4e7df69a6512a749cf7b3cf1eb705260..f3fc08cbfb346cb556a22780025412a2758a2802 100644
--- a/testing/adios2/interface/TestADIOSDefineVariable.cpp
+++ b/testing/adios2/interface/TestADIOSDefineVariable.cpp
@@ -97,8 +97,8 @@ TEST_F(ADIOSDefineVariableTest, DefineGlobalArrayWithSelections)
 
     // Make a 3D selection to describe the local dimensions of the
     // variable we write and its offsets in the global spaces
-    adios2::SelectionBoundingBox sel({50, n / 2, 0}, {10, n / 2, 30});
-    globalarray.SetSelection(sel);
+    globalarray.SetSelection(
+        adios2::Box<adios2::Dims>({50, n / 2, 0}, {10, n / 2, 30}));
 
     // Verify the dimensions, name, and type are correct
     ASSERT_EQ(globalarray.m_Shape.size(), 3);
@@ -128,7 +128,7 @@ TEST_F(ADIOSDefineVariableTest, DefineGlobalArrayConstantDims)
     ::testing::StaticAssertTypeEq<decltype(globalarray),
                                   adios2::Variable<int> &>();
 
-    adios2::SelectionBoundingBox sel({50, n / 2, 0}, {10, n / 2, 30});
+    adios2::Box<adios2::Dims> sel({50, n / 2, 0}, {10, n / 2, 30});
     EXPECT_THROW(globalarray.SetSelection(sel), std::invalid_argument);
 
     // Verify the dimensions, name, and type are correct
@@ -206,10 +206,9 @@ TEST_F(ADIOSDefineVariableTest, DefineLocalArrayWithSelection)
 
     // Make a 3D selection to describe the local dimensions of the
     // variable we write
-    adios2::SelectionBoundingBox sel({}, {10, n / 2, 30});
-    localarray.SetSelection(sel);
+    localarray.SetSelection(adios2::Box<adios2::Dims>({}, {10, n / 2, 30}));
 
-    adios2::SelectionBoundingBox selbad({50, n / 2, 0}, {10, n / 2, 30});
+    adios2::Box<adios2::Dims> selbad({50, n / 2, 0}, {10, n / 2, 30});
     EXPECT_THROW(localarray.SetSelection(selbad), std::invalid_argument);
 
     // Verify the dimensions, name, and type are correct
@@ -235,7 +234,7 @@ TEST_F(ADIOSDefineVariableTest, DefineLocalArrayConstantDims)
     ::testing::StaticAssertTypeEq<decltype(localarray),
                                   adios2::Variable<int> &>();
 
-    adios2::SelectionBoundingBox sel({}, {10, n / 2, 30});
+    adios2::Box<adios2::Dims> sel({}, {10, n / 2, 30});
     EXPECT_THROW(localarray.SetSelection(sel), std::invalid_argument);
 
     // Verify the dimensions, name, and type are correct
diff --git a/testing/adios2/xml/TestXMLConfig.cpp b/testing/adios2/xml/TestXMLConfig.cpp
index 5d3cb161b01080cd33a19083516deba70d3caaaa..e032dd00899ec5656fe3e548db14374a64e46d34 100644
--- a/testing/adios2/xml/TestXMLConfig.cpp
+++ b/testing/adios2/xml/TestXMLConfig.cpp
@@ -41,7 +41,8 @@ TEST_F(XMLConfigTest, TwoIOs)
         EXPECT_EQ(params.at("MaxBufferSize"), "20Mb");
         EXPECT_EQ(params.at("InitialBufferSize"), "1Mb");
         EXPECT_EQ(params.at("BufferGrowthFactor"), "2");
-        auto engine = io.Open("Test BP Writer 1", adios2::OpenMode::Write);
+        adios2::Engine &engine =
+            io.Open("Test BP Writer 1", adios2::Mode::Write);
     });
 
     EXPECT_NO_THROW({