24#if BITPIT_ENABLE_MPI==1
29#if BITPIT_ENABLE_METIS==1
35#include <unordered_set>
36#include <unordered_map>
38#include "bitpit_communications.hpp"
40#include "patch_kernel.hpp"
46using namespace chrono;
61void PatchKernel::initializeCommunicator(MPI_Comm communicator)
64 if (communicator == MPI_COMM_NULL) {
65 m_communicator = communicator;
78 MPI_Comm_dup(communicator, &m_communicator);
81 MPI_Comm_size(m_communicator, &m_nProcessors);
82 MPI_Comm_rank(m_communicator, &m_rank);
85 if (m_nProcessors > 1) {
100 throw std::runtime_error (
"Patch communicator can be set just once");
104 if (communicator == MPI_COMM_NULL) {
105 throw std::runtime_error (
"Patch communicator is not valid");
109 initializeCommunicator(communicator);
130 return m_communicator;
136void PatchKernel::freeCommunicator()
143 MPI_Finalized(&finalizedCalled);
144 if (finalizedCalled) {
148 MPI_Comm_free(&m_communicator);
169 return m_nProcessors;
232int PatchKernel::evalOwner()
const
235 long nGlobalInternalCells = nInternalCells;
237 MPI_Allreduce(MPI_IN_PLACE, &nGlobalInternalCells, 1, MPI_LONG, MPI_SUM,
getCommunicator());
241 if (nGlobalInternalCells > 0) {
242 if (nInternalCells == nGlobalInternalCells) {
247 MPI_Allreduce(MPI_IN_PLACE, &owner, 1, MPI_INT, MPI_MAX,
getCommunicator());
261void PatchKernel::updateOwner()
263 m_owner = evalOwner();
274void PatchKernel::initializeHaloSize(std::size_t haloSize)
276 m_haloSize = haloSize;
289 throw std::runtime_error (
"Halo size can only be set when the patch is all on a single process");
292 if (m_haloSize == haloSize) {
297 if (haloSize > maxHaloSize) {
298 throw std::runtime_error (
"Halo size exceeds the maximum allowed value.");
301 initializeHaloSize(haloSize);
306 updatePartitioningInfo(
true);
353 return m_vertices.end();
357 if (
id != m_lastInternalVertexId) {
358 m_vertices.swap(
id, m_lastInternalVertexId);
365 iterator->setInterior(
false);
368 --m_nInternalVertices;
372 m_firstGhostVertexId = id;
373 if (m_nInternalVertices == 0) {
374 m_lastInternalVertexId = Vertex::NULL_ID;
376 m_lastInternalVertexId = m_vertices.getSizeMarker(m_nInternalVertices - 1, Vertex::NULL_ID);
380 setGhostVertexInfo(
id, owner);
394 return m_vertices.end();
398 if (
id != m_firstGhostVertexId) {
399 m_vertices.swap(
id, m_firstGhostVertexId);
406 iterator->setInterior(
true);
409 ++m_nInternalVertices;
413 m_lastInternalVertexId = id;
414 if (m_nGhostVertices == 0) {
415 m_firstGhostVertexId = Vertex::NULL_ID;
418 ++firstGhostVertexIterator;
419 m_firstGhostVertexId = firstGhostVertexIterator->
getId();
423 unsetGhostVertexInfo(
id);
436 return m_nGhostVertices;
446 return m_vertices[m_firstGhostVertexId];
456 return m_vertices[m_firstGhostVertexId];
477 if (iterator == m_vertices.end()) {
478 throw std::runtime_error(
"Unable to restore the specified vertex: the kernel doesn't contain an entry for that vertex.");
484 _restoreInternalVertex(iterator, coords);
486 _restoreGhostVertex(iterator, coords, owner);
502void PatchKernel::_restoreGhostVertex(
const VertexIterator &iterator,
const std::array<double, 3> &coords,
int owner)
508 Vertex &vertex = *iterator;
509 vertex.
initialize(iterator.getId(), coords,
false);
516 setGhostVertexInfo(vertex.
getId(), owner);
524void PatchKernel::_deleteGhostVertex(
long id)
527 unsetGhostVertexInfo(
id);
530 const Vertex &vertex = m_vertices[id];
534 m_vertices.erase(
id,
true);
536 if (
id == m_firstGhostVertexId) {
541 if (m_vertexIdGenerator) {
542 m_vertexIdGenerator->trash(
id);
553 if (m_nGhostVertices > 0) {
554 return m_vertices.find(m_firstGhostVertexId);
556 return m_vertices.end();
567 return m_vertices.end();
578 if (m_nGhostVertices > 0) {
579 return m_vertices.find(m_firstGhostVertexId);
581 return m_vertices.cend();
592 return m_vertices.cend();
600 if (m_nGhostVertices == 0) {
601 m_firstGhostVertexId = Vertex::NULL_ID;
602 }
else if (m_nInternalVertices == 0) {
604 m_firstGhostVertexId = firstGhostVertexItr->
getId();
606 m_firstGhostVertexId = m_vertices.getSizeMarker(m_nInternalVertices, Vertex::NULL_ID);
620 return m_cells.end();
624 if (
id != m_lastInternalCellId) {
625 m_cells.swap(
id, m_lastInternalCellId);
632 iterator->setInterior(
false);
639 m_firstGhostCellId = id;
640 if (m_nInternalCells == 0) {
641 m_lastInternalCellId = Cell::NULL_ID;
643 m_lastInternalCellId = m_cells.getSizeMarker(m_nInternalCells - 1, Cell::NULL_ID);
647 setGhostCellInfo(
id, owner, haloLayer);
661 return m_cells.end();
665 if (
id != m_firstGhostCellId) {
666 m_cells.swap(
id, m_firstGhostCellId);
673 iterator->setInterior(
true);
680 m_lastInternalCellId = id;
681 if (m_nGhostCells == 0) {
682 m_firstGhostCellId = Cell::NULL_ID;
685 ++firstGhostCellIterator;
686 m_firstGhostCellId = firstGhostCellIterator->
getId();
690 unsetGhostCellInfo(
id);
703 return m_nGhostCells;
723 return m_cells[m_firstGhostCellId];
743 return m_cells[m_firstGhostCellId];
774 return addCell(source, owner, 0,
id);
794 return addCell(source, owner, 0,
id);
815 return addCell(type, owner, 0,
id);
838 return addCell(type, connectivity, owner, 0,
id);
862 return addCell(type, std::move(connectStorage), owner, 0,
id);
888 return addCell(std::move(cell), owner, haloLayer,
id);
914 int connectSize = source.getConnectSize();
915 std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(
new long[connectSize]);
916 if (!source.hasInfo()){
917 std::copy(source.getConnect(), source.getConnect() + connectSize, connectStorage.get());
920 CellIterator iterator =
addCell(source.getType(), std::move(connectStorage), owner, haloLayer,
id);
922 Cell &cell = (*iterator);
924 cell = std::move(source);
950 std::unique_ptr<long[]> connectStorage;
953 connectStorage = std::unique_ptr<long[]>(
new long[connectSize]);
955 connectStorage = std::unique_ptr<long[]>(
nullptr);
958 return addCell(type, std::move(connectStorage), owner, haloLayer,
id);
981 int owner,
int haloLayer,
long id)
983 int connectSize = connectivity.size();
984 std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(
new long[connectSize]);
985 std::copy(connectivity.data(), connectivity.data() + connectSize, connectStorage.get());
987 return addCell(type, std::move(connectStorage), owner, haloLayer,
id);
1011 int owner,
int haloLayer,
long id)
1023 iterator = _addInternalCell(type, std::move(connectStorage),
id);
1025 iterator = _addGhostCell(type, std::move(connectStorage), owner, haloLayer,
id);
1049PatchKernel::CellIterator PatchKernel::_addGhostCell(
ElementType type, std::unique_ptr<
long[]> &&connectStorage,
1050 int owner,
int haloLayer,
long id)
1053 if (m_cellIdGenerator) {
1055 id = m_cellIdGenerator->generate();
1057 m_cellIdGenerator->setAssigned(
id);
1059 }
else if (
id < 0) {
1060 throw std::runtime_error(
"No valid id has been provided for the cell.");
1070 CellIterator iterator;
1071 if (m_lastInternalCellId < 0) {
1072 iterator = m_cells.emreclaim(
id,
id, type, std::move(connectStorage),
false, storeInterfaces, storeAdjacencies);
1074 iterator = m_cells.emreclaimAfter(m_lastInternalCellId,
id,
id, type, std::move(connectStorage),
false, storeInterfaces, storeAdjacencies);
1079 if (m_firstGhostCellId < 0) {
1080 m_firstGhostCellId = id;
1081 }
else if (m_cells.rawIndex(m_firstGhostCellId) > m_cells.rawIndex(
id)) {
1082 m_firstGhostCellId = id;
1086 setGhostCellInfo(
id, owner, haloLayer);
1089 setAddedCellAlterationFlags(
id);
1110 int owner,
int haloLayer,
long id)
1121 if (iterator == m_cells.end()) {
1122 throw std::runtime_error(
"Unable to restore the specified cell: the kernel doesn't contain an entry for that cell.");
1128 _restoreInternalCell(iterator, type, std::move(connectStorage));
1130 _restoreGhostCell(iterator, type, std::move(connectStorage), owner, haloLayer);
1150void PatchKernel::_restoreGhostCell(
const CellIterator &iterator,
ElementType type,
1151 std::unique_ptr<
long[]> &&connectStorage,
1152 int owner,
int haloLayer)
1161 long cellId = iterator.getId();
1162 Cell &cell = *iterator;
1163 cell.
initialize(iterator.getId(), type, std::move(connectStorage),
false, storeInterfaces, storeAdjacencies);
1167 setGhostCellInfo(cellId, owner, haloLayer);
1170 setRestoredCellAlterationFlags(cellId);
1178void PatchKernel::_deleteGhostCell(
long id)
1181 unsetGhostCellInfo(
id);
1184 setDeletedCellAlterationFlags(
id);
1187 m_cells.erase(
id,
true);
1189 if (
id == m_firstGhostCellId) {
1194 if (m_cellIdGenerator) {
1195 m_cellIdGenerator->trash(
id);
1206 if (m_nGhostCells > 0) {
1207 return m_cells.find(m_firstGhostCellId);
1209 return m_cells.end();
1230 return m_cells.end();
1250 if (m_nGhostCells > 0) {
1251 return m_cells.find(m_firstGhostCellId);
1253 return m_cells.cend();
1274 return m_cells.cend();
1292 if (m_nGhostCells == 0) {
1293 m_firstGhostCellId = Cell::NULL_ID;
1294 }
else if (m_nInternalCells == 0) {
1296 m_firstGhostCellId = firstghostCellItr->
getId();
1298 m_firstGhostCellId = m_cells.getSizeMarker(m_nInternalCells, Cell::NULL_ID);
1317std::vector<adaption::Info>
PatchKernel::partition(MPI_Comm communicator,
const std::unordered_map<long, int> &cellRanks,
bool trackPartitioning,
bool squeezeStorage, std::size_t haloSize)
1323 return partition(cellRanks, trackPartitioning, squeezeStorage);
1338std::vector<adaption::Info>
PatchKernel::partition(
const std::unordered_map<long, int> &cellRanks,
bool trackPartitioning,
bool squeezeStorage)
1342 std::vector<adaption::Info> partitioningData =
partitioningAlter(trackPartitioning, squeezeStorage);
1346 return partitioningData;
1363std::vector<adaption::Info>
PatchKernel::partition(MPI_Comm communicator,
bool trackPartitioning,
bool squeezeStorage, std::size_t haloSize)
1369 std::unordered_map<long, double> dummyCellWeights;
1371 return partition(dummyCellWeights, trackPartitioning, squeezeStorage);
1387 std::unordered_map<long, double> dummyCellWeights;
1391 std::vector<adaption::Info> partitioningData =
partitioningAlter(trackPartitioning, squeezeStorage);
1395 return partitioningData;
1415std::vector<adaption::Info>
PatchKernel::partition(MPI_Comm communicator,
const std::unordered_map<long, double> &cellWeights,
bool trackPartitioning,
bool squeezeStorage, std::size_t haloSize)
1421 return partition(cellWeights, trackPartitioning, squeezeStorage);
1438std::vector<adaption::Info>
PatchKernel::partition(
const std::unordered_map<long, double> &cellWeights,
bool trackPartitioning,
bool squeezeStorage)
1442 std::vector<adaption::Info> partitioningData =
partitioningAlter(trackPartitioning, squeezeStorage);
1446 return partitioningData;
1462std::vector<adaption::Info>
PatchKernel::partitioningPrepare(MPI_Comm communicator,
const std::unordered_map<long, int> &cellRanks,
bool trackPartitioning, std::size_t haloSize)
1485 throw std::runtime_error (
"The patch does not support partitioning!");
1490 throw std::runtime_error (
"There is no communicator set for the patch.");
1495 if (partitioningStatus != PARTITIONING_CLEAN) {
1496 throw std::runtime_error (
"A partitioning is already in progress.");
1499 std::vector<adaption::Info> partitioningData =
_partitioningPrepare(cellRanks, trackPartitioning);
1504 return partitioningData;
1525 std::unordered_map<long, double> dummyCellWeights;
1541 std::unordered_map<long, double> dummyCellWeights;
1561std::vector<adaption::Info>
PatchKernel::partitioningPrepare(MPI_Comm communicator,
const std::unordered_map<long, double> &cellWeights,
bool trackPartitioning, std::size_t haloSize)
1586 throw std::runtime_error (
"The patch does not support partitioning!");
1591 if (partitioningStatus != PARTITIONING_CLEAN) {
1592 throw std::runtime_error (
"A partitioning is already in progress.");
1601 return partitioningData;
1621 std::vector<adaption::Info> partitioningData;
1623 return partitioningData;
1628 if (partitioningStatus == PARTITIONING_CLEAN) {
1629 return partitioningData;
1630 }
else if (partitioningStatus != PARTITIONING_PREPARED) {
1631 throw std::runtime_error (
"The prepare function has no been called.");
1638 finalizeAlterations(squeezeStorage);
1643 return partitioningData;
1659 if (partitioningStatus == PARTITIONING_CLEAN) {
1661 }
else if (partitioningStatus == PARTITIONING_PREPARED) {
1662 throw std::runtime_error (
"It is not yet possible to abort a partitioning.");
1663 }
else if (partitioningStatus != PARTITIONING_ALTERED) {
1664 throw std::runtime_error (
"The alter function has no been called.");
1670 if (m_partitioningOutgoings.size() > 0) {
1671 std::unordered_map<long, int>().swap(m_partitioningOutgoings);
1714 return m_partitioningMode;
1727 m_partitioningMode = mode;
1738 int partitioningStatus =
static_cast<int>(m_partitioningStatus);
1742 MPI_Allreduce(MPI_IN_PLACE, &partitioningStatus, 1, MPI_INT, MPI_MAX, communicator);
1755 m_partitioningStatus = status;
1776 std::unordered_map<long, double> dummyCellWeights;
1796 double partitionWeight;
1797 if (!cellWeights.empty()) {
1801 partitionWeight = 0.;
1803 long cellId = cellItr.getId();
1806 auto weightItr = cellWeights.find(cellId);
1807 if (weightItr != cellWeights.end()) {
1808 cellWeight = weightItr->second;
1813 partitionWeight += cellWeight;
1820 double totalPartitionWeight;
1821 MPI_Allreduce(&partitionWeight, &totalPartitionWeight, 1, MPI_DOUBLE, MPI_SUM,
getCommunicator());
1823 double maximumPartitionWeight;
1824 MPI_Allreduce(&partitionWeight, &maximumPartitionWeight, 1, MPI_DOUBLE, MPI_MAX,
getCommunicator());
1829 double unbalance = (maximumPartitionWeight / meanPartitionWeight - 1.);
1837#if BITPIT_ENABLE_METIS==1
1872 if (isCellRankEvaluationNeeded) {
1874 throw std::runtime_error(
"Default partitioning can only be used when the patch is all on a single process");
1881#if BITPIT_ENABLE_METIS==1
1882 std::unordered_map<long, int> cellRanks;
1887 std::unordered_map<long, idx_t> vertexToNodeMap;
1890 for (
const Vertex &vertex : m_vertices) {
1891 vertexToNodeMap[vertex.getId()] = nodeId;
1899 idx_t connectSize = 0;
1900 for (
const Cell &cell : m_cells){
1904 std::vector<idx_t> connectStorage(connectSize);
1905 std::vector<idx_t> connectRanges(nElements + 1);
1906 std::vector<idx_t> elementWeights(nElements,
static_cast<idx_t
>(std::max(defaultWeight, 1.)));
1910 connectRanges[0] = 0;
1911 for (
const Cell &cell : m_cells) {
1914 connectStorage[j] = vertexToNodeMap[vertex];
1917 connectRanges[i + 1] = j;
1920 auto weightItr = cellWeights.find(cell.
getId());
1921 if (weightItr != cellWeights.end()) {
1922 elementWeights[i] =
static_cast<idx_t
>(std::max(std::round(weightItr->second), 1.));
1936 idx_t objectiveValue;
1938 std::vector<idx_t> elementRanks(nElements);
1939 std::vector<idx_t> nodeRanks(nNodes);
1941 int status = METIS_PartMeshDual(&nElements, &nNodes, connectRanges.data(), connectStorage.data(),
1942 elementWeights.data(),
nullptr, &nCommonNodes, &nPartitions,
nullptr,
1943 nullptr, &objectiveValue, elementRanks.data(), nodeRanks.data());
1945 if (status != METIS_OK) {
1946 throw std::runtime_error(
"Error during partitioning (METIS error " + std::to_string(status) +
")");
1951 for (
const Cell &cell : m_cells) {
1952 int metisRank =
static_cast<int>(elementRanks[metisId]);
1954 cellRanks[cell.
getId()] = metisRank;
1966 throw std::runtime_error(
"METIS library is required for automatic patch partitioning.");
1985 std::set<int> recvRanks;
1986 m_partitioningOutgoings.clear();
1987 for (
auto &entry : cellRanks) {
1988 int recvRank = entry.second;
1989 if (recvRank == patchRank) {
1993 long cellId = entry.first;
1994 if (m_ghostCellInfo.count(cellId) > 0) {
1998 m_partitioningOutgoings.insert(entry);
1999 recvRanks.insert(recvRank);
2005 int nExchanges = recvRanks.size();
2006 std::vector<std::pair<int, int>> exchanges;
2007 exchanges.reserve(nExchanges);
2008 for (
int recvRank : recvRanks) {
2009 exchanges.emplace_back(patchRank, recvRank);
2012 int exchangesGatherCount = 2 * nExchanges;
2013 std::vector<int> exchangeGatherCount(nRanks);
2014 MPI_Allgather(&exchangesGatherCount, 1, MPI_INT, exchangeGatherCount.data(), 1, MPI_INT, m_communicator);
2016 std::vector<int> exchangesGatherDispls(nRanks, 0);
2017 for (
int i = 1; i < nRanks; ++i) {
2018 exchangesGatherDispls[i] = exchangesGatherDispls[i - 1] + exchangeGatherCount[i - 1];
2021 int nGlobalExchanges = nExchanges;
2022 MPI_Allreduce(MPI_IN_PLACE, &nGlobalExchanges, 1, MPI_INT, MPI_SUM, m_communicator);
2024 m_partitioningGlobalExchanges.resize(nGlobalExchanges);
2025 MPI_Allgatherv(exchanges.data(), exchangesGatherCount, MPI_INT, m_partitioningGlobalExchanges.data(),
2026 exchangeGatherCount.data(), exchangesGatherDispls.data(), MPI_INT, m_communicator);
2028 std::sort(m_partitioningGlobalExchanges.begin(), m_partitioningGlobalExchanges.end(), greater<std::pair<int,int>>());
2031 std::unordered_set<int> globalSendRanks;
2032 for (
const std::pair<int, int> &entry : m_partitioningGlobalExchanges) {
2033 globalSendRanks.insert(entry.first);
2037 std::unordered_set<int> globalRecvRanks;
2038 for (
const std::pair<int, int> &entry : m_partitioningGlobalExchanges) {
2039 globalRecvRanks.insert(entry.second);
2046 m_partitioningSerialization = (globalRecvRanks.size() == 1);
2047 if (m_partitioningSerialization) {
2048 int receiverRank = *(globalRecvRanks.begin());
2049 if (patchRank != receiverRank) {
2051 m_partitioningSerialization =
false;
2055 MPI_Allreduce(MPI_IN_PLACE, &m_partitioningSerialization, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
2061 std::vector<adaption::Info> partitioningData;
2062 if (trackPartitioning) {
2063 for (
const std::pair<int, int> &entry : m_partitioningGlobalExchanges) {
2064 int sendRank = entry.first;
2065 if (sendRank != patchRank) {
2069 int recvRank = entry.second;
2071 std::vector<long> previous;
2072 for (
const auto &entry : m_partitioningOutgoings) {
2073 int cellRank = entry.second;
2074 if (cellRank != recvRank) {
2078 long cellId = entry.first;
2079 previous.push_back(cellId);
2082 if (!previous.empty()) {
2083 partitioningData.emplace_back();
2085 partitioningInfo.entity = adaption::ENTITY_CELL;
2086 partitioningInfo.type = adaption::TYPE_PARTITION_SEND;
2087 partitioningInfo.rank = recvRank;
2088 partitioningInfo.previous = std::move(previous);
2093 return partitioningData;
2117 std::unordered_map<long, int> ghostCellOwnershipChanges;
2118 if (!m_partitioningSerialization) {
2120 ghostCellOwnershipChanges = _partitioningAlter_evalGhostCellOwnershipChanges();
2123 _partitioningAlter_deleteGhosts();
2132 std::unordered_set<int> batchSendRanks;
2133 std::unordered_set<int> batchRecvRanks;
2135 std::vector<adaption::Info> partitioningData;
2136 std::vector<adaption::Info> rankPartitioningData;
2137 while (!m_partitioningGlobalExchanges.empty()) {
2142 batchSendRanks.clear();
2143 batchRecvRanks.clear();
2144 while (!m_partitioningGlobalExchanges.empty()) {
2145 const std::pair<int, int> &entry = m_partitioningGlobalExchanges.back();
2147 int entrySendRank = entry.first;
2148 if (batchRecvRanks.count(entrySendRank)) {
2152 int entryRecvRank = entry.second;
2153 if (batchSendRanks.count(entryRecvRank)) {
2157 batchSendRanks.insert(entrySendRank);
2158 batchRecvRanks.insert(entryRecvRank);
2159 m_partitioningGlobalExchanges.pop_back();
2163 bool isSender = (batchSendRanks.count(patchRank) > 0);
2164 bool isReceiver = (batchRecvRanks.count(patchRank) > 0);
2168 rankPartitioningData = _partitioningAlter_sendCells(batchRecvRanks, trackPartitioning, &ghostCellOwnershipChanges);
2169 }
else if (isReceiver) {
2170 rankPartitioningData = _partitioningAlter_receiveCells(batchSendRanks, trackPartitioning, &ghostCellOwnershipChanges);
2173 if (trackPartitioning) {
2174 for (
adaption::Info &rankPartitioningInfo : rankPartitioningData) {
2175 partitioningData.emplace_back(std::move(rankPartitioningInfo));
2180 for (
int sendRank : batchSendRanks) {
2181 _partitioningAlter_applyGhostCellOwnershipChanges(sendRank, &ghostCellOwnershipChanges);
2185 assert(ghostCellOwnershipChanges.size() == 0);
2190 return partitioningData;
2204std::unordered_map<long, int> PatchKernel::_partitioningAlter_evalGhostCellOwnershipChanges()
2212 size_t notificationDataSize =
sizeof(patchRank);
2216 const int rank = entry.first;
2217 const auto &targetCells = entry.second;
2219 notificationCommunicator.setRecv(rank, targetCells.size() * notificationDataSize);
2220 notificationCommunicator.startRecv(rank);
2228 const int rank = entry.first;
2229 auto &sourceCells = entry.second;
2231 notificationCommunicator.setSend(rank, sourceCells.size() * notificationDataSize);
2232 SendBuffer &buffer = notificationCommunicator.getSendBuffer(rank);
2233 for (
long id : sourceCells) {
2235 if (m_partitioningOutgoings.count(
id) > 0) {
2236 finalOwner = m_partitioningOutgoings.at(
id);
2238 finalOwner = patchRank;
2241 buffer << finalOwner;
2243 notificationCommunicator.startSend(rank);
2250 std::unordered_map<long, int> ghostCellOwnershipChanges;
2252 int nCompletedRecvs = 0;
2253 while (nCompletedRecvs < notificationCommunicator.getRecvCount()) {
2254 int rank = notificationCommunicator.waitAnyRecv();
2257 RecvBuffer &buffer = notificationCommunicator.getRecvBuffer(rank);
2258 for (
long id : list) {
2260 buffer >> finalOwner;
2262 if (finalOwner != m_ghostCellInfo.at(
id).owner) {
2263 ghostCellOwnershipChanges[id] = finalOwner;
2271 notificationCommunicator.waitAllSends();
2273 return ghostCellOwnershipChanges;
2287void PatchKernel::_partitioningAlter_applyGhostCellOwnershipChanges(
int sendRank,
2288 std::unordered_map<long, int> *ghostCellOwnershipChanges)
2290 for (
auto itr = ghostCellOwnershipChanges->begin(); itr != ghostCellOwnershipChanges->end();) {
2292 long ghostCellId = itr->first;
2293 const GhostCellInfo &ghostCellInfo = m_ghostCellInfo.at(ghostCellId);
2294 int previousGhostCellOwner = ghostCellInfo.owner;
2295 if (previousGhostCellOwner != sendRank) {
2301 int finalGhostCellOwner = itr->second;
2302 setGhostCellInfo(ghostCellId, finalGhostCellOwner, ghostCellInfo.haloLayer);
2303 itr = ghostCellOwnershipChanges->erase(itr);
2310void PatchKernel::_partitioningAlter_deleteGhosts()
2313 std::vector<long> cellsDeleteList;
2314 cellsDeleteList.reserve(m_ghostCellInfo.size());
2315 for (
const auto &entry : m_ghostCellInfo) {
2316 long cellId = entry.first;
2317 cellsDeleteList.emplace_back(cellId);
2354std::vector<adaption::Info> PatchKernel::_partitioningAlter_sendCells(
const std::unordered_set<int> &recvRanks,
bool trackPartitioning,
2355 std::unordered_map<long, int> *ghostCellOwnershipChanges)
2358 std::vector<adaption::Info> partitioningData;
2359 if (trackPartitioning) {
2360 partitioningData.reserve(recvRanks.size());
2364 std::size_t nOutgoingsOverall = m_partitioningOutgoings.size();
2370 const double ACTIVATE_MEMORY_LIMIT_THRESHOLD = 0.15;
2374 MPI_Request verticesSizeRequest = MPI_REQUEST_NULL;
2375 MPI_Request cellsSizeRequest = MPI_REQUEST_NULL;
2377 MPI_Request verticesRequest = MPI_REQUEST_NULL;
2378 MPI_Request cellsRequest = MPI_REQUEST_NULL;
2380 OBinaryStream verticesBuffer;
2381 OBinaryStream cellsBuffer;
2383 std::vector<long> neighsList;
2384 std::unordered_set<long> frontierNeighs;
2385 std::unordered_set<long> frontierVertices;
2386 std::unordered_set<long> frontierFaceVertices;
2387 std::unordered_set<ConstCellHalfEdge, ConstCellHalfEdge::Hasher> frontierEdges;
2389 std::unordered_set<long> outgoingCells;
2390 std::unordered_set<long> frameCells;
2391 std::unordered_map<long, std::size_t> haloCells;
2392 std::vector<long> firstHaloLayerCells;
2394 std::unordered_set<long> frameVertices;
2395 std::unordered_set<long> haloVertices;
2397 std::vector<long> cellSendList;
2398 std::unordered_set<long> vertexSendList;
2400 std::vector<long> frameCellsOverall;
2401 std::unordered_set<long> ghostHaloCellsOverall;
2402 std::unordered_set<long> innerFrontierCellsOverall;
2404 for (
int recvRank : recvRanks) {
2408 outgoingCells.clear();
2409 for (
const auto &rankEntry : m_partitioningOutgoings) {
2410 int rank = rankEntry.second;
2411 if (rank != recvRank) {
2415 long cellId = rankEntry.first;
2416 outgoingCells.insert(cellId);
2458 if (!m_partitioningSerialization) {
2462 frontierVertices.clear();
2463 frontierEdges.clear();
2464 for (
long cellId : outgoingCells) {
2465 Cell &cell = m_cells.at(cellId);
2467 const int nFaces = cell.getFaceCount();
2468 for (
int face = 0; face < nFaces; ++face) {
2469 int nFaceAdjacencies = cell.getAdjacencyCount(face);
2470 if (nFaceAdjacencies == 0) {
2474 const long *faceAdjacencies = cell.getAdjacencies(face);
2475 for (
int i = 0; i < nFaceAdjacencies; ++i) {
2477 long neighId = faceAdjacencies[i];
2478 if (outgoingCells.count(neighId) > 0) {
2483 long frontierCellId;
2485 const Cell *frontierCell;
2486 if (nFaceAdjacencies == 1) {
2487 frontierCellId = cellId;
2488 frontierFace = face;
2489 frontierCell = &cell;
2491 const Cell &neigh =
getCell(neighId);
2493 frontierCellId = neighId;
2495 frontierCell = &neigh;
2497 assert(frontierFace >= 0);
2501 frontierNeighs.clear();
2516 bool innerFrontierFace = (m_partitioningOutgoings.count(neighId) == 0);
2524 frontierNeighs.insert(cellId);
2525 frontierNeighs.insert(neighId);
2527 if (innerFrontierFace) {
2528 innerFrontierCellsOverall.insert(cellId);
2534 ConstProxyVector<int> frontierFaceLocalVerticesIds = frontierCell->getFaceLocalVertexIds(frontierFace);
2535 int nFrontierFaceVertices = frontierFaceLocalVerticesIds.size();
2537 frontierFaceVertices.clear();
2538 for (
int k = 0; k < nFrontierFaceVertices; ++k) {
2539 long vertexId = frontierCell->getFaceVertexId(frontierFace, k);
2540 frontierFaceVertices.insert(vertexId);
2543 auto frontierVertexItr = frontierVertices.find(vertexId);
2544 if (frontierVertexItr != frontierVertices.end()) {
2549 frontierVertices.insert(vertexId);
2553 int vertex = frontierFaceLocalVerticesIds[k];
2557 bool innerFrontierVertex = (m_partitioningOutgoings.count(frontierCellId) == 0);
2558 if (!innerFrontierVertex) {
2559 for (
long frontierNeighId : neighsList) {
2560 if (m_partitioningOutgoings.count(frontierNeighId) == 0) {
2561 innerFrontierVertex =
true;
2568 for (
long frontierNeighId : neighsList) {
2569 frontierNeighs.insert(frontierNeighId);
2570 if (innerFrontierVertex) {
2571 if (m_partitioningOutgoings.count(frontierNeighId) > 0) {
2572 innerFrontierCellsOverall.insert(frontierNeighId);
2581 if (patchDimension == 3) {
2582 int nFrontierCellEdges = frontierCell->getEdgeCount();
2583 for (
int edge = 0; edge < nFrontierCellEdges; ++edge) {
2585 int nEdgeVertices = frontierCell->getEdgeVertexCount(edge);
2587 ConstCellHalfEdge frontierEdge = ConstCellHalfEdge(*frontierCell, edge, ConstCellHalfEdge::WINDING_NATURAL);
2591 ConstProxyVector<long> edgeVertexIds = frontierEdge.getVertexIds();
2593 bool isFrontierFaceEdge =
true;
2594 for (
int k = 0; k < nEdgeVertices; ++k) {
2595 long edgeVertexId = edgeVertexIds[k];
2596 if (frontierFaceVertices.count(edgeVertexId) == 0) {
2597 isFrontierFaceEdge =
false;
2602 if (!isFrontierFaceEdge) {
2607 frontierEdge.setWinding(ConstCellHalfEdge::WINDING_REVERSE);
2608 auto frontierEdgeItr = frontierEdges.find(frontierEdge);
2609 if (frontierEdgeItr != frontierEdges.end()) {
2612 frontierEdge.setWinding(ConstCellHalfEdge::WINDING_NATURAL);
2613 frontierEdgeItr = frontierEdges.find(frontierEdge);
2614 if (frontierEdgeItr != frontierEdges.end()) {
2620 frontierEdges.insert(std::move(frontierEdge));
2627 bool innerFrontierEdge = (m_partitioningOutgoings.count(frontierCellId) == 0);
2628 if (!innerFrontierEdge) {
2629 for (
long frontierNeighId : neighsList) {
2630 if (m_partitioningOutgoings.count(frontierNeighId) == 0) {
2631 innerFrontierEdge =
true;
2638 for (
long frontierNeighId : neighsList) {
2639 frontierNeighs.insert(frontierNeighId);
2640 if (innerFrontierEdge) {
2641 if (m_partitioningOutgoings.count(frontierNeighId) > 0) {
2642 innerFrontierCellsOverall.insert(frontierNeighId);
2650 for (
long frontierNeighId : frontierNeighs) {
2651 if (outgoingCells.count(frontierNeighId) > 0) {
2652 frameCells.insert(frontierNeighId);
2654 haloCells.insert({frontierNeighId, 0});
2664 if (m_haloSize > 1) {
2665 auto frameSelector = [&outgoingCells](
long cellId) {
2666 return (outgoingCells.count(cellId) != 0);
2669 auto frameBuilder = [&frameCells](
long cellId,
int layer) {
2672 frameCells.insert(cellId);
2685 if (m_haloSize > 1) {
2686 firstHaloLayerCells.clear();
2687 firstHaloLayerCells.reserve(haloCells.size());
2688 for (
const auto &haloEntry : haloCells) {
2689 firstHaloLayerCells.push_back(haloEntry.first);
2692 auto haloSelector = [&frameCells](
long cellId) {
2693 return (frameCells.count(cellId) == 0);
2696 auto haloBuilder = [&haloCells](
long cellId,
int layer) {
2697 haloCells.insert({cellId, layer + 1});
2711 std::size_t nOutgoingCells = outgoingCells.size();
2712 std::size_t nHaloCells = haloCells.size();
2714 cellSendList.assign(outgoingCells.begin(), outgoingCells.end());
2716 std::size_t haloIndex = cellSendList.size();
2717 cellSendList.resize(cellSendList.size() + nHaloCells);
2718 for (
const auto &haloEntry : haloCells) {
2719 cellSendList[haloIndex] = haloEntry.first;
2724 frameCellsOverall.insert(frameCellsOverall.end(), frameCells.begin(), frameCells.end());
2727 for (
const auto &haloEntry : haloCells) {
2728 long cellId = haloEntry.first;
2729 const Cell &cell =
getCell(cellId);
2730 if (cell.isInterior()) {
2734 ghostHaloCellsOverall.insert(cellId);
2742 if (cellsSizeRequest != MPI_REQUEST_NULL) {
2743 MPI_Wait(&cellsSizeRequest, MPI_STATUS_IGNORE);
2747 long cellsBufferSize = 2 *
sizeof(long) + 3 * nHaloCells *
sizeof(
int) + 2 * (nOutgoingCells + nHaloCells) *
sizeof(
bool);
2748 for (
const long cellId : cellSendList) {
2749 cellsBufferSize += m_cells.at(cellId).getBinarySize();
2752 MPI_Isend(&cellsBufferSize, 1, MPI_LONG, recvRank, m_partitioningCellsTag, m_communicator, &cellsSizeRequest);
2762 frameVertices.clear();
2763 haloVertices.clear();
2764 vertexSendList.clear();
2765 for (
const long cellId : cellSendList) {
2766 const Cell &cell = m_cells.at(cellId);
2768 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
2769 int nCellVertices = cellVertexIds.size();
2770 for (
int j = 0; j < nCellVertices; ++j) {
2771 long vertexId = cellVertexIds[j];
2773 if (frameCells.count(cellId) > 0) {
2774 frameVertices.insert(vertexId);
2775 }
else if (haloCells.count(cellId) > 0) {
2776 haloVertices.insert(vertexId);
2779 vertexSendList.insert(vertexId);
2783 if (m_partitioningSerialization) {
2784 for (
const long cellId : cellSendList) {
2785 const Cell &cell = m_cells.at(cellId);
2787 int nCellFaces = cell.getFaceCount();
2788 for (
int face = 0; face < nCellFaces; ++face) {
2789 if (!cell.isFaceBorder(face)) {
2793 int nFaceVertices = cell.getFaceVertexCount(face);
2794 for (
int k = 0; k < nFaceVertices; ++k) {
2795 long vertexId = cell.getFaceVertexId(face, k);
2796 frameVertices.insert(vertexId);
2807 if (verticesSizeRequest != MPI_REQUEST_NULL) {
2808 MPI_Wait(&verticesSizeRequest, MPI_STATUS_IGNORE);
2812 long verticesBufferSize =
sizeof(long) + 2 * vertexSendList.size() *
sizeof(bool);
2813 for (
long vertexId : vertexSendList) {
2814 verticesBufferSize += m_vertices[vertexId].getBinarySize();
2817 MPI_Isend(&verticesBufferSize, 1, MPI_LONG, recvRank, m_partitioningVerticesTag, m_communicator, &verticesSizeRequest);
2824 if (verticesRequest != MPI_REQUEST_NULL) {
2825 MPI_Wait(&verticesRequest, MPI_STATUS_IGNORE);
2829 verticesBuffer.setSize(verticesBufferSize);
2830 verticesBuffer.seekg(0);
2832 verticesBuffer << (long) vertexSendList.size();
2833 for (
long vertexId : vertexSendList) {
2835 bool isFrame = (frameVertices.count(vertexId) > 0);
2836 bool isHalo = (haloVertices.count(vertexId) > 0);
2838 verticesBuffer << isFrame;
2839 verticesBuffer << isHalo;
2842 verticesBuffer << m_vertices[vertexId];
2845 if (verticesBufferSize != (
long) verticesBuffer.getSize()) {
2846 throw std::runtime_error (
"Cell buffer size does not match calculated size");
2849 MPI_Isend(verticesBuffer.data(), verticesBuffer.getSize(), MPI_CHAR, recvRank, m_partitioningVerticesTag, m_communicator, &verticesRequest);
2856 if (cellsRequest != MPI_REQUEST_NULL) {
2857 MPI_Wait(&cellsRequest, MPI_STATUS_IGNORE);
2861 cellsBuffer.setSize(cellsBufferSize);
2862 cellsBuffer.seekg(0);
2864 cellsBuffer << (long) nOutgoingCells;
2865 cellsBuffer << (long) nHaloCells;
2866 for (
long cellId : cellSendList) {
2868 bool isFrame = (frameCells.count(cellId) > 0);
2869 bool isHalo = (haloCells.count(cellId) > 0);
2871 cellsBuffer << isFrame;
2872 cellsBuffer << isHalo;
2879 int cellOwnerOnReceiver;
2880 if (m_partitioningOutgoings.count(cellId) > 0) {
2881 cellOwnerOnReceiver = m_partitioningOutgoings.at(cellId);
2882 }
else if (m_ghostCellInfo.count(cellId) > 0) {
2883 cellOwnerOnReceiver = m_ghostCellInfo.at(cellId).owner;
2885 cellOwnerOnReceiver = m_rank;
2888 cellsBuffer << cellOwnerOnReceiver;
2890 int cellHaloLayerOnReceiver;
2891 if (cellOwnerOnReceiver != recvRank) {
2892 cellHaloLayerOnReceiver = haloCells.at(cellId);
2894 cellHaloLayerOnReceiver = -1;
2897 cellsBuffer << cellHaloLayerOnReceiver;
2899 int ghostCellOwnershipChange;
2900 if (ghostCellOwnershipChanges->count(cellId) > 0) {
2901 ghostCellOwnershipChange = ghostCellOwnershipChanges->at(cellId);
2903 ghostCellOwnershipChange = -1;
2906 cellsBuffer << ghostCellOwnershipChange;
2910 const Cell &cell = m_cells.at(cellId);
2912 cellsBuffer << cell;
2915 if (cellsBufferSize != (
long) cellsBuffer.getSize()) {
2916 throw std::runtime_error (
"Cell buffer size does not match calculated size");
2919 MPI_Isend(cellsBuffer.data(), cellsBuffer.getSize(), MPI_CHAR, recvRank, m_partitioningCellsTag, m_communicator, &cellsRequest);
2924 if (trackPartitioning) {
2933 partitioningData.emplace_back();
2934 adaption::Info &partitioningInfo = partitioningData.back();
2935 partitioningInfo.entity = adaption::ENTITY_CELL;
2936 partitioningInfo.type = adaption::TYPE_PARTITION_SEND;
2937 partitioningInfo.rank = recvRank;
2939 partitioningInfo.previous.resize(nOutgoingCells);
2940 for (std::size_t i = 0; i < nOutgoingCells; ++i) {
2941 long cellId = cellSendList[i];
2942 partitioningInfo.previous[i] = cellId;
2950 std::vector<long> deleteList;
2952 deleteList.reserve(nOutgoingCells - frameCells.size());
2953 for (std::size_t i = 0; i < nOutgoingCells; ++i) {
2954 long cellId = cellSendList[i];
2955 if (frameCells.count(cellId) == 0) {
2956 deleteList.push_back(cellId);
2971 bool keepMemoryLimited = (nOutgoingCells > ACTIVATE_MEMORY_LIMIT_THRESHOLD *
getInternalCellCount());
2972 if (keepMemoryLimited) {
2990 if (!sendingAllCells) {
2991 std::vector<long> deleteList;
2998 for (
long cellId : innerFrontierCellsOverall) {
2999 const Cell &cell =
getCell(cellId);
3000 std::size_t cellHaloLayer = 0;
3001 if (!confirmCellHaloLayer(cell, cellHaloLayer, m_partitioningOutgoings)) {
3005 int cellOwner = m_partitioningOutgoings.at(cellId);
3009 auto ghostFrameSelector = [
this](
long cellId) {
3010 return (m_partitioningOutgoings.count(cellId) != 0);
3013 auto ghostFrameBuilder = [
this](
long cellId,
int layer) {
3014 int cellOwner = m_partitioningOutgoings.at(cellId);
3020 processCellsNeighbours(innerFrontierCellsOverall, m_haloSize - 1, ghostFrameSelector, ghostFrameBuilder);
3027 for (
long cellId : frameCellsOverall) {
3028 const Cell &cell =
getCell(cellId);
3029 if (!cell.isInterior()) {
3033 deleteList.push_back(cellId);
3034 ghostCellOwnershipChanges->erase(cellId);
3055 std::vector<long> neighIds;
3056 std::vector<long> updateList;
3058 for (
int haloLayer = 0; haloLayer < static_cast<int>(m_haloSize); ++haloLayer) {
3060 for (
long cellId : ghostHaloCellsOverall) {
3062 const GhostCellInfo &ghostInfo = m_ghostCellInfo.at(cellId);
3063 if (ghostInfo.haloLayer != haloLayer) {
3069 const Cell &cell =
getCell(cellId);
3070 if (confirmCellHaloLayer(cell, haloLayer, m_partitioningOutgoings)) {
3071 updateList.push_back(cellId);
3073 deleteList.push_back(cellId);
3078 for (
long cellId : deleteList) {
3079 ghostCellOwnershipChanges->erase(cellId);
3080 ghostHaloCellsOverall.erase(cellId);
3093 for (
long ghostId : updateList) {
3094 computeCellHaloLayer(ghostId);
3105 ghostCellOwnershipChanges->clear();
3108 if (cellsSizeRequest != MPI_REQUEST_NULL) {
3109 MPI_Wait(&cellsSizeRequest, MPI_STATUS_IGNORE);
3112 if (verticesSizeRequest != MPI_REQUEST_NULL) {
3113 MPI_Wait(&verticesSizeRequest, MPI_STATUS_IGNORE);
3116 if (verticesRequest != MPI_REQUEST_NULL) {
3117 MPI_Wait(&verticesRequest, MPI_STATUS_IGNORE);
3120 if (cellsRequest != MPI_REQUEST_NULL) {
3121 MPI_Wait(&cellsRequest, MPI_STATUS_IGNORE);
3125 return partitioningData;
3143std::vector<adaption::Info> PatchKernel::_partitioningAlter_receiveCells(
const std::unordered_set<int> &sendRanks,
bool trackPartitioning,
3144 std::unordered_map<long, int> *ghostCellOwnershipChanges)
3149 int nSendRanks = sendRanks.size();
3151 std::vector<MPI_Request> cellsSizeRequests(nSendRanks, MPI_REQUEST_NULL);
3152 std::vector<MPI_Request> verticesSizeRequests(nSendRanks, MPI_REQUEST_NULL);
3154 std::vector<long> cellsBufferSizes(nSendRanks);
3155 std::vector<long> verticesBufferSizes(nSendRanks);
3157 std::unordered_map<int, int> sendRankIndexes;
3158 sendRankIndexes.reserve(nSendRanks);
3160 for (
int sendRank : sendRanks) {
3161 int sendRankIndex = sendRankIndexes.size();
3162 sendRankIndexes[sendRank] = sendRankIndex;
3165 long &cellsBufferSize = cellsBufferSizes[sendRankIndex];
3166 MPI_Request &cellsSizeRequest = cellsSizeRequests[sendRankIndex];
3167 MPI_Irecv(&cellsBufferSize, 1, MPI_LONG, sendRank, m_partitioningCellsTag, m_communicator, &cellsSizeRequest);
3170 long &verticesBufferSize = verticesBufferSizes[sendRankIndex];
3171 MPI_Request &verticesSizeRequest = verticesSizeRequests[sendRankIndex];
3172 MPI_Irecv(&verticesBufferSize, 1, MPI_LONG, sendRank, m_partitioningVerticesTag, m_communicator, &verticesSizeRequest);
3176 std::vector<MPI_Request> cellsRequests(nSendRanks, MPI_REQUEST_NULL);
3177 std::vector<MPI_Request> verticesRequests(nSendRanks, MPI_REQUEST_NULL);
3179 std::vector<std::unique_ptr<IBinaryStream>> cellsBuffers(nSendRanks);
3180 std::vector<std::unique_ptr<IBinaryStream>> verticesBuffers(nSendRanks);
3183 std::vector<adaption::Info> partitioningData;
3184 if (trackPartitioning) {
3185 partitioningData.resize(nSendRanks);
3186 for (
int sendRank : sendRanks) {
3187 int sendRankIndex = sendRankIndexes.at(sendRank);
3189 adaption::Info &partitioningInfo = partitioningData[sendRankIndex];
3190 partitioningInfo.entity = adaption::ENTITY_CELL;
3191 partitioningInfo.type = adaption::TYPE_PARTITION_RECV;
3192 partitioningInfo.rank = sendRank;
3204 const Cell &cell = *itr;
3205 const long *interfaces = cell.getInterfaces();
3206 const int nCellInterfaces = cell.getInterfaceCount();
3210 for (
int k = 0; k < nCellInterfaces; ++k) {
3211 long interfaceId = interfaces[k];
3212 const Interface &
interface = getInterface(interfaceId);
3213 if (interface.isBorder()) {
3214 setInterfaceAlterationFlags(interfaceId, FLAG_DANGLING);
3223 int nSendCompleted = 0;
3224 std::vector<int> sendCompletedIndexes(nSendRanks);
3225 std::vector<MPI_Status> sendCompletedStatuses(nSendRanks);
3227 std::vector<long> neighIds;
3229 std::unordered_set<long> duplicateCellsCandidates;
3231 std::array<double, 3> *candidateVertexCoords;
3232 Vertex::Less vertexLess(10 * std::numeric_limits<double>::epsilon());
3233 auto vertexCoordsLess = [
this, &vertexLess, &candidateVertexCoords](
const long &id_1,
const long &id_2)
3235 const std::array<double, 3> &coords_1 = (id_1 >= 0) ? this->
getVertex(id_1).
getCoords() : *candidateVertexCoords;
3236 const std::array<double, 3> &coords_2 = (id_2 >= 0) ? this->
getVertex(id_2).
getCoords() : *candidateVertexCoords;
3238 return vertexLess(coords_1, coords_2);
3240 std::set<long,
decltype(vertexCoordsLess)> duplicateVerticesCandidates(vertexCoordsLess);
3242 std::unordered_map<long, long> verticesMap;
3244 std::unordered_set<long> validReceivedAdjacencies;
3245 std::vector<long> addedCells;
3246 std::unordered_map<long, FlatVector2D<long>> duplicateCellsReceivedAdjacencies;
3247 std::unordered_map<long, long> cellsMap;
3249 std::unordered_set<int> awaitingSendRanks = sendRanks;
3250 while (!awaitingSendRanks.empty()) {
3265 duplicateCellsCandidates.clear();
3266 std::vector<long> firstHaloLayerCells;
3267 for (
const auto &ghostOwnerEntry : m_ghostCellInfo) {
3268 long ghostId = ghostOwnerEntry.first;
3270 duplicateCellsCandidates.insert(ghostId);
3272 firstHaloLayerCells.push_back(ghostId);
3276 auto duplicateCandidatesSelector = [
this](
long cellId) {
3279 return (m_ghostCellInfo.count(cellId) == 0);
3282 auto duplicateCandidatesBuilder = [&duplicateCellsCandidates](
long cellId,
int layer) {
3285 duplicateCellsCandidates.insert({cellId});
3290 processCellsNeighbours(firstHaloLayerCells, m_haloSize, duplicateCandidatesSelector, duplicateCandidatesBuilder);
3302 duplicateVerticesCandidates.clear();
3303 if (!m_partitioningSerialization) {
3304 for (
long cellId : duplicateCellsCandidates) {
3305 const Cell &cell = m_cells.at(cellId);
3306 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
3307 for (
long vertexId : cellVertexIds) {
3308 duplicateVerticesCandidates.insert(vertexId);
3312 for (
const Cell &cell : m_cells) {
3313 int nCellFaces = cell.getFaceCount();
3314 for (
int face = 0; face < nCellFaces; ++face) {
3315 if (!cell.isFaceBorder(face)) {
3319 int nFaceVertices = cell.getFaceVertexCount(face);
3320 for (
int k = 0; k < nFaceVertices; ++k) {
3321 long vertexId = cell.getFaceVertexId(face, k);
3322 duplicateVerticesCandidates.insert(vertexId);
3334 while (sendRank < 0) {
3336 MPI_Waitsome(nSendRanks, verticesSizeRequests.data(), &nSendCompleted, sendCompletedIndexes.data(), sendCompletedStatuses.data());
3337 for (
int i = 0; i < nSendCompleted; ++i) {
3338 int sourceIndex = sendCompletedIndexes[i];
3339 int sourceRank = sendCompletedStatuses[i].MPI_SOURCE;
3341 std::size_t bufferSize = verticesBufferSizes[sourceIndex];
3342 std::unique_ptr<IBinaryStream> buffer = std::unique_ptr<IBinaryStream>(
new IBinaryStream(bufferSize));
3343 MPI_Request *request = verticesRequests.data() + sourceIndex;
3344 MPI_Irecv(buffer->data(), buffer->getSize(), MPI_CHAR, sourceRank, m_partitioningVerticesTag, m_communicator, request);
3345 verticesBuffers[sourceIndex] = std::move(buffer);
3349 MPI_Waitsome(nSendRanks, cellsSizeRequests.data(), &nSendCompleted, sendCompletedIndexes.data(), sendCompletedStatuses.data());
3350 for (
int i = 0; i < nSendCompleted; ++i) {
3351 int sourceIndex = sendCompletedIndexes[i];
3352 int sourceRank = sendCompletedStatuses[i].MPI_SOURCE;
3354 std::size_t bufferSize = cellsBufferSizes[sourceIndex];
3355 std::unique_ptr<IBinaryStream> buffer = std::unique_ptr<IBinaryStream>(
new IBinaryStream(bufferSize));
3356 MPI_Request *request = cellsRequests.data() + sourceIndex;
3357 MPI_Irecv(buffer->data(), buffer->getSize(), MPI_CHAR, sourceRank, m_partitioningCellsTag, m_communicator, request);
3358 cellsBuffers[sourceIndex] = std::move(buffer);
3363 for (
int awaitingSendRank : awaitingSendRanks) {
3364 int sourceIndex = sendRankIndexes.at(awaitingSendRank);
3365 if (verticesRequests[sourceIndex] == MPI_REQUEST_NULL) {
3367 }
else if (cellsRequests[sourceIndex] == MPI_REQUEST_NULL) {
3371 sendRank = awaitingSendRank;
3376 int sendRankIndex = sendRankIndexes.at(sendRank);
3383 MPI_Request *verticesRequest = verticesRequests.data() + sendRankIndex;
3384 MPI_Wait(verticesRequest, MPI_STATUS_IGNORE);
3387 IBinaryStream &verticesBuffer = *(verticesBuffers[sendRankIndex]);
3390 verticesBuffer >> nRecvVertices;
3394 verticesMap.clear();
3395 for (
long i = 0; i < nRecvVertices; ++i) {
3398 verticesBuffer >> isFrame;
3401 verticesBuffer >> isHalo;
3404 verticesBuffer >> vertex;
3405 long originalVertexId = vertex.getId();
3412 vertex.setInterior(
true);
3423 bool isDuplicate = (isFrame || isHalo);
3431 candidateVertexCoords = &(vertex.getCoords());
3432 auto candidateVertexItr = duplicateVerticesCandidates.find(Cell::NULL_ID);
3433 isDuplicate = (candidateVertexItr != duplicateVerticesCandidates.end());
3435 vertexId = *candidateVertexItr;
3445 if (m_vertexIdGenerator) {
3446 if (m_vertexIdGenerator->isAssigned(originalVertexId)) {
3447 vertex.setId(Vertex::NULL_ID);
3449 }
else if (m_vertices.exists(originalVertexId)) {
3450 throw std::runtime_error(
"A vertex with the same id of the received vertex already exists.");
3453 VertexIterator vertexIterator =
addVertex(std::move(vertex));
3454 vertexId = vertexIterator.getId();
3457 if (originalVertexId != vertexId) {
3458 verticesMap.insert({{originalVertexId, vertexId}});
3463 verticesBuffers[sendRankIndex].reset();
3470 MPI_Request *cellsRequest = cellsRequests.data() + sendRankIndex;
3471 MPI_Wait(cellsRequest, MPI_STATUS_IGNORE);
3476 IBinaryStream &cellsBuffer = *(cellsBuffers[sendRankIndex]);
3478 long nReceivedInternalCells;
3479 cellsBuffer >> nReceivedInternalCells;
3482 cellsBuffer >> nReceivedHalo;
3484 long nReceivedCells = nReceivedInternalCells + nReceivedHalo;
3488 if (trackPartitioning) {
3490 partitioningData[sendRankIndex].current.reserve(nReceivedInternalCells);
3493 validReceivedAdjacencies.clear();
3494 validReceivedAdjacencies.reserve(nReceivedCells);
3497 addedCells.reserve(nReceivedCells);
3499 duplicateCellsReceivedAdjacencies.clear();
3503 for (
long i = 0; i < nReceivedCells; ++i) {
3506 cellsBuffer >> isFrame;
3509 cellsBuffer >> isHalo;
3513 int ghostCellOwnershipChange;
3515 cellsBuffer >> cellOwner;
3516 cellsBuffer >> cellHaloLayer;
3517 cellsBuffer >> ghostCellOwnershipChange;
3519 cellOwner = patchRank;
3521 ghostCellOwnershipChange = -1;
3525 cellsBuffer >> cell;
3527 long cellOriginalId = cell.getId();
3530 bool isInterior = (cellOwner == patchRank);
3531 cell.setInterior(isInterior);
3534 if (!verticesMap.empty()) {
3535 cell.renumberVertices(verticesMap);
3541 long cellId = Cell::NULL_ID;
3542 if (isHalo || isFrame) {
3543 for (
long candidateId : duplicateCellsCandidates) {
3544 const Cell &candidateCell = m_cells.at(candidateId);
3545 if (cell.hasSameConnect(candidateCell)) {
3546 cellId = candidateId;
3556 bool isTracked =
false;
3560 cell.resetInterfaces();
3569 if (m_cellIdGenerator) {
3570 if (m_cellIdGenerator->isAssigned(cellOriginalId)) {
3571 cell.setId(Cell::NULL_ID);
3573 }
else if (m_cells.exists(cellOriginalId)) {
3574 throw std::runtime_error(
"A cell with the same id of the received cell already exists.");
3577 CellIterator cellIterator =
addCell(std::move(cell), cellOwner, cellHaloLayer);
3578 cellId = cellIterator.getId();
3579 addedCells.push_back(cellId);
3582 if (!cellIterator->isInterior()) {
3583 if (ghostCellOwnershipChange >= 0) {
3584 ghostCellOwnershipChanges->insert({cellId, ghostCellOwnershipChange});
3589 isTracked = (trackPartitioning && isInterior);
3592 const Cell &localCell = m_cells[cellId];
3593 if (isInterior && !localCell.isInterior()) {
3595 ghostCellOwnershipChanges->erase(cellId);
3596 isTracked = trackPartitioning;
3601 const GhostCellInfo &ghostInfo = m_ghostCellInfo.at(cellId);
3602 if (ghostInfo.haloLayer > cellHaloLayer) {
3603 setGhostCellInfo(cellId, ghostInfo.owner, cellHaloLayer);
3609 FlatVector2D<long> &cellAdjacencies = duplicateCellsReceivedAdjacencies[cellId];
3611 int nCellFaces = cell.getFaceCount();
3612 int nCellAdjacencies = cell.getAdjacencyCount();
3613 cellAdjacencies.reserve(nCellFaces, nCellAdjacencies);
3614 for (
int face = 0; face < nCellFaces; ++face) {
3615 int nFaceAdjacencies = cell.getAdjacencyCount(face);
3616 const long *faceAdjacencies = cell.getAdjacencies(face);
3617 cellAdjacencies.pushBack(nFaceAdjacencies, faceAdjacencies);
3627 if (cellOriginalId != cellId) {
3628 cellsMap.insert({{cellOriginalId, cellId}});
3632 validReceivedAdjacencies.insert(cellOriginalId);
3647 partitioningData[sendRankIndex].current.emplace_back(cellId);
3652 cellsBuffers[sendRankIndex].reset();
3655 for (
long cellId : addedCells) {
3656 Cell &cell = m_cells.at(cellId);
3659 int nCellFaces = cell.getFaceCount();
3660 for (
int face = 0; face < nCellFaces; ++face) {
3661 int nFaceAdjacencies = cell.getAdjacencyCount(face);
3662 const long *faceAdjacencies = cell.getAdjacencies(face);
3665 while (k < nFaceAdjacencies) {
3666 long senderAdjacencyId = faceAdjacencies[k];
3667 if (validReceivedAdjacencies.count(senderAdjacencyId) == 0) {
3668 cell.deleteAdjacency(face, k);
3677 if (!cellsMap.empty()) {
3678 int nCellAdjacencies = cell.getAdjacencyCount();
3679 long *cellAdjacencies = cell.getAdjacencies();
3680 for (
int k = 0; k < nCellAdjacencies; ++k) {
3681 long &cellAdjacencyId = cellAdjacencies[k];
3682 auto cellsMapItr = cellsMap.find(cellAdjacencyId);
3683 if (cellsMapItr != cellsMap.end()) {
3684 cellAdjacencyId = cellsMapItr->second;
3700 if (!m_partitioningSerialization) {
3701 for (
auto &entry : duplicateCellsReceivedAdjacencies) {
3702 long cellId = entry.first;
3703 Cell &cell = m_cells.at(cellId);
3705 int nCellFaces = cell.getFaceCount();
3706 FlatVector2D<long> &cellReceivedAdjacencies = entry.second;
3707 for (
int face = 0; face < nCellFaces; ++face) {
3708 int nFaceLinkAdjacencies = cellReceivedAdjacencies.getItemCount(face);
3709 for (
int k = 0; k < nFaceLinkAdjacencies; ++k) {
3712 long receivedAdjacencyId = cellReceivedAdjacencies.getItem(face, k);
3713 if (validReceivedAdjacencies.count(receivedAdjacencyId) == 0) {
3719 long localAdjacencyId;
3720 auto ajacenciyCellMapItr = cellsMap.find(receivedAdjacencyId);
3721 if (ajacenciyCellMapItr != cellsMap.end()) {
3722 localAdjacencyId = ajacenciyCellMapItr->second;
3724 localAdjacencyId = receivedAdjacencyId;
3727 if (cell.findAdjacency(face, localAdjacencyId) >= 0) {
3731 cell.pushAdjacency(face, localAdjacencyId);
3738 for (
const Cell &cell : m_cells) {
3739 int nCellFaces = cell.getFaceCount();
3740 for (
int face = 0; face < nCellFaces; ++face) {
3741 if (cell.isFaceBorder(face)) {
3742 long cellId = cell.getId();
3751 awaitingSendRanks.erase(sendRank);
3765 return partitioningData;
3785 auto cellInfoItr = m_ghostCellInfo.find(
id);
3786 if (cellInfoItr == m_ghostCellInfo.end()) {
3789 return cellInfoItr->second.owner;
3801 auto cellInfoItr = m_ghostCellInfo.find(
id);
3802 if (cellInfoItr == m_ghostCellInfo.end()) {
3805 return cellInfoItr->second.owner;
3817 auto cellInfoItr = m_ghostCellInfo.find(
id);
3818 if (cellInfoItr == m_ghostCellInfo.end()) {
3821 return cellInfoItr->second.haloLayer;
3833 auto vertexInfoItr = m_ghostVertexInfo.find(
id);
3834 if (vertexInfoItr == m_ghostVertexInfo.end()) {
3837 return vertexInfoItr->second.owner;
3849 auto vertexInfoItr = m_ghostVertexInfo.find(
id);
3850 if (vertexInfoItr == m_ghostVertexInfo.end()) {
3853 return vertexInfoItr->second.owner;
3865 return (m_ghostCellExchangeTargets.count(rank) > 0);
3875 std::vector<int> neighRanks;
3876 neighRanks.reserve(m_ghostCellExchangeTargets.size());
3877 for (
const auto &entry : m_ghostCellExchangeTargets) {
3878 neighRanks.push_back(entry.first);
3902 return m_ghostVertexExchangeTargets;
3923 return m_ghostVertexExchangeTargets.at(rank);
3945 return m_ghostVertexExchangeSources;
3967 return m_ghostVertexExchangeSources.at(rank);
3988 return m_ghostCellExchangeTargets;
4030 return m_ghostCellExchangeTargets.at(rank);
4072 return m_ghostCellExchangeSources;
4114 return m_ghostCellExchangeSources.at(rank);
4144void PatchKernel::setGhostVertexInfo(
long id,
int owner)
4146 auto ghostVertexInfoItr = m_ghostVertexInfo.find(
id);
4147 if (ghostVertexInfoItr != m_ghostVertexInfo.end()) {
4148 ghostVertexInfoItr->second.owner = owner;
4150 GhostVertexInfo ghostVertexInfo;
4151 ghostVertexInfo.owner = owner;
4152 m_ghostVertexInfo.insert({id, std::move(ghostVertexInfo)});
4155 setPartitioningInfoDirty(
true);
4163void PatchKernel::unsetGhostVertexInfo(
long id)
4165 auto ghostVertexInfoItr = m_ghostVertexInfo.find(
id);
4166 if (ghostVertexInfoItr == m_ghostVertexInfo.end()) {
4170 m_ghostVertexInfo.erase(ghostVertexInfoItr);
4172 setPartitioningInfoDirty(
true);
4178void PatchKernel::clearGhostVerticesInfo()
4180 m_ghostVertexInfo.clear();
4182 setPartitioningInfoDirty(
true);
4192void PatchKernel::setGhostCellInfo(
long id,
int owner,
int haloLayer)
4194 auto ghostCellInfoItr = m_ghostCellInfo.find(
id);
4195 if (ghostCellInfoItr != m_ghostCellInfo.end()) {
4196 ghostCellInfoItr->second.owner = owner;
4197 ghostCellInfoItr->second.haloLayer = haloLayer;
4199 GhostCellInfo ghostCellInfo;
4200 ghostCellInfo.owner = owner;
4201 ghostCellInfo.haloLayer = haloLayer;
4202 m_ghostCellInfo.insert({id, std::move(ghostCellInfo)});
4205 setPartitioningInfoDirty(
true);
4213void PatchKernel::unsetGhostCellInfo(
long id)
4215 auto ghostCellInfoItr = m_ghostCellInfo.find(
id);
4216 if (ghostCellInfoItr == m_ghostCellInfo.end()) {
4220 m_ghostCellInfo.erase(ghostCellInfoItr);
4222 setPartitioningInfoDirty(
true);
4234void PatchKernel::computeCellHaloLayer(
int id)
4237 if (
getCell(
id).isInterior()) {
4238 unsetGhostCellInfo(
id);
4243 bool haloLayerIdentified =
false;
4245 std::array<long, 1> layerUpdateSeed = {{
id }};
4247 auto layerUpdateSelector = [](
long cellId) {
4253 auto layerUpdateProcessor = [
this, id, &haloLayerIdentified](
long cellId,
int layer) {
4254 const Cell &cell =
getCell(cellId);
4255 if (cell.isInterior()) {
4256 const GhostCellInfo &cellGhostInfo = m_ghostCellInfo.at(
id);
4257 if (cellGhostInfo.haloLayer != layer) {
4258 setGhostCellInfo(
id, cellGhostInfo.owner, layer);
4261 haloLayerIdentified =
true;
4271 if (!haloLayerIdentified) {
4272 throw std::runtime_error (
"Unable to identify the halo layer of the cell.");
4279void PatchKernel::clearGhostCellsInfo()
4281 m_ghostCellInfo.clear();
4283 setPartitioningInfoDirty(
true);
4300 bool partitioningInfoDirty = m_partitioningInfoDirty;
4303 MPI_Allreduce(MPI_IN_PLACE, &partitioningInfoDirty, 1, MPI_C_BOOL, MPI_LOR, communicator);
4306 return partitioningInfoDirty;
4314void PatchKernel::setPartitioningInfoDirty(
bool dirty)
4320 m_partitioningInfoDirty = dirty;
4329void PatchKernel::updatePartitioningInfo(
bool forcedUpdated)
4337 updateGhostCellExchangeInfo();
4340 updateGhostVertexExchangeInfo();
4346 setPartitioningInfoDirty(
false);
4381void PatchKernel::updateGhostVertexExchangeInfo()
4387 std::unordered_map<long, int> exchangeVertexOwners = evaluateExchangeVertexOwners();
4399 std::vector<long> previousGhosts;
4401 for (VertexConstIterator vertexItr = previousBeginItr; vertexItr != previousEndItr; ++vertexItr) {
4402 long vertexId = vertexItr.getId();
4403 if (exchangeVertexOwners.count(vertexId) != 0) {
4407 previousGhosts.push_back(vertexId);
4411 for (
long vertexId : previousGhosts) {
4422 std::map<std::size_t, long> newGhosts;
4423 for (
const auto &entry : exchangeVertexOwners) {
4424 int vertexOwner = entry.second;
4425 if (vertexOwner == patchRank) {
4429 long vertexId = entry.first;
4430 VertexIterator vertexItr = m_vertices.find(vertexId);
4431 if (!vertexItr->isInterior()) {
4435 newGhosts.insert({vertexItr.getRawIndex(), vertexId});
4442 for (VertexConstIterator vertexItr = beginItr; vertexItr != endItr; ++vertexItr) {
4443 long vertexId = vertexItr->getId();
4444 int vertexOwner = exchangeVertexOwners.at(vertexId);
4445 setGhostVertexInfo(vertexId, vertexOwner);
4455 for (
auto iter = newGhosts.rbegin(); iter != newGhosts.rend(); ++iter) {
4456 long vertexId = iter->second;
4457 int vertexOwner = exchangeVertexOwners.at(vertexId);
4468 m_ghostVertexExchangeTargets.clear();
4471 for (
const auto &entry : m_ghostVertexInfo) {
4472 int ghostVertexOwner = entry.second.owner;
4473 long ghostVertexId = entry.first;
4474 m_ghostVertexExchangeTargets[ghostVertexOwner].push_back(ghostVertexId);
4478 for (
auto &entry : m_ghostVertexExchangeTargets) {
4479 std::vector<long> &rankTargets = entry.second;
4480 std::sort(rankTargets.begin(), rankTargets.end(), VertexPositionLess(*
this));
4493 std::unordered_map<long, std::unordered_set<int>> sourcesDistribution;
4495 const int rank = entry.first;
4496 const std::vector<long> &cellList = entry.second;
4497 for (
long cellId : cellList) {
4498 sourcesDistribution[cellId].insert(rank);
4507 const int rank = entry.first;
4508 const std::vector<long> &cellList = entry.second;
4511 std::size_t bufferSize = 0;
4512 for (
long cellId : cellList) {
4513 bufferSize +=
sizeof(int) +
sizeof(
int) * sourcesDistribution[cellId].size();
4515 sourceDataCommunicator.setSend(rank, bufferSize);
4518 SendBuffer &buffer = sourceDataCommunicator.getSendBuffer(rank);
4519 for (
long cellId : cellList) {
4520 std::unordered_set<int> &cellRankDistribution = sourcesDistribution.at(cellId);
4521 int cellRankDistributionSize = cellRankDistribution.size();
4523 buffer << static_cast<int>(cellRankDistributionSize);
4524 for (
int sourceRank : cellRankDistribution) {
4525 buffer << sourceRank;
4531 sourceDataCommunicator.discoverRecvs();
4534 sourceDataCommunicator.startAllRecvs();
4535 sourceDataCommunicator.startAllSends();
4538 m_ghostVertexExchangeSources.clear();
4541 std::unordered_map<long, std::unordered_set<int>> uniqueSources;
4544 for (
auto &entry : m_ghostCellExchangeSources) {
4545 int rank = entry.first;
4548 for (
long cellId : entry.second) {
4549 const Cell &cell =
getCell(cellId);
4550 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
4551 for (
long vertexId : cellVertexIds) {
4553 if (m_ghostVertexInfo.count(vertexId) > 0) {
4558 uniqueSources[rank].insert(vertexId);
4569 std::vector<int> cellRankDistribution;
4571 int nCompletedCellRecvs = 0;
4572 while (nCompletedCellRecvs < sourceDataCommunicator.getRecvCount()) {
4573 int rank = sourceDataCommunicator.waitAnyRecv();
4576 RecvBuffer &buffer = sourceDataCommunicator.getRecvBuffer(rank);
4577 for (
long cellId : cellList) {
4578 int cellRankDistributionSize;
4579 buffer >> cellRankDistributionSize;
4580 cellRankDistribution.resize(cellRankDistributionSize);
4581 for (
int i = 0; i < cellRankDistributionSize; ++i) {
4582 buffer >> cellRankDistribution[i];
4585 const Cell &cell =
getCell(cellId);
4586 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
4587 for (
long vertexId : cellVertexIds) {
4589 if (m_ghostVertexInfo.count(vertexId) > 0) {
4594 for (
int cellRank : cellRankDistribution) {
4595 if (cellRank == patchRank) {
4599 uniqueSources[cellRank].insert(vertexId);
4604 ++nCompletedCellRecvs;
4608 for (
const auto &entry : uniqueSources) {
4609 int rank = entry.first;
4610 const std::unordered_set<int> &rankUniqueSources = entry.second;
4613 std::vector<long> &rankSources = m_ghostVertexExchangeSources[rank];
4614 rankSources.assign(rankUniqueSources.begin(), rankUniqueSources.end());
4617 std::sort(rankSources.begin(), rankSources.end(), VertexPositionLess(*
this));
4637std::unordered_map<long, int> PatchKernel::evaluateExchangeVertexOwners()
const
4646 for (
const auto &entry : m_ghostCellExchangeTargets) {
4647 int rank = entry.first;
4648 const std::vector<long> &cellIds = entry.second;
4650 std::size_t bufferSize = 0;
4651 for (
long cellId : cellIds) {
4652 const Cell &cell =
getCell(cellId);
4653 bufferSize +=
sizeof(int) * cell.getVertexCount();
4655 vertexOwnerCommunicator.setRecv(rank, bufferSize);
4656 vertexOwnerCommunicator.startRecv(rank);
4660 std::unordered_map<long, int> exchangeVertexOwners;
4662 for (
const auto &entry : m_ghostCellExchangeSources) {
4663 for (
long cellId : entry.second) {
4664 const Cell &cell =
getCell(cellId);
4665 for (
long vertexId : cell.getVertexIds()) {
4666 auto exchangeVertexOwnerItr = exchangeVertexOwners.find(vertexId);
4667 if (exchangeVertexOwnerItr == exchangeVertexOwners.end()) {
4668 exchangeVertexOwners.insert({vertexId, patchRank});
4674 for (
const auto &entry : m_ghostCellExchangeTargets) {
4675 int targetCellOwner = entry.first;
4676 for (
long cellId : entry.second) {
4677 const Cell &cell =
getCell(cellId);
4678 for (
long vertexId : cell.getVertexIds()) {
4679 auto exchangeVertexOwnerItr = exchangeVertexOwners.find(vertexId);
4680 if (exchangeVertexOwnerItr == exchangeVertexOwners.end()) {
4681 exchangeVertexOwners.insert({vertexId, targetCellOwner});
4683 int ¤tVertexOwner = exchangeVertexOwnerItr->second;
4684 if (targetCellOwner < currentVertexOwner) {
4685 currentVertexOwner = targetCellOwner;
4693 for (
const auto &entry : m_ghostCellExchangeSources) {
4694 int rank = entry.first;
4695 const std::vector<long> &cellIds = entry.second;
4697 std::size_t bufferSize = 0;
4698 for (
long cellId : cellIds) {
4699 const Cell &cell =
getCell(cellId);
4700 bufferSize +=
sizeof(int) * cell.getVertexCount();
4702 vertexOwnerCommunicator.setSend(rank, bufferSize);
4704 SendBuffer &buffer = vertexOwnerCommunicator.getSendBuffer(rank);
4705 for (
long cellId : cellIds) {
4706 const Cell &cell =
getCell(cellId);
4707 for (
long vertexId : cell.getVertexIds()) {
4708 buffer << exchangeVertexOwners.at(vertexId);
4711 vertexOwnerCommunicator.startSend(rank);
4715 int nCompletedRecvs = 0;
4716 while (nCompletedRecvs < vertexOwnerCommunicator.getRecvCount()) {
4717 int rank = vertexOwnerCommunicator.waitAnyRecv();
4718 const std::vector<long> &cellIds = m_ghostCellExchangeTargets.at(rank);
4719 RecvBuffer &buffer = vertexOwnerCommunicator.getRecvBuffer(rank);
4721 for (
long cellId : cellIds) {
4722 const Cell &cell =
getCell(cellId);
4723 for (
long vertexId : cell.getVertexIds()) {
4724 int remoteVertexOwner;
4725 buffer >> remoteVertexOwner;
4727 int ¤tVertexOwner = exchangeVertexOwners.at(vertexId);
4728 if (remoteVertexOwner < currentVertexOwner) {
4729 currentVertexOwner = remoteVertexOwner;
4738 vertexOwnerCommunicator.waitAllSends();
4740 return exchangeVertexOwners;
4746void PatchKernel::updateGhostCellExchangeInfo()
4749 m_ghostCellExchangeTargets.clear();
4752 for (
const auto &entry : m_ghostCellInfo) {
4753 int ghostOwner = entry.second.owner;
4754 long ghostCellId = entry.first;
4755 m_ghostCellExchangeTargets[ghostOwner].push_back(ghostCellId);
4759 for (
auto &entry : m_ghostCellExchangeTargets) {
4760 std::vector<long> &rankTargets = entry.second;
4761 std::sort(rankTargets.begin(), rankTargets.end(), CellPositionLess(*
this));
4765 m_ghostCellExchangeSources.clear();
4768 for (
auto &entry : m_ghostCellExchangeTargets) {
4769 int rank = entry.first;
4773 if (rankSources.empty()) {
4774 m_ghostCellExchangeSources.erase(rank);
4779 std::sort(rankSources.begin(), rankSources.end(), CellPositionLess(*
this));
4782 m_ghostCellExchangeSources[rank] = std::move(rankSources);
4798 auto ghostExchangeTargetsItr = m_ghostCellExchangeTargets.find(rank);
4799 if (ghostExchangeTargetsItr == m_ghostCellExchangeTargets.end()) {
4800 return std::vector<long>();
4803 const std::vector<long> &rankTargets = ghostExchangeTargetsItr->second;
4806 std::vector<long> exchangeSources;
4808 auto sourceSelector = [](
long cellId) {
4814 auto sourceBuilder = [
this, &exchangeSources](
long cellId,
int layer) {
4817 if (m_ghostCellInfo.count(cellId) == 0) {
4818 exchangeSources.push_back(cellId);
4826 return exchangeSources;
The Cell class defines the cells.
void initialize(long id, ElementType type, bool interior, bool storeNeighbourhood)
The DataCommunicator class provides the infrastructure needed to exchange data among processes.
static ConstProxyVector< long > getVertexIds(ElementType type, const long *connectivity)
int getVertexCount() const
VertexIterator vertexEnd()
void unsetCellAlterationFlags(AlterationFlags flags)
InterfacesBuildStrategy getInterfacesBuildStrategy() const
CellConstIterator internalCellConstEnd() const
AdjacenciesBuildStrategy getAdjacenciesBuildStrategy() const
int getVertexOwner(long id) const
const std::unordered_map< int, std::vector< long > > & getGhostCellExchangeSources() const
VertexIterator ghostVertexEnd()
virtual std::vector< long > _findGhostCellExchangeSources(int rank)
long getGhostVertexCount() const
void pruneStaleAdjacencies()
void updateFirstGhostCellId()
VertexIterator restoreVertex(const std::array< double, 3 > &coords, int owner, long id)
AdaptionMode getAdaptionMode() const
CellIterator restoreCell(ElementType type, std::unique_ptr< long[]> &&connectStorage, int owner, int haloLayer, long id)
CellConstIterator internalCellConstBegin() const
VertexIterator vertexBegin()
virtual std::vector< adaption::Info > _partitioningPrepare(const std::unordered_map< long, double > &cellWeights, double defaultWeight, bool trackPartitioning)
virtual long getVertexCount() const
const std::unordered_map< int, std::vector< long > > & getGhostCellExchangeTargets() const
bool isRankNeighbour(int rank)
CellIterator ghostCellEnd()
void addPointToBoundingBox(const std::array< double, 3 > &point)
VertexIterator addVertex(const Vertex &source, long id=Vertex::NULL_ID)
bool empty(bool global=true) const
PartitioningMode getPartitioningMode() const
void processCellsNeighbours(const SeedContainer &seedIds, int nLayers, Function function) const
VertexIterator internalVertex2GhostVertex(long id, int owner)
virtual std::vector< adaption::Info > _partitioningAlter(bool trackPartitioning)
CellIterator ghostCellBegin()
CellIterator ghostBegin()
int getVertexRank(long id) const
std::vector< adaption::Info > partition(MPI_Comm communicator, const std::unordered_map< long, int > &cellRanks, bool trackPartitioning, bool squeezeStorage=false, std::size_t haloSize=1)
CellIterator addCell(const Cell &source, long id=Element::NULL_ID)
PartitioningStatus getPartitioningStatus(bool global=false) const
int getCellRank(long id) const
virtual void _partitioningCleanup()
void updateInterfaces(bool forcedUpdated=false)
const std::unordered_map< int BITPIT_COMMA std::vector< long > > & getGhostExchangeTargets() const
bool arePartitioningInfoDirty(bool global=true) const
CellIterator internalCell2GhostCell(long id, int owner, int haloLayer)
CellIterator ghostCell2InternalCell(long id)
VertexConstIterator ghostVertexConstEnd() const
int getOwner(bool allowDirty=false) const
void partitioningCleanup()
double evalPartitioningUnbalance() const
CellConstIterator ghostCellConstEnd() const
static const double DEFAULT_PARTITIONING_WEIGTH
VertexIterator ghostVertexBegin()
const MPI_Comm & getCommunicator() const
std::size_t getHaloSize() const
virtual int findAdjoinNeighFace(const Cell &cell, int cellFace, const Cell &neigh) const
CellConstIterator ghostConstEnd() const
void updateFirstGhostVertexId()
void setHaloSize(std::size_t haloSize)
Vertex & getFirstGhostVertex()
bool isPartitioned() const
Vertex & getVertex(long id)
virtual std::size_t _getMaxHaloSize()
std::vector< adaption::Info > partitioningPrepare(MPI_Comm communicator, const std::unordered_map< long, int > &cellRanks, bool trackPartitioning, std::size_t haloSize=1)
virtual long getCellCount() const
VertexIterator ghostVertex2InternalVertex(long id)
VertexConstIterator ghostVertexConstBegin() const
const std::unordered_map< int, std::vector< long > > & getGhostVertexExchangeTargets() const
void removePointFromBoundingBox(const std::array< double, 3 > &point)
std::vector< long > findCellVertexNeighs(long id, bool complete=true) const
bool isDistributed(bool allowDirty=false) const
std::vector< adaption::Info > partitioningAlter(bool trackPartitioning=true, bool squeezeStorage=false)
bool deleteOrphanVertices()
int getCellHaloLayer(long id) const
const std::unordered_map< int, std::vector< long > > & getGhostVertexExchangeSources() const
void updateAdjacencies(bool forcedUpdated=false)
void setPartitioningMode(PartitioningMode mode)
const std::unordered_map< int BITPIT_COMMA std::vector< long > > & getGhostExchangeSources() const
std::vector< long > findCellEdgeNeighs(long id, bool complete=true) const
long getInternalCellCount() const
int getProcessorCount() const
void setPartitioningStatus(PartitioningStatus status)
CellConstIterator ghostCellConstBegin() const
long getInternalVertexCount() const
CellConstIterator ghostConstBegin() const
bool deleteCells(const IdStorage &ids)
bool reserveCells(size_t nCells)
std::vector< int > getNeighbourRanks()
bool isPartitioningSupported() const
void setCellAlterationFlags(AlterationFlags flags)
long getGhostCellCount() const
long getGhostCount() const
bool reserveVertices(size_t nVertices)
virtual void _setHaloSize(std::size_t haloSize)
bool isCommunicatorSet() const
int getCellOwner(long id) const
virtual void setCommunicator(MPI_Comm communicator)
void pruneStaleInterfaces()
Cell & getFirstGhostCell()
id_t getId(const id_t &fallback=-1) const noexcept
Iterator for the class PiercedStorage.
static bool hasInfo(ElementType type)
static BITPIT_PUBLIC_API const ReferenceElementInfo & getInfo(ElementType type)
void setParallel(uint16_t, uint16_t)
The Vertex class defines the vertexs.
void initialize(long id, const std::array< double, 3 > &coords, bool interior)
std::array< double, 3 > & getCoords()
#define BITPIT_UNUSED(variable)
CommunicationTags & tags()
The Info struct defines the information associated to an adaption.