From 32b711485251f9b4076aee6dda1f7f836c9879a4 Mon Sep 17 00:00:00 2001
From: Thomas Witkowski <thomas.witkowski@gmx.de>
Date: Wed, 5 Jan 2011 11:13:08 +0000
Subject: [PATCH] Fixed some bugs for periodic BCs in 3D in parrallel
 computing.

---
 AMDiS/src/ElInfo.cc                           |   1 +
 AMDiS/src/parallel/InteriorBoundary.cc        |  32 +-
 AMDiS/src/parallel/InteriorBoundary.h         |   4 +-
 AMDiS/src/parallel/MeshDistributor.cc         | 442 +++++++++++++-----
 AMDiS/src/parallel/MeshDistributor.h          |   4 -
 AMDiS/src/parallel/ParMetisPartitioner.cc     |   2 +
 AMDiS/src/parallel/ParallelDebug.cc           |  13 +-
 AMDiS/src/parallel/ParallelProblemStatBase.cc |  10 +-
 AMDiS/src/parallel/PetscSolver.cc             |   7 +-
 AMDiS/src/parallel/StdMpi.cc                  |  26 +-
 10 files changed, 378 insertions(+), 163 deletions(-)

diff --git a/AMDiS/src/ElInfo.cc b/AMDiS/src/ElInfo.cc
index fb213ef4..439dd568 100644
--- a/AMDiS/src/ElInfo.cc
+++ b/AMDiS/src/ElInfo.cc
@@ -172,6 +172,7 @@ namespace AMDiS {
     }
   }
 
+
   BoundaryType ElInfo::getBoundary(GeoIndex pos, int i)
   {
     static int indexOffset[3][3] = {
diff --git a/AMDiS/src/parallel/InteriorBoundary.cc b/AMDiS/src/parallel/InteriorBoundary.cc
index e483ba7e..612d82d7 100644
--- a/AMDiS/src/parallel/InteriorBoundary.cc
+++ b/AMDiS/src/parallel/InteriorBoundary.cc
@@ -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) {
diff --git a/AMDiS/src/parallel/InteriorBoundary.h b/AMDiS/src/parallel/InteriorBoundary.h
index ea12b82f..81280de0 100644
--- a/AMDiS/src/parallel/InteriorBoundary.h
+++ b/AMDiS/src/parallel/InteriorBoundary.h
@@ -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;
     
diff --git a/AMDiS/src/parallel/MeshDistributor.cc b/AMDiS/src/parallel/MeshDistributor.cc
index 6235c168..a1762416 100644
--- a/AMDiS/src/parallel/MeshDistributor.cc
+++ b/AMDiS/src/parallel/MeshDistributor.cc
@@ -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.
 	    TEST_EXIT_DBG(k < rankIt->second.size())("Should never happen!\n");
-	    
+
 	    // Swap the current with the found element.
 	    AtomicBoundary tmpBound = (rankIt->second)[k];
 	    (rankIt->second)[k] = (rankIt->second)[j];
 	    (rankIt->second)[j] = tmpBound;	
-	  }  	  
+	  } 
 	}
       }     
     } // periodicBoundary.boundary.size() > 0
@@ -1873,29 +2032,56 @@ namespace AMDiS {
 
     for (RankToBoundMap::iterator it = periodicBoundary.boundary.begin();
 	 it != periodicBoundary.boundary.end(); ++it) {
-      TEST_EXIT_DBG(it->first != mpiRank)
-	("Periodic interior boundary within the rank itself is not possible!\n");
 
-      // Create dof indices on the boundary. 
-      DofContainer& dofs = rankPeriodicDofs[it->first];
-      for (std::vector<AtomicBoundary>::iterator boundIt = it->second.begin();
-	   boundIt != it->second.end(); ++boundIt) {
-	int nDofs = dofs.size();
+      if (it->first == mpiRank) {
+	TEST_EXIT_DBG(it->second.size() % 2 == 0)("Should not happen!\n");
 
-	boundIt->rankObj.el->getVertexDofs(feSpace, boundIt->rankObj, dofs);
-	boundIt->rankObj.el->getNonVertexDofs(feSpace, boundIt->rankObj, dofs);
+	for (unsigned int i = 0; i < it->second.size(); i++) {
+	  AtomicBoundary &bound = it->second[i];
+	  DofContainer dofs0, dofs1;
+	  bound.rankObj.el->getVertexDofs(feSpace, bound.rankObj, dofs0);
+	  bound.rankObj.el->getNonVertexDofs(feSpace, bound.rankObj, dofs0); 
+	  bound.neighObj.el->getVertexDofs(feSpace, bound.neighObj, dofs1);
+	  bound.neighObj.el->getNonVertexDofs(feSpace, bound.neighObj, dofs1);
 
-	for (unsigned int i = 0; i < (dofs.size() - nDofs); i++)
-	  rankToDofType[it->first].push_back(boundIt->type);
-      }
+	  TEST_EXIT_DBG(dofs0.size() == dofs1.size())("Should not happen!\n");
 
-      // Send the global indices to the rank on the other side.
-      stdMpi.getSendData(it->first).reserve(dofs.size());
-      for (unsigned int i = 0; i < dofs.size(); i++)
-	stdMpi.getSendData(it->first).push_back(mapLocalGlobalDofs[*(dofs[i])]);      
+	  BoundaryType type = bound.type;
+
+	  for (unsigned int j = 0; j < dofs0.size(); j++) {
+	    DegreeOfFreedom globalDof0 = mapLocalGlobalDofs[*(dofs0[j])];
+	    DegreeOfFreedom globalDof1 = mapLocalGlobalDofs[*(dofs1[j])];
+
+	    if (periodicDofAssociations[globalDof0].count(type) == 0) {
+	      periodicDof[type][globalDof0] = globalDof1;
+	      periodicDofAssociations[globalDof0].insert(type);
+	    }
+	  }
+	}
+
+      } else {
+	// Create DOF indices on the boundary. 
+	DofContainer& dofs = rankPeriodicDofs[it->first];
+	for (std::vector<AtomicBoundary>::iterator boundIt = it->second.begin();
+	     boundIt != it->second.end(); ++boundIt) {
 
-      // Receive from this rank the same number of dofs.
-      stdMpi.recv(it->first, dofs.size());
+	  int nDofs = dofs.size();
+	  
+	  boundIt->rankObj.el->getVertexDofs(feSpace, boundIt->rankObj, dofs);
+	  boundIt->rankObj.el->getNonVertexDofs(feSpace, boundIt->rankObj, dofs);
+
+	  for (unsigned int i = 0; i < (dofs.size() - nDofs); i++)
+	    rankToDofType[it->first].push_back(boundIt->type);
+	}
+	
+	// Send the global indices to the rank on the other side.
+	stdMpi.getSendData(it->first).reserve(dofs.size());
+	for (unsigned int i = 0; i < dofs.size(); i++)
+	  stdMpi.getSendData(it->first).push_back(mapLocalGlobalDofs[*(dofs[i])]);      
+	
+	// Receive from this rank the same number of dofs.
+	stdMpi.recv(it->first, dofs.size());
+      }
     }
 
     stdMpi.updateSendDataSize();
@@ -1908,8 +2094,6 @@ namespace AMDiS {
     // === dofs from the other ranks.                                        ===
 
 
-    std::map<DegreeOfFreedom, std::set<int> > dofFromRank;
-
     for (RankToBoundMap::iterator it = periodicBoundary.boundary.begin();
 	 it != periodicBoundary.boundary.end(); ++it) {
       DofContainer& dofs = rankPeriodicDofs[it->first];
@@ -1928,19 +2112,21 @@ namespace AMDiS {
 	if (periodicDofAssociations[globalDofIndex].count(type) == 0) {
 	  periodicDof[type][globalDofIndex] = mapGlobalDofIndex;
 	  periodicDofAssociations[globalDofIndex].insert(type);
-	  dofFromRank[globalDofIndex].insert(it->first);
 	}
       }
     }
 
 
 #if (DEBUG != 0)
-    for (std::map<int, std::set<BoundaryType> >::iterator it = periodicDofAssociations.begin();
-	 it != periodicDofAssociations.end(); ++it) {
-      int nAssoc = it->second.size();
-      TEST_EXIT_DBG(nAssoc == 1 || nAssoc == 3)
- 	("Should not happen! DOF %d has %d periodic associations!\n", 
- 	 it->first, nAssoc);
+    // In 2D, a periodic DOF can have either 1 or 3 associations. Check this!
+    if (mesh->getDim() == 2) {
+      for (std::map<int, std::set<BoundaryType> >::iterator it = periodicDofAssociations.begin();
+	   it != periodicDofAssociations.end(); ++it) {
+	int nAssoc = it->second.size();      
+	TEST_EXIT_DBG(nAssoc == 1 || nAssoc == 3)
+	  ("Should not happen! DOF %d has %d periodic associations!\n", 
+	   it->first, nAssoc);
+      }
     }
 #endif
   }
diff --git a/AMDiS/src/parallel/MeshDistributor.h b/AMDiS/src/parallel/MeshDistributor.h
index d4597e8c..7ad15f37 100644
--- a/AMDiS/src/parallel/MeshDistributor.h
+++ b/AMDiS/src/parallel/MeshDistributor.h
@@ -483,10 +483,6 @@ namespace AMDiS {
     std::map<std::pair<DofEdge, DofEdge>, BoundaryType> periodicEdges;
     std::map<std::pair<DofFace, DofFace>, BoundaryType> periodicFaces;
 
-    // Stores to each DOF all its periodic associations.
-    std::map<DegreeOfFreedom, std::set<BoundaryType> > periodicDofAssoc;
-
-
     /** \brief 
      * Defines the interior boundaries of the domain that result from partitioning
      * the whole mesh. Contains only the boundaries, which are owned by the rank, i.e.,
diff --git a/AMDiS/src/parallel/ParMetisPartitioner.cc b/AMDiS/src/parallel/ParMetisPartitioner.cc
index b1f88900..78d4d3f5 100644
--- a/AMDiS/src/parallel/ParMetisPartitioner.cc
+++ b/AMDiS/src/parallel/ParMetisPartitioner.cc
@@ -364,6 +364,8 @@ namespace AMDiS {
 
     for (int i = 0; i < nElements; i++) {
       wgts[i] = min(wgts[i], kpartMax);
+      wgts[i] = max(wgts[i], 1);
+
       smin = std::min(smin, wgts[i]);
       smax = std::max(smax, wgts[i]);
       ssum += wgts[i];
diff --git a/AMDiS/src/parallel/ParallelDebug.cc b/AMDiS/src/parallel/ParallelDebug.cc
index f4d65426..8fbf82ab 100644
--- a/AMDiS/src/parallel/ParallelDebug.cc
+++ b/AMDiS/src/parallel/ParallelDebug.cc
@@ -67,8 +67,11 @@ namespace AMDiS {
 
     // === To the last, do the same of periodic boundaries. ===
 
-    for (RankToBoundMap::iterator rankIt = pdb.periodicBoundary.boundary.begin();
+    for (RankToBoundMap::iterator rankIt = pdb.periodicBoundary.boundary.begin();       
 	 rankIt != pdb.periodicBoundary.boundary.end(); ++rankIt) {
+      if (rankIt->first == pdb.mpiRank)
+	continue;
+
       int nValues = rankIt->second.size();
       int* sBuffer = new int[nValues];
       for (int i = 0; i < nValues; i++)
@@ -118,11 +121,17 @@ namespace AMDiS {
 
     for (RankToBoundMap::iterator rankIt = pdb.periodicBoundary.boundary.begin();
 	 rankIt != pdb.periodicBoundary.boundary.end(); ++rankIt) {
+      if (rankIt->first == pdb.mpiRank)
+	continue;
+
       for (unsigned int i = 0; i < rankIt->second.size(); i++) {
 	int elIndex1 = recvBuffers[bufCounter][i];
 	int elIndex2 = pdb.periodicBoundary.boundary[rankIt->first][i].neighObj.elIndex;
 
-	TEST_EXIT(elIndex1 == elIndex2)("Wrong element index at periodic boundary!\n");
+	TEST_EXIT(elIndex1 == elIndex2)
+	  ("Wrong element index at periodic boundary el %d with rank %d: %d %d\n", 
+	   pdb.periodicBoundary.boundary[rankIt->first][i].rankObj.elIndex,
+	   rankIt->first, elIndex1, elIndex2);
       }
 
       delete [] recvBuffers[bufCounter++];
diff --git a/AMDiS/src/parallel/ParallelProblemStatBase.cc b/AMDiS/src/parallel/ParallelProblemStatBase.cc
index 015d1727..d7d95dc2 100644
--- a/AMDiS/src/parallel/ParallelProblemStatBase.cc
+++ b/AMDiS/src/parallel/ParallelProblemStatBase.cc
@@ -26,14 +26,16 @@ namespace AMDiS {
     ProblemVec::buildAfterCoarsen(adaptInfo, flag, assembleMatrix, assembleVector);
 
     double vm, rss;
-    processMemUsage(vm, rss);
+    processMemUsage(vm, rss);   
+    vm /= 1024.0;
+    rss /= 1024.0;
     
-    MSG("My memory usage is VM = %f    RSS = %f\n", vm, rss);
+    MSG("My memory usage is VM = %f MB    RSS = %f MB\n", vm, rss);
     
     mpi::globalAdd(vm);
     mpi::globalAdd(rss);
-    
-    MSG("Overall memory usage is VM = %f    RSS = %f\n", vm, rss);
+
+    MSG("Overall memory usage is VM = %f MB    RSS = %f MB\n", vm, rss);
   }
   
   
diff --git a/AMDiS/src/parallel/PetscSolver.cc b/AMDiS/src/parallel/PetscSolver.cc
index e8e25b1e..202b77aa 100644
--- a/AMDiS/src/parallel/PetscSolver.cc
+++ b/AMDiS/src/parallel/PetscSolver.cc
@@ -128,8 +128,8 @@ namespace AMDiS {
       }
 
 
-      // === Up to now we have assembled on row. Now, the row must be send to the ===
-      // === corresponding rows to the petsc matrix.                              ===
+      // === Up to now we have assembled one row. Now, the row must be send to the ===
+      // === corresponding rows in the petsc matrix.                               ===
      
       if (periodicRow) {
 	// The row dof is periodic, so send dof to all the corresponding rows.
@@ -144,7 +144,8 @@ namespace AMDiS {
 	MatSetValues(petscMatrix, 1, &rowIndex, cols.size(), 
 		     &(cols[0]), &(values[0]), ADD_VALUES);	
  
-	for (std::set<int>::iterator perIt = perAsc.begin(); perIt != perAsc.end(); ++perIt) {
+	for (std::set<int>::iterator perIt = perAsc.begin(); 
+	     perIt != perAsc.end(); ++perIt) {
 	  std::vector<int> perCols;
 	  perCols.reserve(300);
 	  std::vector<double> perValues;
diff --git a/AMDiS/src/parallel/StdMpi.cc b/AMDiS/src/parallel/StdMpi.cc
index a95c2d5c..aab70545 100644
--- a/AMDiS/src/parallel/StdMpi.cc
+++ b/AMDiS/src/parallel/StdMpi.cc
@@ -60,7 +60,7 @@ namespace AMDiS {
 
   int intSizeOf(std::vector<AtomicBoundary> &data)
   {
-    return data.size() * 3;
+    return data.size() * 6;
   }
 
   int intSizeOf(std::vector<BoundaryObject> &data)
@@ -242,9 +242,12 @@ namespace AMDiS {
   void makeBuf(std::vector<AtomicBoundary> &data, int *buf)
   {
     for (unsigned int i = 0; i < data.size(); i++) {
-      buf[i * 3] = data[i].rankObj.elIndex;
-      buf[i * 3 + 1] = data[i].rankObj.subObj;
-      buf[i * 3 + 2] = data[i].rankObj.ithObj;
+      buf[i * 6] = data[i].rankObj.elIndex;
+      buf[i * 6 + 1] = data[i].rankObj.subObj;
+      buf[i * 6 + 2] = data[i].rankObj.ithObj;
+      buf[i * 6 + 3] = data[i].neighObj.elIndex;
+      buf[i * 6 + 4] = data[i].neighObj.subObj;
+      buf[i * 6 + 5] = data[i].neighObj.ithObj;
     }
   }
 
@@ -253,13 +256,16 @@ namespace AMDiS {
     if (bufSize == 0)
       return;
 
-    TEST_EXIT(bufSize % 3 == 0)("This should not happen!\n");    
+    TEST_EXIT(bufSize % 6 == 0)("This should not happen!\n");    
 
-    data.resize(bufSize / 3);
-    for (int i = 0; i < bufSize / 3; i++) {
-      data[i].rankObj.elIndex = buf[i * 3];
-      data[i].rankObj.subObj = static_cast<GeoIndex>(buf[i * 3 + 1]);
-      data[i].rankObj.ithObj = buf[i * 3 + 2];
+    data.resize(bufSize / 6);
+    for (int i = 0; i < bufSize / 6; i++) {
+      data[i].rankObj.elIndex = buf[i * 6];
+      data[i].rankObj.subObj = static_cast<GeoIndex>(buf[i * 6 + 1]);
+      data[i].rankObj.ithObj = buf[i * 6 + 2];
+      data[i].neighObj.elIndex = buf[i * 6 + 3];
+      data[i].neighObj.subObj = static_cast<GeoIndex>(buf[i * 6 + 4]);
+      data[i].neighObj.ithObj = buf[i * 6 + 5];
     }
   }
 
-- 
GitLab