diff --git a/src/mesh/StencilArray.hpp b/src/mesh/StencilArray.hpp index d1b35def0fc92c19af436cd192eeab7fae846444..273e38445c2bd76d7f684a90dbc0866b792117bd 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 920dad9e248ef97c2f995cabbc72cff6a24aac7e..350492419db550e28293eeb913f7818777ddf210 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 aaf5076f15cca27b4d199b1b5772dcb573478b31..8b0cc09d1d599811a99f2f64e9c49665e736d941 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 0000000000000000000000000000000000000000..8dfffd3e5f1c6acdd190d7602d211830dc65f537 --- /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 ed1f9ef76ae69937f8c188c9b848d08d3b1dde5c..6de72c08a7fa35ce74cac9cf8a80a66a1fc86a08 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 de0007631dc6a7b0d788cdd1f635275fa35b64e5..6deb86536aab7969fd4dcd16a11130912970bade 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 82f5081a772dd39cc814436b9adace162a670a9e..76d27b5008d373a72df50a8e9d371a52cc750f37 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 b68f0883d2319fe61a4e42db7bd57bfab59d877f..b8c6387e17e35d4c1a593b24e304e74cf18472d9 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));