preCICE v3.2.0
Loading...
Searching...
No Matches
ProvidedPartition.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <map>
3#include <memory>
4#include <numeric>
5#include <ostream>
6#include <utility>
7#include <vector>
8
10#include "com/Extra.hpp"
11#include "com/SharedPointer.hpp"
12#include "logging/LogMacros.hpp"
13#include "m2n/M2N.hpp"
14#include "m2n/SharedPointer.hpp"
15#include "mesh/BoundingBox.hpp"
16#include "mesh/Mesh.hpp"
17#include "mesh/Vertex.hpp"
21#include "profiling/Event.hpp"
22#include "utils/IntraComm.hpp"
23#include "utils/assertion.hpp"
24
26
27namespace precice::partition {
28
34
36{
38
39 prepare();
40
41 if (_m2ns.empty())
42 return;
43
44 // Temporary globalMesh such that the primary rank also keeps his local mesh
45 mesh::Mesh globalMesh(_mesh->getName(), _mesh->getDimensions(), mesh::Mesh::MESH_ID_UNDEFINED);
46 bool hasMeshBeenGathered = false;
47
48 bool twoLevelInitAlreadyUsed = false;
49
50 for (auto &m2n : _m2ns) {
51 if (m2n->usesTwoLevelInitialization()) {
52
53 PRECICE_CHECK(not twoLevelInitAlreadyUsed, "Two-level initialization does not yet support multiple receivers of a provided mesh. "
54 "Please either switch two-level initialization off in your m2n definition, or "
55 "adapt your mesh setup such that each provided mesh is only received by maximum one "
56 "participant.");
57 twoLevelInitAlreadyUsed = true;
58
59 Event e("partition.broadcastMeshPartitions." + _mesh->getName(), profiling::Synchronize);
60
61 // communicate the total number of vertices to the other participants primary rank
63 _m2ns[0]->getPrimaryRankCommunication()->send(_mesh->getGlobalNumberOfVertices(), 0);
64 }
65
66 // the min and max of global vertex IDs of this rank's partition
67 PRECICE_ASSERT(_mesh->getVertexOffsets().size() == static_cast<decltype(_mesh->getVertexOffsets().size())>(utils::IntraComm::getSize()));
68 const int vertexOffset = _mesh->getVertexOffsets()[utils::IntraComm::getRank()];
69 const int minGlobalVertexID = vertexOffset - _mesh->nVertices();
70 const int maxGlobalVertexID = vertexOffset - 1;
71
72 // each rank sends its min/max global vertex index to connected remote ranks
73 _m2ns[0]->broadcastSend(minGlobalVertexID, *_mesh);
74 _m2ns[0]->broadcastSend(maxGlobalVertexID, *_mesh);
75
76 // each rank sends its mesh partition to connected remote ranks
77 _m2ns[0]->broadcastSendMesh(*_mesh);
78
79 } else {
80
81 if (not hasMeshBeenGathered) {
82 // Gather mesh
83 Event e("partition.gatherMesh." + _mesh->getName(), profiling::Synchronize);
85 globalMesh.addMesh(*_mesh); // Add local primary mesh to global mesh
86 }
87 PRECICE_INFO("Gather mesh {}", _mesh->getName());
91
92 for (Rank secondaryRank : utils::IntraComm::allSecondaryRanks()) {
93 com::receiveMesh(*utils::IntraComm::getCommunication(), secondaryRank, globalMesh);
94 PRECICE_DEBUG("Received sub-mesh, from secondary rank: {}, global vertexCount: {}", secondaryRank, globalMesh.nVertices());
95 }
96 }
99 }
100 hasMeshBeenGathered = true;
101 }
102
103 // Send (global) Mesh
104 PRECICE_INFO("Send global mesh {}", _mesh->getName());
105 Event e("partition.sendGlobalMesh." + _mesh->getName(), profiling::Synchronize);
106
108 PRECICE_CHECK(globalMesh.nVertices() > 0,
109 "The provided mesh \"{}\" is empty. Please set the mesh using setMeshVertex()/setMeshVertices() prior to calling initialize().",
110 globalMesh.getName());
111 com::sendMesh(*m2n->getPrimaryRankCommunication(), 0, globalMesh);
112 }
113 }
114 }
115}
116
118{
120 PRECICE_INFO("Prepare partition for mesh {}", _mesh->getName());
121 Event e("partition.prepareMesh." + _mesh->getName(), profiling::Synchronize);
122
123 PRECICE_ASSERT(_mesh->getGlobalNumberOfVertices() <= 0, _mesh->getGlobalNumberOfVertices());
124 PRECICE_ASSERT(_mesh->getVertexOffsets().empty(), _mesh->getVertexOffsets());
125 PRECICE_ASSERT(_mesh->getVertexDistribution().empty(), _mesh->getVertexDistribution());
126
127 int numberOfVertices = _mesh->nVertices();
128
131
132 // set globals IDs on primary rank
133 for (int i = 0; i < numberOfVertices; i++) {
134 _mesh->vertex(i).setGlobalIndex(i);
135 }
136
138 vertexOffsets[0] = numberOfVertices;
139 int globalNumberOfVertices = numberOfVertices;
140
141 // receive number of secondary vertices and fill vertex offsets
142 for (Rank secondaryRank : utils::IntraComm::allSecondaryRanks()) {
143 int numberOfSecondaryRankVertices = -1;
144 utils::IntraComm::getCommunication()->receive(numberOfSecondaryRankVertices, secondaryRank);
145 vertexOffsets[secondaryRank] = numberOfSecondaryRankVertices + vertexOffsets[secondaryRank - 1];
146 utils::IntraComm::getCommunication()->send(globalNumberOfVertices, secondaryRank);
147 globalNumberOfVertices += numberOfSecondaryRankVertices;
148 }
149 PRECICE_ASSERT(std::all_of(vertexOffsets.begin(), vertexOffsets.end(), [](auto i) { return i >= 0; }));
150 _mesh->setVertexOffsets(vertexOffsets);
151
152 // set and broadcast global number of vertices
153 _mesh->setGlobalNumberOfVertices(globalNumberOfVertices);
154 PRECICE_DEBUG("Broadcast global number of vertices: {}", globalNumberOfVertices);
155 utils::IntraComm::getCommunication()->broadcast(globalNumberOfVertices);
156
157 // broadcast vertex offsets to secondary ranks
158 PRECICE_DEBUG("My vertex offsets: {}", vertexOffsets);
159 utils::IntraComm::getCommunication()->broadcast(vertexOffsets);
160
161 // fill vertex distribution
162 if (std::any_of(_m2ns.begin(), _m2ns.end(), [](const m2n::PtrM2N &m2n) { return not m2n->usesTwoLevelInitialization(); }) && utils::IntraComm::isPrimary()) {
163 PRECICE_DEBUG("Fill vertex distribution");
164 PRECICE_ASSERT(_mesh->getVertexDistribution().empty());
166 mesh::Mesh::VertexDistribution vertexDistribution;
167 auto &localIds = vertexDistribution[0];
168 localIds.resize(vertexOffsets[0]);
169 std::iota(localIds.begin(), localIds.end(), 0);
170
171 for (Rank secondaryRank : utils::IntraComm::allSecondaryRanks()) {
172 // This always creates an entry for each secondary rank
173 auto &secondaryIds = vertexDistribution[secondaryRank];
174 for (int i = vertexOffsets[secondaryRank - 1]; i < vertexOffsets[secondaryRank]; i++) {
175 secondaryIds.push_back(i);
176 }
177 }
178 PRECICE_ASSERT(vertexDistribution.size() == static_cast<mesh::Mesh::VertexDistribution::size_type>(utils::IntraComm::getSize()));
179 _mesh->setVertexDistribution(std::move(vertexDistribution));
180 }
181 } else if (utils::IntraComm::isSecondary()) {
182
183 // send number of own vertices
184 PRECICE_DEBUG("Send number of vertices: {}", numberOfVertices);
185 utils::IntraComm::getCommunication()->send(numberOfVertices, 0);
186
187 // set global IDs
188 int globalVertexCounter = -1;
189 utils::IntraComm::getCommunication()->receive(globalVertexCounter, 0);
190 PRECICE_DEBUG("Set global vertex indices");
191 for (int i = 0; i < numberOfVertices; i++) {
192 _mesh->vertex(i).setGlobalIndex(globalVertexCounter + i);
193 }
194
195 // set global number of vertices
196 int globalNumberOfVertices = -1;
197 utils::IntraComm::getCommunication()->broadcast(globalNumberOfVertices, 0);
198 PRECICE_ASSERT(globalNumberOfVertices != -1);
199 _mesh->setGlobalNumberOfVertices(globalNumberOfVertices);
200
201 // receive set vertex offsets
202 mesh::Mesh::VertexOffsets vertexOffsets;
203 utils::IntraComm::getCommunication()->broadcast(vertexOffsets, 0);
204 PRECICE_DEBUG("My vertex offsets: {}", vertexOffsets);
205 PRECICE_ASSERT(_mesh->getVertexOffsets().empty());
206 _mesh->setVertexOffsets(std::move(vertexOffsets));
207
208 } else {
209 // The only rank of the participant contains all vertices
210 _mesh->setVertexDistribution([&] {
211 mesh::Mesh::VertexDistribution vertexDistribution;
212 for (int i = 0; i < numberOfVertices; i++) {
213 vertexDistribution[0].push_back(i);
214 _mesh->vertex(i).setGlobalIndex(i);
215 }
216 return vertexDistribution;
217 }());
218 _mesh->setVertexOffsets({numberOfVertices});
219 _mesh->setGlobalNumberOfVertices(numberOfVertices);
220 PRECICE_ASSERT(!_mesh->getVertexDistribution().empty());
221 }
222
223 PRECICE_DEBUG("Set owner information");
224 for (mesh::Vertex &v : _mesh->vertices()) {
225 v.setOwner(true);
226 }
227
228 PRECICE_ASSERT(_mesh->getGlobalNumberOfVertices() > 0);
229 PRECICE_ASSERT(!_mesh->getVertexOffsets().empty());
230}
231
233{
235 for (const auto &m2n : _m2ns) {
236 if (m2n->usesTwoLevelInitialization()) {
237 // @todo this will probably not work for more than one m2n
238 PRECICE_ASSERT(_m2ns.size() <= 1);
239 // receive communication map from all remote connected ranks
240 m2n->gatherAllCommunicationMap(_mesh->getCommunicationMap(), *_mesh);
241 }
242 }
243}
244
246{
248
249 _mesh->clearPartitioning();
250
251 if (_m2ns.empty())
252 return;
253
254 //@todo coupling mode
255
256 //@todo treatment of multiple m2ns
257 if (not _m2ns[0]->usesTwoLevelInitialization())
258 return;
259
260 // each secondary rank sends its bb to the primary rank
261 if (utils::IntraComm::isSecondary()) { // secondary
262 PRECICE_ASSERT(_mesh->getBoundingBox().getDimension() == _mesh->getDimensions(), "The boundingbox of the local mesh is invalid!");
264 } else { // Primary
265
268
269 // to store the collection of bounding boxes
271 mesh::BoundingBox bb(_mesh->getDimensions());
272 bbm.emplace(0, _mesh->getBoundingBox());
273 PRECICE_ASSERT(!bbm.empty(), "The bounding box of the local mesh is invalid!");
274
275 // primary rank receives bbs from secondary ranks and stores them in bbm
276 for (Rank secondaryRank : utils::IntraComm::allSecondaryRanks()) {
277 // initialize bbm
278 bbm.emplace(secondaryRank, bb);
279 com::receiveBoundingBox(*utils::IntraComm::getCommunication(), secondaryRank, bbm.at(secondaryRank));
280 }
281
282 // primary rank sends number of ranks and bbm to the other primary rank
283 _m2ns[0]->getPrimaryRankCommunication()->send(utils::IntraComm::getSize(), 0);
284 com::sendBoundingBoxMap(*_m2ns[0]->getPrimaryRankCommunication(), 0, bbm);
285 }
286
287 // size of the feedbackmap
288 int remoteConnectionMapSize = 0;
289
291
292 // primary rank receives feedback map (map of other participant ranks -> connected ranks at this participant)
293 // from other participants primary rank
294 std::vector<Rank> connectedRanksList = _m2ns[0]->getPrimaryRankCommunication()->receiveRange(0, com::asVector<Rank>);
295 remoteConnectionMapSize = connectedRanksList.size();
296
297 mesh::Mesh::CommunicationMap remoteConnectionMap;
298 for (auto &rank : connectedRanksList) {
299 remoteConnectionMap[rank] = {-1};
300 }
301 if (remoteConnectionMapSize != 0) {
302 com::receiveConnectionMap(*_m2ns[0]->getPrimaryRankCommunication(), 0, remoteConnectionMap);
303 }
304
305 // broadcast the received feedbackMap
306 utils::IntraComm::getCommunication()->broadcast(connectedRanksList);
307 if (remoteConnectionMapSize != 0) {
309 }
310
311 // primary rank checks which ranks are connected to it
312 PRECICE_ASSERT(_mesh->getConnectedRanks().empty());
313 _mesh->setConnectedRanks([&] {
314 std::vector<Rank> ranks;
315 for (const auto &remoteRank : remoteConnectionMap) {
316 for (const auto &includedRank : remoteRank.second) {
317 if (utils::IntraComm::getRank() == includedRank) {
318 ranks.push_back(remoteRank.first);
319 }
320 }
321 }
322 return ranks;
323 }());
324
325 } else { // Secondary rank
326 std::vector<Rank> connectedRanksList;
327 utils::IntraComm::getCommunication()->broadcast(connectedRanksList, 0);
328
329 mesh::Mesh::CommunicationMap remoteConnectionMap;
330 if (!connectedRanksList.empty()) {
331 for (Rank rank : connectedRanksList) {
332 remoteConnectionMap[rank] = {-1};
333 }
335 }
336
337 PRECICE_ASSERT(_mesh->getConnectedRanks().empty());
338 _mesh->setConnectedRanks([&] {
339 std::vector<Rank> ranks;
340 for (const auto &remoteRank : remoteConnectionMap) {
341 for (int includedRanks : remoteRank.second) {
342 if (utils::IntraComm::getRank() == includedRanks) {
343 ranks.push_back(remoteRank.first);
344 }
345 }
346 }
347 return ranks;
348 }());
349 }
350}
351
352} // namespace precice::partition
#define PRECICE_DEBUG(...)
Definition LogMacros.hpp:61
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:92
#define PRECICE_INFO(...)
Definition LogMacros.hpp:14
#define PRECICE_CHECK(check,...)
Definition LogMacros.hpp:32
T all_of(T... args)
#define PRECICE_ASSERT(...)
Definition assertion.hpp:85
T at(T... args)
T begin(T... args)
An axis-aligned bounding box around a (partition of a) mesh.
Container and creator for meshes.
Definition Mesh.hpp:38
std::map< Rank, std::vector< VertexID > > CommunicationMap
A mapping from remote local ranks to the IDs that must be communicated.
Definition Mesh.hpp:51
void addMesh(Mesh &deltaMesh)
Definition Mesh.cpp:332
const std::string & getName() const
Returns the name of the mesh, as set in the config file.
Definition Mesh.cpp:220
static constexpr MeshID MESH_ID_UNDEFINED
Use if the id of the mesh is not necessary.
Definition Mesh.hpp:57
std::map< Rank, std::vector< VertexID > > VertexDistribution
A mapping from rank to used (not necessarily owned) vertex IDs.
Definition Mesh.hpp:48
std::size_t nVertices() const
Returns the number of vertices.
Definition Mesh.cpp:65
std::map< int, BoundingBox > BoundingBoxMap
Definition Mesh.hpp:45
std::vector< int > VertexOffsets
Definition Mesh.hpp:54
Vertex of a mesh.
Definition Vertex.hpp:16
Partition(mesh::PtrMesh mesh)
Constructor.
Definition Partition.cpp:7
std::vector< m2n::PtrM2N > _m2ns
m2n connection to each connected participant
Definition Partition.hpp:69
void compute() override
All distribution data structures are set up.
void communicate() override
The mesh is gathered and sent to another participant (if required)
void compareBoundingBoxes() override
Intersections between bounding boxes around each rank are computed.
static int getSize()
Number of ranks. This includes ranks from both participants, e.g. minimal size is 2.
Definition IntraComm.cpp:47
static Rank getRank()
Current rank.
Definition IntraComm.cpp:42
static bool isPrimary()
True if this process is running the primary rank.
Definition IntraComm.cpp:52
static auto allSecondaryRanks()
Returns an iterable range over salve ranks [1, _size)
Definition IntraComm.hpp:37
static bool isSecondary()
True if this process is running a secondary rank.
Definition IntraComm.cpp:57
static com::PtrCommunication & getCommunication()
Intra-participant communication.
Definition IntraComm.hpp:31
T emplace(T... args)
T empty(T... args)
T end(T... args)
T iota(T... args)
void sendMesh(Communication &communication, int rankReceiver, const mesh::Mesh &mesh)
Definition Extra.cpp:8
void sendBoundingBox(Communication &communication, int rankReceiver, const mesh::BoundingBox &bb)
Definition Extra.cpp:48
constexpr auto asVector
Allows to use Communication::AsVectorTag in a less verbose way.
void receiveConnectionMap(Communication &communication, int rankSender, mesh::Mesh::ConnectionMap &cm)
Definition Extra.cpp:33
void receiveMesh(Communication &communication, int rankSender, mesh::Mesh &mesh)
Definition Extra.cpp:13
void broadcastSendConnectionMap(Communication &communication, const mesh::Mesh::ConnectionMap &cm)
Definition Extra.cpp:38
void sendBoundingBoxMap(Communication &communication, int rankReceiver, const mesh::Mesh::BoundingBoxMap &bbm)
Definition Extra.cpp:58
void broadcastReceiveConnectionMap(Communication &communication, mesh::Mesh::ConnectionMap &cm)
Definition Extra.cpp:43
void receiveBoundingBox(Communication &communication, int rankSender, mesh::BoundingBox &bb)
Definition Extra.cpp:53
contains the logic of the parallel communication between participants.
Definition BoundM2N.cpp:12
std::shared_ptr< M2N > PtrM2N
provides Mesh, Data and primitives.
std::shared_ptr< Mesh > PtrMesh
contains the partitioning of distributed meshes.
Definition Partition.cpp:5
static constexpr SynchronizeTag Synchronize
Convenience instance of the SynchronizeTag.
Definition Event.hpp:21
int Rank
Definition Types.hpp:37
STL namespace.
T push_back(T... args)
T size(T... args)