35 _geometricFilter(geometricFilter),
36 _bb(mesh->getDimensions()),
37 _dimensions(mesh->getDimensions()),
38 _safetyFactor(safetyFactor),
39 _allowDirectAccess(allowDirectAccess)
49 if (
m2n().usesTwoLevelInitialization()) {
55 int globalNumberOfVertices = -1;
57 _mesh->setGlobalNumberOfVertices(globalNumberOfVertices);
74 _mesh->setGlobalNumberOfVertices(
_mesh->nVertices());
83 int globalNumberOfVertices = -1;
86 _mesh->setGlobalNumberOfVertices(globalNumberOfVertices);
96 PRECICE_DEBUG(
"Handle partition data structures for serial participant");
104 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());
105 unsigned int nFilteredVertices = 0;
111 "{} vertices on mesh \"{}\" have been filtered out due to the defined bounding box in \"setMeshAccessRegion\" "
112 "in serial mode. Associated data values of the filtered vertices will be filled with zero values in order to provide valid data for other participants when reading data.",
113 nFilteredVertices,
_mesh->getName());
116 _mesh->addMesh(filteredMesh);
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. 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();
214 int numberOfVertices =
_mesh->nVertices();
216 for (
int i = 0; i < numberOfVertices; i++) {
217 vertexIDs[i] =
_mesh->vertex(i).getGlobalIndex();
219 vertexDistribution[0] = std::move(vertexIDs);
222 PRECICE_DEBUG(
"Receive partition feedback from the secondary rank {}", secondaryRank);
226 _mesh->setVertexDistribution(std::move(vertexDistribution));
236 int numberOfVertices =
_mesh->nVertices();
244 _mesh->setVertexOffsets(std::move(vertexOffsets));
249 vertexOffsets[0] =
_mesh->nVertices();
253 int numberOfSecondaryRankVertices = -1;
256 vertexOffsets[secondaryRank] = numberOfSecondaryRankVertices + vertexOffsets[secondaryRank - 1];
263 _mesh->setVertexOffsets(std::move(vertexOffsets));
268auto errorMeshFilteredOut(
const std::string &meshName,
const int rank)
270 return fmt::format(
"The re-partitioning completely filtered out the mesh \"{0}\" received on rank {1} "
271 "at the coupling interface, although the provided mesh partition on this rank is "
272 "non-empty. Most probably, the coupling interfaces of your coupled participants do "
273 "not match geometry-wise. Please check your geometry setup again. Small overlaps or "
274 "gaps are no problem. If your geometry setup is correct and if you have very different "
275 "mesh resolutions on both sides, you may want to increase the safety-factor: "
276 "\"<receive-mesh mesh=\"{0} \" ... safety-factor=\"N\"/> (default value is 0.5) of the "
277 "decomposition strategy or disable the filtering completely: "
278 "\"<receive-mesh mesh=\"{0}\" ... geometric-filter=\"no-filter\" />",
287 if (
m2n().usesTwoLevelInitialization()) {
289 " cannot solely be filtered on the primary rank "
290 "(option \"filter-on-primary-rank\") if it is communicated by an m2n communication that uses "
291 "two-level initialization. Use \"filter-on-secondary-rank\" or \"no-filter\" instead.";
300 PRECICE_INFO(
"Pre-filter mesh {} by bounding box on primary rank",
_mesh->getName());
321 PRECICE_DEBUG(
"From secondary rank {}, bounding mesh: {}", secondaryRank, secondaryBB);
324 PRECICE_DEBUG(
"Send filtered mesh to secondary rank: {}", secondaryRank);
331 PRECICE_DEBUG(
"Primary rank mesh, filtered from {} to {} vertices, {} to {} edges, and {} to {} triangles.",
336 _mesh->addMesh(filteredMesh);
343 if (not
m2n().usesTwoLevelInitialization()) {
356 PRECICE_INFO(
"Filter mesh {} by bounding box on secondary ranks",
_mesh->getName());
362 PRECICE_DEBUG(
"Bounding box filter, filtered from {} to {} vertices, {} to {} edges, and {} to {} triangles.",
368 _mesh->addMesh(filteredMesh);
383 _mesh->clearPartitioning();
391 if (not
m2n().usesTwoLevelInitialization())
395 int numberOfRemoteRanks = -1;
408 for (
int remoteRank = 0; remoteRank < numberOfRemoteRanks; remoteRank++) {
409 remoteBBMap.
emplace(remoteRank, initialBB);
430 for (
auto &remoteBB : remoteBBMap) {
432 connectedRanks.
push_back(remoteBB.first);
436 _mesh->setConnectedRanks(connectedRanks);
437 if (not connectedRanks.
empty()) {
438 connectionMap.
emplace(0, std::move(connectedRanks));
445 if (!secondaryConnectedRanks.
empty()) {
447 connectionMap.
emplace(rank, std::move(secondaryConnectedRanks));
454 "The mesh \"{}\" of this participant seems to have no partitions at the coupling interface. "
455 "Check that both mapped meshes are describing the same geometry. "
456 "If you deal with very different mesh resolutions, consider increasing the safety-factor in the <receive-mesh /> tag.",
463 for (
const auto &remoteBB : remoteBBMap) {
465 connectedRanks.
push_back(remoteBB.first);
469 _mesh->setConnectedRanks(connectedRanks);
483 PRECICE_DEBUG(
"Merge bounding boxes and increase by safety factor");
490 auto other_bb = fromMapping->getOutputMesh()->getBoundingBox();
496 auto other_bb = toMapping->getInputMesh()->getBoundingBox();
504 auto &other_bb =
_mesh->getBoundingBox();
512 const float defaultSafetyFactor = 0.5;
515 "The received mesh \"{}\" was entirely partitioned based on the defined access region "
516 "(setMeshAccessRegion) and a safety-factor was defined. However, the safety factor "
517 "will be ignored in this case. You may want to modify the access region by modifying "
518 "the specified region in the function itself.",
535 if (
m2n().usesTwoLevelInitialization()) {
580 localBBMap.
at(0) =
_bb;
600 for (
const auto &localBB : localBBMap) {
602 localConnectedBBMap.
emplace(localBB.first, localBB.second);
611 for (
auto &neighborRank : localConnectedBBMap)
615 const int numberOfVertices =
_mesh->nVertices();
616 PRECICE_DEBUG(
"Tag vertices, number of vertices {}", numberOfVertices);
619 int ownedVerticesCount = 0;
620 for (
int i = 0; i < numberOfVertices; i++) {
621 globalIDs[i] =
_mesh->vertex(i).getGlobalIndex();
622 if (
_mesh->vertex(i).isTagged()) {
623 bool vertexIsShared =
false;
624 for (
const auto &neighborRank : localConnectedBBMap) {
625 if (neighborRank.second.contains(
_mesh->vertex(i))) {
626 vertexIsShared =
true;
627 sharedVerticesSendMap[neighborRank.first].push_back(globalIDs[i]);
631 if (not vertexIsShared) {
633 ownedVerticesCount++;
635 sharedVerticesGlobalIDs.
push_back(globalIDs[i]);
650 for (
auto &neighborRank : localConnectedBBMap) {
651 neighborRanksVertexCount.
emplace(neighborRank.first, 0);
655 for (
auto &neighborRank : localConnectedBBMap) {
661 for (
auto &neighborRank : localConnectedBBMap) {
666 for (
auto &rqst : vertexNumberRequests) {
674 for (
auto &receivingRank : sharedVerticesSendMap) {
675 int sendSize = receivingRank.second.
size();
684 for (
auto &neighborRank : sharedVerticesSendMap) {
687 if (receiveSize != 0) {
695 for (
auto &rqst : vertexListRequests) {
705 for (
auto &sharingRank : sharedVerticesReceiveMap) {
709 if ((ownedVerticesCount > neighborRanksVertexCount[sharingRank.first]) ||
710 (ownedVerticesCount == neighborRanksVertexCount[sharingRank.first] &&
utils::IntraComm::getRank() > sharingRank.first)) {
720 tags[sharedVerticesLocalIDs[r]] =
static_cast<int>(
false);
725 PRECICE_DEBUG(
"{} of {} vertices of mesh {} have been filtered out on rank {} since they have no influence on the mapping.",
730 int numberOfVertices =
_mesh->nVertices();
733 if (numberOfVertices != 0) {
734 PRECICE_DEBUG(
"Tag vertices, number of vertices {}", numberOfVertices);
737 bool atInterface =
false;
738 for (
int i = 0; i < numberOfVertices; i++) {
739 globalIDs[i] =
_mesh->vertex(i).getGlobalIndex();
740 if (
_mesh->vertex(i).isTagged()) {
774 bool primaryRankAtInterface =
false;
778 for (
size_t i = 0; i <
_mesh->nVertices(); i++) {
779 secondaryGlobalIDs[0][i] =
_mesh->vertex(i).getGlobalIndex();
780 if (
_mesh->vertex(i).isTagged()) {
781 primaryRankAtInterface =
true;
782 secondaryTags[0][i] = 1;
784 secondaryTags[0][i] = 0;
790 Rank ranksAtInterface = 0;
791 if (primaryRankAtInterface)
795 int localNumberOfVertices = -1;
797 PRECICE_DEBUG(
"Rank {} has {} vertices.", rank, localNumberOfVertices);
798 secondaryOwnerVecs[rank].
resize(localNumberOfVertices, 0);
800 if (localNumberOfVertices != 0) {
804 PRECICE_DEBUG(
"Rank {} has tags {}", rank, secondaryTags[rank]);
805 PRECICE_DEBUG(
"Rank {} has global IDs {}", rank, secondaryGlobalIDs[rank]);
806 bool atInterface =
false;
814 PRECICE_DEBUG(
"Decide owners, first round by rough load balancing");
817 "After repartitioning of mesh \"{}\" all ranks are empty. "
818 "Please check the dimensions of the provided bounding box "
819 "(in \"setMeshAccessRegion\") and verify that it covers vertices "
820 "in the mesh or check the definition of the provided meshes.",
823 int localGuess =
_mesh->getGlobalNumberOfVertices() / ranksAtInterface;
827 for (
size_t i = 0; i < secondaryOwnerVecs[rank].
size(); i++) {
829 if (globalOwnerVec[secondaryGlobalIDs[rank][i]] == 0 && secondaryTags[rank][i] == 1) {
830 secondaryOwnerVecs[rank][i] = 1;
831 globalOwnerVec[secondaryGlobalIDs[rank][i]] = 1;
833 if (counter == localGuess)
842 for (
size_t i = 0; i < secondaryOwnerVecs[rank].
size(); i++) {
843 if (globalOwnerVec[secondaryGlobalIDs[rank][i]] == 0 && secondaryTags[rank][i] == 1) {
844 secondaryOwnerVecs[rank][i] = 1;
845 globalOwnerVec[secondaryGlobalIDs[rank][i]] = rank + 1;
852 if (not secondaryTags[rank].empty()) {
853 PRECICE_DEBUG(
"Send owner information to secondary rank {}", rank);
858 PRECICE_DEBUG(
"My owner information: {}", secondaryOwnerVecs[0]);
862 for (
size_t i = 0; i < globalOwnerVec.
size(); i++) {
864 "The Vertex with global index {} of mesh: {} was completely filtered out, since it has no influence on any mapping.",
865 i,
_mesh->getName());
870 "{} of {} vertices of mesh {} have been filtered out since they have no influence on the mapping.{}",
871 filteredVertices,
_mesh->getGlobalNumberOfVertices(),
_mesh->getName(),
872 _allowDirectAccess ?
" Associated data values of the filtered vertices will be filled with zero values in order to "
873 "provide valid data for other participants when reading data."
882 if (not fromMapping->getOutputMesh()->empty()) {
887 if (not toMapping->getInputMesh()->empty()) {
908 fromMapping->tagMeshFirstRound();
911 toMapping->tagMeshFirstRound();
923 fromMapping->tagMeshSecondRound();
926 toMapping->tagMeshSecondRound();
936 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.
bool empty() const
Check if every dimension's length is equal to zero.
void expandBy(const BoundingBox &otherBB)
Expand bounding box using another bounding box.
bool overlapping(const BoundingBox &otherBB) const
Checks whether two bounding boxes are overlapping.
int getDimension() const
Getter dimension of the bounding box.
void scaleBy(double safetyFactor)
Increase the size of bounding box by safety margin.
Container and creator for meshes.
static constexpr MeshID MESH_ID_UNDEFINED
Use if the id of the mesh is not necessary.
std::size_t nVertices() const
Returns the number of vertices.
TriangleContainer & triangles()
Returns modifiable container holding all triangles.
EdgeContainer & edges()
Returns modifiable container holding all edges.
Abstract base class for partitions.
std::vector< mapping::PtrMapping > _toMappings
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)
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)
void filterMesh(Mesh &destination, const Mesh &source, UnaryPredicate p)
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...