From 7ee45d4224b1ae003447ad7468c01b68c23d5bc0 Mon Sep 17 00:00:00 2001
From: Tobias Meisel <tobias.meisel@ufz.de>
Date: Tue, 15 Dec 2020 13:02:21 +0100
Subject: [PATCH] [MeL/IO] Introduce data structure for handling meta data for
 hdf writing algorithm

---
 MeshLib/IO/XDMF/HdfData.cpp   | 49 +++++++++++++++++++++++++
 MeshLib/IO/XDMF/HdfData.h     | 36 +++++++++++++++++++
 MeshLib/IO/XDMF/XdmfData.cpp  | 68 +++++++++++++++++++++++++++++++++++
 MeshLib/IO/XDMF/XdmfData.h    | 65 +++++++++++++++++++--------------
 MeshLib/IO/XDMF/XdmfHdfData.h | 44 +++++++++++++++++++++++
 5 files changed, 235 insertions(+), 27 deletions(-)
 create mode 100644 MeshLib/IO/XDMF/HdfData.cpp
 create mode 100644 MeshLib/IO/XDMF/HdfData.h
 create mode 100644 MeshLib/IO/XDMF/XdmfData.cpp
 create mode 100644 MeshLib/IO/XDMF/XdmfHdfData.h

diff --git a/MeshLib/IO/XDMF/HdfData.cpp b/MeshLib/IO/XDMF/HdfData.cpp
new file mode 100644
index 00000000000..54e3c15b48d
--- /dev/null
+++ b/MeshLib/IO/XDMF/HdfData.cpp
@@ -0,0 +1,49 @@
+#include "HdfData.h"
+
+#include <hdf5.h>
+
+#include <map>
+
+#include "BaseLib/Error.h"
+#include "BaseLib/Logging.h"
+#include "partition.h"
+
+namespace MeshLib::IO
+{
+static hid_t meshPropertyType2HdfType(MeshPropertyDataType const ogs_data_type)
+{
+    std::map<MeshPropertyDataType const, hid_t> ogs_to_hdf_type = {
+        {MeshPropertyDataType::float64, H5T_IEEE_F64LE},
+        {MeshPropertyDataType::float32, H5T_IEEE_F32LE},
+        {MeshPropertyDataType::int32, H5T_STD_I32LE},
+        {MeshPropertyDataType::int64, H5T_STD_I64LE},
+        {MeshPropertyDataType::uint32, H5T_STD_U32LE},
+        {MeshPropertyDataType::uint64, H5T_STD_U64LE},
+        {MeshPropertyDataType::int8, H5T_STD_I8LE},
+        {MeshPropertyDataType::uint8, H5T_STD_U8LE}};
+    try
+    {
+        return ogs_to_hdf_type.at(ogs_data_type);
+    }
+    catch (std::exception const& e)
+    {
+        OGS_FATAL("No known HDF5 type for OGS type. {:s}", e.what());
+    }
+}
+
+HdfData::HdfData(void const* data_start, std::size_t const size_partitioned_dim,
+                 std::size_t const size_tuple, std::string const& name,
+                 MeshPropertyDataType const mesh_property_data_type)
+    : data_start(data_start),
+      data_space{size_partitioned_dim, size_tuple},
+      name(name)
+{
+    auto const& partition_info = getPartitionInfo(size_partitioned_dim);
+    DBUG("HdfData: The partition of dataset {:s} has dimension {:d} and offset {:d}.",
+         name, size_partitioned_dim, partition_info.first);
+    auto const& offset_partitioned_dim = partition_info.first;
+    offsets = {offset_partitioned_dim, 0};
+    file_space = {partition_info.second, size_tuple};
+    data_type = meshPropertyType2HdfType(mesh_property_data_type);
+}
+}  // namespace MeshLib::IO
\ No newline at end of file
diff --git a/MeshLib/IO/XDMF/HdfData.h b/MeshLib/IO/XDMF/HdfData.h
new file mode 100644
index 00000000000..e31bb62c90b
--- /dev/null
+++ b/MeshLib/IO/XDMF/HdfData.h
@@ -0,0 +1,36 @@
+/**
+ * \file
+ * \author Tobias Meisel
+ * \date   2020-12-08
+ * \brief  Collects and holds all metadata for writing HDF5 file
+ * \copyright Copyright (c) 2012-2020, OpenGeoSys Community
+ * (http://www.opengeosys.org) Distributed under a Modified BSD License. See
+ * accompanying file LICENSE.txt or http://www.opengeosys.org/project/license
+ */
+
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "MeshPropertyDataType.h"
+
+namespace MeshLib::IO
+{
+using Hdf5DimType = unsigned long long;
+
+struct HdfData
+{
+    HdfData(void const* data_start, std::size_t size_partitioned_dim,
+            std::size_t size_tuple, std::string const& name,
+            MeshPropertyDataType mesh_property_data_type);
+    void const* data_start;
+    std::vector<Hdf5DimType> const data_space;
+    std::vector<Hdf5DimType> offsets;
+    std::vector<Hdf5DimType> file_space;
+    std::string const name;
+    int64_t data_type;
+};
+
+}  // namespace MeshLib::IO
\ No newline at end of file
diff --git a/MeshLib/IO/XDMF/XdmfData.cpp b/MeshLib/IO/XDMF/XdmfData.cpp
new file mode 100644
index 00000000000..cdee513cad8
--- /dev/null
+++ b/MeshLib/IO/XDMF/XdmfData.cpp
@@ -0,0 +1,68 @@
+#include "XdmfData.h"
+
+#include <XdmfArrayType.hpp>
+#include <XdmfAttributeCenter.hpp>
+#include <XdmfTopologyType.hpp>
+#include <cassert>
+#include <map>
+
+#include "BaseLib/Error.h"
+#include "MeshLib/Location.h"
+#include "partition.h"
+
+namespace MeshLib::IO
+
+{
+static boost::shared_ptr<XdmfArrayType const> MeshPropertyDataType2XdmfType(
+    MeshPropertyDataType const ogs_data_type)
+{
+    std::map<MeshPropertyDataType, boost::shared_ptr<XdmfArrayType const>> const
+        ogs_to_xdmf_type = {
+            {MeshPropertyDataType::float64, XdmfArrayType::Float64()},
+            {MeshPropertyDataType::float32, XdmfArrayType::Float32()},
+            {MeshPropertyDataType::int32, XdmfArrayType::Int32()},
+            // TODO (tm) XdmfLib does not support 64 bit data types so far
+            //{MeshPropertyDataType::int64, XdmfArrayType::Int64()},
+            {MeshPropertyDataType::uint32, XdmfArrayType::UInt32()},
+            // TODO (tm) XdmfLib does not support 64 bit data types so far
+            //{MeshPropertyDataType::uint64, XdmfArrayType::UInt64},
+            {MeshPropertyDataType::int8, XdmfArrayType::Int8()},
+            {MeshPropertyDataType::uint8, XdmfArrayType::UInt8()}};
+    try
+    {
+        return ogs_to_xdmf_type.at(ogs_data_type);
+    }
+    catch (const std::exception& e)
+    {
+        OGS_FATAL("No known HDF5 type for XDMF type. {:s}", e.what());
+    }
+}
+
+XdmfData::XdmfData(std::size_t size_partitioned_dim,
+                   std::size_t const size_tuple,
+                   MeshPropertyDataType const mesh_property_data_type,
+                   std::string const& name,
+                   std::optional<MeshLib::MeshItemType> const attribute_center)
+    : starts{0, 0, 0},
+      strides{1, 1, 1},
+      name(name),
+      attribute_center(attribute_center)
+{
+    auto partition_info = getPartitionInfo(size_partitioned_dim);
+    DBUG(
+        "XdmfData: The partition of dataset {:s} has dimension {:d} and offset "
+        "{:d}.",
+        name, size_partitioned_dim, partition_info.first);
+    // TODO (tm) XdmfLib does not support 64 bit data types so far
+    assert(partition_info.second < std::numeric_limits<unsigned int>::max());
+    auto const ui_global_components =
+        static_cast<unsigned int>(partition_info.second);
+    auto const ui_tuple_size = static_cast<unsigned int>(size_tuple);
+
+    piece_dims = {ui_global_components, ui_tuple_size};
+    block_dims = {static_cast<XdmfDimType>(size_partitioned_dim),
+                  ui_tuple_size};
+
+    data_type = MeshPropertyDataType2XdmfType(mesh_property_data_type);
+}
+}  // namespace MeshLib::IO
\ No newline at end of file
diff --git a/MeshLib/IO/XDMF/XdmfData.h b/MeshLib/IO/XDMF/XdmfData.h
index 2a8ad7d90d5..6bb86b6aa09 100644
--- a/MeshLib/IO/XDMF/XdmfData.h
+++ b/MeshLib/IO/XDMF/XdmfData.h
@@ -2,7 +2,7 @@
  * \file
  * \author Tobias Meisel
  * \date   2020-11-13
- * \brief  Definition of the data layer for writing Meshes
+ * \brief  Collects and holds all metadata for writing XDMF file
  * \copyright
  * Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
  *            Distributed under a Modified BSD License.
@@ -13,43 +13,54 @@
 #pragma once
 
 #include <boost/shared_ptr.hpp>
+#include <optional>
 #include <string>
 #include <vector>
 
-class XdmfAttributeCenter;
+#include "MeshLib/Location.h"
+#include "MeshPropertyDataType.h"
+
 class XdmfArrayType;
 
 namespace MeshLib::IO
 {
 using XdmfDimType = unsigned int;
-using Hdf5DimType = unsigned long long;
-struct Geometry final
-{
-    std::vector<double> flattend_values;
-    std::vector<XdmfDimType> const starts;
-    std::vector<XdmfDimType> const strides;
-    std::vector<XdmfDimType> const vdims;
-    std::vector<Hdf5DimType> const vldims;
-};
 
-struct Topology final
+struct XdmfData
 {
-    std::vector<int> flattend_values;
+    /**
+     * \brief XdmfData contains meta data to be passed to the XdmfWriter - it
+     * does not contain the actual values!!
+     * @param size_partitioned_dim The first dimension (index 0) is assumed to
+     * be the dimension that is partitioned. This first dimension expresses  the
+     * length, usually the number of nodes or the number of cells. These values
+     * give the length of the local partition.
+     * @param size_tuple We assume there is at most a rank of 2 of data
+     * (properties). The size of tuple gives the length of the second dimension
+     * (index 1).
+     * @param name The name of the attribute. It assumed to be unique.
+     * @param attribute_center XdmfData is used for topology, geometry and
+     * attributes. Geometry and topology have never a attribute_center.
+     * Attributes have always an  attribute_center
+     * @return vector of meta data
+     */
+    XdmfData(std::size_t size_partitioned_dim, std::size_t size_tuple,
+             MeshPropertyDataType mesh_property_data_type,
+             std::string const& name,
+             std::optional<MeshLib::MeshItemType> attribute_center);
+    // a hyperslab is defined by starts and strides see
+    // https://www.xdmf.org/index.php/XDMF_Model_and_Format#HyperSlab
     std::vector<XdmfDimType> const starts;
     std::vector<XdmfDimType> const strides;
-    std::vector<XdmfDimType> const vdims;
-    std::vector<Hdf5DimType> const vldims;
-};
-
-struct AttributeMeta final
-{
-    const void* data_start;
-    std::string name;
-    boost::shared_ptr<const XdmfAttributeCenter> attribute_center;
+    // piece and block nomenclature taken from
+    // https://www.paraview.org/Wiki/VTK/Tutorials/Composite_Datasets in XDMF it
+    // refers to spatial grid collection composed from subsets
+    // https://www.xdmf.org/index.php/XDMF_Model_and_Format#Grid
+    std::vector<XdmfDimType> piece_dims;
+    std::vector<XdmfDimType> block_dims;
     boost::shared_ptr<const XdmfArrayType> data_type;
-    std::vector<XdmfDimType> starts;
-    std::vector<XdmfDimType> strides;
-    std::vector<XdmfDimType> vdims;
-    std::vector<Hdf5DimType> vldims;
+    std::string const name;
+    std::optional<MeshLib::MeshItemType> const attribute_center;
 };
-}  // namespace MeshLib::IO
\ No newline at end of file
+
+}  // namespace MeshLib::IO
diff --git a/MeshLib/IO/XDMF/XdmfHdfData.h b/MeshLib/IO/XDMF/XdmfHdfData.h
new file mode 100644
index 00000000000..1b049e40f2b
--- /dev/null
+++ b/MeshLib/IO/XDMF/XdmfHdfData.h
@@ -0,0 +1,44 @@
+/**
+ * \file
+ * \author Tobias Meisel
+ * \date   2020-11-13
+ * \brief  Holds all data for the combined writing of xdmf and hdf5 file
+ * \copyright
+ * Copyright (c) 2012-2020, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+#include "HdfData.h"
+#include "XdmfData.h"
+
+// TODO (tm) This structs are the result of transformData.cpp. This structures
+// can be eliminated.
+namespace MeshLib::IO
+{
+struct Geometry final
+{
+    std::vector<double> flattened_values;
+    HdfData hdf;
+    XdmfData xdmf;
+};
+
+struct Topology final
+{
+    std::vector<int> flattened_values;
+    HdfData hdf;
+    XdmfData xdmf;
+};
+
+struct AttributeMeta final
+{
+    HdfData hdf;
+    XdmfData xdmf;
+};
+}  // namespace MeshLib::IO
\ No newline at end of file
-- 
GitLab