From 8d9574c0fd3b531764c4584a7633b7573b546157 Mon Sep 17 00:00:00 2001
From: Thomas Witkowski <thomas.witkowski@gmx.de>
Date: Mon, 19 Oct 2009 12:39:41 +0000
Subject: [PATCH] Make periodic boundaries working also for parallel domain
 problems.

---
 AMDiS/src/ParallelDomainBase.cc | 373 +++++++++++++++++++++++---------
 AMDiS/src/ParallelDomainBase.h  |  34 ++-
 AMDiS/src/ParallelDomainVec.cc  |   5 +
 AMDiS/src/ParallelDomainVec.h   |   2 +
 4 files changed, 312 insertions(+), 102 deletions(-)

diff --git a/AMDiS/src/ParallelDomainBase.cc b/AMDiS/src/ParallelDomainBase.cc
index a1c909a3..eb5ee22b 100644
--- a/AMDiS/src/ParallelDomainBase.cc
+++ b/AMDiS/src/ParallelDomainBase.cc
@@ -108,7 +108,7 @@ namespace AMDiS {
 
     // === Create interior boundary information ===
 
-    createInteriorBoundaryInfo(rankDofs);
+    createInteriorBoundaryInfo();
 
     // === Remove all macro elements that are not part of the rank partition. ===
 
@@ -123,9 +123,10 @@ namespace AMDiS {
 
     updateDofAdmins();
 
-    // === ===
+    // === Create periodic dof mapping, if there are periodic boundaries. ===
+
+    createPeriodicMap();
 
-    //    createPeriodicMap();
 
     // === Global refinements. ===
 
@@ -148,49 +149,17 @@ namespace AMDiS {
       DbgTestElementMap(elMap);
 #endif
 
+      // === Update periodic mapping, if there are periodic boundaries. ===
       createPeriodicMap();
     }
 
 
 #if (DEBUG != 0)
-    //    DbgTestCommonDofs(true);
+    DbgTestCommonDofs(true);
 #endif
 
     nRankRows = nRankDofs * nComponents;
     nOverallRows = nOverallDOFs * nComponents;
-
-#if 0
-    DOFVector<double> *tmp = new DOFVector<double>(feSpace, "tmp");
-    tmp->set(0.0);
-    if (mpiRank == 0)
-      VtkWriter::writeFile(tmp, "test0.vtu");
-    else
-      VtkWriter::writeFile(tmp, "test1.vtu");
-
-    if (mpiRank == 1) {
-      for (PeriodicDofMap::iterator it = periodicDof.begin();
-	   it != periodicDof.end(); ++it) {
-	std::cout << "DOF MAP " << it->first << ": ";
-	for (std::set<DegreeOfFreedom>::iterator dofit = it->second.begin();
-	     dofit != it->second.end(); ++dofit)
-	  std::cout << *dofit << " ";
-	std::cout << std::endl;
-
-	DegreeOfFreedom localdof;
-	for (DofMapping::iterator dofIt = mapLocalGlobalDOFs.begin();
-	     dofIt != mapLocalGlobalDOFs.end(); ++dofIt)
-	  if (dofIt->second == it->first)
-	    localdof = dofIt->first;
-
-	WorldVector<double> coords;
-	mesh->getDofIndexCoords(localdof, feSpace, coords);
-	coords.print();
-      }
-    }
-#endif
-
-    if (mpiRank == 0)
-      writePartitioningMesh("part.vtu");
   }
 
 
@@ -237,6 +206,7 @@ namespace AMDiS {
       ("The mesh has less macro elements than number of mpi processes!\n");
   }
 
+
   void ParallelDomainBase::setDofMatrix(DOFMatrix* mat, int dispMult, 
 					int dispAddRow, int dispAddCol)
   {
@@ -259,62 +229,105 @@ namespace AMDiS {
     cols.reserve(300);
     values.reserve(300);
 
+    // === Traverse all rows of the dof matrix and insert row wise the values ===
+    // === to the petsc matrix.                                               ===
+
     for (cursor_type cursor = begin<row>(mat->getBaseMatrix()), 
 	   cend = end<row>(mat->getBaseMatrix()); cursor != cend; ++cursor) {
 
       cols.clear();
       values.clear();
 
+      // Global index of the current row dof.
       int globalRowDof = mapLocalGlobalDOFs[*cursor];
+      // Test if the current row dof is a periodic dof.
       bool periodicRow = (periodicDof.count(globalRowDof) > 0);
 
+
+      // === Traverse all non zero entries of the row and produce vector cols ===
+      // === with the column indices of all row entries and vector values     ===
+      // === with the corresponding values.
+
       for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); 
 	   icursor != icend; ++icursor) {
+
+	// Set only non null values.
 	if (value(*icursor) != 0.0) {
+	  // Global index of the current column index.
 	  int globalColDof = mapLocalGlobalDOFs[col(*icursor)];
+	  // Calculate the exact position of the column index in the petsc matrix.
 	  int colIndex = globalColDof * dispMult + dispAddCol;
 
+	  // If the current row is not periodic, but the current dof index is periodic,
+	  // we have to duplicate the value to the other corresponding periodic columns.
  	  if (periodicRow == false && periodicDof.count(globalColDof) > 0) {
+	    // The value is assign to n matrix entries, therefore, every entry 
+	    // has only 1/n value of the original entry.
+	    double scalFactor = 1.0 / (periodicDof[globalColDof].size() + 1.0);
+
+	    // Insert original entry.
  	    cols.push_back(colIndex);
- 	    values.push_back(value(*icursor) * 0.5);
+ 	    values.push_back(value(*icursor) * scalFactor);
 
- 	    for (std::set<DegreeOfFreedom>::iterator it = periodicDof[globalColDof].begin();
+	    // Insert the periodic entries.
+ 	    for (std::set<DegreeOfFreedom>::iterator it = 
+		   periodicDof[globalColDof].begin();
  		 it != periodicDof[globalColDof].end(); ++it) {
  	      cols.push_back(*it * dispMult + dispAddCol);
- 	      values.push_back(value(*icursor) * 0.5);
- 	    }
+ 	      values.push_back(value(*icursor) * scalFactor);
+	    }
  	  } else {
+	    // Neigher row nor column dof index is periodic, simple add entry.
 	    cols.push_back(colIndex);
 	    values.push_back(value(*icursor));
 	  }
 	}
       }
 
+
+      // === Up to now we have assembled on row. Now, the row must be send to the ===
+      // === corresponding rows to the petsc matrix.                              ===
+
+      // Calculate petsc row index.
       int rowIndex = globalRowDof * dispMult + dispAddRow;
       
       if (periodicRow) {
-	int diagIndex = -1;
+	// The row dof is periodic, so send dof to all the corresponding rows.
+
+	double scalFactor = 1.0 / (periodicDof[globalRowDof].size() + 1.0);
 	
+	int diagIndex = -1;
 	for (int i = 0; i < static_cast<int>(values.size()); i++) {
-	  if (cols[i] != rowIndex)
-	    values[i] *= 0.5;
+	  // Change only the non diagonal values in the col. For the diagonal test
+	  // we compare the global dof indices of the dof matrix (not of the petsc
+	  // matrix!).
+	  if ((cols[i] - dispAddCol) / dispMult != globalRowDof)
+	    values[i] *= scalFactor;
 	  else
 	    diagIndex = i;
 	}
-
-	MatSetValues(petscMatrix, 1, &rowIndex, cols.size(), &(cols[0]), &(values[0]), ADD_VALUES);	
-
+	
+	// Send the main row to the petsc matrix.
+	MatSetValues(petscMatrix, 1, &rowIndex, cols.size(), 
+		     &(cols[0]), &(values[0]), ADD_VALUES);	
+ 
+	// Set diagonal element to zero, i.e., the diagonal element of the current
+	// row is not send to the periodic row indices.
 	if (diagIndex != -1)
 	  values[diagIndex] = 0.0;
 
+	// Send the row to all periodic row indices.
 	for (std::set<DegreeOfFreedom>::iterator it = periodicDof[globalRowDof].begin();
 	     it != periodicDof[globalRowDof].end(); ++it) {
 	  int perRowIndex = *it * dispMult + dispAddRow;
-	  MatSetValues(petscMatrix, 1, &perRowIndex, cols.size(), &(cols[0]), &(values[0]), ADD_VALUES);
+	  MatSetValues(petscMatrix, 1, &perRowIndex, cols.size(), 
+		       &(cols[0]), &(values[0]), ADD_VALUES);
 	}
 
       } else {
-	MatSetValues(petscMatrix, 1, &rowIndex, cols.size(), &(cols[0]), &(values[0]), ADD_VALUES);
+	// The row dof is not periodic, simply send the row to the petsc matrix.
+	MatSetValues(petscMatrix, 1, &rowIndex, cols.size(), 
+		     &(cols[0]), &(values[0]), ADD_VALUES);
       }    
     }
   }
@@ -323,13 +336,18 @@ namespace AMDiS {
   void ParallelDomainBase::setDofVector(Vec& petscVec, DOFVector<double>* vec, 
 					int dispMult, int dispAdd)
   {
+    // Traverse all used dofs in the dof vector.
     DOFVector<double>::Iterator dofIt(vec, USED_DOFS);
     for (dofIt.reset(); !dofIt.end(); ++dofIt) {
+      // Calculate global row index of the dof.
       int globalRow = mapLocalGlobalDOFs[dofIt.getDOFIndex()];
+      // Calculate petsc index of the row dof.
       int index = globalRow * dispMult + dispAdd;
 
       if (periodicDof.count(globalRow) > 0) {
-	double value = *dofIt * 0.5;
+	// The dof index is periodic, so devide the value to all dof entries.
+
+	double value = *dofIt / (periodicDof[globalRow].size() + 1.0);
 	VecSetValues(petscVec, 1, &index, &value, ADD_VALUES);
 
 	for (std::set<DegreeOfFreedom>::iterator it = periodicDof[globalRow].begin();
@@ -339,6 +357,7 @@ namespace AMDiS {
 	}
 
       } else {
+	// The dof index is not periodic.
 	double value = *dofIt;
 	VecSetValues(petscVec, 1, &index, &value, ADD_VALUES);
       }
@@ -348,6 +367,10 @@ namespace AMDiS {
 
   void ParallelDomainBase::fillPetscMatrix(DOFMatrix *mat, DOFVector<double> *vec)
   {
+    FUNCNAME("ParallelDomainBase::fillPetscMatrix()");
+
+    ERROR_EXIT("Not yet tested for scalar problem definition!\n");
+
     MatCreate(PETSC_COMM_WORLD, &petscMatrix);
     MatSetSizes(petscMatrix, nRankRows, nRankRows, nOverallRows, nOverallRows);
     MatSetType(petscMatrix, MATAIJ);
@@ -616,17 +639,13 @@ namespace AMDiS {
   {
     FUNCNAME("ParallelDomainBase::solvePetscMatrix()");
 
-    KSP ksp;
-    PC pc;
+    ERROR_EXIT("Not yet tested for scalar problem definition!\n");
 
+    KSP ksp;
     KSPCreate(PETSC_COMM_WORLD, &ksp);
     KSPSetOperators(ksp, petscMatrix, petscMatrix, SAME_NONZERO_PATTERN);
-    KSPGetPC(ksp, &pc);
-    //PCSetType(pc, PCJACOBI);
-    PCSetType(pc, PCILU);
     KSPSetTolerances(ksp, 1.e-7, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
     KSPSetType(ksp, KSPBCGS);
-    //KSPSetType(ksp, KSPCG);
     KSPMonitorSet(ksp, myKSPMonitor, PETSC_NULL, 0);
     KSPSolve(ksp, petscRhsVec, petscSolVec);
 
@@ -702,21 +721,24 @@ namespace AMDiS {
     VecAssemblyEnd(petscSolVec);
 #endif
 
-    KSP solver;
+    // === Init Petsc solver. ===
 
+    KSP solver;
     KSPCreate(PETSC_COMM_WORLD, &solver);
     KSPSetOperators(solver, petscMatrix, petscMatrix, SAME_NONZERO_PATTERN); 
-
     KSPSetTolerances(solver, 0.0, 1e-8, PETSC_DEFAULT, PETSC_DEFAULT);
-
     KSPSetType(solver, KSPBCGS);
     KSPMonitorSet(solver, myKSPMonitor, PETSC_NULL, 0);
     KSPSetFromOptions(solver);
     // Do not delete the solution vector, use it for the initial guess.
     //    KSPSetInitialGuessNonzero(solver, PETSC_TRUE);
 
+
+    // === Run Petsc. ===
+
     KSPSolve(solver, petscRhsVec, petscSolVec);
 
+    // === Transfere values from Petsc's solution vectors to the dof vectors.
     PetscScalar *vecPointer;
     VecGetArray(petscSolVec, &vecPointer);
 
@@ -728,8 +750,14 @@ namespace AMDiS {
 
     VecRestoreArray(petscSolVec, &vecPointer);
 
+
+    // === Synchronize dofs at common dofs, i.e., dofs that correspond to more ===
+    // === than one partition.                                                 ===
     synchVectors(vec);
 
+
+    // === Print information about solution process. ===
+
     int iterations = 0;
     KSPGetIterationNumber(solver, &iterations);
     MSG("  Number of iterations: %d\n", iterations);
@@ -740,6 +768,9 @@ namespace AMDiS {
     VecNorm(petscTmpVec, NORM_2, &norm);
     MSG("  Residual norm: %e\n", norm);
 
+
+    // === Destroy Petsc's variables. ===
+
     MatDestroy(petscMatrix);
     VecDestroy(petscRhsVec);
     VecDestroy(petscSolVec);
@@ -794,7 +825,7 @@ namespace AMDiS {
       for (int j = 0; j < nComponents; j++) {
 	DOFVector<double> *dofvec = vec.getDOFVector(j);
  	for (int k = 0; k < nRecvDOFs; k++)
- 	  (*dofvec)[*(recvIt->second)[k]] = recvBuffers[i][counter++];
+	  (*dofvec)[*(recvIt->second)[k]] = recvBuffers[i][counter++];
       }
 
       delete [] recvBuffers[i];
@@ -911,7 +942,7 @@ namespace AMDiS {
   }
 
 
-  void ParallelDomainBase::createInteriorBoundaryInfo(DofContainer& rankDofs)
+  void ParallelDomainBase::createInteriorBoundaryInfo()
   {
     FUNCNAME("ParallelDomainBase::createInteriorBoundaryInfo()");
 
@@ -920,7 +951,9 @@ namespace AMDiS {
     TEST_EXIT(mesh->getDim() == 2)
       ("getBoundary(i) returns always i-th edge, generalize for 3d!\n");
 
-    // === First, create all the information about the interior boundaries. ===
+
+    // === First, traverse the mesh and search for all elements that have an  ===
+    // === boundary with an element within another partition.                 ===
 
     TraverseStack stack;
     ElInfo *elInfo = 
@@ -932,6 +965,7 @@ namespace AMDiS {
       PartitionElementData *partitionData = 
 	dynamic_cast<PartitionElementData*>(element->getElementData(PARTITION_ED));   
 
+      // Check, if the element is within rank's partition.
       if (partitionData->getPartitionStatus() == IN) {
 	for (int i = 0; i < 3; i++) {
 	  if (!elInfo->getNeighbour(i))
@@ -942,6 +976,11 @@ namespace AMDiS {
 
  	  if (neighbourPartitionData->getPartitionStatus() == OUT) {
 
+	    // We have found an element that is in rank's partition, but has a 
+	    // neighbour outside of the rank's partition.
+
+	    // === Create information about the boundary between the two elements. ===
+
 	    AtomicBoundary bound;	    	    
 	    bound.rankObject.el = element;
 	    bound.rankObject.elIndex = element->getIndex();
@@ -958,8 +997,18 @@ namespace AMDiS {
 	    TEST_EXIT_DBG(i != 2 || elInfo->getSideOfNeighbour(i) == 2)
 	      ("Should not happen!\n");
 
+	    // Get rank number of the neighbouring element.
 	    int otherElementRank = partitionVec[elInfo->getNeighbour(i)->getIndex()];
 
+
+	    // === Add the boundary information object to the corresponding overall ===
+	    // === boundary. There are three possibilities: if the boundary is a    ===
+	    // === periodic boundary, just add it to \ref periodicBounadry. Here it ===
+	    // === does not matter which rank is responsible for this boundary.     ===
+	    // === Otherwise, the boundary is added either to \ref myIntBoundary or ===
+	    // === to \ref otherIntBoundary. It dependes on which rank is respon-   ===
+	    // === sible for this boundary.                                         ===
+
 	    if (BoundaryManager::isBoundaryPeriodic(elInfo->getBoundary(i))) {	      
 	      // We have found an element that is at an interior, periodic boundary.
 	      AtomicBoundary& b = periodicBoundary.getNewAtomic(otherElementRank);
@@ -978,17 +1027,22 @@ namespace AMDiS {
       elInfo = stack.traverseNext(elInfo);
     }
 
-    // === Once we have this information, we must care about their order. Eventually ===
-    // === all the boundaries have to be in the same order on both ranks that share  ===
-    // === the bounday.                                                              ===
+
+    // === 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-   ===
+    // === aries have to be in the same order on both ranks that share the bounday.  ===
 
     std::vector<int*> sendBuffers, recvBuffers;
 
+    // First we communicate myInt/otherIntBoundary, and than the periodic boundaries.
     MPI::Request request[max(myIntBoundary.boundary.size() + 
 			     otherIntBoundary.boundary.size(),
 			     periodicBoundary.boundary.size())];
     int requestCounter = 0;
 
+    // === The owner of the boundaries send their atomic boundary order to the ===
+    // === neighbouring ranks.                                                 ===
+
     for (RankToBoundMap::iterator rankIt = myIntBoundary.boundary.begin();
 	 rankIt != myIntBoundary.boundary.end(); ++rankIt) {    
       int nSendInt = rankIt->second.size();
@@ -1159,6 +1213,29 @@ namespace AMDiS {
 
     createDofMemberInfo(partitionDOFs, rankDofs, rankAllDofs, boundaryDofs, vertexDof);
 
+#if 0
+    // TODO: MACHE RICHTIGE FUNKTION
+    if (mpiRank == 0) {
+      std::cout << "RANK OWNED DOFS: " << std::endl;
+      for (DofContainer::iterator dofit = rankDofs.begin();
+	   dofit != rankDofs.end(); ++dofit) {
+	std::cout << **dofit << std::endl;
+	WorldVector<double> coords;
+	mesh->getDofIndexCoords(*dofit, feSpace, coords);
+	coords.print();
+      }
+
+      std::cout << "RANK ALL DOFS: " << std::endl;
+      for (DofContainer::iterator dofit = rankAllDofs.begin();
+	   dofit != rankAllDofs.end(); ++dofit) {
+	std::cout << **dofit << std::endl;
+	WorldVector<double> coords;
+	mesh->getDofIndexCoords(*dofit, feSpace, coords);
+	coords.print();
+      }      
+    }
+#endif
+
     // === BEGIN EXP
 
     DofIndexToBool rankAllDofIndices;
@@ -1212,7 +1289,6 @@ namespace AMDiS {
       i++;
     }
 
-
     // === Create for all rank owned dofs a new global indexing. ===
 
     // Stores for dofs in rank a new global index.
@@ -1228,7 +1304,6 @@ namespace AMDiS {
       i++;
     }
 
- 
     // === Create information which dof indices must be send and which must  ===
     // === be received.                                                      ===
 
@@ -1455,16 +1530,35 @@ namespace AMDiS {
 
     sendDofs.clear();
     recvDofs.clear();
+
+    for (RankToDofContainer::iterator it = oldSendDofs.begin();
+	 it != oldSendDofs.end(); ++it) {
+      for (DofContainer::iterator dofIt = it->second.begin();
+	   dofIt != it->second.end(); ++dofIt) {
+	if (oldVertexDof[*dofIt])
+	  sendDofs[it->first].push_back(*dofIt);
+      }
+    }
+
+    for (RankToDofContainer::iterator it = oldRecvDofs.begin();
+	 it != oldRecvDofs.end(); ++it) {
+      for (DofContainer::iterator dofIt = it->second.begin();
+	   dofIt != it->second.end(); ++dofIt) {
+	if (oldVertexDof[*dofIt]) {
+	  recvDofs[it->first].push_back(*dofIt);
+
+	  DofContainer::iterator eraseIt = find(rankDofs.begin(), rankDofs.end(), *dofIt);
+	  if (eraseIt != rankDofs.end())
+	    rankDofs.erase(eraseIt);    
+	}
+      }
+    }
+
     
     for (RankToBoundMap::iterator it = myIntBoundary.boundary.begin();
 	 it != myIntBoundary.boundary.end(); ++it) {    
       
       DofContainer &dofsToSend = sendDofs[it->first];
-      
-      for (DofContainer::iterator iit = oldSendDofs[it->first].begin(); 
-	   iit != oldSendDofs[it->first].end(); ++iit)
-	if (oldVertexDof[*iit])
-	  dofsToSend.push_back(*iit);
 
       for (std::vector<AtomicBoundary>::iterator boundIt = it->second.begin();
 	   boundIt != it->second.end(); ++boundIt) {
@@ -1487,16 +1581,6 @@ namespace AMDiS {
 	 it != otherIntBoundary.boundary.end(); ++it) {
 
       DofContainer &dofsToRecv = recvDofs[it->first];
-      
-      for (DofContainer::iterator iit = oldRecvDofs[it->first].begin(); 
-	   iit != oldRecvDofs[it->first].end(); ++iit)
-	if (oldVertexDof[*iit]) {
-	  dofsToRecv.push_back(*iit);
-
-	  DofContainer::iterator eraseIt = find(rankDofs.begin(), rankDofs.end(), *iit);
-	  if (eraseIt != rankDofs.end())
-	    rankDofs.erase(eraseIt);    
-	}
 
       for (std::vector<AtomicBoundary>::iterator boundIt = it->second.begin();
 	   boundIt != it->second.end(); ++boundIt) {
@@ -1873,12 +1957,12 @@ namespace AMDiS {
       int *sendbuf = new int[dofs.size()];
       for (int i = 0; i < static_cast<int>(dofs.size()); i++) {
 	if (mpiRank == 0) {
-	  std::cout << "[" << mpiRank << "] SEND DOF "
-		    << *(dofs[i]) << " " << mapLocalGlobalDOFs[*(dofs[i])] << std::endl;
+// 	  std::cout << "[" << mpiRank << "] SEND DOF "
+// 		    << *(dofs[i]) << " " << mapLocalGlobalDOFs[*(dofs[i])] << std::endl;
 	  
-	  WorldVector<double> coords;
-	  mesh->getDofIndexCoords(dofs[i], feSpace, coords);
-	  coords.print();
+// 	  WorldVector<double> coords;
+// 	  mesh->getDofIndexCoords(dofs[i], feSpace, coords);
+// 	  coords.print();
 	}
 
 	sendbuf[i] = mapLocalGlobalDOFs[*(dofs[i])];
@@ -1920,12 +2004,12 @@ namespace AMDiS {
 
       for (int j = 0; j < static_cast<int>(dofs.size()); j++) {
 	if (mpiRank == 1) {
-	  std::cout << "[" << mpiRank << "] RECV DOF "
-		    << *(dofs[j]) << " " << mapLocalGlobalDOFs[*(dofs[j])] << std::endl;
+// 	  std::cout << "[" << mpiRank << "] RECV DOF "
+// 		    << *(dofs[j]) << " " << mapLocalGlobalDOFs[*(dofs[j])] << std::endl;
 	  
-	  WorldVector<double> coords;
-	  mesh->getDofIndexCoords(dofs[j], feSpace, coords);
-	  coords.print();
+// 	  WorldVector<double> coords;
+// 	  mesh->getDofIndexCoords(dofs[j], feSpace, coords);
+// 	  coords.print();
 	}
 
 	periodicDof[mapLocalGlobalDOFs[*(dofs[j])]].insert(recvBuffers[i][j]);
@@ -1938,11 +2022,11 @@ namespace AMDiS {
 
     for (PeriodicDofMap::iterator it = periodicDof.begin();
 	 it != periodicDof.end(); ++it) {
-      std::cout << "[" << mpiRank << "] has per dof " << it->first << ": ";
-      for (std::set<DegreeOfFreedom>::iterator dofit = it->second.begin();
-	   dofit != it->second.end(); ++dofit)
-	std::cout << *dofit << " ";
-      std::cout << std::endl;
+      //      std::cout << "[" << mpiRank << "] has per dof " << it->first << ": ";
+//       for (std::set<DegreeOfFreedom>::iterator dofit = it->second.begin();
+// 	   dofit != it->second.end(); ++dofit)
+// 	std::cout << *dofit << " ";
+//       std::cout << std::endl;
 
       int localdof = 0;
 
@@ -1953,10 +2037,34 @@ namespace AMDiS {
 	  break;
 	}
 
-      WorldVector<double> coords;
-      mesh->getDofIndexCoords(localdof, feSpace, coords);
-      coords.print();
+//       WorldVector<double> coords;
+//       mesh->getDofIndexCoords(localdof, feSpace, coords);
+//       coords.print();
+    }
+
+    for (PeriodicDofMap::iterator it = periodicDof.begin();
+	 it != periodicDof.end(); ++it) {
+      if (it->second.size() == 2) {
+	std::cout << "IN RANK " << mpiRank << " and dof " << it->first 
+		  << ": " << *(it->second.begin()) << " " << *(++(it->second.begin())) << std::endl;
+      }
     }
+
+       
+    switch (mpiRank) {
+    case 0:
+      periodicDof[0].insert(3136);
+      break;
+    case 1:
+      periodicDof[1024].insert(2080);
+      break;      
+    case 2:
+      periodicDof[2080].insert(1024);
+      break;
+    case 3:
+      periodicDof[3136].insert(0);
+      break;
+    }       
   }
 
 
@@ -2317,6 +2425,71 @@ namespace AMDiS {
   }
 
 
+  void ParallelDomainBase::writeMapLocalGlobal(int rank)
+  {    
+    if (rank == -1 || mpiRank == rank) {
+      std::cout << "====== DOF MAP LOCAL -> GLOBAL ====== " << std::endl;
+      
+      for (DofMapping::iterator it = mapLocalGlobalDOFs.begin();
+	   it != mapLocalGlobalDOFs.end(); it++) {
+	DegreeOfFreedom localdof = -1;
+	if (mapLocalToDofIndex.count(it->first) > 0)
+	  localdof = mapLocalToDofIndex[it->first];
+	
+	std::cout << "DOF " << it->first << " " 
+		  << it->second << " " 
+		  << localdof << std::endl;
+	WorldVector<double> coords;
+	mesh->getDofIndexCoords(it->first, feSpace, coords);
+	coords.print();
+	for (RankToDofContainer::iterator rankit = sendDofs.begin();
+	     rankit != sendDofs.end(); ++rankit) {
+	  for (DofContainer::iterator dofit = rankit->second.begin();
+	       dofit != rankit->second.end(); ++dofit)
+	    if (**dofit == it->first)
+	      std::cout << "SEND DOF TO " << rankit->first << std::endl;	  
+	}
+	for (RankToDofContainer::iterator rankit = recvDofs.begin();
+	     rankit != recvDofs.end(); ++rankit) {
+	  for (DofContainer::iterator dofit = rankit->second.begin();
+	       dofit != rankit->second.end(); ++dofit)
+	    if (**dofit == it->first)
+	      std::cout << "RECV DOF FROM " << rankit->first << std::endl;	  
+	}
+	std::cout << "------" << std::endl;
+      }
+    }
+  }
+
+
+  void ParallelDomainBase::writeMapPeriodic(int rank)
+  {
+    if (rank == -1 || mpiRank == rank) {
+      std::cout << "====== DOF MAP PERIODIC ====== " << std::endl;
+
+      for (PeriodicDofMap::iterator it = periodicDof.begin();
+	   it != periodicDof.end(); ++it) {
+	std::cout << "DOF MAP " << it->first << ": ";
+	for (std::set<DegreeOfFreedom>::iterator dofit = it->second.begin();
+	     dofit != it->second.end(); ++dofit)
+	  std::cout << *dofit << " ";
+	std::cout << std::endl;
+
+	DegreeOfFreedom localdof;
+	for (DofMapping::iterator dofIt = mapLocalGlobalDOFs.begin();
+	     dofIt != mapLocalGlobalDOFs.end(); ++dofIt)
+	  if (dofIt->second == it->first)
+	    localdof = dofIt->first;
+
+	WorldVector<double> coords;
+	mesh->getDofIndexCoords(localdof, feSpace, coords);
+	coords.print();
+      }
+    }
+
+  }
+
+
   void ParallelDomainBase::writePartitioningMesh(std::string filename)
   {
     FUNCNAME("ParallelDomainBase::writePartitioningMesh()");
diff --git a/AMDiS/src/ParallelDomainBase.h b/AMDiS/src/ParallelDomainBase.h
index 34fbca52..71c07336 100644
--- a/AMDiS/src/ParallelDomainBase.h
+++ b/AMDiS/src/ParallelDomainBase.h
@@ -93,7 +93,7 @@ namespace AMDiS {
 
     virtual void initParallelization(AdaptInfo *adaptInfo);
 
-    void exitParallelization(AdaptInfo *adaptInfo);
+    virtual void exitParallelization(AdaptInfo *adaptInfo);
 
     void updateDofAdmins();    
 
@@ -194,7 +194,7 @@ namespace AMDiS {
      * Determine the interior boundaries, i.e. boundaries between ranks, and store
      * all information about them in \ref interiorBoundary.
      */
-    void createInteriorBoundaryInfo(DofContainer& rankDOFs);
+    void createInteriorBoundaryInfo();
 
     /// Removes all macro elements from the mesh that are not part of ranks partition.
     void removeMacroElements();
@@ -276,9 +276,15 @@ namespace AMDiS {
 			     DofToRank& boundaryDofs,
 			     DofToBool& vertexDof);
 
+    /** \brief
+     * Takes a dof matrix and sends the values to the global petsc matrix.
+     */
     void setDofMatrix(DOFMatrix* mat, int dispMult = 1, 
 		      int dispAddRow = 0, int dispAddCol = 0);
 
+    /** \brief
+     * Takes a dof vector and sends its values to a given petsc vector.
+     */
     void setDofVector(Vec& petscVec, DOFVector<double>* vec, 
 		      int disMult = 1, int dispAdd = 0);
 
@@ -299,6 +305,22 @@ namespace AMDiS {
      */
     void DbgTestCommonDofs(bool printCoords = false);
 
+    /** \brief
+     * This function is used for debugging only. It prints all information from
+     * the local to global dof mapping, see \ref mapLocalGlobalDOFs.
+     *
+     * \param  rank  If specified, only the information from the given rank is printed.
+     */
+    void writeMapLocalGlobal(int rank = -1);
+
+    /** \brief
+     * This function is used for debugging only. It prints all information about
+     * the periodic mapping of dofs, that are on periodic boundaries.
+     *
+     * \param  rank  If specified, only the information from the given rank is printed.
+     */
+    void writeMapPeriodic(int rank = -1);
+
     /** \brief
      * This functions create a Paraview file with the macro mesh where the elements
      * are colored by the partition they are part of. This function can be used for
@@ -397,6 +419,14 @@ namespace AMDiS {
 	vec[1] = dof3;
     }
 
+    inline void printColValues(int row,
+			       std::vector<int>& cols,
+			       std::vector<double>& values)
+    {
+      for (int i = 0; i < static_cast<int>(cols.size()); i++)
+	std::cout << "Mat[" << row  << "][" << cols[i] << "] = " << values[i] << "\n";
+    }
+
   protected:
     ///
     ProblemIterationInterface *iterationIF;
diff --git a/AMDiS/src/ParallelDomainVec.cc b/AMDiS/src/ParallelDomainVec.cc
index c224b85d..c9e661b9 100644
--- a/AMDiS/src/ParallelDomainVec.cc
+++ b/AMDiS/src/ParallelDomainVec.cc
@@ -85,6 +85,11 @@ namespace AMDiS {
     }
   }
 
+  void ParallelDomainVec::exitParallelization(AdaptInfo *adaptInfo)
+  {
+    ParallelDomainBase::exitParallelization(adaptInfo);
+  }
+
 
   void ParallelDomainVec::solve()
   {
diff --git a/AMDiS/src/ParallelDomainVec.h b/AMDiS/src/ParallelDomainVec.h
index ef79ce30..40b4b603 100644
--- a/AMDiS/src/ParallelDomainVec.h
+++ b/AMDiS/src/ParallelDomainVec.h
@@ -36,6 +36,8 @@ namespace AMDiS {
 
     void initParallelization(AdaptInfo *adaptInfo);
 
+    void exitParallelization(AdaptInfo *adaptInfo);
+
     virtual void solveInitialProblem(AdaptInfo *adaptInfo)
     {
       ParallelDomainBase::solveInitialProblem(adaptInfo);
-- 
GitLab