From c83faffafd4d8147a090e861ee74286debfbf7d6 Mon Sep 17 00:00:00 2001
From: Norbert Podhorszki <pnorbert@ornl.gov>
Date: Thu, 6 Apr 2017 17:05:44 -0400
Subject: [PATCH] Added Selections and Variable.SetSelection(), and use them in
 heatTransfer example.

---
 examples/heatTransfer/IO_adios2.cpp           | 48 ++++++-------
 include/core/VariableBase.h                   | 57 ++++++++++++++-
 .../adios_selection.h}                        | 19 +++--
 include/functions/adiosFunctions.h            |  9 ++-
 include/selection/Selection.h                 | 70 +++++++++++++++++++
 include/selection/SelectionBoundingBox.h      | 38 ++++++++++
 include/selection/SelectionPoints.h           | 55 +++++++++++++++
 source/functions/adiosFunctions.cpp           | 11 +++
 8 files changed, 274 insertions(+), 33 deletions(-)
 rename include/{ADIOS_SELECTION.h => external/adios_selection.h} (97%)
 create mode 100644 include/selection/Selection.h
 create mode 100644 include/selection/SelectionBoundingBox.h
 create mode 100644 include/selection/SelectionPoints.h

diff --git a/examples/heatTransfer/IO_adios2.cpp b/examples/heatTransfer/IO_adios2.cpp
index ac0567820..966bfae20 100644
--- a/examples/heatTransfer/IO_adios2.cpp
+++ b/examples/heatTransfer/IO_adios2.cpp
@@ -31,7 +31,7 @@ IO::IO(const Settings &s, MPI_Comm comm)
     if (!bpWriterSettings.isUserDefined())
     {
         // if not defined by user, we can change the default settings
-        bpWriterSettings.SetEngine("BP"); // BP is the default engine
+        bpWriterSettings.SetEngine("BPFileWriter"); // BP is the default engine
         bpWriterSettings.AllowThreads(
             1); // allow 1 extra thread for data processing
         bpWriterSettings.AddTransport(
@@ -47,11 +47,13 @@ IO::IO(const Settings &s, MPI_Comm comm)
 
     // define T as 2D global array
     varT = &ad->DefineVariable<double>(
-        "T", {s.gndx, s.gndy}, // Global dimensions
-        {s.ndx,
-         s.ndy}, // local size, could be defined later using SetSelection()
-        {s.offsx, s.offsy} // offset of the local array in the global space
-        );
+        "T",
+        // Global dimensions
+        {s.gndx, s.gndy},
+        // local size, could be defined later using SetSelection()
+        {s.ndx, s.ndy},
+        // offset of the local array in the global space
+        {s.offsx, s.offsy});
 
     // add transform to variable
     // adios::Transform tr = adios::transform::BZIP2( );
@@ -71,28 +73,19 @@ IO::~IO()
     delete ad;
 }
 
-void /*IO::*/ old_style_write(int step, const HeatTransfer &ht,
-                              const Settings &s, MPI_Comm comm)
-{
-    bpWriter->Write<double>(*varT, ht.data_noghost().data());
-    bpWriter->Advance();
-}
-
 void IO::write(int step, const HeatTransfer &ht, const Settings &s,
                MPI_Comm comm)
 {
+#if 1
+
     /* This selection is redundant and not required, since we defined
      * the selection already in DefineVariable(). It is here just as an example.
      */
     // Make a selection to describe the local dimensions of the variable we
-    // write
-    // and
-    // its offsets in the global spaces. This could have been done in
+    // write and its offsets in the global spaces. This could have been done in
     // adios.DefineVariable()
-    adios::Selection sel = adios.SelectionBoundingBox(
-        {s.ndx, s.ndy},
-        {s.offsx, s.offsy}); // local dims and offsets; both as list
-    var2D.SetSelection(sel);
+    adios::SelectionBoundingBox sel({s.ndx, s.ndy}, {s.offsx, s.offsy});
+    varT->SetSelection(sel);
 
     /* Select the area that we want to write from the data pointer we pass to
        the
@@ -105,10 +98,17 @@ void IO::write(int step, const HeatTransfer &ht, const Settings &s,
        above.
        Default memspace is always the full selection.
     */
-    adios::Selection memspace =
-        adios.SelectionBoundingBox({s.ndx, s.ndy}, {1, 1});
-    var2D.SetMemorySelection(memspace);
+    adios::SelectionBoundingBox memspace =
+        adios::SelectionBoundingBox({s.ndx, s.ndy}, {1, 1});
+    varT->SetMemorySelection(memspace);
 
-    bpWriter->Write<double>(*varT, ht.data());
+    bpWriter->Write<double>(*varT, ht.data_noghost().data());
     bpWriter->Advance();
+
+#else
+
+    bpWriter->Write<double>(*varT, ht.data_noghost().data());
+    bpWriter->Advance();
+
+#endif
 }
diff --git a/include/core/VariableBase.h b/include/core/VariableBase.h
index eea1d261c..d9d98c916 100644
--- a/include/core/VariableBase.h
+++ b/include/core/VariableBase.h
@@ -12,14 +12,16 @@
 #define VARIABLEBASE_H_
 
 /// \cond EXCLUDE_FROM_DOXYGEN
+#include <exception>
 #include <iterator>
 #include <sstream>
 #include <string>
 #include <vector>
 /// \endcond
 
-#include "functions/adiosFunctions.h" //GetTotalSize
-#include "functions/adiosTemplates.h" //GetType<T>
+#include "functions/adiosFunctions.h" //GetTotalSize, ConvertUint64VectorToSizetVector
+#include "functions/adiosTemplates.h"       //GetType<T>
+#include "selection/SelectionBoundingBox.h" //Selection
 
 namespace adios
 {
@@ -71,11 +73,62 @@ public:
         return GetTotalSize(m_Dimensions);
     }
 
+    /**
+     * Set the local dimension and global offset of the variable using a
+     * selection
+     * Only bounding boxes are allowed
+     */
+    void SetSelection(const SelectionBoundingBox &sel)
+    {
+
+        if (m_GlobalDimensions.size() == 0)
+        {
+            throw std::invalid_argument("Variable.SetSelection() is an invalid "
+                                        "call for single value variables\n");
+        }
+        if (m_GlobalDimensions.size() != sel.m_Count.size())
+        {
+            throw std::invalid_argument("Variable.SetSelection() bounding box "
+                                        "dimension must equal the global "
+                                        "dimension of the variable\n");
+        }
+
+        ConvertUint64VectorToSizetVector(sel.m_Count, m_Dimensions);
+        ConvertUint64VectorToSizetVector(sel.m_Start, m_GlobalDimensions);
+    }
+
+    /**
+     * Set the local dimension and global offset of the variable using a
+     * selection
+     * Only bounding boxes are allowed
+     */
+    void SetMemorySelection(const SelectionBoundingBox &sel)
+    {
+        if (m_GlobalDimensions.size() == 0)
+        {
+            throw std::invalid_argument(
+                "Variable.SetMemorySelection() is an invalid "
+                "call for single value variables\n");
+        }
+        if (m_GlobalDimensions.size() != sel.m_Count.size())
+        {
+            throw std::invalid_argument(
+                "Variable.SetMemorySelection() bounding box "
+                "dimension must equal the global "
+                "dimension of the variable\n");
+        }
+
+        ConvertUint64VectorToSizetVector(sel.m_Count, m_MemoryDimensions);
+        ConvertUint64VectorToSizetVector(sel.m_Start, m_MemoryOffsets);
+    }
+
     // protected: off for now
 
     Dims m_Dimensions;       ///< array of local dimensions
     Dims m_GlobalDimensions; ///< array of global dimensions
     Dims m_GlobalOffsets;    ///< array of global offsets
+    Dims m_MemoryDimensions; ///< array of memory dimensions
+    Dims m_MemoryOffsets;    ///< array of memory offsets
     const bool m_DebugMode = false;
 
     std::string GetDimensionAsString() { return dimsToString(m_Dimensions); }
diff --git a/include/ADIOS_SELECTION.h b/include/external/adios_selection.h
similarity index 97%
rename from include/ADIOS_SELECTION.h
rename to include/external/adios_selection.h
index 806ee9083..2e15d124e 100644
--- a/include/ADIOS_SELECTION.h
+++ b/include/external/adios_selection.h
@@ -1,10 +1,11 @@
 /*
  * Distributed under the OSI-approved Apache License, Version 2.0.  See
  * accompanying file Copyright.txt for details.
+ *
  */
 
 /*
- *   Selection API in C for ADIOS BP format
+ *   Streaming/Chunking/Selection Read API in C for ADIOS BP format
  *
  *   A SELECTION is the data ranges resulting from a QUERY over a file and
  * variable(s).
@@ -30,12 +31,14 @@
  *   the application does not need to retrieve the selection to work on the read
  * data.
  */
-#ifndef __ADIOS_SELECTION_H__
-#define __ADIOS_SELECTION_H__
+#ifndef __ADIOS_SELECTION_C_H__
+#define __ADIOS_SELECTION_C_H__
 
-/// \cond EXCLUDE_FROM_DOXYGEN
 #include <stdint.h>
-/// \endcond
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /*************************/
 /* Types used in the API */
@@ -230,4 +233,8 @@ ADIOS_SELECTION *adios_selection_points_1DtoND(ADIOS_SELECTION *pointsinbox1D,
 
 #endif /*__INCLUDED_FROM_FORTRAN_API__*/
 
-#endif /*__ADIOS_SELECTION_H__*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__ADIOS_SELECTION_C_H__*/
diff --git a/include/functions/adiosFunctions.h b/include/functions/adiosFunctions.h
index ab6edba1d..4f33c2267 100644
--- a/include/functions/adiosFunctions.h
+++ b/include/functions/adiosFunctions.h
@@ -182,6 +182,12 @@ BuildParametersMap(const std::vector<std::string> &parameters,
  */
 std::vector<int> CSVToVectorInt(const std::string csv);
 
+/** Convert a vector of uint64_t elements to a vector of std::size_t elements
+ *  @param input vector of uint64_t elements
+ *  @param output vector of std::size_t elements
+ */
+void ConvertUint64VectorToSizetVector(const std::vector<std::uint64_t> &in,
+                                      std::vector<std::size_t> &out);
 /**
  * Common strategy to check for heap buffer allocation for data and metadata
  * typically calculated in Write
@@ -190,7 +196,8 @@ std::vector<int> CSVToVectorInt(const std::string csv);
  * buffers ( default = 1.5 )
  * @param maxBufferSize user provided maximum buffer size
  * @param buffer to be reallocated
- * @return true: must do a transport flush, false: buffer sizes are enough to
+ * @return true: must do a transport flush, false: buffer sizes are enough
+ * to
  * contain incoming data, no need for transport flush
  */
 bool CheckBufferAllocation(const std::size_t newSize, const float growthFactor,
diff --git a/include/selection/Selection.h b/include/selection/Selection.h
new file mode 100644
index 000000000..70d4c8314
--- /dev/null
+++ b/include/selection/Selection.h
@@ -0,0 +1,70 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ */
+
+/*
+ *   Selection API in C++
+ *
+ *   A SELECTION is the data ranges resulting from a QUERY over a file and
+ * variable(s).
+ *
+ *   A SELECTION can be a list of bounding boxes and point-sets. Other data
+ * structures
+ *   are not supported. Any query will result in such a selection.
+ *   Other selections are the write-block and auto.
+ *
+ *   Write block is a block of data written
+ *   by a writer process, it is identified by an index. If each writer outputs
+ * one block
+ *   then the index equals to the rank of the write process. With multi-var
+ * writing and
+ *   multiple steps in a file, index runs from 0 as rank 0 process' first block.
+ *
+ *   Auto selection lets the read method to automatically choose what to return.
+ * It will
+ *   be a block / blocks of selected writers.
+ *
+ *   If a query is a simple bounding box, the selection is the bounding box
+ * itself, so
+ *   the application does not need to retrieve the selection to work on the read
+ * data.
+ */
+#ifndef __ADIOS_SELECTION_H__
+#define __ADIOS_SELECTION_H__
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include "external/adios_selection.h"
+#include <stdint.h>
+/// \endcond
+
+namespace adios
+{
+
+/*************************/
+/* Types used in the API */
+/*************************/
+/* Type of selection */
+enum class SelectionType
+{
+    // Contiguous block of data defined by offsets and counts in each
+    // dimension
+    BoundingBox = ADIOS_SELECTION_BOUNDINGBOX,
+    // List of individual points
+    Points = ADIOS_SELECTION_POINTS,
+    // Selection of an individual block written by a writer process
+    WriteBlock = ADIOS_SELECTION_WRITEBLOCK,
+    // Let the method decide what to return
+    Auto = ADIOS_SELECTION_AUTO
+};
+
+class Selection
+{
+public:
+    Selection(const SelectionType t) : m_Type(t){};
+    const SelectionType m_Type;
+};
+
+} // namespace adios
+
+#endif /*__ADIOS_SELECTION_H__*/
diff --git a/include/selection/SelectionBoundingBox.h b/include/selection/SelectionBoundingBox.h
new file mode 100644
index 000000000..b110fd96e
--- /dev/null
+++ b/include/selection/SelectionBoundingBox.h
@@ -0,0 +1,38 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ */
+
+#ifndef __ADIOS_SELECTION_BOUNDINGBOX_H__
+#define __ADIOS_SELECTION_BOUNDINGBOX_H__
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <cstdint>
+/// \endcond
+
+#include "selection/Selection.h"
+
+namespace adios
+{
+
+/** Boundingbox selection to read a subset of a non-scalar variable.
+ *  @param start     array of offsets to start reading in each dimension
+ *  @param count     number of data elements to read in each dimension
+ */
+class SelectionBoundingBox : public Selection
+{
+public:
+    SelectionBoundingBox(const std::vector<std::uint64_t> start,
+                         const std::vector<std::uint64_t> count)
+    : Selection(SelectionType::BoundingBox), m_Start(start), m_Count(count)
+    {
+    }
+    ~SelectionBoundingBox(){};
+
+    std::vector<std::uint64_t> m_Start;
+    std::vector<std::uint64_t> m_Count;
+};
+
+} // namespace adios
+
+#endif /*__ADIOS_SELECTION_BOUNDINGBOX_H__*/
diff --git a/include/selection/SelectionPoints.h b/include/selection/SelectionPoints.h
new file mode 100644
index 000000000..13fa951cb
--- /dev/null
+++ b/include/selection/SelectionPoints.h
@@ -0,0 +1,55 @@
+/*
+ * Distributed under the OSI-approved Apache License, Version 2.0.  See
+ * accompanying file Copyright.txt for details.
+ */
+
+#ifndef __ADIOS_SELECTION_POINTS_H__
+#define __ADIOS_SELECTION_POINTS_H__
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <cstdint>
+/// \endcond
+
+#include "selection/Selection.h"
+#include "selection/SelectionBoundingBox.h"
+
+namespace adios
+{
+
+/** Selection for a selection of an enumeration of positions.
+ *  @param     ndim      Number of dimensions
+ *  @param     npoints   Number of points of the selection
+ *  @param     points    1D array of indices, compacted for all dimension
+ *              (e.g.  [i1,j1,k1,i2,j2,k2,...,in,jn,kn] for
+ *              n points in a 3D space.
+ */
+class SelectionPoints : public Selection
+{
+public:
+    SelectionPoints(std::size_t ndim, std::size_t npoints,
+                    std::vector<std::uint64_t> &points)
+    : Selection(SelectionType::Points), m_Ndim(ndim), m_Npoints(npoints),
+      m_Points(points)
+    {
+    }
+
+    ///< C-style constructor to be used in the C-to-C++ wrapper
+    SelectionPoints(std::size_t ndim, std::size_t npoints, uint64_t *points)
+    : Selection(SelectionType::Points), m_Ndim(ndim), m_Npoints(npoints),
+      m_Points(std::vector<std::uint64_t>()), m_PointsC(points)
+    {
+    }
+
+    ~SelectionPoints(){};
+
+    const std::size_t m_Ndim;
+    const std::size_t m_Npoints;
+    std::vector<std::uint64_t> &m_Points;
+    ///< C-to-C++ wrapper needs a pointer to hold the points created by the C
+    /// application
+    std::uint64_t *m_PointsC = nullptr;
+};
+
+} // namespace adios
+
+#endif /*__ADIOS_SELECTION_POINTS_H__*/
diff --git a/source/functions/adiosFunctions.cpp b/source/functions/adiosFunctions.cpp
index 0946dc0d6..a24cc4c25 100644
--- a/source/functions/adiosFunctions.cpp
+++ b/source/functions/adiosFunctions.cpp
@@ -632,6 +632,17 @@ std::vector<int> CSVToVectorInt(const std::string csv)
     return numbers;
 }
 
+void ConvertUint64VectorToSizetVector(const std::vector<std::uint64_t> &in,
+                                      std::vector<std::size_t> &out)
+{
+    out.clear();
+    out.reserve(in.size());
+    for (const auto inElement : in)
+    {
+        out.push_back(static_cast<std::size_t>(inElement));
+    }
+}
+
 bool CheckBufferAllocation(const std::size_t newSize, const float growthFactor,
                            const std::size_t maxBufferSize,
                            std::vector<char> &buffer)
-- 
GitLab