diff --git a/src/language/modules/MeshModule.cpp b/src/language/modules/MeshModule.cpp index da8eb6a69b00159c816b8fa2624071df6104bbab..1bb96c9ac41d1b1fd2bcb85c248fb66aac39d1bf 100644 --- a/src/language/modules/MeshModule.cpp +++ b/src/language/modules/MeshModule.cpp @@ -167,6 +167,37 @@ MeshModule::MeshModule() } )); + + this->_addBuiltinFunction("dual", std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IMesh>( + const std::shared_ptr<const IMesh>&)>>( + + [](const std::shared_ptr<const IMesh>& i_mesh) -> std::shared_ptr<const IMesh> { + switch (i_mesh->dimension()) { + case 1: { + using MeshType = Mesh<Connectivity<1>>; + + std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); + return DualMeshManager::instance().getDualMesh(p_mesh); + } + case 2: { + using MeshType = Mesh<Connectivity<2>>; + + std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); + return DualMeshManager::instance().getDualMesh(p_mesh); + } + case 3: { + using MeshType = Mesh<Connectivity<3>>; + + std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); + return DualMeshManager::instance().getDualMesh(p_mesh); + } + default: { + throw UnexpectedError("invalid dimension"); + } + } + } + + )); } void diff --git a/src/mesh/CMakeLists.txt b/src/mesh/CMakeLists.txt index 8f75c57d649b22f7ee7e63a6fb1af6f24aaefd61..eeef93dd8915ae3f413c27e36c71ae85043d168d 100644 --- a/src/mesh/CMakeLists.txt +++ b/src/mesh/CMakeLists.txt @@ -9,7 +9,9 @@ add_library( ConnectivityDispatcher.cpp DiamondDualConnectivityBuilder.cpp DiamondDualMeshBuilder.cpp + DualConnectivityBuilder.cpp DualConnectivityManager.cpp + DualMeshBuilder.cpp DualMeshManager.cpp GmshReader.cpp IConnectivity.cpp diff --git a/src/mesh/ConnectivityToDualConnectivityDataMapper.hpp b/src/mesh/ConnectivityToDualConnectivityDataMapper.hpp new file mode 100644 index 0000000000000000000000000000000000000000..49f180abb19e1cf1a33943bea1d653a2b30dffc1 --- /dev/null +++ b/src/mesh/ConnectivityToDualConnectivityDataMapper.hpp @@ -0,0 +1,144 @@ +#ifndef CONNECTIVITY_TO_DUAL_CONNECTIVITY_DATA_MAPPER_HPP +#define CONNECTIVITY_TO_DUAL_CONNECTIVITY_DATA_MAPPER_HPP + +#include <mesh/Connectivity.hpp> +#include <mesh/IConnectivityToDualConnectivityDataMapper.hpp> +#include <mesh/ItemIdToItemIdMap.hpp> +#include <mesh/ItemValue.hpp> +#include <utils/Array.hpp> +#include <utils/PugsAssert.hpp> + +template <size_t Dimension> +class ConnectivityToDualConnectivityDataMapper : public IConnectivityToDualConnectivityDataMapper +{ + private: + const IConnectivity* m_primal_connectivity; + const IConnectivity* m_dual_connectivity; + + NodeIdToNodeIdMap m_primal_node_to_dual_node_map; + CellIdToNodeIdMap m_primal_cell_to_dual_node_map; + FaceIdToCellIdMap m_primal_face_to_dual_cell_map; + + public: + template <typename OriginDataType1, typename OriginDataType2, typename DestinationDataType> + void + toDualNode(const NodeValue<OriginDataType1>& primal_node_value, + const CellValue<OriginDataType2>& primal_cell_value, + const NodeValue<DestinationDataType>& dual_node_value) const + { + static_assert(not std::is_const_v<DestinationDataType>, "destination data type must not be constant"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType1>, DestinationDataType>, "incompatible types"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType2>, DestinationDataType>, "incompatible types"); + + Assert(m_primal_connectivity == primal_cell_value.connectivity_ptr().get()); + Assert(m_primal_connectivity == primal_node_value.connectivity_ptr().get()); + Assert(m_dual_connectivity == dual_node_value.connectivity_ptr().get()); + + parallel_for( + m_primal_node_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_node_id, dual_node_id] = m_primal_node_to_dual_node_map[i]; + + dual_node_value[dual_node_id] = primal_node_value[primal_node_id]; + }); + + parallel_for( + m_primal_cell_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_cell_id, dual_node_id] = m_primal_cell_to_dual_node_map[i]; + dual_node_value[dual_node_id] = primal_cell_value[primal_cell_id]; + }); + } + + template <typename OriginDataType, typename DestinationDataType1, typename DestinationDataType2> + void + fromDualNode(const NodeValue<OriginDataType>& dual_node_value, + const NodeValue<DestinationDataType1>& primal_node_value, + const CellValue<DestinationDataType2>& primal_cell_value) const + { + static_assert(not std::is_const_v<DestinationDataType1>, "destination data type must not be constant"); + static_assert(not std::is_const_v<DestinationDataType2>, "destination data type must not be constant"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType>, DestinationDataType1>, "incompatible types"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType>, DestinationDataType2>, "incompatible types"); + + Assert(m_primal_connectivity == primal_cell_value.connectivity_ptr().get()); + Assert(m_primal_connectivity == primal_node_value.connectivity_ptr().get()); + Assert(m_dual_connectivity == dual_node_value.connectivity_ptr().get()); + + parallel_for( + m_primal_node_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_node_id, dual_node_id] = m_primal_node_to_dual_node_map[i]; + + primal_node_value[primal_node_id] = dual_node_value[dual_node_id]; + }); + + parallel_for( + m_primal_cell_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_cell_id, dual_node_id] = m_primal_cell_to_dual_node_map[i]; + primal_cell_value[primal_cell_id] = dual_node_value[dual_node_id]; + }); + } + + template <typename OriginDataType, typename DestinationDataType> + void + toDualCell(const FaceValue<OriginDataType>& primal_face_value, + const CellValue<DestinationDataType>& dual_cell_value) const + { + static_assert(not std::is_const_v<DestinationDataType>, "destination data type must not be constant"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType>, DestinationDataType>, "incompatible types"); + + Assert(m_primal_connectivity == primal_face_value.connectivity_ptr().get()); + Assert(m_dual_connectivity == dual_cell_value.connectivity_ptr().get()); + + parallel_for( + m_primal_face_to_dual_cell_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + + dual_cell_value[dual_cell_id] = primal_face_value[primal_face_id]; + }); + + parallel_for( + m_primal_cell_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + + dual_cell_value[dual_cell_id] = primal_face_value[primal_face_id]; + }); + } + + template <typename OriginDataType, typename DestinationDataType> + void + fromDualCell(const CellValue<DestinationDataType>& dual_cell_value, + const FaceValue<OriginDataType>& primal_face_value) const + { + static_assert(not std::is_const_v<DestinationDataType>, "destination data type must not be constant"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType>, DestinationDataType>, "incompatible types"); + + Assert(m_primal_connectivity == primal_face_value.connectivity_ptr().get()); + Assert(m_dual_connectivity == dual_cell_value.connectivity_ptr().get()); + + parallel_for( + m_primal_face_to_dual_cell_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + + primal_face_value[primal_face_id] = dual_cell_value[dual_cell_id]; + }); + + parallel_for( + m_primal_cell_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + primal_face_value[primal_face_id] = dual_cell_value[dual_cell_id]; + }); + } + + ConnectivityToDualConnectivityDataMapper(const Connectivity<Dimension>& primal_connectivity, + const Connectivity<Dimension>& dual_connectivity, + const NodeIdToNodeIdMap& primal_node_to_dual_node_map, + const CellIdToNodeIdMap& primal_cell_to_dual_node_map, + const FaceIdToCellIdMap& primal_face_to_dual_cell_map) + : m_primal_connectivity{&primal_connectivity}, + m_dual_connectivity{&dual_connectivity}, + m_primal_node_to_dual_node_map{primal_node_to_dual_node_map}, + m_primal_cell_to_dual_node_map{primal_cell_to_dual_node_map}, + m_primal_face_to_dual_cell_map{primal_face_to_dual_cell_map} + {} +}; + +#endif // CONNECTIVITY_TO_DUAL_CONNECTIVITY_DATA_MAPPER_HPP diff --git a/src/mesh/DiamondDualMeshBuilder.cpp b/src/mesh/DiamondDualMeshBuilder.cpp index 175aadfa4562f8bb76967a4f26e6ab090c63acaa..6276012f66faf8101a073fcf22e698a6d70fb3ba 100644 --- a/src/mesh/DiamondDualMeshBuilder.cpp +++ b/src/mesh/DiamondDualMeshBuilder.cpp @@ -2,7 +2,6 @@ #include <mesh/Connectivity.hpp> #include <mesh/ConnectivityToDiamondDualConnectivityDataMapper.hpp> -#include <mesh/DiamondDualConnectivityBuilder.hpp> #include <mesh/DualConnectivityManager.hpp> #include <mesh/ItemValueUtils.hpp> #include <mesh/Mesh.hpp> diff --git a/src/mesh/DualConnectivityBuilder.cpp b/src/mesh/DualConnectivityBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77b00b0f1f62bc03f741ac97cb2d77a9565b2226 --- /dev/null +++ b/src/mesh/DualConnectivityBuilder.cpp @@ -0,0 +1,585 @@ +#include <mesh/DualConnectivityBuilder.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityDescriptor.hpp> +#include <mesh/ConnectivityDispatcher.hpp> +#include <mesh/ConnectivityToDualConnectivityDataMapper.hpp> +#include <mesh/ItemValueUtils.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/RefId.hpp> +#include <utils/Array.hpp> +#include <utils/Messenger.hpp> + +#include <vector> + +template <size_t Dimension> +void +DualConnectivityBuilder::_buildConnectivityDescriptor(const Connectivity<Dimension>& primal_connectivity, + ConnectivityDescriptor& dual_descriptor) +{ + const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes(); + const size_t primal_number_of_faces = primal_connectivity.numberOfFaces(); + const size_t primal_number_of_cells = primal_connectivity.numberOfCells(); + + const auto& primal_node_number = primal_connectivity.nodeNumber(); + const auto& primal_cell_number = primal_connectivity.cellNumber(); + + const size_t dual_number_of_nodes = primal_number_of_cells + primal_number_of_nodes; + const size_t dual_number_of_cells = primal_number_of_faces; + + { + m_primal_node_to_dual_node_map = NodeIdToNodeIdMap{primal_number_of_nodes}; + + NodeId dual_node_id = 0; + for (NodeId primal_node_id = 0; primal_node_id < primal_number_of_nodes; ++primal_node_id) { + m_primal_node_to_dual_node_map[primal_node_id] = std::make_pair(primal_node_id, dual_node_id++); + } + + m_primal_cell_to_dual_node_map = CellIdToNodeIdMap{primal_number_of_cells}; + for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { + m_primal_cell_to_dual_node_map[primal_cell_id] = std::make_pair(primal_cell_id, dual_node_id++); + } + } + + dual_descriptor.node_number_vector.resize(dual_number_of_nodes); + + parallel_for(m_primal_node_to_dual_node_map.size(), [&](size_t i) { + const auto [primal_node_id, dual_dual_node_id] = m_primal_node_to_dual_node_map[i]; + + dual_descriptor.node_number_vector[dual_dual_node_id] = primal_node_number[primal_node_id]; + }); + + const size_t cell_number_shift = max(primal_node_number) + 1; + parallel_for(primal_number_of_cells, [&](size_t i) { + const auto [primal_cell_id, dual_dual_node_id] = m_primal_cell_to_dual_node_map[i]; + + dual_descriptor.node_number_vector[dual_dual_node_id] = primal_cell_number[primal_cell_id] + cell_number_shift; + }); + + { + m_primal_face_to_dual_cell_map = FaceIdToCellIdMap{primal_number_of_faces}; + CellId dual_cell_id = 0; + for (FaceId primal_face_id = 0; primal_face_id < primal_number_of_faces; ++primal_face_id) { + m_primal_face_to_dual_cell_map[primal_face_id] = std::make_pair(primal_face_id, dual_cell_id++); + } + } + + dual_descriptor.cell_number_vector.resize(dual_number_of_cells); + const auto& primal_face_number = primal_connectivity.faceNumber(); + parallel_for(dual_number_of_cells, [&](size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + dual_descriptor.cell_number_vector[dual_cell_id] = primal_face_number[primal_face_id]; + }); + + if constexpr (Dimension == 3) { + const size_t number_of_edges = dual_descriptor.edge_to_node_vector.size(); + dual_descriptor.edge_number_vector.resize(number_of_edges); + for (size_t i_edge = 0; i_edge < number_of_edges; ++i_edge) { + dual_descriptor.edge_number_vector[i_edge] = i_edge; + } + if (parallel::size() > 1) { + throw NotImplementedError("parallel edge numbering is undefined"); + } + } + + dual_descriptor.cell_type_vector.resize(dual_number_of_cells); + + const auto& primal_face_to_cell_matrix = primal_connectivity.faceToCellMatrix(); + const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix(); + + static_assert(Dimension > 1); + parallel_for(primal_number_of_faces, [&](FaceId face_id) { + const size_t i_cell = face_id; + const auto& primal_face_cell_list = primal_face_to_cell_matrix[face_id]; + + if constexpr (Dimension == 2) { + if (primal_face_cell_list.size() == 1) { + dual_descriptor.cell_type_vector[i_cell] = CellType::Triangle; + } else { + Assert(primal_face_cell_list.size() == 2); + dual_descriptor.cell_type_vector[i_cell] = CellType::Quadrangle; + } + } else if constexpr (Dimension == 3) { + if (primal_face_cell_list.size() == 1) { + if (primal_face_to_node_matrix[face_id].size() == 3) { + dual_descriptor.cell_type_vector[i_cell] = CellType::Tetrahedron; + } else { + dual_descriptor.cell_type_vector[i_cell] = CellType::Pyramid; + } + } else { + Assert(primal_face_cell_list.size() == 2); + dual_descriptor.cell_type_vector[i_cell] = CellType::Diamond; + } + } + }); + + dual_descriptor.cell_to_node_vector.resize(dual_number_of_cells); + + const auto& primal_face_local_number_in_their_cells = primal_connectivity.faceLocalNumbersInTheirCells(); + const auto& cell_face_is_reversed = primal_connectivity.cellFaceIsReversed(); + parallel_for(primal_number_of_faces, [&](FaceId face_id) { + const size_t& i_dual_cell = face_id; + const auto& primal_face_cell_list = primal_face_to_cell_matrix[face_id]; + const auto& primal_face_node_list = primal_face_to_node_matrix[face_id]; + if (primal_face_cell_list.size() == 1) { + dual_descriptor.cell_to_node_vector[i_dual_cell].resize(primal_face_node_list.size() + 1); + + const CellId cell_id = primal_face_cell_list[0]; + const auto i_face_in_cell = primal_face_local_number_in_their_cells(face_id, 0); + + for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) { + dual_descriptor.cell_to_node_vector[i_dual_cell][i_node] = primal_face_node_list[i_node]; + } + dual_descriptor.cell_to_node_vector[i_dual_cell][primal_face_node_list.size()] = primal_number_of_nodes + cell_id; + + if constexpr (Dimension == 2) { + if (cell_face_is_reversed(cell_id, i_face_in_cell)) { + std::swap(dual_descriptor.cell_to_node_vector[i_dual_cell][0], + dual_descriptor.cell_to_node_vector[i_dual_cell][1]); + } + } else { + if (not cell_face_is_reversed(cell_id, i_face_in_cell)) { + // In 3D the basis of the pyramid is described in the + // indirect way IF the face is not reversed. In other words + // the "topological normal" must point to the "top" of the + // pyramid. + for (size_t i_node = 0; i_node < primal_face_node_list.size() / 2; ++i_node) { + std::swap(dual_descriptor.cell_to_node_vector[i_dual_cell][i_node], + dual_descriptor.cell_to_node_vector[i_dual_cell][primal_face_node_list.size() - 1 - i_node]); + } + } + } + } else { + Assert(primal_face_cell_list.size() == 2); + dual_descriptor.cell_to_node_vector[i_dual_cell].resize(primal_face_node_list.size() + 2); + + const CellId cell0_id = primal_face_cell_list[0]; + const CellId cell1_id = primal_face_cell_list[1]; + const auto i_face_in_cell0 = primal_face_local_number_in_their_cells(face_id, 0); + + if constexpr (Dimension == 2) { + Assert(primal_face_node_list.size() == 2); + dual_descriptor.cell_to_node_vector[i_dual_cell][0] = primal_number_of_nodes + cell0_id; + dual_descriptor.cell_to_node_vector[i_dual_cell][1] = primal_face_node_list[0]; + dual_descriptor.cell_to_node_vector[i_dual_cell][2] = primal_number_of_nodes + cell1_id; + dual_descriptor.cell_to_node_vector[i_dual_cell][3] = primal_face_node_list[1]; + + if (cell_face_is_reversed(cell0_id, i_face_in_cell0)) { + std::swap(dual_descriptor.cell_to_node_vector[i_dual_cell][1], + dual_descriptor.cell_to_node_vector[i_dual_cell][3]); + } + } else { + dual_descriptor.cell_to_node_vector[i_dual_cell][0] = primal_number_of_nodes + cell0_id; + for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) { + dual_descriptor.cell_to_node_vector[i_dual_cell][i_node + 1] = primal_face_node_list[i_node]; + } + dual_descriptor.cell_to_node_vector[i_dual_cell][primal_face_node_list.size() + 1] = + primal_number_of_nodes + cell1_id; + + if (cell_face_is_reversed(cell0_id, i_face_in_cell0)) { + std::swap(dual_descriptor.cell_to_node_vector[i_dual_cell][0], + dual_descriptor.cell_to_node_vector[i_dual_cell][primal_face_node_list.size() + 1]); + } + } + } + }); +} + +template <> +void +DualConnectivityBuilder::_buildConnectivityDescriptor<1>(const Connectivity<1>& primal_connectivity, + ConnectivityDescriptor& dual_descriptor) +{ + const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes(); + const size_t primal_number_of_faces = primal_connectivity.numberOfFaces(); + const size_t primal_number_of_cells = primal_connectivity.numberOfCells(); + + const size_t dual_number_of_nodes = 2 * primal_number_of_nodes - primal_number_of_cells; + + const size_t dual_number_of_cells = primal_number_of_faces; + const size_t number_of_kept_nodes = 2 * (dual_number_of_nodes - dual_number_of_cells); + + const auto& primal_node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); + size_t next_kept_node_id = 0; + + dual_descriptor.node_number_vector.resize(dual_number_of_nodes); + + const auto& primal_node_number = primal_connectivity.nodeNumber(); + + for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { + const auto& primal_node_cell_list = primal_node_to_cell_matrix[primal_node_id]; + if (primal_node_cell_list.size() == 1) { + dual_descriptor.node_number_vector[next_kept_node_id++] = primal_node_number[primal_node_id]; + } + } + + const size_t primal_number_of_kept_nodes = next_kept_node_id; + + const auto& primal_cell_number = primal_connectivity.cellNumber(); + + const size_t cell_number_shift = max(primal_node_number) + 1; + + for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { + dual_descriptor.node_number_vector[primal_number_of_kept_nodes + primal_cell_id] = + primal_cell_number[primal_cell_id] + cell_number_shift; + } + + if (number_of_kept_nodes != next_kept_node_id) { + throw UnexpectedError("unexpected number of kept node" + std::to_string(next_kept_node_id) + + " != " + std::to_string(number_of_kept_nodes)); + } + + dual_descriptor.cell_number_vector.resize(dual_number_of_cells); + + for (NodeId primal_node_id = 0; primal_node_id < primal_number_of_nodes; ++primal_node_id) { + dual_descriptor.cell_number_vector[primal_node_id] = primal_node_number[primal_node_id]; + } + + dual_descriptor.cell_type_vector.resize(dual_number_of_cells); + + for (NodeId node_id = 0; node_id < primal_connectivity.numberOfNodes(); ++node_id) { + const size_t i_cell = node_id; + + dual_descriptor.cell_type_vector[i_cell] = CellType::Line; + } + + dual_descriptor.cell_to_node_vector.resize(dual_number_of_cells); + + const auto& primal_node_local_number_in_their_cells = primal_connectivity.nodeLocalNumbersInTheirCells(); + + { + size_t next_kept_node_id = 0; + for (NodeId i_node = 0; i_node < primal_connectivity.numberOfNodes(); ++i_node) { + const size_t& i_dual_cell = i_node; + const auto& primal_node_cell_list = primal_node_to_cell_matrix[i_node]; + dual_descriptor.cell_to_node_vector[i_dual_cell].resize(2); + if (primal_node_cell_list.size() == 1) { + const auto i_node_in_cell = primal_node_local_number_in_their_cells(i_node, 0); + + dual_descriptor.cell_to_node_vector[i_dual_cell][i_node_in_cell] = next_kept_node_id++; + dual_descriptor.cell_to_node_vector[i_dual_cell][1 - i_node_in_cell] = + number_of_kept_nodes + primal_node_cell_list[0]; + } else { + dual_descriptor.cell_to_node_vector[i_dual_cell][0] = number_of_kept_nodes + primal_node_cell_list[0]; + dual_descriptor.cell_to_node_vector[i_dual_cell][1] = number_of_kept_nodes + primal_node_cell_list[1]; + } + } + } +} + +template <size_t Dimension> +void +DualConnectivityBuilder::_buildConnectivityFrom(const IConnectivity& i_primal_connectivity) +{ + static_assert(Dimension <= 3, "invalid connectivity dimension"); + + if constexpr (Dimension != 2) { + throw NotImplementedError("dual mesh in dimension " + std::to_string(Dimension)); + } + + using ConnectivityType = Connectivity<Dimension>; + + const ConnectivityType& primal_connectivity = dynamic_cast<const ConnectivityType&>(i_primal_connectivity); + + ConnectivityDescriptor dual_descriptor; + + this->_buildConnectivityDescriptor(primal_connectivity, dual_descriptor); + + if constexpr (Dimension > 1) { + ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<Dimension>(dual_descriptor); + if constexpr (Dimension > 2) { + ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<Dimension>(dual_descriptor); + } + } + + { + const std::unordered_map<unsigned int, NodeId> node_to_id_map = [&] { + std::unordered_map<unsigned int, NodeId> node_to_id_map; + for (size_t i_node = 0; i_node < dual_descriptor.node_number_vector.size(); ++i_node) { + node_to_id_map[dual_descriptor.node_number_vector[i_node]] = i_node; + } + return node_to_id_map; + }(); + + for (size_t i_node_list = 0; i_node_list < primal_connectivity.template numberOfRefItemList<ItemType::node>(); + ++i_node_list) { + const auto& primal_ref_node_list = primal_connectivity.template refItemList<ItemType::node>(i_node_list); + const auto& primal_node_list = primal_ref_node_list.list(); + + const std::vector<NodeId> dual_node_list = [&]() { + std::vector<NodeId> dual_node_list; + + for (size_t i_primal_node = 0; i_primal_node < primal_node_list.size(); ++i_primal_node) { + auto primal_node_id = primal_node_list[i_primal_node]; + const auto i_dual_node = node_to_id_map.find(primal_connectivity.nodeNumber()[primal_node_id]); + if (i_dual_node != node_to_id_map.end()) { + dual_node_list.push_back(i_dual_node->second); + } + } + + return dual_node_list; + }(); + + if (parallel::allReduceOr(dual_node_list.size() > 0)) { + Array<NodeId> node_array(dual_node_list.size()); + for (size_t i = 0; i < dual_node_list.size(); ++i) { + node_array[i] = dual_node_list[i]; + } + dual_descriptor.addRefItemList(RefNodeList{primal_ref_node_list.refId(), node_array}); + } + } + } + + if constexpr (Dimension > 1) { + const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix(); + + using Face = ConnectivityFace<Dimension>; + + const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { + std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; + for (FaceId l = 0; l < dual_descriptor.face_to_node_vector.size(); ++l) { + const auto& node_vector = dual_descriptor.face_to_node_vector[l]; + + face_to_id_map[Face(node_vector, dual_descriptor.node_number_vector)] = l; + } + return face_to_id_map; + }(); + + for (size_t i_face_list = 0; i_face_list < primal_connectivity.template numberOfRefItemList<ItemType::face>(); + ++i_face_list) { + const auto& primal_ref_face_list = primal_connectivity.template refItemList<ItemType::face>(i_face_list); + const auto& primal_face_list = primal_ref_face_list.list(); + + const std::vector<FaceId> dual_face_list = [&]() { + std::vector<FaceId> dual_face_list; + dual_face_list.reserve(primal_face_list.size()); + for (size_t i = 0; i < primal_face_list.size(); ++i) { + FaceId primal_face_id = primal_face_list[i]; + + const auto& primal_face_node_list = primal_face_to_node_matrix[primal_face_id]; + + const auto i_dual_face = [&]() { + std::vector<unsigned int> node_list(primal_face_node_list.size()); + for (size_t i = 0; i < primal_face_node_list.size(); ++i) { + node_list[i] = primal_face_node_list[i]; + } + return face_to_id_map.find(Face(node_list, dual_descriptor.node_number_vector)); + }(); + + if (i_dual_face != face_to_id_map.end()) { + dual_face_list.push_back(i_dual_face->second); + } + } + return dual_face_list; + }(); + + if (parallel::allReduceOr(dual_face_list.size() > 0)) { + Array<FaceId> face_array(dual_face_list.size()); + for (size_t i = 0; i < dual_face_list.size(); ++i) { + face_array[i] = dual_face_list[i]; + } + dual_descriptor.addRefItemList(RefFaceList{primal_ref_face_list.refId(), face_array}); + } + } + } + + if constexpr (Dimension > 2) { + const auto& primal_edge_to_node_matrix = primal_connectivity.edgeToNodeMatrix(); + using Edge = ConnectivityFace<2>; + + const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map = [&] { + std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map; + for (EdgeId l = 0; l < dual_descriptor.edge_to_node_vector.size(); ++l) { + const auto& node_vector = dual_descriptor.edge_to_node_vector[l]; + edge_to_id_map[Edge(node_vector, dual_descriptor.node_number_vector)] = l; + } + return edge_to_id_map; + }(); + + for (size_t i_edge_list = 0; i_edge_list < primal_connectivity.template numberOfRefItemList<ItemType::edge>(); + ++i_edge_list) { + const auto& primal_ref_edge_list = primal_connectivity.template refItemList<ItemType::edge>(i_edge_list); + const auto& primal_edge_list = primal_ref_edge_list.list(); + + const std::vector<EdgeId> dual_edge_list = [&]() { + std::vector<EdgeId> dual_edge_list; + dual_edge_list.reserve(primal_edge_list.size()); + for (size_t i = 0; i < primal_edge_list.size(); ++i) { + EdgeId primal_edge_id = primal_edge_list[i]; + + const auto& primal_edge_node_list = primal_edge_to_node_matrix[primal_edge_id]; + + const auto i_dual_edge = [&]() { + std::vector<unsigned int> node_list(primal_edge_node_list.size()); + for (size_t i = 0; i < primal_edge_node_list.size(); ++i) { + node_list[i] = primal_edge_node_list[i]; + } + return edge_to_id_map.find(Edge(node_list, dual_descriptor.node_number_vector)); + }(); + + if (i_dual_edge != edge_to_id_map.end()) { + dual_edge_list.push_back(i_dual_edge->second); + } + } + return dual_edge_list; + }(); + + if (parallel::allReduceOr(dual_edge_list.size() > 0)) { + Array<EdgeId> edge_array(dual_edge_list.size()); + for (size_t i = 0; i < dual_edge_list.size(); ++i) { + edge_array[i] = dual_edge_list[i]; + } + dual_descriptor.addRefItemList(RefEdgeList{primal_ref_edge_list.refId(), edge_array}); + } + } + } + + const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes(); + const size_t primal_number_of_cells = primal_connectivity.numberOfCells(); + + dual_descriptor.node_owner_vector.resize(dual_descriptor.node_number_vector.size()); + + if constexpr (Dimension == 1) { + const auto& node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); + const auto& primal_node_owner = primal_connectivity.nodeOwner(); + size_t next_kept_node_id = 0; + for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { + if (node_to_cell_matrix[primal_node_id].size() == 1) { + dual_descriptor.node_owner_vector[next_kept_node_id++] = primal_node_owner[primal_node_id]; + } + } + const size_t number_of_kept_nodes = next_kept_node_id; + const auto& primal_cell_owner = primal_connectivity.cellOwner(); + for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { + dual_descriptor.node_owner_vector[number_of_kept_nodes + primal_cell_id] = primal_cell_owner[primal_cell_id]; + } + } else { + const auto& primal_node_owner = primal_connectivity.nodeOwner(); + for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { + dual_descriptor.node_owner_vector[primal_node_id] = primal_node_owner[primal_node_id]; + } + const auto& primal_cell_owner = primal_connectivity.cellOwner(); + for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { + dual_descriptor.node_owner_vector[primal_number_of_nodes + primal_cell_id] = primal_cell_owner[primal_cell_id]; + } + } + + if constexpr (Dimension == 1) { + dual_descriptor.cell_owner_vector.resize(dual_descriptor.cell_number_vector.size()); + const auto& primal_node_owner = primal_connectivity.nodeOwner(); + for (NodeId primal_node_id = 0; primal_node_id < primal_number_of_nodes; ++primal_node_id) { + dual_descriptor.cell_owner_vector[primal_node_id] = primal_node_owner[primal_node_id]; + } + } else { + dual_descriptor.cell_owner_vector.resize(dual_descriptor.cell_number_vector.size()); + const size_t primal_number_of_faces = primal_connectivity.numberOfFaces(); + const auto& primal_face_owner = primal_connectivity.faceOwner(); + for (FaceId primal_face_id = 0; primal_face_id < primal_number_of_faces; ++primal_face_id) { + dual_descriptor.cell_owner_vector[primal_face_id] = primal_face_owner[primal_face_id]; + } + } + + { + std::vector<int> face_cell_owner(dual_descriptor.face_number_vector.size()); + std::fill(std::begin(face_cell_owner), std::end(face_cell_owner), parallel::size()); + + for (size_t i_cell = 0; i_cell < dual_descriptor.cell_to_face_vector.size(); ++i_cell) { + const auto& cell_face_list = dual_descriptor.cell_to_face_vector[i_cell]; + for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { + const size_t face_id = cell_face_list[i_face]; + face_cell_owner[face_id] = std::min(face_cell_owner[face_id], dual_descriptor.cell_number_vector[i_cell]); + } + } + + dual_descriptor.face_owner_vector.resize(face_cell_owner.size()); + for (size_t i_face = 0; i_face < face_cell_owner.size(); ++i_face) { + dual_descriptor.face_owner_vector[i_face] = dual_descriptor.cell_owner_vector[face_cell_owner[i_face]]; + } + } + + if constexpr (Dimension == 3) { + std::vector<int> edge_cell_owner(dual_descriptor.edge_number_vector.size()); + std::fill(std::begin(edge_cell_owner), std::end(edge_cell_owner), parallel::size()); + + for (size_t i_cell = 0; i_cell < dual_descriptor.cell_to_face_vector.size(); ++i_cell) { + const auto& cell_edge_list = dual_descriptor.cell_to_edge_vector[i_cell]; + for (size_t i_edge = 0; i_edge < cell_edge_list.size(); ++i_edge) { + const size_t edge_id = cell_edge_list[i_edge]; + edge_cell_owner[edge_id] = std::min(edge_cell_owner[edge_id], dual_descriptor.cell_number_vector[i_cell]); + } + } + + dual_descriptor.edge_owner_vector.resize(edge_cell_owner.size()); + for (size_t i_edge = 0; i_edge < edge_cell_owner.size(); ++i_edge) { + dual_descriptor.edge_owner_vector[i_edge] = dual_descriptor.cell_owner_vector[edge_cell_owner[i_edge]]; + } + } + + m_connectivity = ConnectivityType::build(dual_descriptor); + + if constexpr (Dimension == 1) { + const auto& node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); + + NodeId dual_node_id = 0; + m_primal_node_to_dual_node_map = [&]() { + std::vector<std::pair<NodeId, NodeId>> primal_node_to_dual_node_vector; + for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { + if (node_to_cell_matrix[primal_node_id].size() == 1) { + primal_node_to_dual_node_vector.push_back(std::make_pair(primal_node_id, dual_node_id++)); + } + } + return convert_to_array(primal_node_to_dual_node_vector); + }(); + + m_primal_cell_to_dual_node_map = [&]() { + CellIdToNodeIdMap primal_cell_to_dual_node_map{primal_number_of_cells}; + for (CellId primal_cell_id = 0; primal_cell_id < primal_cell_to_dual_node_map.size(); ++primal_cell_id) { + primal_cell_to_dual_node_map[primal_cell_id] = std::make_pair(primal_cell_id, dual_node_id++); + } + return primal_cell_to_dual_node_map; + }(); + + m_primal_face_to_dual_cell_map = [&]() { + FaceIdToCellIdMap primal_face_to_dual_cell_map{primal_connectivity.numberOfFaces()}; + for (size_t id = 0; id < primal_face_to_dual_cell_map.size(); ++id) { + const CellId dual_cell_id = id; + const FaceId primal_face_id = id; + + primal_face_to_dual_cell_map[id] = std::make_pair(primal_face_id, dual_cell_id); + } + return primal_face_to_dual_cell_map; + }(); + } + + m_mapper = + std::make_shared<ConnectivityToDualConnectivityDataMapper<Dimension>>(primal_connectivity, + dynamic_cast<const ConnectivityType&>( + *m_connectivity), + m_primal_node_to_dual_node_map, + m_primal_cell_to_dual_node_map, + m_primal_face_to_dual_cell_map); +} + +DualConnectivityBuilder::DualConnectivityBuilder(const IConnectivity& connectivity) +{ + if (parallel::size() > 1) { + throw NotImplementedError("Construction of diamond dual mesh is not implemented in parallel"); + } + switch (connectivity.dimension()) { + case 1: { + this->_buildConnectivityFrom<1>(connectivity); + break; + } + case 2: { + this->_buildConnectivityFrom<2>(connectivity); + break; + } + case 3: { + this->_buildConnectivityFrom<3>(connectivity); + break; + } + default: { + throw UnexpectedError("invalid connectivity dimension: " + std::to_string(connectivity.dimension())); + } + } +} diff --git a/src/mesh/DualConnectivityBuilder.hpp b/src/mesh/DualConnectivityBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2edb39c6c382e79199e9cfd39f57aaab30aef5d8 --- /dev/null +++ b/src/mesh/DualConnectivityBuilder.hpp @@ -0,0 +1,42 @@ +#ifndef DUAL_CONNECTIVITY_BUILDER_HPP +#define DUAL_CONNECTIVITY_BUILDER_HPP + +#include <mesh/ConnectivityBuilderBase.hpp> +#include <mesh/IConnectivityToDualConnectivityDataMapper.hpp> +#include <mesh/ItemIdToItemIdMap.hpp> + +#include <memory> + +template <size_t> +class Connectivity; +class ConnectivityDescriptor; + +class DualConnectivityBuilder : public ConnectivityBuilderBase +{ + private: + NodeIdToNodeIdMap m_primal_node_to_dual_node_map; + CellIdToNodeIdMap m_primal_cell_to_dual_node_map; + FaceIdToCellIdMap m_primal_face_to_dual_cell_map; + + std::shared_ptr<IConnectivityToDualConnectivityDataMapper> m_mapper; + + template <size_t Dimension> + void _buildConnectivityDescriptor(const Connectivity<Dimension>&, ConnectivityDescriptor&); + + template <size_t Dimension> + void _buildConnectivityFrom(const IConnectivity&); + + friend class DualConnectivityManager; + DualConnectivityBuilder(const IConnectivity&); + + public: + std::shared_ptr<IConnectivityToDualConnectivityDataMapper> + mapper() const + { + return m_mapper; + } + + ~DualConnectivityBuilder() = default; +}; + +#endif // DUAL_CONNECTIVITY_BUILDER_HPP diff --git a/src/mesh/DualConnectivityManager.cpp b/src/mesh/DualConnectivityManager.cpp index 60a4279810ccdb19c3ff6f160a87839e09fb872b..b923cc0205888b25da08eb920100396a60622ef4 100644 --- a/src/mesh/DualConnectivityManager.cpp +++ b/src/mesh/DualConnectivityManager.cpp @@ -2,7 +2,9 @@ #include <mesh/Connectivity.hpp> #include <mesh/ConnectivityToDiamondDualConnectivityDataMapper.hpp> +#include <mesh/ConnectivityToDualConnectivityDataMapper.hpp> #include <mesh/DiamondDualConnectivityBuilder.hpp> +#include <mesh/DualConnectivityBuilder.hpp> #include <mesh/DualConnectivityManager.hpp> #include <utils/Exceptions.hpp> @@ -53,6 +55,16 @@ DualConnectivityManager::deleteConnectivity(const IConnectivity* p_connectivity) } while (has_removed); } +template <typename DualConnectivityBuilderType> +DualConnectivityManager::DualConnectivityInfo +DualConnectivityManager::_buildDualConnectivity(const Key& key, const IConnectivity& connectivity) +{ + DualConnectivityBuilderType builder{connectivity}; + DualConnectivityInfo connectivity_info{builder.connectivity(), builder.mapper()}; + m_connectivity_to_dual_connectivity_info_map[key] = connectivity_info; + return connectivity_info; +} + DualConnectivityManager::DualConnectivityInfo DualConnectivityManager::_getDualConnectivityInfo(const DualMeshType& type, const IConnectivity& connectivity) { @@ -63,13 +75,17 @@ DualConnectivityManager::_getDualConnectivityInfo(const DualMeshType& type, cons i_connectivity != m_connectivity_to_dual_connectivity_info_map.end()) { return i_connectivity->second; } else { - DiamondDualConnectivityBuilder builder{connectivity}; - - DualConnectivityInfo connectivity_info{builder.connectivity(), builder.mapper()}; - - m_connectivity_to_dual_connectivity_info_map[key] = connectivity_info; - - return connectivity_info; + switch (type) { + case DualMeshType::Classic: { + return this->_buildDualConnectivity<DualConnectivityBuilder>(key, connectivity); + } + case DualMeshType::Diamond: { + return this->_buildDualConnectivity<DiamondDualConnectivityBuilder>(key, connectivity); + } + default: { + throw UnexpectedError("invalid dual mesh type"); + } + } } } @@ -97,6 +113,30 @@ DualConnectivityManager::getConnectivityToDiamondDualConnectivityDataMapper(cons } } +template <size_t Dimension> +std::shared_ptr<const Connectivity<Dimension>> +DualConnectivityManager::getDualConnectivity(const Connectivity<Dimension>& connectivity) +{ + return std::dynamic_pointer_cast<const Connectivity<Dimension>>( + this->_getDualConnectivityInfo(DualMeshType::Classic, connectivity).dualConnectivity()); +} + +template <size_t Dimension> +std::shared_ptr<const ConnectivityToDualConnectivityDataMapper<Dimension>> +DualConnectivityManager::getConnectivityToDualConnectivityDataMapper(const Connectivity<Dimension>& connectivity) +{ + auto i_data_mapper = + this->_getDualConnectivityInfo(DualMeshType::Classic, connectivity).connectivityToDualConnectivityDataMapper(); + auto data_mapper = + std::dynamic_pointer_cast<const ConnectivityToDualConnectivityDataMapper<Dimension>>(i_data_mapper); + + if (data_mapper.use_count() > 0) { + return data_mapper; + } else { + throw UnexpectedError("invalid connectivity data mapper type"); + } +} + template std::shared_ptr<const Connectivity<1>> DualConnectivityManager::getDiamondDualConnectivity( const Connectivity<1>& connectivity); @@ -114,3 +154,21 @@ DualConnectivityManager::getConnectivityToDiamondDualConnectivityDataMapper(cons template std::shared_ptr<const ConnectivityToDiamondDualConnectivityDataMapper<3>> DualConnectivityManager::getConnectivityToDiamondDualConnectivityDataMapper(const Connectivity<3>&); + +template std::shared_ptr<const Connectivity<1>> DualConnectivityManager::getDualConnectivity( + const Connectivity<1>& connectivity); + +template std::shared_ptr<const Connectivity<2>> DualConnectivityManager::getDualConnectivity( + const Connectivity<2>& connectivity); + +template std::shared_ptr<const Connectivity<3>> DualConnectivityManager::getDualConnectivity( + const Connectivity<3>& connectivity); + +template std::shared_ptr<const ConnectivityToDualConnectivityDataMapper<1>> +DualConnectivityManager::getConnectivityToDualConnectivityDataMapper(const Connectivity<1>&); + +template std::shared_ptr<const ConnectivityToDualConnectivityDataMapper<2>> +DualConnectivityManager::getConnectivityToDualConnectivityDataMapper(const Connectivity<2>&); + +template std::shared_ptr<const ConnectivityToDualConnectivityDataMapper<3>> +DualConnectivityManager::getConnectivityToDualConnectivityDataMapper(const Connectivity<3>&); diff --git a/src/mesh/DualConnectivityManager.hpp b/src/mesh/DualConnectivityManager.hpp index eb6e0cad10862df32bf330deefab00b5c7aaf658..1f6819a89842be7c1973587def875f835befd9f9 100644 --- a/src/mesh/DualConnectivityManager.hpp +++ b/src/mesh/DualConnectivityManager.hpp @@ -14,6 +14,9 @@ class Connectivity; template <size_t Dimension> class ConnectivityToDiamondDualConnectivityDataMapper; +template <size_t Dimension> +class ConnectivityToDualConnectivityDataMapper; + class DualConnectivityManager { private: @@ -55,8 +58,6 @@ class DualConnectivityManager ~DualConnectivityInfo() = default; }; - DualConnectivityInfo _getDualConnectivityInfo(const DualMeshType& type, const IConnectivity& connectivity); - using Key = std::pair<DualMeshType, const IConnectivity*>; struct HashKey { @@ -67,6 +68,11 @@ class DualConnectivityManager } }; + template <typename DualConnectivityBuilderType> + DualConnectivityInfo _buildDualConnectivity(const Key& key, const IConnectivity& connectivity); + + DualConnectivityInfo _getDualConnectivityInfo(const DualMeshType& type, const IConnectivity& connectivity); + std::unordered_map<Key, DualConnectivityInfo, HashKey> m_connectivity_to_dual_connectivity_info_map; static DualConnectivityManager* m_instance; @@ -91,6 +97,13 @@ class DualConnectivityManager void deleteConnectivity(const IConnectivity*); + template <size_t Dimension> + std::shared_ptr<const Connectivity<Dimension>> getDualConnectivity(const Connectivity<Dimension>&); + + template <size_t Dimension> + std::shared_ptr<const ConnectivityToDualConnectivityDataMapper<Dimension>> + getConnectivityToDualConnectivityDataMapper(const Connectivity<Dimension>&); + template <size_t Dimension> std::shared_ptr<const Connectivity<Dimension>> getDiamondDualConnectivity(const Connectivity<Dimension>&); diff --git a/src/mesh/DualMeshBuilder.cpp b/src/mesh/DualMeshBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47cac173e0a04500a3f7e4a83b8252375a306f0a --- /dev/null +++ b/src/mesh/DualMeshBuilder.cpp @@ -0,0 +1,62 @@ +#include <mesh/DualMeshBuilder.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityToDualConnectivityDataMapper.hpp> +#include <mesh/DualConnectivityManager.hpp> +#include <mesh/ItemValueUtils.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshData.hpp> +#include <mesh/MeshDataManager.hpp> + +template <size_t Dimension> +void +DualMeshBuilder::_buildDualMeshFrom(const std::shared_ptr<const IMesh>& p_i_mesh) +{ + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<Connectivity<Dimension>>; + + std::shared_ptr p_primal_mesh = std::dynamic_pointer_cast<const MeshType>(p_i_mesh); + const MeshType& primal_mesh = *p_primal_mesh; + + DualConnectivityManager& manager = DualConnectivityManager::instance(); + + std::shared_ptr<const ConnectivityType> p_dual_connectivity = manager.getDualConnectivity(primal_mesh.connectivity()); + + const ConnectivityType& dual_connectivity = *p_dual_connectivity; + + const NodeValue<const TinyVector<Dimension>> primal_xr = primal_mesh.xr(); + + MeshData<Dimension>& primal_mesh_data = MeshDataManager::instance().getMeshData(primal_mesh); + const CellValue<const TinyVector<Dimension>> primal_xj = primal_mesh_data.xj(); + + std::shared_ptr connectivity_to_dual_connectivity_data_mapper = + manager.getConnectivityToDualConnectivityDataMapper(primal_mesh.connectivity()); + + NodeValue<TinyVector<Dimension>> dual_xr{dual_connectivity}; + connectivity_to_dual_connectivity_data_mapper->toDualNode(primal_xr, primal_xj, dual_xr); + + m_mesh = std::make_shared<MeshType>(p_dual_connectivity, dual_xr); +} + +DualMeshBuilder::DualMeshBuilder(const std::shared_ptr<const IMesh>& p_mesh) +{ + std::cout << "building DualMesh\n"; + + switch (p_mesh->dimension()) { + case 1: { + this->_buildDualMeshFrom<1>(p_mesh); + break; + } + case 2: { + this->_buildDualMeshFrom<2>(p_mesh); + break; + } + case 3: { + this->_buildDualMeshFrom<3>(p_mesh); + break; + } + default: { + throw UnexpectedError("invalid mesh dimension: " + std::to_string(p_mesh->dimension())); + } + } +} diff --git a/src/mesh/DualMeshBuilder.hpp b/src/mesh/DualMeshBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1756d7e92ad7e8bfc4fffb2ca2e41ac1bbcb78f1 --- /dev/null +++ b/src/mesh/DualMeshBuilder.hpp @@ -0,0 +1,21 @@ +#ifndef DUAL_MESH_BUILDER_HPP +#define DUAL_MESH_BUILDER_HPP + +#include <mesh/MeshBuilderBase.hpp> + +#include <memory> + +class DualMeshBuilder : public MeshBuilderBase +{ + private: + template <size_t Dimension> + void _buildDualMeshFrom(const std::shared_ptr<const IMesh>&); + + friend class DualMeshManager; + DualMeshBuilder(const std::shared_ptr<const IMesh>&); + + public: + ~DualMeshBuilder() = default; +}; + +#endif // DUAL_MESH_BUILDER_HPP diff --git a/src/mesh/DualMeshManager.cpp b/src/mesh/DualMeshManager.cpp index cf903145b65709d53aec0210b731c57e51fe878d..4fa108cf461e1a070725cf14866b41f346e8b20f 100644 --- a/src/mesh/DualMeshManager.cpp +++ b/src/mesh/DualMeshManager.cpp @@ -2,6 +2,7 @@ #include <mesh/Connectivity.hpp> #include <mesh/DiamondDualMeshBuilder.hpp> +#include <mesh/DualMeshBuilder.hpp> #include <mesh/Mesh.hpp> #include <utils/Exceptions.hpp> #include <utils/PugsAssert.hpp> @@ -52,6 +53,23 @@ DualMeshManager::deleteMesh(const IMesh* p_mesh) } while (has_removed); } +template <size_t Dimension> +std::shared_ptr<const Mesh<Connectivity<Dimension>>> +DualMeshManager::getDualMesh(std::shared_ptr<const Mesh<Connectivity<Dimension>>> mesh) +{ + const IMesh* p_mesh = mesh.get(); + + auto key = std::make_pair(DualMeshType::Classic, p_mesh); + if (auto i_mesh_data = m_mesh_to_dual_mesh_map.find(key); i_mesh_data != m_mesh_to_dual_mesh_map.end()) { + return std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh_data->second); + } else { + DualMeshBuilder builder{mesh}; + + m_mesh_to_dual_mesh_map[key] = builder.mesh(); + return std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(builder.mesh()); + } +} + template <size_t Dimension> std::shared_ptr<const Mesh<Connectivity<Dimension>>> DualMeshManager::getDiamondDualMesh(std::shared_ptr<const Mesh<Connectivity<Dimension>>> mesh) @@ -69,6 +87,13 @@ DualMeshManager::getDiamondDualMesh(std::shared_ptr<const Mesh<Connectivity<Dime } } +template std::shared_ptr<const Mesh<Connectivity<1>>> DualMeshManager::getDualMesh( + std::shared_ptr<const Mesh<Connectivity<1>>>); +template std::shared_ptr<const Mesh<Connectivity<2>>> DualMeshManager::getDualMesh( + std::shared_ptr<const Mesh<Connectivity<2>>>); +template std::shared_ptr<const Mesh<Connectivity<3>>> DualMeshManager::getDualMesh( + std::shared_ptr<const Mesh<Connectivity<3>>>); + template std::shared_ptr<const Mesh<Connectivity<1>>> DualMeshManager::getDiamondDualMesh( std::shared_ptr<const Mesh<Connectivity<1>>>); template std::shared_ptr<const Mesh<Connectivity<2>>> DualMeshManager::getDiamondDualMesh( diff --git a/src/mesh/DualMeshManager.hpp b/src/mesh/DualMeshManager.hpp index e2b92b599254bbac404478fd590df6747281ae29..dd8af5890564f459034905158d886ee600811ce3 100644 --- a/src/mesh/DualMeshManager.hpp +++ b/src/mesh/DualMeshManager.hpp @@ -55,6 +55,10 @@ class DualMeshManager template <size_t Dimension> std::shared_ptr<const Mesh<Connectivity<Dimension>>> getDiamondDualMesh( std::shared_ptr<const Mesh<Connectivity<Dimension>>>); + + template <size_t Dimension> + std::shared_ptr<const Mesh<Connectivity<Dimension>>> getDualMesh( + std::shared_ptr<const Mesh<Connectivity<Dimension>>>); }; #endif // DUAL_MESH_MANAGER_HPP