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) {
86 m_vtk.setParallel(m_nProcessors, m_rank);
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);
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);
409 ++m_nInternalVertices;
413 m_lastInternalVertexId = id;
414 if (m_nGhostVertices == 0) {
415 m_firstGhostVertexId = Vertex::NULL_ID;
417 VertexIterator firstGhostVertexIterator =
iterator;
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];
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)
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) {
603 VertexIterator firstGhostVertexItr =
vertexBegin();
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);
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);
680 m_lastInternalCellId = id;
681 if (m_nGhostCells == 0) {
682 m_firstGhostCellId = Cell::NULL_ID;
684 CellIterator firstGhostCellIterator =
iterator;
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)
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);
1151 std::unique_ptr<
long[]> &&connectStorage,
1152 int owner,
int haloLayer)
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) {
1295 CellIterator firstghostCellItr =
cellBegin();
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.;
1802 for (CellConstIterator cellItr = beginItr; cellItr != endItr; ++cellItr) {
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);
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;
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());
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 int getDimension(ElementType type)
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()
iterator find(const id_t &id) noexcept
static bool hasInfo(ElementType type)
static BITPIT_PUBLIC_API const ReferenceElementInfo & getInfo(ElementType type)
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 infomation associated to an adaption.