From 5c869015840ef48917e5c253384329c82d6a73cc Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 4 Apr 2024 12:57:22 -0400 Subject: [PATCH 01/18] pugixml: correct target name --- source/adios2/toolkit/remote/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/adios2/toolkit/remote/CMakeLists.txt b/source/adios2/toolkit/remote/CMakeLists.txt index a739e1ad63..2128caa9a9 100644 --- a/source/adios2/toolkit/remote/CMakeLists.txt +++ b/source/adios2/toolkit/remote/CMakeLists.txt @@ -10,7 +10,7 @@ if (NOT ADIOS2_USE_PIP) PRIVATE $<$:shlwapi>) get_property(pugixml_headers_path - TARGET pugixml + TARGET adios2::thirdparty::pugixml PROPERTY INTERFACE_INCLUDE_DIRECTORIES ) From 451df9191862a5966a4097a829705ee26a7e4a0c Mon Sep 17 00:00:00 2001 From: Greg Eisenhauer Date: Thu, 4 Apr 2024 16:47:56 -0400 Subject: [PATCH 02/18] dill 2024-04-04 (55420dee) (#4136) Code extracted from: https://github.com/GTkorvo/dill.git --- thirdparty/dill/dill/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/thirdparty/dill/dill/CMakeLists.txt b/thirdparty/dill/dill/CMakeLists.txt index 8d6bfe8b24..03202c9c1f 100644 --- a/thirdparty/dill/dill/CMakeLists.txt +++ b/thirdparty/dill/dill/CMakeLists.txt @@ -102,7 +102,7 @@ check_type_size("void*" CMAKE_SIZEOF_VOID_P) check_type_size("long" SIZEOF_LONG) set(NATIVE_CG TRUE) unset(NATIVE_ARCH) -if(CMAKE_SYSTEM_PROCESSOR MATCHES "i.86|x86_64|AMD64") +if(CMAKE_SYSTEM_PROCESSOR MATCHES "i.86|x86_64|AMD64|amd64") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(NATIVE_ARCH x86_64) set(HOST_X86_64 1) @@ -200,7 +200,7 @@ endif() if(LIBFFI_FOUND) message(STATUS "Enabling emulation") set(EMULATION_POSSIBLE TRUE) -elseif(DILL_IGNORE_NATIVE OR (NATIVE_ARCH STREQUAL "UNSUPPORTED")) +elseif((DILL_IGNORE_NATIVE OR (NATIVE_ARCH STREQUAL "UNSUPPORTED")) AND NOT DILL_NATIVE_ONLY) find_program (AUTOCONF autoconf) find_program (AUTOMAKE automake) if ((AUTOCONF STREQUAL "AUTOCONF-NOTFOUND") OR (AUTOMAKE STREQUAL "AUTOMAKE-NOTFOUND")) @@ -344,7 +344,6 @@ check_include_files(memory.h HAVE_MEMORY_H) check_include_files(sys/mman.h HAVE_SYS_MMAN_H) include(CheckSymbolExists) check_symbol_exists(__clear_cache "" CLEAR_CACHE_DEFINED) -message(STATUS "Clear cache defined is ${CLEAR_CACHE_DEFINED}") set(NO_DISASSEMBLER TRUE) if(DILL_ENABLE_DISASSEMBLY) From c6ff249b945cf4fd054659d3781294f9fc6d036b Mon Sep 17 00:00:00 2001 From: Norbert Podhorszki Date: Wed, 17 Apr 2024 14:46:33 -0400 Subject: [PATCH 03/18] - based on char signess in installed adios library, use numpy.int8 or numpy.uint8 to read char arrays from BP files - move char as last type in adios type macros, so that unsigned char always becomes uint8_t and signed char becomes int8_t in output (char arrays still become char in output) - add C++ test to write and read char/signed char/unsigned char arrays --- bindings/Python/py11glue.cpp | 1 + python/adios2/stream.py | 8 ++- source/adios2/common/ADIOSMacros.h | 40 +++++++-------- testing/adios2/engine/SmallTestData.h | 22 ++++++++ .../engine/bp/TestBPWriteReadADIOS2.cpp | 50 +++++++++++++++++++ 5 files changed, 100 insertions(+), 21 deletions(-) diff --git a/bindings/Python/py11glue.cpp b/bindings/Python/py11glue.cpp index 2c40280f99..18f3a6eb27 100644 --- a/bindings/Python/py11glue.cpp +++ b/bindings/Python/py11glue.cpp @@ -92,6 +92,7 @@ PYBIND11_MODULE(ADIOS2_PYTHON_MODULE_NAME, m) #else m.attr("is_built_with_mpi") = false; #endif + m.attr("is_char_signed") = (char)-1 < 0; // enum classes pybind11::enum_(m, "Mode") diff --git a/python/adios2/stream.py b/python/adios2/stream.py index 0285507cc9..58a9c09050 100644 --- a/python/adios2/stream.py +++ b/python/adios2/stream.py @@ -11,8 +11,14 @@ def type_adios_to_numpy(name): """Translation between numpy and adios2 types""" + if name == "char": + if bindings.is_char_signed: + print("type_adios_to_numpy char --> signed int8") + return np.int8 + print("type_adios_to_numpy char --> unsigned uint8") + return np.uint8 + return { - "char": np.int8, "int8_t": np.int8, "uint8_t": np.uint8, "int16_t": np.int16, diff --git a/source/adios2/common/ADIOSMacros.h b/source/adios2/common/ADIOSMacros.h index aac757ad6d..8c5f719491 100644 --- a/source/adios2/common/ADIOSMacros.h +++ b/source/adios2/common/ADIOSMacros.h @@ -33,7 +33,6 @@ */ #define ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(MACRO) \ - MACRO(char) \ MACRO(int8_t) \ MACRO(int16_t) \ MACRO(int32_t) \ @@ -44,7 +43,8 @@ MACRO(uint64_t) \ MACRO(float) \ MACRO(double) \ - MACRO(long double) + MACRO(long double) \ + MACRO(char) #define ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(MACRO) \ ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(MACRO) \ @@ -52,16 +52,15 @@ MACRO(std::complex) #define ADIOS2_FOREACH_ATTRIBUTE_STDTYPE_1ARG(MACRO) \ - MACRO(std::string) \ - ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(MACRO) + ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(MACRO) \ + MACRO(std::string) #define ADIOS2_FOREACH_STDTYPE_1ARG(MACRO) \ - MACRO(std::string) \ - ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(MACRO) + ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(MACRO) \ + MACRO(std::string) #define ADIOS2_FOREACH_TYPE_1ARG(MACRO) \ MACRO(std::string) \ - MACRO(char) \ MACRO(signed char) \ MACRO(unsigned char) \ MACRO(short) \ @@ -76,10 +75,10 @@ MACRO(double) \ MACRO(long double) \ MACRO(std::complex) \ - MACRO(std::complex) + MACRO(std::complex) \ + MACRO(char) #define ADIOS2_FOREACH_PRIMITIVE_TYPE_1ARG(MACRO) \ - MACRO(char) \ MACRO(signed char) \ MACRO(unsigned char) \ MACRO(short) \ @@ -94,7 +93,8 @@ MACRO(double) \ MACRO(long double) \ MACRO(std::complex) \ - MACRO(std::complex) + MACRO(std::complex) \ + MACRO(char) #define ADIOS2_FOREACH_COMPLEX_PRIMITIVE_TYPE_1ARG(MACRO) \ MACRO(float) \ @@ -102,9 +102,9 @@ MACRO(long double) #define ADIOS2_FOREACH_CHAR_TYPE_1ARG(MACRO) \ - MACRO(char) \ MACRO(signed char) \ - MACRO(unsigned char) + MACRO(unsigned char) \ + MACRO(char) #define ADIOS2_FOREACH_NUMERIC_TYPE_1ARG(MACRO) \ MACRO(short) \ @@ -123,7 +123,6 @@ #define ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(MACRO) \ MACRO(std::string) \ - MACRO(char) \ MACRO(signed char) \ MACRO(unsigned char) \ MACRO(short) \ @@ -138,10 +137,10 @@ MACRO(double) \ MACRO(long double) \ MACRO(std::complex) \ - MACRO(std::complex) + MACRO(std::complex) \ + MACRO(char) #define ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_TYPE_1ARG(MACRO) \ - MACRO(char) \ MACRO(signed char) \ MACRO(unsigned char) \ MACRO(short) \ @@ -156,7 +155,8 @@ MACRO(double) \ MACRO(long double) \ MACRO(std::complex) \ - MACRO(std::complex) + MACRO(std::complex) \ + MACRO(char) /**
@@ -185,7 +185,6 @@
 #define ADIOS2_FOREACH_ATTRIBUTE_STDTYPE_2ARGS(MACRO)                                              \
     MACRO(std::string, string)                                                                     \
     MACRO(int8_t, int8)                                                                            \
-    MACRO(char, char)                                                                              \
     MACRO(uint8_t, uint8)                                                                          \
     MACRO(int16_t, int16)                                                                          \
     MACRO(uint16_t, uint16)                                                                        \
@@ -197,11 +196,11 @@
     MACRO(double, double)                                                                          \
     MACRO(long double, ldouble)                                                                    \
     MACRO(std::complex, cfloat)                                                             \
-    MACRO(std::complex, cdouble)
+    MACRO(std::complex, cdouble)                                                           \
+    MACRO(char, char)
 
 #define ADIOS2_FOREACH_PRIMITVE_STDTYPE_2ARGS(MACRO)                                               \
     MACRO(int8_t, int8)                                                                            \
-    MACRO(char, char)                                                                              \
     MACRO(uint8_t, uint8)                                                                          \
     MACRO(int16_t, int16)                                                                          \
     MACRO(uint16_t, uint16)                                                                        \
@@ -213,7 +212,8 @@
     MACRO(double, double)                                                                          \
     MACRO(long double, ldouble)                                                                    \
     MACRO(std::complex, cfloat)                                                             \
-    MACRO(std::complex, cdouble)
+    MACRO(std::complex, cdouble)                                                           \
+    MACRO(char, char)
 
 #define ADIOS2_FOREACH_MINMAX_STDTYPE_2ARGS(MACRO)                                                 \
     MACRO(int8_t, int8)                                                                            \
diff --git a/testing/adios2/engine/SmallTestData.h b/testing/adios2/engine/SmallTestData.h
index c090dd8f89..c391c70ce2 100644
--- a/testing/adios2/engine/SmallTestData.h
+++ b/testing/adios2/engine/SmallTestData.h
@@ -66,6 +66,16 @@ struct SmallTestData
 
     std::array CHAR = {{'a', 'b', 'c', 'y', 'z', 'A', 'B', 'C', 'Y', 'Z'}};
     std::array TF = {{true, false, true, true, false, false, true, false, false, true}};
+
+    std::array CHARS = {(char)0, (char)1,  (char)-2, (char)3,  (char)-4,
+                                  (char)5, (char)-6, (char)7,  (char)-8, (char)9};
+    std::array SCHARS = {
+        (signed char)0, (signed char)1,  (signed char)-2, (signed char)3,  (signed char)-4,
+        (signed char)5, (signed char)-6, (signed char)7,  (signed char)-8, (signed char)9};
+    std::array UCHARS = {(unsigned char)0,  (unsigned char)1,  (unsigned char)-2,
+                                            (unsigned char)3,  (unsigned char)-4, (unsigned char)5,
+                                            (unsigned char)-6, (unsigned char)7,  (unsigned char)-8,
+                                            (unsigned char)9};
 };
 
 SmallTestData generateNewSmallTestData(SmallTestData in, size_t step, size_t rank, size_t size)
@@ -109,6 +119,12 @@ SmallTestData generateNewSmallTestData(SmallTestData in, size_t step, size_t ran
         }
     });
 
+    std::for_each(in.CHARS.begin(), in.CHARS.end(), [&](char &v) { v += static_cast(j); });
+    std::for_each(in.SCHARS.begin(), in.SCHARS.end(),
+                  [&](signed char &v) { v += static_cast(j); });
+    std::for_each(in.UCHARS.begin(), in.UCHARS.end(),
+                  [&](unsigned char &v) { v += static_cast(j); });
+
     return in;
 }
 
@@ -149,6 +165,12 @@ void UpdateSmallTestData(SmallTestData &in, int step, int rank, int size)
             v = 'A' + (v - 'Z') - 1;
         }
     });
+
+    std::for_each(in.CHARS.begin(), in.CHARS.end(), [&](char &v) { v += static_cast(j); });
+    std::for_each(in.SCHARS.begin(), in.SCHARS.end(),
+                  [&](signed char &v) { v += static_cast(j); });
+    std::for_each(in.UCHARS.begin(), in.UCHARS.end(),
+                  [&](unsigned char &v) { v += static_cast(j); });
 }
 
 #endif // TESTING_ADIOS2_ENGINE_SMALLTESTDATA_H_
diff --git a/testing/adios2/engine/bp/TestBPWriteReadADIOS2.cpp b/testing/adios2/engine/bp/TestBPWriteReadADIOS2.cpp
index 5bcb64af4b..99f3a12826 100644
--- a/testing/adios2/engine/bp/TestBPWriteReadADIOS2.cpp
+++ b/testing/adios2/engine/bp/TestBPWriteReadADIOS2.cpp
@@ -121,6 +121,12 @@ TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
             EXPECT_TRUE(var_r32);
             auto var_r64 = io.DefineVariable("r64", shape, start, count);
             EXPECT_TRUE(var_r64);
+            auto var_chars = io.DefineVariable("chars", shape, start, count);
+            EXPECT_TRUE(var_chars);
+            auto var_schars = io.DefineVariable("schars", shape, start, count);
+            EXPECT_TRUE(var_schars);
+            auto var_uchars = io.DefineVariable("uchars", shape, start, count);
+            EXPECT_TRUE(var_uchars);
         }
 
         if (!engineName.empty())
@@ -169,6 +175,9 @@ TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
             auto var_u64 = io.InquireVariable("u64");
             auto var_r32 = io.InquireVariable("r32");
             auto var_r64 = io.InquireVariable("r64");
+            auto var_chars = io.InquireVariable("chars");
+            auto var_schars = io.InquireVariable("schars");
+            auto var_uchars = io.InquireVariable("uchars");
 
             // Make a 1D selection to describe the local dimensions of the
             // variable we write and its offsets in the global spaces
@@ -187,6 +196,9 @@ TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
             var_u64.SetSelection(sel);
             var_r32.SetSelection(sel);
             var_r64.SetSelection(sel);
+            var_chars.SetSelection(sel);
+            var_schars.SetSelection(sel);
+            var_uchars.SetSelection(sel);
 
             // Write each one
             // fill in the variable with values from starting index to
@@ -206,6 +218,9 @@ TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
             bpWriter.Put(var_u64, currentTestData.U64.data());
             bpWriter.Put(var_r32, currentTestData.R32.data());
             bpWriter.Put(var_r64, currentTestData.R64.data());
+            bpWriter.Put(var_chars, currentTestData.CHARS.data());
+            bpWriter.Put(var_schars, currentTestData.SCHARS.data());
+            bpWriter.Put(var_uchars, currentTestData.UCHARS.data());
 
             bpWriter.EndStep();
         }
@@ -307,6 +322,24 @@ TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
         ASSERT_EQ(var_r64.Steps(), NSteps);
         ASSERT_EQ(var_r64.Shape()[0], mpiSize * Nx);
 
+        auto var_chars = io.InquireVariable("chars");
+        EXPECT_TRUE(var_chars);
+        ASSERT_EQ(var_chars.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_chars.Steps(), NSteps);
+        ASSERT_EQ(var_chars.Shape()[0], mpiSize * Nx);
+
+        auto var_schars = io.InquireVariable("schars");
+        EXPECT_TRUE(var_schars);
+        ASSERT_EQ(var_schars.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_schars.Steps(), NSteps);
+        ASSERT_EQ(var_schars.Shape()[0], mpiSize * Nx);
+
+        auto var_uchars = io.InquireVariable("uchars");
+        EXPECT_TRUE(var_uchars);
+        ASSERT_EQ(var_uchars.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_uchars.Steps(), NSteps);
+        ASSERT_EQ(var_uchars.Shape()[0], mpiSize * Nx);
+
         // TODO: other types
 
         SmallTestData testData;
@@ -324,6 +357,9 @@ TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
         std::array R64;
         std::array CHAR;
         // std::array TF;
+        std::array CHARS;
+        std::array SCHARS;
+        std::array UCHARS;
 
         const adios2::Dims start{mpiRank * Nx};
         const adios2::Dims count{Nx};
@@ -346,6 +382,10 @@ TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
         var_r32.SetSelection(sel);
         var_r64.SetSelection(sel);
 
+        var_chars.SetSelection(sel);
+        var_schars.SetSelection(sel);
+        var_uchars.SetSelection(sel);
+
         for (size_t t = 0; t < NSteps; ++t)
         {
             // var_bool.SetStepSelection({t, 1});
@@ -364,6 +404,10 @@ TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
             var_r32.SetStepSelection({t, 1});
             var_r64.SetStepSelection({t, 1});
 
+            var_chars.SetStepSelection({t, 1});
+            var_schars.SetStepSelection({t, 1});
+            var_uchars.SetStepSelection({t, 1});
+
             // Generate test data for each rank uniquely
             SmallTestData currentTestData =
                 generateNewSmallTestData(m_TestData, static_cast(t), mpiRank, mpiSize);
@@ -384,6 +428,9 @@ TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
             bpReader.Get(var_r32, R32.data());
             bpReader.Get(var_r64, R64.data());
 
+            bpReader.Get(var_chars, CHARS.data());
+            bpReader.Get(var_schars, SCHARS.data());
+            bpReader.Get(var_uchars, UCHARS.data());
             bpReader.PerformGets();
 
             EXPECT_EQ(IString, currentTestData.S1);
@@ -406,6 +453,9 @@ TEST_F(BPWriteReadTestADIOS2, ADIOS2BPWriteRead1D8)
                 EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
+                EXPECT_EQ(CHARS[i], currentTestData.CHARS[i]) << msg;
+                EXPECT_EQ(SCHARS[i], currentTestData.SCHARS[i]) << msg;
+                EXPECT_EQ(UCHARS[i], currentTestData.UCHARS[i]) << msg;
             }
         }
         bpReader.Close();

From a1549b3eca6e3ea35fde922278e9a302559cca78 Mon Sep 17 00:00:00 2001
From: Greg Eisenhauer 
Date: Thu, 23 May 2024 17:18:37 -0400
Subject: [PATCH 04/18] test CI fix (#4177)

---
 examples/hello/hdf5SubFile/hdf5SubFile.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/examples/hello/hdf5SubFile/hdf5SubFile.cpp b/examples/hello/hdf5SubFile/hdf5SubFile.cpp
index a018267b1a..070d336627 100644
--- a/examples/hello/hdf5SubFile/hdf5SubFile.cpp
+++ b/examples/hello/hdf5SubFile/hdf5SubFile.cpp
@@ -14,7 +14,6 @@
 #include  //std::cout
 #include 
 #include  //std::invalid_argument std::exception
-#include 
 #include 
 
 void writeMe(adios2::IO &hdf5IO, int rank, int size, const char *testFileName)
@@ -34,8 +33,8 @@ void writeMe(adios2::IO &hdf5IO, int rank, int size, const char *testFileName)
     const std::size_t Nx = 1024;
     const std::size_t Ny = 1024 * scale;
 
-    std::vector myFloats(Nx * Ny, 0.1 * rank);
-    std::vector myInts(Nx * Ny, 1 + rank);
+    std::vector myFloats(Nx * Ny, 0.1f * rank);
+    std::vector myInts(Nx * Ny, (int)(1 + rank));
 
     hdf5IO.SetParameter("IdleH5Writer",
                         "true"); // set this if not all ranks are writting
@@ -101,7 +100,7 @@ void ReadVarData(adios2::IO h5IO, adios2::Engine &h5Reader, const std::string &n
 
     if (var)
     {
-        int nDims = var.Shape().size();
+        int nDims = (int)var.Shape().size();
         size_t totalSize = 1;
         for (int i = 0; i < nDims; i++)
         {

From 85cd03625c0fbdfe8cc47882b0af9de78893ebff Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki 
Date: Thu, 23 May 2024 14:01:13 -0400
Subject: [PATCH 05/18] Deactivate campaign recording by default. Use
 .adios-campaign/ as directory name.

---
 source/adios2/core/ADIOS.cpp                                   | 2 +-
 source/adios2/engine/campaign/CampaignManager.h                | 2 +-
 source/utils/adios_campaign_manager/adios2_campaign_manager.py | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/source/adios2/core/ADIOS.cpp b/source/adios2/core/ADIOS.cpp
index a280483ce2..f7d248d2ee 100644
--- a/source/adios2/core/ADIOS.cpp
+++ b/source/adios2/core/ADIOS.cpp
@@ -185,7 +185,7 @@ void ADIOS::SetUserOptionDefaults()
 {
     m_UserOptions.general.verbose = 0;
 
-    m_UserOptions.campaign.active = true;
+    m_UserOptions.campaign.active = false;
     m_UserOptions.campaign.verbose = 0;
     m_UserOptions.campaign.hostname = "";
     m_UserOptions.campaign.campaignstorepath = "";
diff --git a/source/adios2/engine/campaign/CampaignManager.h b/source/adios2/engine/campaign/CampaignManager.h
index 2a23064cd6..ded0e57732 100644
--- a/source/adios2/engine/campaign/CampaignManager.h
+++ b/source/adios2/engine/campaign/CampaignManager.h
@@ -51,7 +51,7 @@ class CampaignManager
     int m_WriterRank;
     CampaignRecordMap cmap;
     std::ofstream m_Output;
-    const std::string m_CampaignDir = "adios-campaign";
+    const std::string m_CampaignDir = ".adios-campaign";
 
 #else
 public:
diff --git a/source/utils/adios_campaign_manager/adios2_campaign_manager.py b/source/utils/adios_campaign_manager/adios2_campaign_manager.py
index be9eecfad3..818cd2ca3e 100755
--- a/source/utils/adios_campaign_manager/adios2_campaign_manager.py
+++ b/source/utils/adios_campaign_manager/adios2_campaign_manager.py
@@ -89,7 +89,7 @@ def SetupArgs():
             args.CampaignFileName = args.campaign_store + "/" + args.CampaignFileName
 
     if args.files is None:
-        args.LocalCampaignDir = "adios-campaign/"
+        args.LocalCampaignDir = ".adios-campaign/"
 
     if args.verbose > 0:
         print(f"# Verbosity = {args.verbose}")

From 99fc509dd6ad431459b2a58fe755a2219c510b9a Mon Sep 17 00:00:00 2001
From: Greg Eisenhauer 
Date: Mon, 15 Apr 2024 18:50:08 -0500
Subject: [PATCH 06/18] Fixes for FreeBSD, including upstream (#4138)

---
 .../toolkit/transport/file/FileHTTP.cpp       |  2 +
 thirdparty/EVPath/EVPath/cmib.c               | 71 +++++--------------
 thirdparty/EVPath/EVPath/mtests/cmping.c      |  1 +
 thirdparty/EVPath/EVPath/mtests/cmtest.c      |  1 +
 thirdparty/EVPath/EVPath/rtests/evtest.c      |  1 +
 .../EVPath/EVPath/rtests/extract_test.c       |  1 +
 .../EVPath/rtests/remote_terminal_test.c      |  1 +
 thirdparty/EVPath/EVPath/tests/evtest.c       |  1 +
 thirdparty/dill/dill/.clang-format            | 18 +++++
 thirdparty/ffs/ffs/CMakeLists.txt             |  1 +
 thirdparty/ffs/ffs/cmake/BisonFlexSub.cmake   |  3 +-
 thirdparty/ffs/ffs/ffs/tests/context_test.c   |  3 +
 12 files changed, 49 insertions(+), 55 deletions(-)
 create mode 100644 thirdparty/dill/dill/.clang-format

diff --git a/source/adios2/toolkit/transport/file/FileHTTP.cpp b/source/adios2/toolkit/transport/file/FileHTTP.cpp
index 7407cb6ff7..6e52cde493 100644
--- a/source/adios2/toolkit/transport/file/FileHTTP.cpp
+++ b/source/adios2/toolkit/transport/file/FileHTTP.cpp
@@ -8,6 +8,8 @@
  *      Author: Dmitry Ganyushin  ganyushin@gmail.com
  */
 #include "FileHTTP.h"
+#include 
+
 #include 
 #include 
 #include 
diff --git a/thirdparty/EVPath/EVPath/cmib.c b/thirdparty/EVPath/EVPath/cmib.c
index 6cfd7c828f..1a956cedb1 100644
--- a/thirdparty/EVPath/EVPath/cmib.c
+++ b/thirdparty/EVPath/EVPath/cmib.c
@@ -369,9 +369,7 @@ static inline uint16_t get_local_lid(struct ibv_context *context, int port)
 }
 
 static int
-check_host(hostname, sin_addr)
-	char *hostname;
-void *sin_addr;
+check_host(char *hostname,void *sin_addr)
 {
 	struct hostent *host_addr;
 	host_addr = gethostbyname(hostname);
@@ -393,8 +391,7 @@ void *sin_addr;
 }
 
 static ib_conn_data_ptr 
-create_ib_conn_data(svc)
-	CMtrans_services svc;
+create_ib_conn_data(CMtrans_services svc)
 {
 	ib_conn_data_ptr ib_conn_data = svc->malloc_func(sizeof(struct ib_connection_data));
 	memset(ib_conn_data, 0, sizeof(struct ib_connection_data));
@@ -946,9 +943,7 @@ CMIB_data_available(transport_entry trans, CMConnection conn)
  * Accept socket connection
  */
 static void
-ib_accept_conn(void_trans, void_conn_sock)
-	void *void_trans;
-void *void_conn_sock;
+ib_accept_conn(void *void_trans, void *void_conn_sock)
 {
 	transport_entry trans = (transport_entry) void_trans;
 	int conn_sock = (int) (long) void_conn_sock;
@@ -1106,9 +1101,7 @@ void *void_conn_sock;
 }
 
 extern void
-libcmib_LTX_shutdown_conn(svc, scd)
-	CMtrans_services svc;
-ib_conn_data_ptr scd;
+libcmib_LTX_shutdown_conn(CMtrans_services svc, ib_conn_data_ptr scd)
 {
 	svc->trace_out(scd->sd->cm, "CMIB shutdown_conn, removing select %d\n",
 	               scd->fd);
@@ -1141,14 +1134,7 @@ is_private_10(int IP)
 }
 
 static int
-initiate_conn(cm, svc, trans, attrs, ib_conn_data, conn_attr_list, no_more_redirect)
-	CManager cm;
-CMtrans_services svc;
-transport_entry trans;
-attr_list attrs;
-ib_conn_data_ptr ib_conn_data;
-attr_list conn_attr_list;
-int no_more_redirect;
+initiate_conn(CManager cm, CMtrans_services svc, transport_entry trans, attr_list attrs, ib_conn_data_ptr ib_conn_data, attr_list conn_attr_list, int no_more_redirect)
 {
 	int sock;
 
@@ -1413,11 +1399,7 @@ int no_more_redirect;
  * (name_str stores the machine name).
  */
 extern CMConnection
-libcmib_LTX_initiate_conn(cm, svc, trans, attrs)
-	CManager cm;
-CMtrans_services svc;
-transport_entry trans;
-attr_list attrs;
+libcmib_LTX_initiate_conn(CManager cm, CMtrans_services svc, transport_entry trans, attr_list attrs)
 {
 	ib_conn_data_ptr ib_conn_data = create_ib_conn_data(svc);
 	attr_list conn_attr_list = create_attr_list();
@@ -1447,11 +1429,7 @@ attr_list attrs;
  * same as ours and if the IP_PORT matches the one we are listening on.
  */
 extern int
-libcmib_LTX_self_check(cm, svc, trans, attrs)
-	CManager cm;
-CMtrans_services svc;
-transport_entry trans;
-attr_list attrs;
+libcmib_LTX_self_check(CManager cm, CMtrans_services svc, transport_entry trans, attr_list attrs)
 {
 
 	ib_client_data_ptr sd = trans->trans_data;
@@ -1499,12 +1477,9 @@ attr_list attrs;
 }
 
 extern int
-libcmib_LTX_connection_eq(cm, svc, trans, attrs, scd)
-	CManager cm;
-CMtrans_services svc;
-transport_entry trans;
-attr_list attrs;
-ib_conn_data_ptr scd;
+libcmib_LTX_connection_eq(CManager cm, CMtrans_services svc, 
+			  transport_entry trans, attr_list attrs,
+			  ib_conn_data_ptr scd)
 {
 
 	int int_port_num;
@@ -1548,11 +1523,8 @@ ib_conn_data_ptr scd;
  * Create an IP socket for connection from other CMs
  */
 extern attr_list
-libcmib_LTX_non_blocking_listen(cm, svc, trans, listen_info)
-	CManager cm;
-CMtrans_services svc;
-transport_entry trans;
-attr_list listen_info;
+libcmib_LTX_non_blocking_listen(CManager cm, CMtrans_services svc,
+				transport_entry trans, attr_list listen_info)
 {
 	ib_client_data_ptr sd = trans->trans_data;
 	unsigned int length;
@@ -1714,11 +1686,8 @@ struct iovec {
 #endif
 
 extern void
-libcmib_LTX_set_write_notify(trans, svc, scd, enable)
-	transport_entry trans;
-CMtrans_services svc;
-ib_conn_data_ptr scd;
-int enable;
+libcmib_LTX_set_write_notify(transport_entry trans, CMtrans_services svc,
+			     ib_conn_data_ptr scd, int enable)
 {
 	if (enable != 0) {
 		svc->fd_write_select(trans->cm, scd->fd, (select_list_func) trans->write_possible,
@@ -1910,12 +1879,8 @@ libcmib_LTX_writev_complete_notify_func(CMtrans_services svc,
 }
 
 extern int
-libcmib_LTX_writev_func(svc, scd, iovs, iovcnt, attrs)
-CMtrans_services svc;
-ib_conn_data_ptr scd;
-void *iovs;
-int iovcnt;
-attr_list attrs;
+libcmib_LTX_writev_func(CMtrans_services svc, ib_conn_data_ptr scd,
+			void *iovs, int iovcnt, attr_list attrs)
 {
     return libcmib_LTX_writev_complete_notify_func(svc, scd, iovs, iovcnt, 
 						   attrs, NULL, NULL);
@@ -1934,9 +1899,7 @@ free_ib_data(CManager cm, void *sdv)
 }
 
 extern void *
-libcmib_LTX_initialize(cm, svc)
-	CManager cm;
-CMtrans_services svc;
+libcmib_LTX_initialize(CManager cm, CMtrans_services svc)
 {
 	static int atom_init = 0;
 
diff --git a/thirdparty/EVPath/EVPath/mtests/cmping.c b/thirdparty/EVPath/EVPath/mtests/cmping.c
index 067eb11f76..59a0783054 100644
--- a/thirdparty/EVPath/EVPath/mtests/cmping.c
+++ b/thirdparty/EVPath/EVPath/mtests/cmping.c
@@ -18,6 +18,7 @@
 #define srand48(x)
 #define kill(x,y) TerminateProcess(OpenProcess(0,0,(DWORD)x),y)
 #else
+#include 
 #include 
 #include 
 #endif
diff --git a/thirdparty/EVPath/EVPath/mtests/cmtest.c b/thirdparty/EVPath/EVPath/mtests/cmtest.c
index 0396443fee..3b2ef85810 100644
--- a/thirdparty/EVPath/EVPath/mtests/cmtest.c
+++ b/thirdparty/EVPath/EVPath/mtests/cmtest.c
@@ -18,6 +18,7 @@
 #define srand48(x)
 #define kill(x,y) TerminateProcess(OpenProcess(0, 0, (DWORD)x),y)
 #else
+#include 
 #include 
 #include 
 #endif
diff --git a/thirdparty/EVPath/EVPath/rtests/evtest.c b/thirdparty/EVPath/EVPath/rtests/evtest.c
index cf1a2ac732..615fc7f903 100644
--- a/thirdparty/EVPath/EVPath/rtests/evtest.c
+++ b/thirdparty/EVPath/EVPath/rtests/evtest.c
@@ -20,6 +20,7 @@
 #define srand48(x)
 #define kill(x,y) TerminateProcess(OpenProcess(0,0,(DWORD)x),y)
 #else
+#include 
 #include 
 #include 
 #endif
diff --git a/thirdparty/EVPath/EVPath/rtests/extract_test.c b/thirdparty/EVPath/EVPath/rtests/extract_test.c
index ed2677329b..47fe155248 100644
--- a/thirdparty/EVPath/EVPath/rtests/extract_test.c
+++ b/thirdparty/EVPath/EVPath/rtests/extract_test.c
@@ -19,6 +19,7 @@
 #define srand48(x)
 #define kill(x,y) TerminateProcess(OpenProcess(0, 0, (DWORD)x),y)
 #else
+#include 
 #include 
 #include 
 #endif
diff --git a/thirdparty/EVPath/EVPath/rtests/remote_terminal_test.c b/thirdparty/EVPath/EVPath/rtests/remote_terminal_test.c
index 999bb626b4..8896145d1c 100644
--- a/thirdparty/EVPath/EVPath/rtests/remote_terminal_test.c
+++ b/thirdparty/EVPath/EVPath/rtests/remote_terminal_test.c
@@ -19,6 +19,7 @@
 #define srand48(x)
 #define kill(x,y) TerminateProcess(OpenProcess(0,0,(DWORD)x),y)
 #else
+#include 
 #include 
 #include 
 #endif
diff --git a/thirdparty/EVPath/EVPath/tests/evtest.c b/thirdparty/EVPath/EVPath/tests/evtest.c
index b13102dbf8..59481adf78 100644
--- a/thirdparty/EVPath/EVPath/tests/evtest.c
+++ b/thirdparty/EVPath/EVPath/tests/evtest.c
@@ -18,6 +18,7 @@
 #define srand48(x)
 #define kill(x,y) TerminateProcess(OpenProcess(0,0,(DWORD)x),y)
 #else
+#include 
 #include 
 #include 
 #endif
diff --git a/thirdparty/dill/dill/.clang-format b/thirdparty/dill/dill/.clang-format
new file mode 100644
index 0000000000..ebaa492bc6
--- /dev/null
+++ b/thirdparty/dill/dill/.clang-format
@@ -0,0 +1,18 @@
+Language:  Cpp
+BasedOnStyle:  Chromium
+BreakBeforeBraces:  Custom
+IndentWidth: 4
+ContinuationIndentWidth: 4
+AccessModifierOffset: -4
+Standard: Cpp11
+ColumnLimit: 80
+AllowAllParametersOfDeclarationOnNextLine: false
+AlwaysBreakAfterReturnType: All
+AlignEscapedNewlines: Right
+AlignAfterOpenBracket: Align
+SortUsingDeclarations: false
+IndentCaseLabels: false
+BraceWrapping:
+  AfterFunction: true
+  SplitEmptyFunction: true
+  SplitEmptyRecord: true
diff --git a/thirdparty/ffs/ffs/CMakeLists.txt b/thirdparty/ffs/ffs/CMakeLists.txt
index c9f516988d..3cd2733e9d 100644
--- a/thirdparty/ffs/ffs/CMakeLists.txt
+++ b/thirdparty/ffs/ffs/CMakeLists.txt
@@ -258,6 +258,7 @@ endif()
 CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H)
 CHECK_INCLUDE_FILE(memory.h HAVE_MEMORY_H)
 CHECK_INCLUDE_FILE(netdb.h HAVE_NETDB_H)
+CHECK_INCLUDE_FILE(netinet/in.h HAVE_NETINET_IN_H)
 CHECK_INCLUDE_FILE(sockLib.h HAVE_SOCKLIB_H)
 CHECK_INCLUDE_FILE(stdarg.h STDC_HEADERS)
 CHECK_INCLUDE_FILE(stdlib.h HAVE_STDLIB_H)
diff --git a/thirdparty/ffs/ffs/cmake/BisonFlexSub.cmake b/thirdparty/ffs/ffs/cmake/BisonFlexSub.cmake
index 40e2e275f5..dedcd711c6 100644
--- a/thirdparty/ffs/ffs/cmake/BisonFlexSub.cmake
+++ b/thirdparty/ffs/ffs/cmake/BisonFlexSub.cmake
@@ -1,7 +1,8 @@
 FUNCTION (SETUP_BISON_FLEX_SUB)
 
 IF ((${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") OR
-   (${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
+   (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") OR
+   (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD"))
    set (BISON_FLEX_PRECOMPILE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cod/pregen_source/Linux")
 elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
    set (BISON_FLEX_PRECOMPILE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cod/pregen_source/Windows")
diff --git a/thirdparty/ffs/ffs/ffs/tests/context_test.c b/thirdparty/ffs/ffs/ffs/tests/context_test.c
index 19af8d4442..fe178133c3 100755
--- a/thirdparty/ffs/ffs/ffs/tests/context_test.c
+++ b/thirdparty/ffs/ffs/ffs/tests/context_test.c
@@ -4,6 +4,9 @@
 #ifdef STDC_HEADERS
 #include 
 #endif
+#ifdef HAVE_NETINET_IN_H
+#include 
+#endif
 #include 
 #ifdef HAVE_UNISTD_H
 #include 

From 04ba05856e38fb511482153b15e95227e0fa3f40 Mon Sep 17 00:00:00 2001
From: Vicente Bolea 
Date: Sun, 21 Apr 2024 16:28:03 -0400
Subject: [PATCH 07/18] Merge pull request #4142 from
 vicentebolea/fix-pugixml-dep

pugixml,cmake: fix linkage when pugixml is external
---
 source/adios2/toolkit/remote/CMakeLists.txt | 12 ++++--------
 source/utils/CMakeLists.txt                 |  8 +-------
 2 files changed, 5 insertions(+), 15 deletions(-)

diff --git a/source/adios2/toolkit/remote/CMakeLists.txt b/source/adios2/toolkit/remote/CMakeLists.txt
index 2128caa9a9..fdea6ec841 100644
--- a/source/adios2/toolkit/remote/CMakeLists.txt
+++ b/source/adios2/toolkit/remote/CMakeLists.txt
@@ -6,15 +6,11 @@
 if (NOT ADIOS2_USE_PIP)
   add_executable(adios2_remote_server ./remote_server.cpp remote_common.cpp)
 
-  target_link_libraries(adios2_remote_server PUBLIC EVPath::EVPath adios2_core adios2sys
-    PRIVATE $<$:shlwapi>)
+  target_link_libraries(adios2_remote_server
+                        PUBLIC EVPath::EVPath adios2_core adios2sys
+                        PRIVATE adios2::thirdparty::pugixml $<$:shlwapi>)
 
-  get_property(pugixml_headers_path
-    TARGET adios2::thirdparty::pugixml
-    PROPERTY INTERFACE_INCLUDE_DIRECTORIES
-  )
-
-  target_include_directories(adios2_remote_server PRIVATE ${PROJECT_BINARY_DIR} ${pugixml_headers_path})
+  target_include_directories(adios2_remote_server PRIVATE ${PROJECT_BINARY_DIR})
 
   set_property(TARGET adios2_remote_server PROPERTY OUTPUT_NAME adios2_remote_server${ADIOS2_EXECUTABLE_SUFFIX})
   install(TARGETS adios2_remote_server EXPORT adios2
diff --git a/source/utils/CMakeLists.txt b/source/utils/CMakeLists.txt
index 30dd48411f..01f5f93c34 100644
--- a/source/utils/CMakeLists.txt
+++ b/source/utils/CMakeLists.txt
@@ -13,17 +13,11 @@ configure_file(
 add_executable(bpls ./bpls/bpls.cpp)
 target_link_libraries(bpls
                       PUBLIC adios2_core adios2sys
-                      PRIVATE $<$:shlwapi>)
-
-get_property(pugixml_headers_path
-  TARGET pugixml
-  PROPERTY INTERFACE_INCLUDE_DIRECTORIES
-)
+                      PRIVATE adios2::thirdparty::pugixml $<$:shlwapi>)
 
 target_include_directories(bpls PRIVATE
   ${PROJECT_BINARY_DIR}
   ${PROJECT_SOURCE_DIR}/bindings/C
-  ${pugixml_headers_path}
 )
 
 set_property(TARGET bpls PROPERTY OUTPUT_NAME bpls${ADIOS2_EXECUTABLE_SUFFIX})

From e7660458d69ee1c0577177089e9dc364f2cc57a2 Mon Sep 17 00:00:00 2001
From: Greg Eisenhauer 
Date: Wed, 24 Apr 2024 14:47:04 -0400
Subject: [PATCH 08/18] ReadModeFlatten (#4147)

Add a new external mode for opening files, ReadFlattenSteps.  This is like ReadRandomAccess (in that it reads all metadata immediately and you can't use BeginStep), but it causes *all* the timesteps in the file to be Flattened into a single step, as if each Put() has been done in that step.
---
 bindings/C/adios2/c/adios2_c_engine.cpp       |    6 +
 bindings/C/adios2/c/adios2_c_io.h             |    8 +-
 bindings/C/adios2/c/adios2_c_io.tcc           |    4 +
 bindings/C/adios2/c/adios2_c_types.h          |    1 +
 .../adios2/cxx11/fstream/ADIOS2fstream.cpp    |    3 +
 .../adios2/cxx11/fstream/ADIOS2fstream.h      |    1 +
 .../Fortran/modules/adios2_parameters_mod.f90 |    1 +
 bindings/Python/py11glue.cpp                  |    1 +
 docs/user_guide/source/components/anatomy.rst |   47 +-
 python/adios2/stream.py                       |    3 +
 source/adios2/common/ADIOSTypes.h             |    1 +
 source/adios2/core/Engine.cpp                 |    3 +-
 source/adios2/core/Engine.tcc                 |    3 +-
 source/adios2/core/IO.cpp                     |   29 +-
 source/adios2/core/Stream.cpp                 |    6 +-
 source/adios2/engine/bp5/BP5Reader.cpp        |   35 +-
 .../toolkit/format/bp5/BP5Deserializer.cpp    |  503 ++++---
 .../toolkit/format/bp5/BP5Deserializer.h      |    4 +-
 source/adios2/toolkit/remote/Remote.cpp       |    3 +
 source/adios2/toolkit/remote/remote_common.h  |    1 +
 .../adios2/toolkit/remote/remote_server.cpp   |    4 +
 source/utils/bpls/bpls.cpp                    |   29 +-
 source/utils/bpls/bpls.h                      |    3 +-
 testing/adios2/engine/bp/CMakeLists.txt       |    2 +
 .../engine/bp/TestBPWriteReadFlatten.cpp      | 1338 +++++++++++++++++
 .../TestUtilsCWriter.bplsh.expected.txt       |    1 +
 26 files changed, 1786 insertions(+), 254 deletions(-)
 create mode 100644 testing/adios2/engine/bp/TestBPWriteReadFlatten.cpp

diff --git a/bindings/C/adios2/c/adios2_c_engine.cpp b/bindings/C/adios2/c/adios2_c_engine.cpp
index 1836893657..9d6cecf32f 100644
--- a/bindings/C/adios2/c/adios2_c_engine.cpp
+++ b/bindings/C/adios2/c/adios2_c_engine.cpp
@@ -34,6 +34,9 @@ adios2::Mode adios2_ToMode(const adios2_mode mode, const std::string &hint)
     case adios2_mode_readRandomAccess:
         modeCpp = adios2::Mode::ReadRandomAccess;
         break;
+    case adios2_mode_readFlattenSteps:
+        modeCpp = adios2::Mode::ReadFlattenSteps;
+        break;
     case adios2_mode_deferred:
         modeCpp = adios2::Mode::Deferred;
         break;
@@ -63,6 +66,9 @@ adios2_mode adios2_fromMode(const adios2::Mode mode, const std::string &hint)
     case adios2::Mode::ReadRandomAccess:
         modeC = adios2_mode_readRandomAccess;
         break;
+    case adios2::Mode::ReadFlattenSteps:
+        modeC = adios2_mode_readFlattenSteps;
+        break;
     case adios2::Mode::Deferred:
         modeC = adios2_mode_deferred;
         break;
diff --git a/bindings/C/adios2/c/adios2_c_io.h b/bindings/C/adios2/c/adios2_c_io.h
index 09fa10e256..a622328e38 100644
--- a/bindings/C/adios2/c/adios2_c_io.h
+++ b/bindings/C/adios2/c/adios2_c_io.h
@@ -329,8 +329,8 @@ adios2_error adios2_remove_all_attributes(adios2_io *io);
  * MPI Collective function as it calls MPI_Comm_dup
  * @param io engine owner
  * @param name unique engine identifier
- * @param mode adios2_mode_write, adios2_mode_read, adios2_mode_append, and
- * adios2_mode_readRandomAccess
+ * @param mode adios2_mode_write, adios2_mode_read, adios2_mode_append,
+ * adios2_mode_readRandomAccess and adios2_mode_readFlattenSteps
  * @return success: handler, failure: NULL
  */
 adios2_engine *adios2_open(adios2_io *io, const char *name, const adios2_mode mode);
@@ -341,8 +341,8 @@ adios2_engine *adios2_open(adios2_io *io, const char *name, const adios2_mode mo
  * MPI Collective function as it calls MPI_Comm_dup
  * @param io engine owner
  * @param name unique engine identifier
- * @param mode adios2_mode_write, adios2_mode_read, adios2_mode_append, and
- * adios2_mode_readRandomAccess
+ * @param mode adios2_mode_write, adios2_mode_read, adios2_mode_append,
+ * adios2_mode_readRandomAccess and adios2_mode_readFlattenSteps
  * @param comm communicator other than adios' handler comm. MPI only.
  * @return success: handler, failure: NULL
  */
diff --git a/bindings/C/adios2/c/adios2_c_io.tcc b/bindings/C/adios2/c/adios2_c_io.tcc
index 29607b87d8..9c9000cd44 100644
--- a/bindings/C/adios2/c/adios2_c_io.tcc
+++ b/bindings/C/adios2/c/adios2_c_io.tcc
@@ -36,6 +36,10 @@ adios2::Mode adios2_ToOpenMode(const adios2_mode modeC)
         mode = adios2::Mode::ReadRandomAccess;
         break;
 
+    case adios2_mode_readFlattenSteps:
+        mode = adios2::Mode::ReadFlattenSteps;
+        break;
+
     default:
         break;
     }
diff --git a/bindings/C/adios2/c/adios2_c_types.h b/bindings/C/adios2/c/adios2_c_types.h
index fb102df4cb..b28bc7f21e 100644
--- a/bindings/C/adios2/c/adios2_c_types.h
+++ b/bindings/C/adios2/c/adios2_c_types.h
@@ -103,6 +103,7 @@ typedef enum
     adios2_mode_read = 2,
     adios2_mode_append = 3,
     adios2_mode_readRandomAccess = 6,
+    adios2_mode_readFlattenSteps = 7,
 
     adios2_mode_deferred = 4,
     adios2_mode_sync = 5
diff --git a/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.cpp b/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.cpp
index 03b881e7fa..12d083beb2 100644
--- a/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.cpp
+++ b/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.cpp
@@ -89,6 +89,9 @@ adios2::Mode fstream::ToMode(const openmode mode) const noexcept
     case (openmode::in_random_access):
         modeCpp = adios2::Mode::ReadRandomAccess;
         break;
+    case (openmode::in_flatten_steps):
+        modeCpp = adios2::Mode::ReadFlattenSteps;
+        break;
     case (openmode::app):
         modeCpp = adios2::Mode::Append;
         break;
diff --git a/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.h b/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.h
index 546bf54ccb..d96a7a749b 100644
--- a/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.h
+++ b/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.h
@@ -48,6 +48,7 @@ class fstream
         out,              //!< write
         in,               //!< read
         in_random_access, //!< read_random_access
+        in_flatten_steps, //!< flatten all input steps to 1
         app               //!< append, not yet supported
     };
 
diff --git a/bindings/Fortran/modules/adios2_parameters_mod.f90 b/bindings/Fortran/modules/adios2_parameters_mod.f90
index bf0dd18c9b..f73561702e 100644
--- a/bindings/Fortran/modules/adios2_parameters_mod.f90
+++ b/bindings/Fortran/modules/adios2_parameters_mod.f90
@@ -56,6 +56,7 @@ module adios2_parameters_mod
    integer, parameter :: adios2_mode_read = 2
    integer, parameter :: adios2_mode_append = 3
    integer, parameter :: adios2_mode_readRandomAccess = 6
+   integer, parameter :: adios2_mode_readFlattenSteps = 7
 
    integer, parameter :: adios2_mode_deferred = 4
    integer, parameter :: adios2_mode_sync = 5
diff --git a/bindings/Python/py11glue.cpp b/bindings/Python/py11glue.cpp
index 18f3a6eb27..c474b8b53c 100644
--- a/bindings/Python/py11glue.cpp
+++ b/bindings/Python/py11glue.cpp
@@ -99,6 +99,7 @@ PYBIND11_MODULE(ADIOS2_PYTHON_MODULE_NAME, m)
         .value("Write", adios2::Mode::Write)
         .value("Read", adios2::Mode::Read)
         .value("ReadRandomAccess", adios2::Mode::ReadRandomAccess)
+        .value("ReadFlattenSteps", adios2::Mode::ReadFlattenSteps)
         .value("Append", adios2::Mode::Append)
         .value("Deferred", adios2::Mode::Deferred)
         .value("Sync", adios2::Mode::Sync)
diff --git a/docs/user_guide/source/components/anatomy.rst b/docs/user_guide/source/components/anatomy.rst
index 0832b6dc3c..2aa8c7f89a 100644
--- a/docs/user_guide/source/components/anatomy.rst
+++ b/docs/user_guide/source/components/anatomy.rst
@@ -114,7 +114,10 @@ named `adios2::Mode::ReadRandomAccess`. `adios2::Mode::Read` mode allows data ac
 current timestep. `ReadRandomAccess` can only be used with file engines and involves loading all the file metadata at
 once. So it can be more memory intensive than `adios2::Mode::Read` mode, but allows reading data from any timestep using
 `SetStepSelection()`. If you use `adios2::Mode::ReadRandomAccess` mode, be sure to allocate enough memory to hold
-multiple steps of the variable content.
+multiple steps of the variable content.  Note that ADIOS streaming
+engines (like SST, DataMan, etc.) do not support `ReadRandomAccess`
+mode.  Also newer file Engines like BP5 to not allow
+`BeginStep/EndStep` calls in `ReadRandomAccess` mode.
 
 .. code:: C++
 
@@ -134,3 +137,45 @@ multiple steps of the variable content.
     |   |--> IO goes out of scope
     |
     |--> ADIOS goes out of scope or adios2_finalize()
+
+Previously we explored how to read using the input mode `adios2::Mode::Read`. Nonetheless, ADIOS has another input mode
+named `adios2::Mode::ReadRandomAccess`. `adios2::Mode::Read` mode allows data access only timestep by timestep using
+`BeginStep/EndStep`, but generally it is more memory efficient as ADIOS is only required to load metadata for the
+current timestep. `ReadRandomAccess` can only be used with file engines and involves loading all the file metadata at
+once. So it can be more memory intensive than `adios2::Mode::Read` mode, but allows reading data from any timestep using
+`SetStepSelection()`. If you use `adios2::Mode::ReadRandomAccess` mode, be sure to allocate enough memory to hold
+multiple steps of the variable content.  Note that ADIOS streaming
+engines (like SST, DataMan, etc.) do not support `ReadRandomAccess`
+mode.  Also newer file Engines like BP5 to not allow
+`BeginStep/EndStep` calls in `ReadRandomAccess` mode.
+
+.. code:: C++
+
+    ADIOS adios("config.xml", MPI_COMM_WORLD);
+    |
+    |   IO io = adios.DeclareIO(...);
+    |   |
+    |   |   Engine e = io.Open("InputFileName.bp", adios2::Mode::ReadRandomAccess);
+    |   |   |
+    |   |   |   Variable var = io.InquireVariable(...)
+    |   |   |   |   var.SetStepSelection()
+    |   |   |   |   e.Get(var, datapointer);
+    |   |   |   |
+    |   |   |
+    |   |   e.Close();
+    |   |
+    |   |--> IO goes out of scope
+    |
+    |--> ADIOS goes out of scope or adios2_finalize()
+    
+
+In addition to the two read modes discussed above, ADIOS has another
+input mode named `adios2::Mode::ReadFlattenSteps`. This is a highly
+specialized mode built that is unlikely to be of general utility, but
+we describe it for completeness.  In `ReadFlattenSteps` mode, ADIOS
+loads all the metadata in the file upon Open (just like
+`ReadRandomAccess` mode, but everything that was written appears that
+it was output on the same step, regardless of how many steps actually
+appear in the file.  This affects the operation of many reader-side
+ADIOS functions, including Steps(), BlocksInfo(), Get(), etc.
+
diff --git a/python/adios2/stream.py b/python/adios2/stream.py
index 58a9c09050..33753604cd 100644
--- a/python/adios2/stream.py
+++ b/python/adios2/stream.py
@@ -43,6 +43,9 @@ def string_to_mode(mode: str) -> [bindings.Mode, bool]:
     elif mode == "rra":
         bmode = bindings.Mode.ReadRandomAccess
         read_mode = True
+    elif mode == "rfs":
+        bmode = bindings.Mode.ReadFlattenSteps
+        read_mode = True
     elif mode == "w":
         bmode = bindings.Mode.Write
     elif mode == "a":
diff --git a/source/adios2/common/ADIOSTypes.h b/source/adios2/common/ADIOSTypes.h
index fad51e8fd9..111ebe4a1d 100644
--- a/source/adios2/common/ADIOSTypes.h
+++ b/source/adios2/common/ADIOSTypes.h
@@ -80,6 +80,7 @@ enum class Mode
     Read,
     Append,
     ReadRandomAccess, // reader random access mode
+    ReadFlattenSteps, // reader flatten steps to one
     // launch execution modes
     Sync,
     Deferred
diff --git a/source/adios2/core/Engine.cpp b/source/adios2/core/Engine.cpp
index 72ab54d4ac..56e6f02c08 100644
--- a/source/adios2/core/Engine.cpp
+++ b/source/adios2/core/Engine.cpp
@@ -135,7 +135,8 @@ void Engine::Put(VariableStruct &variable, const void *data, const Mode launch)
 
 void Engine::Get(VariableStruct &variable, void *data, const Mode launch)
 {
-    CommonChecks(variable, data, {Mode::Read, Mode::ReadRandomAccess}, "in call to Get");
+    CommonChecks(variable, data, {Mode::Read, Mode::ReadRandomAccess, Mode::ReadFlattenSteps},
+                 "in call to Get");
 
     switch (launch)
     {
diff --git a/source/adios2/core/Engine.tcc b/source/adios2/core/Engine.tcc
index b06050b86c..656b2fc30a 100644
--- a/source/adios2/core/Engine.tcc
+++ b/source/adios2/core/Engine.tcc
@@ -87,7 +87,8 @@ void Engine::Put(const std::string &variableName, const T &datum, const Mode /*l
 template 
 void Engine::Get(Variable &variable, T *data, const Mode launch)
 {
-    CommonChecks(variable, data, {Mode::Read, Mode::ReadRandomAccess}, "in call to Get");
+    CommonChecks(variable, data, {Mode::Read, Mode::ReadRandomAccess, Mode::ReadFlattenSteps},
+                 "in call to Get");
 
     switch (launch)
     {
diff --git a/source/adios2/core/IO.cpp b/source/adios2/core/IO.cpp
index 83bf0f3781..eaf4394351 100644
--- a/source/adios2/core/IO.cpp
+++ b/source/adios2/core/IO.cpp
@@ -150,6 +150,14 @@ const std::unordered_map ReadRandomAccess_Supported = {
     {"campaign", true},
 };
 
+const std::unordered_map ReadFlattenSteps_Supported = {
+    {"bp3", false},     {"bp4", false},        {"bp5", true},      {"dataman", false},
+    {"ssc", false},     {"mhs", false},        {"sst", false},     {"daos", false},
+    {"effis", false},   {"dataspaces", false}, {"hdf5", false},    {"skeleton", false},
+    {"inline", false},  {"null", true},        {"nullcore", true}, {"plugin", false},
+    {"campaign", true},
+};
+
 // Synchronize access to the factory in case one thread is
 // looking up while another registers additional entries.
 std::mutex FactoryMutex;
@@ -560,7 +568,8 @@ Engine &IO::Open(const std::string &name, const Mode mode, helper::Comm comm)
         {
             engineTypeLC = "campaign";
         }
-        else if ((mode_to_use == Mode::Read) || (mode_to_use == Mode::ReadRandomAccess))
+        else if ((mode_to_use == Mode::Read) || (mode_to_use == Mode::ReadRandomAccess) ||
+                 (mode_to_use == Mode::ReadFlattenSteps))
         {
             if (adios2sys::SystemTools::FileIsDirectory(name))
             {
@@ -668,10 +677,26 @@ Engine &IO::Open(const std::string &name, const Mode mode, helper::Comm comm)
         }
     }
 
+    if (mode_to_use == Mode::ReadFlattenSteps)
+    {
+        // older engines don't know about ReadFlattenSteps Mode, throw an exception
+        auto it = ReadFlattenSteps_Supported.find(engineTypeLC);
+        if (it != ReadFlattenSteps_Supported.end())
+        {
+            if (!it->second)
+            {
+                helper::Throw("Core", "IO", "Open",
+                                                  "Engine " + engineTypeLC +
+                                                      " doesn't support ReadFlattenSteps mode");
+            }
+        }
+    }
+
     auto f = FactoryLookup(engineTypeLC);
     if (f != Factory.end())
     {
-        if ((mode_to_use == Mode::Read) || (mode_to_use == Mode::ReadRandomAccess))
+        if ((mode_to_use == Mode::Read) || (mode_to_use == Mode::ReadRandomAccess) ||
+            (mode_to_use == Mode::ReadFlattenSteps))
         {
             engine = f->second.MakeReader(*this, name, mode_to_use, std::move(comm));
         }
diff --git a/source/adios2/core/Stream.cpp b/source/adios2/core/Stream.cpp
index 43abacc703..2b923886ae 100644
--- a/source/adios2/core/Stream.cpp
+++ b/source/adios2/core/Stream.cpp
@@ -23,7 +23,8 @@ Stream::Stream(const std::string &name, const Mode mode, helper::Comm comm,
 : m_ADIOS(std::make_shared(std::move(comm), hostLanguage)), m_IO(&m_ADIOS->DeclareIO(name)),
   m_Name(name), m_Mode(mode), m_EngineType(engineType)
 {
-    if ((mode == adios2::Mode::Read) || (mode == adios2::Mode::ReadRandomAccess))
+    if ((mode == adios2::Mode::Read) || (mode == adios2::Mode::ReadRandomAccess) ||
+        (mode == adios2::Mode::ReadFlattenSteps))
     {
         CheckOpen();
     }
@@ -41,7 +42,8 @@ Stream::Stream(const std::string &name, const Mode mode, helper::Comm comm,
 : m_ADIOS(std::make_shared(configFile, std::move(comm), hostLanguage)),
   m_IO(&m_ADIOS->DeclareIO(ioInConfigFile)), m_Name(name), m_Mode(mode)
 {
-    if ((mode == adios2::Mode::Read) || (mode == adios2::Mode::ReadRandomAccess))
+    if ((mode == adios2::Mode::Read) || (mode == adios2::Mode::ReadRandomAccess) ||
+        (mode == adios2::Mode::ReadFlattenSteps))
     {
         CheckOpen();
     }
diff --git a/source/adios2/engine/bp5/BP5Reader.cpp b/source/adios2/engine/bp5/BP5Reader.cpp
index e8fba5f3f3..8fe5d68201 100644
--- a/source/adios2/engine/bp5/BP5Reader.cpp
+++ b/source/adios2/engine/bp5/BP5Reader.cpp
@@ -72,7 +72,7 @@ void BP5Reader::InstallMetadataForTimestep(size_t Step)
         size_t ThisMDSize =
             helper::ReadValue(m_Metadata.Data(), Position, m_Minifooter.IsLittleEndian);
         char *ThisMD = m_Metadata.Data() + MDPosition;
-        if (m_OpenMode == Mode::ReadRandomAccess)
+        if ((m_OpenMode == Mode::ReadRandomAccess) || (m_OpenMode == Mode::ReadFlattenSteps))
         {
             m_BP5Deserializer->InstallMetaData(ThisMD, ThisMDSize, WriterRank, Step);
         }
@@ -98,7 +98,7 @@ StepStatus BP5Reader::BeginStep(StepMode mode, const float timeoutSeconds)
 {
     PERFSTUBS_SCOPED_TIMER("BP5Reader::BeginStep");
 
-    if (m_OpenMode == Mode::ReadRandomAccess)
+    if (m_OpenMode != Mode::Read)
     {
         helper::Throw("Engine", "BP5Reader", "BeginStep",
                                         "BeginStep called in random access mode");
@@ -184,7 +184,7 @@ size_t BP5Reader::CurrentStep() const { return m_CurrentStep; }
 
 void BP5Reader::EndStep()
 {
-    if (m_OpenMode == Mode::ReadRandomAccess)
+    if (m_OpenMode != Mode::Read)
     {
         helper::Throw("Engine", "BP5Reader", "EndStep",
                                         "EndStep called in random access mode");
@@ -475,12 +475,14 @@ void BP5Reader::PerformLocalGets()
 // PRIVATE
 void BP5Reader::Init()
 {
-    if ((m_OpenMode != Mode::Read) && (m_OpenMode != Mode::ReadRandomAccess))
+    if ((m_OpenMode != Mode::Read) && (m_OpenMode != Mode::ReadRandomAccess) &&
+        (m_OpenMode != Mode::ReadFlattenSteps))
     {
-        helper::Throw("Engine", "BP5Reader", "Init",
-                                             "BPFileReader only supports OpenMode::Read or "
-                                             "OpenMode::ReadRandomAccess from" +
-                                                 m_Name);
+        helper::Throw(
+            "Engine", "BP5Reader", "Init",
+            "BPFileReader only supports OpenMode::Read, "
+            "OpenMode::ReadRandomAccess, or OpenMode::ReadFlattenSteps from" +
+                m_Name);
     }
 
     // if IO was involved in reading before this flag may be true now
@@ -519,7 +521,7 @@ void BP5Reader::InitParameters()
     ParseParams(m_IO, m_Parameters);
     if (m_Parameters.OpenTimeoutSecs < 0.0f)
     {
-        if (m_OpenMode == Mode::ReadRandomAccess)
+        if ((m_OpenMode == Mode::ReadRandomAccess) || (m_OpenMode == Mode::ReadFlattenSteps))
         {
             m_Parameters.OpenTimeoutSecs = 0.0f;
         }
@@ -803,7 +805,8 @@ void BP5Reader::UpdateBuffer(const TimePoint &timeoutInstant, const Seconds &pol
         if (!m_BP5Deserializer)
         {
             m_BP5Deserializer = new format::BP5Deserializer(m_WriterIsRowMajor, m_ReaderIsRowMajor,
-                                                            (m_OpenMode == Mode::ReadRandomAccess));
+                                                            (m_OpenMode != Mode::Read),
+                                                            (m_OpenMode == Mode::ReadFlattenSteps));
             m_BP5Deserializer->m_Engine = this;
         }
     }
@@ -900,7 +903,7 @@ void BP5Reader::UpdateBuffer(const TimePoint &timeoutInstant, const Seconds &pol
 
         m_Comm.Bcast(m_Metadata.Data(), inputSize, 0);
 
-        if (m_OpenMode == Mode::ReadRandomAccess)
+        if ((m_OpenMode == Mode::ReadRandomAccess) || (m_OpenMode == Mode::ReadFlattenSteps))
         {
             for (size_t Step = 0; Step < m_MetadataIndexTable.size(); Step++)
             {
@@ -1245,7 +1248,7 @@ void BP5Reader::DoGetStructDeferred(VariableStruct &variable, void *data)
 void BP5Reader::DoClose(const int transportIndex)
 {
     PERFSTUBS_SCOPED_TIMER("BP5Reader::Close");
-    if (m_OpenMode == Mode::ReadRandomAccess)
+    if ((m_OpenMode == Mode::ReadRandomAccess) || (m_OpenMode == Mode::ReadFlattenSteps))
     {
         PerformGets();
     }
@@ -1306,7 +1309,13 @@ void BP5Reader::FlushProfiler()
     }
 }
 
-size_t BP5Reader::DoSteps() const { return m_StepsCount; }
+size_t BP5Reader::DoSteps() const
+{
+    if (m_OpenMode == Mode::ReadFlattenSteps)
+        return 1;
+    else
+        return m_StepsCount;
+}
 
 void BP5Reader::NotifyEngineNoVarsQuery()
 {
diff --git a/source/adios2/toolkit/format/bp5/BP5Deserializer.cpp b/source/adios2/toolkit/format/bp5/BP5Deserializer.cpp
index f78f554c9d..5d5940f256 100644
--- a/source/adios2/toolkit/format/bp5/BP5Deserializer.cpp
+++ b/source/adios2/toolkit/format/bp5/BP5Deserializer.cpp
@@ -980,7 +980,13 @@ void BP5Deserializer::InstallMetaData(void *MetadataBlock, size_t BlockLen, size
             {
                 VarRec->FirstTSSeen = Step;
             }
-            if (m_RandomAccessMode && (VarRec->LastTSAdded != Step))
+            if (m_FlattenSteps)
+            {
+                static_cast(VarRec->Variable)->m_AvailableStepsCount = 1;
+                VarRec->LastTSAdded = 0;
+                VarRec->FirstTSSeen = 0;
+            }
+            else if (m_RandomAccessMode && (VarRec->LastTSAdded != Step))
             {
                 static_cast(VarRec->Variable)->m_AvailableStepsCount++;
                 VarRec->LastTSAdded = Step;
@@ -1545,198 +1551,223 @@ BP5Deserializer::GenerateReadRequests(const bool doAllocTempBuffers, size_t *max
 {
     std::vector Ret;
     *maxReadSize = 0;
+    size_t StepLoopStart, StepLoopEnd;
 
     for (size_t ReqIndex = 0; ReqIndex < PendingGetRequests.size(); ReqIndex++)
     {
         auto Req = &PendingGetRequests[ReqIndex];
         auto VarRec = (struct BP5VarRec *)Req->VarRec;
         VariableBase *VB = static_cast(VarRec->Variable);
+        if (m_FlattenSteps)
+        {
+            StepLoopStart = 0;
+            StepLoopEnd = m_ControlArray.size();
+        }
+        else
+        {
+            StepLoopStart = Req->Step;
+            StepLoopEnd = Req->Step + 1;
+        }
+
         if (Req->RequestType == Local)
         {
-            const size_t writerCohortSize = WriterCohortSize(Req->Step);
             size_t NodeFirstBlock = 0;
-            for (size_t WriterRank = 0; WriterRank < writerCohortSize; WriterRank++)
+            for (size_t Step = StepLoopStart; Step < StepLoopEnd; Step++)
             {
-                MetaArrayRecOperator *writer_meta_base = (MetaArrayRecOperator *)GetMetadataBase(
-                    (struct BP5VarRec *)Req->VarRec, Req->Step, WriterRank);
-                if (!writer_meta_base)
+                const size_t writerCohortSize = WriterCohortSize(Step);
+                for (size_t WriterRank = 0; WriterRank < writerCohortSize; WriterRank++)
                 {
-                    continue; // Not writen on this step
-                }
-                size_t NodeLastBlock = NodeFirstBlock + writer_meta_base->BlockCount - 1;
-                if ((NodeFirstBlock <= Req->BlockID) && (NodeLastBlock >= Req->BlockID))
-                {
-                    // block is here
-                    size_t NeededBlock = Req->BlockID - NodeFirstBlock;
-                    size_t StartDim = NeededBlock * VarRec->DimCount;
-                    ReadRequest RR;
-                    RR.Timestep = Req->Step;
-                    RR.WriterRank = WriterRank;
-                    RR.StartOffset = writer_meta_base->DataBlockLocation[NeededBlock];
-                    if (RR.StartOffset == (size_t)-1)
-                        throw std::runtime_error("No data exists for this variable");
-                    if (Req->MemSpace != MemorySpace::Host)
-                        RR.DirectToAppMemory = false;
-                    else if (VarRec->Operator != NULL)
-                        RR.DirectToAppMemory = false;
-                    else
-                        RR.DirectToAppMemory =
-                            IsContiguousTransfer(Req, &writer_meta_base->Offsets[StartDim],
-                                                 &writer_meta_base->Count[StartDim]);
-                    if (VarRec->Operator)
-                    {
-                        // have to have the whole thing
-                        RR.ReadLength = writer_meta_base->DataBlockSize[NeededBlock];
-                    }
-                    else
+                    MetaArrayRecOperator *writer_meta_base =
+                        (MetaArrayRecOperator *)GetMetadataBase((struct BP5VarRec *)Req->VarRec,
+                                                                Step, WriterRank);
+                    if (!writer_meta_base)
                     {
-                        RR.ReadLength =
-                            helper::GetDataTypeSize(VarRec->Type) *
-                            CalcBlockLength(VarRec->DimCount, &writer_meta_base->Count[StartDim]);
+                        continue; // Not writen on this step
                     }
-                    RR.OffsetInBlock = 0;
-                    if (RR.DirectToAppMemory)
+                    size_t NodeLastBlock = NodeFirstBlock + writer_meta_base->BlockCount - 1;
+                    if ((NodeFirstBlock <= Req->BlockID) && (NodeLastBlock >= Req->BlockID))
                     {
-                        RR.DestinationAddr = (char *)Req->Data;
-                        if (Req->Start.size() != 0)
+                        // block is here
+                        size_t NeededBlock = Req->BlockID - NodeFirstBlock;
+                        size_t StartDim = NeededBlock * VarRec->DimCount;
+                        ReadRequest RR;
+                        RR.Timestep = Req->Step;
+                        RR.WriterRank = WriterRank;
+                        RR.StartOffset = writer_meta_base->DataBlockLocation[NeededBlock];
+                        if (RR.StartOffset == (size_t)-1)
+                            throw std::runtime_error("No data exists for this variable");
+                        if (Req->MemSpace != MemorySpace::Host)
+                            RR.DirectToAppMemory = false;
+                        else if (VarRec->Operator != NULL)
+                            RR.DirectToAppMemory = false;
+                        else
+                            RR.DirectToAppMemory =
+                                IsContiguousTransfer(Req, &writer_meta_base->Offsets[StartDim],
+                                                     &writer_meta_base->Count[StartDim]);
+                        if (VarRec->Operator)
+                        {
+                            // have to have the whole thing
+                            RR.ReadLength = writer_meta_base->DataBlockSize[NeededBlock];
+                        }
+                        else
                         {
                             RR.ReadLength = helper::GetDataTypeSize(VarRec->Type) *
-                                            CalcBlockLength(VarRec->DimCount, Req->Count.data());
-                            /* DirectToAppMemory handles only 1D, so offset calc
-                             * is 1D only for the moment */
-                            RR.StartOffset += helper::GetDataTypeSize(VarRec->Type) * Req->Start[0];
+                                            CalcBlockLength(VarRec->DimCount,
+                                                            &writer_meta_base->Count[StartDim]);
                         }
-                    }
-                    else
-                    {
-                        RR.DestinationAddr = nullptr;
-                        if (doAllocTempBuffers)
+                        RR.OffsetInBlock = 0;
+                        if (RR.DirectToAppMemory)
                         {
-                            RR.DestinationAddr = (char *)malloc(RR.ReadLength);
+                            RR.DestinationAddr = (char *)Req->Data;
+                            if (Req->Start.size() != 0)
+                            {
+                                RR.ReadLength =
+                                    helper::GetDataTypeSize(VarRec->Type) *
+                                    CalcBlockLength(VarRec->DimCount, Req->Count.data());
+                                /* DirectToAppMemory handles only 1D, so offset calc
+                                 * is 1D only for the moment */
+                                RR.StartOffset +=
+                                    helper::GetDataTypeSize(VarRec->Type) * Req->Start[0];
+                            }
                         }
-                        *maxReadSize =
-                            (*maxReadSize < RR.ReadLength ? RR.ReadLength : *maxReadSize);
+                        else
+                        {
+                            RR.DestinationAddr = nullptr;
+                            if (doAllocTempBuffers)
+                            {
+                                RR.DestinationAddr = (char *)malloc(RR.ReadLength);
+                            }
+                            *maxReadSize =
+                                (*maxReadSize < RR.ReadLength ? RR.ReadLength : *maxReadSize);
+                        }
+                        RR.ReqIndex = ReqIndex;
+                        RR.BlockID = NeededBlock;
+                        Ret.push_back(RR);
+                        break;
                     }
-                    RR.ReqIndex = ReqIndex;
-                    RR.BlockID = NeededBlock;
-                    Ret.push_back(RR);
-                    break;
+                    NodeFirstBlock += writer_meta_base->BlockCount;
                 }
-                NodeFirstBlock += writer_meta_base->BlockCount;
             }
         }
         else
         {
             /* global case */
-            const size_t writerCohortSize = WriterCohortSize(Req->Step);
-            for (size_t WriterRank = 0; WriterRank < writerCohortSize; WriterRank++)
+            for (size_t Step = StepLoopStart; Step < StepLoopEnd; Step++)
             {
-                MetaArrayRecOperator *writer_meta_base = (MetaArrayRecOperator *)GetMetadataBase(
-                    (struct BP5VarRec *)Req->VarRec, Req->Step, WriterRank);
-                if (!writer_meta_base)
-                    continue; // Not writen on this step
-
-                for (size_t Block = 0; Block < writer_meta_base->BlockCount; Block++)
+                const size_t writerCohortSize = WriterCohortSize(Step);
+                for (size_t WriterRank = 0; WriterRank < writerCohortSize; WriterRank++)
                 {
-                    std::array intersectionstart;
-                    std::array intersectionend;
-                    std::array intersectioncount;
-
-                    size_t StartDim = Block * VarRec->DimCount;
-                    if (IntersectionStartCount(VarRec->DimCount, Req->Start.data(),
-                                               Req->Count.data(),
-                                               &writer_meta_base->Offsets[StartDim],
-                                               &writer_meta_base->Count[StartDim],
-                                               &intersectionstart[0], &intersectioncount[0]))
+                    MetaArrayRecOperator *writer_meta_base =
+                        (MetaArrayRecOperator *)GetMetadataBase((struct BP5VarRec *)Req->VarRec,
+                                                                Step, WriterRank);
+                    if (!writer_meta_base)
+                        continue; // Not writen on this step
+
+                    for (size_t Block = 0; Block < writer_meta_base->BlockCount; Block++)
                     {
-                        if (VarRec->Operator != NULL)
-                        {
-                            // need the whole thing for decompression anyway
-                            ReadRequest RR;
-                            RR.Timestep = Req->Step;
-                            RR.WriterRank = WriterRank;
-                            RR.StartOffset = writer_meta_base->DataBlockLocation[Block];
-                            RR.ReadLength = writer_meta_base->DataBlockSize[Block];
-                            RR.DestinationAddr = nullptr;
-                            if (RR.StartOffset == (size_t)-1)
-                                throw std::runtime_error("No data exists for this variable");
-                            if (doAllocTempBuffers)
-                            {
-                                RR.DestinationAddr = (char *)malloc(RR.ReadLength);
-                            }
-                            *maxReadSize =
-                                (*maxReadSize < RR.ReadLength ? RR.ReadLength : *maxReadSize);
-                            RR.DirectToAppMemory = false;
-                            RR.ReqIndex = ReqIndex;
-                            RR.BlockID = Block;
-                            RR.OffsetInBlock = 0;
-                            Ret.push_back(RR);
-                        }
-                        else
+                        std::array intersectionstart;
+                        std::array intersectionend;
+                        std::array intersectioncount;
+
+                        size_t StartDim = Block * VarRec->DimCount;
+                        if (IntersectionStartCount(VarRec->DimCount, Req->Start.data(),
+                                                   Req->Count.data(),
+                                                   &writer_meta_base->Offsets[StartDim],
+                                                   &writer_meta_base->Count[StartDim],
+                                                   &intersectionstart[0], &intersectioncount[0]))
                         {
-                            for (size_t Dim = 0; Dim < VarRec->DimCount; Dim++)
-                            {
-                                intersectionstart[Dim] -= writer_meta_base->Offsets[StartDim + Dim];
-                            }
-                            size_t StartOffsetInBlock =
-                                VB->m_ElementSize *
-                                LinearIndex(VarRec->DimCount, &writer_meta_base->Count[StartDim],
-                                            &intersectionstart[0], m_ReaderIsRowMajor);
-                            for (size_t Dim = 0; Dim < VarRec->DimCount; Dim++)
-                            {
-                                intersectionend[Dim] =
-                                    intersectionstart[Dim] + intersectioncount[Dim] - 1;
-                            }
-                            size_t EndOffsetInBlock =
-                                VB->m_ElementSize *
-                                (LinearIndex(VarRec->DimCount, &writer_meta_base->Count[StartDim],
-                                             &intersectionend[0], m_ReaderIsRowMajor) +
-                                 1);
-                            ReadRequest RR;
-                            RR.Timestep = Req->Step;
-                            RR.WriterRank = WriterRank;
-                            RR.StartOffset =
-                                writer_meta_base->DataBlockLocation[Block] + StartOffsetInBlock;
-                            if (writer_meta_base->DataBlockLocation[Block] == (size_t)-1)
-                                throw std::runtime_error("No data exists for this variable");
-                            RR.ReadLength = EndOffsetInBlock - StartOffsetInBlock;
-                            if (Req->MemSpace != MemorySpace::Host)
-                                RR.DirectToAppMemory = false;
-                            else
-                                RR.DirectToAppMemory =
-                                    IsContiguousTransfer(Req, &writer_meta_base->Offsets[StartDim],
-                                                         &writer_meta_base->Count[StartDim]);
-                            if (RR.DirectToAppMemory)
-                            {
-                                /*
-                                 * DirectToAppMemory handles only 1D, so offset
-                                 * calc is 1D only for the moment ContigOffset
-                                 * handles the case where our destination is not
-                                 * the start of the destination memory (because
-                                 * some other block filled in that start)
-                                 */
-
-                                ssize_t ContigOffset =
-                                    (writer_meta_base->Offsets[StartDim + 0] - Req->Start[0]) *
-                                    VB->m_ElementSize;
-                                if (ContigOffset < 0)
-                                    ContigOffset = 0;
-                                RR.DestinationAddr = (char *)Req->Data + ContigOffset;
-                            }
-                            else
+                            if (VarRec->Operator != NULL)
                             {
+                                // need the whole thing for decompression anyway
+                                ReadRequest RR;
+                                RR.Timestep = Step;
+                                RR.WriterRank = WriterRank;
+                                RR.StartOffset = writer_meta_base->DataBlockLocation[Block];
+                                RR.ReadLength = writer_meta_base->DataBlockSize[Block];
                                 RR.DestinationAddr = nullptr;
+                                if (RR.StartOffset == (size_t)-1)
+                                    throw std::runtime_error("No data exists for this variable");
                                 if (doAllocTempBuffers)
                                 {
                                     RR.DestinationAddr = (char *)malloc(RR.ReadLength);
                                 }
                                 *maxReadSize =
                                     (*maxReadSize < RR.ReadLength ? RR.ReadLength : *maxReadSize);
+                                RR.DirectToAppMemory = false;
+                                RR.ReqIndex = ReqIndex;
+                                RR.BlockID = Block;
+                                RR.OffsetInBlock = 0;
+                                Ret.push_back(RR);
+                            }
+                            else
+                            {
+                                for (size_t Dim = 0; Dim < VarRec->DimCount; Dim++)
+                                {
+                                    intersectionstart[Dim] -=
+                                        writer_meta_base->Offsets[StartDim + Dim];
+                                }
+                                size_t StartOffsetInBlock =
+                                    VB->m_ElementSize *
+                                    LinearIndex(VarRec->DimCount,
+                                                &writer_meta_base->Count[StartDim],
+                                                &intersectionstart[0], m_ReaderIsRowMajor);
+                                for (size_t Dim = 0; Dim < VarRec->DimCount; Dim++)
+                                {
+                                    intersectionend[Dim] =
+                                        intersectionstart[Dim] + intersectioncount[Dim] - 1;
+                                }
+                                size_t EndOffsetInBlock =
+                                    VB->m_ElementSize *
+                                    (LinearIndex(VarRec->DimCount,
+                                                 &writer_meta_base->Count[StartDim],
+                                                 &intersectionend[0], m_ReaderIsRowMajor) +
+                                     1);
+                                ReadRequest RR;
+                                RR.Timestep = Step;
+                                RR.WriterRank = WriterRank;
+                                RR.StartOffset =
+                                    writer_meta_base->DataBlockLocation[Block] + StartOffsetInBlock;
+                                if (writer_meta_base->DataBlockLocation[Block] == (size_t)-1)
+                                    throw std::runtime_error("No data exists for this variable");
+                                RR.ReadLength = EndOffsetInBlock - StartOffsetInBlock;
+                                if (Req->MemSpace != MemorySpace::Host)
+                                    RR.DirectToAppMemory = false;
+                                else
+                                    RR.DirectToAppMemory = IsContiguousTransfer(
+                                        Req, &writer_meta_base->Offsets[StartDim],
+                                        &writer_meta_base->Count[StartDim]);
+                                if (RR.DirectToAppMemory)
+                                {
+                                    /*
+                                     * DirectToAppMemory handles only 1D, so offset
+                                     * calc is 1D only for the moment ContigOffset
+                                     * handles the case where our destination is not
+                                     * the start of the destination memory (because
+                                     * some other block filled in that start)
+                                     */
+
+                                    ssize_t ContigOffset =
+                                        (writer_meta_base->Offsets[StartDim + 0] - Req->Start[0]) *
+                                        VB->m_ElementSize;
+                                    if (ContigOffset < 0)
+                                        ContigOffset = 0;
+                                    RR.DestinationAddr = (char *)Req->Data + ContigOffset;
+                                }
+                                else
+                                {
+                                    RR.DestinationAddr = nullptr;
+                                    if (doAllocTempBuffers)
+                                    {
+                                        RR.DestinationAddr = (char *)malloc(RR.ReadLength);
+                                    }
+                                    *maxReadSize = (*maxReadSize < RR.ReadLength ? RR.ReadLength
+                                                                                 : *maxReadSize);
+                                }
+                                RR.OffsetInBlock = StartOffsetInBlock;
+                                RR.ReqIndex = ReqIndex;
+                                RR.BlockID = Block;
+                                Ret.push_back(RR);
                             }
-                            RR.OffsetInBlock = StartOffsetInBlock;
-                            RR.ReqIndex = ReqIndex;
-                            RR.BlockID = Block;
-                            Ret.push_back(RR);
                         }
                     }
                 }
@@ -1756,7 +1787,7 @@ void BP5Deserializer::FinalizeGet(const ReadRequest &Read, const bool freeAddr)
 
     int ElementSize = ((struct BP5VarRec *)Req.VarRec)->ElementSize;
     MetaArrayRec *writer_meta_base = (MetaArrayRec *)GetMetadataBase(
-        ((struct BP5VarRec *)Req.VarRec), Req.Step, Read.WriterRank);
+        ((struct BP5VarRec *)Req.VarRec), Read.Timestep, Read.WriterRank);
 
     size_t *GlobalDimensions = writer_meta_base->Shape;
     auto DimCount = writer_meta_base->Dims;
@@ -1966,9 +1997,9 @@ int BP5Deserializer::FindOffset(size_t Dims, const size_t *Size, const size_t *I
  */
 
 BP5Deserializer::BP5Deserializer(bool WriterIsRowMajor, bool ReaderIsRowMajor,
-                                 bool RandomAccessMode)
+                                 bool RandomAccessMode, bool FlattenSteps)
 : m_WriterIsRowMajor{WriterIsRowMajor}, m_ReaderIsRowMajor{ReaderIsRowMajor},
-  m_RandomAccessMode{RandomAccessMode}
+  m_RandomAccessMode{RandomAccessMode}, m_FlattenSteps{FlattenSteps}
 {
     FMContext Tmp = create_local_FMcontext();
     ReaderFFSContext = create_FFSContext_FM(Tmp);
@@ -2065,17 +2096,57 @@ void *BP5Deserializer::GetMetadataBase(BP5VarRec *VarRec, size_t Step, size_t Wr
 
 MinVarInfo *BP5Deserializer::MinBlocksInfo(const VariableBase &Var, size_t RelStep)
 {
+    auto PossiblyAddValueBlocks = [this](MinVarInfo *MV, BP5VarRec *VarRec, size_t &Id,
+                                         const size_t AbsStep) {
+        const size_t writerCohortSize = WriterCohortSize(AbsStep);
+        for (size_t WriterRank = 0; WriterRank < writerCohortSize; WriterRank++)
+        {
+            MetaArrayRec *writer_meta_base =
+                (MetaArrayRec *)GetMetadataBase(VarRec, AbsStep, WriterRank);
+            if (writer_meta_base)
+            {
+                MinBlockInfo Blk;
+                Blk.MinMax.Init(VarRec->Type);
+                Blk.WriterID = (int)WriterRank;
+                Blk.BlockID = Id++;
+                Blk.BufferP = writer_meta_base;
+                Blk.Start = NULL;
+                Blk.Count = NULL;
+                if (VarRec->OrigShapeID == ShapeID::LocalValue)
+                {
+                    Blk.Count = (size_t *)1;
+                    Blk.Start = (size_t *)WriterRank;
+                }
+                if (writer_meta_base)
+                {
+                    ApplyElementMinMax(Blk.MinMax, VarRec->Type, writer_meta_base);
+                }
+                MV->BlocksInfo.push_back(Blk);
+            }
+        }
+    };
+
     BP5VarRec *VarRec = LookupVarByKey((void *)&Var);
 
     MinVarInfo *MV = new MinVarInfo((int)VarRec->DimCount, VarRec->GlobalDims);
 
     size_t AbsStep = RelStep;
+    size_t StepLoopStart, StepLoopEnd;
 
     if (m_RandomAccessMode)
     {
         AbsStep = VarRec->AbsStepFromRel[RelStep];
     }
-    const size_t writerCohortSize = WriterCohortSize(AbsStep);
+    if (m_FlattenSteps)
+    {
+        StepLoopStart = 0;
+        StepLoopEnd = m_ControlArray.size();
+    }
+    else
+    {
+        StepLoopStart = AbsStep;
+        StepLoopEnd = AbsStep + 1;
+    }
     size_t Id = 0;
     MV->Step = RelStep;
     MV->Dims = (int)VarRec->DimCount;
@@ -2086,6 +2157,7 @@ MinVarInfo *BP5Deserializer::MinBlocksInfo(const VariableBase &Var, size_t RelSt
     if ((VarRec->OrigShapeID == ShapeID::LocalValue) ||
         (VarRec->OrigShapeID == ShapeID::GlobalValue))
     {
+        const size_t writerCohortSize = WriterCohortSize(AbsStep);
         if (VarRec->OrigShapeID == ShapeID::LocalValue)
         {
             // appear as an array locally
@@ -2099,88 +2171,75 @@ MinVarInfo *BP5Deserializer::MinBlocksInfo(const VariableBase &Var, size_t RelSt
         }
         MV->BlocksInfo.reserve(writerCohortSize);
 
-        for (size_t WriterRank = 0; WriterRank < writerCohortSize; WriterRank++)
+        for (size_t Step = StepLoopStart; Step < StepLoopEnd; Step++)
         {
-            MetaArrayRec *writer_meta_base =
-                (MetaArrayRec *)GetMetadataBase(VarRec, AbsStep, WriterRank);
-            if (writer_meta_base)
-            {
-                MinBlockInfo Blk;
-                Blk.MinMax.Init(VarRec->Type);
-                Blk.WriterID = (int)WriterRank;
-                Blk.BlockID = Id++;
-                Blk.BufferP = writer_meta_base;
-                Blk.Start = NULL;
-                Blk.Count = NULL;
-                if (VarRec->OrigShapeID == ShapeID::LocalValue)
-                {
-                    Blk.Count = (size_t *)1;
-                    Blk.Start = (size_t *)WriterRank;
-                }
-                if (writer_meta_base)
-                {
-                    ApplyElementMinMax(Blk.MinMax, VarRec->Type, writer_meta_base);
-                }
-                MV->BlocksInfo.push_back(Blk);
-            }
+            PossiblyAddValueBlocks(MV, VarRec, Id, Step);
         }
         return MV;
     }
-    for (size_t WriterRank = 0; WriterRank < writerCohortSize; WriterRank++)
+    for (size_t Step = StepLoopStart; Step < StepLoopEnd; Step++)
     {
-        MetaArrayRec *writer_meta_base =
-            (MetaArrayRec *)GetMetadataBase(VarRec, AbsStep, WriterRank);
-        if (writer_meta_base)
+        const size_t writerCohortSize = WriterCohortSize(Step);
+        for (size_t WriterRank = 0; WriterRank < writerCohortSize; WriterRank++)
         {
-            if (MV->Shape == NULL)
+            MetaArrayRec *writer_meta_base =
+                (MetaArrayRec *)GetMetadataBase(VarRec, Step, WriterRank);
+            if (writer_meta_base)
             {
-                MV->Shape = writer_meta_base->Shape;
+                if (MV->Shape == NULL)
+                {
+                    MV->Shape = writer_meta_base->Shape;
+                }
+                size_t WriterBlockCount =
+                    writer_meta_base->Dims ? writer_meta_base->DBCount / writer_meta_base->Dims : 1;
+                Id += WriterBlockCount;
             }
-            size_t WriterBlockCount =
-                writer_meta_base->Dims ? writer_meta_base->DBCount / writer_meta_base->Dims : 1;
-            Id += WriterBlockCount;
         }
     }
     MV->BlocksInfo.reserve(Id);
 
     Id = 0;
-    for (size_t WriterRank = 0; WriterRank < writerCohortSize; WriterRank++)
+    for (size_t Step = StepLoopStart; Step < StepLoopEnd; Step++)
     {
-        MetaArrayRec *writer_meta_base =
-            (MetaArrayRec *)GetMetadataBase(VarRec, AbsStep, WriterRank);
+        const size_t writerCohortSize = WriterCohortSize(Step);
+        for (size_t WriterRank = 0; WriterRank < writerCohortSize; WriterRank++)
+        {
+            MetaArrayRec *writer_meta_base =
+                (MetaArrayRec *)GetMetadataBase(VarRec, Step, WriterRank);
 
-        if (!writer_meta_base)
-            continue;
-        size_t WriterBlockCount = MV->Dims ? writer_meta_base->DBCount / MV->Dims : 1;
-        MinMaxStruct *MMs = NULL;
-        if (VarRec->MinMaxOffset != SIZE_MAX)
-        {
-            MMs = *(MinMaxStruct **)(((char *)writer_meta_base) + VarRec->MinMaxOffset);
-        }
-        for (size_t i = 0; i < WriterBlockCount; i++)
-        {
-            size_t *Offsets = NULL;
-            size_t *Count = NULL;
-            if (writer_meta_base->Offsets)
-                Offsets = writer_meta_base->Offsets + (i * MV->Dims);
-            if (writer_meta_base->Count)
-                Count = writer_meta_base->Count + (i * MV->Dims);
-            MinBlockInfo Blk;
-            Blk.WriterID = (int)WriterRank;
-            Blk.BlockID = Id++;
-            Blk.Start = Offsets;
-            Blk.Count = Count;
-            Blk.MinMax.Init(VarRec->Type);
-            if (MMs)
+            if (!writer_meta_base)
+                continue;
+            size_t WriterBlockCount = MV->Dims ? writer_meta_base->DBCount / MV->Dims : 1;
+            MinMaxStruct *MMs = NULL;
+            if (VarRec->MinMaxOffset != SIZE_MAX)
             {
+                MMs = *(MinMaxStruct **)(((char *)writer_meta_base) + VarRec->MinMaxOffset);
+            }
+            for (size_t i = 0; i < WriterBlockCount; i++)
+            {
+                size_t *Offsets = NULL;
+                size_t *Count = NULL;
+                if (writer_meta_base->Offsets)
+                    Offsets = writer_meta_base->Offsets + (i * MV->Dims);
+                if (writer_meta_base->Count)
+                    Count = writer_meta_base->Count + (i * MV->Dims);
+                MinBlockInfo Blk;
+                Blk.WriterID = (int)WriterRank;
+                Blk.BlockID = Id++;
+                Blk.Start = Offsets;
+                Blk.Count = Count;
+                Blk.MinMax.Init(VarRec->Type);
+                if (MMs)
+                {
 
-                char *BlockMinAddr = (((char *)MMs) + 2 * i * VarRec->ElementSize);
-                char *BlockMaxAddr = (((char *)MMs) + (2 * i + 1) * VarRec->ElementSize);
-                ApplyElementMinMax(Blk.MinMax, VarRec->Type, (void *)BlockMinAddr);
-                ApplyElementMinMax(Blk.MinMax, VarRec->Type, (void *)BlockMaxAddr);
+                    char *BlockMinAddr = (((char *)MMs) + 2 * i * VarRec->ElementSize);
+                    char *BlockMaxAddr = (((char *)MMs) + (2 * i + 1) * VarRec->ElementSize);
+                    ApplyElementMinMax(Blk.MinMax, VarRec->Type, (void *)BlockMinAddr);
+                    ApplyElementMinMax(Blk.MinMax, VarRec->Type, (void *)BlockMaxAddr);
+                }
+                // Blk.BufferP
+                MV->BlocksInfo.push_back(Blk);
             }
-            // Blk.BufferP
-            MV->BlocksInfo.push_back(Blk);
         }
     }
     return MV;
diff --git a/source/adios2/toolkit/format/bp5/BP5Deserializer.h b/source/adios2/toolkit/format/bp5/BP5Deserializer.h
index ad6c53fb13..9f5e8d32cd 100644
--- a/source/adios2/toolkit/format/bp5/BP5Deserializer.h
+++ b/source/adios2/toolkit/format/bp5/BP5Deserializer.h
@@ -35,7 +35,8 @@ class BP5Deserializer : virtual public BP5Base
 {
 
 public:
-    BP5Deserializer(bool WriterIsRowMajor, bool ReaderIsRowMajor, bool RandomAccessMode = false);
+    BP5Deserializer(bool WriterIsRowMajor, bool ReaderIsRowMajor, bool RandomAccessMode = false,
+                    bool FlattenSteps = false);
 
     ~BP5Deserializer();
 
@@ -173,6 +174,7 @@ class BP5Deserializer : virtual public BP5Base
     FFSContext ReaderFFSContext;
 
     const bool m_RandomAccessMode;
+    const bool m_FlattenSteps;
 
     std::vector m_WriterCohortSize; // per step, in random mode
     size_t m_CurrentWriterCohortSize;       // valid in streaming mode
diff --git a/source/adios2/toolkit/remote/Remote.cpp b/source/adios2/toolkit/remote/Remote.cpp
index 29c0da3184..a48fa1610b 100644
--- a/source/adios2/toolkit/remote/Remote.cpp
+++ b/source/adios2/toolkit/remote/Remote.cpp
@@ -109,6 +109,9 @@ void Remote::Open(const std::string hostname, const int32_t port, const std::str
     case Mode::ReadRandomAccess:
         open_msg.Mode = RemoteCommon::RemoteFileMode::RemoteOpenRandomAccess;
         break;
+    case Mode::ReadFlattenSteps:
+        open_msg.Mode = RemoteCommon::RemoteFileMode::RemoteOpenFlattenSteps;
+        break;
     default:
         break;
     }
diff --git a/source/adios2/toolkit/remote/remote_common.h b/source/adios2/toolkit/remote/remote_common.h
index 0d78bd290a..ba98cb383f 100644
--- a/source/adios2/toolkit/remote/remote_common.h
+++ b/source/adios2/toolkit/remote/remote_common.h
@@ -15,6 +15,7 @@ enum RemoteFileMode
 {
     RemoteOpen,
     RemoteOpenRandomAccess,
+    RemoteOpenFlattenSteps,
 };
 /*
  */
diff --git a/source/adios2/toolkit/remote/remote_server.cpp b/source/adios2/toolkit/remote/remote_server.cpp
index 5108ed421e..4b79d787e6 100644
--- a/source/adios2/toolkit/remote/remote_server.cpp
+++ b/source/adios2/toolkit/remote/remote_server.cpp
@@ -92,6 +92,8 @@ class AnonADIOSFile
         m_mode = mode;
         if (m_mode == RemoteOpenRandomAccess)
             adios_read_mode = adios2::Mode::ReadRandomAccess;
+        if (m_mode == RemoteOpenFlattenSteps)
+            adios_read_mode = adios2::Mode::ReadFlattenSteps;
         m_engine = &m_io->Open(FileName, adios_read_mode);
         memcpy(&m_ID, m_IOname.c_str(), sizeof(m_ID));
     }
@@ -175,6 +177,8 @@ static void OpenHandler(CManager cm, CMConnection conn, void *vevent, void *clie
     std::string strMode = "Streaming";
     if (open_msg->Mode == RemoteOpenRandomAccess)
         strMode = "RandomAccess";
+    if (open_msg->Mode == RemoteOpenFlattenSteps)
+        strMode = "FlattenSteps";
     std::cout << "Got an open request (mode " << strMode << ") for file " << open_msg->FileName
               << std::endl;
     AnonADIOSFile *f =
diff --git a/source/utils/bpls/bpls.cpp b/source/utils/bpls/bpls.cpp
index 94dd7805cf..42b4a99580 100644
--- a/source/utils/bpls/bpls.cpp
+++ b/source/utils/bpls/bpls.cpp
@@ -95,6 +95,7 @@ bool listmeshes;         // do list meshes too
 bool attrsonly;          // do list attributes only
 bool longopt;            // -l is turned on
 bool timestep;           // read step by step
+bool flatten;            // flatten steps to one
 bool filestream = false; // are we using an engine through FileStream?
 bool noindex;            // do no print array indices with data
 bool printByteAsChar;    // print 8 bit integer arrays as string
@@ -144,6 +145,7 @@ void display_help()
            */
            "  --timestep  | -t           Read content step by step (stream "
            "reading)\n"
+           "  --flatten                  Flatten Steps into one step (open in flatten mode)\n"
            "  --dump      | -d           Dump matched variables/attributes\n"
            "                               To match attributes too, add option "
            "-a\n"
@@ -617,6 +619,7 @@ int bplsMain(int argc, char *argv[])
     arg.AddBooleanArgument("--noindex", &noindex, " | -y Print data without array indices");
     arg.AddBooleanArgument("-y", &noindex, "");
     arg.AddBooleanArgument("--timestep", ×tep, " | -t Print values of timestep elements");
+    arg.AddBooleanArgument("--flatten", &flatten, " Flatten steps to one");
     arg.AddBooleanArgument("-t", ×tep, "");
     arg.AddBooleanArgument("--attrs", &listattrs, " | -a List/match attributes too");
     arg.AddBooleanArgument("-a", &listattrs, "");
@@ -765,6 +768,7 @@ void init_globals()
     output_xml = false;
     noindex = false;
     timestep = false;
+    flatten = false;
     sortnames = false;
     listattrs = false;
     listmeshes = false;
@@ -857,6 +861,8 @@ void printSettings(void)
         printf("      -V : show binary version info of file\n");
     if (timestep)
         printf("      -t : read step-by-step\n");
+    if (flatten)
+        printf("      --flatten : flatten steps into one\n");
 
     if (hidden_attrs)
     {
@@ -1660,6 +1666,10 @@ int doList(std::string path)
             {
                 fp = &io.Open(path, Mode::Read);
             }
+            else if (flatten)
+            {
+                fp = &io.Open(path, Mode::ReadFlattenSteps);
+            }
             else
             {
                 fp = &io.Open(path, Mode::ReadRandomAccess);
@@ -2906,7 +2916,8 @@ bool print_data_xml(const char *s, const size_t length)
     return false;
 }
 
-int print_data(const void *data, int item, DataType adiosvartype, bool allowformat)
+int print_data(const void *data, int item, DataType adiosvartype, bool allowformat,
+               bool char_star_string)
 {
     bool f = format.size() && allowformat;
     const char *fmt = format.c_str();
@@ -2929,9 +2940,15 @@ int print_data(const void *data, int item, DataType adiosvartype, bool allowform
         break;
 
     case DataType::String: {
-        // fprintf(outf, (f ? fmt : "\"%s\""), ((char *)data) + item);
-        const std::string *dataStr = reinterpret_cast(data);
-        fprintf(outf, (f ? fmt : "\"%s\""), dataStr[item].c_str());
+        if (char_star_string)
+        {
+            fprintf(outf, (f ? fmt : "\"%s\""), *((char **)data));
+        }
+        else
+        {
+            const std::string *dataStr = reinterpret_cast(data);
+            fprintf(outf, (f ? fmt : "\"%s\""), dataStr[item].c_str());
+        }
         break;
     }
 
@@ -3380,7 +3397,7 @@ void print_decomp(core::Engine *fp, core::IO *io, core::Variable *variable)
                 if (blocks.size() == 1)
                 {
                     fprintf(outf, " = ");
-                    print_data(blocks[0].BufferP, 0, adiosvartype, true);
+                    print_data(blocks[0].BufferP, 0, adiosvartype, true, /* MBI */ true);
                     fprintf(outf, "\n");
                 }
                 else
@@ -3393,7 +3410,7 @@ void print_decomp(core::Engine *fp, core::IO *io, core::Variable *variable)
                     int col = 0;
                     for (size_t j = 0; j < blocks.size(); j++)
                     {
-                        print_data(blocks[j].BufferP, 0, adiosvartype, true);
+                        print_data(blocks[j].BufferP, 0, adiosvartype, true, /* MBI */ true);
                         ++col;
                         if (j < blocks.size() - 1)
                         {
diff --git a/source/utils/bpls/bpls.h b/source/utils/bpls/bpls.h
index 8d5c9be035..afd1add048 100644
--- a/source/utils/bpls/bpls.h
+++ b/source/utils/bpls/bpls.h
@@ -88,7 +88,8 @@ bool matchesAMask(const char *name);
 int print_start(const std::string &fnamestr);
 void print_slice_info(core::VariableBase *variable, bool timed, uint64_t *s, uint64_t *c,
                       Dims count);
-int print_data(const void *data, int item, DataType adiosvartypes, bool allowformat);
+int print_data(const void *data, int item, DataType adiosvartypes, bool allowformat,
+               bool char_star_string = false);
 
 /* s is a character array not necessarily null terminated.
  * return false on OK print, true if it not XML (not printed)*/
diff --git a/testing/adios2/engine/bp/CMakeLists.txt b/testing/adios2/engine/bp/CMakeLists.txt
index bf99106bfa..707b9e4ee8 100644
--- a/testing/adios2/engine/bp/CMakeLists.txt
+++ b/testing/adios2/engine/bp/CMakeLists.txt
@@ -91,6 +91,8 @@ set(CTEST_TEST_TIMEOUT 10)
 bp_gtest_add_tests_helper(WriteReadADIOS2 MPI_ALLOW)
 async_gtest_add_tests_helper(WriteReadADIOS2 MPI_ALLOW)
 
+gtest_add_tests_helper(WriteReadFlatten MPI_ONLY BP Engine.BP. .BP5 WORKING_DIRECTORY ${BP5_DIR} EXTRA_ARGS "BP5" )
+
 bp_gtest_add_tests_helper(WriteReadADIOS2fstream MPI_ALLOW)
 bp_gtest_add_tests_helper(WriteReadADIOS2stdio MPI_ALLOW)
 bp_gtest_add_tests_helper(WriteReadAsStreamADIOS2 MPI_ALLOW)
diff --git a/testing/adios2/engine/bp/TestBPWriteReadFlatten.cpp b/testing/adios2/engine/bp/TestBPWriteReadFlatten.cpp
new file mode 100644
index 0000000000..5f5b9e50fb
--- /dev/null
+++ b/testing/adios2/engine/bp/TestBPWriteReadFlatten.cpp
@@ -0,0 +1,1338 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ */
+#include 
+#include 
+
+#include 
+#include  //std::iota
+#include 
+
+#include 
+
+#include 
+
+#include "../SmallTestData.h"
+
+std::string engineName;       // comes from command line
+std::string engineParameters; // comes from command line
+
+class BPWriteReadTestFlatten : public ::testing::Test
+{
+public:
+    BPWriteReadTestFlatten() = default;
+
+    SmallTestData m_TestData;
+};
+
+//******************************************************************************
+// 1D 1x8 test data
+//******************************************************************************
+
+// Flatten BP write and read 1D arrays
+TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead1D8)
+{
+    // Each process would write a 1x8 array and all processes would
+    // form a mpiSize * Nx 1D array
+
+    int mpiRank = 0, mpiSize = 1;
+    // Number of rows
+    const size_t Nx = 8;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+    const std::string fname("FlattenBPWriteRead1D8_MPI.bp");
+#else
+    const std::string fname("FlattenBPWriteRead1D8.bp");
+#endif
+
+    // Write test data using BP
+
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+#else
+    adios2::ADIOS adios;
+#endif
+    {
+        adios2::IO io = adios.DeclareIO("TestIO");
+
+        // Declare 1D variables (NumOfProcesses * Nx)
+        // The local process' part (start, count) can be defined now or later
+        // before Write().
+        {
+            const adios2::Dims shape{static_cast(Nx * mpiSize)};
+            const adios2::Dims start{static_cast(Nx * mpiRank)};
+            const adios2::Dims count{Nx};
+
+            auto var_char = io.DefineVariable("ch", shape, start, count);
+            EXPECT_TRUE(var_char);
+            auto var_iString = io.DefineVariable("iString");
+            EXPECT_TRUE(var_iString);
+            auto var_i8 = io.DefineVariable("i8", shape, start, count);
+            EXPECT_TRUE(var_i8);
+            auto var_i16 = io.DefineVariable("i16", shape, start, count);
+            EXPECT_TRUE(var_i16);
+            auto var_i32 = io.DefineVariable("i32", shape, start, count);
+            EXPECT_TRUE(var_i32);
+            auto var_i64 = io.DefineVariable("i64", shape, start, count);
+            EXPECT_TRUE(var_i64);
+            auto var_u8 = io.DefineVariable("u8", shape, start, count);
+            EXPECT_TRUE(var_u8);
+            auto var_u16 = io.DefineVariable("u16", shape, start, count);
+            EXPECT_TRUE(var_u16);
+            auto var_u32 = io.DefineVariable("u32", shape, start, count);
+            EXPECT_TRUE(var_u32);
+            auto var_u64 = io.DefineVariable("u64", shape, start, count);
+            EXPECT_TRUE(var_u64);
+            auto var_r32 = io.DefineVariable("r32", shape, start, count);
+            EXPECT_TRUE(var_r32);
+            auto var_r64 = io.DefineVariable("r64", shape, start, count);
+            EXPECT_TRUE(var_r64);
+        }
+
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+        else
+        {
+            // Create the BP Engine
+            io.SetEngine("BPFile");
+        }
+        if (!engineParameters.empty())
+        {
+            io.SetParameters(engineParameters);
+        }
+
+        io.AddTransport("file");
+
+        adios2::Engine bpWriter = io.Open(fname, adios2::Mode::Write);
+
+        EXPECT_EQ(bpWriter.OpenMode(), adios2::Mode::Write);
+
+        for (size_t step = 0; step < (size_t)mpiSize; ++step)
+        {
+            // Generate test data for each process uniquely (all as if for step 0)
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, static_cast(0), mpiRank, mpiSize);
+
+            // Retrieve the variables that previously went out of scope
+            auto var_char = io.InquireVariable("ch");
+            auto var_iString = io.InquireVariable("iString");
+            auto var_i8 = io.InquireVariable("i8");
+            auto var_i16 = io.InquireVariable("i16");
+            auto var_i32 = io.InquireVariable("i32");
+            auto var_i64 = io.InquireVariable("i64");
+            auto var_u8 = io.InquireVariable("u8");
+            auto var_u16 = io.InquireVariable("u16");
+            auto var_u32 = io.InquireVariable("u32");
+            auto var_u64 = io.InquireVariable("u64");
+            auto var_r32 = io.InquireVariable("r32");
+            auto var_r64 = io.InquireVariable("r64");
+
+            // Make a 1D selection to describe the local dimensions of the
+            // variable we write and its offsets in the global spaces
+            adios2::Box sel({mpiRank * Nx}, {Nx});
+
+            var_char.SetSelection(sel);
+            EXPECT_THROW(var_iString.SetSelection(sel), std::invalid_argument);
+            var_i8.SetSelection(sel);
+            var_i16.SetSelection(sel);
+            var_i32.SetSelection(sel);
+            var_i64.SetSelection(sel);
+            var_u8.SetSelection(sel);
+            var_u16.SetSelection(sel);
+            var_u32.SetSelection(sel);
+            var_u64.SetSelection(sel);
+            var_r32.SetSelection(sel);
+            var_r64.SetSelection(sel);
+
+            // Write each one
+            // fill in the variable with values from starting index to
+            // starting index + count
+            bpWriter.BeginStep();
+
+            if (step == (size_t)mpiRank)
+            {
+                bpWriter.Put(var_char, currentTestData.CHAR.data());
+                bpWriter.Put(var_iString, currentTestData.S1);
+                bpWriter.Put(var_i8, currentTestData.I8.data());
+                bpWriter.Put(var_i16, currentTestData.I16.data());
+                bpWriter.Put(var_i32, currentTestData.I32.data());
+                bpWriter.Put(var_i64, currentTestData.I64.data());
+                bpWriter.Put(var_u8, currentTestData.U8.data());
+                bpWriter.Put(var_u16, currentTestData.U16.data());
+                bpWriter.Put(var_u32, currentTestData.U32.data());
+                bpWriter.Put(var_u64, currentTestData.U64.data());
+                bpWriter.Put(var_r32, currentTestData.R32.data());
+                bpWriter.Put(var_r64, currentTestData.R64.data());
+            }
+            bpWriter.EndStep();
+        }
+
+        // Close the file
+        bpWriter.Close();
+    }
+
+    {
+        adios2::IO io = adios.DeclareIO("ReadIO");
+
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+        if (!engineParameters.empty())
+        {
+            io.SetParameters(engineParameters);
+        }
+
+        adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadFlattenSteps);
+
+        EXPECT_EQ(bpReader.Steps(), 1);
+
+        auto var_char = io.InquireVariable("ch");
+        EXPECT_TRUE(var_char);
+        ASSERT_EQ(var_char.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_char.Steps(), 1);
+        ASSERT_EQ(var_char.Shape()[0], mpiSize * Nx);
+
+        auto var_iString = io.InquireVariable("iString");
+        EXPECT_TRUE(var_iString);
+        ASSERT_EQ(var_iString.Shape().size(), 0);
+        ASSERT_EQ(var_iString.Steps(), 1);
+
+        auto var_i8 = io.InquireVariable("i8");
+        EXPECT_TRUE(var_i8);
+        ASSERT_EQ(var_i8.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i8.Steps(), 1);
+        ASSERT_EQ(var_i8.Shape()[0], mpiSize * Nx);
+
+        auto var_i16 = io.InquireVariable("i16");
+        EXPECT_TRUE(var_i16);
+        ASSERT_EQ(var_i16.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i16.Steps(), 1);
+        ASSERT_EQ(var_i16.Shape()[0], mpiSize * Nx);
+
+        auto var_i32 = io.InquireVariable("i32");
+        EXPECT_TRUE(var_i32);
+        ASSERT_EQ(var_i32.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i32.Steps(), 1);
+        ASSERT_EQ(var_i32.Shape()[0], mpiSize * Nx);
+
+        auto var_i64 = io.InquireVariable("i64");
+        EXPECT_TRUE(var_i64);
+        ASSERT_EQ(var_i64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i64.Steps(), 1);
+        ASSERT_EQ(var_i64.Shape()[0], mpiSize * Nx);
+
+        auto var_u8 = io.InquireVariable("u8");
+        EXPECT_TRUE(var_u8);
+        ASSERT_EQ(var_u8.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u8.Steps(), 1);
+        ASSERT_EQ(var_u8.Shape()[0], mpiSize * Nx);
+
+        auto var_u16 = io.InquireVariable("u16");
+        EXPECT_TRUE(var_u16);
+        ASSERT_EQ(var_u16.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u16.Steps(), 1);
+        ASSERT_EQ(var_u16.Shape()[0], mpiSize * Nx);
+
+        auto var_u32 = io.InquireVariable("u32");
+        EXPECT_TRUE(var_u32);
+        ASSERT_EQ(var_u32.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u32.Steps(), 1);
+        ASSERT_EQ(var_u32.Shape()[0], mpiSize * Nx);
+
+        auto var_u64 = io.InquireVariable("u64");
+        EXPECT_TRUE(var_u64);
+        ASSERT_EQ(var_u64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u64.Steps(), 1);
+        ASSERT_EQ(var_u64.Shape()[0], mpiSize * Nx);
+
+        auto var_r32 = io.InquireVariable("r32");
+        EXPECT_TRUE(var_r32);
+        ASSERT_EQ(var_r32.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r32.Steps(), 1);
+        ASSERT_EQ(var_r32.Shape()[0], mpiSize * Nx);
+
+        auto var_r64 = io.InquireVariable("r64");
+        EXPECT_TRUE(var_r64);
+        ASSERT_EQ(var_r64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r64.Steps(), 1);
+        ASSERT_EQ(var_r64.Shape()[0], mpiSize * Nx);
+
+        // TODO: other types
+
+        SmallTestData testData;
+
+        std::string IString;
+        std::array I8;
+        std::array I16;
+        std::array I32;
+        std::array I64;
+        std::array U8;
+        std::array U16;
+        std::array U32;
+        std::array U64;
+        std::array R32;
+        std::array R64;
+        std::array CHAR;
+
+        const adios2::Dims start{mpiRank * Nx};
+        const adios2::Dims count{Nx};
+
+        const adios2::Box sel(start, count);
+
+        for (size_t t = 0; t < 1; ++t)
+        {
+            var_char.SetSelection(sel);
+
+            var_i8.SetSelection(sel);
+            var_i16.SetSelection(sel);
+            var_i32.SetSelection(sel);
+            var_i64.SetSelection(sel);
+            var_u8.SetSelection(sel);
+            var_u16.SetSelection(sel);
+            var_u32.SetSelection(sel);
+            var_u64.SetSelection(sel);
+            var_r32.SetSelection(sel);
+            var_r64.SetSelection(sel);
+
+            // default step selection should be 0, 1, so no need for that
+
+            // Generate test data for each rank uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, static_cast(0), mpiRank, mpiSize);
+
+            bpReader.Get(var_char, CHAR.data());
+            bpReader.Get(var_iString, IString);
+            bpReader.Get(var_i8, I8.data());
+            bpReader.Get(var_i16, I16.data());
+            bpReader.Get(var_i32, I32.data());
+            bpReader.Get(var_i64, I64.data());
+            bpReader.Get(var_u8, U8.data());
+            bpReader.Get(var_u16, U16.data());
+            bpReader.Get(var_u32, U32.data());
+            bpReader.Get(var_u64, U64.data());
+            bpReader.Get(var_r32, R32.data());
+            bpReader.Get(var_r64, R64.data());
+
+            bpReader.PerformGets();
+
+            EXPECT_EQ(IString, currentTestData.S1) << "rank=" << mpiRank;
+
+            for (size_t i = 0; i < Nx; ++i)
+            {
+                std::stringstream ss;
+                ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
+                std::string msg = ss.str();
+
+                // EXPECT_EQ(TF[i], currentTestData.TF[i]) << msg;
+                EXPECT_EQ(CHAR[i], currentTestData.CHAR[i]) << msg;
+                EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
+                EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
+                EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
+                EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
+                EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
+                EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
+                EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
+                EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
+                EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
+                EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
+            }
+        }
+        bpReader.Close();
+    }
+}
+
+//******************************************************************************
+// 2D 2x4 test data
+//******************************************************************************
+
+// ADIOS2 BP write and read 2D array
+TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead2D2x4)
+{
+    // Each process would write a 2x4 array and all processes would
+    // form a 2D 2 * (numberOfProcess*Nx) matrix where Nx is 4 here
+
+    int mpiRank = 0, mpiSize = 1;
+    // Number of rows
+    const std::size_t Nx = 4;
+
+    // Number of rows
+    const std::size_t Ny = 2;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+    const std::string fname("FlattenBPWriteRead2D2x4Test_MPI.bp");
+#else
+    const std::string fname("FlattenBPWriteRead2D2x4Test.bp");
+#endif
+
+    // Write test data using ADIOS2
+
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+#else
+    adios2::ADIOS adios;
+#endif
+    {
+        adios2::IO io = adios.DeclareIO("TestIO");
+
+        // Declare 2D variables (Ny * (NumOfProcesses * Nx))
+        // The local process' part (start, count) can be defined now or later
+        // before Write().
+        {
+            const adios2::Dims shape{Ny, static_cast(Nx * mpiSize)};
+            const adios2::Dims start{0, static_cast(mpiRank * Nx)};
+            const adios2::Dims count{Ny, Nx};
+
+            auto var_iString = io.DefineVariable("iString");
+            EXPECT_TRUE(var_iString);
+            auto var_i8 = io.DefineVariable("i8", shape, start, count);
+            EXPECT_TRUE(var_i8);
+            auto var_i16 = io.DefineVariable("i16", shape, start, count);
+            EXPECT_TRUE(var_i16);
+            auto var_i32 = io.DefineVariable("i32", shape, start, count);
+            EXPECT_TRUE(var_i32);
+            auto var_i64 = io.DefineVariable("i64", shape, start, count);
+            EXPECT_TRUE(var_i64);
+            auto var_u8 = io.DefineVariable("u8", shape, start, count);
+            EXPECT_TRUE(var_u8);
+            auto var_u16 = io.DefineVariable("u16", shape, start, count);
+            EXPECT_TRUE(var_u16);
+            auto var_u32 = io.DefineVariable("u32", shape, start, count);
+            EXPECT_TRUE(var_u32);
+            auto var_u64 = io.DefineVariable("u64", shape, start, count);
+            EXPECT_TRUE(var_u64);
+            auto var_r32 = io.DefineVariable("r32", shape, start, count);
+            EXPECT_TRUE(var_r32);
+            auto var_r64 = io.DefineVariable("r64", shape, start, count);
+            EXPECT_TRUE(var_r64);
+        }
+
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+        else
+        {
+            // Create the BP Engine
+            io.SetEngine("BPFile");
+        }
+        if (!engineParameters.empty())
+        {
+            io.SetParameters(engineParameters);
+        }
+        io.AddTransport("file");
+
+        adios2::Engine bpWriter = io.Open(fname, adios2::Mode::Write);
+
+        for (size_t step = 0; step < (size_t)mpiSize; ++step)
+        {
+            // Generate test data for each process uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, static_cast(0), mpiRank, mpiSize);
+
+            // Retrieve the variables that previously went out of scope
+            auto var_iString = io.InquireVariable("iString");
+            auto var_i8 = io.InquireVariable("i8");
+            auto var_i16 = io.InquireVariable("i16");
+            auto var_i32 = io.InquireVariable("i32");
+            auto var_i64 = io.InquireVariable("i64");
+            auto var_u8 = io.InquireVariable("u8");
+            auto var_u16 = io.InquireVariable("u16");
+            auto var_u32 = io.InquireVariable("u32");
+            auto var_u64 = io.InquireVariable("u64");
+            auto var_r32 = io.InquireVariable("r32");
+            auto var_r64 = io.InquireVariable("r64");
+
+            // Make a 2D selection to describe the local dimensions of the
+            // variable we write and its offsets in the global spaces
+            adios2::Box sel({0, static_cast(mpiRank * Nx)}, {Ny, Nx});
+            var_i8.SetSelection(sel);
+            var_i16.SetSelection(sel);
+            var_i32.SetSelection(sel);
+            var_i64.SetSelection(sel);
+            var_u8.SetSelection(sel);
+            var_u16.SetSelection(sel);
+            var_u32.SetSelection(sel);
+            var_u64.SetSelection(sel);
+            var_r32.SetSelection(sel);
+            var_r64.SetSelection(sel);
+
+            // Write each one
+            // fill in the variable with values from starting index to
+            // starting index + count
+            bpWriter.BeginStep();
+            if (step == (size_t)mpiRank)
+            {
+                bpWriter.Put(var_iString, currentTestData.S1);
+                bpWriter.Put(var_i8, currentTestData.I8.data());
+                bpWriter.Put(var_i16, currentTestData.I16.data());
+                bpWriter.Put(var_i32, currentTestData.I32.data());
+                bpWriter.Put(var_i64, currentTestData.I64.data());
+                bpWriter.Put(var_u8, currentTestData.U8.data());
+                bpWriter.Put(var_u16, currentTestData.U16.data());
+                bpWriter.Put(var_u32, currentTestData.U32.data());
+                bpWriter.Put(var_u64, currentTestData.U64.data());
+                bpWriter.Put(var_r32, currentTestData.R32.data());
+                bpWriter.Put(var_r64, currentTestData.R64.data());
+            }
+            bpWriter.EndStep();
+        }
+
+        // Close the file
+        bpWriter.Close();
+    }
+
+    {
+        adios2::IO io = adios.DeclareIO("ReadIO");
+
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+        if (!engineParameters.empty())
+        {
+            io.SetParameters(engineParameters);
+        }
+
+        adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadFlattenSteps);
+
+        EXPECT_EQ(bpReader.Steps(), 1);
+        auto var_iString = io.InquireVariable("iString");
+        EXPECT_TRUE(var_iString);
+        ASSERT_EQ(var_iString.Shape().size(), 0);
+        ASSERT_EQ(var_iString.Steps(), 1);
+
+        auto var_i8 = io.InquireVariable("i8");
+        EXPECT_TRUE(var_i8);
+        ASSERT_EQ(var_i8.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i8.Steps(), 1);
+        ASSERT_EQ(var_i8.Shape()[0], Ny);
+        ASSERT_EQ(var_i8.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_i16 = io.InquireVariable("i16");
+        EXPECT_TRUE(var_i16);
+        ASSERT_EQ(var_i16.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i16.Steps(), 1);
+        ASSERT_EQ(var_i16.Shape()[0], Ny);
+        ASSERT_EQ(var_i16.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_i32 = io.InquireVariable("i32");
+        EXPECT_TRUE(var_i32);
+        ASSERT_EQ(var_i32.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i32.Steps(), 1);
+        ASSERT_EQ(var_i32.Shape()[0], Ny);
+        ASSERT_EQ(var_i32.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_i64 = io.InquireVariable("i64");
+        EXPECT_TRUE(var_i64);
+        ASSERT_EQ(var_i64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i64.Steps(), 1);
+        ASSERT_EQ(var_i64.Shape()[0], Ny);
+        ASSERT_EQ(var_i64.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_u8 = io.InquireVariable("u8");
+        EXPECT_TRUE(var_u8);
+        ASSERT_EQ(var_u8.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u8.Steps(), 1);
+        ASSERT_EQ(var_u8.Shape()[0], Ny);
+        ASSERT_EQ(var_u8.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_u16 = io.InquireVariable("u16");
+        EXPECT_TRUE(var_u16);
+        ASSERT_EQ(var_u16.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u16.Steps(), 1);
+        ASSERT_EQ(var_u16.Shape()[0], Ny);
+        ASSERT_EQ(var_u16.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_u32 = io.InquireVariable("u32");
+        EXPECT_TRUE(var_u32);
+        ASSERT_EQ(var_u32.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u32.Steps(), 1);
+        ASSERT_EQ(var_u32.Shape()[0], Ny);
+        ASSERT_EQ(var_u32.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_u64 = io.InquireVariable("u64");
+        EXPECT_TRUE(var_u64);
+        ASSERT_EQ(var_u64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u64.Steps(), 1);
+        ASSERT_EQ(var_u64.Shape()[0], Ny);
+        ASSERT_EQ(var_u64.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_r32 = io.InquireVariable("r32");
+        EXPECT_TRUE(var_r32);
+        ASSERT_EQ(var_r32.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r32.Steps(), 1);
+        ASSERT_EQ(var_r32.Shape()[0], Ny);
+        ASSERT_EQ(var_r32.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_r64 = io.InquireVariable("r64");
+        EXPECT_TRUE(var_r64);
+        ASSERT_EQ(var_r64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r64.Steps(), 1);
+        ASSERT_EQ(var_r64.Shape()[0], Ny);
+        ASSERT_EQ(var_r64.Shape()[1], static_cast(mpiSize * Nx));
+
+        std::string IString;
+        std::array I8;
+        std::array I16;
+        std::array I32;
+        std::array I64;
+        std::array U8;
+        std::array U16;
+        std::array U32;
+        std::array U64;
+        std::array R32;
+        std::array R64;
+
+        const adios2::Dims start{0, static_cast(mpiRank * Nx)};
+        const adios2::Dims count{Ny, Nx};
+
+        const adios2::Box sel(start, count);
+
+        var_i8.SetSelection(sel);
+        var_i16.SetSelection(sel);
+        var_i32.SetSelection(sel);
+        var_i64.SetSelection(sel);
+
+        var_u8.SetSelection(sel);
+        var_u16.SetSelection(sel);
+        var_u32.SetSelection(sel);
+        var_u64.SetSelection(sel);
+
+        var_r32.SetSelection(sel);
+        var_r64.SetSelection(sel);
+
+        for (size_t t = 0; t < 1; ++t)
+        {
+            var_i8.SetStepSelection({t, 1});
+            var_i16.SetStepSelection({t, 1});
+            var_i32.SetStepSelection({t, 1});
+            var_i64.SetStepSelection({t, 1});
+
+            var_u8.SetStepSelection({t, 1});
+            var_u16.SetStepSelection({t, 1});
+            var_u32.SetStepSelection({t, 1});
+            var_u64.SetStepSelection({t, 1});
+
+            var_r32.SetStepSelection({t, 1});
+            var_r64.SetStepSelection({t, 1});
+
+            bpReader.Get(var_iString, IString);
+
+            bpReader.Get(var_i8, I8.data());
+            bpReader.Get(var_i16, I16.data());
+            bpReader.Get(var_i32, I32.data());
+            bpReader.Get(var_i64, I64.data());
+
+            bpReader.Get(var_u8, U8.data());
+            bpReader.Get(var_u16, U16.data());
+            bpReader.Get(var_u32, U32.data());
+            bpReader.Get(var_u64, U64.data());
+
+            bpReader.Get(var_r32, R32.data());
+            bpReader.Get(var_r64, R64.data());
+
+            bpReader.PerformGets();
+            // Generate test data for each rank uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, static_cast(0), mpiRank, mpiSize);
+
+            EXPECT_EQ(IString, currentTestData.S1);
+
+            for (size_t i = 0; i < Nx * Ny; ++i)
+            {
+                std::stringstream ss;
+                ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
+                std::string msg = ss.str();
+
+                EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
+                EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
+                EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
+                EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
+                EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
+                EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
+                EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
+                EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
+                EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
+                EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
+            }
+        }
+        bpReader.Close();
+    }
+}
+
+//******************************************************************************
+// 2D 4x2 test data
+//******************************************************************************
+
+TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead2D4x2)
+{
+    // Each process would write a 4x2 array and all processes would
+    // form a 2D 4 * (NumberOfProcess * Nx) matrix where Nx is 2 here
+
+    int mpiRank = 0, mpiSize = 1;
+    // Number of rows
+    const std::size_t Nx = 2;
+    // Number of cols
+    const std::size_t Ny = 4;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+    const std::string fname("FlattenBPWriteRead2D4x2Test_MPI.bp");
+#else
+    const std::string fname("FlattenBPWriteRead2D4x2Test.bp");
+#endif
+
+    // Write test data using ADIOS2
+
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+#else
+    adios2::ADIOS adios;
+#endif
+    {
+        adios2::IO io = adios.DeclareIO("TestIO");
+
+        // Declare 2D variables (4 * (NumberOfProcess * Nx))
+        // The local process' part (start, count) can be defined now or later
+        // before Write().
+        {
+            adios2::Dims shape{static_cast(Ny),
+                               static_cast(mpiSize * Nx)};
+            adios2::Dims start{static_cast(0),
+                               static_cast(mpiRank * Nx)};
+            adios2::Dims count{static_cast(Ny), static_cast(Nx)};
+            auto var_i8 = io.DefineVariable("i8", shape, start, count);
+            EXPECT_TRUE(var_i8);
+            auto var_i16 = io.DefineVariable("i16", shape, start, count);
+            EXPECT_TRUE(var_i16);
+            auto var_i32 = io.DefineVariable("i32", shape, start, count);
+            EXPECT_TRUE(var_i32);
+            auto var_i64 = io.DefineVariable("i64", shape, start, count);
+            EXPECT_TRUE(var_i64);
+            auto var_u8 = io.DefineVariable("u8", shape, start, count);
+            EXPECT_TRUE(var_u8);
+            auto var_u16 = io.DefineVariable("u16", shape, start, count);
+            EXPECT_TRUE(var_u16);
+            auto var_u32 = io.DefineVariable("u32", shape, start, count);
+            EXPECT_TRUE(var_u32);
+            auto var_u64 = io.DefineVariable("u64", shape, start, count);
+            EXPECT_TRUE(var_u64);
+            auto var_r32 = io.DefineVariable("r32", shape, start, count);
+            EXPECT_TRUE(var_r32);
+            auto var_r64 = io.DefineVariable("r64", shape, start, count);
+            EXPECT_TRUE(var_r64);
+        }
+
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+        else
+        {
+            // Create the BP Engine
+            io.SetEngine("BPFile");
+        }
+        if (!engineParameters.empty())
+        {
+            io.SetParameters(engineParameters);
+        }
+
+        io.AddTransport("file");
+
+        adios2::Engine bpWriter = io.Open(fname, adios2::Mode::Write);
+
+        for (size_t step = 0; step < (size_t)mpiSize; ++step)
+        {
+            // Generate test data for each process uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, static_cast(0), mpiRank, mpiSize);
+
+            // Retrieve the variables that previously went out of scope
+            auto var_i8 = io.InquireVariable("i8");
+            auto var_i16 = io.InquireVariable("i16");
+            auto var_i32 = io.InquireVariable("i32");
+            auto var_i64 = io.InquireVariable("i64");
+            auto var_u8 = io.InquireVariable("u8");
+            auto var_u16 = io.InquireVariable("u16");
+            auto var_u32 = io.InquireVariable("u32");
+            auto var_u64 = io.InquireVariable("u64");
+            auto var_r32 = io.InquireVariable("r32");
+            auto var_r64 = io.InquireVariable("r64");
+
+            // Make a 2D selection to describe the local dimensions of the
+            // variable we write and its offsets in the global spaces
+            adios2::Box sel({0, static_cast(mpiRank * Nx)}, {Ny, Nx});
+            var_i8.SetSelection(sel);
+            var_i16.SetSelection(sel);
+            var_i32.SetSelection(sel);
+            var_i64.SetSelection(sel);
+            var_u8.SetSelection(sel);
+            var_u16.SetSelection(sel);
+            var_u32.SetSelection(sel);
+            var_u64.SetSelection(sel);
+            var_r32.SetSelection(sel);
+            var_r64.SetSelection(sel);
+
+            // Write each one
+            // fill in the variable with values from starting index to
+            // starting index + count
+            bpWriter.BeginStep();
+            if (step == (size_t)mpiRank)
+            {
+                bpWriter.Put(var_i8, currentTestData.I8.data());
+                bpWriter.Put(var_i16, currentTestData.I16.data());
+                bpWriter.Put(var_i32, currentTestData.I32.data());
+                bpWriter.Put(var_i64, currentTestData.I64.data());
+                bpWriter.Put(var_u8, currentTestData.U8.data());
+                bpWriter.Put(var_u16, currentTestData.U16.data());
+                bpWriter.Put(var_u32, currentTestData.U32.data());
+                bpWriter.Put(var_u64, currentTestData.U64.data());
+                bpWriter.Put(var_r32, currentTestData.R32.data());
+                bpWriter.Put(var_r64, currentTestData.R64.data());
+            }
+            bpWriter.EndStep();
+        }
+
+        // Close the file
+        bpWriter.Close();
+    }
+
+    {
+        adios2::IO io = adios.DeclareIO("ReadIO");
+
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+        if (!engineParameters.empty())
+        {
+            io.SetParameters(engineParameters);
+        }
+
+        adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadFlattenSteps);
+
+        EXPECT_EQ(bpReader.Steps(), 1);
+
+        auto var_i8 = io.InquireVariable("i8");
+        EXPECT_TRUE(var_i8);
+        ASSERT_EQ(var_i8.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i8.Steps(), 1);
+        ASSERT_EQ(var_i8.Shape()[0], Ny);
+        ASSERT_EQ(var_i8.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_i16 = io.InquireVariable("i16");
+        EXPECT_TRUE(var_i16);
+        ASSERT_EQ(var_i16.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i16.Steps(), 1);
+        ASSERT_EQ(var_i16.Shape()[0], Ny);
+        ASSERT_EQ(var_i16.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_i32 = io.InquireVariable("i32");
+        EXPECT_TRUE(var_i32);
+        ASSERT_EQ(var_i32.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i32.Steps(), 1);
+        ASSERT_EQ(var_i32.Shape()[0], Ny);
+        ASSERT_EQ(var_i32.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_i64 = io.InquireVariable("i64");
+        EXPECT_TRUE(var_i64);
+        ASSERT_EQ(var_i64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_i64.Steps(), 1);
+        ASSERT_EQ(var_i64.Shape()[0], Ny);
+        ASSERT_EQ(var_i64.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_u8 = io.InquireVariable("u8");
+        EXPECT_TRUE(var_u8);
+        ASSERT_EQ(var_u8.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u8.Steps(), 1);
+        ASSERT_EQ(var_u8.Shape()[0], Ny);
+        ASSERT_EQ(var_u8.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_u16 = io.InquireVariable("u16");
+        EXPECT_TRUE(var_u16);
+        ASSERT_EQ(var_u16.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u16.Steps(), 1);
+        ASSERT_EQ(var_u16.Shape()[0], Ny);
+        ASSERT_EQ(var_u16.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_u32 = io.InquireVariable("u32");
+        EXPECT_TRUE(var_u32);
+        ASSERT_EQ(var_u32.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u32.Steps(), 1);
+        ASSERT_EQ(var_u32.Shape()[0], Ny);
+        ASSERT_EQ(var_u32.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_u64 = io.InquireVariable("u64");
+        EXPECT_TRUE(var_u64);
+        ASSERT_EQ(var_u64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_u64.Steps(), 1);
+        ASSERT_EQ(var_u64.Shape()[0], Ny);
+        ASSERT_EQ(var_u64.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_r32 = io.InquireVariable("r32");
+        EXPECT_TRUE(var_r32);
+        ASSERT_EQ(var_r32.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r32.Steps(), 1);
+        ASSERT_EQ(var_r32.Shape()[0], Ny);
+        ASSERT_EQ(var_r32.Shape()[1], static_cast(mpiSize * Nx));
+
+        auto var_r64 = io.InquireVariable("r64");
+        EXPECT_TRUE(var_r64);
+        ASSERT_EQ(var_r64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r64.Steps(), 1);
+        ASSERT_EQ(var_r64.Shape()[0], Ny);
+        ASSERT_EQ(var_r64.Shape()[1], static_cast(mpiSize * Nx));
+
+        // If the size of the array is smaller than the data
+        // the result is weird... double and uint64_t would get
+        // completely garbage data
+        std::array I8;
+        std::array I16;
+        std::array I32;
+        std::array I64;
+        std::array U8;
+        std::array U16;
+        std::array U32;
+        std::array U64;
+        std::array R32;
+        std::array R64;
+
+        const adios2::Dims start{0, static_cast(mpiRank * Nx)};
+        const adios2::Dims count{Ny, Nx};
+
+        const adios2::Box sel(start, count);
+
+        var_i8.SetSelection(sel);
+        var_i16.SetSelection(sel);
+        var_i32.SetSelection(sel);
+        var_i64.SetSelection(sel);
+
+        var_u8.SetSelection(sel);
+        var_u16.SetSelection(sel);
+        var_u32.SetSelection(sel);
+        var_u64.SetSelection(sel);
+
+        var_r32.SetSelection(sel);
+        var_r64.SetSelection(sel);
+
+        for (size_t t = 0; t < 1; ++t)
+        {
+            var_i8.SetStepSelection({t, 1});
+            var_i16.SetStepSelection({t, 1});
+            var_i32.SetStepSelection({t, 1});
+            var_i64.SetStepSelection({t, 1});
+
+            var_u8.SetStepSelection({t, 1});
+            var_u16.SetStepSelection({t, 1});
+            var_u32.SetStepSelection({t, 1});
+            var_u64.SetStepSelection({t, 1});
+
+            var_r32.SetStepSelection({t, 1});
+            var_r64.SetStepSelection({t, 1});
+
+            bpReader.Get(var_i8, I8.data());
+            bpReader.Get(var_i16, I16.data());
+            bpReader.Get(var_i32, I32.data());
+            bpReader.Get(var_i64, I64.data());
+
+            bpReader.Get(var_u8, U8.data());
+            bpReader.Get(var_u16, U16.data());
+            bpReader.Get(var_u32, U32.data());
+            bpReader.Get(var_u64, U64.data());
+
+            bpReader.Get(var_r32, R32.data());
+            bpReader.Get(var_r64, R64.data());
+
+            bpReader.PerformGets();
+
+            // Generate test data for each rank uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, static_cast(t), mpiRank, mpiSize);
+
+            for (size_t i = 0; i < Nx * Ny; ++i)
+            {
+                std::stringstream ss;
+                ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
+                std::string msg = ss.str();
+
+                EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
+                EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
+                EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
+                EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
+                EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
+                EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
+                EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
+                EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
+                EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
+                EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
+            }
+        }
+        bpReader.Close();
+    }
+}
+
+TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead10D2x2)
+{
+    // Each process would write a 2x2x...x2 9D array and all processes would
+    // form a 10D NumberOfProcess x 2 x ... x 2) array
+
+    int mpiRank = 0, mpiSize = 1;
+
+#if ADIOS2_USE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+    const std::string fname("FlattenBPWriteRead10D2x2Test_MPI.bp");
+#else
+    const std::string fname("FlattenBPWriteRead10D2x2Test.bp");
+#endif
+
+    size_t NX = static_cast(mpiSize);
+    size_t OX = static_cast(mpiRank);
+    const adios2::Dims shape{NX, 2, 2, 2, 2, 2, 2, 2, 2, 2};
+    const adios2::Dims start{OX, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const adios2::Dims count{1, 2, 2, 2, 2, 2, 2, 2, 2, 2};
+
+    std::array R64w, R64r;
+    std::array, 512> CR64w, CR64r;
+
+    // Write test data using ADIOS2
+
+#if ADIOS2_USE_MPI
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+#else
+    adios2::ADIOS adios;
+#endif
+    {
+        adios2::IO io = adios.DeclareIO("TestIO");
+
+        // Declare 10D variables
+        {
+            auto var_r64 = io.DefineVariable("r64", shape, start, count);
+            EXPECT_TRUE(var_r64);
+            auto var_c64 = io.DefineVariable>("cr64", shape, start, count);
+            EXPECT_TRUE(var_c64);
+        }
+
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+        else
+        {
+            // Create the BP Engine
+            io.SetEngine("BPFile");
+        }
+        if (!engineParameters.empty())
+        {
+            io.SetParameters(engineParameters);
+        }
+
+        io.AddTransport("file");
+
+        adios2::Engine bpWriter = io.Open(fname, adios2::Mode::Write);
+
+        for (size_t step = 0; step < (size_t)mpiSize; ++step)
+        {
+            // double d = mpiRank + 1 + step / 10.0;
+            double d = mpiRank + 1 / 10.0; // every step is the same
+            // Generate test data for each process uniquely
+            std::for_each(R64w.begin(), R64w.end(), [&](double &v) {
+                v = d;
+                d += 0.0001;
+            });
+            std::for_each(CR64w.begin(), CR64w.end(), [&](std::complex &v) {
+                v.real(d);
+                v.imag(d);
+            });
+
+            // Retrieve the variables that previously went out of scope
+            auto var_r64 = io.InquireVariable("r64");
+            auto var_cr64 = io.InquireVariable>("cr64");
+
+            // Make a 2D selection to describe the local dimensions of the
+            // variable we write and its offsets in the global spaces
+            adios2::Box sel({start, count});
+            var_r64.SetSelection(sel);
+            var_cr64.SetSelection(sel);
+
+            // Write each one
+            // fill in the variable with values from starting index to
+            // starting index + count
+            bpWriter.BeginStep();
+            // write ranks in reverse, end down
+            if (step == (size_t)(mpiSize - mpiRank - 1))
+            {
+                bpWriter.Put(var_r64, R64w.data());
+                bpWriter.Put(var_cr64, CR64w.data());
+            }
+            bpWriter.EndStep();
+        }
+
+        // Close the file
+        bpWriter.Close();
+    }
+
+    {
+        adios2::IO io = adios.DeclareIO("ReadIO");
+
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+        if (!engineParameters.empty())
+        {
+            io.SetParameters(engineParameters);
+        }
+
+        adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadFlattenSteps);
+
+        EXPECT_EQ(bpReader.Steps(), 1);
+
+        auto var_r64 = io.InquireVariable("r64");
+        EXPECT_TRUE(var_r64);
+        ASSERT_EQ(var_r64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_r64.Steps(), 1);
+        ASSERT_EQ(var_r64.Shape().size(), 10);
+        ASSERT_EQ(var_r64.Shape()[0], NX);
+        ASSERT_EQ(var_r64.Shape()[1], 2);
+        ASSERT_EQ(var_r64.Shape()[2], 2);
+        ASSERT_EQ(var_r64.Shape()[3], 2);
+        ASSERT_EQ(var_r64.Shape()[4], 2);
+        ASSERT_EQ(var_r64.Shape()[5], 2);
+        ASSERT_EQ(var_r64.Shape()[6], 2);
+        ASSERT_EQ(var_r64.Shape()[7], 2);
+        ASSERT_EQ(var_r64.Shape()[8], 2);
+        ASSERT_EQ(var_r64.Shape()[9], 2);
+
+        auto var_cr64 = io.InquireVariable>("cr64");
+        EXPECT_TRUE(var_cr64);
+        ASSERT_EQ(var_cr64.ShapeID(), adios2::ShapeID::GlobalArray);
+        ASSERT_EQ(var_cr64.Steps(), 1);
+        ASSERT_EQ(var_cr64.Shape().size(), 10);
+        ASSERT_EQ(var_cr64.Shape()[0], NX);
+        ASSERT_EQ(var_cr64.Shape()[1], 2);
+        ASSERT_EQ(var_cr64.Shape()[2], 2);
+        ASSERT_EQ(var_cr64.Shape()[3], 2);
+        ASSERT_EQ(var_cr64.Shape()[4], 2);
+        ASSERT_EQ(var_cr64.Shape()[5], 2);
+        ASSERT_EQ(var_cr64.Shape()[6], 2);
+        ASSERT_EQ(var_cr64.Shape()[7], 2);
+        ASSERT_EQ(var_cr64.Shape()[8], 2);
+        ASSERT_EQ(var_cr64.Shape()[9], 2);
+
+        const adios2::Box sel(start, count);
+
+        var_r64.SetSelection(sel);
+        var_cr64.SetSelection(sel);
+
+        for (size_t step = 0; step < 1; ++step)
+        {
+            var_r64.SetStepSelection({step, 1});
+            var_cr64.SetStepSelection({step, 1});
+            bpReader.Get(var_r64, R64r.data());
+            bpReader.Get(var_cr64, CR64r.data());
+            bpReader.PerformGets();
+
+            // double d = mpiRank + 1 + step / 10.0;
+            double d = mpiRank + 1 / 10.0;
+            // Re-generate test data for each process uniquely that was written
+            std::for_each(R64w.begin(), R64w.end(), [&](double &v) {
+                v = d;
+                d += 0.0001;
+            });
+            std::for_each(CR64w.begin(), CR64w.end(), [&](std::complex &v) {
+                v.real(d);
+                v.imag(d);
+            });
+
+            for (size_t i = 0; i < 512; ++i)
+            {
+                std::stringstream ss;
+                ss << "t=" << step << " i=" << i << " rank=" << mpiRank;
+                std::string msg = ss.str();
+
+                EXPECT_EQ(R64r[i], R64w[i]) << msg;
+                EXPECT_EQ(CR64r[i], CR64w[i]) << msg;
+            }
+        }
+        bpReader.Close();
+    }
+}
+
+// ADIOS2 BP write and read 1D arrays
+TEST_F(BPWriteReadTestFlatten, FlattenBPWriteReadEmptyProcess)
+{
+#if ADIOS2_USE_MPI
+    // Each process, except rank 0 would write a 1x8 array and all
+    // processes would form a (mpiSize-1) * Nx 1D array
+    const std::string fname("FlattenBPWriteReadEmptyProces.bp");
+
+    int mpiRank = 0, mpiSize = 1;
+    // Number of rows
+    const size_t Nx = 8;
+
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+
+    // Number of steps
+    const size_t NSteps = mpiSize;
+
+    /* This is a parallel test, do not run in serial */
+    adios2::ADIOS adios(MPI_COMM_WORLD);
+    {
+        adios2::IO io = adios.DeclareIO("TestIO");
+        // Declare 1D variables (NumOfProcesses * Nx)
+        // The local process' part (start, count) can be defined now or later
+        // before Write().
+
+        adios2::Dims shape{static_cast(Nx * (mpiSize - 1))};
+        adios2::Dims start{static_cast(Nx * (mpiRank - 1))};
+        adios2::Dims count{Nx};
+        if (!mpiRank)
+        {
+            count[0] = 0;
+            start[0] = 0;
+        }
+
+        auto var_r32 = io.DefineVariable("r32", shape, start, count);
+        EXPECT_TRUE(var_r32);
+
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+        else
+        {
+            // Create the BP Engine
+            io.SetEngine("BPFile");
+        }
+        if (!engineParameters.empty())
+        {
+            io.SetParameters(engineParameters);
+        }
+
+        adios2::Engine bpWriter = io.Open(fname, adios2::Mode::Write);
+
+        for (size_t step = 0; step < NSteps; ++step)
+        {
+            // Generate test data for each process uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, static_cast(0), mpiRank, mpiSize);
+
+            bpWriter.BeginStep();
+            if (step == (size_t)mpiRank)
+            {
+                if (mpiRank != 0)
+                {
+                    bpWriter.Put(var_r32, currentTestData.R32.data());
+                }
+            }
+            bpWriter.EndStep();
+        }
+
+        // Close the file
+        bpWriter.Close();
+    }
+
+    {
+        adios2::IO io = adios.DeclareIO("ReadIO");
+
+        if (!engineName.empty())
+        {
+            io.SetEngine(engineName);
+        }
+        if (!engineParameters.empty())
+        {
+            io.SetParameters(engineParameters);
+        }
+
+        adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadFlattenSteps);
+
+        for (size_t step = 0; step < 1; ++step)
+        {
+            // Generate test data for each process uniquely
+            SmallTestData currentTestData =
+                generateNewSmallTestData(m_TestData, static_cast(0), mpiRank + 1, mpiSize);
+
+            auto var_r32 = io.InquireVariable("r32");
+            EXPECT_TRUE(var_r32);
+            ASSERT_EQ(var_r32.ShapeID(), adios2::ShapeID::GlobalArray);
+            ASSERT_EQ(var_r32.Shape()[0], (mpiSize - 1) * Nx);
+
+            SmallTestData testData;
+            std::array R32;
+
+            // last process does not read
+            // readers 0..N-2, while data was produced by 1..N-1
+            adios2::Dims start{mpiRank * Nx};
+            adios2::Dims count{Nx};
+
+            if (mpiRank == mpiSize - 1)
+            {
+                count[0] = 0;
+                start[0] = 0;
+            }
+
+            const adios2::Box sel(start, count);
+            var_r32.SetSelection(sel);
+
+            if (mpiRank < mpiSize - 1)
+            {
+                bpReader.Get(var_r32, R32.data(), adios2::Mode::Sync);
+                for (size_t i = 0; i < Nx; ++i)
+                {
+                    std::stringstream ss;
+                    ss << "t=" << step << " i=" << i << " rank=" << mpiRank;
+                    std::string msg = ss.str();
+                    EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
+                }
+            }
+        }
+        bpReader.Close();
+    }
+#else
+    return;
+#endif
+}
+
+//******************************************************************************
+// main
+//******************************************************************************
+
+int main(int argc, char **argv)
+{
+#if ADIOS2_USE_MPI
+    int provided;
+
+    // MPI_THREAD_MULTIPLE is only required if you enable the SST MPI_DP
+    MPI_Init_thread(nullptr, nullptr, MPI_THREAD_MULTIPLE, &provided);
+#endif
+
+    int result;
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (argc > 1)
+    {
+        engineName = std::string(argv[1]);
+    }
+    if (argc > 2)
+    {
+        engineParameters = std::string(argv[2]);
+    }
+    result = RUN_ALL_TESTS();
+
+#if ADIOS2_USE_MPI
+    MPI_Finalize();
+#endif
+
+    return result;
+}
diff --git a/testing/utils/cwriter/TestUtilsCWriter.bplsh.expected.txt b/testing/utils/cwriter/TestUtilsCWriter.bplsh.expected.txt
index 24bd5cd4c4..b768a7daf4 100644
--- a/testing/utils/cwriter/TestUtilsCWriter.bplsh.expected.txt
+++ b/testing/utils/cwriter/TestUtilsCWriter.bplsh.expected.txt
@@ -11,6 +11,7 @@ The time dimension is the first dimension then.
   --attrsonly | -A           List attributes only
   --meshes    | -m           List meshes
   --timestep  | -t           Read content step by step (stream reading)
+  --flatten                  Flatten Steps into one step (open in flatten mode)
   --dump      | -d           Dump matched variables/attributes
                                To match attributes too, add option -a
   --regexp    | -e           Treat masks as extended regular expressions

From 0dea90b255b3bbe1ffaff2d1f0a8b4bdc27aa204 Mon Sep 17 00:00:00 2001
From: Greg Eisenhauer 
Date: Fri, 26 Apr 2024 18:54:16 -0400
Subject: [PATCH 09/18] Minor docs tweaks (#4153)

---
 docs/user_guide/source/components/io.rst        | 2 +-
 docs/user_guide/source/tutorials/helloWorld.rst | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/docs/user_guide/source/components/io.rst b/docs/user_guide/source/components/io.rst
index 326b93ad34..4e6906bc6d 100644
--- a/docs/user_guide/source/components/io.rst
+++ b/docs/user_guide/source/components/io.rst
@@ -196,7 +196,7 @@ A particular ``Engine`` type is set to the current ``IO`` component with the ``I
 Engine polymorphism is handled internally by the ``IO`` class, which allows subclassing future derived ``Engine`` types without changing the basic API.
 
 ``Engine`` objects are created in various modes.
-The available modes are ``adios2::Mode::Read``, ``adios2::Mode::Write``, ``adios2::Mode::Append``, ``adios2::Mode::Sync``, ``adios2::Mode::Deferred``, and ``adios2::Mode::Undefined``.
+The available modes are ``adios2::Mode::Read``, ``adios2::Mode::ReadRandomAccess``, ``adios2::Mode::ReadFlattenSteps``, ``adios2::Mode::Write``, ``adios2::Mode::Append``, ``adios2::Mode::Sync``, ``adios2::Mode::Deferred``, and ``adios2::Mode::Undefined``.
 
 
 .. code-block:: c++
diff --git a/docs/user_guide/source/tutorials/helloWorld.rst b/docs/user_guide/source/tutorials/helloWorld.rst
index a0e424a097..cdc709eea0 100644
--- a/docs/user_guide/source/tutorials/helloWorld.rst
+++ b/docs/user_guide/source/tutorials/helloWorld.rst
@@ -86,6 +86,7 @@ Start editing the skeleton file `ADIOS2/examples/hello/helloWorld/hello-world_tu
 
   adios2::Engine reader = io.Open("hello-world-cpp.bp", adios2::Mode::Read);
   std::string greeting;
+  reader.BeginStep();
   reader.Get(varGreeting, greeting);
   reader.EndStep();
   reader.Close();
@@ -93,7 +94,7 @@ Start editing the skeleton file `ADIOS2/examples/hello/helloWorld/hello-world_tu
 
 .. note::
 
-  The ``BeginStep`` and ``EndStep`` calls are required when **reading** one step and multiple steps. We will see in
+  In Mode::Read, the ``BeginStep`` and ``EndStep`` calls are required when **reading** one step and multiple steps. We will see in
   another tutorial how to read multiple steps. It's important to note that the ``BeginStep`` should be called **before**
   all ``Inquire*`` / ``Available*`` function calls.
 

From 78137c5a8a627881f40115fd8cc13f1aab00df7c Mon Sep 17 00:00:00 2001
From: Ana Gainaru 
Date: Sat, 11 May 2024 10:03:15 -0400
Subject: [PATCH 10/18] Merge pull request #4161 from
 anagainaru/derived-performance

Adding hooks to gather performance for derived variables
---
 source/adios2/engine/bp5/BP5Writer.cpp                | 3 +++
 source/adios2/toolkit/derived/Function.cpp            | 4 ++++
 source/adios2/toolkit/profiling/iochrono/IOChrono.cpp | 2 ++
 3 files changed, 9 insertions(+)

diff --git a/source/adios2/engine/bp5/BP5Writer.cpp b/source/adios2/engine/bp5/BP5Writer.cpp
index ff1889577e..856ef2134b 100644
--- a/source/adios2/engine/bp5/BP5Writer.cpp
+++ b/source/adios2/engine/bp5/BP5Writer.cpp
@@ -507,9 +507,11 @@ void BP5Writer::MarshalAttributes()
 #ifdef ADIOS2_HAVE_DERIVED_VARIABLE
 void BP5Writer::ComputeDerivedVariables()
 {
+    PERFSTUBS_SCOPED_TIMER("BP5Writer::ComputeDerivedVariables");
     auto const &m_VariablesDerived = m_IO.GetDerivedVariables();
     auto const &m_Variables = m_IO.GetVariables();
     // parse all derived variables
+    m_Profiler.Start("DeriveVars");
     for (auto it = m_VariablesDerived.begin(); it != m_VariablesDerived.end(); it++)
     {
         // identify the variables used in the derived variable
@@ -562,6 +564,7 @@ void BP5Writer::ComputeDerivedVariables()
             free(std::get<0>(derivedBlock));
         }
     }
+    m_Profiler.Stop("DeriveVars");
 }
 #endif
 
diff --git a/source/adios2/toolkit/derived/Function.cpp b/source/adios2/toolkit/derived/Function.cpp
index 441be6a7c6..da64e37f60 100644
--- a/source/adios2/toolkit/derived/Function.cpp
+++ b/source/adios2/toolkit/derived/Function.cpp
@@ -5,6 +5,7 @@
 #include "Function.tcc"
 #include "adios2/common/ADIOSMacros.h"
 #include "adios2/helper/adiosFunctions.h"
+#include 
 #include 
 
 namespace adios2
@@ -14,6 +15,7 @@ namespace derived
 
 DerivedData AddFunc(std::vector inputData, DataType type)
 {
+    PERFSTUBS_SCOPED_TIMER("derived::Function::AddFunc");
     size_t dataSize = std::accumulate(std::begin(inputData[0].Count), std::end(inputData[0].Count),
                                       1, std::multiplies());
 
@@ -31,6 +33,7 @@ DerivedData AddFunc(std::vector inputData, DataType type)
 
 DerivedData MagnitudeFunc(std::vector inputData, DataType type)
 {
+    PERFSTUBS_SCOPED_TIMER("derived::Function::MagnitudeFunc");
     size_t dataSize = std::accumulate(std::begin(inputData[0].Count), std::end(inputData[0].Count),
                                       1, std::multiplies());
 #define declare_type_mag(T)                                                                        \
@@ -147,6 +150,7 @@ float linear_interp(DerivedData input, size_t index, size_t dim)
  */
 DerivedData Curl3DFunc(const std::vector inputData, DataType type)
 {
+    PERFSTUBS_SCOPED_TIMER("derived::Function::Curl3DFunc");
     size_t dataSize = inputData[0].Count[0] * inputData[0].Count[1] * inputData[0].Count[2];
 
     DerivedData curl;
diff --git a/source/adios2/toolkit/profiling/iochrono/IOChrono.cpp b/source/adios2/toolkit/profiling/iochrono/IOChrono.cpp
index 0cfd7eef26..1002d110ae 100644
--- a/source/adios2/toolkit/profiling/iochrono/IOChrono.cpp
+++ b/source/adios2/toolkit/profiling/iochrono/IOChrono.cpp
@@ -56,6 +56,8 @@ JSONProfiler::JSONProfiler(helper::Comm const &comm) : m_Comm(comm)
     AddTimerWatch("DC_WaitOnAsync2");
     AddTimerWatch("PDW");
 
+    AddTimerWatch("DeriveVars");
+
     m_Profiler.m_Bytes.emplace("buffering", 0);
     AddTimerWatch("DataRead");
     m_Profiler.m_Bytes.emplace("dataread", 0);

From ee179efb4a9433e917c3ff8fde576ab5dc3e973f Mon Sep 17 00:00:00 2001
From: Ana Gainaru 
Date: Fri, 17 May 2024 10:59:42 -0400
Subject: [PATCH 11/18] Typo in the build command inside the documentation
 (#4166)

---
 docs/user_guide/source/setting_up/source/cmake.rst | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/docs/user_guide/source/setting_up/source/cmake.rst b/docs/user_guide/source/setting_up/source/cmake.rst
index d268fdd764..ce5b44dd2a 100644
--- a/docs/user_guide/source/setting_up/source/cmake.rst
+++ b/docs/user_guide/source/setting_up/source/cmake.rst
@@ -8,7 +8,7 @@ To build ADIOS v2.x, clone the repository and invoke the canonical CMake build s
 
     $ git clone https://github.com/ornladios/ADIOS2.git ADIOS2
     $ mkdir adios2-build && cd adios2-build
-    $ cmake ../ADIOS2 cmake -DADIOS2_BUILD_EXAMPLES=ON
+    $ cmake ../ADIOS2 -DADIOS2_BUILD_EXAMPLES=ON
     -- The C compiler identification is GNU 9.4.0
     -- The CXX compiler identification is GNU 9.4.0
     ...
@@ -111,10 +111,11 @@ Optionally, run the tests (need to configure with ``-DBUILD_TESTING=ON`` cmake f
     Total Test time (real) =   95.95 sec
 
 
-And finally, use the standard invocation to install:
+And finally, use the standard invocation to install (setting the install path beforehand):
 
 .. code-block:: bash
 
+    $ cmake ../ADIOS2 -DCMAKE_INSTALL_PREFIX=/path/to/where/adios/will/be/installed
     $ make install
 
 

From 83112ab7374b3196ea0b9c37e573c2c285d08b5d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Franz=20P=C3=B6schel?= 
Date: Fri, 24 May 2024 13:11:57 +0200
Subject: [PATCH 12/18] Add API call to reset memory selection (#4169)

* Add API to reset memory selection
---
 bindings/CXX11/adios2/cxx11/Variable.h | 2 +-
 source/adios2/core/VariableBase.cpp    | 7 +++++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/bindings/CXX11/adios2/cxx11/Variable.h b/bindings/CXX11/adios2/cxx11/Variable.h
index b2263a5780..ded48baded 100644
--- a/bindings/CXX11/adios2/cxx11/Variable.h
+++ b/bindings/CXX11/adios2/cxx11/Variable.h
@@ -214,7 +214,7 @@ class Variable
      * variable.Count() = {Ny,Nx}, then memoryCount = {Ny+2,Nx+2}
      * 
*/ - void SetMemorySelection(const adios2::Box &memorySelection); + void SetMemorySelection(const adios2::Box &memorySelection = {{}, {}}); /** * Sets a step selection modifying current startStep, countStep diff --git a/source/adios2/core/VariableBase.cpp b/source/adios2/core/VariableBase.cpp index 2eb3442c0c..0bb9311471 100644 --- a/source/adios2/core/VariableBase.cpp +++ b/source/adios2/core/VariableBase.cpp @@ -221,6 +221,13 @@ void VariableBase::SetMemorySelection(const Box &memorySelection) const Dims &memoryStart = memorySelection.first; const Dims &memoryCount = memorySelection.second; + if (memoryStart.empty() && memoryCount.empty()) + { + m_MemoryStart.clear(); + m_MemoryCount.clear(); + return; + } + if (m_SingleValue) { helper::Throw("Core", "VariableBase", "SetMemorySelection", From 7e8248e13e06ea6e6c6b6f0f32500a9eee7a159d Mon Sep 17 00:00:00 2001 From: Greg Eisenhauer Date: Mon, 27 May 2024 20:57:44 -0400 Subject: [PATCH 13/18] EVPath 2024-05-27 (45471c87) (#4181) Code extracted from: https://github.com/GTkorvo/EVPath.git at commit 45471c87f14c735bb4a3f92477f3a04b0a06b18a (master). --- thirdparty/EVPath/EVPath/gen_interface.pl | 692 +++++++++++----------- 1 file changed, 354 insertions(+), 338 deletions(-) diff --git a/thirdparty/EVPath/EVPath/gen_interface.pl b/thirdparty/EVPath/EVPath/gen_interface.pl index f76852ba75..d79335ea5d 100755 --- a/thirdparty/EVPath/EVPath/gen_interface.pl +++ b/thirdparty/EVPath/EVPath/gen_interface.pl @@ -10,26 +10,26 @@ sub gen_type print REVP " int condition_var;\n"; @args = split( ", ", $arg_str,2); foreach $arg (split (", ", $args[1])) { - $_ = $arg; - if (/^\s*(.*\W+)(\w+)$\s*/) { - $argtype = $1; - $argname = $2; - $argtype =~ s/\s+$//; - $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space - $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space - $iotype = $argtype; - $sizetype = $argtype; - switch:for ($argtype) { - /attr_list/ && do {$iotype = "string"; $argtype="char*"; last;}; - /char*/ && do {$iotype = "string"; $argtype="char*"; last;}; - /EVstone$/ && do {$iotype = "integer"; $argtype="EVstone"; last;}; - /EVstone\*/ && do {print REVP " int ${argname}_len;\n"; + $_ = $arg; + if (/^\s*(.*\W+)(\w+)$\s*/) { + $argtype = $1; + $argname = $2; + $argtype =~ s/\s+$//; + $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space + $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space + $iotype = $argtype; + $sizetype = $argtype; + switch:for ($argtype) { + /attr_list/ && do {$iotype = "string"; $argtype="char*"; last;}; + /char*/ && do {$iotype = "string"; $argtype="char*"; last;}; + /EVstone$/ && do {$iotype = "integer"; $argtype="EVstone"; last;}; + /EVstone\*/ && do {print REVP " int ${argname}_len;\n"; $iotype = "integer[${argname}_len]"; $argtype="int *"; last;}; - /EVSimpleHandlerFunc$/ && do {$iotype = "string"; $argtype="char*"; last;}; - /FMStructDescList/ && do {$iotype = "string"; $argtype="char*"; last;}; - } - } - print REVP " $argtype $argname;\n"; + /EVSimpleHandlerFunc$/ && do {$iotype = "string"; $argtype="char*"; last;}; + /FMStructDescList/ && do {$iotype = "string"; $argtype="char*"; last;}; + } + } + print REVP " $argtype $argname;\n"; } print REVP "} ${subr}_request;\n"; $ret_type = $return_type{$subr}; @@ -52,27 +52,27 @@ sub gen_field_list print REVP " {\"condition_var\", \"integer\", sizeof(int), FMOffset(${subr}_request*, condition_var)},\n"; @args = split( ", ", $arg_str,2); foreach $arg (split (", ", $args[1])) { - $_ = $arg; - if (/^\s*(.*\W+)(\w+)$\s*/) { - $argtype = $1; - $argname = $2; - $argtype =~ s/\s+$//; - $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space - $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space - $iotype = $argtype; - $sizetype = $argtype; - switch:for ($argtype) { - /attr_list/ && do {$iotype = "string"; $argtype="char*"; last;}; - /char*/ && do {$iotype = "string"; $argtype="char*"; last;}; - /void*/ && do {$iotype = "char[${argname}_len"; $argtype="void*"; last;}; - /int/ && do {$iotype = "integer"; $argtype="int"; last;}; - /EVstone/ && do {$iotype = "integer"; $argtype="EVstone"; last;}; - /EVaction/ && do {$iotype = "integer"; $argtype="EVaction"; last;}; - /EVSimpleHandlerFunc/ && do {$iotype = "string"; $argtype="EVSimpleHandlerFunc"; last;}; - /FMStructDescList/ && do {$iotype = "string"; $argtype="EVSimpleHandlerFunc"; last;}; - } - } - print REVP " {\"$argname\", \"$iotype\", sizeof($sizetype), FMOffset(${subr}_request*,$argname)},\n"; + $_ = $arg; + if (/^\s*(.*\W+)(\w+)$\s*/) { + $argtype = $1; + $argname = $2; + $argtype =~ s/\s+$//; + $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space + $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space + $iotype = $argtype; + $sizetype = $argtype; + switch:for ($argtype) { + /attr_list/ && do {$iotype = "string"; $argtype="char*"; last;}; + /char*/ && do {$iotype = "string"; $argtype="char*"; last;}; + /void*/ && do {$iotype = "char[${argname}_len"; $argtype="void*"; last;}; + /int/ && do {$iotype = "integer"; $argtype="int"; last;}; + /EVstone/ && do {$iotype = "integer"; $argtype="EVstone"; last;}; + /EVaction/ && do {$iotype = "integer"; $argtype="EVaction"; last;}; + /EVSimpleHandlerFunc/ && do {$iotype = "string"; $argtype="EVSimpleHandlerFunc"; last;}; + /FMStructDescList/ && do {$iotype = "string"; $argtype="EVSimpleHandlerFunc"; last;}; + } + } + print REVP " {\"$argname\", \"$iotype\", sizeof($sizetype), FMOffset(${subr}_request*,$argname)},\n"; } print REVP " {NULL, NULL, 0, 0}\n};\n"; print REVP "\nFMStructDescRec ${subr}_req_formats[] = {\n"; @@ -87,17 +87,17 @@ sub gen_stub { print REVP "\nextern $return_type{$subr}\n"; print REVPHI "\nextern $return_type{$subr}\n"; if ($#args > 0) { - print REVP "INT_R$subr(CMConnection conn, $args[1])\n"; - print REVPHI "INT_R$subr(CMConnection conn, $args[1]);\n"; + print REVP "INT_R$subr(CMConnection conn, $args[1])\n"; + print REVPHI "INT_R$subr(CMConnection conn, $args[1]);\n"; } else { - print REVP "INT_R$subr(CMConnection conn)\n"; - print REVPHI "INT_R$subr(CMConnection conn);\n"; + print REVP "INT_R$subr(CMConnection conn)\n"; + print REVPHI "INT_R$subr(CMConnection conn);\n"; } print REVP "{\n"; $_ = $return_type{$subr}; if (/^\s*void\s*$/) { - $return_type{$subr} = "void"; + $return_type{$subr} = "void"; } $retsubtype = $return_type{$subr}; switch: for ($ret_type) { @@ -115,33 +115,33 @@ sub gen_stub { print REVP " f = INT_CMlookup_format(conn->cm, ${subr}_req_formats);\n"; $free_list = ""; foreach $arg (split (", ", $args[1])) { - $_ = $arg; - if (/^\s*(.*\W+)(\w+)$\s*/) { - $argtype = $1; - $argname = $2; - $argtype =~ s/\s+$//; - $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space - $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space - $argright = $argname; - switch:for ($argtype) { - /attr_list/ && do {$argright = "attr_list_to_string($argname)"; $free_list .= " free(request.$argname);\n"; last;}; - /FMStructDescList/ && do {$argright = "get_format_name(conn->cm, $argname)"; last;}; - } - } - print REVP " request.$argname = $argright;\n"; + $_ = $arg; + if (/^\s*(.*\W+)(\w+)$\s*/) { + $argtype = $1; + $argname = $2; + $argtype =~ s/\s+$//; + $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space + $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space + $argright = $argname; + switch:for ($argtype) { + /attr_list/ && do {$argright = "attr_list_to_string($argname)"; $free_list .= " free(request.$argname);\n"; last;}; + /FMStructDescList/ && do {$argright = "get_format_name(conn->cm, $argname)"; last;}; + } + } + print REVP " request.$argname = $argright;\n"; } print REVP " request.condition_var = cond;\n"; print REVP " if (f == NULL) {\n"; print REVP " f = INT_CMregister_format(conn->cm, ${subr}_req_formats);\n"; print REVP " }\n"; if ($return_type{$subr} eq "void") { - print REVP " INT_CMCondition_set_client_data(conn->cm, cond, NULL);\n"; + print REVP " INT_CMCondition_set_client_data(conn->cm, cond, NULL);\n"; } else { - print REVP " INT_CMCondition_set_client_data(conn->cm, cond, &response);\n"; + print REVP " INT_CMCondition_set_client_data(conn->cm, cond, &response);\n"; } print REVP " INT_CMwrite(conn, f, &request);\n"; if ("$free_list" ne "") { - print REVP "$free_list"; + print REVP "$free_list"; } print REVP " INT_CMCondition_wait(conn->cm, cond);\n"; switch:for ($return_type{$subr}) { @@ -173,7 +173,7 @@ sub gen_wrapper { print REVP "{\n"; $_ = $return_type{$subr}; if (/^\s*void\s*$/) { - $return_type{$subr} = "void"; + $return_type{$subr} = "void"; } $retsubtype = $return_type{$subr}; switch: for ($ret_type) { @@ -190,21 +190,21 @@ sub gen_wrapper { print REVP " ret = INT_R${subr}(conn"; } foreach $arg (split (", ", $args[1])) { - $_ = $arg; - if (/^\s*(.*\W+)(\w+)$\s*/) { - $argtype = $1; - $argname = $2; - $argtype =~ s/\s+$//; - $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space - $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space - $argright = "$argname"; - switch:for ($argtype) { - /attr_list/ && do {$argright = "$argname"; last;}; - /EVSimpleHandlerFunc/ && do {$argright = "$argname"; last;}; - /FMStructDescList/ && do {$argright = "$argname"; last;}; - } - } - print REVP ", $argright"; + $_ = $arg; + if (/^\s*(.*\W+)(\w+)$\s*/) { + $argtype = $1; + $argname = $2; + $argtype =~ s/\s+$//; + $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space + $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space + $argright = "$argname"; + switch:for ($argtype) { + /attr_list/ && do {$argright = "$argname"; last;}; + /EVSimpleHandlerFunc/ && do {$argright = "$argname"; last;}; + /FMStructDescList/ && do {$argright = "$argname"; last;}; + } + } + print REVP ", $argright"; } print REVP ");\n"; print REVP " CManager_unlock(conn->cm);\n"; @@ -229,7 +229,7 @@ sub gen_handler { print REVP "{\n"; $_ = $return_type{$subr}; if (/^\s*void\s*$/) { - $return_type{$subr} = "void"; + $return_type{$subr} = "void"; } $retsubtype = $return_type{$subr}; switch: for ($ret_type) { @@ -248,43 +248,43 @@ sub gen_handler { print REVP " f = INT_CMregister_format(conn->cm, EV_${retsubtype}_response_formats);\n"; print REVP " }\n"; foreach $arg (split (", ", $args[1])) { - $_ = $arg; - if (/^\s*(.*\W+)(\w+)$\s*/) { - $argtype = $1; - $argname = $2; - $argtype =~ s/\s+$//; - $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space - $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space - $argright = $argname; - switch:for ($argtype) { - /attr_list/ && do {print REVP " attr_list $argname = attr_list_from_string(request->$argname);\n"; last;}; - /EVSimpleHandlerFunc/ && do {print REVP " EVSimpleHandlerFunc $argname = REVPlookup_handler(request->$argname);\n"; last;}; - /FMStructDescList/ && do {print REVP " FMStructDescList $argname = REVPlookup_format_structs(conn->cm, request->$argname);\n"; last;}; - } - } + $_ = $arg; + if (/^\s*(.*\W+)(\w+)$\s*/) { + $argtype = $1; + $argname = $2; + $argtype =~ s/\s+$//; + $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space + $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space + $argright = $argname; + switch:for ($argtype) { + /attr_list/ && do {print REVP " attr_list $argname = attr_list_from_string(request->$argname);\n"; last;}; + /EVSimpleHandlerFunc/ && do {print REVP " EVSimpleHandlerFunc $argname = REVPlookup_handler(request->$argname);\n"; last;}; + /FMStructDescList/ && do {print REVP " FMStructDescList $argname = REVPlookup_format_structs(conn->cm, request->$argname);\n"; last;}; + } + } } if ($return_type{$subr} eq "void") { - print REVP " $subr(cm"; + print REVP " $subr(cm"; } else { - print REVP " ret = $subr(cm"; + print REVP " ret = $subr(cm"; } $after = ""; foreach $arg (split (", ", $args[1])) { - $_ = $arg; - if (/^\s*(.*\W+)(\w+)$\s*/) { - $argtype = $1; - $argname = $2; - $argtype =~ s/\s+$//; - $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space - $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space - $argright = "request->$argname"; - switch:for ($argtype) { - /attr_list/ && do {$argright = "$argname"; $after .= "free_attr_list($argname);\n"; last;}; - /EVSimpleHandlerFunc/ && do {$argright = "$argname"; last;}; - /FMStructDescList/ && do {$argright = "$argname"; last;}; - } - } - print REVP ", $argright"; + $_ = $arg; + if (/^\s*(.*\W+)(\w+)$\s*/) { + $argtype = $1; + $argname = $2; + $argtype =~ s/\s+$//; + $argtype =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space + $argtype =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space + $argright = "request->$argname"; + switch:for ($argtype) { + /attr_list/ && do {$argright = "$argname"; $after .= "free_attr_list($argname);\n"; last;}; + /EVSimpleHandlerFunc/ && do {$argright = "$argname"; last;}; + /FMStructDescList/ && do {$argright = "$argname"; last;}; + } + } + print REVP ", $argright"; } if ($has_client_data == 1) {print REVP ", NULL";} print REVP ");\n"; @@ -311,7 +311,7 @@ sub strip_client_data { @args = split( ", ", $arguments{$subr}); $_ = pop(@args); if (!/.*client_data\W*$/) { - push(@args, $_); + push(@args, $_); } $arg_str = join(", ", @args); } @@ -321,10 +321,10 @@ sub mod_EVhandler { local(@args); @args = split( ", ", $arg_str); for( my $i=0; $i < scalar(@args); $i++) { - $_ = $args[$i]; - if (/\W*EVSimpleHandlerFunc.*$/) { - $args[$i] = "char *handler"; - } + $_ = $args[$i]; + if (/\W*EVSimpleHandlerFunc.*$/) { + $args[$i] = "char *handler"; + } } $arg_str = join(", ", @args); return $arg_str; @@ -332,23 +332,39 @@ sub mod_EVhandler { { local ($/, *INPUT); - + + $cat = "cat"; + if ($^O eq "MSWin32") { + $cat = "powershell.exe Get-Content"; + } $cat_args = ""; $has_ev_dfg = 0; $cm_only = 0; + $index = 0; foreach my $a(@ARGV) { - if ($a =~ "-CM_ONLY") { - $cm_only = 1; - next; - } - $a=~s/ /\\ /g; - $cat_args .= "$a "; - if ($a =~ /ev_dfg/) { - $has_evdfg = 1; - } + if ($a =~ "-CM_ONLY") { + $cm_only = 1; + next; + } + $a=~s/ /\\ /g; + + if ($^O eq "MSWin32") { + $sep = ","; + } else { + $sep = " "; + } + if ($index == 0) + { + $sep = ""; + } + $cat_args .= "$sep$a"; + if ($a =~ /ev_dfg/) { + $has_evdfg = 1; + } + $index++; } - unless (open(INPUT, "cat $cat_args |")) { - die "sudden flaming death, no file: $cat_args\n"; + unless (open(INPUT, "$cat $cat_args |")) { + die "sudden flaming death, no file: $cat_args\n"; } $_ = ; @@ -361,76 +377,76 @@ sub mod_EVhandler { LINE: for (@f) { if (/NOLOCK/) { - $nolock = 1; + $nolock = 1; } if (/REMOTE/) { - $remote = 1; + $remote = 1; } if (/^extern/) { - next LINE if (/\"C\"/); - $decl = ""; - if ($nolock == 1) {$decl = "NOLOCK";} - if ($remote == 1) {$decl = "REMOTE";} - $nolock = 0; - $remote = 0; - $pending = 1; + next LINE if (/\"C\"/); + $decl = ""; + if ($nolock == 1) {$decl = "NOLOCK";} + if ($remote == 1) {$decl = "REMOTE";} + $nolock = 0; + $remote = 0; + $pending = 1; } if (($pending) && /;/) { - $decl = $decl . " " . $_; - push (@DECLS, $decl); - $pending = 0; + $decl = $decl . " " . $_; + push (@DECLS, $decl); + $pending = 0; } if ($pending) { - $decl = $decl . " " . $_; + $decl = $decl . " " . $_; } } for (@DECLS) { $nolock = 0; $remote = 0; if (/NOLOCK/) { - s/NOLOCK//g; - $nolock = 1; + s/NOLOCK//g; + $nolock = 1; } if (/REMOTE/) { - s/REMOTE//g; - $remote = 1; + s/REMOTE//g; + $remote = 1; } if (/extern\W+(\w+\W+)(\w+)\W*\((.*)\)/) { - $return = $1; - $name = $2; - $_ = $3; - s/\)//g; - s/\s+/ /g; - $return =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space - $return =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space - $return =~ s/\s*$//; #remove unnecessary white space - $return =~ s/^\s*//; #remove unnecessary white space - $return_type{$name} = $return; - $args = $_; - $arguments{$name} = "$args"; + $return = $1; + $name = $2; + $_ = $3; + s/\)//g; + s/\s+/ /g; + $return =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space + $return =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space + $return =~ s/\s*$//; #remove unnecessary white space + $return =~ s/^\s*//; #remove unnecessary white space + $return_type{$name} = $return; + $args = $_; + $arguments{$name} = "$args"; } else { if (/extern\W+(\w+\W+\w+\W+)(\w+).*\((.*)\)/) { - $return = $1; - $name = $2; - $_ = $3; - s/\)//g; - s/\s+/ /g; - $return =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space - $return =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space - $return =~ s/\s*$//; #remove unnecessary white space - $return =~ s/^\s*//; #remove unnecessary white space - $return_type{$name} = $return; - $args = $_; - $arguments{$name} = "$args"; + $return = $1; + $name = $2; + $_ = $3; + s/\)//g; + s/\s+/ /g; + $return =~ s/(?!\w)\s+(?=\W)//; #remove unnecessary white space + $return =~ s/(?!\W)\s+(?=\w)//; #remove unnecessary white space + $return =~ s/\s*$//; #remove unnecessary white space + $return =~ s/^\s*//; #remove unnecessary white space + $return_type{$name} = $return; + $args = $_; + $arguments{$name} = "$args"; } else { - print "Failed to match function2 on $_\n" + print "Failed to match function2 on $_\n" } } if ($nolock == 1) { - $nolocking{$name} = 1; + $nolocking{$name} = 1; } if ($remote == 1) { - $remote_enabled{$name} = 1; + $remote_enabled{$name} = 1; } } @@ -459,121 +475,121 @@ sub mod_EVhandler { print INT "#include \"ev_dfg_internal.h\"\n"; } print INT<cm"; - } - if (/EVmaster\W/) { - $cmanager = $name. "->cm"; - } - if (/EVdfg_stone\W/) { - $evdfg_stone = $name; - } - } - - $_ = $return_type{$subr}; - if (/^\s*void\s*$/) { - $return_type{$subr} = "void"; - } - if ($return_type{$subr} ne "void") { - print INT "\t$return_type{$subr} ret;\n"; - } - if (!defined($nolocking{$subr})) { - if (defined($cmanager)) { - print INT "\tCManager_lock($cmanager);\n"; - } else { - if (defined($cmconnection)) { - print INT "\tCManager cm = $cmconnection->cm;\n"; - } elsif (defined($evsource)) { - print INT "\tCManager cm = $evsource->cm;\n"; - } elsif (defined($cmtaskhandle)) { - print INT "\tCManager cm = $cmtaskhandle->cm;\n"; - } elsif (defined($cmformat)) { - print INT "\tCManager cm = $cmformat->cm;\n"; - } elsif (defined($evdfg)) { - print INT "\tCManager cm = $evdfg->master->cm;\n"; - } elsif (defined($evdfg_stone)) { - print INT "\tCManager cm = $evdfg_stone->dfg->master->cm;\n"; - } else { -# print INT "\tCManager cm = duh;\n"; - } - print INT "\tCManager_lock(cm);\n"; - } - } - if ($return_type{$subr} eq "void") { - print INT "\t"; - } else { - print INT "\tret = "; - } - - print INT "INT_$subr("; - $first = 1; - foreach $arg (split ( ",", $arguments{$subr})) { - if ($first != 1) { - print INT ", "; - } else { - $first = 0; - } - $_ = $arg; - if (/\W+(\w+)\W*$/) { - print INT "$1"; - } - } - print INT ");\n"; - if ((!defined($nolocking{$subr})) && ($subr ne "CManager_close")) { - if (defined($cmanager)) { - print INT "\tCManager_unlock($cmanager);\n"; - } else { - print INT "\tCManager_unlock(cm);\n"; - } - } - print INT "\treturn ret;\n" unless ($return_type{$subr} eq "void"); - print INT "}\n"; + if ($cm_only && (($subr =~ /^EV/) || ($subr =~ /^create/))) { + next; + } + print INT "\nextern $return_type{$subr}\n"; + print INT "$subr ( $arguments{$subr} )\n"; + print INT "{\n"; + undef $cmanager; + undef $cmconnection; + undef $evsource; + undef $cmtaskhandle; + undef $cmformat; + undef $evdfg; + undef $evdfg_stone; + foreach $arg (split ( ",", $arguments{$subr})) { + $_ = $arg; + if (/\W+(\w+)\W*$/) { + $name = $1; + } + if (/CManager/) { + $cmanager = $name; + } + if (/CMConnection/) { + $cmconnection = $name; + } + if (/EVsource/) { + $evsource = $name; + } + if (/CMTaskHandle/) { + $cmtaskhandle = $name; + } + if (/CMFormat\W/) { + $cmformat = $name; + } + if (/EVdfg\W/) { + $evdfg = $name; + } + if (/EVclient\W/) { + $cmanager = $name. "->cm"; + } + if (/EVmaster\W/) { + $cmanager = $name. "->cm"; + } + if (/EVdfg_stone\W/) { + $evdfg_stone = $name; + } + } + + $_ = $return_type{$subr}; + if (/^\s*void\s*$/) { + $return_type{$subr} = "void"; + } + if ($return_type{$subr} ne "void") { + print INT "\t$return_type{$subr} ret;\n"; + } + if (!defined($nolocking{$subr})) { + if (defined($cmanager)) { + print INT "\tCManager_lock($cmanager);\n"; + } else { + if (defined($cmconnection)) { + print INT "\tCManager cm = $cmconnection->cm;\n"; + } elsif (defined($evsource)) { + print INT "\tCManager cm = $evsource->cm;\n"; + } elsif (defined($cmtaskhandle)) { + print INT "\tCManager cm = $cmtaskhandle->cm;\n"; + } elsif (defined($cmformat)) { + print INT "\tCManager cm = $cmformat->cm;\n"; + } elsif (defined($evdfg)) { + print INT "\tCManager cm = $evdfg->master->cm;\n"; + } elsif (defined($evdfg_stone)) { + print INT "\tCManager cm = $evdfg_stone->dfg->master->cm;\n"; + } else { +# print INT "\tCManager cm = duh;\n"; + } + print INT "\tCManager_lock(cm);\n"; + } + } + if ($return_type{$subr} eq "void") { + print INT "\t"; + } else { + print INT "\tret = "; + } + + print INT "INT_$subr("; + $first = 1; + foreach $arg (split ( ",", $arguments{$subr})) { + if ($first != 1) { + print INT ", "; + } else { + $first = 0; + } + $_ = $arg; + if (/\W+(\w+)\W*$/) { + print INT "$1"; + } + } + print INT ");\n"; + if ((!defined($nolocking{$subr})) && ($subr ne "CManager_close")) { + if (defined($cmanager)) { + print INT "\tCManager_unlock($cmanager);\n"; + } else { + print INT "\tCManager_unlock(cm);\n"; + } + } + print INT "\treturn ret;\n" unless ($return_type{$subr} eq "void"); + print INT "}\n"; } print "done\n"; print INT<evp->fmc, (char*)id); free(id); @@ -825,27 +841,27 @@ sub mod_EVhandler { EOF foreach $subr (sort (keys %return_type)) { - defined($remote_enabled{$subr}) || next; - - print REVPH "\nextern $return_type{$subr}\n"; - $no_client_data = strip_client_data($arguments{$subr}); - $no_handler = mod_EVhandler($no_client_data); - $_ = $arguments{$subr}; - $has_client_data = 0; - if (/.*client_data\W*$/) { - $has_client_data = 1; - } - @args = split( ", ", $no_handler, 2); - if ($#args > 0) { - print REVPH "R$subr(CMConnection conn, $args[1]);\n"; - } else { - print REVPH "R$subr(CMConnection conn);\n"; - } - gen_type(${subr}, $no_handler); - gen_field_list(${subr}, $no_handler); - gen_stub(${subr}, $no_handler); - gen_wrapper(${subr}, $no_handler, $has_client_data); - gen_handler(${subr}, $no_client_data, $has_client_data); + defined($remote_enabled{$subr}) || next; + + print REVPH "\nextern $return_type{$subr}\n"; + $no_client_data = strip_client_data($arguments{$subr}); + $no_handler = mod_EVhandler($no_client_data); + $_ = $arguments{$subr}; + $has_client_data = 0; + if (/.*client_data\W*$/) { + $has_client_data = 1; + } + @args = split( ", ", $no_handler, 2); + if ($#args > 0) { + print REVPH "R$subr(CMConnection conn, $args[1]);\n"; + } else { + print REVPH "R$subr(CMConnection conn);\n"; + } + gen_type(${subr}, $no_handler); + gen_field_list(${subr}, $no_handler); + gen_stub(${subr}, $no_handler); + gen_wrapper(${subr}, $no_handler, $has_client_data); + gen_handler(${subr}, $no_client_data, $has_client_data); } print REVP<condition_var); if (NULL != response_ptr) { - *response_ptr = data; + *response_ptr = data; } CMCondition_signal(cm, response->condition_var); } @@ -866,7 +882,7 @@ sub mod_EVhandler { EV_void_response *response = (EV_void_response*) data; void **response_ptr = CMCondition_get_client_data(cm, response->condition_var); if (NULL != response_ptr) { - memcpy(response_ptr, data, sizeof(EV_int_response)); + memcpy(response_ptr, data, sizeof(EV_int_response)); } CMCondition_signal(cm, response->condition_var); } @@ -877,8 +893,8 @@ sub mod_EVhandler { EV_string_response *response = (EV_string_response*) data; EV_string_response *stub_ptr = CMCondition_get_client_data(cm, response->condition_var); if (NULL != stub_ptr) { - memcpy(stub_ptr, data, sizeof(EV_string_response)); - stub_ptr->ret = strdup(response->ret); + memcpy(stub_ptr, data, sizeof(EV_string_response)); + stub_ptr->ret = strdup(response->ret); } CMCondition_signal(cm, response->condition_var); } @@ -889,8 +905,8 @@ sub mod_EVhandler { EV_EVevent_list_response *response = (EV_EVevent_list_response*) data; EV_EVevent_list_response *stub_ptr = CMCondition_get_client_data(cm, response->condition_var); if (NULL != stub_ptr) { - memcpy(stub_ptr, data, sizeof(EV_EVevent_list_response)); - stub_ptr->ret = copy_EVevent_list(response->ret); + memcpy(stub_ptr, data, sizeof(EV_EVevent_list_response)); + stub_ptr->ret = copy_EVevent_list(response->ret); } CMCondition_signal(cm, response->condition_var); } @@ -915,7 +931,7 @@ sub mod_EVhandler { EOF print REVPH< Date: Sat, 11 May 2024 16:28:15 -0400 Subject: [PATCH 14/18] =?UTF-8?q?Remove=20special=20ReadFlattenSteps=20Mod?= =?UTF-8?q?e,=20switch=20to=20control=20by=20writer-sid=E2=80=A6=20(#4160)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove special ReadFlattenSteps Mode, switch to control by writer-side FlattenSteps parameter --- bindings/C/adios2/c/adios2_c_engine.cpp | 6 --- bindings/C/adios2/c/adios2_c_io.h | 8 ++-- bindings/C/adios2/c/adios2_c_io.tcc | 4 -- bindings/C/adios2/c/adios2_c_types.h | 1 - .../adios2/cxx11/fstream/ADIOS2fstream.cpp | 3 -- .../adios2/cxx11/fstream/ADIOS2fstream.h | 1 - .../Fortran/modules/adios2_parameters_mod.f90 | 1 - bindings/Python/py11glue.cpp | 1 - docs/user_guide/source/components/anatomy.rst | 10 ---- docs/user_guide/source/components/io.rst | 2 +- docs/user_guide/source/engines/bp5.rst | 10 ++++ source/adios2/common/ADIOSTypes.h | 1 - source/adios2/core/Engine.cpp | 3 +- source/adios2/core/Engine.tcc | 3 +- source/adios2/core/IO.cpp | 29 +---------- source/adios2/core/Stream.cpp | 6 +-- source/adios2/engine/bp5/BP5Engine.h | 38 +++++++++++---- source/adios2/engine/bp5/BP5Reader.cpp | 37 ++++++++------ source/adios2/engine/bp5/BP5Reader.h | 3 ++ source/adios2/engine/bp5/BP5Writer.cpp | 20 ++++---- source/adios2/toolkit/remote/Remote.cpp | 3 -- source/adios2/toolkit/remote/remote_common.h | 1 - .../adios2/toolkit/remote/remote_server.cpp | 4 -- source/utils/bpls/bpls.cpp | 48 +++++++++++-------- .../engine/bp/TestBPWriteReadFlatten.cpp | 15 ++++-- .../TestUtilsCWriter.bplsh.expected.txt | 2 +- 26 files changed, 123 insertions(+), 137 deletions(-) diff --git a/bindings/C/adios2/c/adios2_c_engine.cpp b/bindings/C/adios2/c/adios2_c_engine.cpp index 9d6cecf32f..1836893657 100644 --- a/bindings/C/adios2/c/adios2_c_engine.cpp +++ b/bindings/C/adios2/c/adios2_c_engine.cpp @@ -34,9 +34,6 @@ adios2::Mode adios2_ToMode(const adios2_mode mode, const std::string &hint) case adios2_mode_readRandomAccess: modeCpp = adios2::Mode::ReadRandomAccess; break; - case adios2_mode_readFlattenSteps: - modeCpp = adios2::Mode::ReadFlattenSteps; - break; case adios2_mode_deferred: modeCpp = adios2::Mode::Deferred; break; @@ -66,9 +63,6 @@ adios2_mode adios2_fromMode(const adios2::Mode mode, const std::string &hint) case adios2::Mode::ReadRandomAccess: modeC = adios2_mode_readRandomAccess; break; - case adios2::Mode::ReadFlattenSteps: - modeC = adios2_mode_readFlattenSteps; - break; case adios2::Mode::Deferred: modeC = adios2_mode_deferred; break; diff --git a/bindings/C/adios2/c/adios2_c_io.h b/bindings/C/adios2/c/adios2_c_io.h index a622328e38..c790cd0647 100644 --- a/bindings/C/adios2/c/adios2_c_io.h +++ b/bindings/C/adios2/c/adios2_c_io.h @@ -329,8 +329,8 @@ adios2_error adios2_remove_all_attributes(adios2_io *io); * MPI Collective function as it calls MPI_Comm_dup * @param io engine owner * @param name unique engine identifier - * @param mode adios2_mode_write, adios2_mode_read, adios2_mode_append, - * adios2_mode_readRandomAccess and adios2_mode_readFlattenSteps + * @param mode adios2_mode_write, adios2_mode_read, adios2_mode_append + * and adios2_mode_readRandomAccess * @return success: handler, failure: NULL */ adios2_engine *adios2_open(adios2_io *io, const char *name, const adios2_mode mode); @@ -341,8 +341,8 @@ adios2_engine *adios2_open(adios2_io *io, const char *name, const adios2_mode mo * MPI Collective function as it calls MPI_Comm_dup * @param io engine owner * @param name unique engine identifier - * @param mode adios2_mode_write, adios2_mode_read, adios2_mode_append, - * adios2_mode_readRandomAccess and adios2_mode_readFlattenSteps + * @param mode adios2_mode_write, adios2_mode_read, adios2_mode_append and + * adios2_mode_readRandomAccess * @param comm communicator other than adios' handler comm. MPI only. * @return success: handler, failure: NULL */ diff --git a/bindings/C/adios2/c/adios2_c_io.tcc b/bindings/C/adios2/c/adios2_c_io.tcc index 9c9000cd44..29607b87d8 100644 --- a/bindings/C/adios2/c/adios2_c_io.tcc +++ b/bindings/C/adios2/c/adios2_c_io.tcc @@ -36,10 +36,6 @@ adios2::Mode adios2_ToOpenMode(const adios2_mode modeC) mode = adios2::Mode::ReadRandomAccess; break; - case adios2_mode_readFlattenSteps: - mode = adios2::Mode::ReadFlattenSteps; - break; - default: break; } diff --git a/bindings/C/adios2/c/adios2_c_types.h b/bindings/C/adios2/c/adios2_c_types.h index b28bc7f21e..fb102df4cb 100644 --- a/bindings/C/adios2/c/adios2_c_types.h +++ b/bindings/C/adios2/c/adios2_c_types.h @@ -103,7 +103,6 @@ typedef enum adios2_mode_read = 2, adios2_mode_append = 3, adios2_mode_readRandomAccess = 6, - adios2_mode_readFlattenSteps = 7, adios2_mode_deferred = 4, adios2_mode_sync = 5 diff --git a/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.cpp b/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.cpp index 12d083beb2..03b881e7fa 100644 --- a/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.cpp +++ b/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.cpp @@ -89,9 +89,6 @@ adios2::Mode fstream::ToMode(const openmode mode) const noexcept case (openmode::in_random_access): modeCpp = adios2::Mode::ReadRandomAccess; break; - case (openmode::in_flatten_steps): - modeCpp = adios2::Mode::ReadFlattenSteps; - break; case (openmode::app): modeCpp = adios2::Mode::Append; break; diff --git a/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.h b/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.h index d96a7a749b..546bf54ccb 100644 --- a/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.h +++ b/bindings/CXX11/adios2/cxx11/fstream/ADIOS2fstream.h @@ -48,7 +48,6 @@ class fstream out, //!< write in, //!< read in_random_access, //!< read_random_access - in_flatten_steps, //!< flatten all input steps to 1 app //!< append, not yet supported }; diff --git a/bindings/Fortran/modules/adios2_parameters_mod.f90 b/bindings/Fortran/modules/adios2_parameters_mod.f90 index f73561702e..bf0dd18c9b 100644 --- a/bindings/Fortran/modules/adios2_parameters_mod.f90 +++ b/bindings/Fortran/modules/adios2_parameters_mod.f90 @@ -56,7 +56,6 @@ module adios2_parameters_mod integer, parameter :: adios2_mode_read = 2 integer, parameter :: adios2_mode_append = 3 integer, parameter :: adios2_mode_readRandomAccess = 6 - integer, parameter :: adios2_mode_readFlattenSteps = 7 integer, parameter :: adios2_mode_deferred = 4 integer, parameter :: adios2_mode_sync = 5 diff --git a/bindings/Python/py11glue.cpp b/bindings/Python/py11glue.cpp index c474b8b53c..18f3a6eb27 100644 --- a/bindings/Python/py11glue.cpp +++ b/bindings/Python/py11glue.cpp @@ -99,7 +99,6 @@ PYBIND11_MODULE(ADIOS2_PYTHON_MODULE_NAME, m) .value("Write", adios2::Mode::Write) .value("Read", adios2::Mode::Read) .value("ReadRandomAccess", adios2::Mode::ReadRandomAccess) - .value("ReadFlattenSteps", adios2::Mode::ReadFlattenSteps) .value("Append", adios2::Mode::Append) .value("Deferred", adios2::Mode::Deferred) .value("Sync", adios2::Mode::Sync) diff --git a/docs/user_guide/source/components/anatomy.rst b/docs/user_guide/source/components/anatomy.rst index 2aa8c7f89a..27f325b646 100644 --- a/docs/user_guide/source/components/anatomy.rst +++ b/docs/user_guide/source/components/anatomy.rst @@ -169,13 +169,3 @@ mode. Also newer file Engines like BP5 to not allow |--> ADIOS goes out of scope or adios2_finalize() -In addition to the two read modes discussed above, ADIOS has another -input mode named `adios2::Mode::ReadFlattenSteps`. This is a highly -specialized mode built that is unlikely to be of general utility, but -we describe it for completeness. In `ReadFlattenSteps` mode, ADIOS -loads all the metadata in the file upon Open (just like -`ReadRandomAccess` mode, but everything that was written appears that -it was output on the same step, regardless of how many steps actually -appear in the file. This affects the operation of many reader-side -ADIOS functions, including Steps(), BlocksInfo(), Get(), etc. - diff --git a/docs/user_guide/source/components/io.rst b/docs/user_guide/source/components/io.rst index 4e6906bc6d..fefebe7f5f 100644 --- a/docs/user_guide/source/components/io.rst +++ b/docs/user_guide/source/components/io.rst @@ -196,7 +196,7 @@ A particular ``Engine`` type is set to the current ``IO`` component with the ``I Engine polymorphism is handled internally by the ``IO`` class, which allows subclassing future derived ``Engine`` types without changing the basic API. ``Engine`` objects are created in various modes. -The available modes are ``adios2::Mode::Read``, ``adios2::Mode::ReadRandomAccess``, ``adios2::Mode::ReadFlattenSteps``, ``adios2::Mode::Write``, ``adios2::Mode::Append``, ``adios2::Mode::Sync``, ``adios2::Mode::Deferred``, and ``adios2::Mode::Undefined``. +The available modes are ``adios2::Mode::Read``, ``adios2::Mode::ReadRandomAccess``, ``adios2::Mode::Write``, ``adios2::Mode::Append``, ``adios2::Mode::Sync``, ``adios2::Mode::Deferred``, and ``adios2::Mode::Undefined``. .. code-block:: c++ diff --git a/docs/user_guide/source/engines/bp5.rst b/docs/user_guide/source/engines/bp5.rst index b29ec71eb5..76696d427a 100644 --- a/docs/user_guide/source/engines/bp5.rst +++ b/docs/user_guide/source/engines/bp5.rst @@ -130,6 +130,14 @@ This engine allows the user to fine tune the buffering operations through the fo #. **Threads**: Read side: Specify how many threads one process can use to speed up reading. The default value is *0*, to let the engine estimate the number of threads based on how many processes are running on the compute node and how many hardware threads are available on the compute node but it will use maximum 16 threads. Value *1* forces the engine to read everything within the main thread of the process. Other values specify the exact number of threads the engine can use. Although multithreaded reading works in a single *Get(adios2::Mode::Sync)* call if the read selection spans multiple data blocks in the file, the best parallelization is achieved by using deferred mode and reading everything in *PerformGets()/EndStep()*. + #. **FlattenSteps**: This is a writer-side parameter specifies that the + reader should interpret multiple writer-created timesteps as a + single timestep, essentially flattening all Put()s into a single step. + + #. **IgnoreFlattenSteps**: This is a reader-side parameter that + tells the reader to ignore any FlattenSteps parameter supplied + to the writer. + ============================== ===================== =========================================================== **Key** **Value Format** **Default** and Examples ============================== ===================== =========================================================== @@ -156,6 +164,8 @@ This engine allows the user to fine tune the buffering operations through the fo StatsLevel integer, 0 or 1 **1**, 0 MaxOpenFilesAtOnce integer >= 0 **UINT_MAX**, 1024, 1 Threads integer >= 0 **0**, 1, 32 + FlattenSteps boolean **off**, on, true, false + IgnoreFlattenSteps boolean **off**, on, true, false ============================== ===================== =========================================================== diff --git a/source/adios2/common/ADIOSTypes.h b/source/adios2/common/ADIOSTypes.h index 111ebe4a1d..fad51e8fd9 100644 --- a/source/adios2/common/ADIOSTypes.h +++ b/source/adios2/common/ADIOSTypes.h @@ -80,7 +80,6 @@ enum class Mode Read, Append, ReadRandomAccess, // reader random access mode - ReadFlattenSteps, // reader flatten steps to one // launch execution modes Sync, Deferred diff --git a/source/adios2/core/Engine.cpp b/source/adios2/core/Engine.cpp index 56e6f02c08..72ab54d4ac 100644 --- a/source/adios2/core/Engine.cpp +++ b/source/adios2/core/Engine.cpp @@ -135,8 +135,7 @@ void Engine::Put(VariableStruct &variable, const void *data, const Mode launch) void Engine::Get(VariableStruct &variable, void *data, const Mode launch) { - CommonChecks(variable, data, {Mode::Read, Mode::ReadRandomAccess, Mode::ReadFlattenSteps}, - "in call to Get"); + CommonChecks(variable, data, {Mode::Read, Mode::ReadRandomAccess}, "in call to Get"); switch (launch) { diff --git a/source/adios2/core/Engine.tcc b/source/adios2/core/Engine.tcc index 656b2fc30a..b06050b86c 100644 --- a/source/adios2/core/Engine.tcc +++ b/source/adios2/core/Engine.tcc @@ -87,8 +87,7 @@ void Engine::Put(const std::string &variableName, const T &datum, const Mode /*l template void Engine::Get(Variable &variable, T *data, const Mode launch) { - CommonChecks(variable, data, {Mode::Read, Mode::ReadRandomAccess, Mode::ReadFlattenSteps}, - "in call to Get"); + CommonChecks(variable, data, {Mode::Read, Mode::ReadRandomAccess}, "in call to Get"); switch (launch) { diff --git a/source/adios2/core/IO.cpp b/source/adios2/core/IO.cpp index eaf4394351..83bf0f3781 100644 --- a/source/adios2/core/IO.cpp +++ b/source/adios2/core/IO.cpp @@ -150,14 +150,6 @@ const std::unordered_map ReadRandomAccess_Supported = { {"campaign", true}, }; -const std::unordered_map ReadFlattenSteps_Supported = { - {"bp3", false}, {"bp4", false}, {"bp5", true}, {"dataman", false}, - {"ssc", false}, {"mhs", false}, {"sst", false}, {"daos", false}, - {"effis", false}, {"dataspaces", false}, {"hdf5", false}, {"skeleton", false}, - {"inline", false}, {"null", true}, {"nullcore", true}, {"plugin", false}, - {"campaign", true}, -}; - // Synchronize access to the factory in case one thread is // looking up while another registers additional entries. std::mutex FactoryMutex; @@ -568,8 +560,7 @@ Engine &IO::Open(const std::string &name, const Mode mode, helper::Comm comm) { engineTypeLC = "campaign"; } - else if ((mode_to_use == Mode::Read) || (mode_to_use == Mode::ReadRandomAccess) || - (mode_to_use == Mode::ReadFlattenSteps)) + else if ((mode_to_use == Mode::Read) || (mode_to_use == Mode::ReadRandomAccess)) { if (adios2sys::SystemTools::FileIsDirectory(name)) { @@ -677,26 +668,10 @@ Engine &IO::Open(const std::string &name, const Mode mode, helper::Comm comm) } } - if (mode_to_use == Mode::ReadFlattenSteps) - { - // older engines don't know about ReadFlattenSteps Mode, throw an exception - auto it = ReadFlattenSteps_Supported.find(engineTypeLC); - if (it != ReadFlattenSteps_Supported.end()) - { - if (!it->second) - { - helper::Throw("Core", "IO", "Open", - "Engine " + engineTypeLC + - " doesn't support ReadFlattenSteps mode"); - } - } - } - auto f = FactoryLookup(engineTypeLC); if (f != Factory.end()) { - if ((mode_to_use == Mode::Read) || (mode_to_use == Mode::ReadRandomAccess) || - (mode_to_use == Mode::ReadFlattenSteps)) + if ((mode_to_use == Mode::Read) || (mode_to_use == Mode::ReadRandomAccess)) { engine = f->second.MakeReader(*this, name, mode_to_use, std::move(comm)); } diff --git a/source/adios2/core/Stream.cpp b/source/adios2/core/Stream.cpp index 2b923886ae..43abacc703 100644 --- a/source/adios2/core/Stream.cpp +++ b/source/adios2/core/Stream.cpp @@ -23,8 +23,7 @@ Stream::Stream(const std::string &name, const Mode mode, helper::Comm comm, : m_ADIOS(std::make_shared(std::move(comm), hostLanguage)), m_IO(&m_ADIOS->DeclareIO(name)), m_Name(name), m_Mode(mode), m_EngineType(engineType) { - if ((mode == adios2::Mode::Read) || (mode == adios2::Mode::ReadRandomAccess) || - (mode == adios2::Mode::ReadFlattenSteps)) + if ((mode == adios2::Mode::Read) || (mode == adios2::Mode::ReadRandomAccess)) { CheckOpen(); } @@ -42,8 +41,7 @@ Stream::Stream(const std::string &name, const Mode mode, helper::Comm comm, : m_ADIOS(std::make_shared(configFile, std::move(comm), hostLanguage)), m_IO(&m_ADIOS->DeclareIO(ioInConfigFile)), m_Name(name), m_Mode(mode) { - if ((mode == adios2::Mode::Read) || (mode == adios2::Mode::ReadRandomAccess) || - (mode == adios2::Mode::ReadFlattenSteps)) + if ((mode == adios2::Mode::Read) || (mode == adios2::Mode::ReadRandomAccess)) { CheckOpen(); } diff --git a/source/adios2/engine/bp5/BP5Engine.h b/source/adios2/engine/bp5/BP5Engine.h index 354ec67949..be7f40a3b1 100644 --- a/source/adios2/engine/bp5/BP5Engine.h +++ b/source/adios2/engine/bp5/BP5Engine.h @@ -56,15 +56,33 @@ class BP5Engine format::BufferSTL m_MetadataIndex; - /** Positions of flags in Index Table Header that Reader uses */ - static constexpr size_t m_IndexHeaderSize = 64; - static constexpr size_t m_EndianFlagPosition = 36; - static constexpr size_t m_BPVersionPosition = 37; - static constexpr size_t m_BPMinorVersionPosition = 38; - static constexpr size_t m_ActiveFlagPosition = 39; - static constexpr size_t m_ColumnMajorFlagPosition = 40; - static constexpr size_t m_VersionTagPosition = 0; - static constexpr size_t m_VersionTagLength = 32; + /** Positions of flags in Index Table Header that Reader uses - MUST BE 64 bytes total */ + struct BP5IndexTableHeader + { + char VersionTag[32]; + uint8_t adiosMajorVersion; + uint8_t adiosMinorVersion; + uint8_t adiosPatchVersion; + uint8_t unused1; // init to zero + uint8_t isLittleEndian; // boolean + uint8_t bpVersion; // 5 here + uint8_t bpMinorVersion; + uint8_t activeFlag; + char columnMajor; // y or n + uint8_t flattenSteps; // writer requests all steps flattened to one on read + char unused2[22]; // init to zero + }; + static constexpr size_t m_IndexHeaderSize = sizeof(BP5IndexTableHeader); + static constexpr size_t m_EndianFlagPosition = offsetof(BP5IndexTableHeader, isLittleEndian); + static constexpr size_t m_BPVersionPosition = offsetof(BP5IndexTableHeader, bpVersion); + static constexpr size_t m_BPMinorVersionPosition = + offsetof(BP5IndexTableHeader, bpMinorVersion); + static constexpr size_t m_ActiveFlagPosition = offsetof(BP5IndexTableHeader, activeFlag); + static constexpr size_t m_ColumnMajorFlagPosition = offsetof(BP5IndexTableHeader, columnMajor); + static constexpr size_t m_FlattenStepsPosition = offsetof(BP5IndexTableHeader, flattenSteps); + static constexpr size_t m_VersionTagPosition = offsetof(BP5IndexTableHeader, VersionTag); + static constexpr size_t m_VersionTagLength = sizeof(BP5IndexTableHeader().VersionTag); + static constexpr size_t m_HeaderTailPadding = sizeof(BP5IndexTableHeader().unused2); static constexpr uint8_t m_BP5MinorVersion = 2; @@ -154,6 +172,8 @@ class BP5Engine MACRO(StatsBlockSize, SizeBytes, size_t, DefaultStatsBlockSize) \ MACRO(Threads, UInt, unsigned int, 0) \ MACRO(UseOneTimeAttributes, Bool, bool, true) \ + MACRO(FlattenSteps, Bool, bool, false) \ + MACRO(IgnoreFlattenSteps, Bool, bool, false) \ MACRO(RemoteDataPath, String, std::string, "") \ MACRO(MaxOpenFilesAtOnce, UInt, unsigned int, UINT_MAX) diff --git a/source/adios2/engine/bp5/BP5Reader.cpp b/source/adios2/engine/bp5/BP5Reader.cpp index 8fe5d68201..5a1a581cf0 100644 --- a/source/adios2/engine/bp5/BP5Reader.cpp +++ b/source/adios2/engine/bp5/BP5Reader.cpp @@ -72,7 +72,7 @@ void BP5Reader::InstallMetadataForTimestep(size_t Step) size_t ThisMDSize = helper::ReadValue(m_Metadata.Data(), Position, m_Minifooter.IsLittleEndian); char *ThisMD = m_Metadata.Data() + MDPosition; - if ((m_OpenMode == Mode::ReadRandomAccess) || (m_OpenMode == Mode::ReadFlattenSteps)) + if ((m_OpenMode == Mode::ReadRandomAccess) || (m_FlattenSteps)) { m_BP5Deserializer->InstallMetaData(ThisMD, ThisMDSize, WriterRank, Step); } @@ -475,14 +475,12 @@ void BP5Reader::PerformLocalGets() // PRIVATE void BP5Reader::Init() { - if ((m_OpenMode != Mode::Read) && (m_OpenMode != Mode::ReadRandomAccess) && - (m_OpenMode != Mode::ReadFlattenSteps)) + if ((m_OpenMode != Mode::Read) && (m_OpenMode != Mode::ReadRandomAccess)) { - helper::Throw( - "Engine", "BP5Reader", "Init", - "BPFileReader only supports OpenMode::Read, " - "OpenMode::ReadRandomAccess, or OpenMode::ReadFlattenSteps from" + - m_Name); + helper::Throw("Engine", "BP5Reader", "Init", + "BPFileReader only supports OpenMode::Read or " + "OpenMode::ReadRandomAccess from" + + m_Name); } // if IO was involved in reading before this flag may be true now @@ -521,7 +519,7 @@ void BP5Reader::InitParameters() ParseParams(m_IO, m_Parameters); if (m_Parameters.OpenTimeoutSecs < 0.0f) { - if ((m_OpenMode == Mode::ReadRandomAccess) || (m_OpenMode == Mode::ReadFlattenSteps)) + if (m_OpenMode == Mode::ReadRandomAccess) { m_Parameters.OpenTimeoutSecs = 0.0f; } @@ -804,9 +802,9 @@ void BP5Reader::UpdateBuffer(const TimePoint &timeoutInstant, const Seconds &pol // create the serializer object if (!m_BP5Deserializer) { - m_BP5Deserializer = new format::BP5Deserializer(m_WriterIsRowMajor, m_ReaderIsRowMajor, - (m_OpenMode != Mode::Read), - (m_OpenMode == Mode::ReadFlattenSteps)); + m_BP5Deserializer = + new format::BP5Deserializer(m_WriterIsRowMajor, m_ReaderIsRowMajor, + (m_OpenMode != Mode::Read), (m_FlattenSteps)); m_BP5Deserializer->m_Engine = this; } } @@ -903,7 +901,7 @@ void BP5Reader::UpdateBuffer(const TimePoint &timeoutInstant, const Seconds &pol m_Comm.Bcast(m_Metadata.Data(), inputSize, 0); - if ((m_OpenMode == Mode::ReadRandomAccess) || (m_OpenMode == Mode::ReadFlattenSteps)) + if ((m_OpenMode == Mode::ReadRandomAccess) || m_FlattenSteps) { for (size_t Step = 0; Step < m_MetadataIndexTable.size(); Step++) { @@ -980,6 +978,15 @@ size_t BP5Reader::ParseMetadataIndex(format::BufferSTL &bufferSTL, const size_t const uint8_t val = helper::ReadValue(buffer, position, m_Minifooter.IsLittleEndian); m_WriterIsRowMajor = val == 'n'; + + position = m_FlattenStepsPosition; + const uint8_t flatten_val = + helper::ReadValue(buffer, position, m_Minifooter.IsLittleEndian); + m_FlattenSteps = (flatten_val != 0); + + if (m_Parameters.IgnoreFlattenSteps) + m_FlattenSteps = false; + // move position to first row position = m_IndexHeaderSize; } @@ -1248,7 +1255,7 @@ void BP5Reader::DoGetStructDeferred(VariableStruct &variable, void *data) void BP5Reader::DoClose(const int transportIndex) { PERFSTUBS_SCOPED_TIMER("BP5Reader::Close"); - if ((m_OpenMode == Mode::ReadRandomAccess) || (m_OpenMode == Mode::ReadFlattenSteps)) + if (m_OpenMode == Mode::ReadRandomAccess) { PerformGets(); } @@ -1311,7 +1318,7 @@ void BP5Reader::FlushProfiler() size_t BP5Reader::DoSteps() const { - if (m_OpenMode == Mode::ReadFlattenSteps) + if (m_FlattenSteps) return 1; else return m_StepsCount; diff --git a/source/adios2/engine/bp5/BP5Reader.h b/source/adios2/engine/bp5/BP5Reader.h index 5e121cfa2d..6e8508041c 100644 --- a/source/adios2/engine/bp5/BP5Reader.h +++ b/source/adios2/engine/bp5/BP5Reader.h @@ -57,6 +57,8 @@ class BP5Reader : public BP5Engine, public Engine MinVarInfo *MinBlocksInfo(const VariableBase &, const size_t Step) const; bool VarShape(const VariableBase &Var, const size_t Step, Dims &Shape) const; bool VariableMinMax(const VariableBase &, const size_t Step, MinMaxStruct &MinMax); + const char *VariableExprStr(const VariableBase &Var); + void SetFlattenMode(bool flatten) { m_FlattenSteps = flatten; }; private: format::BP5Deserializer *m_BP5Deserializer = nullptr; @@ -222,6 +224,7 @@ class BP5Reader : public BP5Engine, public Engine uint32_t m_WriterColumnMajor = 0; bool m_ReaderIsRowMajor = true; bool m_WriterIsRowMajor = true; + bool m_FlattenSteps = false; // set to true of writer requested all steps be flattened into 1 format::BufferSTL m_MetadataIndex; format::BufferSTL m_MetaMetadata; diff --git a/source/adios2/engine/bp5/BP5Writer.cpp b/source/adios2/engine/bp5/BP5Writer.cpp index 856ef2134b..19c2f1aba0 100644 --- a/source/adios2/engine/bp5/BP5Writer.cpp +++ b/source/adios2/engine/bp5/BP5Writer.cpp @@ -1221,9 +1221,12 @@ void BP5Writer::MakeHeader(std::vector &buffer, size_t &position, const st helper::CopyToBuffer(buffer, position, version.c_str()); }; - // auto &buffer = b.m_Buffer; - // auto &position = b.m_Position; - // auto &absolutePosition = b.m_AbsolutePosition; + if (sizeof(BP5IndexTableHeader) != 64) + { + std::cerr << "BP6 Index Table Header must be 64 bytes" << std::endl; + exit(1); + } + if (position > 0) { helper::Throw( @@ -1276,11 +1279,7 @@ void BP5Writer::MakeHeader(std::vector &buffer, size_t &position, const st lf_CopyVersionChar(majorVersion, buffer, position); lf_CopyVersionChar(minorVersion, buffer, position); lf_CopyVersionChar(patchVersion, buffer, position); - ++position; - - // Note: Reader does process and use bytes 36-38 in - // BP4Deserialize.cpp::ParseMetadataIndex(). - // Order and position must match there. + position = m_EndianFlagPosition; // byte 36: endianness if (position != m_EndianFlagPosition) @@ -1330,8 +1329,9 @@ void BP5Writer::MakeHeader(std::vector &buffer, size_t &position, const st const uint8_t columnMajor = (m_IO.m_ArrayOrder == ArrayOrdering::ColumnMajor) ? 'y' : 'n'; helper::CopyToBuffer(buffer, position, &columnMajor); - // byte 41-63: unused - position += 23; + helper::CopyToBuffer(buffer, position, &m_Parameters.FlattenSteps); + // remainder unused + position = m_IndexHeaderSize; // absolutePosition = position; } diff --git a/source/adios2/toolkit/remote/Remote.cpp b/source/adios2/toolkit/remote/Remote.cpp index a48fa1610b..29c0da3184 100644 --- a/source/adios2/toolkit/remote/Remote.cpp +++ b/source/adios2/toolkit/remote/Remote.cpp @@ -109,9 +109,6 @@ void Remote::Open(const std::string hostname, const int32_t port, const std::str case Mode::ReadRandomAccess: open_msg.Mode = RemoteCommon::RemoteFileMode::RemoteOpenRandomAccess; break; - case Mode::ReadFlattenSteps: - open_msg.Mode = RemoteCommon::RemoteFileMode::RemoteOpenFlattenSteps; - break; default: break; } diff --git a/source/adios2/toolkit/remote/remote_common.h b/source/adios2/toolkit/remote/remote_common.h index ba98cb383f..0d78bd290a 100644 --- a/source/adios2/toolkit/remote/remote_common.h +++ b/source/adios2/toolkit/remote/remote_common.h @@ -15,7 +15,6 @@ enum RemoteFileMode { RemoteOpen, RemoteOpenRandomAccess, - RemoteOpenFlattenSteps, }; /* */ diff --git a/source/adios2/toolkit/remote/remote_server.cpp b/source/adios2/toolkit/remote/remote_server.cpp index 4b79d787e6..5108ed421e 100644 --- a/source/adios2/toolkit/remote/remote_server.cpp +++ b/source/adios2/toolkit/remote/remote_server.cpp @@ -92,8 +92,6 @@ class AnonADIOSFile m_mode = mode; if (m_mode == RemoteOpenRandomAccess) adios_read_mode = adios2::Mode::ReadRandomAccess; - if (m_mode == RemoteOpenFlattenSteps) - adios_read_mode = adios2::Mode::ReadFlattenSteps; m_engine = &m_io->Open(FileName, adios_read_mode); memcpy(&m_ID, m_IOname.c_str(), sizeof(m_ID)); } @@ -177,8 +175,6 @@ static void OpenHandler(CManager cm, CMConnection conn, void *vevent, void *clie std::string strMode = "Streaming"; if (open_msg->Mode == RemoteOpenRandomAccess) strMode = "RandomAccess"; - if (open_msg->Mode == RemoteOpenFlattenSteps) - strMode = "FlattenSteps"; std::cout << "Got an open request (mode " << strMode << ") for file " << open_msg->FileName << std::endl; AnonADIOSFile *f = diff --git a/source/utils/bpls/bpls.cpp b/source/utils/bpls/bpls.cpp index 42b4a99580..66398ad157 100644 --- a/source/utils/bpls/bpls.cpp +++ b/source/utils/bpls/bpls.cpp @@ -95,7 +95,7 @@ bool listmeshes; // do list meshes too bool attrsonly; // do list attributes only bool longopt; // -l is turned on bool timestep; // read step by step -bool flatten; // flatten steps to one +bool ignore_flatten; // dont flatten steps to one bool filestream = false; // are we using an engine through FileStream? bool noindex; // do no print array indices with data bool printByteAsChar; // print 8 bit integer arrays as string @@ -145,7 +145,8 @@ void display_help() */ " --timestep | -t Read content step by step (stream " "reading)\n" - " --flatten Flatten Steps into one step (open in flatten mode)\n" + " --ignore_flatten Display steps as written (don't flatten, even if writer " + "said to)\n" " --dump | -d Dump matched variables/attributes\n" " To match attributes too, add option " "-a\n" @@ -447,6 +448,7 @@ bool introspectAsBPDir(const std::string &name) noexcept char patch = buffer[34]; bool isBigEndian = static_cast(buffer[36]); uint8_t BPVersion = static_cast(buffer[37]); + uint8_t flatten = static_cast(buffer[41]); bool isActive = false; if (BPVersion == 4) { @@ -459,9 +461,9 @@ bool introspectAsBPDir(const std::string &name) noexcept { uint8_t minversion = static_cast(buffer[38]); isActive = static_cast(buffer[39]); - printf("ADIOS-BP Version %d.%d %s - ADIOS v%c.%c.%c %s\n", BPVersion, minversion, + printf("ADIOS-BP Version %d.%d %s - ADIOS v%c.%c.%c %s%s\n", BPVersion, minversion, (isBigEndian ? "Big Endian" : "Little Endian"), major, minor, patch, - (isActive ? "- active" : "")); + (isActive ? "- active" : ""), (flatten ? "- flatten_steps " : "")); } else { @@ -619,7 +621,7 @@ int bplsMain(int argc, char *argv[]) arg.AddBooleanArgument("--noindex", &noindex, " | -y Print data without array indices"); arg.AddBooleanArgument("-y", &noindex, ""); arg.AddBooleanArgument("--timestep", ×tep, " | -t Print values of timestep elements"); - arg.AddBooleanArgument("--flatten", &flatten, " Flatten steps to one"); + arg.AddBooleanArgument("--ignore_flatten", &ignore_flatten, " Don't flatten steps to one"); arg.AddBooleanArgument("-t", ×tep, ""); arg.AddBooleanArgument("--attrs", &listattrs, " | -a List/match attributes too"); arg.AddBooleanArgument("-a", &listattrs, ""); @@ -768,7 +770,7 @@ void init_globals() output_xml = false; noindex = false; timestep = false; - flatten = false; + ignore_flatten = false; sortnames = false; listattrs = false; listmeshes = false; @@ -861,8 +863,8 @@ void printSettings(void) printf(" -V : show binary version info of file\n"); if (timestep) printf(" -t : read step-by-step\n"); - if (flatten) - printf(" --flatten : flatten steps into one\n"); + if (ignore_flatten) + printf(" --ignore_flatten : ignore FlattenSteps writer specification\n"); if (hidden_attrs) { @@ -1655,6 +1657,11 @@ int doList(std::string path) io.SetParameters(p); } + if (ignore_flatten) + { + io.SetParameters("IgnoreFlattenSteps=on"); + } + for (auto &engineName : engineList) { if (verbose > 2) @@ -1666,10 +1673,6 @@ int doList(std::string path) { fp = &io.Open(path, Mode::Read); } - else if (flatten) - { - fp = &io.Open(path, Mode::ReadFlattenSteps); - } else { fp = &io.Open(path, Mode::ReadRandomAccess); @@ -1687,7 +1690,13 @@ int doList(std::string path) break; } - if (fp != nullptr) + if (fp == nullptr) + { + fprintf(stderr, "\nError: Could not open this file with any ADIOS2 " + "file reading engines\n"); + return 4; + } + { //, variables, timesteps, and attributes // all parameters are integers, @@ -1757,12 +1766,6 @@ int doList(std::string path) } fp->Close(); } - else - { - fprintf(stderr, "\nError: Could not open this file with any ADIOS2 " - "file reading engines\n"); - return 4; - } return 0; } @@ -3690,9 +3693,12 @@ void print_decomp_singlestep(core::Engine *fp, core::IO *io, core::Variable * DataType adiosvartype = variable->m_Type; const auto minBlocks = fp->MinBlocksInfo(*variable, fp->CurrentStep()); - std::vector::BPInfo> coreBlocks = - fp->BlocksInfo(*variable, fp->CurrentStep()); + std::vector::BPInfo> coreBlocks; + if (!minBlocks) + { + coreBlocks = fp->BlocksInfo(*variable, fp->CurrentStep()); + } if (!minBlocks && coreBlocks.empty()) { return; diff --git a/testing/adios2/engine/bp/TestBPWriteReadFlatten.cpp b/testing/adios2/engine/bp/TestBPWriteReadFlatten.cpp index 5f5b9e50fb..cef5459af9 100644 --- a/testing/adios2/engine/bp/TestBPWriteReadFlatten.cpp +++ b/testing/adios2/engine/bp/TestBPWriteReadFlatten.cpp @@ -106,6 +106,7 @@ TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead1D8) io.SetParameters(engineParameters); } + io.SetParameters("FlattenSteps=on"); io.AddTransport("file"); adios2::Engine bpWriter = io.Open(fname, adios2::Mode::Write); @@ -188,7 +189,7 @@ TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead1D8) io.SetParameters(engineParameters); } - adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadFlattenSteps); + adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadRandomAccess); EXPECT_EQ(bpReader.Steps(), 1); @@ -429,6 +430,7 @@ TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead2D2x4) } io.AddTransport("file"); + io.SetParameters("FlattenSteps=on"); adios2::Engine bpWriter = io.Open(fname, adios2::Mode::Write); for (size_t step = 0; step < (size_t)mpiSize; ++step) @@ -501,7 +503,7 @@ TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead2D2x4) io.SetParameters(engineParameters); } - adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadFlattenSteps); + adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadRandomAccess); EXPECT_EQ(bpReader.Steps(), 1); auto var_iString = io.InquireVariable("iString"); @@ -748,6 +750,7 @@ TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead2D4x2) io.AddTransport("file"); + io.SetParameters("FlattenSteps=on"); adios2::Engine bpWriter = io.Open(fname, adios2::Mode::Write); for (size_t step = 0; step < (size_t)mpiSize; ++step) @@ -818,7 +821,7 @@ TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead2D4x2) io.SetParameters(engineParameters); } - adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadFlattenSteps); + adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadRandomAccess); EXPECT_EQ(bpReader.Steps(), 1); @@ -1038,6 +1041,7 @@ TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead10D2x2) io.AddTransport("file"); + io.SetParameters("FlattenSteps=on"); adios2::Engine bpWriter = io.Open(fname, adios2::Mode::Write); for (size_t step = 0; step < (size_t)mpiSize; ++step) @@ -1093,7 +1097,7 @@ TEST_F(BPWriteReadTestFlatten, FlattenBPWriteRead10D2x2) io.SetParameters(engineParameters); } - adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadFlattenSteps); + adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadRandomAccess); EXPECT_EQ(bpReader.Steps(), 1); @@ -1220,6 +1224,7 @@ TEST_F(BPWriteReadTestFlatten, FlattenBPWriteReadEmptyProcess) io.SetParameters(engineParameters); } + io.SetParameters("FlattenSteps=on"); adios2::Engine bpWriter = io.Open(fname, adios2::Mode::Write); for (size_t step = 0; step < NSteps; ++step) @@ -1255,7 +1260,7 @@ TEST_F(BPWriteReadTestFlatten, FlattenBPWriteReadEmptyProcess) io.SetParameters(engineParameters); } - adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadFlattenSteps); + adios2::Engine bpReader = io.Open(fname, adios2::Mode::ReadRandomAccess); for (size_t step = 0; step < 1; ++step) { diff --git a/testing/utils/cwriter/TestUtilsCWriter.bplsh.expected.txt b/testing/utils/cwriter/TestUtilsCWriter.bplsh.expected.txt index b768a7daf4..13f56300f5 100644 --- a/testing/utils/cwriter/TestUtilsCWriter.bplsh.expected.txt +++ b/testing/utils/cwriter/TestUtilsCWriter.bplsh.expected.txt @@ -11,7 +11,7 @@ The time dimension is the first dimension then. --attrsonly | -A List attributes only --meshes | -m List meshes --timestep | -t Read content step by step (stream reading) - --flatten Flatten Steps into one step (open in flatten mode) + --ignore_flatten Display steps as written (don't flatten, even if writer said to) --dump | -d Dump matched variables/attributes To match attributes too, add option -a --regexp | -e Treat masks as extended regular expressions From f839acd37bf6b6885ee965406f502ff5e9bc0c7b Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Tue, 28 May 2024 19:24:57 -0400 Subject: [PATCH 15/18] fix: make changes from #4144 abi compat --- source/adios2/common/ADIOSMacros.h | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/source/adios2/common/ADIOSMacros.h b/source/adios2/common/ADIOSMacros.h index 8c5f719491..aac757ad6d 100644 --- a/source/adios2/common/ADIOSMacros.h +++ b/source/adios2/common/ADIOSMacros.h @@ -33,6 +33,7 @@ */ #define ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(MACRO) \ + MACRO(char) \ MACRO(int8_t) \ MACRO(int16_t) \ MACRO(int32_t) \ @@ -43,8 +44,7 @@ MACRO(uint64_t) \ MACRO(float) \ MACRO(double) \ - MACRO(long double) \ - MACRO(char) + MACRO(long double) #define ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(MACRO) \ ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(MACRO) \ @@ -52,15 +52,16 @@ MACRO(std::complex) #define ADIOS2_FOREACH_ATTRIBUTE_STDTYPE_1ARG(MACRO) \ - ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(MACRO) \ - MACRO(std::string) + MACRO(std::string) \ + ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(MACRO) #define ADIOS2_FOREACH_STDTYPE_1ARG(MACRO) \ - ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(MACRO) \ - MACRO(std::string) + MACRO(std::string) \ + ADIOS2_FOREACH_PRIMITIVE_STDTYPE_1ARG(MACRO) #define ADIOS2_FOREACH_TYPE_1ARG(MACRO) \ MACRO(std::string) \ + MACRO(char) \ MACRO(signed char) \ MACRO(unsigned char) \ MACRO(short) \ @@ -75,10 +76,10 @@ MACRO(double) \ MACRO(long double) \ MACRO(std::complex) \ - MACRO(std::complex) \ - MACRO(char) + MACRO(std::complex) #define ADIOS2_FOREACH_PRIMITIVE_TYPE_1ARG(MACRO) \ + MACRO(char) \ MACRO(signed char) \ MACRO(unsigned char) \ MACRO(short) \ @@ -93,8 +94,7 @@ MACRO(double) \ MACRO(long double) \ MACRO(std::complex) \ - MACRO(std::complex) \ - MACRO(char) + MACRO(std::complex) #define ADIOS2_FOREACH_COMPLEX_PRIMITIVE_TYPE_1ARG(MACRO) \ MACRO(float) \ @@ -102,9 +102,9 @@ MACRO(long double) #define ADIOS2_FOREACH_CHAR_TYPE_1ARG(MACRO) \ + MACRO(char) \ MACRO(signed char) \ - MACRO(unsigned char) \ - MACRO(char) + MACRO(unsigned char) #define ADIOS2_FOREACH_NUMERIC_TYPE_1ARG(MACRO) \ MACRO(short) \ @@ -123,6 +123,7 @@ #define ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(MACRO) \ MACRO(std::string) \ + MACRO(char) \ MACRO(signed char) \ MACRO(unsigned char) \ MACRO(short) \ @@ -137,10 +138,10 @@ MACRO(double) \ MACRO(long double) \ MACRO(std::complex) \ - MACRO(std::complex) \ - MACRO(char) + MACRO(std::complex) #define ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_TYPE_1ARG(MACRO) \ + MACRO(char) \ MACRO(signed char) \ MACRO(unsigned char) \ MACRO(short) \ @@ -155,8 +156,7 @@ MACRO(double) \ MACRO(long double) \ MACRO(std::complex) \ - MACRO(std::complex) \ - MACRO(char) + MACRO(std::complex) /**
@@ -185,6 +185,7 @@
 #define ADIOS2_FOREACH_ATTRIBUTE_STDTYPE_2ARGS(MACRO)                                              \
     MACRO(std::string, string)                                                                     \
     MACRO(int8_t, int8)                                                                            \
+    MACRO(char, char)                                                                              \
     MACRO(uint8_t, uint8)                                                                          \
     MACRO(int16_t, int16)                                                                          \
     MACRO(uint16_t, uint16)                                                                        \
@@ -196,11 +197,11 @@
     MACRO(double, double)                                                                          \
     MACRO(long double, ldouble)                                                                    \
     MACRO(std::complex, cfloat)                                                             \
-    MACRO(std::complex, cdouble)                                                           \
-    MACRO(char, char)
+    MACRO(std::complex, cdouble)
 
 #define ADIOS2_FOREACH_PRIMITVE_STDTYPE_2ARGS(MACRO)                                               \
     MACRO(int8_t, int8)                                                                            \
+    MACRO(char, char)                                                                              \
     MACRO(uint8_t, uint8)                                                                          \
     MACRO(int16_t, int16)                                                                          \
     MACRO(uint16_t, uint16)                                                                        \
@@ -212,8 +213,7 @@
     MACRO(double, double)                                                                          \
     MACRO(long double, ldouble)                                                                    \
     MACRO(std::complex, cfloat)                                                             \
-    MACRO(std::complex, cdouble)                                                           \
-    MACRO(char, char)
+    MACRO(std::complex, cdouble)
 
 #define ADIOS2_FOREACH_MINMAX_STDTYPE_2ARGS(MACRO)                                                 \
     MACRO(int8_t, int8)                                                                            \

From e77056e395a428c323570f98bd6fe14680e515c9 Mon Sep 17 00:00:00 2001
From: Vicente Adolfo Bolea Sanchez 
Date: Tue, 28 May 2024 19:25:27 -0400
Subject: [PATCH 16/18] fix: make changes from #4160 abi compat

---
 source/adios2/engine/bp5/BP5Engine.h                 | 6 +++---
 source/adios2/toolkit/format/bp5/BP5Deserializer.cpp | 6 ++++++
 source/adios2/toolkit/format/bp5/BP5Deserializer.h   | 5 +++--
 3 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/source/adios2/engine/bp5/BP5Engine.h b/source/adios2/engine/bp5/BP5Engine.h
index be7f40a3b1..42464119a3 100644
--- a/source/adios2/engine/bp5/BP5Engine.h
+++ b/source/adios2/engine/bp5/BP5Engine.h
@@ -172,10 +172,10 @@ class BP5Engine
     MACRO(StatsBlockSize, SizeBytes, size_t, DefaultStatsBlockSize)                                \
     MACRO(Threads, UInt, unsigned int, 0)                                                          \
     MACRO(UseOneTimeAttributes, Bool, bool, true)                                                  \
-    MACRO(FlattenSteps, Bool, bool, false)                                                         \
-    MACRO(IgnoreFlattenSteps, Bool, bool, false)                                                   \
     MACRO(RemoteDataPath, String, std::string, "")                                                 \
-    MACRO(MaxOpenFilesAtOnce, UInt, unsigned int, UINT_MAX)
+    MACRO(MaxOpenFilesAtOnce, UInt, unsigned int, UINT_MAX)                                        \
+    MACRO(FlattenSteps, Bool, bool, false)                                                         \
+    MACRO(IgnoreFlattenSteps, Bool, bool, false)
 
     struct BP5Params
     {
diff --git a/source/adios2/toolkit/format/bp5/BP5Deserializer.cpp b/source/adios2/toolkit/format/bp5/BP5Deserializer.cpp
index 5d5940f256..22fef0463a 100644
--- a/source/adios2/toolkit/format/bp5/BP5Deserializer.cpp
+++ b/source/adios2/toolkit/format/bp5/BP5Deserializer.cpp
@@ -1996,6 +1996,12 @@ int BP5Deserializer::FindOffset(size_t Dims, const size_t *Size, const size_t *I
  * *******************************
  */
 
+BP5Deserializer::BP5Deserializer(bool WriterIsRowMajor, bool ReaderIsRowMajor,
+                                 bool RandomAccessMode)
+: BP5Deserializer::BP5Deserializer(WriterIsRowMajor, ReaderIsRowMajor, RandomAccessMode, false)
+{
+}
+
 BP5Deserializer::BP5Deserializer(bool WriterIsRowMajor, bool ReaderIsRowMajor,
                                  bool RandomAccessMode, bool FlattenSteps)
 : m_WriterIsRowMajor{WriterIsRowMajor}, m_ReaderIsRowMajor{ReaderIsRowMajor},
diff --git a/source/adios2/toolkit/format/bp5/BP5Deserializer.h b/source/adios2/toolkit/format/bp5/BP5Deserializer.h
index 9f5e8d32cd..7c8461aacb 100644
--- a/source/adios2/toolkit/format/bp5/BP5Deserializer.h
+++ b/source/adios2/toolkit/format/bp5/BP5Deserializer.h
@@ -35,8 +35,9 @@ class BP5Deserializer : virtual public BP5Base
 {
 
 public:
-    BP5Deserializer(bool WriterIsRowMajor, bool ReaderIsRowMajor, bool RandomAccessMode = false,
-                    bool FlattenSteps = false);
+    BP5Deserializer(bool WriterIsRowMajor, bool ReaderIsRowMajor, bool RandomAccessMode = false);
+    BP5Deserializer(bool WriterIsRowMajor, bool ReaderIsRowMajor, bool RandomAccessMode,
+                    bool FlattenSteps);
 
     ~BP5Deserializer();
 

From 260166dd8fef769cfb55af99a8370f0fcc0f4813 Mon Sep 17 00:00:00 2001
From: Greg Eisenhauer 
Date: Tue, 28 May 2024 17:54:37 -0400
Subject: [PATCH 17/18] Kill outdated reference to
 bindings.Mode.ReadFlattenSteps (#4185)

---
 python/adios2/stream.py | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/python/adios2/stream.py b/python/adios2/stream.py
index 33753604cd..58a9c09050 100644
--- a/python/adios2/stream.py
+++ b/python/adios2/stream.py
@@ -43,9 +43,6 @@ def string_to_mode(mode: str) -> [bindings.Mode, bool]:
     elif mode == "rra":
         bmode = bindings.Mode.ReadRandomAccess
         read_mode = True
-    elif mode == "rfs":
-        bmode = bindings.Mode.ReadFlattenSteps
-        read_mode = True
     elif mode == "w":
         bmode = bindings.Mode.Write
     elif mode == "a":

From 5a42440f7fba8a0a9e3cc27f616fe58dd4638fe4 Mon Sep 17 00:00:00 2001
From: Vicente Adolfo Bolea Sanchez 
Date: Tue, 28 May 2024 20:44:46 -0400
Subject: [PATCH 18/18] Bump version to v2.10.1

---
 CMakeLists.txt                                     | 2 +-
 ReadMe.md                                          | 2 +-
 docs/user_guide/source/conf.py                     | 2 +-
 docs/user_guide/source/setting_up/source/cmake.rst | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4c2ea67687..cb3697a15d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,7 @@ endif()
 
 include(${CMAKE_CURRENT_LIST_DIR}/cmake/ADIOSFunctions.cmake)
 
-setup_version(2.10.0)
+setup_version(2.10.1)
 
 project(ADIOS2 VERSION ${ADIOS2_VERSION})
 
diff --git a/ReadMe.md b/ReadMe.md
index 9eec18d848..0daa2fa117 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -71,7 +71,7 @@ Once ADIOS2 is installed refer to:
 
 ## Releases
 
-* Latest release: [v2.10.0](https://github.com/ornladios/ADIOS2/releases/tag/v2.10.0)
+* Latest release: [v2.10.1](https://github.com/ornladios/ADIOS2/releases/tag/v2.10.1)
 
 * Previous releases: [https://github.com/ornladios/ADIOS2/releases](https://github.com/ornladios/ADIOS2/releases)
 
diff --git a/docs/user_guide/source/conf.py b/docs/user_guide/source/conf.py
index ec81cf9a34..65074a4cd4 100644
--- a/docs/user_guide/source/conf.py
+++ b/docs/user_guide/source/conf.py
@@ -74,7 +74,7 @@
 # The short X.Y version.
 version = u'2'
 # The full version, including alpha/beta/rc tags.
-release = u'2.10.0'
+release = u'2.10.1'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/docs/user_guide/source/setting_up/source/cmake.rst b/docs/user_guide/source/setting_up/source/cmake.rst
index ce5b44dd2a..8bb79463a7 100644
--- a/docs/user_guide/source/setting_up/source/cmake.rst
+++ b/docs/user_guide/source/setting_up/source/cmake.rst
@@ -14,7 +14,7 @@ To build ADIOS v2.x, clone the repository and invoke the canonical CMake build s
     ...
 
     ADIOS2 build configuration:
-      ADIOS Version: 2.10.0
+      ADIOS Version: 2.10.1
       C++ Compiler : GNU 9.4.0
         /usr/bin/c++