From 7f81c57043323c1efef4a244b5681e8121b7ddd7 Mon Sep 17 00:00:00 2001
From: Thomas Witkowski <thomas.witkowski@gmx.de>
Date: Thu, 25 Oct 2012 08:39:57 +0000
Subject: [PATCH] Fixed some issues for removing periodic boundary conditions.

---
 AMDiS/src/ProblemStat.cc                      |   2 +
 AMDiS/src/io/MacroReader.cc                   |   4 +-
 AMDiS/src/parallel/ElementObjectDatabase.cc   |  33 +--
 AMDiS/src/parallel/ElementObjectDatabase.h    |  24 +-
 AMDiS/src/parallel/InteriorBoundary.cc        | 249 +++++++++++++-----
 AMDiS/src/parallel/InteriorBoundary.h         |  20 ++
 AMDiS/src/parallel/MeshDistributor.cc         |   4 +-
 AMDiS/src/parallel/MeshDistributor.h          |   4 +-
 .../src/parallel/ParallelCoarseSpaceMatVec.h  |   7 +
 AMDiS/src/parallel/ParallelProblemStatBase.h  |   4 +-
 AMDiS/src/parallel/PetscProblemStat.cc        |   9 +-
 AMDiS/src/parallel/PetscSolverFeti.cc         | 180 +++++--------
 AMDiS/src/parallel/PetscSolverFeti.h          |  10 +-
 AMDiS/src/parallel/PetscSolverFetiMonitor.cc  |   2 +-
 .../src/parallel/PetscSolverFetiOperators.cc  |  16 +-
 AMDiS/src/parallel/PetscSolverFetiStructs.h   |   2 -
 AMDiS/src/parallel/PetscSolverGlobalMatrix.cc |   2 +-
 17 files changed, 323 insertions(+), 249 deletions(-)

diff --git a/AMDiS/src/ProblemStat.cc b/AMDiS/src/ProblemStat.cc
index 4c6d4471..e37ed74d 100644
--- a/AMDiS/src/ProblemStat.cc
+++ b/AMDiS/src/ProblemStat.cc
@@ -505,6 +505,7 @@ namespace AMDiS {
   {
     FUNCNAME("ProblemStat::createSolver()");
 
+#ifndef HAVE_PARALLEL_DOMAIN_AMDIS
     // === create solver ===
     string solverType("0");
     string initFileStr = name + "->solver";
@@ -515,6 +516,7 @@ namespace AMDiS {
     solverCreator->setName(initFileStr);
     solver = solverCreator->create();
     solver->initParameters();
+#endif
   }
 
 
diff --git a/AMDiS/src/io/MacroReader.cc b/AMDiS/src/io/MacroReader.cc
index 6e6e4b7a..0f079bf2 100644
--- a/AMDiS/src/io/MacroReader.cc
+++ b/AMDiS/src/io/MacroReader.cc
@@ -48,9 +48,7 @@ namespace AMDiS {
     DegreeOfFreedom **dof = macroInfo->dof;
 
     // === read periodic data =================================
-    if (periodicFile != "") {
-      WARNING("Periodic boundaries may lead to errors in small meshes if element neighbours are not set!\n");
-    
+    if (periodicFile != "") {   
       FILE *file = fopen(periodicFile.c_str(), "r");
       TEST_EXIT(file)("can't open file %s\n", periodicFile.c_str());
 
diff --git a/AMDiS/src/parallel/ElementObjectDatabase.cc b/AMDiS/src/parallel/ElementObjectDatabase.cc
index 9ec7f81f..38b147d2 100644
--- a/AMDiS/src/parallel/ElementObjectDatabase.cc
+++ b/AMDiS/src/parallel/ElementObjectDatabase.cc
@@ -105,16 +105,15 @@ namespace AMDiS {
 	  periodicEdgeAssoc[edge0].insert(edge1);
 	  
 	  // Add both vertices of the edge to be periodic.
-	  periodicVertices[make_pair(edge0.first, edge1.first)] = boundaryType;
-	  periodicVertices[make_pair(edge0.second, edge1.second)] = boundaryType;
+	  DegreeOfFreedom mappedDof0 = 
+	    mesh->getPeriodicAssociations(boundaryType)[edge0.first];
+	  DegreeOfFreedom mappedDof1 = 
+	    mesh->getPeriodicAssociations(boundaryType)[edge0.second];
+	  periodicVertices[make_pair(edge0.first, mappedDof0)] = boundaryType;
+	  periodicVertices[make_pair(edge0.second, mappedDof1)] = boundaryType;
+
 	  periodicDofAssoc[edge0.first].insert(boundaryType);
-	  periodicDofAssoc[edge0.second].insert(boundaryType);
-	  
-	  TEST_EXIT_DBG(edge0.first == 
-			mesh->getPeriodicAssociations(boundaryType)[edge1.first] &&
-			edge0.second == 
-			mesh->getPeriodicAssociations(boundaryType)[edge1.second])
-	    ("Should not happen!\n");
+	  periodicDofAssoc[edge0.second].insert(boundaryType); 
 	}
       }
       break;
@@ -134,12 +133,16 @@ namespace AMDiS {
 	  periodicFaces[make_pair(face0, face1)] = elInfo->getBoundary(i);
 	  
 	  /// Add all three vertices of the face to be periodic.
-	  periodicVertices[make_pair(face0.get<0>(), face1.get<0>())] = 
-	    boundaryType;
-	  periodicVertices[make_pair(face0.get<1>(), face1.get<1>())] = 
-	    boundaryType;
-	  periodicVertices[make_pair(face0.get<2>(), face1.get<2>())] = 
-	    boundaryType;
+	  DegreeOfFreedom mappedDof0 = 
+	    mesh->getPeriodicAssociations(boundaryType)[face0.get<0>()];
+	  DegreeOfFreedom mappedDof1 = 
+	    mesh->getPeriodicAssociations(boundaryType)[face0.get<1>()];
+	  DegreeOfFreedom mappedDof2 = 
+	    mesh->getPeriodicAssociations(boundaryType)[face0.get<2>()];
+
+	  periodicVertices[make_pair(face0.get<0>(), mappedDof0)] = boundaryType;
+	  periodicVertices[make_pair(face0.get<1>(), mappedDof1)] = boundaryType;
+	  periodicVertices[make_pair(face0.get<2>(), mappedDof2)] = boundaryType;
 	  
 	  periodicDofAssoc[face0.get<0>()].insert(boundaryType);
 	  periodicDofAssoc[face0.get<1>()].insert(boundaryType);
diff --git a/AMDiS/src/parallel/ElementObjectDatabase.h b/AMDiS/src/parallel/ElementObjectDatabase.h
index 69fb5224..f781c429 100644
--- a/AMDiS/src/parallel/ElementObjectDatabase.h
+++ b/AMDiS/src/parallel/ElementObjectDatabase.h
@@ -309,24 +309,32 @@ namespace AMDiS {
       return faceElements[face];
     }
 
-
-    
-    /// Returns a map that maps to each rank all macro elements in this rank that
-    /// have a given vertex DOF in common.
+    /// Returns, for a given vertex, a map that maps from rank numbers to 
+    /// element data objects, which identify on the rank the element which 
+    /// contains this vertex. If more than one element in one subdomain contains
+    /// the vertex, the element with the highest element index is given. If the
+    /// vertex is not contained in a rank's subdomain, it will not be considered
+    /// in this mapping.
     map<int, ElementObjectData>& getElementsInRank(DegreeOfFreedom vertex)
     {
       return vertexInRank[vertex];
     }
 
-    /// Returns a map that maps to each rank all macro elements in this rank that
-    /// have a given edge in common.
+    /// Returns, for a given edge, a map that maps from rank numbers to 
+    /// element data objects, which identify on the rank the element which 
+    /// contains this edge. If more than one element in one subdomain contains
+    /// the edge, the element with the highest element index is given. If the
+    /// edge is not contained in a rank's subdomain, it will not be considered
+    /// in this mapping.
     map<int, ElementObjectData>& getElementsInRank(DofEdge edge)
     {
       return edgeInRank[edge];
     }
 
-    /// Returns a map that maps to each rank all macro elements in this rank that
-    /// have a given face in common.
+    /// Returns, for a given face, a map that maps from rank numbers to 
+    /// element data objects, which identify on the rank the element which 
+    /// contains this face. If the face is not contained in a rank's subdomain, 
+    /// it will not be considered in this mapping.
     map<int, ElementObjectData>& getElementsInRank(DofFace face)
     {
       return faceInRank[face];
diff --git a/AMDiS/src/parallel/InteriorBoundary.cc b/AMDiS/src/parallel/InteriorBoundary.cc
index feb0f5cd..24243fb0 100644
--- a/AMDiS/src/parallel/InteriorBoundary.cc
+++ b/AMDiS/src/parallel/InteriorBoundary.cc
@@ -110,7 +110,7 @@ namespace AMDiS {
 	    bound.neighObj.ithObj = it2->second.ithObject;
 	    
 	    bound.type = INTERIOR;
-	    
+
 	    AtomicBoundary& b = getNewOwn(it2->first);
 	    b = bound;
 	    if (geoIndex == EDGE)
@@ -181,6 +181,7 @@ namespace AMDiS {
 	bound.neighObj.subObj = VERTEX;
 	bound.neighObj.ithObj = perDofEl1.ithObject;
 
+
 	if (removePeriodicBoundary) {
 	  bound.type = INTERIOR;
 	  
@@ -191,47 +192,56 @@ namespace AMDiS {
 	  
 	  int owner = std::max(elObjDb.getOwner(it->first.first, level),
 			       elObjDb.getOwner(it->first.second, level));
+
+	  // Consider the following configuration of four elements partitioned
+	  // to four ranks:
+	  //
+	  //  |--------|--------|(*)
+	  //  |       /|       /|
+	  //  |  3   / |  0   / |
+	  //  |     /  |     /  |
+	  //  |    /   |    /   |
+	  //  |   /    |   /    |
+	  //  |  /  2  |  /  1  |
+	  //  | /      | /      |
+	  //  |/-------|/-------|
+	  //
+	  // We are in now interested in vertex (*). For the first, rank 1 owns
+	  // the interior boundary with rank 0 on this vertex. When we remove 
+	  // periodic boundaries, which are applied on the left and right outer
+	  // boundary, rank 3 becomes the owner of this vertex. Rank 0 and rank 1
+	  // will have an interior boundary with rank 3 on this vertex, but rank
+	  // 0 and rank 1 have no more interior boundaries on vertex (*). Thus we
+	  // have to search and remove for this scenario.
+	  
+	  if (owner != globalMpiRank) {
+	    removeOwn(bound.rankObj);
+	    removeOther(bound.rankObj);
+	  }
+
+
+	  // And than we can add the boundary to either own or other part of the
+	  // interior database.
+
 	  if (owner == globalMpiRank) {
-	    for (map<int, ElementObjectData>::iterator it2 = objData.begin();
-	     	 it2 != objData.end(); ++it2) {
-	      if (it2->first == globalMpiRank)
-	     	continue;
-	      
-	      if (!allRanks && levelRanks.count(it2->first) == 0)
-	     	continue;
-	      
-	      AtomicBoundary& b = getNewOwn(it2->first);	  
-	      b = bound;	  
-	      b.neighObj.el = elObjDb.getElementPtr(it2->second.elIndex);
-	      b.neighObj.elIndex = it2->second.elIndex;
-	      b.neighObj.elType = elObjDb.getElementType(it2->second.elIndex);
-	      b.neighObj.ithObj = it2->second.ithObject;
-	    }
+	    AtomicBoundary& b = getNewOwn(otherElementRank);	  
+	    b = bound;	  
 	  } else {
+	    ElementObjectData& ownerBoundEl = objData[owner];    
+	    bound.neighObj.el = elObjDb.getElementPtr(ownerBoundEl.elIndex);
+	    bound.neighObj.elIndex = ownerBoundEl.elIndex;
+	    bound.neighObj.elType = -1;
+	    bound.neighObj.ithObj = ownerBoundEl.ithObject;
+
 	    AtomicBoundary& b = getNewOther(owner);
 	    b = bound;
-	    
-	    ElementObjectData& ownerBoundEl = objData[owner];    
-	    b.neighObj.el = elObjDb.getElementPtr(ownerBoundEl.elIndex);
-	    b.neighObj.elIndex = ownerBoundEl.elIndex;
-	    b.neighObj.elType = -1;
-	    b.neighObj.ithObj = ownerBoundEl.ithObject;
 	  }
+
 	} else {
 	  bound.type = it->second;
 	  
-	  if (MeshDistributor::sebastianMode) {
-	    if (bound.rankObj.elIndex == 3 &&
-		bound.rankObj.ithObj == 1 ||
-		bound.rankObj.elIndex == 78 &&
-		bound.rankObj.ithObj == 2) {
-	      AtomicBoundary& b = getNewPeriodic(otherElementRank);
-	      b = bound;	    	    
-	    }
-	  } else {
-	    AtomicBoundary& b = getNewPeriodic(otherElementRank);
-	    b = bound;	    	  
-	  }
+	  AtomicBoundary& b = getNewPeriodic(otherElementRank);
+	  b = bound;	  
 	}
       }
     }
@@ -276,24 +286,15 @@ namespace AMDiS {
 			       elObjDb.getOwner(it->first.second, level));
 	  ElementObjectData& rankBoundEl = objData[globalMpiRank];
 
+	  // See comments in the same part of code for VERTEX
+	  if (owner != globalMpiRank) {
+	    removeOwn(bound.rankObj);
+	    removeOther(bound.rankObj);
+	  }
+
 	  if (owner == globalMpiRank) {
-	    for (map<int, ElementObjectData>::iterator it2 = objData.begin();
-	     	 it2 != objData.end(); ++it2) {
-	      if (it2->first == globalMpiRank)
-	     	continue;
-	      
-	      if (!allRanks && levelRanks.count(it2->first) == 0)
-	     	continue;
-	      
-	      AtomicBoundary& b = getNewOwn(it2->first);	  
-	      b = bound;	  
-	      b.neighObj.el = elObjDb.getElementPtr(it2->second.elIndex);
-	      b.neighObj.elIndex = it2->second.elIndex;
-	      b.neighObj.elType = elObjDb.getElementType(it2->second.elIndex);
-	      b.neighObj.ithObj = it2->second.ithObject;
-	      b.neighObj.reverseMode = 
-		elObjDb.getEdgeReverseMode(rankBoundEl, it2->second);
-	    }
+	    AtomicBoundary& b = getNewOwn(otherElementRank); 
+	    b = bound;	  
 	  } else {
 	    AtomicBoundary& b = getNewOther(owner);
 	    b = bound;
@@ -368,23 +369,8 @@ namespace AMDiS {
 	  ElementObjectData& rankBoundEl = objData[globalMpiRank];
 
 	  if (owner == globalMpiRank) {
-	    for (map<int, ElementObjectData>::iterator it2 = objData.begin();
-	     	 it2 != objData.end(); ++it2) {
-	      if (it2->first == globalMpiRank)
-	     	continue;
-	      
-	      if (!allRanks && levelRanks.count(it2->first) == 0)
-	     	continue;
-	      
-	      AtomicBoundary& b = getNewOwn(it2->first);	  
-	      b = bound;	  
-	      b.neighObj.el = elObjDb.getElementPtr(it2->second.elIndex);
-	      b.neighObj.elIndex = it2->second.elIndex;
-	      b.neighObj.elType = elObjDb.getElementType(it2->second.elIndex);
-	      b.neighObj.ithObj = it2->second.ithObject;
-	      b.neighObj.reverseMode = 
-		elObjDb.getFaceReverseMode(rankBoundEl, it2->second);
-	    }
+	    AtomicBoundary& b = getNewOwn(otherElementRank);
+	    b = bound;	  
 	  } else {
 	    AtomicBoundary& b = getNewOther(owner);
 	    b = bound;
@@ -413,6 +399,7 @@ namespace AMDiS {
       }
     }
 
+
     // === Once we have this information, we must care about the order of the ===
     // === atomic bounds in the three boundary handling object. Eventually    ===
     // === all the boundaries have to be in the same order on both ranks that ===
@@ -454,19 +441,25 @@ namespace AMDiS {
 
 	// If the expected object is not at place, search for it.
 
-	BoundaryObject &recvedBound = 
+	BoundaryObject &receivedBound = 
 	  stdMpi.getRecvData()[rank][j].rankObj;
 
-	if ((rankIt->second)[j].neighObj != recvedBound) {
+	if ((rankIt->second)[j].neighObj != receivedBound) {
 	  unsigned int k = j + 1;
 
-	  for (; k < rankIt->second.size(); k++)
- 	    if ((rankIt->second)[k].neighObj == recvedBound)
+	  for (; k < rankIt->second.size(); k++) {
+ 	    if ((rankIt->second)[k].neighObj == receivedBound)
 	      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");
+	  TEST_EXIT_DBG(k < rankIt->second.size())
+	    ("Cannot find element %d/%d/%d received from rank %d!\n",
+	     receivedBound.elIndex, 
+	     receivedBound.subObj, 
+	     receivedBound.ithObj,
+	     rank);
 
 	  // Swap the current with the found element.
 	  AtomicBoundary tmpBound = (rankIt->second)[k];
@@ -531,6 +524,11 @@ namespace AMDiS {
 	}
       }     
     } // periodicBoundary.boundary.size() > 0
+
+
+    // === Run verification procedure. ===
+    
+    verifyBoundary();
   }
 
 
@@ -644,8 +642,37 @@ namespace AMDiS {
   }
 
 
+  void InteriorBoundary::verifyBoundary()
+  {
+    FUNCNAME("InteriorBoundary::verifyBoundary()");
+
+    // === Check if no other boundery rank object is also included in own ===
+    // === boundary part, which would make no sence.                      ===
+
+    std::set<BoundaryObject> allOwnBounds;
+    for (map<int, vector<AtomicBoundary> >::iterator it = own.begin(); 
+	 it != own.end(); ++it)
+      for (vector<AtomicBoundary>::iterator bIt = it->second.begin();
+	   bIt != it->second.end(); ++bIt)
+	allOwnBounds.insert(bIt->rankObj);
+
+    for (map<int, vector<AtomicBoundary> >::iterator it = other.begin(); 
+	 it != other.end(); ++it)
+      for (vector<AtomicBoundary>::iterator bIt = it->second.begin();
+	   bIt != it->second.end(); ++bIt)
+	if (allOwnBounds.count(bIt->rankObj)) {
+	  ERROR_EXIT("Boundary %d/%d/%d is included in both, own and other interior boundary part!\n",
+		     bIt->rankObj.elIndex,
+		     bIt->rankObj.subObj,
+		     bIt->rankObj.ithObj);
+	}
+  }
+
+
   AtomicBoundary& InteriorBoundary::getNewOwn(int rank)
   {
+    FUNCNAME("InteriorBoundary::getNewOwn()");
+
     int size = own[rank].size();
     own[rank].resize(size + 1);
     return own[rank][size];
@@ -654,6 +681,8 @@ namespace AMDiS {
 
   AtomicBoundary& InteriorBoundary::getNewOther(int rank)
   {
+    FUNCNAME("InteriorBoundary::getNewOther()");
+
     int size = other[rank].size();
     other[rank].resize(size + 1);
     return other[rank][size];
@@ -662,12 +691,86 @@ namespace AMDiS {
 
   AtomicBoundary& InteriorBoundary::getNewPeriodic(int rank)
   {
+    FUNCNAME("InteriorBoundary::getNewPeriodic()");
+
     int size = periodic[rank].size();
     periodic[rank].resize(size + 1);
     return periodic[rank][size];
   }
 
 
+  bool InteriorBoundary::checkOther(AtomicBoundary& bound, int rank)
+  {
+    FUNCNAME("InteriorBoundary::checkOther()");
+
+    int globalMpiRank = MPI::COMM_WORLD.Get_rank();
+    TEST_EXIT(rank > globalMpiRank)
+      ("Wrong MPI ranks: %d %d\n", rank, globalMpiRank);
+
+    bool found = false;
+
+    if (other.count(rank)) {
+      vector<AtomicBoundary>& otherBounds = other[rank];
+      for (int i = 0; i < static_cast<int>(otherBounds.size()); i++) {
+	if (otherBounds[i].rankObj == bound.rankObj) {
+	  if (otherBounds[i].neighObj != bound.neighObj) {
+	    ERROR_EXIT("If this really can happen, I have to thing about this!\n");
+	  } else {
+	    found = true;
+	    break;
+	  }
+	}
+      }
+    }
+
+    return found;
+  }
+
+
+  bool InteriorBoundary::removeOwn(BoundaryObject& bound)
+  {
+    FUNCNAME("InteriorBoundary::removeOwn()");
+
+    bool removed = false;
+
+    for (map<int, vector<AtomicBoundary> >::iterator it = own.begin();
+	 it != own.end(); ++it) {
+      for (vector<AtomicBoundary>::iterator bIt = it->second.begin();
+	   bIt != it->second.end(); ++bIt) {
+	if (bIt->rankObj == bound) {
+	  it->second.erase(bIt);
+	  removed = true;
+	  break;
+	}
+      }
+    }
+
+    return removed;
+  }
+
+
+  bool InteriorBoundary::removeOther(BoundaryObject& bound)
+  {
+    FUNCNAME("InteriorBoundary::removeOther()");
+
+    bool removed = false;
+
+    for (map<int, vector<AtomicBoundary> >::iterator it = other.begin();
+	 it != other.end(); ++it) {
+      for (vector<AtomicBoundary>::iterator bIt = it->second.begin();
+	   bIt != it->second.end(); ++bIt) {
+	if (bIt->rankObj == bound) {
+	  it->second.erase(bIt);
+	  removed = true;
+	  break;
+	}
+      }
+    }
+
+    return removed;    
+  }
+
+
   void InteriorBoundary::serializeExcludeList(ostream &out, 
 					      ExcludeList &list)
   {
diff --git a/AMDiS/src/parallel/InteriorBoundary.h b/AMDiS/src/parallel/InteriorBoundary.h
index 2660253f..594c295e 100644
--- a/AMDiS/src/parallel/InteriorBoundary.h
+++ b/AMDiS/src/parallel/InteriorBoundary.h
@@ -86,12 +86,32 @@ namespace AMDiS {
     void deserialize(istream &in, Mesh *mesh);
 
   private:
+    /// In this function, we put some verification procedures to check for 
+    /// consistency if the created interior boundary data. This function is
+    /// enabled even for optimized mode to check all possible meshes. Thus,
+    /// everything herein should be fast. If the code is stable, we can think
+    /// to remove this function.
+    void verifyBoundary();
+
     AtomicBoundary& getNewOwn(int rank);
 
     AtomicBoundary& getNewOther(int rank);
 
     AtomicBoundary& getNewPeriodic(int rank);
 
+    /// Checks whether the given boundary is already a other boundary with 
+    /// given rank number. Returns true, if the bound is already in the other
+    /// boundary database.
+    bool checkOther(AtomicBoundary& bound, int rank);
+
+    /// Removes the given boundary object from all owned boundaries. Returns 
+    /// true, if at least one object has been removed, otherwise false.
+    bool removeOwn(BoundaryObject& bound);
+
+    /// Removes the given boundary object from all other boundaries. Returns 
+    /// true, if at least one object has been removed, otherwise false.
+    bool removeOther(BoundaryObject& bound);
+
     void serialize(ostream &out, RankToBoundMap& boundary);
 
     void deserialize(istream &in, 
diff --git a/AMDiS/src/parallel/MeshDistributor.cc b/AMDiS/src/parallel/MeshDistributor.cc
index 444cb894..c84d4e23 100644
--- a/AMDiS/src/parallel/MeshDistributor.cc
+++ b/AMDiS/src/parallel/MeshDistributor.cc
@@ -68,8 +68,6 @@ namespace AMDiS {
     return (*dof1 < *dof2);
   }
 
-  bool MeshDistributor::sebastianMode = false;
-
   MeshDistributor::MeshDistributor()
     : problemStat(0),
       initialized(false),
@@ -1696,7 +1694,7 @@ namespace AMDiS {
 
       dofMaps[i]->update();
 #if (DEBUG != 0)
-      dofMaps[i]->printInfo();
+      //      dofMaps[i]->printInfo();
 #endif
     }
 
diff --git a/AMDiS/src/parallel/MeshDistributor.h b/AMDiS/src/parallel/MeshDistributor.h
index db4b23f5..e8a5a791 100644
--- a/AMDiS/src/parallel/MeshDistributor.h
+++ b/AMDiS/src/parallel/MeshDistributor.h
@@ -290,7 +290,7 @@ namespace AMDiS {
 
     void setBoundaryDofRequirement(Flag flag)
     {
-      createBoundaryDofFlag = flag;
+      createBoundaryDofFlag |= flag;
     }
 
     BoundaryDofInfo& getBoundaryDofInfo(const FiniteElemSpace *feSpace,
@@ -584,8 +584,6 @@ namespace AMDiS {
     vector<ParallelDofMapping*> dofMaps;
 
   public:
-    static bool sebastianMode;
-
     /// The boundary DOFs are sorted by subobject entities, i.e., first all
     /// face DOFs, edge DOFs and to the last vertex DOFs will be set to
     /// communication structure vectors, \ref sendDofs and \ref recvDofs.
diff --git a/AMDiS/src/parallel/ParallelCoarseSpaceMatVec.h b/AMDiS/src/parallel/ParallelCoarseSpaceMatVec.h
index 3ceb8e73..b4911552 100644
--- a/AMDiS/src/parallel/ParallelCoarseSpaceMatVec.h
+++ b/AMDiS/src/parallel/ParallelCoarseSpaceMatVec.h
@@ -47,6 +47,7 @@ namespace AMDiS {
    */
   class ParallelCoarseSpaceMatVec {
   public:
+    /// Constructor
     ParallelCoarseSpaceMatVec();
 
     /// Set parallel DOF mapping for the interior DOFs.
@@ -54,6 +55,12 @@ namespace AMDiS {
     {
       interiorMap = interiorDofs;
     }
+
+    /// Returns the parallel DOF mapping for the interior DOFs.
+    ParallelDofMapping* getDofMapping()
+    {
+      return interiorMap;
+    }
     
     /** \brief
      * Sets the coarse space for all or a specific component.
diff --git a/AMDiS/src/parallel/ParallelProblemStatBase.h b/AMDiS/src/parallel/ParallelProblemStatBase.h
index 7320196a..6eeb5c67 100644
--- a/AMDiS/src/parallel/ParallelProblemStatBase.h
+++ b/AMDiS/src/parallel/ParallelProblemStatBase.h
@@ -40,8 +40,8 @@ namespace AMDiS {
     virtual ~ParallelProblemStatBase() {}
 
     void buildAfterCoarsen(AdaptInfo *adaptInfo, Flag flag,
-			   bool assembleMatrix,
-			   bool assembleVector);
+			   bool assembleMatrix = true,
+			   bool assembleVector = true);
 
     void initialize(Flag initFlag,
 		    ProblemStatSeq *adoptProblem = NULL,
diff --git a/AMDiS/src/parallel/PetscProblemStat.cc b/AMDiS/src/parallel/PetscProblemStat.cc
index b9c57b2e..4aa37d37 100644
--- a/AMDiS/src/parallel/PetscProblemStat.cc
+++ b/AMDiS/src/parallel/PetscProblemStat.cc
@@ -33,15 +33,16 @@ namespace AMDiS {
     FUNCNAME("PetscProblemStat::PetscProblemStat()");
 
     string tmp("");
-    Parameters::get("parallel->solver", tmp);
-    
+    string initFileStr = nameStr + "->solver";
+    Parameters::get(initFileStr, tmp);
+   
     if (tmp == "petsc-schur") {
       petscSolver = new PetscSolverSchur();
     } else if (tmp == "petsc-feti") {
-      petscSolver = new PetscSolverFeti();
+      petscSolver = new PetscSolverFeti(initFileStr);
     } else if (tmp == "petsc-block") {
       petscSolver = new PetscSolverGlobalBlockMatrix();
-    } else if (tmp == "petsc" || tmp == "") {
+    } else if (tmp == "petsc") {
       petscSolver = new PetscSolverGlobalMatrix();
     } else if (tmp == "bddcml") {
 #ifdef HAVE_BDDC_ML
diff --git a/AMDiS/src/parallel/PetscSolverFeti.cc b/AMDiS/src/parallel/PetscSolverFeti.cc
index 72402ac3..e91404cc 100644
--- a/AMDiS/src/parallel/PetscSolverFeti.cc
+++ b/AMDiS/src/parallel/PetscSolverFeti.cc
@@ -28,8 +28,9 @@ namespace AMDiS {
 
   using namespace std;
 
-  PetscSolverFeti::PetscSolverFeti()
+  PetscSolverFeti::PetscSolverFeti(string name)
     : PetscSolver(),
+      initFileStr(name),
       primalDofMap(COMPONENT_WISE),
       dualDofMap(COMPONENT_WISE),
       interfaceDofMap(COMPONENT_WISE),
@@ -51,8 +52,8 @@ namespace AMDiS {
     FUNCNAME("PetscSolverFeti::PetscSolverFeti()");
 
     string preconditionerName = "";
-    Parameters::get("parallel->solver->precon", preconditionerName);
-    if (preconditionerName == "" || preconditionerName == "none") {
+    Parameters::get(initFileStr + "->left precon", preconditionerName);
+    if (preconditionerName == "" || preconditionerName == "no") {
       MSG("Create FETI-DP solver with no preconditioner!\n");
       fetiPreconditioner = FETI_NONE;
     } else if (preconditionerName == "dirichlet") {
@@ -66,20 +67,34 @@ namespace AMDiS {
 		 preconditionerName.c_str());
     }
 
-    Parameters::get("parallel->feti->schur primal solver", schurPrimalSolver);
+    preconditionerName = "";
+    Parameters::get(initFileStr + "->right precon", preconditionerName);
+    if (preconditionerName != "" && preconditionerName != "no") {
+      ERROR_EXIT("FETI-DP does not support right preconditioning! (parameter \"%s->right precon\" has value \"%s\")\n",
+		 initFileStr.c_str(), preconditionerName.c_str());
+    }
+
+    Parameters::get(initFileStr + "->feti->schur primal solver", schurPrimalSolver);
     TEST_EXIT(schurPrimalSolver == 0 || schurPrimalSolver == 1)
       ("Wrong solver \"%d\"for the Schur primal complement!\n", 
        schurPrimalSolver);
 
+    Parameters::get(initFileStr + "->feti->stokes mode", stokesMode);
+    if (stokesMode) {
+      Parameters::get(initFileStr + "->feti->pressure component", pressureComponent);
+      TEST_EXIT(pressureComponent >= 0)
+	("FETI-DP in Stokes mode, no pressure component defined!\n");
+    }
+			   
+    Parameters::get(initFileStr + "->feti->augmented lagrange", augmentedLagrange);
+
+    Parameters::get(initFileStr + "->feti->symmetric", isSymmetric);
+
     Parameters::get("parallel->multi level test", multiLevelTest);
     if (multiLevelTest)
       meshLevel = 1;
 
     Parameters::get("parallel->print timings", printTimings);
-
-    Parameters::get("parallel->feti->augmented lagrange", augmentedLagrange);
-
-    Parameters::get("parallel->feti->symmetric", isSymmetric);
   }
 
 
@@ -92,14 +107,6 @@ namespace AMDiS {
 
     MeshLevelData& levelData = meshDistributor->getMeshLevelData();
 
-    stokesMode = false;
-    Parameters::get("parallel->feti->stokes mode", stokesMode);
-    if (stokesMode) {
-      Parameters::get("parallel->feti->pressure component", pressureComponent);
-      TEST_EXIT(pressureComponent >= 0)
-	("FETI-DP in Stokes mode, no pressure component defined!\n");
-    }
-			   
     if (subdomain == NULL) {
       subdomain = new PetscSolverGlobalMatrix();
       subdomain->setSymmetric(isSymmetric);
@@ -1149,8 +1156,19 @@ namespace AMDiS {
     KSPSetType(ksp_feti, KSPGMRES);
     KSPSetTolerances(ksp_feti, 0, 1e-8, 1e+3, 1000);
     KSPSetFromOptions(ksp_feti);
-    if (stokesMode)
-      KSPMonitorSet(ksp_feti, KSPMonitorFetiStokes, &fetiKspData, PETSC_NULL);
+
+    
+    // === Set KSP monitor. ===
+
+    bool monitor = false;
+    Parameters::get(initFileStr + "->feti->monitor", monitor);
+    if (monitor) {
+      if (stokesMode)
+	KSPMonitorSet(ksp_feti, KSPMonitorFetiStokes, &fetiKspData, PETSC_NULL);
+      else 
+	KSPMonitorSet(ksp_feti, KSPMonitorTrueResidualNorm, PETSC_NULL, PETSC_NULL);
+    }
+
 
     // === Create null space objects. ===
     
@@ -1257,64 +1275,53 @@ namespace AMDiS {
 	}
 
 	if (stokesMode) {
-	  // === Create H2 vec ===
+	  // === Create mass matrix solver ===
 
 	  const FiniteElemSpace *pressureFeSpace = 
 	    componentSpaces[pressureComponent];
 
-	  DOFVector<double> tmpvec(pressureFeSpace, "tmpvec");
-	  createH2vec(tmpvec);
-	  interfaceDofMap.createVec(fetiInterfaceLumpedPreconData.h2vec);
-
-	  DofMap& m = interfaceDofMap[pressureComponent].getMap();
-	  for (DofMap::iterator it = m.begin(); it != m.end(); ++it) {
-	    if (dofMap[pressureFeSpace].isRankDof(it->first)) {
-	      int index = interfaceDofMap.getMatIndex(pressureComponent, it->first);
-	      VecSetValue(fetiInterfaceLumpedPreconData.h2vec, 
-			  index, tmpvec[it->first], INSERT_VALUES);
-	    }
-	  }  
-
-	  VecAssemblyBegin(fetiInterfaceLumpedPreconData.h2vec);
-	  VecAssemblyEnd(fetiInterfaceLumpedPreconData.h2vec);
-
-	  // === Create mass matrix solver ===
-	  
-	  if (!massMatrixSolver) {
-	    ParallelDofMapping *massMapping = new ParallelDofMapping(COMPONENT_WISE);
+	  // Create parallel DOF mapping in pressure space.
+	  ParallelDofMapping *massMapping = NULL;
+	  if (massMatrixSolver) {
+	    massMapping = massMatrixSolver->getDofMapping();
+	  } else {
+	    massMapping = 
+	      new ParallelDofMapping(COMPONENT_WISE);
 	    massMapping->init(meshDistributor->getMeshLevelData(), 
 			      pressureFeSpace, pressureFeSpace);
 	    massMapping->setDofComm(meshDistributor->getDofComm());
 	    massMapping->setMpiComm(meshDistributor->getMeshLevelData().getMpiComm(0), 0);
 	    massMapping->setComputeMatIndex(true);
-	    (*massMapping)[0] = interfaceDofMap[pressureComponent];
-	    massMapping->update();	    
-
-	    DOFMatrix massMatrix(pressureFeSpace, pressureFeSpace);
-	    Operator op(pressureFeSpace, pressureFeSpace);
-	    Simple_ZOT zot;
-	    op.addTerm(&zot);
-	    massMatrix.assembleOperator(op);
+	  }	   
+	  (*massMapping)[0] = interfaceDofMap[pressureComponent];
+	  massMapping->update();
+	  
+	  DOFMatrix massMatrix(pressureFeSpace, pressureFeSpace);
+	  Operator op(pressureFeSpace, pressureFeSpace);
+	  Simple_ZOT zot;
+	  op.addTerm(&zot);
+	  massMatrix.assembleOperator(op);
 
+	  if (!massMatrixSolver) {
 	    massMatrixSolver = new PetscSolverGlobalMatrix;
 	    massMatrixSolver->setKspPrefix("mass_");
 	    massMatrixSolver->setMeshDistributor(meshDistributor,
 						 mpiCommGlobal,
 						 mpiCommLocal);
 	    massMatrixSolver->setDofMapping(massMapping);
-	    massMatrixSolver->fillPetscMatrix(&massMatrix);
-
-	    int r, c;
-	    MatGetSize(massMatrixSolver->getMatInterior(), &r, &c);
-	    MatInfo info;
-	    MatGetInfo(massMatrixSolver->getMatInterior(), MAT_GLOBAL_SUM, &info);
-	    MSG("MASS MAT INFO:  size = %d x %d   nnz = %d\n",
-		r, c,
-		static_cast<int>(info.nz_used));
-
-	    fetiInterfaceLumpedPreconData.ksp_mass = 
-	      massMatrixSolver->getSolver();
 	  }
+	   
+	  massMatrixSolver->fillPetscMatrix(&massMatrix);
+
+	  int r, c;
+	  MatGetSize(massMatrixSolver->getMatInterior(), &r, &c);
+	  MatInfo info;
+	  MatGetInfo(massMatrixSolver->getMatInterior(), MAT_GLOBAL_SUM, &info);
+	  MSG("MASS MAT INFO:  size = %d x %d   nnz = %d\n",
+	      r, c, static_cast<int>(info.nz_used));
+	  
+	  fetiInterfaceLumpedPreconData.ksp_mass = massMatrixSolver->getSolver();
+
 
 	  // === Create tmp vectors ===
  
@@ -2374,59 +2381,4 @@ namespace AMDiS {
     MeshDistributor::globalMeshDistributor->synchVector(vec);
   }
 
-
-  void PetscSolverFeti::createH2vec(DOFVector<double> &vec)
-  {
-    FUNCNAME("PetscSolverFeti::createH2vec()");
-    
-    vec.set(0.0);
-    
-    Mesh *mesh = vec.getFeSpace()->getMesh();    
-    TEST_EXIT(mesh->getDim() == 2)("This works only in 2D!\n");
-    int n0 = vec.getFeSpace()->getAdmin()->getNumberOfPreDofs(VERTEX);
-
-    TraverseStack stack;
-    ElInfo *elInfo = 
-      stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS);
-    while (elInfo) {
-      Element *el = elInfo->getElement();
-      std::vector<double> length(3, 0.0);
-      double sumLength = 0.0;
-
-      for (int i = 0; i < 3; i++) {
-	int idx0 = el->getVertexOfEdge(i, 0);
-	int idx1 = el->getVertexOfEdge(i, 1);
-	DegreeOfFreedom dof0 = el->getDof(idx0, n0);
-	DegreeOfFreedom dof1 = el->getDof(idx1, n0);
-
-	WorldVector<double> c0 = elInfo->getCoord(idx0);
-	WorldVector<double> c1 = elInfo->getCoord(idx1);
-	c0 -= c1;
-	length[i] = norm(c0);
-	sumLength += length[i];
-      }
-
-      sumLength *= 0.5;
-      double area = 
-	sqrt(sumLength * (sumLength - length[0]) * (sumLength - length[1]) * (sumLength - length[2]));
-
-      for (int i = 0; i < 3; i++) {
-	DegreeOfFreedom d = el->getDof(i, n0);
-	vec[d] += area;
-      }
-      
-      elInfo = stack.traverseNext(elInfo);
-    }
-
-    meshDistributor->synchAddVector(vec);
-
-    double scalePower = 2.0;
-    Parameters::get("lp->scale power", scalePower);
-    DOFIterator<double> dofIt(&vec, USED_DOFS);
-    for (dofIt.reset(); !dofIt.end(); ++dofIt) {
-      DegreeOfFreedom d = dofIt.getDOFIndex();
-      vec[d] = 1.0 / pow(vec[d], scalePower);      
-    }
-  }
-
 }
diff --git a/AMDiS/src/parallel/PetscSolverFeti.h b/AMDiS/src/parallel/PetscSolverFeti.h
index e10d725b..e4398497 100644
--- a/AMDiS/src/parallel/PetscSolverFeti.h
+++ b/AMDiS/src/parallel/PetscSolverFeti.h
@@ -41,7 +41,8 @@ namespace AMDiS {
   class PetscSolverFeti : public PetscSolver
   {
   public:
-    PetscSolverFeti();
+    /// Constructor of FETI-DP solver class.
+    PetscSolverFeti(string name);
 
     /// Assemble the sequentially created matrices to the global matrices
     /// required by the FETI-DP method.
@@ -228,11 +229,10 @@ namespace AMDiS {
       return false;
     }
 
-    /// Traverse the mesh and create a DOF vector where each DOF is in the
-    /// order of: 1/h^2
-    void createH2vec(DOFVector<double> &vec);
-
   protected:
+    /// Prefix string for parameters in init file.
+    string initFileStr;
+
     /// Mapping from primal DOF indices to a global index of primals.
     ParallelDofMapping primalDofMap;
 
diff --git a/AMDiS/src/parallel/PetscSolverFetiMonitor.cc b/AMDiS/src/parallel/PetscSolverFetiMonitor.cc
index 866d5efb..07ee4d7f 100644
--- a/AMDiS/src/parallel/PetscSolverFetiMonitor.cc
+++ b/AMDiS/src/parallel/PetscSolverFetiMonitor.cc
@@ -35,7 +35,7 @@ namespace AMDiS {
     VecDestroy(&v);
     VecDestroy(&w);
 
-    PetscPrintf(PETSC_COMM_WORLD, "%3D KSP residual norm %1.12e [%1.12e %1.12e] and preconditioned norm [%1.12e]\n",
+    PetscPrintf(PETSC_COMM_WORLD, "%3D KSP residual norm %1.12e [ %1.12e %1.12e ] and preconditioned norm [%1.12e]\n",
 		n, norm, norm0, norm1, rnorm);
 
     return 0;
diff --git a/AMDiS/src/parallel/PetscSolverFetiOperators.cc b/AMDiS/src/parallel/PetscSolverFetiOperators.cc
index cd9c94c3..2b66bd67 100644
--- a/AMDiS/src/parallel/PetscSolverFetiOperators.cc
+++ b/AMDiS/src/parallel/PetscSolverFetiOperators.cc
@@ -466,21 +466,7 @@ namespace AMDiS {
     VecNestGetSubVec(yvec, 0, &y_interface);
     VecNestGetSubVec(yvec, 1, &y_lagrange);
 
-    bool useMassMatrix = false;
-    Parameters::get("lp->mass matrix", useMassMatrix);
-    if (useMassMatrix) {
-      KSPSolve(data->ksp_mass, x_interface, y_interface);
-    } else {
-      VecCopy(x_interface, y_interface);
-      double scaleFactor = 1.0;
-      Parameters::get("lp->scal", scaleFactor);
-      bool mult = false;
-      Parameters::get("lp->mult", mult);
-      if (mult)
-	VecPointwiseMult(y_interface, x_interface, data->h2vec);
-      if (scaleFactor != 0.0)
-	VecScale(y_interface, scaleFactor);
-    }
+    KSPSolve(data->ksp_mass, x_interface, y_interface);
 
     MatMultTranspose(*(data->mat_lagrange_scaled), x_lagrange, data->tmp_vec_b0);   
 
diff --git a/AMDiS/src/parallel/PetscSolverFetiStructs.h b/AMDiS/src/parallel/PetscSolverFetiStructs.h
index 8fa97340..2ed5cedb 100644
--- a/AMDiS/src/parallel/PetscSolverFetiStructs.h
+++ b/AMDiS/src/parallel/PetscSolverFetiStructs.h
@@ -144,8 +144,6 @@ namespace AMDiS {
 
     PetscSolver* subSolver;
 
-    Vec h2vec;
-
     Vec tmp_primal;
 
     KSP ksp_mass;
diff --git a/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc b/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc
index b3c0208b..a0ebc076 100644
--- a/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc
+++ b/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc
@@ -487,8 +487,8 @@ namespace AMDiS {
 	  if (bIt->second && bIt->second->isDirichlet()) {
 	    dirichletRow = true;
 	    if ((dynamic_cast<DirichletBC*>(bIt->second))->applyBoundaryCondition()) {
-	      TEST_EXIT_DBG(dirichletMainCol == -1)("Should not happen!\n");
 	      dirichletMainCol = j;
+	      break;
 	    } 
 	  }
 	}
-- 
GitLab