From 9855a3e0781995d5fcd26b7d4b103d93ab032b7b Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Wed, 24 Jun 2020 17:56:08 -0400
Subject: [PATCH 01/10] Added tests for reading back global/local arrays with
 different modes: File vs Stream, All steps vs step by step, and
 block-by-block.

---
 testing/adios2/engine/bp/CMakeLists.txt       |   2 +
 .../engine/bp/TestBPStepsFileGlobalArray.cpp  | 908 ++++++++++++++++++
 .../engine/bp/TestBPStepsFileLocalArray.cpp   | 612 ++++++++++++
 3 files changed, 1522 insertions(+)
 create mode 100644 testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
 create mode 100644 testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp

diff --git a/testing/adios2/engine/bp/CMakeLists.txt b/testing/adios2/engine/bp/CMakeLists.txt
index f47d49ee46..70a4eaabaf 100644
--- a/testing/adios2/engine/bp/CMakeLists.txt
+++ b/testing/adios2/engine/bp/CMakeLists.txt
@@ -41,6 +41,8 @@ bp3_bp4_gtest_add_tests_helper(WriteReadBlockInfo MPI_ALLOW)
 bp3_bp4_gtest_add_tests_helper(WriteReadVariableSpan MPI_ALLOW)
 bp3_bp4_gtest_add_tests_helper(TimeAggregation MPI_ALLOW)
 bp3_bp4_gtest_add_tests_helper(NoXMLRecovery MPI_ALLOW)
+bp3_bp4_gtest_add_tests_helper(StepsFileGlobalArray MPI_ALLOW)
+bp3_bp4_gtest_add_tests_helper(StepsFileLocalArray MPI_ALLOW)
 
 if(NOT MSVC)
   bp3_bp4_gtest_add_tests_helper(BufferSize MPI_NONE)
diff --git a/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp b/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
new file mode 100644
index 0000000000..8b591e6b6c
--- /dev/null
+++ b/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
@@ -0,0 +1,908 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ */
+#include <cstdint>
+#include <cstring>
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+
+#include <adios2.h>
+
+#include <gtest/gtest.h>
+
+std::string engineName; // comes from command line
+
+class BPStepsFileGlobalArray : public ::testing::Test
+{
+protected:
+    BPStepsFileGlobalArray() = default;
+
+    // Number of elements per process
+    static const std::size_t Nx = 10;
+
+    const std::array<int32_t, Nx> I32 = {
+        {512, 513, -510, 515, -508, 517, -506, 519, -504, 521}};
+
+    std::array<int32_t, Nx> GenerateData(int step, int rank, int size)
+    {
+        std::array<int32_t, Nx> d;
+        int j = rank + 1 + step * size;
+        for (size_t i = 0; i < d.size(); ++i)
+        {
+            d[i] = I32[i] + j;
+        }
+        return d;
+    }
+
+    std::string ArrayToString(int32_t *data, size_t nelems)
+    {
+        std::stringstream ss;
+        ss << "[";
+        for (size_t i = 0; i < nelems; ++i)
+        {
+            ss << data[i];
+            if (i < nelems - 1)
+            {
+                ss << " ";
+            }
+        }
+        ss << "]";
+        return ss.str();
+    }
+};
+
+enum class ReadMode
+{
+    ReadFileAll,
+    ReadFileStepByStep,
+    ReadFileStepByStepBlocks,
+    ReadStream,
+    ReadStreamBlocks
+};
+
+std::string ReadModeToString(ReadMode r)
+{
+    switch (r)
+    {
+    case ReadMode::ReadFileAll:
+        return "ReadFileAll";
+        break;
+    case ReadMode::ReadFileStepByStep:
+        return "ReadFileStepByStep";
+        break;
+    case ReadMode::ReadFileStepByStepBlocks:
+        return "ReadFileStepByStepBlocks";
+        break;
+    case ReadMode::ReadStream:
+        return "ReadStream";
+        break;
+    case ReadMode::ReadStreamBlocks:
+        return "ReadStreamBlocks";
+        break;
+    }
+    return "unknown";
+}
+
+class BPStepsFileGlobalArrayReaders
+: public BPStepsFileGlobalArray,
+  public ::testing::WithParamInterface<ReadMode>
+{
+protected:
+    ReadMode GetReadMode() { return GetParam(); };
+};
+
+// Basic case: Variable written every step
+TEST_P(BPStepsFileGlobalArrayReaders, EveryStep)
+{
+    const ReadMode readMode = GetReadMode();
+    std::string fname_prefix =
+        "BPStepsFileGlobalArray.EveryStep." + ReadModeToString(readMode);
+    int mpiRank = 0, mpiSize = 1;
+    const std::size_t NSteps = 4;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::array<int32_t, Nx> m_TestData[NSteps];
+    adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
+    adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
+    adios2::Dims count{static_cast<unsigned int>(Nx)};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+#endif
+
+    // Write test data using ADIOS2
+    {
+        if (!mpiRank)
+        {
+            std::cout << "Write one variable in every step" << std::endl;
+        }
+        adios2::IO io = adios.DeclareIO("Write");
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+
+        adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
+
+        auto var_i32 = io.DefineVariable<int32_t>("i32", shape, start, count);
+
+        for (int step = 0; step < NSteps; ++step)
+        {
+            // Generate test data for each process uniquely
+            m_TestData[step] = GenerateData(step, mpiRank, mpiSize);
+            std::cout << "Rank " << mpiRank << " write step " << step << ": "
+                      << ArrayToString(m_TestData[step].data(), Nx)
+                      << std::endl;
+            engine.BeginStep();
+            engine.Put(var_i32, m_TestData[step].data());
+            engine.EndStep();
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+    adios2::IO io = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        io.SetEngine(engineName);
+    }
+    adios2::Engine engine = io.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(engine);
+
+    if (readMode == ReadMode::ReadFileAll)
+    {
+        /// Read back data with File reading mode
+        /// Read back the whole thing and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with File reading mode, read all steps at once"
+                      << std::endl;
+        }
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        EXPECT_TRUE(var_i32);
+        EXPECT_EQ(var_i32.Steps(), NSteps);
+        EXPECT_EQ(var_i32.StepsStart(), 0);
+
+        var_i32.SetStepSelection({0, NSteps});
+        size_t start = static_cast<size_t>(mpiRank) * Nx;
+        var_i32.SetSelection({{start}, {Nx}});
+        std::array<int32_t, NSteps * Nx> d;
+        engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+        std::cout << "Rank " << mpiRank
+                  << " read all steps: " << ArrayToString(d.data(), NSteps * Nx)
+                  << std::endl;
+        for (size_t step = 0; step < NSteps; ++step)
+        {
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[step * Nx + i], m_TestData[step][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadFileStepByStep)
+    {
+        /// Read back data with File reading mode
+        /// Read back step by step and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with File reading mode, read step by step"
+                      << std::endl;
+        }
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        EXPECT_TRUE(var_i32);
+        EXPECT_EQ(var_i32.Steps(), NSteps);
+        EXPECT_EQ(var_i32.StepsStart(), 0);
+        for (size_t step = 0; step < NSteps; ++step)
+        {
+            var_i32.SetStepSelection({step, 1});
+            size_t start = static_cast<size_t>(mpiRank) * Nx;
+            var_i32.SetSelection({{start}, {Nx}});
+            std::array<int32_t, Nx> d;
+            engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << step << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadFileStepByStepBlocks)
+    {
+        /// Read back data with File reading mode
+        /// Read back step by step and block by block and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with File reading mode, read step by step, "
+                         "block by block"
+                      << std::endl;
+        }
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        EXPECT_TRUE(var_i32);
+        EXPECT_EQ(var_i32.Steps(), NSteps);
+        EXPECT_EQ(var_i32.StepsStart(), 0);
+        for (size_t step = 0; step < NSteps; ++step)
+        {
+            var_i32.SetStepSelection({step, 1});
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var_i32.SetBlockSelection(blockID);
+            std::array<int32_t, Nx> d;
+            engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << step
+                      << " block " << blockID << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            auto start = var_i32.Start();
+            auto count = var_i32.Count();
+            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(count[0], 1 * Nx);
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadStream)
+    {
+        /// Read back data with Stream reading mode
+        /// Read back step by step and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with Stream reading mode, read step by step"
+                      << std::endl;
+        }
+        for (size_t step = 0; step < NSteps; ++step)
+        {
+            engine.BeginStep();
+            auto var_i32 = io.InquireVariable<int32_t>("i32");
+            EXPECT_TRUE(var_i32);
+            // EXPECT_EQ(var_i32.Steps(), 1);
+            EXPECT_EQ(var_i32.StepsStart(), 0);
+            size_t start = static_cast<size_t>(mpiRank) * Nx;
+            var_i32.SetSelection({{start}, {Nx}});
+            std::array<int32_t, Nx> d;
+            engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << step << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+            engine.EndStep();
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadStreamBlocks)
+    {
+        /// Read back data with Stream reading mode
+        /// Read back step by step and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with Stream reading mode, read step by step, "
+                         "block by block"
+                      << std::endl;
+        }
+        for (size_t step = 0; step < NSteps; ++step)
+        {
+            engine.BeginStep();
+            auto var_i32 = io.InquireVariable<int32_t>("i32");
+            EXPECT_TRUE(var_i32);
+            // EXPECT_EQ(var_i32.Steps(), 1);
+            EXPECT_EQ(var_i32.StepsStart(), 0);
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var_i32.SetBlockSelection(blockID);
+            std::array<int32_t, Nx> d;
+            engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << step
+                      << " block " << blockID << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            auto start = var_i32.Start();
+            auto count = var_i32.Count();
+            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(count[0], 1 * Nx);
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+            engine.EndStep();
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+}
+
+// Variable written every other step from 2nd step
+TEST_P(BPStepsFileGlobalArrayReaders, NewVarPerStep)
+{
+    const ReadMode readMode = GetReadMode();
+    std::string fname_prefix =
+        "BPStepsFileGlobalArray.NewVarPerStep." + ReadModeToString(readMode);
+    int mpiRank = 0, mpiSize = 1;
+    const std::size_t NSteps = 4;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::array<int32_t, Nx> m_TestData[NSteps];
+    adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
+    adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
+    adios2::Dims count{static_cast<unsigned int>(Nx)};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+#endif
+
+    auto lf_VarName = [](int step) -> std::string {
+        return "i32_" + std::to_string(step);
+    };
+
+    // Write test data using ADIOS2
+    {
+        if (!mpiRank)
+        {
+            std::cout << "Write a new variable in each step" << std::endl;
+        }
+        adios2::IO io = adios.DeclareIO("Write");
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+
+        adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
+
+        for (int step = 0; step < NSteps; ++step)
+        {
+            const std::string varName = lf_VarName(step);
+            auto var = io.DefineVariable<int32_t>(varName, shape, start, count);
+            // Generate test data for each process uniquely
+            m_TestData[step] = GenerateData(step, mpiRank, mpiSize);
+            std::cout << "Rank " << mpiRank << " write step " << step << " var "
+                      << varName << ": "
+                      << ArrayToString(m_TestData[step].data(), Nx)
+                      << std::endl;
+            engine.BeginStep();
+            engine.Put(var, m_TestData[step].data());
+            engine.EndStep();
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+    adios2::IO io = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        io.SetEngine(engineName);
+    }
+    adios2::Engine engine = io.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(engine);
+
+    if (readMode == ReadMode::ReadFileAll)
+    {
+        /// Read back each variable with File reading mode
+        /// Use SetStepSelection(0,1) explicitly
+        if (!mpiRank)
+        {
+            std::cout
+                << "Read with File reading mode using explicit SetStepSelection"
+                << std::endl;
+        }
+        for (int step = 0; step < NSteps; ++step)
+        {
+            const std::string varName = lf_VarName(step);
+            auto var = io.InquireVariable<int32_t>(varName);
+            EXPECT_TRUE(var);
+            EXPECT_EQ(var.Steps(), 1);
+            EXPECT_EQ(var.StepsStart(), 0);
+            var.SetStepSelection({0, 1});
+            size_t start = static_cast<size_t>(mpiRank) * Nx;
+            var.SetSelection({{start}, {Nx}});
+            std::array<int32_t, Nx> d;
+            engine.Get(var, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read var " << varName << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadFileStepByStep)
+    {
+        /// Read back each variable with File reading mode
+        /// and do not use SetStepSelection() so default read after open is
+        /// tested
+        if (!mpiRank)
+        {
+            std::cout << "Read with File reading mode without SetStepSelection"
+                      << std::endl;
+        }
+        for (int step = 0; step < NSteps; ++step)
+        {
+            const std::string varName = lf_VarName(step);
+            auto var = io.InquireVariable<int32_t>(varName);
+            EXPECT_TRUE(var);
+            EXPECT_EQ(var.Steps(), 1);
+            EXPECT_EQ(var.StepsStart(), 0);
+            size_t start = static_cast<size_t>(mpiRank) * Nx;
+            var.SetSelection({{start}, {Nx}});
+            std::array<int32_t, Nx> d;
+            engine.Get(var, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read var " << varName << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadFileStepByStepBlocks)
+    {
+        /// Read back each variable with File reading mode
+        /// Read back block by block and check data
+        if (!mpiRank)
+        {
+            std::cout
+                << "Read with File reading mode using explicit SetStepSelection"
+                   ", block by block"
+                << std::endl;
+        }
+        for (int step = 0; step < NSteps; ++step)
+        {
+            const std::string varName = lf_VarName(step);
+            auto var = io.InquireVariable<int32_t>(varName);
+            EXPECT_TRUE(var);
+            EXPECT_EQ(var.Steps(), 1);
+            EXPECT_EQ(var.StepsStart(), 0);
+            var.SetStepSelection({0, 1});
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var.SetBlockSelection(blockID);
+            std::array<int32_t, Nx> d;
+            engine.Get(var, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << step
+                      << " block " << blockID << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            auto start = var.Start();
+            auto count = var.Count();
+            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(count[0], 1 * Nx);
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadStream)
+    {
+        /// Read back each variable with Streaming reading mode
+        if (!mpiRank)
+        {
+            std::cout << "Read with Stream reading mode step by step"
+                      << std::endl;
+        }
+        for (int step = 0; step < NSteps; ++step)
+        {
+            engine.BeginStep();
+            const std::string varName = lf_VarName(step);
+            auto var = io.InquireVariable<int32_t>(varName);
+            EXPECT_TRUE(var);
+            EXPECT_EQ(var.Steps(), 1);
+            EXPECT_EQ(var.StepsStart(), 0);
+            size_t start = static_cast<size_t>(mpiRank) * Nx;
+            var.SetSelection({{start}, {Nx}});
+            std::array<int32_t, Nx> d;
+            engine.Get(var, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read var " << varName << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+            engine.EndStep();
+#if ADIOS2_USE_MPI
+            MPI_Barrier(MPI_COMM_WORLD);
+#endif
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadStreamBlocks)
+    {
+        /// Read back each variable with Streaming reading mode
+        if (!mpiRank)
+        {
+            std::cout
+                << "Read with Stream reading mode step by step, block by block"
+                << std::endl;
+        }
+        for (int step = 0; step < NSteps; ++step)
+        {
+            engine.BeginStep();
+            const std::string varName = lf_VarName(step);
+            auto var = io.InquireVariable<int32_t>(varName);
+            EXPECT_TRUE(var);
+            EXPECT_EQ(var.Steps(), 1);
+            EXPECT_EQ(var.StepsStart(), 0);
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var.SetBlockSelection(blockID);
+            std::array<int32_t, Nx> d;
+            engine.Get(var, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << step
+                      << " block " << blockID << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            auto start = var.Start();
+            auto count = var.Count();
+            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(count[0], 1 * Nx);
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+            engine.EndStep();
+#if ADIOS2_USE_MPI
+            MPI_Barrier(MPI_COMM_WORLD);
+#endif
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+}
+
+INSTANTIATE_TEST_CASE_P(BPStepsFileGlobalArray, BPStepsFileGlobalArrayReaders,
+                        ::testing::Values(ReadMode::ReadFileAll,
+                                          ReadMode::ReadFileStepByStep,
+                                          ReadMode::ReadFileStepByStepBlocks,
+                                          ReadMode::ReadStream,
+                                          ReadMode::ReadStreamBlocks));
+
+class BPStepsFileGlobalArrayParameters
+: public BPStepsFileGlobalArray,
+  public ::testing::WithParamInterface<std::tuple<size_t, size_t, ReadMode>>
+{
+protected:
+    size_t GetNsteps() { return std::get<0>(GetParam()); };
+    size_t GetOddity() { return std::get<1>(GetParam()); };
+    ReadMode GetReadMode() { return std::get<2>(GetParam()); };
+};
+
+// Variable written every other step from 1st step
+TEST_P(BPStepsFileGlobalArrayParameters, EveryOtherStep)
+{
+    const std::size_t NSteps = GetNsteps();
+    const std::size_t Oddity = GetOddity();
+    const ReadMode readMode = GetReadMode();
+    std::string fname_prefix =
+        "BPStepsFileGlobalArray.EveryOtherStep.Steps" + std::to_string(NSteps) +
+        ".Oddity" + std::to_string(Oddity) + "." + ReadModeToString(readMode);
+    int mpiRank = 0, mpiSize = 1;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::array<int32_t, Nx> m_TestData[NSteps / 2];
+    adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
+    adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
+    adios2::Dims count{static_cast<unsigned int>(Nx)};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+
+#endif
+
+    size_t stepsWritten = 0;
+
+    // Write test data using ADIOS2
+    {
+        if (!mpiRank)
+        {
+            std::cout << "Write one variable in every "
+                      << (Oddity ? "ODD" : "EVEN") << " steps, within "
+                      << std::to_string(NSteps) << " steps" << std::endl;
+        }
+        adios2::IO io = adios.DeclareIO("Write");
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+
+        adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
+
+        auto var_i32 = io.DefineVariable<int32_t>("i32", shape, start, count);
+        auto var_step = io.DefineVariable<int>("step");
+        for (int step = 0; step < NSteps; ++step)
+        {
+            // Generate test data for each process uniquely
+            engine.BeginStep();
+            engine.Put(var_step, step);
+            if (step % 2 == Oddity)
+            {
+                m_TestData[stepsWritten] = GenerateData(step, mpiRank, mpiSize);
+                std::cout << "Rank " << mpiRank << " write step " << step
+                          << ": "
+                          << ArrayToString(m_TestData[stepsWritten].data(), Nx)
+                          << std::endl;
+                engine.Put(var_i32, m_TestData[stepsWritten].data());
+                ++stepsWritten;
+            }
+            engine.EndStep();
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+    adios2::IO io = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        io.SetEngine(engineName);
+    }
+    adios2::Engine engine = io.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(engine);
+
+    if (readMode == ReadMode::ReadFileAll)
+    {
+        /// Read back data with File reading mode
+        /// Read back the whole thing and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with File reading mode, read all steps at once"
+                      << std::endl;
+        }
+
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        EXPECT_TRUE(var_i32);
+        EXPECT_EQ(var_i32.Steps(), stepsWritten);
+        EXPECT_EQ(var_i32.StepsStart(), 0);
+
+        var_i32.SetStepSelection({0, stepsWritten});
+        size_t start = static_cast<size_t>(mpiRank) * Nx;
+        var_i32.SetSelection({{start}, {Nx}});
+        std::vector<int32_t> d(stepsWritten * Nx, 0);
+        engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+        std::cout << "Rank " << mpiRank
+                  << " read all steps: " << ArrayToString(d.data(), d.size())
+                  << std::endl;
+        for (size_t s = 0; s < stepsWritten; ++s)
+        {
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[s * Nx + i], m_TestData[s][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadFileStepByStep)
+    {
+        /// Read back data with File reading mode
+        /// Read back step by step and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with File reading mode, read step by step"
+                      << std::endl;
+        }
+
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        EXPECT_TRUE(var_i32);
+        EXPECT_EQ(var_i32.Steps(), stepsWritten);
+        EXPECT_EQ(var_i32.StepsStart(), 0);
+
+        for (size_t s = 0; s < stepsWritten; ++s)
+        {
+            var_i32.SetStepSelection({s, 1});
+            size_t start = static_cast<size_t>(mpiRank) * Nx;
+            var_i32.SetSelection({{start}, {Nx}});
+            std::array<int32_t, Nx> d;
+            engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << s << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[s][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadFileStepByStepBlocks)
+    {
+        /// Read back data with File reading mode
+        /// Read back step by step, block by block and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with File reading mode, read step by step, "
+                         "block by block"
+                      << std::endl;
+        }
+
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        EXPECT_TRUE(var_i32);
+        EXPECT_EQ(var_i32.Steps(), stepsWritten);
+        EXPECT_EQ(var_i32.StepsStart(), 0);
+
+        for (size_t s = 0; s < stepsWritten; ++s)
+        {
+            var_i32.SetStepSelection({s, 1});
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var_i32.SetBlockSelection(blockID);
+            std::array<int32_t, Nx> d;
+            engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << s << " block "
+                      << blockID << ": " << ArrayToString(d.data(), Nx)
+                      << std::endl;
+            auto start = var_i32.Start();
+            auto count = var_i32.Count();
+            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(count[0], 1 * Nx);
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[s][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadStream)
+    {
+        /// Read back data with Stream reading mode
+        /// Read back step by step and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with Stream reading mode step by step"
+                      << std::endl;
+        }
+
+        size_t writtenStep = 0;
+        for (int step = 0; step < NSteps; ++step)
+        {
+            engine.BeginStep();
+            if (step % 2 == Oddity)
+            {
+                auto var_i32 = io.InquireVariable<int32_t>("i32");
+                EXPECT_TRUE(var_i32);
+                // EXPECT_EQ(var_i32.Steps(), 1);
+                EXPECT_EQ(var_i32.StepsStart(), 0);
+                size_t start = static_cast<size_t>(mpiRank) * Nx;
+                var_i32.SetSelection({{start}, {Nx}});
+                std::array<int32_t, Nx> d;
+                engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+                std::cout << "Rank " << mpiRank << " read at step " << step
+                          << ": " << ArrayToString(d.data(), Nx) << std::endl;
+
+                for (size_t i = 0; i < Nx; ++i)
+                {
+                    EXPECT_EQ(d[i], m_TestData[writtenStep][i]);
+                }
+                ++writtenStep;
+            }
+            engine.EndStep();
+#if ADIOS2_USE_MPI
+            MPI_Barrier(MPI_COMM_WORLD);
+#endif
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadStreamBlocks)
+    {
+        /// Read back data with Stream reading mode
+        /// Read back step by step and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with Stream reading mode, read step by step, "
+                         "block by block"
+                      << std::endl;
+        }
+        for (size_t step = 0; step < NSteps; ++step)
+        {
+            engine.BeginStep();
+            if (step % 2 == Oddity)
+            {
+                auto var_i32 = io.InquireVariable<int32_t>("i32");
+                EXPECT_TRUE(var_i32);
+                // EXPECT_EQ(var_i32.Steps(), 1);
+                EXPECT_EQ(var_i32.StepsStart(), 0);
+                size_t blockID = static_cast<size_t>(mpiRank);
+                var_i32.SetBlockSelection(blockID);
+                std::array<int32_t, Nx> d;
+                engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+                std::cout << "Rank " << mpiRank << " read step " << step
+                          << " block " << blockID << ": "
+                          << ArrayToString(d.data(), Nx) << std::endl;
+                auto start = var_i32.Start();
+                auto count = var_i32.Count();
+                EXPECT_EQ(start[0], mpiRank * Nx);
+                EXPECT_EQ(count[0], 1 * Nx);
+                for (size_t i = 0; i < Nx; ++i)
+                {
+                    EXPECT_EQ(d[i], m_TestData[step][i]);
+                }
+            }
+            engine.EndStep();
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+}
+
+INSTANTIATE_TEST_CASE_P(
+    BPStepsFileGlobalArray, BPStepsFileGlobalArrayParameters,
+    ::testing::Values(std::make_tuple(4, 0, ReadMode::ReadFileAll),
+                      std::make_tuple(4, 0, ReadMode::ReadFileStepByStep),
+                      std::make_tuple(4, 0, ReadMode::ReadFileStepByStepBlocks),
+                      std::make_tuple(4, 0, ReadMode::ReadStream),
+                      std::make_tuple(4, 0, ReadMode::ReadStreamBlocks),
+                      std::make_tuple(4, 1, ReadMode::ReadFileAll),
+                      std::make_tuple(4, 1, ReadMode::ReadFileStepByStep),
+                      std::make_tuple(4, 1, ReadMode::ReadFileStepByStepBlocks),
+                      std::make_tuple(4, 1, ReadMode::ReadStream),
+                      std::make_tuple(4, 1, ReadMode::ReadStreamBlocks),
+                      std::make_tuple(2, 1, ReadMode::ReadFileAll),
+                      std::make_tuple(2, 1, ReadMode::ReadFileStepByStep),
+                      std::make_tuple(2, 1, ReadMode::ReadFileStepByStepBlocks),
+                      std::make_tuple(2, 1, ReadMode::ReadStream),
+                      std::make_tuple(2, 1, ReadMode::ReadStreamBlocks)));
+//******************************************************************************
+// main
+//******************************************************************************
+
+int main(int argc, char **argv)
+{
+#if ADIOS2_USE_MPI
+    MPI_Init(nullptr, nullptr);
+#endif
+
+    int result;
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (argc > 1)
+    {
+        engineName = std::string(argv[1]);
+    }
+    result = RUN_ALL_TESTS();
+
+#if ADIOS2_USE_MPI
+    MPI_Finalize();
+#endif
+
+    return result;
+}
diff --git a/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp b/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp
new file mode 100644
index 0000000000..0ae936097f
--- /dev/null
+++ b/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp
@@ -0,0 +1,612 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ */
+#include <cstdint>
+#include <cstring>
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+
+#include <adios2.h>
+
+#include <gtest/gtest.h>
+
+std::string engineName; // comes from command line
+
+class BPStepsFileLocalArray : public ::testing::Test
+{
+protected:
+    BPStepsFileLocalArray() = default;
+
+    // Number of elements per process
+    static const std::size_t Nx = 10;
+
+    const std::array<int32_t, Nx> I32 = {
+        {512, 513, -510, 515, -508, 517, -506, 519, -504, 521}};
+
+    std::array<int32_t, Nx> GenerateData(int step, int rank, int size)
+    {
+        std::array<int32_t, Nx> d;
+        int j = rank + 1 + step * size;
+        for (size_t i = 0; i < d.size(); ++i)
+        {
+            d[i] = I32[i] + j;
+        }
+        return d;
+    }
+
+    std::string ArrayToString(int32_t *data, size_t nelems)
+    {
+        std::stringstream ss;
+        ss << "[";
+        for (size_t i = 0; i < nelems; ++i)
+        {
+            ss << data[i];
+            if (i < nelems - 1)
+            {
+                ss << " ";
+            }
+        }
+        ss << "]";
+        return ss.str();
+    }
+};
+
+enum class ReadMode
+{
+    ReadFileStepByStepBlocks,
+    ReadStreamBlocks
+};
+
+std::string ReadModeToString(ReadMode r)
+{
+    switch (r)
+    {
+    case ReadMode::ReadFileStepByStepBlocks:
+        return "ReadFileStepByStepBlocks";
+        break;
+    case ReadMode::ReadStreamBlocks:
+        return "ReadStreamBlocks";
+        break;
+    }
+    return "unknown";
+}
+
+class BPStepsFileLocalArrayReaders
+: public BPStepsFileLocalArray,
+  public ::testing::WithParamInterface<ReadMode>
+{
+protected:
+    ReadMode GetReadMode() { return GetParam(); };
+};
+
+// Basic case: Variable written every step
+TEST_P(BPStepsFileLocalArrayReaders, EveryStep)
+{
+    const ReadMode readMode = GetReadMode();
+    std::string fname_prefix =
+        "BPStepsFileLocalArray.EveryStep." + ReadModeToString(readMode);
+    int mpiRank = 0, mpiSize = 1;
+    const std::size_t NSteps = 4;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::array<int32_t, Nx> m_TestData[NSteps];
+    adios2::Dims shape{};
+    adios2::Dims start{};
+    adios2::Dims count{Nx};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+#endif
+
+    // Write test data using ADIOS2
+    {
+        if (!mpiRank)
+        {
+            std::cout << "Write one variable in every step" << std::endl;
+        }
+        adios2::IO io = adios.DeclareIO("Write");
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+
+        adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
+
+        auto var_i32 = io.DefineVariable<int32_t>("i32", shape, start, count);
+
+        for (int step = 0; step < NSteps; ++step)
+        {
+            // Generate test data for each process uniquely
+            m_TestData[step] = GenerateData(step, mpiRank, mpiSize);
+            std::cout << "Rank " << mpiRank << " write step " << step << ": "
+                      << ArrayToString(m_TestData[step].data(), Nx)
+                      << std::endl;
+            engine.BeginStep();
+            engine.Put(var_i32, m_TestData[step].data());
+            engine.EndStep();
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+    adios2::IO io = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        io.SetEngine(engineName);
+    }
+    adios2::Engine engine = io.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(engine);
+
+    if (readMode == ReadMode::ReadFileStepByStepBlocks)
+    {
+        /// Read back data with File reading mode
+        /// Read back step by step and block by block and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with File reading mode, read step by step, "
+                         "block by block"
+                      << std::endl;
+        }
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        EXPECT_TRUE(var_i32);
+        EXPECT_EQ(var_i32.Steps(), NSteps);
+        EXPECT_EQ(var_i32.StepsStart(), 0);
+        for (size_t step = 0; step < NSteps; ++step)
+        {
+            var_i32.SetStepSelection({step, 1});
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var_i32.SetBlockSelection(blockID);
+            std::array<int32_t, Nx> d;
+            engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << step
+                      << " block " << blockID << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            auto start = var_i32.Start();
+            auto count = var_i32.Count();
+            /*EXPECT_EQ(start.size(), 1); -- start and count is actually {}
+            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(count.size(), 1);
+            EXPECT_EQ(count[0], 1 * Nx);*/
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadStreamBlocks)
+    {
+        /// Read back data with Stream reading mode
+        /// Read back step by step and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with Stream reading mode, read step by step, "
+                         "block by block"
+                      << std::endl;
+        }
+        for (size_t step = 0; step < NSteps; ++step)
+        {
+            engine.BeginStep();
+            auto var_i32 = io.InquireVariable<int32_t>("i32");
+            EXPECT_TRUE(var_i32);
+            // EXPECT_EQ(var_i32.Steps(), 1);
+            EXPECT_EQ(var_i32.StepsStart(), 0);
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var_i32.SetBlockSelection(blockID);
+            std::array<int32_t, Nx> d;
+            engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << step
+                      << " block " << blockID << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            auto start = var_i32.Start();
+            auto count = var_i32.Count();
+            /*EXPECT_EQ(start.size(), 1); -- start and count is actually {}
+            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(count.size(), 1);
+            EXPECT_EQ(count[0], 1 * Nx);*/
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+            engine.EndStep();
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+}
+
+// Variable written every other step from 2nd step
+TEST_P(BPStepsFileLocalArrayReaders, NewVarPerStep)
+{
+    const ReadMode readMode = GetReadMode();
+    std::string fname_prefix =
+        "BPStepsFileLocalArray.NewVarPerStep." + ReadModeToString(readMode);
+    int mpiRank = 0, mpiSize = 1;
+    const std::size_t NSteps = 4;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::array<int32_t, Nx> m_TestData[NSteps];
+    adios2::Dims shape{};
+    adios2::Dims start{};
+    adios2::Dims count{Nx};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+#endif
+
+    auto lf_VarName = [](int step) -> std::string {
+        return "i32_" + std::to_string(step);
+    };
+
+    // Write test data using ADIOS2
+    {
+        if (!mpiRank)
+        {
+            std::cout << "Write a new variable in each step" << std::endl;
+        }
+        adios2::IO io = adios.DeclareIO("Write");
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+
+        adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
+
+        for (int step = 0; step < NSteps; ++step)
+        {
+            const std::string varName = lf_VarName(step);
+            auto var = io.DefineVariable<int32_t>(varName, shape, start, count);
+            // Generate test data for each process uniquely
+            m_TestData[step] = GenerateData(step, mpiRank, mpiSize);
+            std::cout << "Rank " << mpiRank << " write step " << step << " var "
+                      << varName << ": "
+                      << ArrayToString(m_TestData[step].data(), Nx)
+                      << std::endl;
+            engine.BeginStep();
+            engine.Put(var, m_TestData[step].data());
+            engine.EndStep();
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+    adios2::IO io = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        io.SetEngine(engineName);
+    }
+    adios2::Engine engine = io.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(engine);
+
+    if (readMode == ReadMode::ReadFileStepByStepBlocks)
+    {
+        /// Read back each variable with File reading mode
+        /// Read back block by block and check data
+        if (!mpiRank)
+        {
+            std::cout
+                << "Read with File reading mode using explicit SetStepSelection"
+                   ", block by block"
+                << std::endl;
+        }
+        for (int step = 0; step < NSteps; ++step)
+        {
+            const std::string varName = lf_VarName(step);
+            auto var = io.InquireVariable<int32_t>(varName);
+            EXPECT_TRUE(var);
+            EXPECT_EQ(var.Steps(), 1);
+            EXPECT_EQ(var.StepsStart(), 0);
+            var.SetStepSelection({0, 1});
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var.SetBlockSelection(blockID);
+            std::array<int32_t, Nx> d;
+            engine.Get(var, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << step
+                      << " block " << blockID << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            auto start = var.Start();
+            auto count = var.Count();
+            /*EXPECT_EQ(start.size(), 1); -- start and count is actually {}
+            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(count.size(), 1);
+            EXPECT_EQ(count[0], 1 * Nx);*/
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadStreamBlocks)
+    {
+        /// Read back each variable with Streaming reading mode
+        if (!mpiRank)
+        {
+            std::cout
+                << "Read with Stream reading mode step by step, block by block"
+                << std::endl;
+        }
+        for (int step = 0; step < NSteps; ++step)
+        {
+            engine.BeginStep();
+            const std::string varName = lf_VarName(step);
+            auto var = io.InquireVariable<int32_t>(varName);
+            EXPECT_TRUE(var);
+            EXPECT_EQ(var.Steps(), 1);
+            EXPECT_EQ(var.StepsStart(), 0);
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var.SetBlockSelection(blockID);
+            std::array<int32_t, Nx> d;
+            engine.Get(var, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << step
+                      << " block " << blockID << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            auto start = var.Start();
+            auto count = var.Count();
+            /*EXPECT_EQ(start.size(), 1); -- start and count is actually {}
+            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(count.size(), 1);
+            EXPECT_EQ(count[0], 1 * Nx);*/
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[step][i]);
+            }
+            engine.EndStep();
+#if ADIOS2_USE_MPI
+            MPI_Barrier(MPI_COMM_WORLD);
+#endif
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+}
+
+INSTANTIATE_TEST_CASE_P(BPStepsFileLocalArray, BPStepsFileLocalArrayReaders,
+                        ::testing::Values(ReadMode::ReadFileStepByStepBlocks,
+                                          ReadMode::ReadStreamBlocks));
+
+class BPStepsFileLocalArrayParameters
+: public BPStepsFileLocalArray,
+  public ::testing::WithParamInterface<std::tuple<size_t, size_t, ReadMode>>
+{
+protected:
+    size_t GetNsteps() { return std::get<0>(GetParam()); };
+    size_t GetOddity() { return std::get<1>(GetParam()); };
+    ReadMode GetReadMode() { return std::get<2>(GetParam()); };
+};
+
+// Variable written every other step from 1st step
+TEST_P(BPStepsFileLocalArrayParameters, EveryOtherStep)
+{
+    const std::size_t NSteps = GetNsteps();
+    const std::size_t Oddity = GetOddity();
+    const ReadMode readMode = GetReadMode();
+    std::string fname_prefix =
+        "BPStepsFileLocalArray.EveryOtherStep.Steps" + std::to_string(NSteps) +
+        ".Oddity" + std::to_string(Oddity) + "." + ReadModeToString(readMode);
+    int mpiRank = 0, mpiSize = 1;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::array<int32_t, Nx> m_TestData[NSteps / 2];
+    adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
+    adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
+    adios2::Dims count{static_cast<unsigned int>(Nx)};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+
+#endif
+
+    size_t stepsWritten = 0;
+
+    // Write test data using ADIOS2
+    {
+        if (!mpiRank)
+        {
+            std::cout << "Write one variable in every "
+                      << (Oddity ? "ODD" : "EVEN") << " steps, within "
+                      << std::to_string(NSteps) << " steps" << std::endl;
+        }
+        adios2::IO io = adios.DeclareIO("Write");
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+
+        adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
+
+        auto var_i32 = io.DefineVariable<int32_t>("i32", shape, start, count);
+        auto var_step = io.DefineVariable<int>("step");
+        for (int step = 0; step < NSteps; ++step)
+        {
+            // Generate test data for each process uniquely
+            engine.BeginStep();
+            engine.Put(var_step, step);
+            if (step % 2 == Oddity)
+            {
+                m_TestData[stepsWritten] = GenerateData(step, mpiRank, mpiSize);
+                std::cout << "Rank " << mpiRank << " write step " << step
+                          << ": "
+                          << ArrayToString(m_TestData[stepsWritten].data(), Nx)
+                          << std::endl;
+                engine.Put(var_i32, m_TestData[stepsWritten].data());
+                ++stepsWritten;
+            }
+            engine.EndStep();
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+    adios2::IO io = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        io.SetEngine(engineName);
+    }
+    adios2::Engine engine = io.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(engine);
+
+    if (readMode == ReadMode::ReadFileStepByStepBlocks)
+    {
+        /// Read back data with File reading mode
+        /// Read back step by step, block by block and check data
+        if (!mpiRank)
+        {
+            std::cout << "Read with File reading mode, read step by step, "
+                         "block by block"
+                      << std::endl;
+        }
+
+        auto var_i32 = io.InquireVariable<int32_t>("i32");
+        EXPECT_TRUE(var_i32);
+        EXPECT_EQ(var_i32.Steps(), stepsWritten);
+        EXPECT_EQ(var_i32.StepsStart(), 0);
+
+        for (size_t s = 0; s < stepsWritten; ++s)
+        {
+            var_i32.SetStepSelection({s, 1});
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var_i32.SetBlockSelection(blockID);
+            std::array<int32_t, Nx> d;
+            engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << s << " block "
+                      << blockID << ": " << ArrayToString(d.data(), Nx)
+                      << std::endl;
+            auto start = var_i32.Start();
+            auto count = var_i32.Count();
+            EXPECT_EQ(start.size(), 1);
+            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(count.size(), 1);
+            EXPECT_EQ(count[0], 1 * Nx);
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[s][i]);
+            }
+        }
+        engine.Close();
+    }
+    else if (readMode == ReadMode::ReadStreamBlocks)
+    {
+        /// Read back data with Stream reading mode
+        /// Read back step by step and check data
+        if (!mpiRank)
+        {
+            std::cout
+                << "Read with Stream reading mode step by step, block by block"
+                << std::endl;
+        }
+
+        size_t writtenStep = 0;
+        for (int step = 0; step < NSteps; ++step)
+        {
+            engine.BeginStep();
+            if (step % 2 == Oddity)
+            {
+                auto var_i32 = io.InquireVariable<int32_t>("i32");
+                EXPECT_TRUE(var_i32);
+                // EXPECT_EQ(var_i32.Steps(), 1);
+                EXPECT_EQ(var_i32.StepsStart(), 0);
+                size_t blockID = static_cast<size_t>(mpiRank);
+                var_i32.SetBlockSelection(blockID);
+                std::array<int32_t, Nx> d;
+                engine.Get(var_i32, d.data(), adios2::Mode::Sync);
+                std::cout << "Rank " << mpiRank << " read step " << step
+                          << " block " << blockID << ": "
+                          << ArrayToString(d.data(), Nx) << std::endl;
+                auto start = var_i32.Start();
+                auto count = var_i32.Count();
+                EXPECT_EQ(start.size(), 1);
+                EXPECT_EQ(start[0], mpiRank * Nx);
+                EXPECT_EQ(count.size(), 1);
+                EXPECT_EQ(count[0], 1 * Nx);
+                for (size_t i = 0; i < Nx; ++i)
+                {
+                    EXPECT_EQ(d[i], m_TestData[writtenStep][i]);
+                }
+                ++writtenStep;
+            }
+            engine.EndStep();
+#if ADIOS2_USE_MPI
+            MPI_Barrier(MPI_COMM_WORLD);
+#endif
+        }
+        engine.Close();
+    }
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+}
+
+INSTANTIATE_TEST_CASE_P(
+    BPStepsFileLocalArray, BPStepsFileLocalArrayParameters,
+    ::testing::Values(std::make_tuple(4, 0, ReadMode::ReadFileStepByStepBlocks),
+                      std::make_tuple(4, 0, ReadMode::ReadStreamBlocks),
+                      std::make_tuple(4, 1, ReadMode::ReadFileStepByStepBlocks),
+                      std::make_tuple(4, 1, ReadMode::ReadStreamBlocks),
+                      std::make_tuple(2, 1, ReadMode::ReadFileStepByStepBlocks),
+                      std::make_tuple(2, 1, ReadMode::ReadStreamBlocks)));
+//******************************************************************************
+// main
+//******************************************************************************
+
+int main(int argc, char **argv)
+{
+#if ADIOS2_USE_MPI
+    MPI_Init(nullptr, nullptr);
+#endif
+
+    int result;
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (argc > 1)
+    {
+        engineName = std::string(argv[1]);
+    }
+    result = RUN_ALL_TESTS();
+
+#if ADIOS2_USE_MPI
+    MPI_Finalize();
+#endif
+
+    return result;
+}

From 13a06f8431363b60bfda19d45f5823ac1f55ee40 Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Thu, 25 Jun 2020 08:05:32 -0400
Subject: [PATCH 02/10] Added insitu cases for testing steps, five different
 schedules of three write and read steps.

---
 testing/adios2/engine/bp/CMakeLists.txt       |   2 +
 .../engine/bp/TestBPStepsFileGlobalArray.cpp  |   8 +-
 .../engine/bp/TestBPStepsFileLocalArray.cpp   |  40 +-
 .../bp/TestBPStepsInSituGlobalArray.cpp       | 683 ++++++++++++++++++
 .../engine/bp/TestBPStepsInSituLocalArray.cpp | 535 ++++++++++++++
 5 files changed, 1241 insertions(+), 27 deletions(-)
 create mode 100644 testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
 create mode 100644 testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp

diff --git a/testing/adios2/engine/bp/CMakeLists.txt b/testing/adios2/engine/bp/CMakeLists.txt
index 70a4eaabaf..0216f10137 100644
--- a/testing/adios2/engine/bp/CMakeLists.txt
+++ b/testing/adios2/engine/bp/CMakeLists.txt
@@ -43,6 +43,8 @@ bp3_bp4_gtest_add_tests_helper(TimeAggregation MPI_ALLOW)
 bp3_bp4_gtest_add_tests_helper(NoXMLRecovery MPI_ALLOW)
 bp3_bp4_gtest_add_tests_helper(StepsFileGlobalArray MPI_ALLOW)
 bp3_bp4_gtest_add_tests_helper(StepsFileLocalArray MPI_ALLOW)
+bp3_bp4_gtest_add_tests_helper(StepsInSituGlobalArray MPI_ALLOW)
+bp3_bp4_gtest_add_tests_helper(StepsInSituLocalArray MPI_ALLOW)
 
 if(NOT MSVC)
   bp3_bp4_gtest_add_tests_helper(BufferSize MPI_NONE)
diff --git a/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp b/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
index 8b591e6b6c..2357abebb9 100644
--- a/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
@@ -5,9 +5,12 @@
 #include <cstdint>
 #include <cstring>
 
+#include <array>
 #include <iostream>
 #include <sstream>
 #include <stdexcept>
+#include <string>
+#include <vector>
 
 #include <adios2.h>
 
@@ -69,19 +72,14 @@ std::string ReadModeToString(ReadMode r)
     {
     case ReadMode::ReadFileAll:
         return "ReadFileAll";
-        break;
     case ReadMode::ReadFileStepByStep:
         return "ReadFileStepByStep";
-        break;
     case ReadMode::ReadFileStepByStepBlocks:
         return "ReadFileStepByStepBlocks";
-        break;
     case ReadMode::ReadStream:
         return "ReadStream";
-        break;
     case ReadMode::ReadStreamBlocks:
         return "ReadStreamBlocks";
-        break;
     }
     return "unknown";
 }
diff --git a/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp b/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp
index 0ae936097f..9bd7ade068 100644
--- a/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp
@@ -5,9 +5,13 @@
 #include <cstdint>
 #include <cstring>
 
+#include <array>
 #include <iostream>
+#include <limits>
 #include <sstream>
 #include <stdexcept>
+#include <string>
+#include <vector>
 
 #include <adios2.h>
 
@@ -60,16 +64,14 @@ enum class ReadMode
     ReadStreamBlocks
 };
 
-std::string ReadModeToString(ReadMode r)
+std::string ReadModeToString(const ReadMode r)
 {
     switch (r)
     {
     case ReadMode::ReadFileStepByStepBlocks:
         return "ReadFileStepByStepBlocks";
-        break;
     case ReadMode::ReadStreamBlocks:
         return "ReadStreamBlocks";
-        break;
     }
     return "unknown";
 }
@@ -177,10 +179,9 @@ TEST_P(BPStepsFileLocalArrayReaders, EveryStep)
                       << ArrayToString(d.data(), Nx) << std::endl;
             auto start = var_i32.Start();
             auto count = var_i32.Count();
-            /*EXPECT_EQ(start.size(), 1); -- start and count is actually {}
-            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(start.size(), 0);
             EXPECT_EQ(count.size(), 1);
-            EXPECT_EQ(count[0], 1 * Nx);*/
+            EXPECT_EQ(count[0], 1 * Nx);
             for (size_t i = 0; i < Nx; ++i)
             {
                 EXPECT_EQ(d[i], m_TestData[step][i]);
@@ -214,10 +215,9 @@ TEST_P(BPStepsFileLocalArrayReaders, EveryStep)
                       << ArrayToString(d.data(), Nx) << std::endl;
             auto start = var_i32.Start();
             auto count = var_i32.Count();
-            /*EXPECT_EQ(start.size(), 1); -- start and count is actually {}
-            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(start.size(), 0);
             EXPECT_EQ(count.size(), 1);
-            EXPECT_EQ(count[0], 1 * Nx);*/
+            EXPECT_EQ(count[0], 1 * Nx);
             for (size_t i = 0; i < Nx; ++i)
             {
                 EXPECT_EQ(d[i], m_TestData[step][i]);
@@ -333,10 +333,9 @@ TEST_P(BPStepsFileLocalArrayReaders, NewVarPerStep)
                       << ArrayToString(d.data(), Nx) << std::endl;
             auto start = var.Start();
             auto count = var.Count();
-            /*EXPECT_EQ(start.size(), 1); -- start and count is actually {}
-            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(start.size(), 0);
             EXPECT_EQ(count.size(), 1);
-            EXPECT_EQ(count[0], 1 * Nx);*/
+            EXPECT_EQ(count[0], 1 * Nx);
             for (size_t i = 0; i < Nx; ++i)
             {
                 EXPECT_EQ(d[i], m_TestData[step][i]);
@@ -370,10 +369,9 @@ TEST_P(BPStepsFileLocalArrayReaders, NewVarPerStep)
                       << ArrayToString(d.data(), Nx) << std::endl;
             auto start = var.Start();
             auto count = var.Count();
-            /*EXPECT_EQ(start.size(), 1); -- start and count is actually {}
-            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(start.size(), 0);
             EXPECT_EQ(count.size(), 1);
-            EXPECT_EQ(count[0], 1 * Nx);*/
+            EXPECT_EQ(count[0], 1 * Nx);
             for (size_t i = 0; i < Nx; ++i)
             {
                 EXPECT_EQ(d[i], m_TestData[step][i]);
@@ -421,9 +419,9 @@ TEST_P(BPStepsFileLocalArrayParameters, EveryOtherStep)
 #endif
 
     std::array<int32_t, Nx> m_TestData[NSteps / 2];
-    adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
-    adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
-    adios2::Dims count{static_cast<unsigned int>(Nx)};
+    adios2::Dims shape{};
+    adios2::Dims start{};
+    adios2::Dims count{Nx};
 
     std::string fname;
 #if ADIOS2_USE_MPI
@@ -514,8 +512,7 @@ TEST_P(BPStepsFileLocalArrayParameters, EveryOtherStep)
                       << std::endl;
             auto start = var_i32.Start();
             auto count = var_i32.Count();
-            EXPECT_EQ(start.size(), 1);
-            EXPECT_EQ(start[0], mpiRank * Nx);
+            EXPECT_EQ(start.size(), 0);
             EXPECT_EQ(count.size(), 1);
             EXPECT_EQ(count[0], 1 * Nx);
             for (size_t i = 0; i < Nx; ++i)
@@ -555,8 +552,7 @@ TEST_P(BPStepsFileLocalArrayParameters, EveryOtherStep)
                           << ArrayToString(d.data(), Nx) << std::endl;
                 auto start = var_i32.Start();
                 auto count = var_i32.Count();
-                EXPECT_EQ(start.size(), 1);
-                EXPECT_EQ(start[0], mpiRank * Nx);
+                EXPECT_EQ(start.size(), 0);
                 EXPECT_EQ(count.size(), 1);
                 EXPECT_EQ(count[0], 1 * Nx);
                 for (size_t i = 0; i < Nx; ++i)
diff --git a/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp b/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
new file mode 100644
index 0000000000..06f70b1b22
--- /dev/null
+++ b/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
@@ -0,0 +1,683 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ */
+#include <cstdint>
+#include <cstring>
+
+#include <array>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include <adios2.h>
+
+#include <gtest/gtest.h>
+
+std::string engineName; // comes from command line
+
+// Number of elements per process
+const std::size_t Nx = 10;
+using DataArray = std::array<int32_t, Nx>;
+
+class BPStepsInSituGlobalArray : public ::testing::Test
+{
+protected:
+    BPStepsInSituGlobalArray() = default;
+
+    const DataArray I32 = {
+        {512, 513, -510, 515, -508, 517, -506, 519, -504, 521}};
+
+    DataArray GenerateData(const int step, const int rank, const int size)
+    {
+        DataArray d;
+        int j = rank + 1 + step * size;
+        for (size_t i = 0; i < d.size(); ++i)
+        {
+            d[i] = I32[i] + j;
+        }
+        return d;
+    }
+
+    std::string ArrayToString(const int32_t *data, const size_t nelems)
+    {
+        std::stringstream ss;
+        ss << "[";
+        for (size_t i = 0; i < nelems; ++i)
+        {
+            ss << data[i];
+            if (i < nelems - 1)
+            {
+                ss << " ";
+            }
+        }
+        ss << "]";
+        return ss.str();
+    }
+};
+
+enum class ReadMode
+{
+    ReadGlobal,
+    ReadBlocks
+};
+
+std::string ReadModeToString(const ReadMode r)
+{
+    switch (r)
+    {
+    case ReadMode::ReadGlobal:
+        return "ReadGlobal";
+    case ReadMode::ReadBlocks:
+        return "ReadBlocks";
+    }
+    return "unknown";
+}
+
+enum class Act
+{
+    Write,
+    Read
+};
+
+const std::vector<std::vector<Act>> Schedules = {
+    {Act::Write, Act::Write, Act::Write, Act::Read, Act::Read, Act::Read},
+    {Act::Write, Act::Write, Act::Read, Act::Write, Act::Read, Act::Read},
+    {Act::Write, Act::Write, Act::Read, Act::Read, Act::Write, Act::Read},
+    {Act::Write, Act::Read, Act::Write, Act::Write, Act::Read, Act::Read},
+    {Act::Write, Act::Read, Act::Write, Act::Read, Act::Write, Act::Read}};
+
+std::string ScheduleToString(const std::vector<Act> &schedule)
+{
+    std::stringstream ss;
+    ss << "[";
+    for (int i = 0; i < schedule.size(); ++i)
+    {
+        if (schedule[i] == Act::Write)
+        {
+            ss << "Write";
+        }
+        else if (schedule[i] == Act::Read)
+        {
+            ss << "Read";
+        }
+        if (i < schedule.size() - 1)
+        {
+            ss << " ";
+        }
+    }
+    ss << "]";
+    return ss.str();
+}
+
+class BPStepsInSituGlobalArrayReaders
+: public BPStepsInSituGlobalArray,
+  public ::testing::WithParamInterface<std::tuple<size_t, ReadMode>>
+{
+protected:
+    const std::vector<Act> &GetSchedule()
+    {
+        return Schedules[std::get<0>(GetParam())];
+    };
+    ReadMode GetReadMode() { return std::get<1>(GetParam()); };
+    int GetScheduleID() { return std::get<0>(GetParam()); };
+};
+
+// Basic case: Variable written every step
+TEST_P(BPStepsInSituGlobalArrayReaders, EveryStep)
+{
+    const std::vector<Act> &schedule = GetSchedule();
+    const ReadMode readMode = GetReadMode();
+    const std::string fname_prefix = "BPStepsInSituGlobalArray.EveryStep." +
+                                     std::to_string(GetScheduleID()) + "." +
+                                     ReadModeToString(readMode);
+    int mpiRank = 0, mpiSize = 1;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::vector<DataArray> m_TestData;
+    adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
+    adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
+    adios2::Dims count{static_cast<unsigned int>(Nx)};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+#endif
+
+    if (!mpiRank)
+    {
+        std::cout << "Test with Schedule " << GetScheduleID() << " "
+                  << ScheduleToString(schedule) << " Read Mode "
+                  << ReadModeToString(readMode) << std::endl;
+    }
+
+    // Start writer
+    adios2::IO iow = adios.DeclareIO("Write");
+    if (!engineName.empty())
+    {
+        iow.SetEngine(engineName);
+    }
+    adios2::Engine writer = iow.Open(fname, adios2::Mode::Write);
+    EXPECT_TRUE(writer);
+    auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
+    EXPECT_TRUE(var_i32);
+
+    // Start reader
+    adios2::IO ior = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        ior.SetEngine(engineName);
+    }
+    adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(reader);
+
+    size_t stepsWritten = 0;
+    size_t stepsRead = 0;
+
+    for (const auto act : schedule)
+    {
+        if (act == Act::Write)
+        {
+            // Write test data using ADIOS2
+            if (!mpiRank)
+            {
+                std::cout << "Write step " << stepsWritten << std::endl;
+            }
+
+            // Generate test data for each process uniquely
+            m_TestData.push_back(GenerateData(stepsWritten, mpiRank, mpiSize));
+            std::cout << "Rank " << mpiRank << " write step " << stepsWritten
+                      << ": "
+                      << ArrayToString(m_TestData[stepsWritten].data(), Nx)
+                      << std::endl;
+            writer.BeginStep();
+            writer.Put(var_i32, m_TestData[stepsWritten].data());
+            writer.EndStep();
+            ++stepsWritten;
+        }
+        else if (act == Act::Read)
+        {
+            if (readMode == ReadMode::ReadGlobal)
+            {
+                /// Read back data with global selection
+                if (!mpiRank)
+                {
+                    std::cout << "Read step " << stepsRead
+                              << " with Global selection" << std::endl;
+                }
+
+                reader.BeginStep();
+                auto var_i32 = ior.InquireVariable<int32_t>("i32");
+                EXPECT_TRUE(var_i32);
+                // EXPECT_EQ(var_i32.Steps(), 1);
+                EXPECT_EQ(var_i32.StepsStart(), 0);
+                size_t start = static_cast<size_t>(mpiRank) * Nx;
+                var_i32.SetSelection({{start}, {Nx}});
+                DataArray d;
+                reader.Get(var_i32, d.data(), adios2::Mode::Sync);
+                std::cout << "Rank " << mpiRank << " read step " << stepsRead
+                          << ": " << ArrayToString(d.data(), Nx) << std::endl;
+                for (size_t i = 0; i < Nx; ++i)
+                {
+                    EXPECT_EQ(d[i], m_TestData[stepsRead][i]);
+                }
+                reader.EndStep();
+            }
+            else if (readMode == ReadMode::ReadBlocks)
+            {
+                /// Read back data with block selection
+                if (!mpiRank)
+                {
+                    std::cout << "Read step " << stepsRead
+                              << " with Block selection" << std::endl;
+                }
+
+                reader.BeginStep();
+                auto var_i32 = ior.InquireVariable<int32_t>("i32");
+                EXPECT_TRUE(var_i32);
+                // EXPECT_EQ(var_i32.Steps(), 1);
+                EXPECT_EQ(var_i32.StepsStart(), 0);
+                size_t blockID = static_cast<size_t>(mpiRank);
+                var_i32.SetBlockSelection(blockID);
+                DataArray d;
+                reader.Get(var_i32, d.data(), adios2::Mode::Sync);
+                std::cout << "Rank " << mpiRank << " read step " << stepsRead
+                          << " block " << blockID << ": "
+                          << ArrayToString(d.data(), Nx) << std::endl;
+                auto start = var_i32.Start();
+                auto count = var_i32.Count();
+                EXPECT_EQ(start[0], mpiRank * Nx);
+                EXPECT_EQ(count[0], 1 * Nx);
+                for (size_t i = 0; i < Nx; ++i)
+                {
+                    EXPECT_EQ(d[i], m_TestData[stepsRead][i]);
+                }
+                reader.EndStep();
+            }
+            ++stepsRead;
+        }
+#if ADIOS2_USE_MPI
+        std::flush(std::cout);
+        MPI_Barrier(MPI_COMM_WORLD);
+#endif
+    }
+    writer.Close();
+    reader.Close();
+}
+
+// A new variable is created and written every step
+TEST_P(BPStepsInSituGlobalArrayReaders, NewVarPerStep)
+{
+    const std::vector<Act> &schedule = GetSchedule();
+    const ReadMode readMode = GetReadMode();
+    const std::string fname_prefix = "BPStepsInSituGlobalArray.NewVarPerStep." +
+                                     std::to_string(GetScheduleID()) + "." +
+                                     ReadModeToString(readMode);
+    int mpiRank = 0, mpiSize = 1;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::vector<DataArray> m_TestData;
+    adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
+    adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
+    adios2::Dims count{static_cast<unsigned int>(Nx)};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+#endif
+
+    auto lf_VarName = [](int step) -> std::string {
+        return "i32_" + std::to_string(step);
+    };
+
+    std::cout << "Test with Schedule " << GetScheduleID() << " "
+              << ScheduleToString(schedule) << " Read Mode "
+              << ReadModeToString(readMode) << std::endl;
+
+    // Start writer
+    adios2::IO iow = adios.DeclareIO("Write");
+    if (!engineName.empty())
+    {
+        iow.SetEngine(engineName);
+    }
+    adios2::Engine writer = iow.Open(fname, adios2::Mode::Write);
+    EXPECT_TRUE(writer);
+    auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
+    EXPECT_TRUE(var_i32);
+
+    // Start reader
+    adios2::IO ior = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        ior.SetEngine(engineName);
+    }
+    adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(reader);
+
+    size_t stepsWritten = 0;
+    size_t stepsRead = 0;
+
+    for (const auto act : schedule)
+    {
+        if (act == Act::Write)
+        {
+            if (!mpiRank)
+            {
+                std::cout << "Write step " << stepsWritten << std::endl;
+            }
+
+            const std::string varName = lf_VarName(stepsWritten);
+            auto var =
+                iow.DefineVariable<int32_t>(varName, shape, start, count);
+            // Generate test data for each process uniquely
+            m_TestData.push_back(GenerateData(stepsWritten, mpiRank, mpiSize));
+            std::cout << "Rank " << mpiRank << " write step " << stepsWritten
+                      << " var " << varName << ": "
+                      << ArrayToString(m_TestData[stepsWritten].data(), Nx)
+                      << std::endl;
+            writer.BeginStep();
+            writer.Put(var, m_TestData[stepsWritten].data());
+            writer.EndStep();
+            ++stepsWritten;
+        }
+        else if (act == Act::Read)
+        {
+            if (readMode == ReadMode::ReadGlobal)
+            {
+                /// Read back data with global selection
+                if (!mpiRank)
+                {
+                    std::cout << "Read step " << stepsRead
+                              << " with Global selection" << std::endl;
+                }
+
+                reader.BeginStep();
+                const std::string varName = lf_VarName(stepsRead);
+                auto var = ior.InquireVariable<int32_t>(varName);
+                EXPECT_TRUE(var);
+                EXPECT_EQ(var.Steps(), 1);
+                EXPECT_EQ(var.StepsStart(), 0);
+                size_t start = static_cast<size_t>(mpiRank) * Nx;
+                var.SetSelection({{start}, {Nx}});
+                DataArray d;
+                reader.Get(var, d.data(), adios2::Mode::Sync);
+                std::cout << "Rank " << mpiRank << " read var " << varName
+                          << ": " << ArrayToString(d.data(), Nx) << std::endl;
+
+                for (size_t i = 0; i < Nx; ++i)
+                {
+                    EXPECT_EQ(d[i], m_TestData[stepsRead][i]);
+                }
+                reader.EndStep();
+            }
+            else if (readMode == ReadMode::ReadBlocks)
+            {
+                /// Read back data with block selection
+                if (!mpiRank)
+                {
+                    std::cout << "Read step " << stepsRead
+                              << " with Block selection" << std::endl;
+                }
+
+                reader.BeginStep();
+                const std::string varName = lf_VarName(stepsRead);
+                auto var = ior.InquireVariable<int32_t>(varName);
+                EXPECT_TRUE(var);
+                EXPECT_EQ(var.Steps(), 1);
+                EXPECT_EQ(var.StepsStart(), 0);
+                size_t blockID = static_cast<size_t>(mpiRank);
+                var.SetBlockSelection(blockID);
+                DataArray d;
+                reader.Get(var, d.data(), adios2::Mode::Sync);
+                std::cout << "Rank " << mpiRank << " read step " << stepsRead
+                          << " block " << blockID << ": "
+                          << ArrayToString(d.data(), Nx) << std::endl;
+                auto start = var.Start();
+                auto count = var.Count();
+                EXPECT_EQ(start[0], mpiRank * Nx);
+                EXPECT_EQ(count[0], 1 * Nx);
+                for (size_t i = 0; i < Nx; ++i)
+                {
+                    EXPECT_EQ(d[i], m_TestData[stepsRead][i]);
+                }
+                reader.EndStep();
+            }
+            ++stepsRead;
+        }
+#if ADIOS2_USE_MPI
+        std::flush(std::cout);
+        MPI_Barrier(MPI_COMM_WORLD);
+#endif
+    }
+    writer.Close();
+    reader.Close();
+}
+
+INSTANTIATE_TEST_CASE_P(
+    BPStepsInSituGlobalArray, BPStepsInSituGlobalArrayReaders,
+    ::testing::Values(std::make_tuple(0, ReadMode::ReadGlobal),
+                      std::make_tuple(1, ReadMode::ReadGlobal),
+                      std::make_tuple(2, ReadMode::ReadGlobal),
+                      std::make_tuple(3, ReadMode::ReadGlobal),
+                      std::make_tuple(4, ReadMode::ReadGlobal),
+                      std::make_tuple(0, ReadMode::ReadBlocks),
+                      std::make_tuple(1, ReadMode::ReadBlocks),
+                      std::make_tuple(2, ReadMode::ReadBlocks),
+                      std::make_tuple(3, ReadMode::ReadBlocks),
+                      std::make_tuple(4, ReadMode::ReadBlocks)));
+
+class BPStepsInSituGlobalArrayParameters
+: public BPStepsInSituGlobalArray,
+  public ::testing::WithParamInterface<std::tuple<size_t, size_t, ReadMode>>
+{
+protected:
+    const std::vector<Act> &GetSchedule()
+    {
+        return Schedules[std::get<0>(GetParam())];
+    };
+    size_t GetOddity() { return std::get<1>(GetParam()); };
+    ReadMode GetReadMode() { return std::get<2>(GetParam()); };
+    int GetScheduleID() { return std::get<0>(GetParam()); };
+};
+
+// A variable written every other step either from step 0 (EVEN) or from
+// step 1 (ODD)
+TEST_P(BPStepsInSituGlobalArrayParameters, EveryOtherStep)
+{
+    const std::vector<Act> &schedule = GetSchedule();
+    const std::size_t Oddity = GetOddity();
+    const ReadMode readMode = GetReadMode();
+    const std::string fname_prefix =
+        "BPStepsInSituGlobalArray.EveryOtherStep.Schedule" +
+        std::to_string(GetScheduleID()) + ".Oddity" + std::to_string(Oddity) +
+        "." + ReadModeToString(readMode);
+    int mpiRank = 0, mpiSize = 1;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::vector<DataArray> m_TestData;
+    adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
+    adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
+    adios2::Dims count{static_cast<unsigned int>(Nx)};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+
+#endif
+
+    if (!mpiRank)
+    {
+        std::cout << "Test with Schedule " << GetScheduleID() << " "
+                  << ScheduleToString(schedule) << " Oddity " << Oddity
+                  << " Read Mode " << ReadModeToString(readMode) << std::endl;
+    }
+
+    // Start writer
+    adios2::IO iow = adios.DeclareIO("Write");
+    if (!engineName.empty())
+    {
+        iow.SetEngine(engineName);
+    }
+    adios2::Engine writer = iow.Open(fname, adios2::Mode::Write);
+    EXPECT_TRUE(writer);
+    auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
+    EXPECT_TRUE(var_i32);
+    auto var_step = iow.DefineVariable<size_t>("step");
+    EXPECT_TRUE(var_step);
+
+    // Start reader
+    adios2::IO ior = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        ior.SetEngine(engineName);
+    }
+    adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(reader);
+
+    size_t stepsWritten = 0;
+    size_t stepsRead = 0;
+    size_t varStepsWritten = 0;
+    size_t varStepsRead = 0;
+    for (const auto act : schedule)
+    {
+        if (act == Act::Write)
+        {
+            if (!mpiRank)
+            {
+                std::cout << "Write step " << stepsWritten << std::endl;
+            }
+
+            // Generate test data for each process uniquely
+            writer.BeginStep();
+            writer.Put(var_step, stepsWritten);
+            if (stepsWritten % 2 == Oddity)
+            {
+                m_TestData.push_back(
+                    GenerateData(stepsWritten, mpiRank, mpiSize));
+                std::cout << "Rank " << mpiRank << " at step " << stepsWritten
+                          << " write var-step " << varStepsWritten << ": "
+                          << ArrayToString(m_TestData[varStepsWritten].data(),
+                                           Nx)
+                          << std::endl;
+                writer.Put(var_i32, m_TestData[varStepsWritten].data());
+                ++varStepsWritten;
+            }
+            writer.EndStep();
+            ++stepsWritten;
+        }
+        else if (act == Act::Read)
+        {
+
+            if (readMode == ReadMode::ReadGlobal)
+            {
+                /// Read back data with global selection
+                if (!mpiRank)
+                {
+                    std::cout << "Read step " << stepsRead
+                              << " with Global selection" << std::endl;
+                }
+
+                reader.BeginStep();
+                if (stepsRead % 2 == Oddity)
+                {
+                    auto var_i32 = ior.InquireVariable<int32_t>("i32");
+                    EXPECT_TRUE(var_i32);
+                    // EXPECT_EQ(var_i32.Steps(), 1);
+                    EXPECT_EQ(var_i32.StepsStart(), 0);
+                    size_t start = static_cast<size_t>(mpiRank) * Nx;
+                    var_i32.SetSelection({{start}, {Nx}});
+                    DataArray d;
+                    reader.Get(var_i32, d.data(), adios2::Mode::Sync);
+                    std::cout << "Rank " << mpiRank << " read at step "
+                              << stepsRead << " var-step " << varStepsRead
+                              << ": " << ArrayToString(d.data(), Nx)
+                              << std::endl;
+
+                    for (size_t i = 0; i < Nx; ++i)
+                    {
+                        EXPECT_EQ(d[i], m_TestData[varStepsRead][i]);
+                    }
+                    ++varStepsRead;
+                }
+                reader.EndStep();
+            }
+            else if (readMode == ReadMode::ReadBlocks)
+            {
+                /// Read back data with block selection
+                if (!mpiRank)
+                {
+                    std::cout << "Read step " << stepsRead
+                              << " with Block selection" << std::endl;
+                }
+                reader.BeginStep();
+                if (stepsRead % 2 == Oddity)
+                {
+                    auto var_i32 = ior.InquireVariable<int32_t>("i32");
+                    EXPECT_TRUE(var_i32);
+                    // EXPECT_EQ(var_i32.Steps(), 1);
+                    EXPECT_EQ(var_i32.StepsStart(), 0);
+                    size_t blockID = static_cast<size_t>(mpiRank);
+                    var_i32.SetBlockSelection(blockID);
+                    DataArray d;
+                    reader.Get(var_i32, d.data(), adios2::Mode::Sync);
+                    std::cout << "Rank " << mpiRank << " read at step "
+                              << stepsRead << " var-step " << varStepsRead
+                              << " block " << blockID << ": "
+                              << ArrayToString(d.data(), Nx) << std::endl;
+                    auto start = var_i32.Start();
+                    auto count = var_i32.Count();
+                    EXPECT_EQ(start[0], mpiRank * Nx);
+                    EXPECT_EQ(count[0], 1 * Nx);
+                    for (size_t i = 0; i < Nx; ++i)
+                    {
+                        EXPECT_EQ(d[i], m_TestData[varStepsRead][i]);
+                    }
+                    ++varStepsRead;
+                }
+                reader.EndStep();
+            }
+            ++stepsRead;
+        }
+
+#if ADIOS2_USE_MPI
+        std::flush(std::cout);
+        MPI_Barrier(MPI_COMM_WORLD);
+#endif
+    }
+    writer.Close();
+    reader.Close();
+}
+
+INSTANTIATE_TEST_CASE_P(
+    BPStepsInSituGlobalArray, BPStepsInSituGlobalArrayParameters,
+    ::testing::Values(std::make_tuple(0, 0, ReadMode::ReadGlobal),
+                      std::make_tuple(0, 0, ReadMode::ReadBlocks),
+                      std::make_tuple(0, 1, ReadMode::ReadGlobal),
+                      std::make_tuple(0, 1, ReadMode::ReadBlocks),
+                      std::make_tuple(1, 0, ReadMode::ReadGlobal),
+                      std::make_tuple(1, 0, ReadMode::ReadBlocks),
+                      std::make_tuple(1, 1, ReadMode::ReadGlobal),
+                      std::make_tuple(1, 1, ReadMode::ReadBlocks),
+                      std::make_tuple(2, 0, ReadMode::ReadGlobal),
+                      std::make_tuple(2, 0, ReadMode::ReadBlocks),
+                      std::make_tuple(2, 1, ReadMode::ReadGlobal),
+                      std::make_tuple(2, 1, ReadMode::ReadBlocks),
+                      std::make_tuple(3, 0, ReadMode::ReadGlobal),
+                      std::make_tuple(3, 0, ReadMode::ReadBlocks),
+                      std::make_tuple(3, 1, ReadMode::ReadGlobal),
+                      std::make_tuple(3, 1, ReadMode::ReadBlocks),
+                      std::make_tuple(4, 0, ReadMode::ReadGlobal),
+                      std::make_tuple(4, 0, ReadMode::ReadBlocks),
+                      std::make_tuple(4, 1, ReadMode::ReadGlobal),
+                      std::make_tuple(4, 1, ReadMode::ReadBlocks)));
+//******************************************************************************
+// main
+//******************************************************************************
+
+int main(int argc, char **argv)
+{
+#if ADIOS2_USE_MPI
+    MPI_Init(nullptr, nullptr);
+#endif
+
+    int result;
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (argc > 1)
+    {
+        engineName = std::string(argv[1]);
+    }
+    result = RUN_ALL_TESTS();
+
+#if ADIOS2_USE_MPI
+    MPI_Finalize();
+#endif
+
+    return result;
+}
diff --git a/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp b/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
new file mode 100644
index 0000000000..93bc2ea980
--- /dev/null
+++ b/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
@@ -0,0 +1,535 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ */
+#include <cstdint>
+#include <cstring>
+
+#include <array>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include <adios2.h>
+
+#include <gtest/gtest.h>
+
+std::string engineName; // comes from command line
+
+// Number of elements per process
+const std::size_t Nx = 10;
+using DataArray = std::array<int32_t, Nx>;
+
+class BPStepsInSituLocalArray : public ::testing::Test
+{
+protected:
+    BPStepsInSituLocalArray() = default;
+
+    const DataArray I32 = {
+        {512, 513, -510, 515, -508, 517, -506, 519, -504, 521}};
+
+    DataArray GenerateData(const int step, const int rank, const int size)
+    {
+        DataArray d;
+        int j = rank + 1 + step * size;
+        for (size_t i = 0; i < d.size(); ++i)
+        {
+            d[i] = I32[i] + j;
+        }
+        return d;
+    }
+
+    std::string ArrayToString(const int32_t *data, const size_t nelems)
+    {
+        std::stringstream ss;
+        ss << "[";
+        for (size_t i = 0; i < nelems; ++i)
+        {
+            ss << data[i];
+            if (i < nelems - 1)
+            {
+                ss << " ";
+            }
+        }
+        ss << "]";
+        return ss.str();
+    }
+};
+
+enum class Act
+{
+    Write,
+    Read
+};
+
+const std::vector<std::vector<Act>> Schedules = {
+    {Act::Write, Act::Write, Act::Write, Act::Read, Act::Read, Act::Read},
+    {Act::Write, Act::Write, Act::Read, Act::Write, Act::Read, Act::Read},
+    {Act::Write, Act::Write, Act::Read, Act::Read, Act::Write, Act::Read},
+    {Act::Write, Act::Read, Act::Write, Act::Write, Act::Read, Act::Read},
+    {Act::Write, Act::Read, Act::Write, Act::Read, Act::Write, Act::Read}};
+
+std::string ScheduleToString(const std::vector<Act> &schedule)
+{
+    std::stringstream ss;
+    ss << "[";
+    for (int i = 0; i < schedule.size(); ++i)
+    {
+        if (schedule[i] == Act::Write)
+        {
+            ss << "Write";
+        }
+        else if (schedule[i] == Act::Read)
+        {
+            ss << "Read";
+        }
+        if (i < schedule.size() - 1)
+        {
+            ss << " ";
+        }
+    }
+    ss << "]";
+    return ss.str();
+}
+
+class BPStepsInSituLocalArrayReaders
+: public BPStepsInSituLocalArray,
+  public ::testing::WithParamInterface<size_t>
+{
+protected:
+    const std::vector<Act> &GetSchedule() { return Schedules[GetParam()]; };
+    int GetScheduleID() { return GetParam(); };
+};
+
+// Basic case: Variable written every step
+TEST_P(BPStepsInSituLocalArrayReaders, EveryStep)
+{
+    const std::vector<Act> &schedule = GetSchedule();
+    const std::string fname_prefix =
+        "BPStepsInSituLocalArray.EveryStep." + std::to_string(GetScheduleID());
+    int mpiRank = 0, mpiSize = 1;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::vector<DataArray> m_TestData;
+    adios2::Dims shape{};
+    adios2::Dims start{};
+    adios2::Dims count{Nx};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+#endif
+    if (!mpiRank)
+    {
+        std::cout << "Test with Schedule " << GetScheduleID() << " "
+                  << ScheduleToString(schedule) << std::endl;
+    }
+
+    // Start writer
+    adios2::IO iow = adios.DeclareIO("Write");
+    if (!engineName.empty())
+    {
+        iow.SetEngine(engineName);
+    }
+    adios2::Engine writer = iow.Open(fname, adios2::Mode::Write);
+    EXPECT_TRUE(writer);
+    auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
+    EXPECT_TRUE(var_i32);
+
+    // Start reader
+    adios2::IO ior = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        ior.SetEngine(engineName);
+    }
+    adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(reader);
+
+    size_t stepsWritten = 0;
+    size_t stepsRead = 0;
+
+    for (const auto act : schedule)
+    {
+        if (act == Act::Write)
+        {
+            // Write test data using ADIOS2
+            if (!mpiRank)
+            {
+                std::cout << "Write step " << stepsWritten << std::endl;
+            }
+
+            // Generate test data for each process uniquely
+            m_TestData.push_back(GenerateData(stepsWritten, mpiRank, mpiSize));
+            std::cout << "Rank " << mpiRank << " write step " << stepsWritten
+                      << ": "
+                      << ArrayToString(m_TestData[stepsWritten].data(), Nx)
+                      << std::endl;
+            writer.BeginStep();
+            writer.Put(var_i32, m_TestData[stepsWritten].data());
+            writer.EndStep();
+            ++stepsWritten;
+        }
+        else if (act == Act::Read)
+        {
+            /// Read back data with block selection
+            if (!mpiRank)
+            {
+                std::cout << "Read step " << stepsRead
+                          << " with Block selection" << std::endl;
+            }
+
+            reader.BeginStep();
+            auto var_i32 = ior.InquireVariable<int32_t>("i32");
+            EXPECT_TRUE(var_i32);
+            // EXPECT_EQ(var_i32.Steps(), 1);
+            EXPECT_EQ(var_i32.StepsStart(), 0);
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var_i32.SetBlockSelection(blockID);
+            DataArray d;
+            reader.Get(var_i32, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << stepsRead
+                      << " block " << blockID << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            auto start = var_i32.Start();
+            auto count = var_i32.Count();
+            EXPECT_EQ(start.size(), 0);
+            EXPECT_EQ(count.size(), 1);
+            EXPECT_EQ(count[0], 1 * Nx);
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[stepsRead][i]);
+            }
+            reader.EndStep();
+            ++stepsRead;
+        }
+#if ADIOS2_USE_MPI
+        std::flush(std::cout);
+        MPI_Barrier(MPI_COMM_WORLD);
+#endif
+    }
+    writer.Close();
+    reader.Close();
+}
+
+// A new variable is created and written every step
+TEST_P(BPStepsInSituLocalArrayReaders, NewVarPerStep)
+{
+    const std::vector<Act> &schedule = GetSchedule();
+    const std::string fname_prefix = "BPStepsInSituLocalArray.NewVarPerStep." +
+                                     std::to_string(GetScheduleID());
+    int mpiRank = 0, mpiSize = 1;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::vector<DataArray> m_TestData;
+    adios2::Dims shape{};
+    adios2::Dims start{};
+    adios2::Dims count{Nx};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+#endif
+
+    auto lf_VarName = [](int step) -> std::string {
+        return "i32_" + std::to_string(step);
+    };
+
+    if (!mpiRank)
+    {
+        std::cout << "Test with Schedule " << GetScheduleID() << " "
+                  << ScheduleToString(schedule) << std::endl;
+    }
+
+    // Start writer
+    adios2::IO iow = adios.DeclareIO("Write");
+    if (!engineName.empty())
+    {
+        iow.SetEngine(engineName);
+    }
+    adios2::Engine writer = iow.Open(fname, adios2::Mode::Write);
+    EXPECT_TRUE(writer);
+    auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
+    EXPECT_TRUE(var_i32);
+
+    // Start reader
+    adios2::IO ior = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        ior.SetEngine(engineName);
+    }
+    adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(reader);
+
+    size_t stepsWritten = 0;
+    size_t stepsRead = 0;
+
+    for (const auto act : schedule)
+    {
+        if (act == Act::Write)
+        {
+            if (!mpiRank)
+            {
+                std::cout << "Write step " << stepsWritten << std::endl;
+            }
+
+            const std::string varName = lf_VarName(stepsWritten);
+            auto var =
+                iow.DefineVariable<int32_t>(varName, shape, start, count);
+            // Generate test data for each process uniquely
+            m_TestData.push_back(GenerateData(stepsWritten, mpiRank, mpiSize));
+            std::cout << "Rank " << mpiRank << " write step " << stepsWritten
+                      << " var " << varName << ": "
+                      << ArrayToString(m_TestData[stepsWritten].data(), Nx)
+                      << std::endl;
+            writer.BeginStep();
+            writer.Put(var, m_TestData[stepsWritten].data());
+            writer.EndStep();
+            ++stepsWritten;
+        }
+        else if (act == Act::Read)
+        {
+            /// Read back data with block selection
+            if (!mpiRank)
+            {
+                std::cout << "Read step " << stepsRead
+                          << " with Block selection" << std::endl;
+            }
+
+            reader.BeginStep();
+            const std::string varName = lf_VarName(stepsRead);
+            auto var = ior.InquireVariable<int32_t>(varName);
+            EXPECT_TRUE(var);
+            EXPECT_EQ(var.Steps(), 1);
+            EXPECT_EQ(var.StepsStart(), 0);
+            size_t blockID = static_cast<size_t>(mpiRank);
+            var.SetBlockSelection(blockID);
+            DataArray d;
+            reader.Get(var, d.data(), adios2::Mode::Sync);
+            std::cout << "Rank " << mpiRank << " read step " << stepsRead
+                      << " block " << blockID << ": "
+                      << ArrayToString(d.data(), Nx) << std::endl;
+            auto start = var.Start();
+            auto count = var.Count();
+            EXPECT_EQ(start.size(), 0);
+            EXPECT_EQ(count.size(), 1);
+            EXPECT_EQ(count[0], 1 * Nx);
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                EXPECT_EQ(d[i], m_TestData[stepsRead][i]);
+            }
+            reader.EndStep();
+            ++stepsRead;
+        }
+#if ADIOS2_USE_MPI
+        std::flush(std::cout);
+        MPI_Barrier(MPI_COMM_WORLD);
+#endif
+    }
+    writer.Close();
+    reader.Close();
+}
+
+INSTANTIATE_TEST_CASE_P(BPStepsInSituLocalArray, BPStepsInSituLocalArrayReaders,
+                        ::testing::Values(0, 1, 2, 3, 4));
+
+class BPStepsInSituLocalArrayParameters
+: public BPStepsInSituLocalArray,
+  public ::testing::WithParamInterface<std::tuple<size_t, size_t>>
+{
+protected:
+    const std::vector<Act> &GetSchedule()
+    {
+        return Schedules[std::get<0>(GetParam())];
+    };
+    size_t GetOddity() { return std::get<1>(GetParam()); };
+    int GetScheduleID() { return std::get<0>(GetParam()); };
+};
+
+// A variable written every other step either from step 0 (EVEN) or from
+// step 1 (ODD)
+TEST_P(BPStepsInSituLocalArrayParameters, EveryOtherStep)
+{
+    const std::vector<Act> &schedule = GetSchedule();
+    const std::size_t Oddity = GetOddity();
+    const std::string fname_prefix =
+        "BPStepsInSituLocalArray.EveryOtherStep.Schedule" +
+        std::to_string(GetScheduleID()) + ".Oddity" + std::to_string(Oddity);
+    int mpiRank = 0, mpiSize = 1;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    std::vector<DataArray> m_TestData;
+    adios2::Dims shape{};
+    adios2::Dims start{};
+    adios2::Dims count{Nx};
+
+    std::string fname;
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    fname = fname_prefix + ".MPI.bp";
+#else
+    adios2::ADIOS adios;
+    fname = fname_prefix + ".Serial.bp";
+
+#endif
+
+    if (!mpiRank)
+    {
+        std::cout << "Test with Schedule " << GetScheduleID() << " "
+                  << ScheduleToString(schedule) << " Oddity " << Oddity
+                  << std::endl;
+    }
+
+    // Start writer
+    adios2::IO iow = adios.DeclareIO("Write");
+    if (!engineName.empty())
+    {
+        iow.SetEngine(engineName);
+    }
+    adios2::Engine writer = iow.Open(fname, adios2::Mode::Write);
+    EXPECT_TRUE(writer);
+    auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
+    EXPECT_TRUE(var_i32);
+    auto var_step = iow.DefineVariable<size_t>("step");
+    EXPECT_TRUE(var_step);
+
+    // Start reader
+    adios2::IO ior = adios.DeclareIO("Read");
+    if (!engineName.empty())
+    {
+        ior.SetEngine(engineName);
+    }
+    adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
+    EXPECT_TRUE(reader);
+
+    size_t stepsWritten = 0;
+    size_t stepsRead = 0;
+    size_t varStepsWritten = 0;
+    size_t varStepsRead = 0;
+    for (const auto act : schedule)
+    {
+        if (act == Act::Write)
+        {
+            if (!mpiRank)
+            {
+                std::cout << "Write step " << stepsWritten << std::endl;
+            }
+
+            // Generate test data for each process uniquely
+            writer.BeginStep();
+            writer.Put(var_step, stepsWritten);
+            if (stepsWritten % 2 == Oddity)
+            {
+                m_TestData.push_back(
+                    GenerateData(stepsWritten, mpiRank, mpiSize));
+                std::cout << "Rank " << mpiRank << " at step " << stepsWritten
+                          << " write var-step " << varStepsWritten << ": "
+                          << ArrayToString(m_TestData[varStepsWritten].data(),
+                                           Nx)
+                          << std::endl;
+                writer.Put(var_i32, m_TestData[varStepsWritten].data());
+                ++varStepsWritten;
+            }
+            writer.EndStep();
+            ++stepsWritten;
+        }
+        else if (act == Act::Read)
+        {
+            /// Read back data with block selection
+            if (!mpiRank)
+            {
+                std::cout << "Read step " << stepsRead
+                          << " with Block selection" << std::endl;
+            }
+            reader.BeginStep();
+            if (stepsRead % 2 == Oddity)
+            {
+                auto var_i32 = ior.InquireVariable<int32_t>("i32");
+                EXPECT_TRUE(var_i32);
+                // EXPECT_EQ(var_i32.Steps(), 1);
+                EXPECT_EQ(var_i32.StepsStart(), 0);
+                size_t blockID = static_cast<size_t>(mpiRank);
+                var_i32.SetBlockSelection(blockID);
+                DataArray d;
+                reader.Get(var_i32, d.data(), adios2::Mode::Sync);
+                std::cout << "Rank " << mpiRank << " read at step " << stepsRead
+                          << " var-step " << varStepsRead << " block "
+                          << blockID << ": " << ArrayToString(d.data(), Nx)
+                          << std::endl;
+                auto start = var_i32.Start();
+                auto count = var_i32.Count();
+                EXPECT_EQ(start.size(), 0);
+                EXPECT_EQ(count.size(), 1);
+                EXPECT_EQ(count[0], 1 * Nx);
+                for (size_t i = 0; i < Nx; ++i)
+                {
+                    EXPECT_EQ(d[i], m_TestData[varStepsRead][i]);
+                }
+                ++varStepsRead;
+            }
+            reader.EndStep();
+            ++stepsRead;
+        }
+
+#if ADIOS2_USE_MPI
+        std::flush(std::cout);
+        MPI_Barrier(MPI_COMM_WORLD);
+#endif
+    }
+    writer.Close();
+    reader.Close();
+}
+
+INSTANTIATE_TEST_CASE_P(
+    BPStepsInSituLocalArray, BPStepsInSituLocalArrayParameters,
+    ::testing::Values(std::make_tuple(0, 0), std::make_tuple(0, 1),
+                      std::make_tuple(1, 0), std::make_tuple(1, 1),
+                      std::make_tuple(2, 0), std::make_tuple(2, 1),
+                      std::make_tuple(3, 0), std::make_tuple(3, 1),
+                      std::make_tuple(4, 0), std::make_tuple(4, 1)));
+//******************************************************************************
+// main
+//******************************************************************************
+
+int main(int argc, char **argv)
+{
+#if ADIOS2_USE_MPI
+    MPI_Init(nullptr, nullptr);
+#endif
+
+    int result;
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (argc > 1)
+    {
+        engineName = std::string(argv[1]);
+    }
+    result = RUN_ALL_TESTS();
+
+#if ADIOS2_USE_MPI
+    MPI_Finalize();
+#endif
+
+    return result;
+}

From b1922c9ab5a0e51d8dfb55213fbaa00f8a0adc26 Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Thu, 25 Jun 2020 09:14:20 -0400
Subject: [PATCH 03/10] fix windows complaints, synchronize processes between
 file create and open for read, remove insitu test for BP3 which does not
 support insitu

---
 testing/adios2/engine/bp/CMakeLists.txt       |  8 +++-
 .../engine/bp/TestBPStepsFileGlobalArray.cpp  | 47 ++++++++++---------
 .../engine/bp/TestBPStepsFileLocalArray.cpp   | 33 ++++++-------
 .../bp/TestBPStepsInSituGlobalArray.cpp       | 16 ++++++-
 .../engine/bp/TestBPStepsInSituLocalArray.cpp | 16 ++++++-
 5 files changed, 75 insertions(+), 45 deletions(-)

diff --git a/testing/adios2/engine/bp/CMakeLists.txt b/testing/adios2/engine/bp/CMakeLists.txt
index 0216f10137..60ed8f65a4 100644
--- a/testing/adios2/engine/bp/CMakeLists.txt
+++ b/testing/adios2/engine/bp/CMakeLists.txt
@@ -43,8 +43,6 @@ bp3_bp4_gtest_add_tests_helper(TimeAggregation MPI_ALLOW)
 bp3_bp4_gtest_add_tests_helper(NoXMLRecovery MPI_ALLOW)
 bp3_bp4_gtest_add_tests_helper(StepsFileGlobalArray MPI_ALLOW)
 bp3_bp4_gtest_add_tests_helper(StepsFileLocalArray MPI_ALLOW)
-bp3_bp4_gtest_add_tests_helper(StepsInSituGlobalArray MPI_ALLOW)
-bp3_bp4_gtest_add_tests_helper(StepsInSituLocalArray MPI_ALLOW)
 
 if(NOT MSVC)
   bp3_bp4_gtest_add_tests_helper(BufferSize MPI_NONE)
@@ -63,4 +61,10 @@ gtest_add_tests_helper(WriteNull MPI_ALLOW BP Engine.BP. .BP3
 gtest_add_tests_helper(WriteAppendReadADIOS2 MPI_ALLOW BP Engine.BP. .BP4
   WORKING_DIRECTORY ${BP4_DIR} EXTRA_ARGS "BP4"
 )
+gtest_add_tests_helper(StepsInSituGlobalArray MPI_ALLOW BP Engine.BP. .BP4
+  WORKING_DIRECTORY ${BP4_DIR} EXTRA_ARGS "BP4"
+)
+gtest_add_tests_helper(StepsInSituLocalArray MPI_ALLOW BP Engine.BP. .BP4
+  WORKING_DIRECTORY ${BP4_DIR} EXTRA_ARGS "BP4"
+)
 
diff --git a/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp b/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
index 2357abebb9..b69e208256 100644
--- a/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
@@ -18,20 +18,21 @@
 
 std::string engineName; // comes from command line
 
+// Number of elements per process
+const std::size_t Nx = 10;
+using DataArray = std::array<int32_t, Nx>;
+
 class BPStepsFileGlobalArray : public ::testing::Test
 {
 protected:
     BPStepsFileGlobalArray() = default;
 
-    // Number of elements per process
-    static const std::size_t Nx = 10;
-
-    const std::array<int32_t, Nx> I32 = {
+    const DataArray I32 = {
         {512, 513, -510, 515, -508, 517, -506, 519, -504, 521}};
 
-    std::array<int32_t, Nx> GenerateData(int step, int rank, int size)
+    DataArray GenerateData(int step, int rank, int size)
     {
-        std::array<int32_t, Nx> d;
+        DataArray d;
         int j = rank + 1 + step * size;
         for (size_t i = 0; i < d.size(); ++i)
         {
@@ -106,7 +107,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, EveryStep)
     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
 #endif
 
-    std::array<int32_t, Nx> m_TestData[NSteps];
+    DataArray m_TestData[NSteps];
     adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
     adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
     adios2::Dims count{static_cast<unsigned int>(Nx)};
@@ -210,7 +211,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, EveryStep)
             var_i32.SetStepSelection({step, 1});
             size_t start = static_cast<size_t>(mpiRank) * Nx;
             var_i32.SetSelection({{start}, {Nx}});
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var_i32, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << step << ": "
                       << ArrayToString(d.data(), Nx) << std::endl;
@@ -240,7 +241,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, EveryStep)
             var_i32.SetStepSelection({step, 1});
             size_t blockID = static_cast<size_t>(mpiRank);
             var_i32.SetBlockSelection(blockID);
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var_i32, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << step
                       << " block " << blockID << ": "
@@ -274,7 +275,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, EveryStep)
             EXPECT_EQ(var_i32.StepsStart(), 0);
             size_t start = static_cast<size_t>(mpiRank) * Nx;
             var_i32.SetSelection({{start}, {Nx}});
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var_i32, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << step << ": "
                       << ArrayToString(d.data(), Nx) << std::endl;
@@ -305,7 +306,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, EveryStep)
             EXPECT_EQ(var_i32.StepsStart(), 0);
             size_t blockID = static_cast<size_t>(mpiRank);
             var_i32.SetBlockSelection(blockID);
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var_i32, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << step
                       << " block " << blockID << ": "
@@ -341,7 +342,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, NewVarPerStep)
     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
 #endif
 
-    std::array<int32_t, Nx> m_TestData[NSteps];
+    DataArray m_TestData[NSteps];
     adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
     adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
     adios2::Dims count{static_cast<unsigned int>(Nx)};
@@ -421,7 +422,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, NewVarPerStep)
             var.SetStepSelection({0, 1});
             size_t start = static_cast<size_t>(mpiRank) * Nx;
             var.SetSelection({{start}, {Nx}});
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read var " << varName << ": "
                       << ArrayToString(d.data(), Nx) << std::endl;
@@ -452,7 +453,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, NewVarPerStep)
             EXPECT_EQ(var.StepsStart(), 0);
             size_t start = static_cast<size_t>(mpiRank) * Nx;
             var.SetSelection({{start}, {Nx}});
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read var " << varName << ": "
                       << ArrayToString(d.data(), Nx) << std::endl;
@@ -485,7 +486,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, NewVarPerStep)
             var.SetStepSelection({0, 1});
             size_t blockID = static_cast<size_t>(mpiRank);
             var.SetBlockSelection(blockID);
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << step
                       << " block " << blockID << ": "
@@ -519,7 +520,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, NewVarPerStep)
             EXPECT_EQ(var.StepsStart(), 0);
             size_t start = static_cast<size_t>(mpiRank) * Nx;
             var.SetSelection({{start}, {Nx}});
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read var " << varName << ": "
                       << ArrayToString(d.data(), Nx) << std::endl;
@@ -554,7 +555,7 @@ TEST_P(BPStepsFileGlobalArrayReaders, NewVarPerStep)
             EXPECT_EQ(var.StepsStart(), 0);
             size_t blockID = static_cast<size_t>(mpiRank);
             var.SetBlockSelection(blockID);
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << step
                       << " block " << blockID << ": "
@@ -612,7 +613,7 @@ TEST_P(BPStepsFileGlobalArrayParameters, EveryOtherStep)
     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
 #endif
 
-    std::array<int32_t, Nx> m_TestData[NSteps / 2];
+    std::vector<DataArray> m_TestData;
     adios2::Dims shape{static_cast<unsigned int>(mpiSize * Nx)};
     adios2::Dims start{static_cast<unsigned int>(mpiRank * Nx)};
     adios2::Dims count{static_cast<unsigned int>(Nx)};
@@ -654,7 +655,7 @@ TEST_P(BPStepsFileGlobalArrayParameters, EveryOtherStep)
             engine.Put(var_step, step);
             if (step % 2 == Oddity)
             {
-                m_TestData[stepsWritten] = GenerateData(step, mpiRank, mpiSize);
+                m_TestData.push_back(GenerateData(step, mpiRank, mpiSize));
                 std::cout << "Rank " << mpiRank << " write step " << step
                           << ": "
                           << ArrayToString(m_TestData[stepsWritten].data(), Nx)
@@ -730,7 +731,7 @@ TEST_P(BPStepsFileGlobalArrayParameters, EveryOtherStep)
             var_i32.SetStepSelection({s, 1});
             size_t start = static_cast<size_t>(mpiRank) * Nx;
             var_i32.SetSelection({{start}, {Nx}});
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var_i32, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << s << ": "
                       << ArrayToString(d.data(), Nx) << std::endl;
@@ -762,7 +763,7 @@ TEST_P(BPStepsFileGlobalArrayParameters, EveryOtherStep)
             var_i32.SetStepSelection({s, 1});
             size_t blockID = static_cast<size_t>(mpiRank);
             var_i32.SetBlockSelection(blockID);
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var_i32, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << s << " block "
                       << blockID << ": " << ArrayToString(d.data(), Nx)
@@ -800,7 +801,7 @@ TEST_P(BPStepsFileGlobalArrayParameters, EveryOtherStep)
                 EXPECT_EQ(var_i32.StepsStart(), 0);
                 size_t start = static_cast<size_t>(mpiRank) * Nx;
                 var_i32.SetSelection({{start}, {Nx}});
-                std::array<int32_t, Nx> d;
+                DataArray d;
                 engine.Get(var_i32, d.data(), adios2::Mode::Sync);
                 std::cout << "Rank " << mpiRank << " read at step " << step
                           << ": " << ArrayToString(d.data(), Nx) << std::endl;
@@ -839,7 +840,7 @@ TEST_P(BPStepsFileGlobalArrayParameters, EveryOtherStep)
                 EXPECT_EQ(var_i32.StepsStart(), 0);
                 size_t blockID = static_cast<size_t>(mpiRank);
                 var_i32.SetBlockSelection(blockID);
-                std::array<int32_t, Nx> d;
+                DataArray d;
                 engine.Get(var_i32, d.data(), adios2::Mode::Sync);
                 std::cout << "Rank " << mpiRank << " read step " << step
                           << " block " << blockID << ": "
diff --git a/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp b/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp
index 9bd7ade068..e51f309b71 100644
--- a/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsFileLocalArray.cpp
@@ -19,20 +19,21 @@
 
 std::string engineName; // comes from command line
 
+// Number of elements per process
+const std::size_t Nx = 10;
+using DataArray = std::array<int32_t, Nx>;
+
 class BPStepsFileLocalArray : public ::testing::Test
 {
 protected:
     BPStepsFileLocalArray() = default;
 
-    // Number of elements per process
-    static const std::size_t Nx = 10;
-
-    const std::array<int32_t, Nx> I32 = {
+    const DataArray I32 = {
         {512, 513, -510, 515, -508, 517, -506, 519, -504, 521}};
 
-    std::array<int32_t, Nx> GenerateData(int step, int rank, int size)
+    DataArray GenerateData(int step, int rank, int size)
     {
-        std::array<int32_t, Nx> d;
+        DataArray d;
         int j = rank + 1 + step * size;
         for (size_t i = 0; i < d.size(); ++i)
         {
@@ -98,7 +99,7 @@ TEST_P(BPStepsFileLocalArrayReaders, EveryStep)
     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
 #endif
 
-    std::array<int32_t, Nx> m_TestData[NSteps];
+    DataArray m_TestData[NSteps];
     adios2::Dims shape{};
     adios2::Dims start{};
     adios2::Dims count{Nx};
@@ -172,7 +173,7 @@ TEST_P(BPStepsFileLocalArrayReaders, EveryStep)
             var_i32.SetStepSelection({step, 1});
             size_t blockID = static_cast<size_t>(mpiRank);
             var_i32.SetBlockSelection(blockID);
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var_i32, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << step
                       << " block " << blockID << ": "
@@ -208,7 +209,7 @@ TEST_P(BPStepsFileLocalArrayReaders, EveryStep)
             EXPECT_EQ(var_i32.StepsStart(), 0);
             size_t blockID = static_cast<size_t>(mpiRank);
             var_i32.SetBlockSelection(blockID);
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var_i32, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << step
                       << " block " << blockID << ": "
@@ -245,7 +246,7 @@ TEST_P(BPStepsFileLocalArrayReaders, NewVarPerStep)
     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
 #endif
 
-    std::array<int32_t, Nx> m_TestData[NSteps];
+    DataArray m_TestData[NSteps];
     adios2::Dims shape{};
     adios2::Dims start{};
     adios2::Dims count{Nx};
@@ -326,7 +327,7 @@ TEST_P(BPStepsFileLocalArrayReaders, NewVarPerStep)
             var.SetStepSelection({0, 1});
             size_t blockID = static_cast<size_t>(mpiRank);
             var.SetBlockSelection(blockID);
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << step
                       << " block " << blockID << ": "
@@ -362,7 +363,7 @@ TEST_P(BPStepsFileLocalArrayReaders, NewVarPerStep)
             EXPECT_EQ(var.StepsStart(), 0);
             size_t blockID = static_cast<size_t>(mpiRank);
             var.SetBlockSelection(blockID);
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << step
                       << " block " << blockID << ": "
@@ -418,7 +419,7 @@ TEST_P(BPStepsFileLocalArrayParameters, EveryOtherStep)
     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
 #endif
 
-    std::array<int32_t, Nx> m_TestData[NSteps / 2];
+    std::vector<DataArray> m_TestData;
     adios2::Dims shape{};
     adios2::Dims start{};
     adios2::Dims count{Nx};
@@ -460,7 +461,7 @@ TEST_P(BPStepsFileLocalArrayParameters, EveryOtherStep)
             engine.Put(var_step, step);
             if (step % 2 == Oddity)
             {
-                m_TestData[stepsWritten] = GenerateData(step, mpiRank, mpiSize);
+                m_TestData.push_back(GenerateData(step, mpiRank, mpiSize));
                 std::cout << "Rank " << mpiRank << " write step " << step
                           << ": "
                           << ArrayToString(m_TestData[stepsWritten].data(), Nx)
@@ -505,7 +506,7 @@ TEST_P(BPStepsFileLocalArrayParameters, EveryOtherStep)
             var_i32.SetStepSelection({s, 1});
             size_t blockID = static_cast<size_t>(mpiRank);
             var_i32.SetBlockSelection(blockID);
-            std::array<int32_t, Nx> d;
+            DataArray d;
             engine.Get(var_i32, d.data(), adios2::Mode::Sync);
             std::cout << "Rank " << mpiRank << " read step " << s << " block "
                       << blockID << ": " << ArrayToString(d.data(), Nx)
@@ -545,7 +546,7 @@ TEST_P(BPStepsFileLocalArrayParameters, EveryOtherStep)
                 EXPECT_EQ(var_i32.StepsStart(), 0);
                 size_t blockID = static_cast<size_t>(mpiRank);
                 var_i32.SetBlockSelection(blockID);
-                std::array<int32_t, Nx> d;
+                DataArray d;
                 engine.Get(var_i32, d.data(), adios2::Mode::Sync);
                 std::cout << "Rank " << mpiRank << " read step " << step
                           << " block " << blockID << ": "
diff --git a/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp b/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
index 06f70b1b22..f9bf05be02 100644
--- a/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
@@ -122,7 +122,7 @@ class BPStepsInSituGlobalArrayReaders
         return Schedules[std::get<0>(GetParam())];
     };
     ReadMode GetReadMode() { return std::get<1>(GetParam()); };
-    int GetScheduleID() { return std::get<0>(GetParam()); };
+    size_t GetScheduleID() { return std::get<0>(GetParam()); };
 };
 
 // Basic case: Variable written every step
@@ -172,6 +172,10 @@ TEST_P(BPStepsInSituGlobalArrayReaders, EveryStep)
     auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
     EXPECT_TRUE(var_i32);
 
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
     // Start reader
     adios2::IO ior = adios.DeclareIO("Read");
     if (!engineName.empty())
@@ -323,6 +327,10 @@ TEST_P(BPStepsInSituGlobalArrayReaders, NewVarPerStep)
     auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
     EXPECT_TRUE(var_i32);
 
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
     // Start reader
     adios2::IO ior = adios.DeclareIO("Read");
     if (!engineName.empty())
@@ -455,7 +463,7 @@ class BPStepsInSituGlobalArrayParameters
     };
     size_t GetOddity() { return std::get<1>(GetParam()); };
     ReadMode GetReadMode() { return std::get<2>(GetParam()); };
-    int GetScheduleID() { return std::get<0>(GetParam()); };
+    size_t GetScheduleID() { return std::get<0>(GetParam()); };
 };
 
 // A variable written every other step either from step 0 (EVEN) or from
@@ -511,6 +519,10 @@ TEST_P(BPStepsInSituGlobalArrayParameters, EveryOtherStep)
     auto var_step = iow.DefineVariable<size_t>("step");
     EXPECT_TRUE(var_step);
 
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
     // Start reader
     adios2::IO ior = adios.DeclareIO("Read");
     if (!engineName.empty())
diff --git a/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp b/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
index 93bc2ea980..13d1d4911a 100644
--- a/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
@@ -100,7 +100,7 @@ class BPStepsInSituLocalArrayReaders
 {
 protected:
     const std::vector<Act> &GetSchedule() { return Schedules[GetParam()]; };
-    int GetScheduleID() { return GetParam(); };
+    size_t GetScheduleID() { return GetParam(); };
 };
 
 // Basic case: Variable written every step
@@ -146,6 +146,10 @@ TEST_P(BPStepsInSituLocalArrayReaders, EveryStep)
     auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
     EXPECT_TRUE(var_i32);
 
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
     // Start reader
     adios2::IO ior = adios.DeclareIO("Read");
     if (!engineName.empty())
@@ -269,6 +273,10 @@ TEST_P(BPStepsInSituLocalArrayReaders, NewVarPerStep)
     auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
     EXPECT_TRUE(var_i32);
 
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
     // Start reader
     adios2::IO ior = adios.DeclareIO("Read");
     if (!engineName.empty())
@@ -360,7 +368,7 @@ class BPStepsInSituLocalArrayParameters
         return Schedules[std::get<0>(GetParam())];
     };
     size_t GetOddity() { return std::get<1>(GetParam()); };
-    int GetScheduleID() { return std::get<0>(GetParam()); };
+    size_t GetScheduleID() { return std::get<0>(GetParam()); };
 };
 
 // A variable written every other step either from step 0 (EVEN) or from
@@ -414,6 +422,10 @@ TEST_P(BPStepsInSituLocalArrayParameters, EveryOtherStep)
     auto var_step = iow.DefineVariable<size_t>("step");
     EXPECT_TRUE(var_step);
 
+#if ADIOS2_USE_MPI
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
     // Start reader
     adios2::IO ior = adios.DeclareIO("Read");
     if (!engineName.empty())

From afbe951de7dccee785dacc27c43f9c970237260a Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Thu, 25 Jun 2020 11:08:50 -0400
Subject: [PATCH 04/10] add timeout to the insitu reader engines

---
 .../engine/bp/TestBPStepsFileGlobalArray.cpp       | 14 +++++++++-----
 .../engine/bp/TestBPStepsInSituGlobalArray.cpp     |  3 +++
 .../engine/bp/TestBPStepsInSituLocalArray.cpp      |  3 +++
 3 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp b/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
index b69e208256..5eac4f6b1e 100644
--- a/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsFileGlobalArray.cpp
@@ -804,7 +804,8 @@ TEST_P(BPStepsFileGlobalArrayParameters, EveryOtherStep)
                 DataArray d;
                 engine.Get(var_i32, d.data(), adios2::Mode::Sync);
                 std::cout << "Rank " << mpiRank << " read at step " << step
-                          << ": " << ArrayToString(d.data(), Nx) << std::endl;
+                          << " var-step " << writtenStep << ": "
+                          << ArrayToString(d.data(), Nx) << std::endl;
 
                 for (size_t i = 0; i < Nx; ++i)
                 {
@@ -829,6 +830,8 @@ TEST_P(BPStepsFileGlobalArrayParameters, EveryOtherStep)
                          "block by block"
                       << std::endl;
         }
+
+        size_t writtenStep = 0;
         for (size_t step = 0; step < NSteps; ++step)
         {
             engine.BeginStep();
@@ -842,17 +845,18 @@ TEST_P(BPStepsFileGlobalArrayParameters, EveryOtherStep)
                 var_i32.SetBlockSelection(blockID);
                 DataArray d;
                 engine.Get(var_i32, d.data(), adios2::Mode::Sync);
-                std::cout << "Rank " << mpiRank << " read step " << step
-                          << " block " << blockID << ": "
-                          << ArrayToString(d.data(), Nx) << std::endl;
+                std::cout << "Rank " << mpiRank << " read at step " << step
+                          << " var-step " << writtenStep << " block " << blockID
+                          << ": " << ArrayToString(d.data(), Nx) << std::endl;
                 auto start = var_i32.Start();
                 auto count = var_i32.Count();
                 EXPECT_EQ(start[0], mpiRank * Nx);
                 EXPECT_EQ(count[0], 1 * Nx);
                 for (size_t i = 0; i < Nx; ++i)
                 {
-                    EXPECT_EQ(d[i], m_TestData[step][i]);
+                    EXPECT_EQ(d[i], m_TestData[writtenStep][i]);
                 }
+                ++writtenStep;
             }
             engine.EndStep();
         }
diff --git a/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp b/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
index f9bf05be02..65dad03b86 100644
--- a/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
@@ -182,6 +182,7 @@ TEST_P(BPStepsInSituGlobalArrayReaders, EveryStep)
     {
         ior.SetEngine(engineName);
     }
+    ior.SetParameter("OpenTimeoutSecs", "10.0");
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
@@ -337,6 +338,7 @@ TEST_P(BPStepsInSituGlobalArrayReaders, NewVarPerStep)
     {
         ior.SetEngine(engineName);
     }
+    ior.SetParameter("OpenTimeoutSecs", "10.0");
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
@@ -529,6 +531,7 @@ TEST_P(BPStepsInSituGlobalArrayParameters, EveryOtherStep)
     {
         ior.SetEngine(engineName);
     }
+    ior.SetParameter("OpenTimeoutSecs", "10.0");
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
diff --git a/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp b/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
index 13d1d4911a..5d122b71c7 100644
--- a/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
@@ -156,6 +156,7 @@ TEST_P(BPStepsInSituLocalArrayReaders, EveryStep)
     {
         ior.SetEngine(engineName);
     }
+    ior.SetParameter("OpenTimeoutSecs", "10.0");
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
@@ -283,6 +284,7 @@ TEST_P(BPStepsInSituLocalArrayReaders, NewVarPerStep)
     {
         ior.SetEngine(engineName);
     }
+    ior.SetParameter("OpenTimeoutSecs", "10.0");
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
@@ -432,6 +434,7 @@ TEST_P(BPStepsInSituLocalArrayParameters, EveryOtherStep)
     {
         ior.SetEngine(engineName);
     }
+    ior.SetParameter("OpenTimeoutSecs", "10.0");
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 

From 3661f02deb78ecbea110ae2170e8374eb63d3648 Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Thu, 25 Jun 2020 11:09:11 -0400
Subject: [PATCH 05/10] More detailed error message from BP4 Open()

---
 source/adios2/engine/bp4/BP4Reader.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/source/adios2/engine/bp4/BP4Reader.cpp b/source/adios2/engine/bp4/BP4Reader.cpp
index 02f70e9684..17173aeb88 100644
--- a/source/adios2/engine/bp4/BP4Reader.cpp
+++ b/source/adios2/engine/bp4/BP4Reader.cpp
@@ -395,7 +395,13 @@ void BP4Reader::InitBuffer(const TimePoint &timeoutInstant,
                     " was found with an index file but md.0 "
                     "has not contained enough data within "
                     "the specified timeout of " +
-                    std::to_string(timeoutSeconds.count()) + " seconds.");
+                    std::to_string(timeoutSeconds.count()) +
+                    " seconds. index size = " +
+                    std::to_string(metadataIndexFileSize) +
+                    " metadata size = " + std::to_string(fileSize) +
+                    " expected size = " + std::to_string(expectedMinFileSize) +
+                    ". One reason could be if the reader finds old data while "
+                    "the writer is creating the new files.");
             }
         }
     }

From aaf3234b243a39b1460f28478e6b5b04449907f5 Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Thu, 25 Jun 2020 11:09:37 -0400
Subject: [PATCH 06/10] Fix step handling issues - so that variables in one or
 multiple but not in all steps can be read back, and that variable blocks can
 be read back in insitu cases. All BPStep tests passes with these fixes.

---
 .../toolkit/format/bp/bp3/BP3Deserializer.tcc | 21 ++++++++++---------
 .../toolkit/format/bp/bp4/BP4Deserializer.tcc | 20 ++++++++++--------
 2 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/source/adios2/toolkit/format/bp/bp3/BP3Deserializer.tcc b/source/adios2/toolkit/format/bp/bp3/BP3Deserializer.tcc
index f822dd5968..cfe796b470 100644
--- a/source/adios2/toolkit/format/bp/bp3/BP3Deserializer.tcc
+++ b/source/adios2/toolkit/format/bp/bp3/BP3Deserializer.tcc
@@ -69,7 +69,10 @@ BP3Deserializer::InitVariableBlockInfo(core::Variable<T> &variable,
     }
 
     auto itStep = std::next(indices.begin(), stepsStart);
+    // BlocksInfo() expects absolute step, stepsStart is relative
+    const size_t absStep = itStep->first;
 
+    // Check that we have enough steps from stepsStart
     for (size_t i = 0; i < stepsCount; ++i)
     {
         if (itStep == indices.end())
@@ -88,8 +91,11 @@ BP3Deserializer::InitVariableBlockInfo(core::Variable<T> &variable,
 
     if (variable.m_SelectionType == SelectionType::WriteBlock)
     {
+        // BlocksInfo() expects absolute step, stepsStart is relative
+        // BlocksInfo() adds +1 to match the step starting from 1
+        // but absStep already is the actual step in the map
         const std::vector<typename core::Variable<T>::Info> blocksInfo =
-            BlocksInfo(variable, stepsStart);
+            BlocksInfo(variable, absStep - 1);
 
         if (variable.m_BlockID >= blocksInfo.size())
         {
@@ -749,10 +755,8 @@ inline void BP3Deserializer::DefineVariableInEngineIO<std::string>(
         variable->m_ShapeID = ShapeID::GlobalArray;
         variable->m_SingleValue = true;
     }
-    /* Update variable's starting step, which equals to the min value in
-    the sorted map minus one */
-    variable->m_StepsStart =
-        variable->m_AvailableStepBlockIndexOffsets.begin()->first - 1;
+    /* Update variable's starting step, which is always 0 */
+    variable->m_StepsStart = 0;
 
     // update variable Engine for read streaming functions
     variable->m_Engine = &engine;
@@ -924,11 +928,8 @@ void BP3Deserializer::DefineVariableInEngineIO(const ElementIndexHeader &header,
         // in metadata
         variable->m_SingleValue = true;
     }
-
-    /* Update variable's starting step, which equals to the min value in the
-     * sorted map minus one */
-    variable->m_StepsStart =
-        variable->m_AvailableStepBlockIndexOffsets.begin()->first - 1;
+    /* Update variable's starting step, which is always 0 */
+    variable->m_StepsStart = 0;
 
     // update variable Engine for read streaming functions
     variable->m_Engine = &engine;
diff --git a/source/adios2/toolkit/format/bp/bp4/BP4Deserializer.tcc b/source/adios2/toolkit/format/bp/bp4/BP4Deserializer.tcc
index 6aa6e60f1d..1801464d07 100644
--- a/source/adios2/toolkit/format/bp/bp4/BP4Deserializer.tcc
+++ b/source/adios2/toolkit/format/bp/bp4/BP4Deserializer.tcc
@@ -72,7 +72,10 @@ BP4Deserializer::InitVariableBlockInfo(core::Variable<T> &variable,
     }
 
     auto itStep = std::next(indices.begin(), stepsStart);
+    // BlocksInfo() expects absolute step, stepsStart is relative
+    const size_t absStep = itStep->first;
 
+    // Check that we have enough steps from stepsStart
     for (size_t i = 0; i < stepsCount; ++i)
     {
         if (itStep == indices.end())
@@ -91,8 +94,11 @@ BP4Deserializer::InitVariableBlockInfo(core::Variable<T> &variable,
 
     if (variable.m_SelectionType == SelectionType::WriteBlock)
     {
+        // BlocksInfo() expects absolute step, stepsStart is relative
+        // BlocksInfo() adds +1 to match the step starting from 1
+        // but absStep already is the actual step in the map
         const std::vector<typename core::Variable<T>::Info> blocksInfo =
-            BlocksInfo(variable, stepsStart);
+            BlocksInfo(variable, absStep - 1);
 
         if (variable.m_BlockID >= blocksInfo.size())
         {
@@ -758,10 +764,8 @@ inline void BP4Deserializer::DefineVariableInEngineIOPerStep<std::string>(
         variable->m_ShapeID = ShapeID::GlobalArray;
         variable->m_SingleValue = true;
     }
-    /* Update variable's starting step, which equals to the min value in the
-     * sorted map minus one */
-    variable->m_StepsStart =
-        variable->m_AvailableStepBlockIndexOffsets.begin()->first - 1;
+    /* Update variable's starting step, which is always 0 */
+    variable->m_StepsStart = 0;
 
     // update variable Engine for read streaming functions
     variable->m_Engine = &engine;
@@ -1010,10 +1014,8 @@ void BP4Deserializer::DefineVariableInEngineIOPerStep(
         // in metadata
         variable->m_SingleValue = true;
     }
-    /* Update variable's starting step, which equals to the min value in the
-     * sorted map minus one */
-    variable->m_StepsStart =
-        variable->m_AvailableStepBlockIndexOffsets.begin()->first - 1;
+    /* Update variable's starting step, which is always 0 */
+    variable->m_StepsStart = 0;
 
     // update variable Engine for read streaming functions
     variable->m_Engine = &engine;

From 9d2a91dbb507a3dccd91649f71ff61b01bfd63f0 Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Thu, 25 Jun 2020 11:37:14 -0400
Subject: [PATCH 07/10] fix size_t - int issue

---
 .../engine/bp/TestBPStepsInSituGlobalArray.cpp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp b/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
index 65dad03b86..155b6b571f 100644
--- a/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsInSituGlobalArray.cpp
@@ -186,8 +186,8 @@ TEST_P(BPStepsInSituGlobalArrayReaders, EveryStep)
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
-    size_t stepsWritten = 0;
-    size_t stepsRead = 0;
+    int stepsWritten = 0;
+    int stepsRead = 0;
 
     for (const auto act : schedule)
     {
@@ -342,8 +342,8 @@ TEST_P(BPStepsInSituGlobalArrayReaders, NewVarPerStep)
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
-    size_t stepsWritten = 0;
-    size_t stepsRead = 0;
+    int stepsWritten = 0;
+    int stepsRead = 0;
 
     for (const auto act : schedule)
     {
@@ -518,7 +518,7 @@ TEST_P(BPStepsInSituGlobalArrayParameters, EveryOtherStep)
     EXPECT_TRUE(writer);
     auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
     EXPECT_TRUE(var_i32);
-    auto var_step = iow.DefineVariable<size_t>("step");
+    auto var_step = iow.DefineVariable<int>("step");
     EXPECT_TRUE(var_step);
 
 #if ADIOS2_USE_MPI
@@ -535,10 +535,10 @@ TEST_P(BPStepsInSituGlobalArrayParameters, EveryOtherStep)
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
-    size_t stepsWritten = 0;
-    size_t stepsRead = 0;
-    size_t varStepsWritten = 0;
-    size_t varStepsRead = 0;
+    int stepsWritten = 0;
+    int stepsRead = 0;
+    int varStepsWritten = 0;
+    int varStepsRead = 0;
     for (const auto act : schedule)
     {
         if (act == Act::Write)

From 2b52d615011e0cf094e1947b34a4ee7d074d4bb4 Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Thu, 25 Jun 2020 11:41:07 -0400
Subject: [PATCH 08/10] Add back Staging.*.LocalVarying.BPS.* tests now that
 reading blocks in stream works

---
 testing/adios2/engine/staging-common/CMakeLists.txt           | 2 +-
 testing/adios2/engine/staging-common/TestCommonWriteLocal.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/testing/adios2/engine/staging-common/CMakeLists.txt b/testing/adios2/engine/staging-common/CMakeLists.txt
index 5c138e60e8..2c3e8eb24c 100644
--- a/testing/adios2/engine/staging-common/CMakeLists.txt
+++ b/testing/adios2/engine/staging-common/CMakeLists.txt
@@ -246,7 +246,7 @@ if(NOT MSVC)    # not on windows
     # Fortran scalar reads don't work for BP4 streaming
     list (FILTER BP4_STREAM_TESTS EXCLUDE REGEX "(FtoF|CtoF).*")
     # Local Vars have a heisen failure for BP4 streaming
-    list (FILTER BP4_STREAM_TESTS EXCLUDE REGEX ".*LocalVarying.BPS$")
+#list (FILTER BP4_STREAM_TESTS EXCLUDE REGEX ".*LocalVarying.BPS$")
     # The nobody-writes-data-in-a-timestep tests don't work for any BP file engine
     list (FILTER BP4_STREAM_TESTS EXCLUDE REGEX ".*NoData.BPS$")
     
diff --git a/testing/adios2/engine/staging-common/TestCommonWriteLocal.cpp b/testing/adios2/engine/staging-common/TestCommonWriteLocal.cpp
index b253b2aa67..17754a6b3b 100644
--- a/testing/adios2/engine/staging-common/TestCommonWriteLocal.cpp
+++ b/testing/adios2/engine/staging-common/TestCommonWriteLocal.cpp
@@ -192,7 +192,7 @@ int main(int argc, char **argv)
     int result;
     ::testing::InitGoogleTest(&argc, argv);
 
-    DelayMS = 0; // zero for common writer
+    DelayMS = 0; // zero default for common writer
 
     ParseArgs(argc, argv);
 

From 219cc917f246c9ce99228833a79b7f9936cde1dd Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Thu, 25 Jun 2020 11:55:04 -0400
Subject: [PATCH 09/10] fix size_t - int issue again

---
 .../engine/bp/TestBPStepsInSituLocalArray.cpp  | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp b/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
index 5d122b71c7..d327c21d5a 100644
--- a/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
+++ b/testing/adios2/engine/bp/TestBPStepsInSituLocalArray.cpp
@@ -160,8 +160,8 @@ TEST_P(BPStepsInSituLocalArrayReaders, EveryStep)
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
-    size_t stepsWritten = 0;
-    size_t stepsRead = 0;
+    int stepsWritten = 0;
+    int stepsRead = 0;
 
     for (const auto act : schedule)
     {
@@ -288,8 +288,8 @@ TEST_P(BPStepsInSituLocalArrayReaders, NewVarPerStep)
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
-    size_t stepsWritten = 0;
-    size_t stepsRead = 0;
+    int stepsWritten = 0;
+    int stepsRead = 0;
 
     for (const auto act : schedule)
     {
@@ -421,7 +421,7 @@ TEST_P(BPStepsInSituLocalArrayParameters, EveryOtherStep)
     EXPECT_TRUE(writer);
     auto var_i32 = iow.DefineVariable<int32_t>("i32", shape, start, count);
     EXPECT_TRUE(var_i32);
-    auto var_step = iow.DefineVariable<size_t>("step");
+    auto var_step = iow.DefineVariable<int>("step");
     EXPECT_TRUE(var_step);
 
 #if ADIOS2_USE_MPI
@@ -438,10 +438,10 @@ TEST_P(BPStepsInSituLocalArrayParameters, EveryOtherStep)
     adios2::Engine reader = ior.Open(fname, adios2::Mode::Read);
     EXPECT_TRUE(reader);
 
-    size_t stepsWritten = 0;
-    size_t stepsRead = 0;
-    size_t varStepsWritten = 0;
-    size_t varStepsRead = 0;
+    int stepsWritten = 0;
+    int stepsRead = 0;
+    int varStepsWritten = 0;
+    int varStepsRead = 0;
     for (const auto act : schedule)
     {
         if (act == Act::Write)

From fba2d991dba49a1b25af3b26bb6cf93b196bdbec Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Fri, 26 Jun 2020 07:06:07 -0400
Subject: [PATCH 10/10] fix BP3 GetSubFileInfo() step handling which is
 exclusively used by InSituMPI. Fixes broken InSituMPI tests.

---
 source/adios2/toolkit/format/bp/bp3/BP3Deserializer.tcc | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/source/adios2/toolkit/format/bp/bp3/BP3Deserializer.tcc b/source/adios2/toolkit/format/bp/bp3/BP3Deserializer.tcc
index cfe796b470..f03c812578 100644
--- a/source/adios2/toolkit/format/bp/bp3/BP3Deserializer.tcc
+++ b/source/adios2/toolkit/format/bp/bp3/BP3Deserializer.tcc
@@ -989,13 +989,14 @@ BP3Deserializer::GetSubFileInfo(const core::Variable<T> &variable) const
 
     const auto &buffer = m_Metadata.m_Buffer;
 
-    const size_t stepStart = variable.m_StepsStart + 1;
-    const size_t stepEnd = stepStart + variable.m_StepsCount; // exclusive
+    auto itStep = variable.m_AvailableStepBlockIndexOffsets.begin();
+    const size_t absStepStart = itStep->first; // absolute step in map
+    const size_t stepEnd = absStepStart + variable.m_StepsCount; // exclusive
 
     const Box<Dims> selectionBox = helper::StartEndBox(
         variable.m_Start, variable.m_Count, m_ReverseDimensions);
 
-    for (size_t step = stepStart; step < stepEnd; ++step)
+    for (size_t step = absStepStart; step < stepEnd; ++step)
     {
         auto itBlockStarts =
             variable.m_AvailableStepBlockIndexOffsets.find(step);