diff --git a/examples/heatTransfer/read/CMakeLists.txt b/examples/heatTransfer/read/CMakeLists.txt
index 7f3e9c4589874abe0d85fc6b7a065ad2fbc7ed4e..8527738fb7c8a25bbd19a2488d6c06ec8bbb5fa9 100644
--- a/examples/heatTransfer/read/CMakeLists.txt
+++ b/examples/heatTransfer/read/CMakeLists.txt
@@ -4,9 +4,18 @@
 #------------------------------------------------------------------------------#
 
 if(ADIOS_USE_MPI)
+
+    find_package(MPI COMPONENTS C REQUIRED)
+    add_executable(heatTransfer_read_adios2 heatRead_adios2.cpp PrintData.cpp)
+    target_include_directories(heatTransfer_read_adios2
+      PRIVATE ${MPI_C_INCLUDE_PATH}
+    )
+    target_link_libraries(heatTransfer_read_adios2
+      adios2 ${MPI_C_LIBRARIES}
+    )
+    
   if(ADIOS_USE_ADIOS1)
     find_package(ADIOS1 REQUIRED)
-    find_package(MPI COMPONENTS C REQUIRED)
 
     add_executable(heatTransfer_read_adios1 heatRead_adios1.cpp PrintData.cpp)
     target_include_directories(heatTransfer_read_adios1
@@ -16,5 +25,6 @@ if(ADIOS_USE_MPI)
       adios1::adios ${MPI_C_LIBRARIES}
     )
   endif()
+  
 endif()
 
diff --git a/examples/heatTransfer/read/heatRead_adios2.cpp b/examples/heatTransfer/read/heatRead_adios2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9d19ad85244b5c2d17404b6f1b66c58de85c8936
--- /dev/null
+++ b/examples/heatTransfer/read/heatRead_adios2.cpp
@@ -0,0 +1,111 @@
+
+#include <mpi.h>
+
+#include "adios2.h"
+
+#include <cstdint>
+#include <iomanip>
+#include <iostream>
+#include <math.h>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include "PrintData.h"
+
+int main(int argc, char *argv[])
+{
+    MPI_Init(&argc, &argv);
+
+    if (argc < 2)
+    {
+        std::cout << "Not enough arguments: need an input file\n";
+        return 1;
+    }
+    const char *inputfile = argv[1];
+
+    /* World comm spans all applications started with the same aprun command
+     on a Cray XK6. So we have to split and create the local
+     'world' communicator for the reader only.
+     In normal start-up, the communicator will just equal the MPI_COMM_WORLD.
+     */
+
+    int wrank, wnproc;
+    MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
+    MPI_Comm_size(MPI_COMM_WORLD, &wnproc);
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    const unsigned int color = 2;
+    MPI_Comm mpiReaderComm;
+    MPI_Comm_split(MPI_COMM_WORLD, color, wrank, &mpiReaderComm);
+
+    int rank, nproc;
+    MPI_Comm_rank(mpiReaderComm, &rank);
+    MPI_Comm_size(mpiReaderComm, &nproc);
+
+    adios::ADIOS ad("adios2.xml", mpiReaderComm, adios::Verbose::INFO);
+
+    // Define method for engine creation
+    // 1. Get method def from config file or define new one
+
+    adios::Method &bpReaderSettings = ad.DeclareMethod("input");
+    if (!bpReaderSettings.IsUserDefined())
+    {
+        // if not defined by user, we can change the default settings
+        // BPFileWriter is the default engine
+        bpReaderSettings.SetEngine("ADIOS1Reader");
+        // Allow an extra thread for data processing
+        bpReaderSettings.AllowThreads(1);
+        // ISO-POSIX file is the default transport
+        // Passing parameters to the transport
+        bpReaderSettings.AddTransport("File", "verbose=4");
+    }
+
+    auto bpReader = ad.Open(inputfile, "r", mpiReaderComm, bpReaderSettings);
+
+    if (bpReader == nullptr)
+        throw std::ios_base::failure("ERROR: failed to open ADIOS bpReader\n");
+
+    unsigned int gndx;
+    unsigned int gndy;
+    bpReader->Read<unsigned int>("gndx", &gndx);
+    bpReader->Read<unsigned int>("gndy", &gndy);
+
+    if (rank == 0)
+    {
+        std::cout << "gndx = " << gndx << std::endl;
+        std::cout << "gndy = " << gndy << std::endl;
+    }
+
+    // 1D decomposition of the columns, which is inefficient for reading!
+    std::vector<uint64_t> readsize({gndx, gndy / nproc});
+    std::vector<uint64_t> offset({0LL, rank * readsize[1]});
+    if (rank == nproc - 1)
+    {
+        // last process should read all the rest of columns
+        readsize[1] = gndy - readsize[1] * (nproc - 1);
+    }
+
+    std::cout << "rank " << rank << " reads " << readsize[1]
+              << " columns from offset " << offset[1] << std::endl;
+
+    adios::Variable<double> *vT = bpReader->InquireVariableDouble("T");
+
+    double *T = new double[vT->GetNSteps() * readsize[0] * readsize[1]];
+
+    // Create a 2D selection for the subset
+    adios::SelectionBoundingBox sel(offset, readsize);
+    vT->SetSelection(sel);
+
+    // Arrays are read by scheduling one or more of them
+    // and performing the reads at once
+    bpReader->ScheduleRead(*vT, T);
+    bpReader->PerformReads(adios::PerformReadMode::BLOCKINGREAD);
+
+    printData(T, readsize.data(), offset.data(), rank, vT->GetNSteps());
+    bpReader->Close();
+    delete[] T;
+    MPI_Finalize();
+    return 0;
+}
diff --git a/source/adios2/core/Engine.cpp b/source/adios2/core/Engine.cpp
index 76ded52fae6704f798c76c4692a3efa314c0f8bd..d8bcbd1eb5679d61ae02d86054cf8c37c0884a6f 100644
--- a/source/adios2/core/Engine.cpp
+++ b/source/adios2/core/Engine.cpp
@@ -280,11 +280,15 @@ VariableCompound *Engine::InquireVariableCompound(const std::string & /*name*/,
 }
 
 void Engine::Read(Variable<double> & /*variable*/, const double * /*values*/) {}
-void Engine::ScheduleRead(Variable<double> & /*variable*/,
-                          const double * /*values*/)
+void Engine::ScheduleRead(Variable<double> & /*variable*/, double * /*values*/)
+{
+}
+void Engine::ScheduleRead(const std::string /*variableName*/,
+                          double * /*values*/)
 {
 }
 void Engine::Release() {}
+void Engine::PerformReads(PerformReadMode /*mode*/){};
 
 // PROTECTED
 void Engine::Init() {}
diff --git a/source/adios2/core/Engine.h b/source/adios2/core/Engine.h
index cea4802d4a9caf53a85fb1a24496eeb757a118b4..dec2565ddb5e3064d50842b88c88a58d1eb640fb 100644
--- a/source/adios2/core/Engine.h
+++ b/source/adios2/core/Engine.h
@@ -311,7 +311,7 @@ public:
      * @param values pointer passed from the application
      */
     template <class T>
-    void ScheduleRead(Variable<T> &variable, const T *values)
+    void ScheduleRead(Variable<T> &variable, T *values)
     {
         ScheduleRead(variable, values);
     }
@@ -322,7 +322,7 @@ public:
      * @param values
      */
     template <class T>
-    void ScheduleRead(const std::string variableName, const T *values)
+    void ScheduleRead(const std::string variableName, T *values)
     {
         ScheduleRead(variableName, values);
     }
@@ -333,7 +333,7 @@ public:
      * @param values
      */
     template <class T>
-    void ScheduleRead(Variable<T> &variable, const T &values)
+    void ScheduleRead(Variable<T> &variable, T &values)
     {
         ScheduleRead(variable, &values);
     }
@@ -344,7 +344,7 @@ public:
      * @param values
      */
     template <class T>
-    void ScheduleRead(const std::string variableName, const T &values)
+    void ScheduleRead(const std::string variableName, T &values)
     {
         ScheduleRead(variableName, &values);
     }
@@ -364,7 +364,8 @@ public:
      */
     void ScheduleRead() { ScheduleRead(nullptr, nullptr); }
 
-    virtual void ScheduleRead(Variable<double> &variable, const double *values);
+    virtual void ScheduleRead(Variable<double> &variable, double *values);
+    virtual void ScheduleRead(const std::string variableName, double *values);
 
     /**
      * Perform all scheduled reads, either blocking until all reads completed,
@@ -372,7 +373,7 @@ public:
      * return immediately.
      * @param mode Blocking or non-blocking modes
      */
-    void PerformReads(PerformReadMode mode);
+    virtual void PerformReads(PerformReadMode mode);
 
     /**
      * Reader application indicates that no more data will be read from the
diff --git a/source/adios2/core/Variable.h b/source/adios2/core/Variable.h
index 5b0fdbb5b81b94743e2860d7c15efb68fbfa3841..9493878377380304c8f6734b4239e9e51477ee47 100644
--- a/source/adios2/core/Variable.h
+++ b/source/adios2/core/Variable.h
@@ -76,11 +76,6 @@ public:
      */
     std::vector<std::size_t> GetGlobalDimensions();
 
-    /** Return the number of steps available for the variable
-     *  @return Number of steps
-     */
-    int GetSteps();
-
     void Monitor(std::ostream &logInfo) const noexcept
     {
         logInfo << "Variable: " << m_Name << "\n";
diff --git a/source/adios2/core/VariableBase.h b/source/adios2/core/VariableBase.h
index aef3af0d3ab2b96817ec18b91b417a82155865f7..0061c8ec5a2abddb98f4255fad84966d02710a8b 100644
--- a/source/adios2/core/VariableBase.h
+++ b/source/adios2/core/VariableBase.h
@@ -133,6 +133,16 @@ public:
         ConvertUint64VectorToSizetVector(sel.m_Count, m_MemoryDimensions);
         ConvertUint64VectorToSizetVector(sel.m_Start, m_MemoryOffsets);
     }
+
+    /** Return the number of steps available for the variable
+     *  @return Number of steps
+     */
+    int GetNSteps() { return m_nsteps; }
+
+private:
+    /* Values filled by InquireVariable() */
+    int m_nsteps =
+        1; ///< number of steps available in a file (or 1 in staging),
 };
 
 } // end namespace
diff --git a/source/adios2/engine/adios1/ADIOS1Reader.cpp b/source/adios2/engine/adios1/ADIOS1Reader.cpp
index 7ec1ac27934ac73522c8d769e7fe4afe7f626ca0..b1ad2750dbc00e4072331460909a6ad18cb3fe54 100644
--- a/source/adios2/engine/adios1/ADIOS1Reader.cpp
+++ b/source/adios2/engine/adios1/ADIOS1Reader.cpp
@@ -27,9 +27,16 @@ ADIOS1Reader::ADIOS1Reader(ADIOS &adios, const std::string &name,
 {
     Init();
     adios_read_init_method(m_ReadMethod, mpiComm, "");
+    m_fh = adios_read_open(name.c_str(), m_ReadMethod, mpiComm,
+                           ADIOS_LOCKMODE_CURRENT, 0.0);
 }
 
-ADIOS1Reader::~ADIOS1Reader() { adios_read_finalize_method(m_ReadMethod); }
+ADIOS1Reader::~ADIOS1Reader()
+{
+    if (m_fh != nullptr)
+        adios_read_close(m_fh);
+    adios_read_finalize_method(m_ReadMethod);
+}
 
 Variable<void> *
 ADIOS1Reader::InquireVariable(const std::string &variableName,
@@ -157,7 +164,40 @@ ADIOS1Reader::InquireVariableCompound(const std::string &variableName,
     return nullptr;
 }
 
-void ADIOS1Reader::Close(const int transportIndex) {}
+void ADIOS1Reader::ScheduleReadCommon(const std::string &name,
+                                      const Dims &ldims, const Dims &offs,
+                                      void *data)
+{
+
+    uint64_t start[32], count[32];
+    for (int i = 0; i < ldims.size(); i++)
+    {
+        start[i] = (uint64_t)offs[i];
+        count[i] = (uint64_t)ldims[i];
+    }
+    ADIOS_SELECTION *sel =
+        adios_selection_boundingbox(ldims.size(), start, count);
+    adios_schedule_read(m_fh, sel, name.c_str(), 1, 0, data);
+    adios_selection_delete(sel);
+}
+
+void ADIOS1Reader::ScheduleRead(Variable<double> &variable, double *values)
+{
+    ScheduleReadCommon(variable.m_Name, variable.m_LocalDimensions,
+                       variable.m_Offsets, (void *)values);
+}
+
+void ADIOS1Reader::ScheduleRead(const std::string variableName, double *values)
+{
+    ScheduleRead(m_ADIOS.GetVariable<double>(variableName), values);
+}
+
+void ADIOS1Reader::PerformReads(PerformReadMode mode)
+{
+    adios_perform_reads(m_fh, (int)mode);
+}
+
+void ADIOS1Reader::Close(const int transportIndex) { adios_read_close(m_fh); }
 
 // PRIVATE
 void ADIOS1Reader::Init()
diff --git a/source/adios2/engine/adios1/ADIOS1Reader.h b/source/adios2/engine/adios1/ADIOS1Reader.h
index 51b9e044335625cdc6fd8274d408db3340ef24b0..720acbad605dd5ac6fb6802816f859cdad44ed5d 100644
--- a/source/adios2/engine/adios1/ADIOS1Reader.h
+++ b/source/adios2/engine/adios1/ADIOS1Reader.h
@@ -88,9 +88,14 @@ public:
     VariableCompound *InquireVariableCompound(const std::string &name,
                                               const bool readIn = true);
 
+    void ScheduleRead(Variable<double> &variable, double *values);
+    void ScheduleRead(const std::string variableName, double *values);
+
+    void PerformReads(PerformReadMode mode);
     void Close(const int transportIndex = -1);
 
 private:
+    ADIOS_FILE *m_fh = nullptr; ///< ADIOS1 file handler
     void Init(); ///< called from constructor, gets the selected ADIOS1
                  /// transport method from settings
     void InitParameters();
@@ -110,6 +115,9 @@ private:
         return nullptr; // on failure
     }
 
+    void ScheduleReadCommon(const std::string &name, const Dims &ldims,
+                            const Dims &offs, void *data);
+
     enum ADIOS_READ_METHOD m_ReadMethod = ADIOS_READ_METHOD_BP;
 };