diff --git a/src/mesh/Stencil.hpp b/src/mesh/Stencil.hpp index d67aa09ed03252b5085c9238d4e968c5947c2678..5dc20dc326fe0ebc716df1b85fb766f50cc790e0 100644 --- a/src/mesh/Stencil.hpp +++ b/src/mesh/Stencil.hpp @@ -8,8 +8,17 @@ class Stencil { private: ConnectivityMatrix m_stencil; +#warning TEMPORARY IMPLEMENTATION + std::vector<std::pair<std::string, ConnectivityMatrix>> m_symmetry_name_stencil; public: + PUGS_INLINE + const auto& + symmetryNameStencil() const + { + return m_symmetry_name_stencil; + } + PUGS_INLINE auto operator[](CellId cell_id) const @@ -17,7 +26,10 @@ class Stencil return m_stencil[cell_id]; } - Stencil(const ConnectivityMatrix& stencil) : m_stencil(stencil) {} + Stencil(const ConnectivityMatrix& stencil, + const std::vector<std::pair<std::string, ConnectivityMatrix>>& symmetry_name_stencil) + : m_stencil{stencil}, m_symmetry_name_stencil{symmetry_name_stencil} + {} Stencil(const Stencil&) = default; Stencil(Stencil&&) = default; ~Stencil() = default; diff --git a/src/mesh/StencilBuilder.cpp b/src/mesh/StencilBuilder.cpp index 34015395ae6d57c5e0c2850333ad90ef65211ef1..92738a6432fcaf5e86a5e1a5c9cd1d5f467b053d 100644 --- a/src/mesh/StencilBuilder.cpp +++ b/src/mesh/StencilBuilder.cpp @@ -1,6 +1,7 @@ #include <mesh/Connectivity.hpp> #include <mesh/StencilBuilder.hpp> +#include <mesh/ItemArray.hpp> #include <utils/Messenger.hpp> #warning remove after rework @@ -109,91 +110,238 @@ StencilBuilder::_getColumnIndices(const ConnectivityType& connectivity, const Ar template <typename ConnectivityType> Stencil -StencilBuilder::_build(const ConnectivityType& connectivity, size_t number_of_layers) const +StencilBuilder::_build(const ConnectivityType& connectivity, + size_t number_of_layers, + const std::set<std::string>& symmetry_boundary_names) const { - if (number_of_layers == 1) { - Array<const uint32_t> row_map = this->_getRowMap(connectivity); - Array<const uint32_t> column_indices = this->_getColumnIndices(connectivity, row_map); - - return ConnectivityMatrix{row_map, column_indices}; - } else { - if (number_of_layers > 2) { - throw NotImplementedError("number of layers too large"); - } - if (parallel::size() > 1) { - throw NotImplementedError("stencils with more than 1 layers are not defined in parallel"); - } +#warning TEMPORARY + if (symmetry_boundary_names.size() == 0) { + if (number_of_layers == 1) { + Array<const uint32_t> row_map = this->_getRowMap(connectivity); + Array<const uint32_t> column_indices = this->_getColumnIndices(connectivity, row_map); + + return {ConnectivityMatrix{row_map, column_indices}, {}}; + } else { + if (number_of_layers > 2) { + throw NotImplementedError("number of layers too large"); + } + if (parallel::size() > 1) { + throw NotImplementedError("stencils with more than 1 layers are not defined in parallel"); + } - auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); - auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + 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(); + auto cell_is_owned = connectivity.cellIsOwned(); + auto cell_number = connectivity.cellNumber(); - Array<uint32_t> row_map{connectivity.numberOfCells() + 1}; - row_map[0] = 0; + Array<uint32_t> row_map{connectivity.numberOfCells() + 1}; + row_map[0] = 0; - std::vector<CellId> column_indices_vector; + std::vector<CellId> column_indices_vector; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - if (cell_is_owned[cell_id]) { - std::set<CellId, std::function<bool(CellId, CellId)>> cell_set( - [=](CellId cell_0, CellId cell_1) { return cell_number[cell_0] < cell_number[cell_1]; }); + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + if (cell_is_owned[cell_id]) { + std::set<CellId, std::function<bool(CellId, CellId)>> cell_set( + [=](CellId cell_0, CellId cell_1) { return cell_number[cell_0] < cell_number[cell_1]; }); - for (size_t i_node_1 = 0; i_node_1 < cell_to_node_matrix[cell_id].size(); ++i_node_1) { - const NodeId layer_1_node_id = cell_to_node_matrix[cell_id][i_node_1]; + for (size_t i_node_1 = 0; i_node_1 < cell_to_node_matrix[cell_id].size(); ++i_node_1) { + const NodeId layer_1_node_id = cell_to_node_matrix[cell_id][i_node_1]; - for (size_t i_cell_1 = 0; i_cell_1 < node_to_cell_matrix[layer_1_node_id].size(); ++i_cell_1) { - CellId cell_1_id = node_to_cell_matrix[layer_1_node_id][i_cell_1]; + for (size_t i_cell_1 = 0; i_cell_1 < node_to_cell_matrix[layer_1_node_id].size(); ++i_cell_1) { + CellId cell_1_id = node_to_cell_matrix[layer_1_node_id][i_cell_1]; - for (size_t i_node_2 = 0; i_node_2 < cell_to_node_matrix[cell_1_id].size(); ++i_node_2) { - const NodeId layer_2_node_id = cell_to_node_matrix[cell_1_id][i_node_2]; + for (size_t i_node_2 = 0; i_node_2 < cell_to_node_matrix[cell_1_id].size(); ++i_node_2) { + const NodeId layer_2_node_id = cell_to_node_matrix[cell_1_id][i_node_2]; - for (size_t i_cell_2 = 0; i_cell_2 < node_to_cell_matrix[layer_2_node_id].size(); ++i_cell_2) { - CellId cell_2_id = node_to_cell_matrix[layer_2_node_id][i_cell_2]; + for (size_t i_cell_2 = 0; i_cell_2 < node_to_cell_matrix[layer_2_node_id].size(); ++i_cell_2) { + CellId cell_2_id = node_to_cell_matrix[layer_2_node_id][i_cell_2]; - if (cell_2_id != cell_id) { - cell_set.insert(cell_2_id); + if (cell_2_id != cell_id) { + cell_set.insert(cell_2_id); + } } } } } - } - for (auto stencil_cell_id : cell_set) { - column_indices_vector.push_back(stencil_cell_id); + for (auto stencil_cell_id : cell_set) { + column_indices_vector.push_back(stencil_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(); } - } - if (row_map[row_map.size() - 1] != column_indices_vector.size()) { - throw UnexpectedError("incorrect stencil size"); - } + if (row_map[row_map.size() - 1] != column_indices_vector.size()) { + throw UnexpectedError("incorrect stencil size"); + } + + Array<uint32_t> column_indices(row_map[row_map.size() - 1]); + column_indices.fill(std::numeric_limits<uint32_t>::max()); - Array<uint32_t> column_indices(row_map[row_map.size() - 1]); - column_indices.fill(std::numeric_limits<uint32_t>::max()); + for (size_t i = 0; i < column_indices.size(); ++i) { + column_indices[i] = column_indices_vector[i]; + } + ConnectivityMatrix primal_stencil{row_map, column_indices}; - for (size_t i = 0; i < column_indices.size(); ++i) { - column_indices[i] = column_indices_vector[i]; + return {primal_stencil, {}}; } + } else { + if constexpr (ConnectivityType::Dimension > 1) { + std::vector<Array<const FaceId>> boundary_node_list; + + NodeArray<bool> symmetry_node_list(connectivity, symmetry_boundary_names.size()); + symmetry_node_list.fill(0); + + auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + + { + size_t i_boundary_name = 0; + for (auto boundary_name : symmetry_boundary_names) { + 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().tagName() == boundary_name) { + 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_boundary_name] = true; + } + } + break; + } + } + ++i_boundary_name; + if (not found) { +#warning IMPROVE ERROR MESSAGE + throw NormalError("cannot find boundary " + boundary_name); + }; + } + } + + auto cell_is_owned = connectivity.cellIsOwned(); + auto cell_number = connectivity.cellNumber(); - return ConnectivityMatrix{row_map, column_indices}; + Array<uint32_t> row_map{connectivity.numberOfCells() + 1}; + row_map[0] = 0; + std::vector<Array<uint32_t>> symmetry_row_map_list(symmetry_boundary_names.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_names.size()); + + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + std::set<CellId> cell_set; + + 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); + } + } + } + row_map[cell_id + 1] = row_map[cell_id] + cell_set.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 (auto&& vector_cell_id : cell_vector) { + column_indices_vector.push_back(vector_cell_id); + } + } + + std::vector<std::set<CellId>> by_boundary_symmetry_cell; + for (size_t i = 0; i < symmetry_boundary_names.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); + } + } + } + symmetry_row_map_list[i][cell_id + 1] = symmetry_row_map_list[i][cell_id] + symmetry_cell_set.size(); + by_boundary_symmetry_cell.emplace_back(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); + } + } + } + } + ConnectivityMatrix primal_stencil{row_map, convert_to_array(column_indices_vector)}; + + std::vector<std::pair<std::string, ConnectivityMatrix>> symmetry_name_stencil; + { + size_t i = 0; + for (auto&& boundary_name : symmetry_boundary_names) { + symmetry_name_stencil.emplace_back( + std::make_pair(boundary_name, ConnectivityMatrix{symmetry_row_map_list[i], + convert_to_array(symmetry_column_indices_vector[i])})); + ++i; + } + } + + return {{primal_stencil}, {symmetry_name_stencil}}; + + } else { + throw NotImplementedError("Only implemented in 2D"); + } } } Stencil -StencilBuilder::build(const IConnectivity& connectivity, size_t number_of_layers) const +StencilBuilder::build(const IConnectivity& connectivity, + size_t number_of_layers, + const std::set<std::string>& symmetry_boundary_names) const { switch (connectivity.dimension()) { case 1: { - return StencilBuilder::_build(dynamic_cast<const Connectivity<1>&>(connectivity), number_of_layers); + return StencilBuilder::_build(dynamic_cast<const Connectivity<1>&>(connectivity), number_of_layers, + symmetry_boundary_names); } case 2: { - return StencilBuilder::_build(dynamic_cast<const Connectivity<2>&>(connectivity), number_of_layers); + return StencilBuilder::_build(dynamic_cast<const Connectivity<2>&>(connectivity), number_of_layers, + symmetry_boundary_names); } case 3: { - return StencilBuilder::_build(dynamic_cast<const Connectivity<3>&>(connectivity), number_of_layers); + return StencilBuilder::_build(dynamic_cast<const Connectivity<3>&>(connectivity), number_of_layers, + symmetry_boundary_names); } default: { throw UnexpectedError("invalid connectivity dimension"); diff --git a/src/mesh/StencilBuilder.hpp b/src/mesh/StencilBuilder.hpp index 53918e64ac9234c396986f2bfef3f90510f287e0..c52933da26b4969410eba7f8aca090842ba9fdc8 100644 --- a/src/mesh/StencilBuilder.hpp +++ b/src/mesh/StencilBuilder.hpp @@ -3,6 +3,9 @@ #include <mesh/Stencil.hpp> +#include <set> +#include <string> + class IConnectivity; class StencilBuilder { @@ -15,10 +18,14 @@ class StencilBuilder const Array<const uint32_t>& row_map) const; template <typename ConnectivityType> - Stencil _build(const ConnectivityType& connectivity, size_t number_of_layers) const; + Stencil _build(const ConnectivityType& connectivity, + size_t number_of_layers, + const std::set<std::string>& symmetry_boundary_names) const; friend class StencilManager; - Stencil build(const IConnectivity& connectivity, size_t number_of_layers) const; + Stencil build(const IConnectivity& connectivity, + size_t number_of_layers, + const std::set<std::string>& symmetry_boundary_names) const; public: StencilBuilder() = default; diff --git a/src/mesh/StencilManager.cpp b/src/mesh/StencilManager.cpp index 120a95e0dfc54a38f9ea7a4ab94bbe4607014981..618431ee75dab1696c4500a306dd70a9f99e1e7f 100644 --- a/src/mesh/StencilManager.cpp +++ b/src/mesh/StencilManager.cpp @@ -32,14 +32,16 @@ StencilManager::destroy() } const Stencil& -StencilManager::getStencil(const IConnectivity& connectivity, size_t degree) +StencilManager::getStencil(const IConnectivity& connectivity, + size_t degree, + const std::set<std::string>& symmetry_boundary_names) { - if (not m_stored_stencil_map.contains(Key{connectivity.id(), degree})) { - m_stored_stencil_map[Key{connectivity.id(), degree}] = - std::make_shared<Stencil>(StencilBuilder{}.build(connectivity, degree)); + if (not m_stored_stencil_map.contains(Key{connectivity.id(), degree, symmetry_boundary_names})) { + m_stored_stencil_map[Key{connectivity.id(), degree, symmetry_boundary_names}] = + std::make_shared<Stencil>(StencilBuilder{}.build(connectivity, degree, symmetry_boundary_names)); } - return *m_stored_stencil_map.at(Key{connectivity.id(), degree}); + return *m_stored_stencil_map.at(Key{connectivity.id(), degree, symmetry_boundary_names}); } void diff --git a/src/mesh/StencilManager.hpp b/src/mesh/StencilManager.hpp index f2912be1fca197aab6b9e010c600de3d8e507827..8199ce5a324a26879ca2c94c05f8871e9e6d7559 100644 --- a/src/mesh/StencilManager.hpp +++ b/src/mesh/StencilManager.hpp @@ -5,6 +5,7 @@ #include <mesh/Stencil.hpp> #include <memory> +#include <set> #include <unordered_map> class StencilManager @@ -19,11 +20,26 @@ class StencilManager { size_t connectivity_id; size_t degree; + std::set<std::string> symmetry_boundary_names; PUGS_INLINE bool operator==(const Key& k) const { - return (connectivity_id == k.connectivity_id) and (degree == k.degree); + if ((connectivity_id != k.connectivity_id) or (degree != k.degree) or + (symmetry_boundary_names.size() != k.symmetry_boundary_names.size())) { + return false; + } + + auto i_name = symmetry_boundary_names.begin(); + auto i_k_name = k.symmetry_boundary_names.begin(); + + for (; i_name != symmetry_boundary_names.end(); ++i_name, ++i_k_name) { + if (*i_name != *i_k_name) { + return false; + } + } + + return true; } }; struct HashKey @@ -31,6 +47,7 @@ class StencilManager size_t operator()(const Key& key) const { + // We do not use the symmetry boundary set by now return (std::hash<decltype(Key::connectivity_id)>()(key.connectivity_id)) ^ (std::hash<decltype(Key::degree)>()(key.degree) << 1); } @@ -52,7 +69,9 @@ class StencilManager void deleteConnectivity(const size_t connectivity_id); - const Stencil& getStencil(const IConnectivity& i_connectivity, size_t degree = 1); + const Stencil& getStencil(const IConnectivity& i_connectivity, + size_t degree = 1, + const std::set<std::string>& symmetry_boundary_names = {}); StencilManager(const StencilManager&) = delete; StencilManager(StencilManager&&) = delete; diff --git a/src/scheme/PolynomialReconstruction.cpp b/src/scheme/PolynomialReconstruction.cpp index 7673255bbb3c3e20266a07a0eb6889998c3ae25e..086583c9f5b5fcca55a9321c00a2f51f13934709 100644 --- a/src/scheme/PolynomialReconstruction.cpp +++ b/src/scheme/PolynomialReconstruction.cpp @@ -17,11 +17,29 @@ #include <geometry/TriangleTransformation.hpp> #include <mesh/MeshData.hpp> #include <mesh/MeshDataManager.hpp> +#include <mesh/MeshFlatFaceBoundary.hpp> +#include <mesh/NamedBoundaryDescriptor.hpp> #include <mesh/StencilManager.hpp> #include <scheme/DiscreteFunctionDPkVariant.hpp> #include <scheme/DiscreteFunctionUtils.hpp> #include <scheme/DiscreteFunctionVariant.hpp> +template <size_t Dimension> +PUGS_INLINE auto +symmetrize_vector(const TinyVector<Dimension>& normal, const TinyVector<Dimension>& u) +{ + return u - 2 * dot(u, normal) * normal; +} + +template <size_t Dimension> +PUGS_INLINE auto +symmetrize_coordinates(const TinyVector<Dimension>& origin, + const TinyVector<Dimension>& normal, + const TinyVector<Dimension>& u) +{ + return u - 2 * dot(u - origin, normal) * normal; +} + class PolynomialReconstruction::MutableDiscreteFunctionDPkVariant { public: @@ -304,6 +322,35 @@ _computeEjkMean(const TinyVector<1>& Xj, } } +template <typename NodeListT> +void +_computeEjkMeanInSymmetricCell(const TinyVector<1>& origin, + const TinyVector<1>& normal, + const TinyVector<1>& Xj, + const NodeValue<const TinyVector<1>>& xr, + const NodeListT& node_list, + const CellType& cell_type, + const double Vi, + const size_t degree, + const size_t basis_dimension, + SmallArray<double>& inv_Vj_wq_detJ_ek, + SmallArray<double>& mean_of_ejk) +{ + if (cell_type == CellType::Line) { + const auto x0 = symmetrize_coordinates(origin, normal, xr[node_list[1]]); + const auto x1 = symmetrize_coordinates(origin, normal, xr[node_list[0]]); + + const LineTransformation<1> T{x0, x1}; + + const auto& quadrature = QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor{degree}); + + _computeEjkMean(quadrature, T, Xj, Vi, degree, basis_dimension, inv_Vj_wq_detJ_ek, mean_of_ejk); + + } else { + throw NotImplementedError("unexpected cell type: " + std::string{name(cell_type)}); + } +} + template <typename ConformTransformationT> void _computeEjkBoundaryMean(const QuadratureFormula<1>& quadrature, @@ -384,6 +431,46 @@ _computeEjkMeanByBoundary(const TinyVector<2>& Xj, } } +void +_computeEjkMeanByBoundaryInSymmetricCell(const TinyVector<2>& origin, + const TinyVector<2>& normal, + const TinyVector<2>& Xj, + const CellId& cell_id, + const NodeValue<const TinyVector<2>>& xr, + const auto& cell_to_face_matrix, + const auto& face_to_node_matrix, + const auto& cell_face_is_reversed, + const CellValue<const double>& Vi, + const size_t degree, + const size_t basis_dimension, + SmallArray<double>& inv_Vj_alpha_p_1_wq_X_prime_orth_ek, + SmallArray<double>& mean_of_ejk) +{ + const auto& quadrature = QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(degree + 1)); + + mean_of_ejk.fill(0); + auto cell_face_list = cell_to_face_matrix[cell_id]; + for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { + bool is_reversed = cell_face_is_reversed[cell_id][i_face]; + + const FaceId face_id = cell_face_list[i_face]; + auto face_node_list = face_to_node_matrix[face_id]; + + const auto x0 = symmetrize_coordinates(origin, normal, xr[face_node_list[1]]); + const auto x1 = symmetrize_coordinates(origin, normal, xr[face_node_list[0]]); + + if (is_reversed) { + const LineTransformation<2> T{x1, x0}; + _computeEjkBoundaryMean(quadrature, T, Xj, Vi[cell_id], degree, basis_dimension, + inv_Vj_alpha_p_1_wq_X_prime_orth_ek, mean_of_ejk); + } else { + const LineTransformation<2> T{x0, x1}; + _computeEjkBoundaryMean(quadrature, T, Xj, Vi[cell_id], degree, basis_dimension, + inv_Vj_alpha_p_1_wq_X_prime_orth_ek, mean_of_ejk); + } + } +} + template <typename NodeListT> void _computeEjkMean(const TinyVector<2>& Xj, @@ -418,6 +505,51 @@ _computeEjkMean(const TinyVector<2>& Xj, } } +template <typename NodeListT> +void +_computeEjkMeanInSymmetricCell(const TinyVector<2>& origin, + const TinyVector<2>& normal, + const TinyVector<2>& Xj, + const NodeValue<const TinyVector<2>>& xr, + const NodeListT& node_list, + const CellType& cell_type, + const double Vi, + const size_t degree, + const size_t basis_dimension, + SmallArray<double>& inv_Vj_wq_detJ_ek, + SmallArray<double>& mean_of_ejk) +{ + switch (cell_type) { + case CellType::Triangle: { + const auto x0 = symmetrize_coordinates(origin, normal, xr[node_list[2]]); + const auto x1 = symmetrize_coordinates(origin, normal, xr[node_list[1]]); + const auto x2 = symmetrize_coordinates(origin, normal, xr[node_list[0]]); + + const TriangleTransformation<2> T{x0, x1, x2}; + const auto& quadrature = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor{degree}); + + _computeEjkMean(quadrature, T, Xj, Vi, degree, basis_dimension, inv_Vj_wq_detJ_ek, mean_of_ejk); + break; + } + case CellType::Quadrangle: { + const auto x0 = symmetrize_coordinates(origin, normal, xr[node_list[3]]); + const auto x1 = symmetrize_coordinates(origin, normal, xr[node_list[2]]); + const auto x2 = symmetrize_coordinates(origin, normal, xr[node_list[1]]); + const auto x3 = symmetrize_coordinates(origin, normal, xr[node_list[0]]); + + const SquareTransformation<2> T{x0, x1, x2, x3}; + const auto& quadrature = + QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor{degree + 1}); + + _computeEjkMean(quadrature, T, Xj, Vi, degree, basis_dimension, inv_Vj_wq_detJ_ek, mean_of_ejk); + break; + } + default: { + throw NotImplementedError("unexpected cell type: " + std::string{name(cell_type)}); + } + } +} + template <typename NodeListT> void _computeEjkMean(const TinyVector<3>& Xj, @@ -467,6 +599,81 @@ _computeEjkMean(const TinyVector<3>& Xj, } } +template <typename NodeListT> +void +_computeEjkMeanInSymmetricCell(const TinyVector<3>& origin, + const TinyVector<3>& normal, + const TinyVector<3>& Xj, + const NodeValue<const TinyVector<3>>& xr, + const NodeListT& node_list, + const CellType& cell_type, + const double Vi, + const size_t degree, + const size_t basis_dimension, + SmallArray<double>& inv_Vj_wq_detJ_ek, + SmallArray<double>& mean_of_ejk) +{ + if (cell_type == CellType::Tetrahedron) { + const auto x0 = symmetrize_coordinates(origin, normal, xr[node_list[1]]); + const auto x1 = symmetrize_coordinates(origin, normal, xr[node_list[0]]); + const auto x2 = symmetrize_coordinates(origin, normal, xr[node_list[2]]); + const auto x3 = symmetrize_coordinates(origin, normal, xr[node_list[3]]); + + const TetrahedronTransformation T{x0, x1, x2, x3}; + + const auto& quadrature = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor{degree}); + + _computeEjkMean(quadrature, T, Xj, Vi, degree, basis_dimension, inv_Vj_wq_detJ_ek, mean_of_ejk); + + } else if (cell_type == CellType::Prism) { + const auto x0 = symmetrize_coordinates(origin, normal, xr[node_list[1]]); + const auto x1 = symmetrize_coordinates(origin, normal, xr[node_list[0]]); + const auto x2 = symmetrize_coordinates(origin, normal, xr[node_list[2]]); + const auto x3 = symmetrize_coordinates(origin, normal, xr[node_list[4]]); + const auto x4 = symmetrize_coordinates(origin, normal, xr[node_list[3]]); + const auto x5 = symmetrize_coordinates(origin, normal, xr[node_list[5]]); + + const PrismTransformation T{x0, x1, x2, // + x3, x4, x5}; + + const auto& quadrature = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor{degree + 1}); + + _computeEjkMean(quadrature, T, Xj, Vi, degree, basis_dimension, inv_Vj_wq_detJ_ek, mean_of_ejk); + + } else if (cell_type == CellType::Pyramid) { + const auto x0 = symmetrize_coordinates(origin, normal, xr[node_list[3]]); + const auto x1 = symmetrize_coordinates(origin, normal, xr[node_list[2]]); + const auto x2 = symmetrize_coordinates(origin, normal, xr[node_list[1]]); + const auto x3 = symmetrize_coordinates(origin, normal, xr[node_list[0]]); + const auto x4 = symmetrize_coordinates(origin, normal, xr[node_list[4]]); + const PyramidTransformation T{x0, x1, x2, x3, x4}; + + const auto& quadrature = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor{degree + 1}); + + _computeEjkMean(quadrature, T, Xj, Vi, degree, basis_dimension, inv_Vj_wq_detJ_ek, mean_of_ejk); + + } else if (cell_type == CellType::Hexahedron) { + const auto x0 = symmetrize_coordinates(origin, normal, xr[node_list[3]]); + const auto x1 = symmetrize_coordinates(origin, normal, xr[node_list[2]]); + const auto x2 = symmetrize_coordinates(origin, normal, xr[node_list[1]]); + const auto x3 = symmetrize_coordinates(origin, normal, xr[node_list[0]]); + const auto x4 = symmetrize_coordinates(origin, normal, xr[node_list[7]]); + const auto x5 = symmetrize_coordinates(origin, normal, xr[node_list[6]]); + const auto x6 = symmetrize_coordinates(origin, normal, xr[node_list[5]]); + const auto x7 = symmetrize_coordinates(origin, normal, xr[node_list[4]]); + + const CubeTransformation T{x0, x1, x2, x3, x4, x5, x6, x7}; + + const auto& quadrature = + QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor{degree + 1}); + + _computeEjkMean(quadrature, T, Xj, Vi, degree, basis_dimension, inv_Vj_wq_detJ_ek, mean_of_ejk); + + } else { + throw NotImplementedError("unexpected cell type: " + std::string{name(cell_type)}); + } +} + size_t PolynomialReconstruction::_getNumberOfColumns( const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list) const @@ -550,7 +757,8 @@ PolynomialReconstruction::_build( const size_t basis_dimension = DiscreteFunctionDPk<MeshType::Dimension, double>::BasisViewType::dimensionFromDegree(m_descriptor.degree()); - const Stencil& stencil = StencilManager::instance().getStencil(mesh.connectivity(), m_descriptor.degree()); + const Stencil& stencil = StencilManager::instance().getStencil(mesh.connectivity(), m_descriptor.degree(), + m_descriptor.symmetryBoundaryNames()); auto xr = mesh.xr(); auto xj = MeshDataManager::instance().getMeshData(mesh).xj(); @@ -561,17 +769,58 @@ PolynomialReconstruction::_build( auto cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); auto cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); + auto full_stencil_size = [&](const CellId cell_id) { + auto stencil_cell_list = stencil[cell_id]; + size_t stencil_size = stencil_cell_list.size(); + for (size_t i = 0; i < m_descriptor.symmetryBoundaryNames().size(); ++i) { + auto& ghost_stencil = stencil.symmetryNameStencil()[i].second; + stencil_size += ghost_stencil[cell_id].size(); + } + + return stencil_size; + }; + const size_t max_stencil_size = [&]() { size_t max_size = 0; for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - auto stencil_cell_list = stencil[cell_id]; - if (cell_is_owned[cell_id] and stencil_cell_list.size() > max_size) { - max_size = stencil_cell_list.size(); + auto stencil_cell_list = stencil[cell_id]; + const size_t stencil_size = full_stencil_size(cell_id); + if (cell_is_owned[cell_id] and stencil_size > max_size) { + max_size = stencil_size; } } return max_size; }(); + SmallArray<const Rd> symmetry_normal_list = [&] { + SmallArray<Rd> normal_list(m_descriptor.symmetryBoundaryNames().size()); + size_t i_symmetry_boundary = 0; + for (auto name : m_descriptor.symmetryBoundaryNames()) { + auto symmetry_boundary = getMeshFlatFaceBoundary(mesh, NamedBoundaryDescriptor(name)); + normal_list[i_symmetry_boundary++] = symmetry_boundary.outgoingNormal(); + } + return normal_list; + }(); + SmallArray<const Rd> symmetry_origin_list = [&] { + SmallArray<Rd> origin_list(m_descriptor.symmetryBoundaryNames().size()); + size_t i_symmetry_boundary = 0; + for (auto name : m_descriptor.symmetryBoundaryNames()) { + auto symmetry_boundary = getMeshFlatFaceBoundary(mesh, NamedBoundaryDescriptor(name)); + origin_list[i_symmetry_boundary++] = symmetry_boundary.origin(); + } + return origin_list; + }(); + { + size_t i_symmetry_boundary = 0; + for (auto name : m_descriptor.symmetryBoundaryNames()) { + auto symmetry_boundary = getMeshFlatFaceBoundary(mesh, NamedBoundaryDescriptor(name)); + std::cout << name << " n=" << symmetry_boundary.outgoingNormal() << " o=" << symmetry_boundary.origin() << '\n'; + ++i_symmetry_boundary; + } + } + std::cout << "symmetry_origin_list = " << symmetry_origin_list << '\n'; + std::cout << "symmetry_normal_list = " << symmetry_normal_list << '\n'; + Kokkos::Experimental::UniqueToken<Kokkos::DefaultExecutionSpace::execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; @@ -611,7 +860,7 @@ PolynomialReconstruction::_build( auto stencil_cell_list = stencil[cell_j_id]; - ShrinkMatrixView B(B_pool[t], stencil_cell_list.size()); + ShrinkMatrixView B(B_pool[t], full_stencil_size(cell_j_id)); size_t column_begin = 0; for (size_t i_discrete_function_variant = 0; @@ -624,19 +873,58 @@ PolynomialReconstruction::_build( if constexpr (is_discrete_function_P0_v<DiscreteFunctionT>) { using DataType = std::decay_t<typename DiscreteFunctionT::data_type>; const DataType& qj = discrete_function[cell_j_id]; - for (size_t i = 0; i < stencil_cell_list.size(); ++i) { + size_t index = 0; + for (size_t i = 0; i < stencil_cell_list.size(); ++i, ++index) { const CellId cell_i_id = stencil_cell_list[i]; const DataType& qi_qj = discrete_function[cell_i_id] - qj; if constexpr (std::is_arithmetic_v<DataType>) { - B(i, column_begin) = qi_qj; + B(index, column_begin) = qi_qj; } else if constexpr (is_tiny_vector_v<DataType>) { for (size_t kB = column_begin, k = 0; k < DataType::Dimension; ++k, ++kB) { - B(i, kB) = qi_qj[k]; + B(index, kB) = qi_qj[k]; } } else if constexpr (is_tiny_matrix_v<DataType>) { for (size_t k = 0; k < DataType::NumberOfRows; ++k) { for (size_t l = 0; l < DataType::NumberOfColumns; ++l) { - B(i, column_begin + k * DataType::NumberOfColumns + l) = qi_qj(k, l); + B(index, column_begin + k * DataType::NumberOfColumns + l) = qi_qj(k, l); + } + } + } + } + + for (size_t i_symmetry = 0; i_symmetry < stencil.symmetryNameStencil().size(); ++i_symmetry) { + auto& ghost_stencil = stencil.symmetryNameStencil()[i_symmetry].second; + auto ghost_cell_list = ghost_stencil[cell_j_id]; + for (size_t i = 0; i < ghost_cell_list.size(); ++i, ++index) { + const CellId cell_i_id = ghost_cell_list[i]; + if constexpr (std::is_arithmetic_v<DataType>) { + const DataType& qi_qj = discrete_function[cell_i_id] - qj; + B(index, column_begin) = qi_qj; + } else if constexpr (is_tiny_vector_v<DataType>) { + if constexpr (DataType::Dimension == MeshType::Dimension) { + const Rd& normal = symmetry_normal_list[i_symmetry]; + + const DataType& qi = discrete_function[cell_i_id]; + const DataType& qi_qj = symmetrize_vector(normal, qi) - qj; + for (size_t kB = column_begin, k = 0; k < DataType::Dimension; ++k, ++kB) { + B(index, kB) = qi_qj[k]; + } + } else { + const DataType& qi_qj = discrete_function[cell_i_id] - qj; + for (size_t kB = column_begin, k = 0; k < DataType::Dimension; ++k, ++kB) { + B(index, kB) = qi_qj[k]; + } + } + } else if constexpr (is_tiny_matrix_v<DataType>) { + if constexpr ((DataType::NumberOfColumns == DataType::NumberOfRows) and + (DataType::NumberOfColumns == MeshType::Dimension)) { + throw NotImplementedError("TinyMatrix symmetries for reconstruction"); + } + const DataType& qi_qj = discrete_function[cell_i_id] - qj; + for (size_t k = 0; k < DataType::NumberOfRows; ++k) { + for (size_t l = 0; l < DataType::NumberOfColumns; ++l) { + B(index, column_begin + k * DataType::NumberOfColumns + l) = qi_qj(k, l); + } } } } @@ -650,12 +938,26 @@ PolynomialReconstruction::_build( } else if constexpr (is_discrete_function_P0_vector_v<DiscreteFunctionT>) { using DataType = std::decay_t<typename DiscreteFunctionT::data_type>; const auto qj_vector = discrete_function[cell_j_id]; - for (size_t l = 0; l < qj_vector.size(); ++l) { - const DataType& qj = qj_vector[l]; - for (size_t i = 0; i < stencil_cell_list.size(); ++i) { - const CellId cell_i_id = stencil_cell_list[i]; - const DataType& qi_qj = discrete_function[cell_i_id][l] - qj; - B(i, column_begin + l) = qi_qj; + size_t index = 0; + for (size_t i = 0; i < stencil_cell_list.size(); ++i, ++index) { + const CellId cell_i_id = stencil_cell_list[i]; + for (size_t l = 0; l < qj_vector.size(); ++l) { + const DataType& qj = qj_vector[l]; + const DataType& qi_qj = discrete_function[cell_i_id][l] - qj; + B(index, column_begin + l) = qi_qj; + } + } + + for (size_t i_symmetry = 0; i_symmetry < stencil.symmetryNameStencil().size(); ++i_symmetry) { + auto& ghost_stencil = stencil.symmetryNameStencil()[i_symmetry].second; + auto ghost_cell_list = ghost_stencil[cell_j_id]; + for (size_t i = 0; i < ghost_cell_list.size(); ++i, ++index) { + const CellId cell_i_id = ghost_cell_list[i]; + for (size_t l = 0; l < qj_vector.size(); ++l) { + const DataType& qj = qj_vector[l]; + const DataType& qi_qj = discrete_function[cell_i_id][l] - qj; + B(index, column_begin + l) = qi_qj; + } } } column_begin += qj_vector.size(); @@ -668,16 +970,32 @@ PolynomialReconstruction::_build( discrete_function_variant->discreteFunction()); } - ShrinkMatrixView A(A_pool[t], stencil_cell_list.size()); + ShrinkMatrixView A(A_pool[t], full_stencil_size(cell_j_id)); if ((m_descriptor.degree() == 1) and (m_descriptor.integrationMethodType() == IntegrationMethodType::cell_center)) { const Rd& Xj = xj[cell_j_id]; - for (size_t i = 0; i < stencil_cell_list.size(); ++i) { + size_t index = 0; + for (size_t i = 0; i < stencil_cell_list.size(); ++i, ++index) { const CellId cell_i_id = stencil_cell_list[i]; const Rd Xi_Xj = xj[cell_i_id] - Xj; for (size_t l = 0; l < basis_dimension - 1; ++l) { - A(i, l) = Xi_Xj[l]; + A(index, l) = Xi_Xj[l]; + } + } + for (size_t i_symmetry = 0; i_symmetry < stencil.symmetryNameStencil().size(); ++i_symmetry) { + auto& ghost_stencil = stencil.symmetryNameStencil()[i_symmetry].second; + auto ghost_cell_list = ghost_stencil[cell_j_id]; + + const Rd& origin = symmetry_origin_list[i_symmetry]; + const Rd& normal = symmetry_normal_list[i_symmetry]; + + for (size_t i = 0; i < ghost_cell_list.size(); ++i, ++index) { + const CellId cell_i_id = ghost_cell_list[i]; + const Rd Xi_Xj = symmetrize_coordinates(origin, normal, xj[cell_i_id]) - Xj; + for (size_t l = 0; l < basis_dimension - 1; ++l) { + A(index, l) = Xi_Xj[l]; + } } } @@ -698,7 +1016,8 @@ PolynomialReconstruction::_build( cell_face_is_reversed, Vj, m_descriptor.degree(), basis_dimension, inv_Vj_alpha_p_1_wq_X_prime_orth_ek, mean_j_of_ejk); - for (size_t i = 0; i < stencil_cell_list.size(); ++i) { + size_t index = 0; + for (size_t i = 0; i < stencil_cell_list.size(); ++i, ++index) { const CellId cell_i_id = stencil_cell_list[i]; _computeEjkMeanByBoundary(Xj, cell_i_id, xr, cell_to_face_matrix, face_to_node_matrix, @@ -706,7 +1025,28 @@ PolynomialReconstruction::_build( inv_Vj_alpha_p_1_wq_X_prime_orth_ek, mean_i_of_ejk); for (size_t l = 0; l < basis_dimension - 1; ++l) { - A(i, l) = mean_i_of_ejk[l] - mean_j_of_ejk[l]; + A(index, l) = mean_i_of_ejk[l] - mean_j_of_ejk[l]; + } + } + for (size_t i_symmetry = 0; i_symmetry < stencil.symmetryNameStencil().size(); ++i_symmetry) { + auto& ghost_stencil = stencil.symmetryNameStencil()[i_symmetry].second; + auto ghost_cell_list = ghost_stencil[cell_j_id]; + + const Rd& origin = symmetry_origin_list[i_symmetry]; + const Rd& normal = symmetry_normal_list[i_symmetry]; + + for (size_t i = 0; i < ghost_cell_list.size(); ++i, ++index) { + const CellId cell_i_id = ghost_cell_list[i]; + + _computeEjkMeanByBoundaryInSymmetricCell(origin, normal, // + Xj, cell_i_id, xr, cell_to_face_matrix, face_to_node_matrix, + cell_face_is_reversed, Vj, m_descriptor.degree(), + basis_dimension, inv_Vj_alpha_p_1_wq_X_prime_orth_ek, + mean_i_of_ejk); + + for (size_t l = 0; l < basis_dimension - 1; ++l) { + A(index, l) = mean_i_of_ejk[l] - mean_j_of_ejk[l]; + } } } } else { @@ -722,14 +1062,35 @@ PolynomialReconstruction::_build( _computeEjkMean(Xj, xr, cell_to_node_matrix[cell_j_id], cell_type[cell_j_id], Vj[cell_j_id], m_descriptor.degree(), basis_dimension, inv_Vj_wq_detJ_ek, mean_j_of_ejk); - for (size_t i = 0; i < stencil_cell_list.size(); ++i) { + size_t index = 0; + for (size_t i = 0; i < stencil_cell_list.size(); ++i, ++index) { const CellId cell_i_id = stencil_cell_list[i]; _computeEjkMean(Xj, xr, cell_to_node_matrix[cell_i_id], cell_type[cell_i_id], Vj[cell_i_id], m_descriptor.degree(), basis_dimension, inv_Vj_wq_detJ_ek, mean_i_of_ejk); for (size_t l = 0; l < basis_dimension - 1; ++l) { - A(i, l) = mean_i_of_ejk[l] - mean_j_of_ejk[l]; + A(index, l) = mean_i_of_ejk[l] - mean_j_of_ejk[l]; + } + } + for (size_t i_symmetry = 0; i_symmetry < stencil.symmetryNameStencil().size(); ++i_symmetry) { + auto& ghost_stencil = stencil.symmetryNameStencil()[i_symmetry].second; + auto ghost_cell_list = ghost_stencil[cell_j_id]; + + const Rd& origin = symmetry_origin_list[i_symmetry]; + const Rd& normal = symmetry_normal_list[i_symmetry]; + + for (size_t i = 0; i < ghost_cell_list.size(); ++i, ++index) { + const CellId cell_i_id = ghost_cell_list[i]; + + _computeEjkMeanInSymmetricCell(origin, normal, // + Xj, xr, cell_to_node_matrix[cell_i_id], cell_type[cell_i_id], + Vj[cell_i_id], m_descriptor.degree(), basis_dimension, inv_Vj_wq_detJ_ek, + mean_i_of_ejk); + + for (size_t l = 0; l < basis_dimension - 1; ++l) { + A(index, l) = mean_i_of_ejk[l] - mean_j_of_ejk[l]; + } } } } diff --git a/src/scheme/PolynomialReconstructionDescriptor.hpp b/src/scheme/PolynomialReconstructionDescriptor.hpp index 1160724c4840d1457d52925b7edd55689cb3523a..9274a7282ac6347fba0166ea40644db1a75090b0 100644 --- a/src/scheme/PolynomialReconstructionDescriptor.hpp +++ b/src/scheme/PolynomialReconstructionDescriptor.hpp @@ -5,6 +5,7 @@ #include <utils/PugsMacros.hpp> #include <cstddef> +#include <set> class PolynomialReconstructionDescriptor { @@ -12,6 +13,9 @@ class PolynomialReconstructionDescriptor private: IntegrationMethodType m_integration_method; size_t m_degree; + + std::set<std::string> m_symmetry_boundary_names; + bool m_preconditioning = true; bool m_row_weighting = true; @@ -29,6 +33,13 @@ class PolynomialReconstructionDescriptor return m_degree; } + PUGS_INLINE + const std::set<std::string>& + symmetryBoundaryNames() const + { + return m_symmetry_boundary_names; + } + PUGS_INLINE bool preconditioning() const @@ -64,8 +75,11 @@ class PolynomialReconstructionDescriptor m_row_weighting = row_weighting; } - PolynomialReconstructionDescriptor(const IntegrationMethodType integration_method, const size_t degree) - : m_integration_method{integration_method}, m_degree{degree} +#warning TEMPORARY + PolynomialReconstructionDescriptor(const IntegrationMethodType integration_method, + const size_t degree, + const std::set<std::string>& symmetry_boundary_names = {}) + : m_integration_method{integration_method}, m_degree{degree}, m_symmetry_boundary_names(symmetry_boundary_names) {} PolynomialReconstructionDescriptor() = delete; diff --git a/src/scheme/test_reconstruction.cpp b/src/scheme/test_reconstruction.cpp index 01007d156bf477df78fd6b814f276ce1c5724012..a17965ac51af42672fca6b583e50acdc0a995d07 100644 --- a/src/scheme/test_reconstruction.cpp +++ b/src/scheme/test_reconstruction.cpp @@ -8,16 +8,11 @@ void test_reconstruction(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list, uint64_t degree) { - std::vector descriptor_list = {PolynomialReconstructionDescriptor{IntegrationMethodType::cell_center, degree}, - PolynomialReconstructionDescriptor{IntegrationMethodType::element, degree}, - PolynomialReconstructionDescriptor{IntegrationMethodType::boundary, degree}}; - - [[maybe_unused]] auto x = - PolynomialReconstruction{PolynomialReconstructionDescriptor{IntegrationMethodType::cell_center, degree}}.build( - discrete_function_variant_list); + std::vector descriptor_list = { + PolynomialReconstructionDescriptor{IntegrationMethodType::boundary, degree, {"XMIN", "XMAX", "YMIN", "YMAX"}}}; for (auto&& descriptor : descriptor_list) { - const size_t nb_loops = 50; + const size_t nb_loops = 1; std::cout << "** variable list at once (" << nb_loops << " times) using " << rang::fgB::yellow << name(descriptor.integrationMethodType()) << rang::fg::reset << "\n"; diff --git a/tests/test_StencilBuilder.cpp b/tests/test_StencilBuilder.cpp index 0cb54f2623541fc97c1ce5058313c4c2f3b2ab5d..54dd9755678bfe5c0128807d6a1f16e65d927e8b 100644 --- a/tests/test_StencilBuilder.cpp +++ b/tests/test_StencilBuilder.cpp @@ -15,101 +15,129 @@ TEST_CASE("StencilBuilder", "[mesh]") { - auto is_valid = [](const auto& connectivity, const Stencil& stencil) { - 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(); - - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - if (cell_is_owned[cell_id]) { - std::set<CellId, std::function<bool(CellId, CellId)>> cell_set( - [=](CellId cell_0, CellId cell_1) { return cell_number[cell_0] < cell_number[cell_1]; }); - auto cell_nodes = cell_to_node_matrix[cell_id]; - for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { - const NodeId node_id = cell_nodes[i_node]; - auto node_cells = node_to_cell_matrix[node_id]; - for (size_t i_node_cell = 0; i_node_cell < node_cells.size(); ++i_node_cell) { - const CellId node_cell_id = node_cells[i_node_cell]; - if (node_cell_id != cell_id) { - cell_set.insert(node_cell_id); + SECTION("inner stencil") + { + auto is_valid = [](const auto& connectivity, const Stencil& stencil) { + 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(); + + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + if (cell_is_owned[cell_id]) { + std::set<CellId, std::function<bool(CellId, CellId)>> cell_set( + [=](CellId cell_0, CellId cell_1) { return cell_number[cell_0] < cell_number[cell_1]; }); + auto cell_nodes = cell_to_node_matrix[cell_id]; + for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { + const NodeId node_id = cell_nodes[i_node]; + auto node_cells = node_to_cell_matrix[node_id]; + for (size_t i_node_cell = 0; i_node_cell < node_cells.size(); ++i_node_cell) { + const CellId node_cell_id = node_cells[i_node_cell]; + if (node_cell_id != cell_id) { + cell_set.insert(node_cell_id); + } } } - } - auto cell_stencil = stencil[cell_id]; + auto cell_stencil = stencil[cell_id]; - auto i_set_cell = cell_set.begin(); - for (size_t index = 0; index < cell_stencil.size(); ++index, ++i_set_cell) { - if (*i_set_cell != cell_stencil[index]) { - return false; + auto i_set_cell = cell_set.begin(); + for (size_t index = 0; index < cell_stencil.size(); ++index, ++i_set_cell) { + if (*i_set_cell != cell_stencil[index]) { + return false; + } } } } - } - return true; - }; + return true; + }; - SECTION("1D") - { - SECTION("cartesian") + SECTION("1D") { - const auto& mesh = *MeshDataBaseForTests::get().cartesian1DMesh()->get<Mesh<1>>(); + SECTION("cartesian") + { + const auto& mesh = *MeshDataBaseForTests::get().cartesian1DMesh()->get<Mesh<1>>(); - const Connectivity<1>& connectivity = mesh.connectivity(); + const Connectivity<1>& connectivity = mesh.connectivity(); - Stencil stencil = StencilManager::instance().getStencil(connectivity); + Stencil stencil = StencilManager::instance().getStencil(connectivity); - REQUIRE(is_valid(connectivity, stencil)); - } + REQUIRE(is_valid(connectivity, stencil)); + } - SECTION("unordered") - { - const auto& mesh = *MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<1>>(); + SECTION("unordered") + { + const auto& mesh = *MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<1>>(); - const Connectivity<1>& connectivity = mesh.connectivity(); - Stencil stencil = StencilManager::instance().getStencil(connectivity); + const Connectivity<1>& connectivity = mesh.connectivity(); + Stencil stencil = StencilManager::instance().getStencil(connectivity); - REQUIRE(is_valid(connectivity, stencil)); + REQUIRE(is_valid(connectivity, stencil)); + } } - } - SECTION("2D") - { - SECTION("cartesian") + SECTION("2D") { - const auto& mesh = *MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<2>>(); + SECTION("cartesian") + { + const auto& mesh = *MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<2>>(); - const Connectivity<2>& connectivity = mesh.connectivity(); - REQUIRE(is_valid(connectivity, StencilManager::instance().getStencil(connectivity))); + const Connectivity<2>& connectivity = mesh.connectivity(); + REQUIRE(is_valid(connectivity, StencilManager::instance().getStencil(connectivity))); + } + + SECTION("hybrid") + { + const auto& mesh = *MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<2>>(); + + const Connectivity<2>& connectivity = mesh.connectivity(); + REQUIRE(is_valid(connectivity, StencilManager::instance().getStencil(connectivity))); + } } - SECTION("hybrid") + SECTION("3D") { - const auto& mesh = *MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<2>>(); + SECTION("carteian") + { + const auto& mesh = *MeshDataBaseForTests::get().cartesian3DMesh()->get<Mesh<3>>(); + + const Connectivity<3>& connectivity = mesh.connectivity(); + REQUIRE(is_valid(connectivity, StencilManager::instance().getStencil(connectivity))); + } + + SECTION("hybrid") + { + const auto& mesh = *MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<3>>(); - const Connectivity<2>& connectivity = mesh.connectivity(); - REQUIRE(is_valid(connectivity, StencilManager::instance().getStencil(connectivity))); + const Connectivity<3>& connectivity = mesh.connectivity(); + REQUIRE(is_valid(connectivity, StencilManager::instance().getStencil(connectivity))); + } } } - SECTION("3D") + SECTION("Stencil using symmetries") { - SECTION("carteian") + SECTION("2D") { - const auto& mesh = *MeshDataBaseForTests::get().cartesian3DMesh()->get<Mesh<3>>(); + SECTION("cartesian") + { + const auto& mesh = *MeshDataBaseForTests::get().cartesian2DMesh()->get<Mesh<2>>(); - const Connectivity<3>& connectivity = mesh.connectivity(); - REQUIRE(is_valid(connectivity, StencilManager::instance().getStencil(connectivity))); + const Connectivity<2>& connectivity = mesh.connectivity(); + StencilManager::instance().getStencil(connectivity, 1, {"XMIN", "XMAX", "YMIN", "YMAX"}); + } } - SECTION("hybrid") + SECTION("3D") { - const auto& mesh = *MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<3>>(); + SECTION("cartesian") + { + const auto& mesh = *MeshDataBaseForTests::get().cartesian3DMesh()->get<Mesh<3>>(); - const Connectivity<3>& connectivity = mesh.connectivity(); - REQUIRE(is_valid(connectivity, StencilManager::instance().getStencil(connectivity))); + const Connectivity<3>& connectivity = mesh.connectivity(); + StencilManager::instance().getStencil(connectivity, 1, {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}); + } } } }