50 if (
m2n().usesTwoLevelInitialization()) {
56 int globalNumberOfVertices = -1;
58 _mesh->setGlobalNumberOfVertices(globalNumberOfVertices);
75 _mesh->setGlobalNumberOfVertices(
_mesh->nVertices());
84 int globalNumberOfVertices = -1;
87 _mesh->setGlobalNumberOfVertices(globalNumberOfVertices);
99 PRECICE_DEBUG(
"Handle partition data structures for serial participant");
106 PRECICE_CHECK(!
_bb.empty(),
"You are running this participant in serial mode and the bounding box on mesh \"{}\", is empty. Did you call setMeshAccessRegion with valid data?",
_mesh->getName());
110 unsigned int nFilteredVertices = nVerticesInBox -
_mesh->nVertices();
113 "{} vertices on mesh \"{}\" have been filtered out due to the defined bounding box in \"setMeshAccessRegion\" "
114 "in serial mode. For direct-mesh access via \"getMeshVertexCoordinatesAndIDs()\", these vertices are not accessible. "
115 "Their data values will internally be filled with zero values in order to provide valid data for other participants when reading data.",
116 nFilteredVertices,
_mesh->getName());
120 int vertexCounter = 0;
123 vertexDistribution[0].push_back(vertexCounter);
127 _mesh->setVertexDistribution(std::move(vertexDistribution));
129 _mesh->setVertexOffsets({vertexCounter});
136 "The received mesh {} needs a mapping (either from it, to it, or both) or API access enabled (api-access=\"true\"). Maybe you don't want to receive this mesh at all?",
164 PRECICE_DEBUG(
"Mapping filter, filtered from {} to {} vertices, {} to {} edges, and {} to {} triangles.",
170 _mesh->addMesh(filteredMesh);
174 if (
m2n().usesTwoLevelInitialization()) {
185 for (
size_t vertexIndex = 0; vertexIndex <
_mesh->nVertices(); ++vertexIndex) {
186 for (
size_t rankIndex = 0; rankIndex <
_mesh->getConnectedRanks().size(); ++rankIndex) {
187 int globalVertexIndex =
_mesh->vertex(vertexIndex).getGlobalIndex();
189 int remoteRank =
_mesh->getConnectedRanks()[rankIndex];
191 _mesh->getCommunicationMap()[remoteRank].push_back(vertexIndex);
204 int numberOfVertices =
_mesh->nVertices();
206 for (
int i = 0; i < numberOfVertices; i++) {
207 vertexIDs[i] =
_mesh->vertex(i).getGlobalIndex();
213 int numberOfVertices =
_mesh->nVertices();
215 for (
int i = 0; i < numberOfVertices; i++) {
216 vertexIDs[i] =
_mesh->vertex(i).getGlobalIndex();
218 vertexDistribution[0] = std::move(vertexIDs);
221 PRECICE_DEBUG(
"Receive partition feedback from the secondary rank {}", secondaryRank);
225 _mesh->setVertexDistribution(std::move(vertexDistribution));
235 int numberOfVertices =
_mesh->nVertices();
243 _mesh->setVertexOffsets(std::move(vertexOffsets));
248 vertexOffsets[0] =
_mesh->nVertices();
252 int numberOfSecondaryRankVertices = -1;
255 vertexOffsets[secondaryRank] = numberOfSecondaryRankVertices + vertexOffsets[secondaryRank - 1];
262 _mesh->setVertexOffsets(std::move(vertexOffsets));
272auto errorMeshFilteredOut(
const std::string &meshName,
const int rank)
274 return fmt::format(
"The re-partitioning completely filtered out the mesh \"{0}\" received on rank {1} "
275 "at the coupling interface, although the provided mesh partition on this rank is "
276 "non-empty. Most probably, the coupling interfaces of your coupled participants do "
277 "not match geometry-wise. Please check your geometry setup again. Small overlaps or "
278 "gaps are no problem. If your geometry setup is correct and if you have very different "
279 "mesh resolutions on both sides, you may want to increase the safety-factor: "
280 "\"<receive-mesh mesh=\"{0} \" ... safety-factor=\"N\"/> (default value is 0.5) of the "
281 "decomposition strategy or disable the filtering completely: "
282 "\"<receive-mesh mesh=\"{0}\" ... geometric-filter=\"no-filter\" />",
291 if (
m2n().usesTwoLevelInitialization()) {
293 " cannot solely be filtered on the primary rank "
294 "(option \"filter-on-primary-rank\") if it is communicated by an m2n communication that uses "
295 "two-level initialization. Use \"filter-on-secondary-rank\" or \"no-filter\" instead.";
304 PRECICE_INFO(
"Pre-filter mesh {} by bounding box on primary rank",
_mesh->getName());
325 PRECICE_DEBUG(
"From secondary rank {}, bounding mesh: {}", secondaryRank, secondaryBB);
328 PRECICE_DEBUG(
"Send filtered mesh to secondary rank: {}", secondaryRank);
335 PRECICE_DEBUG(
"Primary rank mesh, filtered from {} to {} vertices, {} to {} edges, and {} to {} triangles.",
340 _mesh->addMesh(filteredMesh);
347 if (not
m2n().usesTwoLevelInitialization()) {
360 PRECICE_INFO(
"Filter mesh {} by bounding box on secondary ranks",
_mesh->getName());
366 PRECICE_DEBUG(
"Bounding box filter, filtered from {} to {} vertices, {} to {} edges, and {} to {} triangles.",
372 _mesh->addMesh(filteredMesh);
387 _mesh->clearPartitioning();
395 if (not
m2n().usesTwoLevelInitialization())
399 int numberOfRemoteRanks = -1;
412 for (
int remoteRank = 0; remoteRank < numberOfRemoteRanks; remoteRank++) {
413 remoteBBMap.
emplace(remoteRank, initialBB);
434 for (
auto &remoteBB : remoteBBMap) {
435 if (
_bb.overlapping(remoteBB.second)) {
436 connectedRanks.
push_back(remoteBB.first);
440 _mesh->setConnectedRanks(connectedRanks);
441 if (not connectedRanks.
empty()) {
442 connectionMap.
emplace(0, std::move(connectedRanks));
449 if (!secondaryConnectedRanks.
empty()) {
451 connectionMap.
emplace(rank, std::move(secondaryConnectedRanks));
458 "The mesh \"{}\" of this participant seems to have no partitions at the coupling interface. "
459 "Check that both mapped meshes are describing the same geometry. "
460 "If you deal with very different mesh resolutions, consider increasing the safety-factor in the <receive-mesh /> tag.",
467 for (
const auto &remoteBB : remoteBBMap) {
468 if (
_bb.overlapping(remoteBB.second)) {
469 connectedRanks.
push_back(remoteBB.first);
473 _mesh->setConnectedRanks(connectedRanks);
487 PRECICE_DEBUG(
"Merge bounding boxes and increase by safety factor");
497 auto other_bb = fromMapping->getOutputMesh()->getBoundingBox();
498 _bb.expandBy(other_bb);
503 auto other_bb = toMapping->getInputMesh()->getBoundingBox();
504 _bb.expandBy(other_bb);
511 auto &other_bb =
_mesh->getBoundingBox();
512 _bb.expandBy(other_bb);
530 const float defaultSafetyFactor = 0.5;
533 "The received mesh \"{}\" was entirely partitioned based on the defined access region "
534 "(setMeshAccessRegion) and a safety-factor was defined. However, the safety factor "
535 "will be ignored in this case. You may want to modify the access region by modifying "
536 "the specified region in the function itself.",
553 if (
m2n().usesTwoLevelInitialization()) {
598 localBBMap.
at(0) =
_bb;
618 for (
const auto &localBB : localBBMap) {
619 if (
_bb.overlapping(localBB.second)) {
620 localConnectedBBMap.
emplace(localBB.first, localBB.second);
629 for (
auto &neighborRank : localConnectedBBMap)
633 const int numberOfVertices =
_mesh->nVertices();
634 PRECICE_DEBUG(
"Tag vertices, number of vertices {}", numberOfVertices);
637 int ownedVerticesCount = 0;
638 for (
int i = 0; i < numberOfVertices; i++) {
639 globalIDs[i] =
_mesh->vertex(i).getGlobalIndex();
640 if (
_mesh->vertex(i).isTagged()) {
641 bool vertexIsShared =
false;
642 for (
const auto &neighborRank : localConnectedBBMap) {
643 if (neighborRank.second.contains(
_mesh->vertex(i))) {
644 vertexIsShared =
true;
645 sharedVerticesSendMap[neighborRank.first].push_back(globalIDs[i]);
649 if (not vertexIsShared) {
651 ownedVerticesCount++;
653 sharedVerticesGlobalIDs.
push_back(globalIDs[i]);
668 for (
auto &neighborRank : localConnectedBBMap) {
669 neighborRanksVertexCount.
emplace(neighborRank.first, 0);
673 for (
auto &neighborRank : localConnectedBBMap) {
679 for (
auto &neighborRank : localConnectedBBMap) {
684 for (
auto &rqst : vertexNumberRequests) {
692 for (
auto &receivingRank : sharedVerticesSendMap) {
693 int sendSize = receivingRank.second.size();
702 for (
auto &neighborRank : sharedVerticesSendMap) {
705 if (receiveSize != 0) {
713 for (
auto &rqst : vertexListRequests) {
723 for (
auto &sharingRank : sharedVerticesReceiveMap) {
727 if ((ownedVerticesCount > neighborRanksVertexCount[sharingRank.first]) ||
728 (ownedVerticesCount == neighborRanksVertexCount[sharingRank.first] &&
utils::IntraComm::getRank() > sharingRank.first)) {
738 tags[sharedVerticesLocalIDs[r]] =
static_cast<int>(
false);
743 PRECICE_DEBUG(
"{} of {} vertices of mesh {} have been filtered out on rank {} since they have no influence on the mapping.",
748 int numberOfVertices =
_mesh->nVertices();
751 if (numberOfVertices != 0) {
752 PRECICE_DEBUG(
"Tag vertices, number of vertices {}", numberOfVertices);
755 bool atInterface =
false;
756 for (
int i = 0; i < numberOfVertices; i++) {
757 globalIDs[i] =
_mesh->vertex(i).getGlobalIndex();
758 if (
_mesh->vertex(i).isTagged()) {
792 bool primaryRankAtInterface =
false;
796 for (
size_t i = 0; i <
_mesh->nVertices(); i++) {
797 secondaryGlobalIDs[0][i] =
_mesh->vertex(i).getGlobalIndex();
798 if (
_mesh->vertex(i).isTagged()) {
799 primaryRankAtInterface =
true;
800 secondaryTags[0][i] = 1;
802 secondaryTags[0][i] = 0;
808 Rank ranksAtInterface = 0;
809 if (primaryRankAtInterface)
813 int localNumberOfVertices = -1;
815 PRECICE_DEBUG(
"Rank {} has {} vertices.", rank, localNumberOfVertices);
816 secondaryOwnerVecs[rank].
resize(localNumberOfVertices, 0);
818 if (localNumberOfVertices != 0) {
822 PRECICE_DEBUG(
"Rank {} has tags {}", rank, secondaryTags[rank]);
823 PRECICE_DEBUG(
"Rank {} has global IDs {}", rank, secondaryGlobalIDs[rank]);
824 bool atInterface =
false;
832 PRECICE_DEBUG(
"Decide owners, first round by rough load balancing");
835 "After repartitioning of mesh \"{}\" all ranks are empty. "
836 "Please check the dimensions of the provided bounding box "
837 "(in \"setMeshAccessRegion\") and verify that it covers vertices "
838 "in the mesh or check the definition of the provided meshes.",
841 int localGuess =
_mesh->getGlobalNumberOfVertices() / ranksAtInterface;
845 for (
size_t i = 0; i < secondaryOwnerVecs[rank].
size(); i++) {
847 if (globalOwnerVec[secondaryGlobalIDs[rank][i]] == 0 && secondaryTags[rank][i] == 1) {
848 secondaryOwnerVecs[rank][i] = 1;
849 globalOwnerVec[secondaryGlobalIDs[rank][i]] = 1;
851 if (counter == localGuess)
860 for (
size_t i = 0; i < secondaryOwnerVecs[rank].
size(); i++) {
861 if (globalOwnerVec[secondaryGlobalIDs[rank][i]] == 0 && secondaryTags[rank][i] == 1) {
862 secondaryOwnerVecs[rank][i] = 1;
863 globalOwnerVec[secondaryGlobalIDs[rank][i]] = rank + 1;
870 if (not secondaryTags[rank].empty()) {
871 PRECICE_DEBUG(
"Send owner information to secondary rank {}", rank);
876 PRECICE_DEBUG(
"My owner information: {}", secondaryOwnerVecs[0]);
880 for (
size_t i = 0; i < globalOwnerVec.
size(); i++) {
882 "The Vertex with global index {} of mesh: {} was completely filtered out, since it has no influence on any mapping.",
883 i,
_mesh->getName());
888 "{} of {} vertices of mesh {} have been filtered out since they have no influence on the mapping.{}",
889 filteredVertices,
_mesh->getGlobalNumberOfVertices(),
_mesh->getName(),
890 _allowDirectAccess ?
" Associated data values of the filtered vertices will be filled with zero values in order to "
891 "provide valid data for other participants when reading data."
900 if (not fromMapping->getOutputMesh()->empty()) {
905 if (not toMapping->getInputMesh()->empty()) {
928 auto userDefinedBB =
_mesh->getBoundingBox();
929 for (
auto &vertex :
_mesh->vertices()) {
930 if (userDefinedBB.contains(vertex)) {
937 fromMapping->tagMeshFirstRound();
940 toMapping->tagMeshFirstRound();
947 fromMapping->tagMeshSecondRound();
950 toMapping->tagMeshSecondRound();
960 vertex.setOwner(ownerVec[i] == 1);
#define PRECICE_WARN_IF(condition,...)
#define PRECICE_DEBUG(...)
#define PRECICE_DEBUG_IF(condition,...)
#define PRECICE_TRACE(...)
#define PRECICE_INFO(...)
#define PRECICE_CHECK(check,...)
#define PRECICE_ASSERT(...)
T back_inserter(T... args)
M2N communication class. This layer is necessary since communication between two participants can be ...
void scatterAllCommunicationMap(std::map< int, std::vector< int > > &localCommunicationMap, mesh::Mesh &mesh)
Scatters a communication map over connected ranks on remote participant (concerning the given mesh)
void broadcastReceiveAll(std::vector< int > &itemToReceive, mesh::Mesh &mesh)
Receives an int per connected rank on remote participant (concerning the given mesh) @para[out] itemT...
com::PtrCommunication getPrimaryRankCommunication()
Get the basic communication between the 2 primary ranks.
void broadcastReceiveAllMesh(mesh::Mesh &mesh)
Receive mesh partitions per connected rank on remote participant (concerning the given mesh)
An axis-aligned bounding box around a (partition of a) mesh.
bool contains(const Vertex &vertex) const
Checks if vertex in contained in _bb.
Container and creator for meshes.
std::map< Rank, std::vector< VertexID > > CommunicationMap
A mapping from remote local ranks to the IDs that must be communicated.
static constexpr MeshID MESH_ID_UNDEFINED
Use if the id of the mesh is not necessary.
std::map< Rank, std::vector< VertexID > > VertexDistribution
A mapping from rank to used (not necessarily owned) vertex IDs.
std::size_t nVertices() const
Returns the number of vertices.
std::map< int, BoundingBox > BoundingBoxMap
std::vector< int > VertexOffsets
TriangleContainer & triangles()
Returns modifiable container holding all triangles.
EdgeContainer & edges()
Returns modifiable container holding all edges.
std::vector< mapping::PtrMapping > _toMappings
Partition(mesh::PtrMesh mesh)
Constructor.
std::vector< mapping::PtrMapping > _fromMappings
std::vector< m2n::PtrM2N > _m2ns
m2n connection to each connected participant
bool isAnyProvidedMeshNonEmpty() const
void prepareBoundingBox()
Sets _bb to the union with the mesh from fromMapping resp. toMapping, also enlage by _safetyFactor.
ReceivedPartition(const mesh::PtrMesh &mesh, GeometricFilter geometricFilter, double safetyFactor, bool allowDirectAccess=false)
Constructor.
void compute() override
The partition is computed, i.e. the mesh re-partitioned if required and all data structures are set u...
std::vector< int > _remoteMaxGlobalVertexIDs
Max global vertex IDs of remote connected ranks.
void tagMeshFirstRound()
Tag mesh in first round according to all mappings.
std::vector< int > _remoteMinGlobalVertexIDs
Min global vertex IDs of remote connected ranks.
GeometricFilter _geometricFilter
bool hasAnyMapping() const
Returns whether any mapping is defined.
void tagMeshSecondRound()
Tag mesh in second round according to all mappings.
void createOwnerInformation()
m2n::M2N & m2n()
return the one m2n, a ReceivedPartition can only have one m2n
void compareBoundingBoxes() override
Intersections between bounding boxes around each rank are computed.
bool _boundingBoxPrepared
Is the local other (i.e. provided) bounding box already prepared (i.e. has prepareBoundingBox() been ...
GeometricFilter
Defines the type of geometric filter used.
@ ON_PRIMARY_RANK
Filter at primary rank and communicate only filtered mesh.
@ ON_SECONDARY_RANKS
Filter after communication on all secondary ranks.
@ NO_FILTER
No geometric filter used (e.g. for RBF mappings)
void filterByBoundingBox()
void setOwnerInformation(const std::vector< int > &ownerVec)
Helper function for 'createOwnerFunction' to set local owner information.
void communicate() override
The mesh is communicated between both primary ranks (if required)
void stop()
Stops a running event.
A C++ 11 implementation of the non-owning C++20 std::span type.
PRECICE_SPAN_CONSTEXPR11 span< element_type, Count > first() const
static int getSize()
Number of ranks. This includes ranks from both participants, e.g. minimal size is 2.
static Rank getRank()
Current rank.
static bool isPrimary()
True if this process is running the primary rank.
static auto allSecondaryRanks()
Returns an iterable range over salve ranks [1, _size)
static auto allRanks()
Returns an iterable range over all ranks [0, _size)
static bool isParallel()
True if this process is running in parallel.
static bool isSecondary()
True if this process is running a secondary rank.
static com::PtrCommunication & getCommunication()
Intra-participant communication.
void receiveBoundingBoxMap(Communication &communication, int rankSender, mesh::Mesh::BoundingBoxMap &bbm)
void broadcastReceiveBoundingBoxMap(Communication &communication, mesh::Mesh::BoundingBoxMap &bbm)
void sendMesh(Communication &communication, int rankReceiver, const mesh::Mesh &mesh)
void broadcastSendMesh(Communication &communication, const mesh::Mesh &mesh)
void sendBoundingBox(Communication &communication, int rankReceiver, const mesh::BoundingBox &bb)
void sendConnectionMap(Communication &communication, int rankReceiver, const mesh::Mesh::ConnectionMap &cm)
constexpr auto asVector
Allows to use Communication::AsVectorTag in a less verbose way.
void broadcastReceiveMesh(Communication &communication, mesh::Mesh &mesh)
void receiveMesh(Communication &communication, int rankSender, mesh::Mesh &mesh)
void broadcastSendBoundingBoxMap(Communication &communication, const mesh::Mesh::BoundingBoxMap &bbm)
void receiveBoundingBox(Communication &communication, int rankSender, mesh::BoundingBox &bb)
std::shared_ptr< Mapping > PtrMapping
provides Mesh, Data and primitives.
void filterMesh(Mesh &destination, const Mesh &source, UnaryPredicate p)
std::shared_ptr< Mesh > PtrMesh
std::size_t countVerticesInBoundingBox(mesh::PtrMesh mesh, const mesh::BoundingBox &bb)
Given a Mesh and a bounding box, counts all vertices within the bounding box.
contains the partitioning of distributed meshes.
static constexpr SynchronizeTag Synchronize
Convenience instance of the SynchronizeTag.
void set_intersection_indices(InputIt1 ref1, InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first)
This function is by and large the same as std::set_intersection(). The only difference is that we don...