From eb60a58ab1f21ef7f04ebba25c6eb33caf20467b Mon Sep 17 00:00:00 2001
From: Norihiro Watanabe <norihiro.watanabe@ufz.de>
Date: Wed, 28 Sep 2016 14:55:04 +0200
Subject: [PATCH] fix a bug in LocalToGlobalIndexMap for multiple variables
 with multiple components

---
 NumLib/DOF/LocalToGlobalIndexMap.cpp | 47 +++++++++++++++++++---------
 NumLib/DOF/LocalToGlobalIndexMap.h   | 26 +++++++++++++--
 2 files changed, 56 insertions(+), 17 deletions(-)

diff --git a/NumLib/DOF/LocalToGlobalIndexMap.cpp b/NumLib/DOF/LocalToGlobalIndexMap.cpp
index 6dcfd18a79f..144e7d68ed0 100644
--- a/NumLib/DOF/LocalToGlobalIndexMap.cpp
+++ b/NumLib/DOF/LocalToGlobalIndexMap.cpp
@@ -48,35 +48,54 @@ LocalToGlobalIndexMap::findGlobalIndices(
 LocalToGlobalIndexMap::LocalToGlobalIndexMap(
     std::vector<std::unique_ptr<MeshLib::MeshSubsets>>&& mesh_subsets,
     NumLib::ComponentOrder const order)
+    : LocalToGlobalIndexMap(std::move(mesh_subsets), std::vector<unsigned>(mesh_subsets.size(), 1), order)
+{
+}
+
+
+LocalToGlobalIndexMap::LocalToGlobalIndexMap(
+    std::vector<std::unique_ptr<MeshLib::MeshSubsets>>&& mesh_subsets,
+    std::vector<unsigned> const& vec_var_n_components,
+    NumLib::ComponentOrder const order)
     : _mesh_subsets(std::move(mesh_subsets)),
       _mesh_component_map(_mesh_subsets, order)
 {
+    // construct a mapping table to get a global component ID from a variableID & a variable comp ID
+    _map_varCompID_to_globalCompID.resize(vec_var_n_components.size());
+    {
+        unsigned global_component_ID = 0;
+        for (unsigned i=0; i<vec_var_n_components.size(); i++)
+            for (unsigned j=0; j<vec_var_n_components[i]; j++)
+                _map_varCompID_to_globalCompID[i].push_back(global_component_ID++);
+    }
+
     // For all MeshSubsets and each of their MeshSubset's and each element
     // of that MeshSubset save a line of global indices.
 
 
-    _variable_component_offsets.reserve(_mesh_subsets.size());
     std::size_t offset = 0;
-    for (int variable_id = 0; variable_id < static_cast<int>(_mesh_subsets.size());
+    for (int variable_id = 0; variable_id < static_cast<int>(vec_var_n_components.size());
          ++variable_id)
     {
-        _variable_component_offsets.push_back(offset);
-        auto const& mss = *_mesh_subsets[variable_id];
-        for (int component_id = 0; component_id < static_cast<int>(mss.size());
+        for (int component_id = 0; component_id < static_cast<int>(vec_var_n_components[variable_id]);
              ++component_id)
         {
-            MeshLib::MeshSubset const& ms = mss.getMeshSubset(component_id);
-            std::size_t const mesh_id = ms.getMeshID();
-
             auto const global_component_id =
                 getGlobalComponent(variable_id, component_id);
 
-            findGlobalIndices(ms.elementsBegin(), ms.elementsEnd(), ms.getNodes(),
-                              mesh_id, global_component_id, global_component_id);
+            auto const& mss = *_mesh_subsets[global_component_id];
+            for (int subset_id = 0; subset_id < static_cast<int>(mss.size());
+                 ++subset_id)
+            {
+                MeshLib::MeshSubset const& ms = mss.getMeshSubset(subset_id);
+                std::size_t const mesh_id = ms.getMeshID();
+
+                findGlobalIndices(ms.elementsBegin(), ms.elementsEnd(), ms.getNodes(),
+                                  mesh_id, global_component_id, global_component_id);
+            }
+            // increase by number of components of that variable
+            offset += mss.size();
         }
-
-        // increase by number of components of that variable
-        offset += mss.size();
     }
 }
 
@@ -87,7 +106,7 @@ LocalToGlobalIndexMap::LocalToGlobalIndexMap(
     NumLib::MeshComponentMap&& mesh_component_map)
     : _mesh_subsets(std::move(mesh_subsets)),
       _mesh_component_map(std::move(mesh_component_map)),
-      _variable_component_offsets(1, 0) // Single variable only.
+      _map_varCompID_to_globalCompID(1, std::vector<int>(1, 0)) // Single variable only.
 {
     // There is only on mesh_subsets in the vector _mesh_subsets.
     assert(_mesh_subsets.size() == 1);
diff --git a/NumLib/DOF/LocalToGlobalIndexMap.h b/NumLib/DOF/LocalToGlobalIndexMap.h
index 2b71d267357..a8f14702348 100644
--- a/NumLib/DOF/LocalToGlobalIndexMap.h
+++ b/NumLib/DOF/LocalToGlobalIndexMap.h
@@ -44,8 +44,24 @@ public:
 public:
     /// Creates a MeshComponentMap internally and stores the global indices for
     /// each mesh element of the given mesh_subsets.
-    explicit LocalToGlobalIndexMap(
+    ///
+    /// \attention This constructor assumes the number of the given mesh subsets
+    /// is equal to the number of variables, i.e. every variable has a single component.
+    LocalToGlobalIndexMap(
+        std::vector<std::unique_ptr<MeshLib::MeshSubsets>>&& mesh_subsets,
+        NumLib::ComponentOrder const order);
+
+    /// Creates a MeshComponentMap internally and stores the global indices for
+    /// each mesh element of the given mesh_subsets.
+    ///
+    /// \param mesh_subsets  a vector of components
+    /// \param vec_var_n_components  a vector of the number of variable components.
+    /// The size of the vector should be equal to the number of variables. Sum of the entries
+    /// should be equal to the size of the mesh_subsets.
+    /// \param order  type of ordering values in a vector
+    LocalToGlobalIndexMap(
         std::vector<std::unique_ptr<MeshLib::MeshSubsets>>&& mesh_subsets,
+        std::vector<unsigned> const& vec_var_n_components,
         NumLib::ComponentOrder const order);
 
     /// Derive a LocalToGlobalIndexMap constrained to a set of mesh subsets and
@@ -73,6 +89,10 @@ public:
 
     std::size_t size() const;
 
+    std::size_t getNumberOfVariables() const { return _map_varCompID_to_globalCompID.size(); }
+
+    std::size_t getNumberOfVariableComponents(int variable_id) const { return _map_varCompID_to_globalCompID[variable_id].size(); }
+
     std::size_t getNumberOfComponents() const { return _mesh_subsets.size(); }
 
     RowColumnIndices operator()(std::size_t const mesh_item_id, const unsigned component_id) const;
@@ -139,7 +159,7 @@ private:
     std::size_t getGlobalComponent(int const variable_id,
                                    int const component_id) const
     {
-        return _variable_component_offsets[variable_id] + component_id;
+        return _map_varCompID_to_globalCompID[variable_id][component_id];
     }
 
 private:
@@ -156,7 +176,7 @@ private:
     /// \see _rows
     Table const& _columns = _rows;
 
-    std::vector<int> _variable_component_offsets;
+    std::vector<std::vector<int>> _map_varCompID_to_globalCompID;
 #ifndef NDEBUG
     /// Prints first rows of the table, every line, and the mesh component map.
     friend std::ostream& operator<<(std::ostream& os, LocalToGlobalIndexMap const& map);
-- 
GitLab