diff --git a/src/amdis/utility/CMakeLists.txt b/src/amdis/utility/CMakeLists.txt index 870230af8d6cc5e42061d2bffb6e135918017f11..33add2585317639ad95105ba90b78d6bf0df0ed5 100644 --- a/src/amdis/utility/CMakeLists.txt +++ b/src/amdis/utility/CMakeLists.txt @@ -4,4 +4,5 @@ install(FILES LocalToGlobalAdapter.hpp MacroGridFactory.hpp QuadratureFactory.hpp + UniqueBorderPartition.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/utility) diff --git a/src/amdis/utility/UniqueBorderPartition.hpp b/src/amdis/utility/UniqueBorderPartition.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6a3000b2f02dfef5e59e7d14f44ee53b43b275e9 --- /dev/null +++ b/src/amdis/utility/UniqueBorderPartition.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include <cassert> +#include <set> + +#include <dune/common/unused.hh> +#include <dune/grid/common/datahandleif.hh> + +namespace AMDiS +{ + /// \brief Determine for each border entity which processor owns it + /** + * All entities must be uniquely owned by exactly one processor, but they can + * exist on multiple processors. For interior, overlap, and ghost entities the + * assignment is trivial: interior: owner, otherwise not owner. + * + * For border entities (codim != 0) the ownership is not known a priori and must + * be communicated. Here we assign the entity to the processor with the lowest rank. + **/ + template <class Grid> + class UniqueBorderPartitionDataHandle + : public Dune::CommDataHandleIF<UniqueBorderPartitionDataHandle<Grid>, int> + { + using IdSet = typename Grid::GlobalIdSet; + using IdType = typename IdSet::IdType; + + public: + using EntitySet = std::set<IdType>; + + public: + /// \brief Construct a UniqueBorderPartition DataHandle to be used in a GridView + /// communicator. + /** + * \param rank The own processor rank + * \param borderEntities A set of entity ids filled with all border entities + * owned by this processor after communication. + * \param idSet The id set of entity ids to store in borderEntities, + * typically the grid globalIdSet. + * + * NOTE: Since idSet is stored by reference it must not go out of scope + * until all calls to \ref gather and \ref scatter are finished. + **/ + UniqueBorderPartitionDataHandle(int rank, EntitySet& borderEntities, IdSet const& idSet) + : myrank_(rank) + , borderEntities_(&borderEntities) + , idSet_(idSet) + {} + + // Communicate all entities except for grid elements + bool contains(int /*dim*/, int codim) const { return codim != 0; } + + // communicate exactly one integer, the rank + bool fixedSize(int /*dim*/, int /*codim*/) const { return true; } + + // Always contains one int, the rank + template <class Entity> + std::size_t size(Entity const& e) const { return 1; } + + template <class MessageBuffer, class Entity> + void gather(MessageBuffer& buff, Entity const& e) const + { + buff.write(myrank_); + // insert all border entities + borderEntities_->insert(idSet_.id(e)); + } + + template <class MessageBuffer, class Entity> + void scatter(MessageBuffer& buff, Entity const& e, std::size_t n) + { + DUNE_UNUSED_PARAMETER(n); // n == 1 + assert(n == 1); + + int rank = 0; + buff.read(rank); + // remove all border entities with rank < myrank_ + if (rank < myrank_) + borderEntities_->erase(idSet_.id(e)); + } + + private: + int myrank_; + EntitySet* borderEntities_; + IdSet const& idSet_; + }; + +} // end namespace AMDiS diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 282214b3a68816de41ce0f583939d8f86a0bc0bf..da50325e8666af00621bab9d5615d6e69a0e74a1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -97,3 +97,9 @@ dune_add_test(SOURCES TreeContainerTest.cpp dune_add_test(SOURCES TypeTraitsTest.cpp LINK_LIBRARIES amdis) + +dune_add_test(SOURCES UniqueBorderPartitionTest.cpp + LINK_LIBRARIES amdis + MPI_RANKS 2 + TIMEOUT 300 + CMAKE_GUARD MPI_FOUND) diff --git a/test/UniqueBorderPartitionTest.cpp b/test/UniqueBorderPartitionTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e23f95225e2aaf4f16c1122ea17f4439fc77fd12 --- /dev/null +++ b/test/UniqueBorderPartitionTest.cpp @@ -0,0 +1,40 @@ +#include <amdis/AMDiS.hpp> +#include <amdis/utility/UniqueBorderPartition.hpp> + +#include <dune/grid/yaspgrid.hh> + +#include "Tests.hpp" + +using namespace AMDiS; + +template <class GridView> +void test(GridView const& gv) +{ + using Grid = typename GridView::Grid; + using DataHandle = UniqueBorderPartitionDataHandle<Grid>; + + using EntitySet = typename DataHandle::EntitySet; + EntitySet borderEntities; + + DataHandle handle(gv.comm().rank(), borderEntities, gv.grid().globalIdSet()); + gv.communicate(handle, + Dune::InterfaceType::InteriorBorder_InteriorBorder_Interface, + Dune::CommunicationDirection::ForwardCommunication); + + msg("#borderEntities = {}", borderEntities.size()); +} + +int main(int argc, char** argv) +{ + Environment env(argc, argv); + + Dune::YaspGrid<2> grid1({1.0, 1.0}, {8,8}, 0, 0); // no overlap + Dune::YaspGrid<2> grid2({1.0, 1.0}, {8,8}, 0, 1); // overlap = 1 + Dune::YaspGrid<3> grid3({1.0, 1.0, 1.0}, {8,8,8}, 0, 1); // overlap = 1 + + test(grid1.leafGridView()); + test(grid2.leafGridView()); + test(grid3.leafGridView()); + + return report_errors(); +}