preCICE
Loading...
Searching...
No Matches
PointToPointCommunication.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <boost/container/flat_map.hpp>
3#include <boost/io/ios_state.hpp>
4#include <functional>
5#include <iomanip>
6#include <iostream>
7#include <limits>
8#include <map>
9#include <set>
10#include <thread>
11#include <utility>
12#include <vector>
13
15#include "com/Communication.hpp"
17#include "com/Extra.hpp"
18#include "com/Request.hpp"
19#include "logging/LogMacros.hpp"
21#include "mesh/Mesh.hpp"
23#include "profiling/Event.hpp"
24#include "utils/IntraComm.hpp"
25#include "utils/algorithm.hpp"
26#include "utils/assertion.hpp"
27
29
30namespace precice::m2n {
31
33 int rankReceiver,
34 const com::PtrCommunication &communication)
35{
36 communication->send(static_cast<int>(m.size()), rankReceiver);
37
38 for (auto const &i : m) {
39 auto const &rank = i.first;
40 auto const &indices = i.second;
41 communication->send(rank, rankReceiver);
42 communication->sendRange(indices, rankReceiver);
43 }
44}
45
47 int rankSender,
48 const com::PtrCommunication &communication)
49{
50 m.clear();
51 int size = 0;
52 communication->receive(size, rankSender);
53
54 while (size--) {
55 Rank rank = -1;
56 communication->receive(rank, rankSender);
57 m[rank] = communication->receiveRange(rankSender, com::asVector<int>);
58 }
59}
60
63{
64 communication->broadcast(static_cast<int>(m.size()));
65
66 for (auto const &i : m) {
67 auto const &rank = i.first;
68 auto const &indices = i.second;
69 communication->broadcast(rank);
70 communication->broadcast(indices);
71 }
72}
73
75 int rankBroadcaster,
77{
78 m.clear();
79 int size = 0;
80 communication->broadcast(size, rankBroadcaster);
81
82 while (size--) {
83 Rank rank = -1;
84 communication->broadcast(rank, rankBroadcaster);
85 communication->broadcast(m[rank], rankBroadcaster);
86 }
87}
88
90{
92 // Broadcast (send) vertex distributions.
94 } else if (utils::IntraComm::isSecondary()) {
95 // Broadcast (receive) vertex distributions.
97 }
98}
99
100void print(std::map<int, std::vector<int>> const &m)
101{
102 std::ostringstream oss;
103
104 oss << "rank: " << utils::IntraComm::getRank() << "\n";
105
106 for (auto &i : m) {
107 for (auto &j : i.second) {
108 oss << i.first << ":" << j << '\n'; // prints rank:index
109 }
110 }
111
113 utils::IntraComm::getCommunication()->send(oss.str(), 0);
114 } else {
115
116 std::string s;
117
119 utils::IntraComm::getCommunication()->receive(s, rank);
120
121 oss << s;
122 }
123
124 std::cout << oss.str();
125 }
126}
127
128void printCommunicationPartnerCountStats(std::map<int, std::vector<int>> const &m)
129{
130 int size = m.size();
131
133 size_t count = 0;
134 size_t maximum = std::numeric_limits<size_t>::min();
135 size_t minimum = std::numeric_limits<size_t>::max();
136 size_t total = size;
137
138 if (size) {
139 maximum = std::max(maximum, static_cast<size_t>(size));
140 minimum = std::min(minimum, static_cast<size_t>(size));
141 count++;
142 }
143
145 utils::IntraComm::getCommunication()->receive(size, rank);
146
147 total += size;
148
149 if (size) {
150 maximum = std::max(maximum, static_cast<size_t>(size));
151 minimum = std::min(minimum, static_cast<size_t>(size));
152 count++;
153 }
154 }
155
156 if (minimum > maximum)
157 minimum = maximum;
158
159 auto average = static_cast<double>(total);
160 if (count != 0) {
161 average /= count;
162 }
163
164 boost::io::ios_all_saver ias{std::cout};
165 std::cout << std::fixed << std::setprecision(3) //
166 << "Number of Communication Partners per Interface Process:"
167 << "\n"
168 << " Total: " << total << "\n"
169 << " Maximum: " << maximum << "\n"
170 << " Minimum: " << minimum << "\n"
171 << " Average: " << average << "\n"
172 << "Number of Interface Processes: " << count << "\n"
173 << '\n';
174 } else {
176 utils::IntraComm::getCommunication()->send(size, 0);
177 }
178}
179
180void printLocalIndexCountStats(std::map<int, std::vector<int>> const &m)
181{
182 int size = 0;
183
184 for (auto &i : m) {
185 size += i.second.size();
186 }
187
189 size_t count = 0;
190 size_t maximum = std::numeric_limits<size_t>::min();
191 size_t minimum = std::numeric_limits<size_t>::max();
192 size_t total = size;
193
194 if (size) {
195 maximum = std::max(maximum, static_cast<size_t>(size));
196 minimum = std::min(minimum, static_cast<size_t>(size));
197
198 count++;
199 }
200
202 utils::IntraComm::getCommunication()->receive(size, rank);
203
204 total += size;
205
206 if (size) {
207 maximum = std::max(maximum, static_cast<size_t>(size));
208 minimum = std::min(minimum, static_cast<size_t>(size));
209
210 count++;
211 }
212 }
213
214 if (minimum > maximum)
215 minimum = maximum;
216
217 auto average = static_cast<double>(total);
218 if (count != 0) {
219 average /= count;
220 }
221
222 boost::io::ios_all_saver ias{std::cout};
223 std::cout << std::fixed << std::setprecision(3) //
224 << "Number of LVDIs per Interface Process:"
225 << "\n"
226 << " Total: " << total << '\n'
227 << " Maximum: " << maximum << '\n'
228 << " Minimum: " << minimum << '\n'
229 << " Average: " << average << '\n'
230 << "Number of Interface Processes: " << count << '\n'
231 << '\n';
232 } else {
234
235 utils::IntraComm::getCommunication()->send(size, 0);
236 }
237}
238
261std::map<int, std::vector<int>> buildCommunicationMap(
262 // `thisVertexDistribution' is input vertex distribution from this participant.
263 mesh::Mesh::VertexDistribution const &thisVertexDistribution,
264 // `otherVertexDistribution' is input vertex distribution from other participant.
265 mesh::Mesh::VertexDistribution const &otherVertexDistribution,
266 int thisRank = utils::IntraComm::getRank())
267{
268 auto iterator = thisVertexDistribution.find(thisRank);
269 if (iterator == thisVertexDistribution.end()) {
270 return {};
271 }
272
273 std::map<int, std::vector<int>> communicationMap;
274 // first a safety check, that we are actually sorted, as the function below operates
275 // on sorted data sets
276 PRECICE_ASSERT(std::is_sorted(iterator->second.begin(), iterator->second.end()));
277
278 // now we iterate over all other vertex distributions to compute the intersection
279 for (const auto &[rank, vertices] : otherVertexDistribution) {
280 // first a safety check, that we are actually sorted, as the function below operates
281 // on sorted data sets
282 PRECICE_ASSERT(std::is_sorted(vertices.begin(), vertices.end()));
283
284 // before starting to compute an actual intersection, we first check if elements can
285 // possibly be in both data sets by comparing upper and lower index bounds of both
286 // data sets. For typical partitioning schemes, each rank only exchanges data with
287 // a few neighbors such that this check already filters out a significant amount of
288 // computations
289 if (iterator->second.empty() || vertices.empty() || (vertices.back() < iterator->second.at(0)) || (vertices.at(0) > iterator->second.back())) {
290 // in this case there is nothing to be done
291 continue;
292 }
293 // we have an intersection, let's compute it
294 std::vector<int> inters;
295 // the actual worker function, which gives us the indices of intersecting elements
296 // have a look at the documentation of the function for more details
297 precice::utils::set_intersection_indices(iterator->second.begin(), iterator->second.begin(), iterator->second.end(),
298 vertices.begin(), vertices.end(),
299 std::back_inserter(inters));
300 // we have the results, now commit it into the final map
301 if (!inters.empty()) {
302 communicationMap.insert({rank, std::move(inters)});
303 }
304 }
305 return communicationMap;
306}
307
309 com::PtrCommunicationFactory communicationFactory,
310 mesh::PtrMesh mesh)
311 : DistributedCommunication(std::move(mesh)),
312 _communicationFactory(std::move(communicationFactory))
313{
314}
315
316PointToPointCommunication::~PointToPointCommunication()
317{
318 PRECICE_TRACE(_isConnected);
320}
321
322bool PointToPointCommunication::isConnected() const
323{
324 return _isConnected;
325}
326
327void PointToPointCommunication::acceptConnection(std::string const &acceptorName,
328 std::string const &requesterName)
329{
330 PRECICE_TRACE(acceptorName, requesterName);
331 PRECICE_ASSERT(not isConnected(), "Already connected.");
332
333 mesh::Mesh::VertexDistribution vertexDistribution = _mesh->getVertexDistribution();
334 mesh::Mesh::VertexDistribution requesterVertexDistribution;
335
337 PRECICE_DEBUG("Exchange vertex distribution between both primary ranks");
338 Event e0("m2n.exchangeVertexDistribution");
339 // Establish connection between participants' primary processes.
340 auto c = _communicationFactory->newCommunication();
341
342 c->acceptConnection(acceptorName, requesterName, "TMP-PRIMARYCOM-" + _mesh->getName(), utils::IntraComm::getRank());
343
344 // Exchange vertex distributions.
345 m2n::send(vertexDistribution, 0, c);
346 m2n::receive(requesterVertexDistribution, 0, c);
347 }
348
349 PRECICE_DEBUG("Broadcast vertex distributions");
350 Event e1("m2n.broadcastVertexDistributions", profiling::Synchronize);
351 m2n::broadcast(vertexDistribution);
353 _mesh->setVertexDistribution(vertexDistribution);
354 }
355 m2n::broadcast(requesterVertexDistribution);
356 e1.stop();
357
358 // Local (for process rank in the current participant) communication map that
359 // defines a mapping from a process rank in the remote participant to an array
360 // of local data indices, which define a subset of local (for process rank in
361 // the current participant) data to be communicated between the current
362 // process rank and the remote process rank.
363 //
364 // Example. Assume that the current process rank is 3. Assume that its
365 // `communicationMap' is
366 //
367 // 1 -> {1, 3}
368 // 4 -> {0, 2}
369 //
370 // then it means that the current process (with rank 3)
371 // - has to communicate (send/receive) data with local indices 1 and 3 with
372 // the remote process with rank 1;
373 // - has to communicate (send/receive) data with local indices 0 and 2 with
374 // the remote process with rank 4.
375 Event e2("m2n.buildCommunicationMap", profiling::Synchronize);
376 std::map<int, std::vector<int>> communicationMap = m2n::buildCommunicationMap(
377 vertexDistribution, requesterVertexDistribution);
378 e2.stop();
379
380// Print `communicationMap'.
381#ifdef P2P_LCM_PRINT
382 PRECICE_DEBUG("Print communication map");
383 print(communicationMap);
384#endif
385
386// Print statistics of `communicationMap'.
387#ifdef P2P_LCM_PRINT_STATS
388 PRECICE_DEBUG("Print communication map statistics");
389 printCommunicationPartnerCountStats(communicationMap);
390 printLocalIndexCountStats(communicationMap);
391#endif
392
393 Event e4("m2n.createCommunications");
394 e4.addData("Connections", communicationMap.size());
395 if (communicationMap.empty()) {
396 _isConnected = true;
397 return;
398 }
399
400 PRECICE_DEBUG("Create and connect communication");
401 _communication = _communicationFactory->newCommunication();
402
403 // Accept point-to-point connections (as server) between the current acceptor
404 // process (in the current participant) with rank `utils::IntraComm::getRank()'
405 // and (multiple) requester processes (in the requester participant).
406 _communication->acceptConnectionAsServer(acceptorName,
407 requesterName,
408 _mesh->getName(),
410 communicationMap.size());
411
412 PRECICE_DEBUG("Store communication map");
413 for (auto const &comMap : communicationMap) {
414 int globalRequesterRank = comMap.first;
415 auto indices = std::move(communicationMap[globalRequesterRank]);
416
417 _mappings.push_back({globalRequesterRank, std::move(indices), com::PtrRequest(), {}});
418 }
419 e4.stop();
420 _isConnected = true;
421}
422
423void PointToPointCommunication::acceptPreConnection(std::string const &acceptorName,
424 std::string const &requesterName)
425{
426 PRECICE_TRACE(acceptorName, requesterName);
427 PRECICE_ASSERT(not isConnected(), "Already connected.");
428
429 const std::vector<int> &localConnectedRanks = _mesh->getConnectedRanks();
430
431 if (localConnectedRanks.empty()) {
432 _isConnected = true;
433 return;
434 }
435
436 _communication = _communicationFactory->newCommunication();
437
438 _communication->acceptConnectionAsServer(
439 acceptorName,
440 requesterName,
441 _mesh->getName(),
443 localConnectedRanks.size());
444
445 _connectionDataVector.reserve(localConnectedRanks.size());
446
447 for (int connectedRank : localConnectedRanks) {
448 _connectionDataVector.push_back({connectedRank, com::PtrRequest()});
449 }
450
451 _isConnected = true;
452}
453
454void PointToPointCommunication::requestConnection(std::string const &acceptorName,
455 std::string const &requesterName)
456{
457 PRECICE_TRACE(acceptorName, requesterName);
458 PRECICE_ASSERT(not isConnected(), "Already connected.");
459
460 mesh::Mesh::VertexDistribution vertexDistribution = _mesh->getVertexDistribution();
461 mesh::Mesh::VertexDistribution acceptorVertexDistribution;
462
464 PRECICE_DEBUG("Exchange vertex distribution between both primary ranks");
465 Event e0("m2n.exchangeVertexDistribution");
466 // Establish connection between participants' primary processes.
467 auto c = _communicationFactory->newCommunication();
468 c->requestConnection(acceptorName, requesterName,
469 "TMP-PRIMARYCOM-" + _mesh->getName(),
470 0, 1);
471
472 // Exchange vertex distributions.
473 m2n::receive(acceptorVertexDistribution, 0, c);
474 m2n::send(vertexDistribution, 0, c);
475 }
476
477 PRECICE_DEBUG("Broadcast vertex distributions");
478 Event e1("m2n.broadcastVertexDistributions", profiling::Synchronize);
479 m2n::broadcast(vertexDistribution);
481 _mesh->setVertexDistribution(vertexDistribution);
482 }
483 m2n::broadcast(acceptorVertexDistribution);
484 e1.stop();
485
486 // Local (for process rank in the current participant) communication map that
487 // defines a mapping from a process rank in the remote participant to an array
488 // of local data indices, which define a subset of local (for process rank in
489 // the current participant) data to be communicated between the current
490 // process rank and the remote process rank.
491 //
492 // Example. Assume that the current process rank is 3. Assume that its
493 // `communicationMap' is
494 //
495 // 1 -> {1, 3}
496 // 4 -> {0, 2}
497 //
498 // then it means that the current process (with rank 3)
499 // - has to communicate (send/receive) data with local indices 1 and 3 with
500 // the remote process with rank 1;
501 // - has to communicate (send/receive) data with local indices 0 and 2 with
502 // the remote process with rank 4.
503 Event e2("m2n.buildCommunicationMap", profiling::Synchronize);
504 std::map<int, std::vector<int>> communicationMap = m2n::buildCommunicationMap(
505 vertexDistribution, acceptorVertexDistribution);
506 e2.stop();
507
508// Print `communicationMap'.
509#ifdef P2P_LCM_PRINT
510 PRECICE_DEBUG("Print communication map");
511 print(communicationMap);
512#endif
513
514// Print statistics of `communicationMap'.
515#ifdef P2P_LCM_PRINT_STATS
516 PRECICE_DEBUG("Print communication map statistics");
517 printCommunicationPartnerCountStats(communicationMap);
518 printLocalIndexCountStats(communicationMap);
519#endif
520
521 Event e4("m2n.createCommunications");
522 e4.addData("Connections", communicationMap.size());
523 if (communicationMap.empty()) {
524 _isConnected = true;
525 return;
526 }
527
528 std::vector<com::PtrRequest> requests;
529 requests.reserve(communicationMap.size());
530
531 std::set<int> acceptingRanks;
532 for (auto &i : communicationMap)
533 acceptingRanks.emplace(i.first);
534
535 PRECICE_DEBUG("Create and connect communication");
536 _communication = _communicationFactory->newCommunication();
537 // Request point-to-point connections (as client) between the current
538 // requester process (in the current participant) and (multiple) acceptor
539 // processes (in the acceptor participant) to ranks `accceptingRanks'
540 // according to `communicationMap`.
541 _communication->requestConnectionAsClient(acceptorName, requesterName,
542 _mesh->getName(),
543 acceptingRanks, utils::IntraComm::getRank());
544
545 PRECICE_DEBUG("Store communication map");
546 for (auto &i : communicationMap) {
547 auto globalAcceptorRank = i.first;
548 auto indices = std::move(i.second);
549
550 _mappings.push_back({globalAcceptorRank, std::move(indices), com::PtrRequest(), {}});
551 }
552 e4.stop();
553 _isConnected = true;
554}
555
556void PointToPointCommunication::requestPreConnection(std::string const &acceptorName,
557 std::string const &requesterName)
558{
559 PRECICE_TRACE(acceptorName, requesterName);
560 PRECICE_ASSERT(not isConnected(), "Already connected.");
561
562 std::vector<int> localConnectedRanks = _mesh->getConnectedRanks();
563
564 if (localConnectedRanks.empty()) {
565 _isConnected = true;
566 return;
567 }
568
569 std::vector<com::PtrRequest> requests;
570 requests.reserve(localConnectedRanks.size());
571 _connectionDataVector.reserve(localConnectedRanks.size());
572
573 std::set<int> acceptingRanks(localConnectedRanks.begin(), localConnectedRanks.end());
574
575 _communication = _communicationFactory->newCommunication();
576 _communication->requestConnectionAsClient(acceptorName, requesterName,
577 _mesh->getName(),
578 acceptingRanks, utils::IntraComm::getRank());
579
580 for (auto &connectedRank : localConnectedRanks) {
581 _connectionDataVector.push_back({connectedRank, com::PtrRequest()});
582 }
583 _isConnected = true;
584}
585
586void PointToPointCommunication::completeSecondaryRanksConnection()
587{
588 mesh::Mesh::CommunicationMap localCommunicationMap = _mesh->getCommunicationMap();
589
590 for (auto &i : _connectionDataVector) {
591 _mappings.push_back({i.remoteRank, std::move(localCommunicationMap[i.remoteRank]), i.request, {}});
592 }
593}
594
595void PointToPointCommunication::closeConnection()
596{
598
599 if (not isConnected())
600 return;
601
602 checkBufferedRequests(true);
603
604 _communication.reset();
605 _mappings.clear();
606 _connectionDataVector.clear();
607 _isConnected = false;
608}
609
610void PointToPointCommunication::send(precice::span<double const> itemsToSend, int valueDimension)
611{
612
613 if (_mappings.empty() || itemsToSend.empty()) {
614 return;
615 }
616
617 for (auto &mapping : _mappings) {
618 auto buffer = std::make_shared<std::vector<double>>();
619 buffer->reserve(mapping.indices.size() * valueDimension);
620 for (auto index : mapping.indices) {
621 for (int d = 0; d < valueDimension; ++d) {
622 buffer->push_back(itemsToSend[index * valueDimension + d]);
623 }
624 }
625 auto request = _communication->aSend(span<const double>{*buffer}, mapping.remoteRank);
626 bufferedRequests.emplace_back(request, buffer);
627 }
628 checkBufferedRequests(false);
629}
630
631void PointToPointCommunication::receive(precice::span<double> itemsToReceive, int valueDimension)
632{
633 if (_mappings.empty() || itemsToReceive.empty()) {
634 return;
635 }
636
637 std::fill(itemsToReceive.begin(), itemsToReceive.end(), 0.0);
638
639 for (auto &mapping : _mappings) {
640 mapping.recvBuffer.resize(mapping.indices.size() * valueDimension);
641 mapping.request = _communication->aReceive(span<double>{mapping.recvBuffer}, mapping.remoteRank);
642 }
643
644 for (auto &mapping : _mappings) {
645 mapping.request->wait();
646
647 int i = 0;
648 for (auto index : mapping.indices) {
649 for (int d = 0; d < valueDimension; ++d) {
650 itemsToReceive[index * valueDimension + d] += mapping.recvBuffer[i * valueDimension + d];
651 }
652 i++;
653 }
654 }
655}
656
657void PointToPointCommunication::broadcastSend(int itemToSend)
658{
659 for (auto &connectionData : _connectionDataVector) {
660 _communication->send(itemToSend, connectionData.remoteRank);
661 }
662}
663
664void PointToPointCommunication::broadcastReceiveAll(std::vector<int> &itemToReceive)
665
666{
667 int data = 0;
668 for (auto &connectionData : _connectionDataVector) {
669 _communication->receive(data, connectionData.remoteRank);
670 itemToReceive.push_back(data);
671 }
672}
673
674void PointToPointCommunication::broadcastSendMesh()
675{
676 for (auto &connectionData : _connectionDataVector) {
677 com::sendMesh(*_communication, connectionData.remoteRank, *_mesh);
678 }
679}
680
681void PointToPointCommunication::broadcastReceiveAllMesh()
682{
683 for (auto &connectionData : _connectionDataVector) {
684 com::receiveMesh(*_communication, connectionData.remoteRank, *_mesh);
685 }
686}
687
688void PointToPointCommunication::scatterAllCommunicationMap(CommunicationMap &localCommunicationMap)
689{
690 for (auto &connectionData : _connectionDataVector) {
691 _communication->sendRange(localCommunicationMap[connectionData.remoteRank], connectionData.remoteRank);
692 }
693}
694
695void PointToPointCommunication::gatherAllCommunicationMap(CommunicationMap &localCommunicationMap)
696{
697 for (auto &connectionData : _connectionDataVector) {
698 localCommunicationMap[connectionData.remoteRank] = _communication->receiveRange(connectionData.remoteRank, com::asVector<int>);
699 }
700}
701
702void PointToPointCommunication::checkBufferedRequests(bool blocking)
703{
704 PRECICE_TRACE(bufferedRequests.size());
705 do {
706 for (auto it = bufferedRequests.begin(); it != bufferedRequests.end();) {
707 if (it->first->test())
708 it = bufferedRequests.erase(it);
709 else
710 ++it;
711 }
712 if (bufferedRequests.empty())
713 return;
714 if (blocking)
715 std::this_thread::yield(); // give up our time slice, so MPI may work
716 } while (blocking);
717}
718
719} // namespace precice::m2n
#define PRECICE_DEBUG(...)
Definition LogMacros.hpp:61
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:92
#define PRECICE_ASSERT(...)
Definition assertion.hpp:85
Interface for all distributed solver to solver communication classes.
PointToPointCommunication(com::PtrCommunicationFactory communicationFactory, mesh::PtrMesh mesh)
std::map< Rank, std::vector< VertexID > > CommunicationMap
A mapping from remote local ranks to the IDs that must be communicated.
Definition Mesh.hpp:51
std::map< Rank, std::vector< VertexID > > VertexDistribution
A mapping from rank to used (not necessarily owned) vertex IDs.
Definition Mesh.hpp:48
A C++ 11 implementation of the non-owning C++20 std::span type.
Definition span.hpp:284
PRECICE_SPAN_NODISCARD constexpr bool empty() const noexcept
Definition span.hpp:476
constexpr iterator begin() const noexcept
Definition span.hpp:503
constexpr iterator end() const noexcept
Definition span.hpp:505
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
void sendMesh(Communication &communication, int rankReceiver, const mesh::Mesh &mesh)
Definition Extra.cpp:8
constexpr auto asVector
Allows to use Communication::AsVectorTag in a less verbose way.
std::shared_ptr< Request > PtrRequest
void receiveMesh(Communication &communication, int rankSender, mesh::Mesh &mesh)
Definition Extra.cpp:13
virtual void closeConnection()=0
Disconnects from communication space, i.e. participant.
std::shared_ptr< CommunicationFactory > PtrCommunicationFactory
std::shared_ptr< Communication > PtrCommunication
constexpr auto data(C &c) -> decltype(c.data())
Definition span.hpp:194
contains the logic of the parallel communication between participants.
Definition BoundM2N.cpp:12
void print(std::map< int, std::vector< int > > const &m)
void broadcastReceive(mesh::Mesh::VertexDistribution &m, int rankBroadcaster, const com::PtrCommunication &communication=utils::IntraComm::getCommunication())
void printCommunicationPartnerCountStats(std::map< int, std::vector< int > > const &m)
void printLocalIndexCountStats(std::map< int, std::vector< int > > const &m)
void receive(mesh::Mesh::VertexDistribution &m, int rankSender, const com::PtrCommunication &communication)
void broadcast(mesh::Mesh::VertexDistribution &m)
void send(mesh::Mesh::VertexDistribution const &m, int rankReceiver, const com::PtrCommunication &communication)
void broadcastSend(mesh::Mesh::VertexDistribution const &m, const com::PtrCommunication &communication=utils::IntraComm::getCommunication())
contains data mapping from points to meshes.
std::shared_ptr< Mesh > PtrMesh
static constexpr SynchronizeTag Synchronize
Convenience instance of the SynchronizeTag.
Definition Event.hpp:28
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...
Definition algorithm.hpp:33
int Rank
Definition Types.hpp:37