From b417f2c678a5cf8476fef4c12877fee9631ee409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com> Date: Fri, 11 Oct 2024 19:38:09 +0200 Subject: [PATCH] Add a (first?) stencil descriptor and prepare other kinds of stencils --- src/mesh/StencilArray.hpp | 2 + src/mesh/StencilBuilder.cpp | 14 +++--- src/mesh/StencilBuilder.hpp | 3 +- src/mesh/StencilDescriptor.hpp | 62 +++++++++++++++++++++++++ src/mesh/StencilManager.cpp | 60 +++++++++++++++--------- src/mesh/StencilManager.hpp | 31 ++++++++++--- src/scheme/PolynomialReconstruction.cpp | 5 +- tests/test_StencilBuilder.cpp | 48 +++++++++++++++---- 8 files changed, 177 insertions(+), 48 deletions(-) create mode 100644 src/mesh/StencilDescriptor.hpp diff --git a/src/mesh/StencilArray.hpp b/src/mesh/StencilArray.hpp index d1b35def0..273e38445 100644 --- a/src/mesh/StencilArray.hpp +++ b/src/mesh/StencilArray.hpp @@ -99,5 +99,7 @@ class StencilArray }; using CellToCellStencilArray = StencilArray<ItemType::cell, ItemType::cell>; +using CellToFaceStencilArray = StencilArray<ItemType::cell, ItemType::face>; +using NodeToCellStencilArray = StencilArray<ItemType::cell, ItemType::node>; #endif // STENCIL_ARRAY_HPP diff --git a/src/mesh/StencilBuilder.cpp b/src/mesh/StencilBuilder.cpp index 920dad9e2..350492419 100644 --- a/src/mesh/StencilBuilder.cpp +++ b/src/mesh/StencilBuilder.cpp @@ -335,21 +335,21 @@ StencilBuilder::_build(const ConnectivityType& connectivity, CellToCellStencilArray StencilBuilder::build(const IConnectivity& connectivity, - size_t number_of_layers, + const StencilDescriptor& stencil_descriptor, const BoundaryDescriptorList& symmetry_boundary_descriptor_list) const { switch (connectivity.dimension()) { case 1: { - return StencilBuilder::_build(dynamic_cast<const Connectivity<1>&>(connectivity), number_of_layers, - symmetry_boundary_descriptor_list); + return StencilBuilder::_build(dynamic_cast<const Connectivity<1>&>(connectivity), + stencil_descriptor.numberOfLayers(), symmetry_boundary_descriptor_list); } case 2: { - return StencilBuilder::_build(dynamic_cast<const Connectivity<2>&>(connectivity), number_of_layers, - symmetry_boundary_descriptor_list); + return StencilBuilder::_build(dynamic_cast<const Connectivity<2>&>(connectivity), + stencil_descriptor.numberOfLayers(), symmetry_boundary_descriptor_list); } case 3: { - return StencilBuilder::_build(dynamic_cast<const Connectivity<3>&>(connectivity), number_of_layers, - symmetry_boundary_descriptor_list); + return StencilBuilder::_build(dynamic_cast<const Connectivity<3>&>(connectivity), + stencil_descriptor.numberOfLayers(), symmetry_boundary_descriptor_list); } default: { throw UnexpectedError("invalid connectivity dimension"); diff --git a/src/mesh/StencilBuilder.hpp b/src/mesh/StencilBuilder.hpp index aaf5076f1..8b0cc09d1 100644 --- a/src/mesh/StencilBuilder.hpp +++ b/src/mesh/StencilBuilder.hpp @@ -3,6 +3,7 @@ #include <mesh/IBoundaryDescriptor.hpp> #include <mesh/StencilArray.hpp> +#include <mesh/StencilDescriptor.hpp> #include <string> #include <vector> @@ -28,7 +29,7 @@ class StencilBuilder friend class StencilManager; CellToCellStencilArray build(const IConnectivity& connectivity, - size_t number_of_layers, + const StencilDescriptor& stencil_descriptor, const BoundaryDescriptorList& symmetry_boundary_descriptor_list) const; public: diff --git a/src/mesh/StencilDescriptor.hpp b/src/mesh/StencilDescriptor.hpp new file mode 100644 index 000000000..8dfffd3e5 --- /dev/null +++ b/src/mesh/StencilDescriptor.hpp @@ -0,0 +1,62 @@ +#ifndef STENCIL_DESCRIPTOR_HPP +#define STENCIL_DESCRIPTOR_HPP + +#include <utils/PugsMacros.hpp> + +#include <cstddef> + +class StencilDescriptor +{ + public: + enum class Type : int + { + by_nodes = 1, + by_edges = 2, + by_faces = 3 + }; + + private: + size_t m_number_of_layers; + Type m_type; + + public: + PUGS_INLINE + const size_t& + numberOfLayers() const + { + return m_number_of_layers; + }; + + PUGS_INLINE + const Type& + type() const + { + return m_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); + } + + PUGS_INLINE + friend bool + operator!=(const StencilDescriptor& sd0, const StencilDescriptor& sd1) + { + 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() : m_number_of_layers(1), m_type{Type::by_nodes} {}; + + StencilDescriptor(const StencilDescriptor&) = default; + StencilDescriptor(StencilDescriptor&&) = default; + + ~StencilDescriptor() = default; +}; + +#endif // STENCIL_DESCRIPTOR_HPP diff --git a/src/mesh/StencilManager.cpp b/src/mesh/StencilManager.cpp index ed1f9ef76..6de72c08a 100644 --- a/src/mesh/StencilManager.cpp +++ b/src/mesh/StencilManager.cpp @@ -18,46 +18,60 @@ StencilManager::destroy() Assert(m_instance != nullptr, "StencilManager was not created"); // LCOV_EXCL_START - if (m_instance->m_stored_cell_to_cell_stencil_map.size() > 0) { - std::stringstream error; - error << ": some connectivities are still registered\n"; - for (const auto& [key, stencil_p] : m_instance->m_stored_cell_to_cell_stencil_map) { - error << " - connectivity of id " << rang::fgB::magenta << key.connectivity_id << rang::style::reset << '\n'; + auto check_still_registered = [](auto& stored_stencil_map) { + if (stored_stencil_map.size() > 0) { + std::stringstream error; + error << ": some connectivities are still registered\n"; + for (const auto& [key, stencil_p] : stored_stencil_map) { + error << " - connectivity of id " << rang::fgB::magenta << key.connectivity_id << rang::style::reset << '\n'; + } + throw UnexpectedError(error.str()); } - throw UnexpectedError(error.str()); - // LCOV_EXCL_STOP - } + }; + + check_still_registered(m_instance->m_stored_cell_to_cell_stencil_map); + check_still_registered(m_instance->m_stored_cell_to_face_stencil_map); + check_still_registered(m_instance->m_stored_node_to_cell_stencil_map); + // LCOV_EXCL_STOP + delete m_instance; m_instance = nullptr; } const CellToCellStencilArray& StencilManager::getCellToCellStencilArray(const IConnectivity& connectivity, - size_t degree, + const StencilDescriptor& stencil_descriptor, const BoundaryDescriptorList& symmetry_boundary_descriptor_list) { if (not m_stored_cell_to_cell_stencil_map.contains( - Key{connectivity.id(), degree, symmetry_boundary_descriptor_list})) { - m_stored_cell_to_cell_stencil_map[Key{connectivity.id(), degree, symmetry_boundary_descriptor_list}] = + Key{connectivity.id(), stencil_descriptor, symmetry_boundary_descriptor_list})) { + m_stored_cell_to_cell_stencil_map[Key{connectivity.id(), stencil_descriptor, symmetry_boundary_descriptor_list}] = std::make_shared<CellToCellStencilArray>( - StencilBuilder{}.build(connectivity, degree, symmetry_boundary_descriptor_list)); + StencilBuilder{}.build(connectivity, stencil_descriptor, symmetry_boundary_descriptor_list)); } - return *m_stored_cell_to_cell_stencil_map.at(Key{connectivity.id(), degree, symmetry_boundary_descriptor_list}); + return *m_stored_cell_to_cell_stencil_map.at( + Key{connectivity.id(), stencil_descriptor, symmetry_boundary_descriptor_list}); } void StencilManager::deleteConnectivity(const size_t connectivity_id) { - bool has_removed = false; - do { - has_removed = false; - for (const auto& [key, p_stencil] : m_stored_cell_to_cell_stencil_map) { - if (connectivity_id == key.connectivity_id) { - m_stored_cell_to_cell_stencil_map.erase(key); - has_removed = true; - break; + auto delete_connectivity_stencil = [&connectivity_id](auto& stored_stencil_map) { + bool has_removed = false; + do { + has_removed = false; + for (const auto& [key, p_stencil] : stored_stencil_map) { + if (connectivity_id == key.connectivity_id) { + stored_stencil_map.erase(key); + has_removed = true; + break; + } } - } - } while (has_removed); + } while (has_removed); + }; + + delete_connectivity_stencil(m_stored_cell_to_cell_stencil_map); + delete_connectivity_stencil(m_stored_cell_to_face_stencil_map); + delete_connectivity_stencil(m_stored_node_to_cell_stencil_map); } diff --git a/src/mesh/StencilManager.hpp b/src/mesh/StencilManager.hpp index de0007631..6deb86536 100644 --- a/src/mesh/StencilManager.hpp +++ b/src/mesh/StencilManager.hpp @@ -4,6 +4,7 @@ #include <mesh/IBoundaryDescriptor.hpp> #include <mesh/IConnectivity.hpp> #include <mesh/StencilArray.hpp> +#include <mesh/StencilDescriptor.hpp> #include <memory> #include <set> @@ -24,13 +25,13 @@ class StencilManager struct Key { size_t connectivity_id; - size_t degree; + StencilDescriptor stencil_descriptor; BoundaryDescriptorList symmetry_boundary_descriptor_list; PUGS_INLINE bool operator==(const Key& k) const { - if ((connectivity_id != k.connectivity_id) or (degree != k.degree) or + if ((connectivity_id != k.connectivity_id) or (stencil_descriptor != k.stencil_descriptor) or (symmetry_boundary_descriptor_list.size() != k.symmetry_boundary_descriptor_list.size())) { return false; } @@ -57,12 +58,20 @@ class StencilManager 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); + return ((std::hash<decltype(Key::connectivity_id)>()(key.connectivity_id)) ^ + (std::hash<std::decay_t<decltype(Key::stencil_descriptor.numberOfLayers())>>()( + key.stencil_descriptor.numberOfLayers()) + << 1)); } }; - std::unordered_map<Key, std::shared_ptr<const CellToCellStencilArray>, HashKey> m_stored_cell_to_cell_stencil_map; + template <ItemType source_item_type, ItemType target_item_type> + using StoredStencilTMap = + std::unordered_map<Key, std::shared_ptr<const StencilArray<source_item_type, target_item_type>>, HashKey>; + + StoredStencilTMap<ItemType::cell, ItemType::cell> m_stored_cell_to_cell_stencil_map; + StoredStencilTMap<ItemType::cell, ItemType::face> m_stored_cell_to_face_stencil_map; + StoredStencilTMap<ItemType::node, ItemType::cell> m_stored_node_to_cell_stencil_map; public: static void create(); @@ -80,7 +89,17 @@ class StencilManager const CellToCellStencilArray& getCellToCellStencilArray( const IConnectivity& i_connectivity, - size_t degree = 1, + const StencilDescriptor& stencil_descriptor, + const BoundaryDescriptorList& symmetry_boundary_descriptor_list = {}); + + const CellToFaceStencilArray& getCellToFaceStencilArray( + const IConnectivity& i_connectivity, + const StencilDescriptor& stencil_descriptor, + const BoundaryDescriptorList& symmetry_boundary_descriptor_list = {}); + + const NodeToCellStencilArray& getNodeToCellStencilArray( + const IConnectivity& i_connectivity, + const StencilDescriptor& stencil_descriptor, const BoundaryDescriptorList& symmetry_boundary_descriptor_list = {}); StencilManager(const StencilManager&) = delete; diff --git a/src/scheme/PolynomialReconstruction.cpp b/src/scheme/PolynomialReconstruction.cpp index 82f5081a7..76d27b500 100644 --- a/src/scheme/PolynomialReconstruction.cpp +++ b/src/scheme/PolynomialReconstruction.cpp @@ -19,6 +19,7 @@ #include <mesh/MeshDataManager.hpp> #include <mesh/MeshFlatFaceBoundary.hpp> #include <mesh/NamedBoundaryDescriptor.hpp> +#include <mesh/StencilDescriptor.hpp> #include <mesh/StencilManager.hpp> #include <scheme/DiscreteFunctionDPkVariant.hpp> #include <scheme/DiscreteFunctionUtils.hpp> @@ -770,7 +771,9 @@ PolynomialReconstruction::_build( DiscreteFunctionDPk<MeshType::Dimension, double>::BasisViewType::dimensionFromDegree(m_descriptor.degree()); const auto& stencil_array = - StencilManager::instance().getCellToCellStencilArray(mesh.connectivity(), m_descriptor.degree(), + StencilManager::instance().getCellToCellStencilArray(mesh.connectivity(), + StencilDescriptor{m_descriptor.degree(), + StencilDescriptor::Type::by_nodes}, m_descriptor.symmetryBoundaryDescriptorList()); auto xr = mesh.xr(); diff --git a/tests/test_StencilBuilder.cpp b/tests/test_StencilBuilder.cpp index b68f0883d..b8c6387e1 100644 --- a/tests/test_StencilBuilder.cpp +++ b/tests/test_StencilBuilder.cpp @@ -63,7 +63,9 @@ TEST_CASE("StencilBuilder", "[mesh]") const Connectivity<1>& connectivity = mesh.connectivity(); - auto stencil_array = StencilManager::instance().getCellToCellStencilArray(connectivity); + auto stencil_array = + StencilManager::instance().getCellToCellStencilArray(connectivity, + StencilDescriptor{1, StencilDescriptor::Type::by_nodes}); REQUIRE(is_valid(connectivity, stencil_array)); } @@ -73,7 +75,9 @@ TEST_CASE("StencilBuilder", "[mesh]") const auto& mesh = *MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<1>>(); const Connectivity<1>& connectivity = mesh.connectivity(); - auto stencil_array = StencilManager::instance().getCellToCellStencilArray(connectivity); + auto stencil_array = + StencilManager::instance().getCellToCellStencilArray(connectivity, + StencilDescriptor{1, StencilDescriptor::Type::by_nodes}); REQUIRE(is_valid(connectivity, stencil_array)); } @@ -86,7 +90,10 @@ 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))); + REQUIRE(is_valid(connectivity, + StencilManager::instance() + .getCellToCellStencilArray(connectivity, + StencilDescriptor{1, StencilDescriptor::Type::by_nodes}))); } SECTION("hybrid") @@ -94,7 +101,10 @@ 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))); + REQUIRE(is_valid(connectivity, + StencilManager::instance() + .getCellToCellStencilArray(connectivity, + StencilDescriptor{1, StencilDescriptor::Type::by_nodes}))); } } @@ -105,7 +115,10 @@ 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))); + REQUIRE(is_valid(connectivity, + StencilManager::instance() + .getCellToCellStencilArray(connectivity, + StencilDescriptor{1, StencilDescriptor::Type::by_nodes}))); } SECTION("hybrid") @@ -113,7 +126,10 @@ 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))); + REQUIRE(is_valid(connectivity, + StencilManager::instance() + .getCellToCellStencilArray(connectivity, + StencilDescriptor{1, StencilDescriptor::Type::by_nodes}))); } } } @@ -221,7 +237,10 @@ TEST_CASE("StencilBuilder", "[mesh]") const Connectivity<2>& connectivity = mesh.connectivity(); - auto stencil_array = StencilManager::instance().getCellToCellStencilArray(connectivity, 1, list); + auto stencil_array = + StencilManager::instance().getCellToCellStencilArray(connectivity, + StencilDescriptor{1, StencilDescriptor::Type::by_nodes}, + list); REQUIRE(stencil_array.symmetryBoundaryStencilArrayList().size() == 4); REQUIRE(check_ghost_cells_have_empty_stencils(stencil_array, connectivity)); @@ -233,7 +252,10 @@ TEST_CASE("StencilBuilder", "[mesh]") const auto& mesh = *MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<2>>(); const Connectivity<2>& connectivity = mesh.connectivity(); - auto stencil = StencilManager::instance().getCellToCellStencilArray(connectivity, 1, list); + auto stencil = + StencilManager::instance().getCellToCellStencilArray(connectivity, + StencilDescriptor{1, StencilDescriptor::Type::by_nodes}, + list); REQUIRE(stencil.symmetryBoundaryStencilArrayList().size() == 4); REQUIRE(check_ghost_cells_have_empty_stencils(stencil, connectivity)); @@ -256,7 +278,10 @@ TEST_CASE("StencilBuilder", "[mesh]") const auto& mesh = *MeshDataBaseForTests::get().cartesian3DMesh()->get<Mesh<3>>(); const Connectivity<3>& connectivity = mesh.connectivity(); - auto stencil = StencilManager::instance().getCellToCellStencilArray(connectivity, 1, list); + auto stencil = + StencilManager::instance().getCellToCellStencilArray(connectivity, + StencilDescriptor{1, StencilDescriptor::Type::by_nodes}, + list); REQUIRE(stencil.symmetryBoundaryStencilArrayList().size() == 6); REQUIRE(check_ghost_cells_have_empty_stencils(stencil, connectivity)); @@ -268,7 +293,10 @@ TEST_CASE("StencilBuilder", "[mesh]") const auto& mesh = *MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<3>>(); const Connectivity<3>& connectivity = mesh.connectivity(); - auto stencil = StencilManager::instance().getCellToCellStencilArray(connectivity, 1, list); + auto stencil = + StencilManager::instance().getCellToCellStencilArray(connectivity, + StencilDescriptor{1, StencilDescriptor::Type::by_nodes}, + list); REQUIRE(stencil.symmetryBoundaryStencilArrayList().size() == 6); REQUIRE(check_ghost_cells_have_empty_stencils(stencil, connectivity)); -- GitLab