From b240d9b4e88593bc313d6d07087bd35de27448bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Tue, 22 Oct 2024 19:15:17 +0200
Subject: [PATCH] Add symmetry stencil for 1D and continue generalization and
 cleanup

---
 src/mesh/StencilBuilder.cpp                   | 357 +++++++++++-------
 src/mesh/StencilBuilder.hpp                   |  19 +
 src/mesh/StencilDescriptor.hpp                |  20 +-
 .../PolynomialReconstructionDescriptor.hpp    |   4 +-
 ...est_PolynomialReconstructionDescriptor.cpp |  14 +-
 tests/test_StencilBuilder.cpp                 | 106 ++++--
 6 files changed, 342 insertions(+), 178 deletions(-)

diff --git a/src/mesh/StencilBuilder.cpp b/src/mesh/StencilBuilder.cpp
index d70ea9534..1880c0493 100644
--- a/src/mesh/StencilBuilder.cpp
+++ b/src/mesh/StencilBuilder.cpp
@@ -7,6 +7,87 @@
 
 #include <set>
 
+template <typename ConnectivityType>
+auto
+StencilBuilder::_buildSymmetryNodeList(const ConnectivityType& connectivity,
+                                       const BoundaryDescriptorList& symmetry_boundary_descriptor_list) const
+{
+  static_assert(ConnectivityType::Dimension > 1);
+  NodeArray<bool> symmetry_node_list{connectivity, symmetry_boundary_descriptor_list.size()};
+  symmetry_node_list.fill(false);
+
+  auto face_to_node_matrix   = connectivity.faceToNodeMatrix();
+  size_t i_symmetry_boundary = 0;
+  for (auto p_boundary_descriptor : symmetry_boundary_descriptor_list) {
+    const IBoundaryDescriptor& boundary_descriptor = *p_boundary_descriptor;
+
+    bool found = false;
+    for (size_t i_ref_node_list = 0; i_ref_node_list < connectivity.template numberOfRefItemList<ItemType::face>();
+         ++i_ref_node_list) {
+      const auto& ref_face_list = connectivity.template refItemList<ItemType::face>(i_ref_node_list);
+      if (ref_face_list.refId() == boundary_descriptor) {
+        found = true;
+        for (size_t i_face = 0; i_face < ref_face_list.list().size(); ++i_face) {
+          const FaceId face_id = ref_face_list.list()[i_face];
+          auto node_list       = face_to_node_matrix[face_id];
+          for (size_t i_node = 0; i_node < node_list.size(); ++i_node) {
+            const NodeId node_id = node_list[i_node];
+
+            symmetry_node_list[node_id][i_symmetry_boundary] = true;
+          }
+        }
+        break;
+      }
+    }
+    ++i_symmetry_boundary;
+    if (not found) {
+      std::ostringstream error_msg;
+      error_msg << "cannot find boundary '" << rang::fgB::yellow << boundary_descriptor << rang::fg::reset << '\'';
+      throw NormalError(error_msg.str());
+    }
+  }
+
+  return symmetry_node_list;
+}
+
+template <>
+auto
+StencilBuilder::_buildSymmetryNodeList(const Connectivity<1>& connectivity,
+                                       const BoundaryDescriptorList& symmetry_boundary_descriptor_list) const
+{
+  NodeArray<bool> symmetry_node_list{connectivity, symmetry_boundary_descriptor_list.size()};
+  symmetry_node_list.fill(false);
+
+  size_t i_symmetry_boundary = 0;
+  for (auto p_boundary_descriptor : symmetry_boundary_descriptor_list) {
+    const IBoundaryDescriptor& boundary_descriptor = *p_boundary_descriptor;
+
+    bool found = false;
+    for (size_t i_ref_node_list = 0; i_ref_node_list < connectivity.template numberOfRefItemList<ItemType::node>();
+         ++i_ref_node_list) {
+      const auto& ref_node_list = connectivity.template refItemList<ItemType::node>(i_ref_node_list);
+      if (ref_node_list.refId() == boundary_descriptor) {
+        found          = true;
+        auto node_list = ref_node_list.list();
+        for (size_t i_node = 0; i_node < node_list.size(); ++i_node) {
+          const NodeId node_id = node_list[i_node];
+
+          symmetry_node_list[node_id][i_symmetry_boundary] = true;
+        }
+        break;
+      }
+    }
+    ++i_symmetry_boundary;
+    if (not found) {
+      std::ostringstream error_msg;
+      error_msg << "cannot find boundary '" << rang::fgB::yellow << boundary_descriptor << rang::fg::reset << '\'';
+      throw NormalError(error_msg.str());
+    }
+  }
+
+  return symmetry_node_list;
+}
+
 template <typename ConnectivityType>
 Array<const uint32_t>
 StencilBuilder::_getRowMap(const ConnectivityType& connectivity) const
@@ -192,151 +273,173 @@ StencilBuilder::_buildC2C(const ConnectivityType& connectivity,
       return {primal_stencil, {}};
     }
   } else {
-    if constexpr (ConnectivityType::Dimension > 1) {
-      std::vector<Array<const FaceId>> boundary_node_list;
+    NodeArray<bool> symmetry_node_list = this->_buildSymmetryNodeList(connectivity, symmetry_boundary_descriptor_list);
 
-      NodeArray<bool> symmetry_node_list(connectivity, symmetry_boundary_descriptor_list.size());
-      symmetry_node_list.fill(0);
+    auto cell_to_node_matrix = connectivity.cellToNodeMatrix();
+    auto node_to_cell_matrix = connectivity.nodeToCellMatrix();
 
-      auto face_to_node_matrix = connectivity.faceToNodeMatrix();
-      auto cell_to_node_matrix = connectivity.cellToNodeMatrix();
-      auto node_to_cell_matrix = connectivity.nodeToCellMatrix();
+    auto cell_is_owned = connectivity.cellIsOwned();
+    auto cell_number   = connectivity.cellNumber();
 
-      {
-        size_t i_symmetry_boundary = 0;
-        for (auto p_boundary_descriptor : symmetry_boundary_descriptor_list) {
-          const IBoundaryDescriptor& boundary_descriptor = *p_boundary_descriptor;
-
-          bool found = false;
-          for (size_t i_ref_node_list = 0;
-               i_ref_node_list < connectivity.template numberOfRefItemList<ItemType::face>(); ++i_ref_node_list) {
-            const auto& ref_face_list = connectivity.template refItemList<ItemType::face>(i_ref_node_list);
-            if (ref_face_list.refId() == boundary_descriptor) {
-              found = true;
-              boundary_node_list.push_back(ref_face_list.list());
-              for (size_t i_face = 0; i_face < ref_face_list.list().size(); ++i_face) {
-                const FaceId face_id = ref_face_list.list()[i_face];
-                auto node_list       = face_to_node_matrix[face_id];
-                for (size_t i_node = 0; i_node < node_list.size(); ++i_node) {
-                  const NodeId node_id = node_list[i_node];
-
-                  symmetry_node_list[node_id][i_symmetry_boundary] = true;
-                }
-              }
-              break;
+    Array<uint32_t> row_map{connectivity.numberOfCells() + 1};
+    row_map[0] = 0;
+    std::vector<Array<uint32_t>> symmetry_row_map_list(symmetry_boundary_descriptor_list.size());
+    for (auto&& symmetry_row_map : symmetry_row_map_list) {
+      symmetry_row_map    = Array<uint32_t>{connectivity.numberOfCells() + 1};
+      symmetry_row_map[0] = 0;
+    }
+
+    std::vector<uint32_t> column_indices_vector;
+    std::vector<std::vector<uint32_t>> symmetry_column_indices_vector(symmetry_boundary_descriptor_list.size());
+
+    for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) {
+      std::set<CellId> cell_set;
+      std::vector<std::set<CellId>> by_boundary_symmetry_cell(symmetry_boundary_descriptor_list.size());
+
+      if (cell_is_owned[cell_id]) {
+        auto cell_node_list = cell_to_node_matrix[cell_id];
+        for (size_t i_cell_node = 0; i_cell_node < cell_node_list.size(); ++i_cell_node) {
+          const NodeId cell_node_id = cell_node_list[i_cell_node];
+          auto node_cell_list       = node_to_cell_matrix[cell_node_id];
+          for (size_t i_node_cell = 0; i_node_cell < node_cell_list.size(); ++i_node_cell) {
+            const CellId node_cell_id = node_cell_list[i_node_cell];
+            if (cell_id != node_cell_id) {
+              cell_set.insert(node_cell_id);
             }
           }
-          ++i_symmetry_boundary;
-          if (not found) {
-            std::ostringstream error_msg;
-            error_msg << "cannot find boundary '" << rang::fgB::yellow << boundary_descriptor << rang::fg::reset
-                      << '\'';
-            throw NormalError(error_msg.str());
-          }
         }
-      }
 
-      auto cell_is_owned = connectivity.cellIsOwned();
-      auto cell_number   = connectivity.cellNumber();
-
-      Array<uint32_t> row_map{connectivity.numberOfCells() + 1};
-      row_map[0] = 0;
-      std::vector<Array<uint32_t>> symmetry_row_map_list(symmetry_boundary_descriptor_list.size());
-      for (auto&& symmetry_row_map : symmetry_row_map_list) {
-        symmetry_row_map    = Array<uint32_t>{connectivity.numberOfCells() + 1};
-        symmetry_row_map[0] = 0;
-      }
-
-      std::vector<uint32_t> column_indices_vector;
-      std::vector<std::vector<uint32_t>> symmetry_column_indices_vector(symmetry_boundary_descriptor_list.size());
+        {
+          std::vector<CellId> cell_vector;
+          for (auto&& set_cell_id : cell_set) {
+            cell_vector.push_back(set_cell_id);
+          }
+          std::sort(cell_vector.begin(), cell_vector.end(),
+                    [&cell_number](const CellId& cell0_id, const CellId& cell1_id) {
+                      return cell_number[cell0_id] < cell_number[cell1_id];
+                    });
 
-      for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) {
-        std::set<CellId> cell_set;
-        std::vector<std::set<CellId>> by_boundary_symmetry_cell(symmetry_boundary_descriptor_list.size());
+          for (auto&& vector_cell_id : cell_vector) {
+            column_indices_vector.push_back(vector_cell_id);
+          }
+        }
 
-        if (cell_is_owned[cell_id]) {
-          auto cell_node_list = cell_to_node_matrix[cell_id];
+        for (size_t i = 0; i < symmetry_boundary_descriptor_list.size(); ++i) {
+          std::set<CellId> symmetry_cell_set;
           for (size_t i_cell_node = 0; i_cell_node < cell_node_list.size(); ++i_cell_node) {
             const NodeId cell_node_id = cell_node_list[i_cell_node];
-            auto node_cell_list       = node_to_cell_matrix[cell_node_id];
-            for (size_t i_node_cell = 0; i_node_cell < node_cell_list.size(); ++i_node_cell) {
-              const CellId node_cell_id = node_cell_list[i_node_cell];
-              if (cell_id != node_cell_id) {
-                cell_set.insert(node_cell_id);
+            if (symmetry_node_list[cell_node_id][i]) {
+              auto node_cell_list = node_to_cell_matrix[cell_node_id];
+              for (size_t i_node_cell = 0; i_node_cell < node_cell_list.size(); ++i_node_cell) {
+                const CellId node_cell_id = node_cell_list[i_node_cell];
+                symmetry_cell_set.insert(node_cell_id);
               }
             }
           }
+          by_boundary_symmetry_cell[i] = symmetry_cell_set;
 
-          {
-            std::vector<CellId> cell_vector;
-            for (auto&& set_cell_id : cell_set) {
-              cell_vector.push_back(set_cell_id);
-            }
-            std::sort(cell_vector.begin(), cell_vector.end(),
-                      [&cell_number](const CellId& cell0_id, const CellId& cell1_id) {
-                        return cell_number[cell0_id] < cell_number[cell1_id];
-                      });
-
-            for (auto&& vector_cell_id : cell_vector) {
-              column_indices_vector.push_back(vector_cell_id);
-            }
+          std::vector<CellId> cell_vector;
+          for (auto&& set_cell_id : symmetry_cell_set) {
+            cell_vector.push_back(set_cell_id);
           }
+          std::sort(cell_vector.begin(), cell_vector.end(),
+                    [&cell_number](const CellId& cell0_id, const CellId& cell1_id) {
+                      return cell_number[cell0_id] < cell_number[cell1_id];
+                    });
 
-          for (size_t i = 0; i < symmetry_boundary_descriptor_list.size(); ++i) {
-            std::set<CellId> symmetry_cell_set;
-            for (size_t i_cell_node = 0; i_cell_node < cell_node_list.size(); ++i_cell_node) {
-              const NodeId cell_node_id = cell_node_list[i_cell_node];
-              if (symmetry_node_list[cell_node_id][i]) {
-                auto node_cell_list = node_to_cell_matrix[cell_node_id];
-                for (size_t i_node_cell = 0; i_node_cell < node_cell_list.size(); ++i_node_cell) {
-                  const CellId node_cell_id = node_cell_list[i_node_cell];
-                  symmetry_cell_set.insert(node_cell_id);
-                }
-              }
-            }
-            by_boundary_symmetry_cell[i] = symmetry_cell_set;
-
-            std::vector<CellId> cell_vector;
-            for (auto&& set_cell_id : symmetry_cell_set) {
-              cell_vector.push_back(set_cell_id);
-            }
-            std::sort(cell_vector.begin(), cell_vector.end(),
-                      [&cell_number](const CellId& cell0_id, const CellId& cell1_id) {
-                        return cell_number[cell0_id] < cell_number[cell1_id];
-                      });
-
-            for (auto&& vector_cell_id : cell_vector) {
-              symmetry_column_indices_vector[i].push_back(vector_cell_id);
-            }
+          for (auto&& vector_cell_id : cell_vector) {
+            symmetry_column_indices_vector[i].push_back(vector_cell_id);
           }
         }
-        row_map[cell_id + 1] = row_map[cell_id] + cell_set.size();
+      }
+      row_map[cell_id + 1] = row_map[cell_id] + cell_set.size();
 
-        for (size_t i = 0; i < symmetry_row_map_list.size(); ++i) {
-          symmetry_row_map_list[i][cell_id + 1] =
-            symmetry_row_map_list[i][cell_id] + by_boundary_symmetry_cell[i].size();
-        }
+      for (size_t i = 0; i < symmetry_row_map_list.size(); ++i) {
+        symmetry_row_map_list[i][cell_id + 1] = symmetry_row_map_list[i][cell_id] + by_boundary_symmetry_cell[i].size();
       }
-      ConnectivityMatrix primal_stencil{row_map, convert_to_array(column_indices_vector)};
-
-      CellToCellStencilArray::BoundaryDescriptorStencilArrayList symmetry_boundary_stencil_list;
-      {
-        size_t i = 0;
-        for (auto&& p_boundary_descriptor : symmetry_boundary_descriptor_list) {
-          symmetry_boundary_stencil_list.emplace_back(
-            CellToCellStencilArray::
-              BoundaryDescriptorStencilArray{p_boundary_descriptor,
-                                             ConnectivityMatrix{symmetry_row_map_list[i],
-                                                                convert_to_array(symmetry_column_indices_vector[i])}});
-          ++i;
-        }
+    }
+    ConnectivityMatrix primal_stencil{row_map, convert_to_array(column_indices_vector)};
+
+    CellToCellStencilArray::BoundaryDescriptorStencilArrayList symmetry_boundary_stencil_list;
+    {
+      size_t i = 0;
+      for (auto&& p_boundary_descriptor : symmetry_boundary_descriptor_list) {
+        symmetry_boundary_stencil_list.emplace_back(
+          CellToCellStencilArray::
+            BoundaryDescriptorStencilArray{p_boundary_descriptor,
+                                           ConnectivityMatrix{symmetry_row_map_list[i],
+                                                              convert_to_array(symmetry_column_indices_vector[i])}});
+        ++i;
       }
+    }
 
-      return {{primal_stencil}, {symmetry_boundary_stencil_list}};
+    return {{primal_stencil}, {symmetry_boundary_stencil_list}};
+  }
+}
 
-    } else {
-      throw NotImplementedError("Only implemented in 2D/3D");
-    }
+template <>
+CellToCellStencilArray
+StencilBuilder::_buildC2C(const Connectivity<1>& connectivity,
+                          const StencilDescriptor& stencil_descriptor,
+                          const BoundaryDescriptorList& symmetry_boundary_descriptor_list) const
+{
+  if (stencil_descriptor.connectionType() != StencilDescriptor::ConnectionType::by_cells) {
+    return StencilBuilder::_buildC2C(connectivity, stencil_descriptor.numberOfLayers(),
+                                     symmetry_boundary_descriptor_list);
+  } else {
+    throw UnexpectedError("Cannot build cell to cell stencil using cell connectivity");
+  }
+}
+
+template <>
+CellToCellStencilArray
+StencilBuilder::_buildC2C(const Connectivity<2>& connectivity,
+                          const StencilDescriptor& stencil_descriptor,
+                          const BoundaryDescriptorList& symmetry_boundary_descriptor_list) const
+{
+  switch (stencil_descriptor.connectionType()) {
+  case StencilDescriptor::ConnectionType::by_nodes: {
+    return StencilBuilder::_buildC2C(connectivity, stencil_descriptor.numberOfLayers(),
+                                     symmetry_boundary_descriptor_list);
+  }
+  case StencilDescriptor::ConnectionType::by_edges:
+  case StencilDescriptor::ConnectionType::by_faces: {
+    throw NotImplementedError("non by_node stencil");
+  }
+  case StencilDescriptor::ConnectionType::by_cells: {
+    throw UnexpectedError("Cannot build cell to cell stencil using cell connectivity");
+  }
+    // LCOV_EXCL_START
+  default: {
+    throw UnexpectedError("invalid connection type");
+  }
+    // LCOV_EXCL_STOP
+  }
+}
+
+template <>
+CellToCellStencilArray
+StencilBuilder::_buildC2C(const Connectivity<3>& connectivity,
+                          const StencilDescriptor& stencil_descriptor,
+                          const BoundaryDescriptorList& symmetry_boundary_descriptor_list) const
+{
+  switch (stencil_descriptor.connectionType()) {
+  case StencilDescriptor::ConnectionType::by_nodes: {
+    return StencilBuilder::_buildC2C(connectivity, stencil_descriptor.numberOfLayers(),
+                                     symmetry_boundary_descriptor_list);
+  }
+  case StencilDescriptor::ConnectionType::by_edges:
+  case StencilDescriptor::ConnectionType::by_faces: {
+    throw NotImplementedError("non by_node stencil");
+  }
+  case StencilDescriptor::ConnectionType::by_cells: {
+    throw UnexpectedError("Cannot build cell to cell stencil using cell connectivity");
+  }
+    // LCOV_EXCL_START
+  default: {
+    throw UnexpectedError("invalid connection type");
+  }
+    // LCOV_EXCL_STOP
   }
 }
 
@@ -347,16 +450,16 @@ StencilBuilder::buildC2C(const IConnectivity& connectivity,
 {
   switch (connectivity.dimension()) {
   case 1: {
-    return StencilBuilder::_buildC2C(dynamic_cast<const Connectivity<1>&>(connectivity),
-                                     stencil_descriptor.numberOfLayers(), symmetry_boundary_descriptor_list);
+    return StencilBuilder::_buildC2C(dynamic_cast<const Connectivity<1>&>(connectivity), stencil_descriptor,
+                                     symmetry_boundary_descriptor_list);
   }
   case 2: {
-    return StencilBuilder::_buildC2C(dynamic_cast<const Connectivity<2>&>(connectivity),
-                                     stencil_descriptor.numberOfLayers(), symmetry_boundary_descriptor_list);
+    return StencilBuilder::_buildC2C(dynamic_cast<const Connectivity<2>&>(connectivity), stencil_descriptor,
+                                     symmetry_boundary_descriptor_list);
   }
   case 3: {
-    return StencilBuilder::_buildC2C(dynamic_cast<const Connectivity<3>&>(connectivity),
-                                     stencil_descriptor.numberOfLayers(), symmetry_boundary_descriptor_list);
+    return StencilBuilder::_buildC2C(dynamic_cast<const Connectivity<3>&>(connectivity), stencil_descriptor,
+                                     symmetry_boundary_descriptor_list);
   }
   default: {
     throw UnexpectedError("invalid connectivity dimension");
diff --git a/src/mesh/StencilBuilder.hpp b/src/mesh/StencilBuilder.hpp
index b930ca4cc..464a7fc27 100644
--- a/src/mesh/StencilBuilder.hpp
+++ b/src/mesh/StencilBuilder.hpp
@@ -9,6 +9,7 @@
 #include <vector>
 
 class IConnectivity;
+
 class StencilBuilder
 {
  public:
@@ -22,6 +23,24 @@ class StencilBuilder
   Array<const uint32_t> _getColumnIndices(const ConnectivityType& connectivity,
                                           const Array<const uint32_t>& row_map) const;
 
+  template <typename ConnectivityType>
+  auto _buildSymmetryNodeList(const ConnectivityType& connectivity,
+                              const BoundaryDescriptorList& symmetry_boundary_descriptor_list) const;
+
+  template <typename ConnectivityType,
+            ItemType source_item_type,
+            ItemType connecting_item_type,
+            ItemType target_item_type>
+  StencilArray<source_item_type, target_item_type> _build(
+    const ConnectivityType& connectivity,
+    const StencilDescriptor& stencil_descriptor,
+    const BoundaryDescriptorList& symmetry_boundary_descriptor_list) const;
+
+  template <typename ConnectivityType>
+  CellToCellStencilArray _buildC2C(const ConnectivityType& connectivity,
+                                   const StencilDescriptor& stencil_descriptor,
+                                   const BoundaryDescriptorList& symmetry_boundary_descriptor_list) const;
+
   template <typename ConnectivityType>
   CellToCellStencilArray _buildC2C(const ConnectivityType& connectivity,
                                    size_t number_of_layers,
diff --git a/src/mesh/StencilDescriptor.hpp b/src/mesh/StencilDescriptor.hpp
index 8dfffd3e5..d099f0086 100644
--- a/src/mesh/StencilDescriptor.hpp
+++ b/src/mesh/StencilDescriptor.hpp
@@ -8,16 +8,17 @@
 class StencilDescriptor
 {
  public:
-  enum class Type : int
+  enum class ConnectionType : int
   {
     by_nodes = 1,
     by_edges = 2,
-    by_faces = 3
+    by_faces = 3,
+    by_cells = 4
   };
 
  private:
   size_t m_number_of_layers;
-  Type m_type;
+  ConnectionType m_connection_type;
 
  public:
   PUGS_INLINE
@@ -28,17 +29,17 @@ class StencilDescriptor
   };
 
   PUGS_INLINE
-  const Type&
-  type() const
+  const ConnectionType&
+  connectionType() const
   {
-    return m_type;
+    return m_connection_type;
   };
 
   PUGS_INLINE
   friend bool
   operator==(const StencilDescriptor& sd0, const StencilDescriptor& sd1)
   {
-    return (sd0.m_number_of_layers == sd1.m_number_of_layers) and (sd0.m_type == sd1.m_type);
+    return (sd0.m_number_of_layers == sd1.m_number_of_layers) and (sd0.m_connection_type == sd1.m_connection_type);
   }
 
   PUGS_INLINE
@@ -48,11 +49,10 @@ class StencilDescriptor
     return not(sd0 == sd1);
   }
 
-  StencilDescriptor(const size_t number_of_layers, const Type type) : m_number_of_layers{number_of_layers}, m_type{type}
+  StencilDescriptor(const size_t number_of_layers, const ConnectionType type)
+    : m_number_of_layers{number_of_layers}, m_connection_type{type}
   {}
 
-  // StencilDescriptor() : m_number_of_layers(1), m_type{Type::by_nodes} {};
-
   StencilDescriptor(const StencilDescriptor&) = default;
   StencilDescriptor(StencilDescriptor&&)      = default;
 
diff --git a/src/scheme/PolynomialReconstructionDescriptor.hpp b/src/scheme/PolynomialReconstructionDescriptor.hpp
index 87188f85f..44fdd2082 100644
--- a/src/scheme/PolynomialReconstructionDescriptor.hpp
+++ b/src/scheme/PolynomialReconstructionDescriptor.hpp
@@ -84,7 +84,7 @@ class PolynomialReconstructionDescriptor
   PolynomialReconstructionDescriptor(const IntegrationMethodType integration_method, const size_t degree)
     : m_integration_method{integration_method},
       m_degree{degree},
-      m_stencil_descriptor(degree, StencilDescriptor::Type::by_nodes)
+      m_stencil_descriptor(degree, StencilDescriptor::ConnectionType::by_nodes)
   {}
 
   PolynomialReconstructionDescriptor(const IntegrationMethodType integration_method,
@@ -92,7 +92,7 @@ class PolynomialReconstructionDescriptor
                                      const BoundaryDescriptorList& symmetry_boundary_descriptor_list)
     : m_integration_method{integration_method},
       m_degree{degree},
-      m_stencil_descriptor(degree, StencilDescriptor::Type::by_nodes),
+      m_stencil_descriptor(degree, StencilDescriptor::ConnectionType::by_nodes),
       m_symmetry_boundary_descriptor_list(symmetry_boundary_descriptor_list)
   {}
 
diff --git a/tests/test_PolynomialReconstructionDescriptor.cpp b/tests/test_PolynomialReconstructionDescriptor.cpp
index 9fc51a5bf..32d3c4af1 100644
--- a/tests/test_PolynomialReconstructionDescriptor.cpp
+++ b/tests/test_PolynomialReconstructionDescriptor.cpp
@@ -16,7 +16,7 @@ TEST_CASE("PolynomialReconstructionDescriptor", "[scheme]")
 
     REQUIRE(descriptor.degree() == 1);
     REQUIRE(descriptor.stencilDescriptor().numberOfLayers() == 1);
-    REQUIRE(descriptor.stencilDescriptor().type() == StencilDescriptor::Type::by_nodes);
+    REQUIRE(descriptor.stencilDescriptor().connectionType() == StencilDescriptor::ConnectionType::by_nodes);
     REQUIRE(descriptor.symmetryBoundaryDescriptorList().size() == 0);
 
     REQUIRE(descriptor.preconditioning() == true);
@@ -29,7 +29,7 @@ TEST_CASE("PolynomialReconstructionDescriptor", "[scheme]")
 
     REQUIRE(descriptor.degree() == 4);
     REQUIRE(descriptor.stencilDescriptor().numberOfLayers() == 4);
-    REQUIRE(descriptor.stencilDescriptor().type() == StencilDescriptor::Type::by_nodes);
+    REQUIRE(descriptor.stencilDescriptor().connectionType() == StencilDescriptor::ConnectionType::by_nodes);
     REQUIRE(descriptor.symmetryBoundaryDescriptorList().size() == 0);
 
     REQUIRE(descriptor.preconditioning() == true);
@@ -38,13 +38,13 @@ TEST_CASE("PolynomialReconstructionDescriptor", "[scheme]")
 
   SECTION("degree and stencil")
   {
-    StencilDescriptor sd{2, StencilDescriptor::Type::by_faces};
+    StencilDescriptor sd{2, StencilDescriptor::ConnectionType::by_faces};
 
     PolynomialReconstructionDescriptor descriptor{IntegrationMethodType::cell_center, 1, sd};
 
     REQUIRE(descriptor.degree() == 1);
     REQUIRE(descriptor.stencilDescriptor().numberOfLayers() == 2);
-    REQUIRE(descriptor.stencilDescriptor().type() == StencilDescriptor::Type::by_faces);
+    REQUIRE(descriptor.stencilDescriptor().connectionType() == StencilDescriptor::ConnectionType::by_faces);
     REQUIRE(descriptor.symmetryBoundaryDescriptorList().size() == 0);
 
     REQUIRE(descriptor.preconditioning() == true);
@@ -62,7 +62,7 @@ TEST_CASE("PolynomialReconstructionDescriptor", "[scheme]")
 
     REQUIRE(descriptor.degree() == 2);
     REQUIRE(descriptor.stencilDescriptor().numberOfLayers() == 2);
-    REQUIRE(descriptor.stencilDescriptor().type() == StencilDescriptor::Type::by_nodes);
+    REQUIRE(descriptor.stencilDescriptor().connectionType() == StencilDescriptor::ConnectionType::by_nodes);
     REQUIRE(descriptor.symmetryBoundaryDescriptorList().size() == 3);
 
     REQUIRE(descriptor.symmetryBoundaryDescriptorList()[0]->type() == IBoundaryDescriptor::Type::named);
@@ -75,7 +75,7 @@ TEST_CASE("PolynomialReconstructionDescriptor", "[scheme]")
 
   SECTION("degree, stencil and symmetries")
   {
-    StencilDescriptor sd{3, StencilDescriptor::Type::by_edges};
+    StencilDescriptor sd{3, StencilDescriptor::ConnectionType::by_edges};
 
     std::vector<std::shared_ptr<const IBoundaryDescriptor>> bc_list;
     bc_list.push_back(std::make_shared<NamedBoundaryDescriptor>("XMIN"));
@@ -86,7 +86,7 @@ TEST_CASE("PolynomialReconstructionDescriptor", "[scheme]")
 
     REQUIRE(descriptor.degree() == 1);
     REQUIRE(descriptor.stencilDescriptor().numberOfLayers() == 3);
-    REQUIRE(descriptor.stencilDescriptor().type() == StencilDescriptor::Type::by_edges);
+    REQUIRE(descriptor.stencilDescriptor().connectionType() == StencilDescriptor::ConnectionType::by_edges);
     REQUIRE(descriptor.symmetryBoundaryDescriptorList().size() == 3);
 
     REQUIRE(descriptor.symmetryBoundaryDescriptorList()[0]->type() == IBoundaryDescriptor::Type::named);
diff --git a/tests/test_StencilBuilder.cpp b/tests/test_StencilBuilder.cpp
index b8c6387e1..b99ba218a 100644
--- a/tests/test_StencilBuilder.cpp
+++ b/tests/test_StencilBuilder.cpp
@@ -64,8 +64,8 @@ TEST_CASE("StencilBuilder", "[mesh]")
         const Connectivity<1>& connectivity = mesh.connectivity();
 
         auto stencil_array =
-          StencilManager::instance().getCellToCellStencilArray(connectivity,
-                                                               StencilDescriptor{1, StencilDescriptor::Type::by_nodes});
+          StencilManager::instance()
+            .getCellToCellStencilArray(connectivity, StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes});
 
         REQUIRE(is_valid(connectivity, stencil_array));
       }
@@ -76,8 +76,8 @@ TEST_CASE("StencilBuilder", "[mesh]")
 
         const Connectivity<1>& connectivity = mesh.connectivity();
         auto stencil_array =
-          StencilManager::instance().getCellToCellStencilArray(connectivity,
-                                                               StencilDescriptor{1, StencilDescriptor::Type::by_nodes});
+          StencilManager::instance()
+            .getCellToCellStencilArray(connectivity, StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes});
 
         REQUIRE(is_valid(connectivity, stencil_array));
       }
@@ -90,10 +90,11 @@ TEST_CASE("StencilBuilder", "[mesh]")
         const auto& mesh = *MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<2>>();
 
         const Connectivity<2>& connectivity = mesh.connectivity();
-        REQUIRE(is_valid(connectivity,
-                         StencilManager::instance()
-                           .getCellToCellStencilArray(connectivity,
-                                                      StencilDescriptor{1, StencilDescriptor::Type::by_nodes})));
+        REQUIRE(
+          is_valid(connectivity,
+                   StencilManager::instance()
+                     .getCellToCellStencilArray(connectivity,
+                                                StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes})));
       }
 
       SECTION("hybrid")
@@ -101,10 +102,11 @@ TEST_CASE("StencilBuilder", "[mesh]")
         const auto& mesh = *MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<2>>();
 
         const Connectivity<2>& connectivity = mesh.connectivity();
-        REQUIRE(is_valid(connectivity,
-                         StencilManager::instance()
-                           .getCellToCellStencilArray(connectivity,
-                                                      StencilDescriptor{1, StencilDescriptor::Type::by_nodes})));
+        REQUIRE(
+          is_valid(connectivity,
+                   StencilManager::instance()
+                     .getCellToCellStencilArray(connectivity,
+                                                StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes})));
       }
     }
 
@@ -115,10 +117,11 @@ TEST_CASE("StencilBuilder", "[mesh]")
         const auto& mesh = *MeshDataBaseForTests::get().cartesian3DMesh()->get<Mesh<3>>();
 
         const Connectivity<3>& connectivity = mesh.connectivity();
-        REQUIRE(is_valid(connectivity,
-                         StencilManager::instance()
-                           .getCellToCellStencilArray(connectivity,
-                                                      StencilDescriptor{1, StencilDescriptor::Type::by_nodes})));
+        REQUIRE(
+          is_valid(connectivity,
+                   StencilManager::instance()
+                     .getCellToCellStencilArray(connectivity,
+                                                StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes})));
       }
 
       SECTION("hybrid")
@@ -126,10 +129,11 @@ TEST_CASE("StencilBuilder", "[mesh]")
         const auto& mesh = *MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<3>>();
 
         const Connectivity<3>& connectivity = mesh.connectivity();
-        REQUIRE(is_valid(connectivity,
-                         StencilManager::instance()
-                           .getCellToCellStencilArray(connectivity,
-                                                      StencilDescriptor{1, StencilDescriptor::Type::by_nodes})));
+        REQUIRE(
+          is_valid(connectivity,
+                   StencilManager::instance()
+                     .getCellToCellStencilArray(connectivity,
+                                                StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes})));
       }
     }
   }
@@ -223,6 +227,44 @@ TEST_CASE("StencilBuilder", "[mesh]")
       return is_valid;
     };
 
+    SECTION("1D")
+    {
+      StencilManager::BoundaryDescriptorList list;
+      list.emplace_back(std::make_shared<NamedBoundaryDescriptor>("XMIN"));
+      list.emplace_back(std::make_shared<NamedBoundaryDescriptor>("XMAX"));
+
+      SECTION("cartesian")
+      {
+        const auto& mesh = *MeshDataBaseForTests::get().cartesian1DMesh()->get<Mesh<1>>();
+
+        const Connectivity<1>& connectivity = mesh.connectivity();
+
+        auto stencil_array =
+          StencilManager::instance()
+            .getCellToCellStencilArray(connectivity, StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes},
+                                       list);
+
+        REQUIRE(stencil_array.symmetryBoundaryStencilArrayList().size() == 2);
+        REQUIRE(check_ghost_cells_have_empty_stencils(stencil_array, connectivity));
+        REQUIRE(symmetry_stencils_are_valid(stencil_array, mesh));
+      }
+
+      SECTION("hybrid")
+      {
+        const auto& mesh = *MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<1>>();
+
+        const Connectivity<1>& connectivity = mesh.connectivity();
+        auto stencil =
+          StencilManager::instance()
+            .getCellToCellStencilArray(connectivity, StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes},
+                                       list);
+
+        REQUIRE(stencil.symmetryBoundaryStencilArrayList().size() == 2);
+        REQUIRE(check_ghost_cells_have_empty_stencils(stencil, connectivity));
+        REQUIRE(symmetry_stencils_are_valid(stencil, mesh));
+      }
+    }
+
     SECTION("2D")
     {
       StencilManager::BoundaryDescriptorList list;
@@ -238,9 +280,9 @@ TEST_CASE("StencilBuilder", "[mesh]")
         const Connectivity<2>& connectivity = mesh.connectivity();
 
         auto stencil_array =
-          StencilManager::instance().getCellToCellStencilArray(connectivity,
-                                                               StencilDescriptor{1, StencilDescriptor::Type::by_nodes},
-                                                               list);
+          StencilManager::instance()
+            .getCellToCellStencilArray(connectivity, StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes},
+                                       list);
 
         REQUIRE(stencil_array.symmetryBoundaryStencilArrayList().size() == 4);
         REQUIRE(check_ghost_cells_have_empty_stencils(stencil_array, connectivity));
@@ -253,9 +295,9 @@ TEST_CASE("StencilBuilder", "[mesh]")
 
         const Connectivity<2>& connectivity = mesh.connectivity();
         auto stencil =
-          StencilManager::instance().getCellToCellStencilArray(connectivity,
-                                                               StencilDescriptor{1, StencilDescriptor::Type::by_nodes},
-                                                               list);
+          StencilManager::instance()
+            .getCellToCellStencilArray(connectivity, StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes},
+                                       list);
 
         REQUIRE(stencil.symmetryBoundaryStencilArrayList().size() == 4);
         REQUIRE(check_ghost_cells_have_empty_stencils(stencil, connectivity));
@@ -279,9 +321,9 @@ TEST_CASE("StencilBuilder", "[mesh]")
 
         const Connectivity<3>& connectivity = mesh.connectivity();
         auto stencil =
-          StencilManager::instance().getCellToCellStencilArray(connectivity,
-                                                               StencilDescriptor{1, StencilDescriptor::Type::by_nodes},
-                                                               list);
+          StencilManager::instance()
+            .getCellToCellStencilArray(connectivity, StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes},
+                                       list);
 
         REQUIRE(stencil.symmetryBoundaryStencilArrayList().size() == 6);
         REQUIRE(check_ghost_cells_have_empty_stencils(stencil, connectivity));
@@ -294,9 +336,9 @@ TEST_CASE("StencilBuilder", "[mesh]")
 
         const Connectivity<3>& connectivity = mesh.connectivity();
         auto stencil =
-          StencilManager::instance().getCellToCellStencilArray(connectivity,
-                                                               StencilDescriptor{1, StencilDescriptor::Type::by_nodes},
-                                                               list);
+          StencilManager::instance()
+            .getCellToCellStencilArray(connectivity, StencilDescriptor{1, StencilDescriptor::ConnectionType::by_nodes},
+                                       list);
 
         REQUIRE(stencil.symmetryBoundaryStencilArrayList().size() == 6);
         REQUIRE(check_ghost_cells_have_empty_stencils(stencil, connectivity));
-- 
GitLab