Commit 32b71148 authored by Thomas Witkowski's avatar Thomas Witkowski
Browse files

Fixed some bugs for periodic BCs in 3D in parrallel computing.

parent 8be28f3a
......@@ -172,6 +172,7 @@ namespace AMDiS {
}
}
BoundaryType ElInfo::getBoundary(GeoIndex pos, int i)
{
static int indexOffset[3][3] = {
......
......@@ -14,11 +14,13 @@
#include "FiniteElemSpace.h"
#include "BasisFunction.h"
#include "Serializer.h"
#include "VertexVector.h"
namespace AMDiS {
void BoundaryObject::setReverseMode(BoundaryObject &otherBound,
FiniteElemSpace *feSpace)
FiniteElemSpace *feSpace,
BoundaryType boundary)
{
FUNCNAME("BoundaryObject::setReverseMode()");
......@@ -31,7 +33,8 @@ namespace AMDiS {
case 3:
TEST_EXIT_DBG(otherBound.elType == 0)
("Only 3D macro elements with level 0 are supported!\n");
("Only 3D macro elements with level 0 are supported. This element has level %d!\n", otherBound.elType);
if (subObj == EDGE) {
int el0_v0 = el->getVertexOfEdge(ithObj, 0);
......@@ -45,15 +48,22 @@ namespace AMDiS {
basFcts->getLocalIndices(el, feSpace->getAdmin(), localDofs0);
basFcts->getLocalIndices(otherBound.el, feSpace->getAdmin(), localDofs1);
TEST_EXIT_DBG(localDofs0[el0_v0] == localDofs1[el1_v0] ||
localDofs0[el0_v0] == localDofs1[el1_v1])
("This should not happen!\n");
TEST_EXIT_DBG(localDofs0[el0_v1] == localDofs1[el1_v0] ||
localDofs0[el0_v1] == localDofs1[el1_v1])
("This should not happen!\n");
if (localDofs0[el0_v0] != localDofs1[el1_v0])
otherMode = true;
Mesh *mesh = feSpace->getMesh();
if (mesh->isPeriodicAssociation(boundary) == false) {
TEST_EXIT_DBG(localDofs0[el0_v0] == localDofs1[el1_v0] ||
localDofs0[el0_v0] == localDofs1[el1_v1])
("This should not happen!\n");
TEST_EXIT_DBG(localDofs0[el0_v1] == localDofs1[el1_v0] ||
localDofs0[el0_v1] == localDofs1[el1_v1])
("This should not happen!\n");
if (localDofs0[el0_v0] != localDofs1[el1_v0])
otherMode = true;
} else {
if (mesh->associated(localDofs0[el0_v0], localDofs1[el1_v0]) == false)
otherMode = true;
}
}
if (subObj == FACE && ithObj != 1) {
......
......@@ -54,7 +54,9 @@ namespace AMDiS {
excludedSubstructures(0)
{}
void setReverseMode(BoundaryObject &otherBound, FiniteElemSpace *feSpace);
void setReverseMode(BoundaryObject &otherBound,
FiniteElemSpace *feSpace,
BoundaryType boundary);
bool operator==(const BoundaryObject& other) const;
......
......@@ -221,6 +221,7 @@ namespace AMDiS {
createPeriodicMap();
// === Global refinements. ===
int globalRefinement = 0;
......@@ -544,10 +545,15 @@ namespace AMDiS {
(mesh->getDim() == 3 && it->rankObj.subObj == FACE))
allBound[it.getRank()].push_back(*it);
for (InteriorBoundary::iterator it(periodicBoundary); !it.end(); ++it)
if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) ||
(mesh->getDim() == 3 && it->rankObj.subObj == FACE))
allBound[it.getRank()].push_back(*it);
for (InteriorBoundary::iterator it(periodicBoundary); !it.end(); ++it) {
if (it.getRank() == mpiRank) {
// ERROR_EXIT("Na, du weisst schon!\n");
} else {
if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) ||
(mesh->getDim() == 3 && it->rankObj.subObj == FACE))
allBound[it.getRank()].push_back(*it);
}
}
// === Check the boundaries and adapt mesh if necessary. ===
......@@ -579,8 +585,7 @@ namespace AMDiS {
// === Update periodic mapping, if there are periodic boundaries. ===
createPeriodicMap();
createPeriodicMap();
INFO(info, 8)("Parallel mesh adaption needed %.5f seconds\n",
......@@ -1256,6 +1261,8 @@ namespace AMDiS {
{
FUNCNAME("MeshDistributor::createInteriorBoundaryInfo()");
MSG("CREATE BOUNDARY INFO!\n");
createMeshElementData();
createBoundaryData();
......@@ -1267,6 +1274,8 @@ namespace AMDiS {
{
FUNCNAME("MeshDistributor::updateInteriorBoundaryInfo()");
MSG("UPDATE BOUNDARY INFO!\n");
elObjects.createRankData(partitionVec);
createBoundaryData();
......@@ -1277,6 +1286,13 @@ namespace AMDiS {
{
FUNCNAME("MeshDistributor::createMeshElementData()");
// Stores to each vertex all its periodic associations.
std::map<DegreeOfFreedom, std::set<BoundaryType> > periodicDofAssoc;
// Stores to each edge all its periodic associations.
std::map<DofEdge, std::set<DofEdge> > periodicEdgeAssoc;
// === Fills macro element data structures. ===
TraverseStack stack;
......@@ -1301,43 +1317,68 @@ namespace AMDiS {
switch (mesh->getDim()) {
case 2:
for (int i = 0; i < el->getGeo(EDGE); i++) {
if (mesh->isPeriodicAssociation(elInfo->getBoundary(i))) {
if (mesh->isPeriodicAssociation(elInfo->getBoundary(EDGE, i))) {
Element *neigh = elInfo->getNeighbour(i);
DofEdge edge1 = el->getEdge(i);
DofEdge edge2 = elInfo->getNeighbour(i)->getEdge(elInfo->getOppVertex(i));
BoundaryType boundaryType = elInfo->getBoundary(i);
DofEdge edge2 = neigh->getEdge(elInfo->getOppVertex(i));
BoundaryType boundaryType = elInfo->getBoundary(EDGE, i);
periodicEdges[std::make_pair(edge1, edge2)] = boundaryType;
periodicEdgeAssoc[edge1].insert(edge2);
for (int j = 0; j < 2; j++) {
int ithDofRankObj = el->getVertexOfEdge(i, j);
DegreeOfFreedom dof = el->getDof(ithDofRankObj, 0);
DegreeOfFreedom neighDof = -1;
int ithDofNeighObj = -1;
for (int k = 0; k < 3; k++) {
if (elInfo->getNeighbour(i)->getDof(k, 0) ==
mesh->getPeriodicAssociations(boundaryType)[dof]) {
neighDof = elInfo->getNeighbour(i)->getDof(k, 0);
ithDofNeighObj = k;
break;
}
}
TEST_EXIT_DBG(neighDof > -1)("Should not happen!\n");
periodicDofs[std::make_pair(dof, neighDof)] = boundaryType;
periodicDofAssoc[dof].insert(boundaryType);
}
periodicDofs[std::make_pair(edge1.first, edge2.first)] = boundaryType;
periodicDofs[std::make_pair(edge1.second, edge2.second)] = boundaryType;
periodicDofAssoc[edge1.first].insert(boundaryType);
periodicDofAssoc[edge1.second].insert(boundaryType);
TEST_EXIT_DBG(edge1.first == mesh->getPeriodicAssociations(boundaryType)[edge2.first] &&
edge1.second == mesh->getPeriodicAssociations(boundaryType)[edge2.second])
("Should not happen!\n");
}
}
break;
case 3:
for (int i = 0; i < el->getGeo(FACE); i++) {
if (mesh->isPeriodicAssociation(elInfo->getBoundary(i))) {
if (mesh->isPeriodicAssociation(elInfo->getBoundary(FACE, i))) {
Element *neigh = elInfo->getNeighbour(i);
DofFace face1 = el->getFace(i);
DofFace face2 = elInfo->getNeighbour(i)->getFace(elInfo->getOppVertex(i));
DofFace face2 = neigh->getFace(elInfo->getOppVertex(i));
BoundaryType boundaryType = elInfo->getBoundary(FACE, i);
periodicFaces[std::make_pair(face1, face2)] = elInfo->getBoundary(i);
periodicDofs[std::make_pair(face1.get<0>(), face2.get<0>())] = boundaryType;
periodicDofs[std::make_pair(face1.get<1>(), face2.get<1>())] = boundaryType;
periodicDofs[std::make_pair(face1.get<2>(), face2.get<2>())] = boundaryType;
periodicDofAssoc[face1.get<0>()].insert(boundaryType);
periodicDofAssoc[face1.get<1>()].insert(boundaryType);
periodicDofAssoc[face1.get<2>()].insert(boundaryType);
TEST_EXIT_DBG(face1.get<0>() == mesh->getPeriodicAssociations(boundaryType)[face2.get<0>()] &&
face1.get<1>() == mesh->getPeriodicAssociations(boundaryType)[face2.get<1>()] &&
face1.get<2>() == mesh->getPeriodicAssociations(boundaryType)[face2.get<2>()])
("Should not happen!\n");
DofEdge elEdge1 = std::make_pair(face1.get<0>(), face1.get<1>());
DofEdge elEdge2 = std::make_pair(face1.get<0>(), face1.get<2>());
DofEdge elEdge3 = std::make_pair(face1.get<1>(), face1.get<2>());
DofEdge neighEdge1 = std::make_pair(face2.get<0>(), face2.get<1>());
DofEdge neighEdge2 = std::make_pair(face2.get<0>(), face2.get<2>());
DofEdge neighEdge3 = std::make_pair(face2.get<1>(), face2.get<2>());
periodicEdges[std::make_pair(elEdge1, neighEdge1)] = boundaryType;
periodicEdges[std::make_pair(elEdge2, neighEdge2)] = boundaryType;
periodicEdges[std::make_pair(elEdge3, neighEdge3)] = boundaryType;
periodicEdgeAssoc[elEdge1].insert(neighEdge1);
periodicEdgeAssoc[elEdge2].insert(neighEdge2);
periodicEdgeAssoc[elEdge3].insert(neighEdge3);
}
}
break;
......@@ -1355,35 +1396,90 @@ namespace AMDiS {
// === Search for interectly connected vertices in periodic boundaries. ===
if (periodicDofs.size() > 0) {
TEST_EXIT(mesh->getDim() == 2)("Parallel boundaries not yet supported in 3D!\n");
std::vector<DegreeOfFreedom> twoPeriodicDof;
// === Search for an unsed boundary index. ===
BoundaryType newPeriodicBoundaryType = 0;
for (std::map<BoundaryType, VertexVector*>::iterator it = mesh->getPeriodicAssociations().begin();
it != mesh->getPeriodicAssociations().end(); ++it)
newPeriodicBoundaryType = min(newPeriodicBoundaryType, it->first);
TEST_EXIT_DBG(newPeriodicBoundaryType < 0)("Should not happen!\n");
newPeriodicBoundaryType--;
mesh->getPeriodicAssociations()[newPeriodicBoundaryType] =
new VertexVector(feSpace->getAdmin(), "");
// === Get all vertex DOFs that have multiple periodic associations. ===
std::vector<DegreeOfFreedom> multiplePeriodicDof;
for (std::map<DegreeOfFreedom, std::set<BoundaryType> >::iterator it = periodicDofAssoc.begin();
it != periodicDofAssoc.end(); ++it) {
TEST_EXIT_DBG(it->second.size() < 3)("Should not happen!\n");
if (mesh->getDim() == 2) {
TEST_EXIT_DBG(it->second.size() <= 2)("Should not happen!\n");
}
if (mesh->getDim() == 3) {
TEST_EXIT_DBG(it->second.size() <= 3)("Should not happen!\n");
}
if (it->second.size() == 2)
twoPeriodicDof.push_back(it->first);
if ((mesh->getDim() == 2 && it->second.size() == 2) ||
(mesh->getDim() == 3 && it->second.size() == 3))
multiplePeriodicDof.push_back(it->first);
}
TEST_EXIT_DBG(twoPeriodicDof.size() == 0 || twoPeriodicDof.size() == 4)
("Should not happen (%d)!\n", twoPeriodicDof.size());
if (twoPeriodicDof.size() == 4) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (i == j)
continue;
std::pair<DegreeOfFreedom, DegreeOfFreedom> perDofs =
std::make_pair(twoPeriodicDof[i], twoPeriodicDof[j]);
if (mesh->getDim() == 2) {
TEST_EXIT_DBG(multiplePeriodicDof.size() == 0 ||
multiplePeriodicDof.size() == 4)
("Should not happen (%d)!\n", multiplePeriodicDof.size());
}
if (periodicDofs.count(perDofs) == 0)
periodicDofs[perDofs] = 3;
}
if (mesh->getDim() == 3) {
TEST_EXIT_DBG(multiplePeriodicDof.size() == 0 ||
multiplePeriodicDof.size() == 8)
("Should not happen (%d)!\n", multiplePeriodicDof.size());
}
int nMultiplePeriodicDofs = multiplePeriodicDof.size();
for (int i = 0; i < nMultiplePeriodicDofs; i++) {
for (int j = 0; j < nMultiplePeriodicDofs; j++) {
if (i == j)
continue;
std::pair<DegreeOfFreedom, DegreeOfFreedom> perDofs =
std::make_pair(multiplePeriodicDof[i], multiplePeriodicDof[j]);
if (periodicDofs.count(perDofs) == 0)
periodicDofs[perDofs] = newPeriodicBoundaryType;
}
}
// === Get all edges that have multiple periodic associations (3D only!). ===
for (std::map<DofEdge, std::set<DofEdge> >::iterator it = periodicEdgeAssoc.begin();
it != periodicEdgeAssoc.end(); ++it) {
if (it->second.size() > 1) {
TEST_EXIT_DBG(mesh->getDim() == 3)("Should not happen!\n");
TEST_EXIT_DBG(it->second.size() == 2)("Should not happen!\n");
std::pair<DofEdge, DofEdge> perEdge0 =
std::make_pair(*(it->second.begin()), *(++(it->second.begin())));
std::pair<DofEdge, DofEdge> perEdge1 =
std::make_pair(perEdge0.second, perEdge0.first);
periodicEdges[perEdge0] = newPeriodicBoundaryType;
periodicEdges[perEdge1] = newPeriodicBoundaryType;
}
}
}
}
......@@ -1450,7 +1546,7 @@ namespace AMDiS {
AtomicBoundary& b = myIntBoundary.getNewAtomic(it2->first);
b = bound;
b.rankObj.setReverseMode(b.neighObj, feSpace);
b.rankObj.setReverseMode(b.neighObj, feSpace, bound.type);
}
} else {
......@@ -1473,7 +1569,7 @@ namespace AMDiS {
AtomicBoundary& b = otherIntBoundary.getNewAtomic(owner);
b = bound;
b.neighObj.setReverseMode(b.rankObj, feSpace);
b.neighObj.setReverseMode(b.rankObj, feSpace, bound.type);
}
}
}
......@@ -1487,11 +1583,12 @@ namespace AMDiS {
if (elObjects.isInRank(it->first.first, mpiRank) == false)
continue;
ElementObjectData& perDofEl0 = elObjects.getElementsInRank(it->first.first)[mpiRank];
for (std::map<int, ElementObjectData>::iterator elIt = elObjects.getElementsInRank(it->first.second).begin();
elIt != elObjects.getElementsInRank(it->first.second).end(); ++elIt) {
int otherElementRank = elIt->first;
ElementObjectData& perDofEl0 = elObjects.getElementsInRank(it->first.first)[mpiRank];
ElementObjectData& perDofEl1 = elIt->second;
AtomicBoundary bound;
......@@ -1503,7 +1600,7 @@ namespace AMDiS {
bound.neighObj.el = macroElIndexMap[perDofEl1.elIndex];
bound.neighObj.elIndex = perDofEl1.elIndex;
bound.neighObj.elType = -1;
bound.neighObj.elType = macroElIndexTypeMap[perDofEl1.elIndex];
bound.neighObj.subObj = VERTEX;
bound.neighObj.ithObj = perDofEl1.ithObject;
......@@ -1515,50 +1612,88 @@ namespace AMDiS {
}
for (std::map<std::pair<DofEdge, DofEdge>, BoundaryType>::iterator it = periodicEdges.begin();
it != periodicEdges.end(); ++it) {
int perEdgeOwner0 = elObjects.getOwner(it->first.first);
int perEdgeOwner1 = elObjects.getOwner(it->first.second);
if (elObjects.isInRank(it->first.first, mpiRank) == false)
continue;
ElementObjectData& perEdgeEl0 = elObjects.getElementsInRank(it->first.first)[mpiRank];
for (std::map<int, ElementObjectData>::iterator elIt = elObjects.getElementsInRank(it->first.second).begin();
elIt != elObjects.getElementsInRank(it->first.second).end(); ++elIt) {
int otherElementRank = elIt->first;
ElementObjectData& perEdgeEl1 = elIt->second;
AtomicBoundary bound;
bound.rankObj.el = macroElIndexMap[perEdgeEl0.elIndex];
bound.rankObj.elIndex = perEdgeEl0.elIndex;
bound.rankObj.elType = macroElIndexTypeMap[perEdgeEl0.elIndex];
bound.rankObj.subObj = EDGE;
bound.rankObj.ithObj = perEdgeEl0.ithObject;
bound.neighObj.el = macroElIndexMap[perEdgeEl1.elIndex];
bound.neighObj.elIndex = perEdgeEl1.elIndex;
bound.neighObj.elType = macroElIndexTypeMap[perEdgeEl1.elIndex];
bound.neighObj.subObj = EDGE;
bound.neighObj.ithObj = perEdgeEl1.ithObject;
bound.type = it->second;
AtomicBoundary& b = periodicBoundary.getNewAtomic(otherElementRank);
b = bound;
if (mpiRank > otherElementRank)
b.rankObj.setReverseMode(b.neighObj, feSpace, bound.type);
else
b.neighObj.setReverseMode(b.rankObj, feSpace, bound.type);
}
}
if (perEdgeOwner0 != mpiRank)
for (std::map<std::pair<DofFace, DofFace>, BoundaryType>::iterator it = periodicFaces.begin();
it != periodicFaces.end(); ++it) {
if (elObjects.isInRank(it->first.first, mpiRank) == false)
continue;
TEST_EXIT_DBG(perEdgeOwner0 != perEdgeOwner1)("Should not happen!\n");
TEST_EXIT_DBG(elObjects.getElements(it->first.first).size() == 1)
("Should not happen!\n");
("Should not happen!\n");
TEST_EXIT_DBG(elObjects.getElements(it->first.second).size() == 1)
("Should not happen!\n");
int otherElementRank = perEdgeOwner1;
ElementObjectData& perEdgeEl0 = elObjects.getElements(it->first.first)[0];
ElementObjectData& perEdgeEl1 = elObjects.getElements(it->first.second)[0];
AtomicBoundary bound;
bound.rankObj.el = macroElIndexMap[perEdgeEl0.elIndex];
bound.rankObj.elIndex = perEdgeEl0.elIndex;
bound.rankObj.elType = macroElIndexTypeMap[perEdgeEl0.elIndex];
bound.rankObj.subObj = EDGE;
bound.rankObj.ithObj = perEdgeEl0.ithObject;
bound.neighObj.el = macroElIndexMap[perEdgeEl1.elIndex];
bound.neighObj.elIndex = perEdgeEl1.elIndex;
bound.neighObj.elType = -1;
bound.neighObj.subObj = EDGE;
bound.neighObj.ithObj = perEdgeEl1.ithObject;
bound.type = it->second;
AtomicBoundary& b = periodicBoundary.getNewAtomic(otherElementRank);
b = bound;
if (mpiRank > otherElementRank)
b.rankObj.setReverseMode(b.neighObj, feSpace);
else
b.neighObj.setReverseMode(b.rankObj, feSpace);
}
("Should not happen!\n");
ElementObjectData& perEdgeEl0 = elObjects.getElementsInRank(it->first.first)[mpiRank];
for (std::map<int, ElementObjectData>::iterator elIt = elObjects.getElementsInRank(it->first.second).begin();
elIt != elObjects.getElementsInRank(it->first.second).end(); ++elIt) {
int otherElementRank = elIt->first;
ElementObjectData& perEdgeEl1 = elIt->second;
AtomicBoundary bound;
bound.rankObj.el = macroElIndexMap[perEdgeEl0.elIndex];
bound.rankObj.elIndex = perEdgeEl0.elIndex;
bound.rankObj.elType = macroElIndexTypeMap[perEdgeEl0.elIndex];
bound.rankObj.subObj = FACE;
bound.rankObj.ithObj = perEdgeEl0.ithObject;
bound.neighObj.el = macroElIndexMap[perEdgeEl1.elIndex];
bound.neighObj.elIndex = perEdgeEl1.elIndex;
bound.neighObj.elType = macroElIndexTypeMap[perEdgeEl1.elIndex];
bound.neighObj.subObj = FACE;
bound.neighObj.ithObj = perEdgeEl1.ithObject;
bound.type = it->second;
AtomicBoundary& b = periodicBoundary.getNewAtomic(otherElementRank);
b = bound;
if (mpiRank > otherElementRank)
b.rankObj.setReverseMode(b.neighObj, feSpace, bound.type);
else
b.neighObj.setReverseMode(b.rankObj, feSpace, bound.type);
}
}
// === Once we have this information, we must care about the order of the atomic ===
// === bounds in the three boundary handling object. Eventually all the bound- ===
......@@ -1569,6 +1704,7 @@ namespace AMDiS {
stdMpi.recv(otherIntBoundary.boundary);
stdMpi.startCommunication<int>(MPI_INT);
// === The information about all neighbouring boundaries has been received. So ===
// === the rank tests if its own atomic boundaries are in the same order. If ===
// === not, the atomic boundaries are swaped to the correct order. ===
......@@ -1614,43 +1750,66 @@ namespace AMDiS {
for (RankToBoundMap::iterator rankIt = periodicBoundary.boundary.begin();
rankIt != periodicBoundary.boundary.end(); ++rankIt) {
TEST_EXIT_DBG(rankIt->first != mpiRank)
("It is not allowed to have an interior boundary within a rank partition!\n");
if (rankIt->first == mpiRank)
continue;
if (rankIt->first < mpiRank)
sendBounds.boundary[rankIt->first] = rankIt->second;
else
recvBounds.boundary[rankIt->first] = rankIt->second;
recvBounds.boundary[rankIt->first] = rankIt->second;
}
stdMpi.send(sendBounds.boundary);
stdMpi.recv(recvBounds.boundary);
stdMpi.startCommunication<int>(MPI_INT);
/*
for (RankToBoundMap::iterator rankIt = periodicBoundary.boundary.begin();
rankIt != periodicBoundary.boundary.end(); ++rankIt) {
if (rankIt->first <= mpiRank)
continue;
for (unsigned int j = 0; j < rankIt->second.size(); j++) {
BoundaryObject &recvedBound = stdMpi.getRecvData()[rankIt->first][j].rankObj;
if (periodicBoundary.boundary[rankIt->first][j].neighObj != recvedBound) {
MSG("%-ith boundary with rank %d\n", j, rankIt->first);
MSG(" bound: el = %d subobj = %d ithobj = %d\n",
periodicBoundary.boundary[rankIt->first][j].rankObj.elIndex,
periodicBoundary.boundary[rankIt->first][j].rankObj.subObj,
periodicBoundary.boundary[rankIt->first][j].rankObj.ithObj);
MSG(" neigh: el = %d subobj = %d ithobj = %d\n",
periodicBoundary.boundary[rankIt->first][j].neighObj.elIndex,
periodicBoundary.boundary[rankIt->first][j].neighObj.subObj,
periodicBoundary.boundary[rankIt->first][j].neighObj.ithObj);
}
}
*/
for (RankToBoundMap::iterator rankIt = periodicBoundary.boundary.begin();
rankIt != periodicBoundary.boundary.end(); ++rankIt) {
if (rankIt->first <= mpiRank)
continue;
for (unsigned int j = 0; j < rankIt->second.size(); j++) {
BoundaryObject &recvRankObj = stdMpi.getRecvData()[rankIt->first][j].rankObj;
BoundaryObject &recvNeighObj = stdMpi.getRecvData()[rankIt->first][j].neighObj;
if (periodicBoundary.boundary[rankIt->first][j].neighObj != recvRankObj ||
periodicBoundary.boundary[rankIt->first][j].rankObj != recvNeighObj) {
unsigned int k = j + 1;
for (; k < rankIt->second.size(); k++)
if (periodicBoundary.boundary[rankIt->first][k].neighObj == recvedBound)
if (periodicBoundary.boundary[rankIt->first][k].neighObj == recvRankObj &&
periodicBoundary.boundary[rankIt->first][k].rankObj == recvNeighObj)
break;
// The element must always be found, because the list is just in
// another order.