diff --git a/AMDiS/src/AMDiS_fwd.h b/AMDiS/src/AMDiS_fwd.h
index c642788e9c5a11e8723b9074361783291466096a..994e8ff88dda0ca5ec32dd1d7ace1e2b7f489e3f 100644
--- a/AMDiS/src/AMDiS_fwd.h
+++ b/AMDiS/src/AMDiS_fwd.h
@@ -99,6 +99,7 @@ namespace AMDiS {
 
 #ifdef HAVE_PARALLEL_DOMAIN_AMDIS
   class FeSpaceDofMap;
+  class MeshLevelData;
 #endif
 
   struct BoundaryObject;
diff --git a/AMDiS/src/DOFMatrix.cc b/AMDiS/src/DOFMatrix.cc
index 53a6d21e9be023a4792117870ca3e9bf4d648e01..6b32912b01c5102ae5f362edb1a61365d18856cc 100644
--- a/AMDiS/src/DOFMatrix.cc
+++ b/AMDiS/src/DOFMatrix.cc
@@ -238,7 +238,7 @@ namespace AMDiS {
 	if (condition->applyBoundaryCondition()) {
 
 #ifdef HAVE_PARALLEL_DOMAIN_AMDIS
- 	  if (dofMap->isRankDof(rowIndices[i])) 
+ 	  if (dofMap->isRankDof(rowIndices[i], 0))
  	    applyDBCs.insert(static_cast<int>(row));
 #else
  	  applyDBCs.insert(static_cast<int>(row));
diff --git a/AMDiS/src/DOFVector.h b/AMDiS/src/DOFVector.h
index 94813642e05f4b2000987ac204f8f66795960638..8625f12cdfd6cd08759432e2f71778f4cdb2e474 100644
--- a/AMDiS/src/DOFVector.h
+++ b/AMDiS/src/DOFVector.h
@@ -248,7 +248,7 @@ namespace AMDiS {
     {
       TEST_EXIT_DBG(dofMap)("No rank dofs set!\n");
 
-      return dofMap->isRankDof(dof);
+      return dofMap->isRankDof(dof, 0);
     }
 #endif
 
diff --git a/AMDiS/src/io/Spreadsheet.cc b/AMDiS/src/io/Spreadsheet.cc
index 5cb39df11ceebf3a60061c0b99107a179b80c1f7..96ef2bb3028d052623ce361619c21eb918b65282 100644
--- a/AMDiS/src/io/Spreadsheet.cc
+++ b/AMDiS/src/io/Spreadsheet.cc
@@ -54,6 +54,8 @@ namespace AMDiS {
 
   void Spreadsheet::read(string filename)
   {
+    FUNCNAME("Spreadsheet::read()");
+
     data.clear();
 
     string line;
diff --git a/AMDiS/src/parallel/DofComm.cc b/AMDiS/src/parallel/DofComm.cc
index aa973a91a4f6d94e35a8ee16e9f4063930a2d99d..28fa6378293f93eec4a0e53385afdaebd5b40713 100644
--- a/AMDiS/src/parallel/DofComm.cc
+++ b/AMDiS/src/parallel/DofComm.cc
@@ -41,7 +41,26 @@ namespace AMDiS {
     }
   }
 
-  
+
+  int DofComm::getNumberDofs(int level, const FiniteElemSpace *feSpace)
+  {
+    FUNCNAME("DofComm::getNumberDofs()");
+
+    TEST_EXIT_DBG(level < data.size())("Should not happen!\n");
+
+    DofContainerSet dofs;
+
+    for (DataIter rankIt = data[level].begin(); 
+	 rankIt != data[level].end(); ++rankIt)
+      for (FeMapIter feIt = rankIt->second.begin();
+	   feIt != rankIt->second.end(); ++feIt)
+	if (feIt->first == feSpace)
+	  dofs.insert(feIt->second.begin(), feIt->second.end());
+
+    return static_cast<int>(dofs.size());
+  }
+
+
   bool DofComm::Iterator::setNextFeMap()
   {
     FUNCNAME("DofComm::Iterator::setNextFeMap()");
diff --git a/AMDiS/src/parallel/DofComm.h b/AMDiS/src/parallel/DofComm.h
index dd33200176e5a1df2d81ffe0232eb6e2e82958c3..6e5467a12434fb778f0dc32ed1bec3d0ccde6b39 100644
--- a/AMDiS/src/parallel/DofComm.h
+++ b/AMDiS/src/parallel/DofComm.h
@@ -65,6 +65,8 @@ namespace AMDiS {
       return data[level];
     }
 
+    int getNumberDofs(int level, const FiniteElemSpace *feSpace);
+
   protected:
     LevelDataType data;
 
diff --git a/AMDiS/src/parallel/ElementObjectDatabase.cc b/AMDiS/src/parallel/ElementObjectDatabase.cc
index 93308fb6937cc6621173c1f5f5507418076748d4..f169e8fe7a7ad7f95c434af5375c1968ae47fe00 100644
--- a/AMDiS/src/parallel/ElementObjectDatabase.cc
+++ b/AMDiS/src/parallel/ElementObjectDatabase.cc
@@ -376,9 +376,13 @@ namespace AMDiS {
   }
 
 
-  void ElementObjectDatabase::createRankData(map<int, int>& macroElementRankMap) 
+  void ElementObjectDatabase::createRankData(map<int, int>& macroElementRankMap,
+					     MeshLevelData& levelData)
   {
     FUNCNAME("ElementObjectDatabase::createRankData()");
+    
+    int nLevel = levelData.getLevelNumber();
+    TEST_EXIT_DBG(nLevel > 0)("Should not happen!\n");
 
     vertexOwner.clear();
     vertexInRank.clear();
@@ -391,7 +395,11 @@ namespace AMDiS {
 	if (it2->elIndex > vertexInRank[it->first][elementInRank].elIndex)
 	  vertexInRank[it->first][elementInRank] = *it2;
 
-	vertexOwner[it->first] = std::max(vertexOwner[it->first], elementInRank);
+	for (int level = 0; level < nLevel; level++) {
+	  int levelId = levelData.getLevelId(level, elementInRank);
+	  vertexOwner[it->first][level] = 
+	    std::max(vertexOwner[it->first][level], levelId);
+	}
       }
     }
     
@@ -407,7 +415,11 @@ namespace AMDiS {
 	if (it2->elIndex > edgeInRank[it->first][elementInRank].elIndex)
 	  edgeInRank[it->first][elementInRank] = *it2;
 
-	edgeOwner[it->first] = std::max(edgeOwner[it->first], elementInRank);
+	for (int level = 0; level < nLevel; level++) {
+	  int levelId = levelData.getLevelId(level, elementInRank);
+	  edgeOwner[it->first][level] = 
+	    std::max(edgeOwner[it->first][level], levelId);
+	}
       }
     }
     
@@ -423,7 +435,11 @@ namespace AMDiS {
 	if (it2->elIndex > faceInRank[it->first][elementInRank].elIndex)
 	  faceInRank[it->first][elementInRank] = *it2;
 
-	faceOwner[it->first] = std::max(faceOwner[it->first], elementInRank);
+	for (int level = 0; level < nLevel; level++) {
+	  int levelId = levelData.getLevelId(level, elementInRank);
+	  faceOwner[it->first][level] = 
+	    std::max(faceOwner[it->first][level], levelId);
+	}
       }
     }
   }
@@ -597,11 +613,12 @@ namespace AMDiS {
     }
 
 
-
+    ERROR_EXIT("REWRITE SERIALIZATION!\n");
+    /*
     SerUtil::serialize(out, vertexOwner);
     SerUtil::serialize(out, edgeOwner);
     SerUtil::serialize(out, faceOwner);
-
+    */
 
     nSize = vertexInRank.size();
     SerUtil::serialize(out, nSize);
@@ -737,6 +754,7 @@ namespace AMDiS {
     }
 
 
+    ERROR_EXIT("REWRITE DESERIALIZATION!\n");
     SerUtil::deserialize(in, vertexOwner);
     SerUtil::deserialize(in, edgeOwner);
     SerUtil::deserialize(in, faceOwner);
diff --git a/AMDiS/src/parallel/ElementObjectDatabase.h b/AMDiS/src/parallel/ElementObjectDatabase.h
index b68005ad799eac238b51ac7c7150dd239e7297d1..a7ecb5989c2a9c6d7f39b2955cde10dcd92dace7 100644
--- a/AMDiS/src/parallel/ElementObjectDatabase.h
+++ b/AMDiS/src/parallel/ElementObjectDatabase.h
@@ -28,6 +28,7 @@
 #include <boost/tuple/tuple.hpp>
 #include <boost/tuple/tuple_comparison.hpp>
 
+#include "AMDiS_fwd.h"
 #include "Containers.h"
 #include "Global.h"
 #include "Boundary.h"
@@ -144,7 +145,8 @@ namespace AMDiS {
      * \param[in]  macroElementRankMap   Maps to each macro element of the mesh
      *                                   the rank that owns this macro element.
      */
-    void createRankData(map<int, int>& macroElementRankMap);
+    void createRankData(map<int, int>& macroElementRankMap,
+			MeshLevelData& levelData);
 
 
     /** \brief
@@ -257,17 +259,17 @@ namespace AMDiS {
 
 
     /// Returns the rank owner of the current iterator position.
-    int getIterateOwner()
+    int getIterateOwner(int level)
     {
       switch (iterGeoPos) {
       case VERTEX:
-	return vertexOwner[vertexIter->first];
+	return vertexOwner[vertexIter->first][level];
 	break;
       case EDGE:
-	return edgeOwner[edgeIter->first];
+	return edgeOwner[edgeIter->first][level];
 	break;
       case FACE:
-	return faceOwner[faceIter->first];
+	return faceOwner[faceIter->first][level];
 	break;
       default:
 	ERROR_EXIT("Should not happen!\n");
@@ -279,21 +281,21 @@ namespace AMDiS {
 
 
     /// Returns the rank owner of a vertex DOF.
-    int getOwner(DegreeOfFreedom vertex)
+    int getOwner(DegreeOfFreedom vertex, int level)
     {
-      return vertexOwner[vertex];
+      return vertexOwner[vertex][level];
     }
 
     /// Returns the rank owner of an edge.
-    int getOwner(DofEdge edge)
+    int getOwner(DofEdge edge, int level)
     {
-      return edgeOwner[edge];
+      return edgeOwner[edge][level];
     }
 
     /// Returns the rank owner of an face.
-    int getOwner(DofFace face)
+    int getOwner(DofFace face, int level)
     {
-      return faceOwner[face];
+      return faceOwner[face][level];
     }
 
 
@@ -540,15 +542,17 @@ namespace AMDiS {
     /// Maps to an element object the corresponding face.
     map<ElementObjectData, DofFace> faceLocalMap;
 
+    /// Maps from level to rank number
+    typedef map<int, int> LevelRank;
 
     /// Defines for all vertex DOFs the rank that ownes this vertex DOF.
-    map<DegreeOfFreedom, int> vertexOwner;
+    map<DegreeOfFreedom, LevelRank> vertexOwner;
 
     /// Defines for all edges the rank that ownes this edge.
-    map<DofEdge, int> edgeOwner;
+    map<DofEdge, LevelRank> edgeOwner;
 
     /// Defines for all faces the rank that ownes this face.
-    map<DofFace, int> faceOwner;
+    map<DofFace, LevelRank> faceOwner;
 
 
     /// Defines to each vertex DOF a map that maps to each rank number the element
diff --git a/AMDiS/src/parallel/InteriorBoundary.cc b/AMDiS/src/parallel/InteriorBoundary.cc
index f3e694a4435b195970036e42300b825aed2f506b..62b13aa6faf0ab12a77a0b5d27d7a214cbfda4fa 100644
--- a/AMDiS/src/parallel/InteriorBoundary.cc
+++ b/AMDiS/src/parallel/InteriorBoundary.cc
@@ -18,10 +18,11 @@
 
 namespace AMDiS {
 
-  AtomicBoundary& InteriorBoundary::getNewAtomic(int rank)
+  AtomicBoundary& InteriorBoundary::getNewAtomic(int level, int rank)
   {
-    boundary[rank].resize(boundary[rank].size() + 1);
-    return boundary[rank][boundary[rank].size() - 1];
+    int size = boundary[level][rank].size();
+    boundary[level][rank].resize(size + 1);
+    return boundary[level][rank][size];
   }
 
 
@@ -29,32 +30,51 @@ namespace AMDiS {
   {
     InteriorBoundary& other2 = const_cast<InteriorBoundary&>(other);
 
-    for (RankToBoundMap::const_iterator it = boundary.begin(); 
-	 it != boundary.end(); ++it) {
-      if (other2.boundary.count(it->first) == 0)
-	return false;     
-
-      if (other2.boundary[it->first].size() != it->second.size())
-	return false;
-            
-      for (unsigned int i = 0; i < it->second.size(); i++) {
-	std::vector<AtomicBoundary>::iterator bIt = 
-	  find(other2.boundary[it->first].begin(),
-	       other2.boundary[it->first].end(), it->second[i]);
+    if (boundary.size() != other2.boundary.size())
+      return false;
+
+    for (unsigned int level = 0; level < boundary.size(); level++) {
+      for (RankToBoundMap::const_iterator it = boundary[level].begin(); 
+	   it != boundary[level].end(); ++it) {
+	if (other2.boundary[level].count(it->first) == 0)
+	  return false;     
+	
+	if (other2.boundary[level][it->first].size() != it->second.size())
+	  return false;
 	
-	if (bIt == other2.boundary[it->first].end())
-	  return false;	
-      }      
+	for (unsigned int i = 0; i < it->second.size(); i++) {
+	  std::vector<AtomicBoundary>::iterator bIt = 
+	    find(other2.boundary[level][it->first].begin(),
+		 other2.boundary[level][it->first].end(), it->second[i]);
+	  
+	  if (bIt == other2.boundary[level][it->first].end())
+	    return false;	
+	}      
+      }
     }
 
     return true;
   }
 
 
+  void InteriorBoundary::reset(int level)
+  { 
+    FUNCNAME("InteriorBoundary::reset()");
+
+    nLevel = level;
+
+    boundary.clear();
+    boundary.resize(nLevel);
+  }
+
+
   void InteriorBoundary::serialize(std::ostream &out)
   {
     FUNCNAME("InteriorBoundary::serialize()");
 
+    ERROR_EXIT("REWRITE TO MULTILEVEL STRUCTURE!\n");
+
+#if 0
     int mSize = boundary.size();
     SerUtil::serialize(out, mSize);
     for (RankToBoundMap::iterator it = boundary.begin(); 
@@ -83,6 +103,7 @@ namespace AMDiS {
 	SerUtil::serialize(out, bound.type);
       }
     }
+#endif
   }
 
 
@@ -91,6 +112,9 @@ namespace AMDiS {
   {
     FUNCNAME("InteriorBoundary::deserialize()");
 
+    ERROR_EXIT("REWRITE TO MULTILEVEL STRUCTURE!\n");
+
+#if 0
     int mSize = 0;
     SerUtil::deserialize(in, mSize);
     for (int i = 0; i < mSize; i++) {
@@ -137,6 +161,7 @@ namespace AMDiS {
 	  bound.neighObj.el = NULL;
       }
     }
+#endif
   }
 
 
diff --git a/AMDiS/src/parallel/InteriorBoundary.h b/AMDiS/src/parallel/InteriorBoundary.h
index 3102165e7eb4828ac6d3595b322e8ff73a62b86d..bdc02b773648b55be2e199ff5ac2d5075512752a 100644
--- a/AMDiS/src/parallel/InteriorBoundary.h
+++ b/AMDiS/src/parallel/InteriorBoundary.h
@@ -47,34 +47,35 @@ namespace AMDiS {
     public:
       iterator(InteriorBoundary &b)
 	: bound(b),
-	  levelData(NULL),
 	  level(0)
       {
 	reset();
       }
 
-      iterator(InteriorBoundary &b, MeshLevelData &levelData, int level)
+      iterator(InteriorBoundary &b, int level)
 	: bound(b),
-	  levelData(&levelData),
 	  level(level)
       {
+	TEST_EXIT_DBG(level < bound.boundary.size())
+	  ("Should not happen!\n");
+
 	reset();
       }
 
       /// Set the iterator to the first position.
       void reset()
       {
-	mapIt = bound.boundary.begin();
+	mapIt = bound.boundary[level].begin();
 	nextNonempty();
 
-	if (mapIt != bound.boundary.end())
+	if (mapIt != bound.boundary[level].end())
 	  vecIt = mapIt->second.begin();	
       }
 
       /// Test if iterator is at the final position.
       bool end() const
       {
-	return (mapIt == bound.boundary.end());
+	return (mapIt == bound.boundary[level].end());
       }
 
       /// Move iterator to the next position.
@@ -85,7 +86,7 @@ namespace AMDiS {
 	  ++mapIt;
 	  nextNonempty();
 
-	  if (mapIt != bound.boundary.end())
+	  if (mapIt != bound.boundary[level].end())
 	    vecIt = mapIt->second.begin();	  
 	}	
       }
@@ -105,22 +106,12 @@ namespace AMDiS {
 	++mapIt;
 	nextNonempty();
 
-	if (mapIt != bound.boundary.end())
+	if (mapIt != bound.boundary[level].end())
 	  vecIt = mapIt->second.begin();	
       }
 
       inline int getRank() 
       {
-	if (level > 0) {
-	  int r = levelData->mapRank(mapIt->first, level - 1, level);
-
-	  TEST_EXIT_DBG(r >= 0)
-	    ("Mapping rank %d from level % to level %d does not work!\n",
-	     mapIt->first, level - 1, level);
-
-	  return r;
-	}
-
 	return mapIt->first;
       }
 
@@ -128,25 +119,13 @@ namespace AMDiS {
 
       inline void nextNonempty()
       {
-	if (mapIt == bound.boundary.end())
+	if (mapIt == bound.boundary[level].end())
 	  return;
 
-	if (level > 0) {
-	  TEST_EXIT_DBG(levelData)("No mesh level data object defined!\n");
-	  TEST_EXIT_DBG(level == 1)("Only 2-level method supported!\n");
-
-	  while (!levelData->rankInSubdomain(mapIt->first, level) ||
-		 mapIt->second.size() == 0) {
-	    ++mapIt;
-	    if (mapIt == bound.boundary.end())
-	      return;	  
-	  }
-	} else {
-	  while (mapIt->second.size() == 0) {
-	    ++mapIt;
-	    if (mapIt == bound.boundary.end())
-	      return;
-	  }
+	while (mapIt->second.size() == 0) {
+	  ++mapIt;
+	  if (mapIt == bound.boundary[level].end())
+	    return;	  
 	}
       }
 
@@ -157,20 +136,19 @@ namespace AMDiS {
 
       InteriorBoundary &bound;
 
-      MeshLevelData *levelData;
-
       int level;
     };
 
   public:
-    InteriorBoundary() {}
-
-    void clear()
+    InteriorBoundary(int l = 1) 
+      : nLevel(l)
     {
-      boundary.clear();
+      boundary.resize(nLevel);
     }
 
-    AtomicBoundary& getNewAtomic(int rank);
+    void reset(int nLevel);
+
+    AtomicBoundary& getNewAtomic(int level, int rank);
 
     /// Writes this object to a file.
     void serialize(ostream &out);
@@ -185,10 +163,13 @@ namespace AMDiS {
   protected:
     void serializeExcludeList(ostream &out, ExcludeList &list);
 
-    void deserializeExcludeList(istream &in, ExcludeList &list);
+    void deserializeExcludeList(istream &in, ExcludeList &list);    
 
   public:
-    RankToBoundMap boundary;
+    vector<RankToBoundMap> boundary;    
+
+  protected:
+    int nLevel;
   };
 }
 
diff --git a/AMDiS/src/parallel/MeshDistributor.cc b/AMDiS/src/parallel/MeshDistributor.cc
index 027993db02295f18f69375e420708415f6c6439f..ee86021131c18282f24e499f0bc0f8425b3eae86 100644
--- a/AMDiS/src/parallel/MeshDistributor.cc
+++ b/AMDiS/src/parallel/MeshDistributor.cc
@@ -232,9 +232,10 @@ namespace AMDiS {
       }
     }
 
+    // If required, create hierarchical mesh level structure.
+    createMeshLevelStructure();
 
-    // === Create interior boundary information. ===
-
+    // Create interior boundary information.
     createInteriorBoundaryInfo();
 
 #if (DEBUG != 0)    
@@ -294,11 +295,6 @@ namespace AMDiS {
 	 it != mesh->getPeriodicAssociations().end(); ++it)
       const_cast<DOFAdmin&>(mesh->getDofAdmin(0)).removeDOFContainer(dynamic_cast<DOFContainer*>(it->second));
 
-
-    // If required, create hierarchical mesh level structure.
-    createMeshLevelStructure();
-
-
     updateLocalGlobalNumbering();
 
     // === In 3D we have to make some test, if the resulting mesh is valid.  ===
@@ -784,18 +780,73 @@ namespace AMDiS {
   {
     FUNCNAME("MeshDistributor::createMeshLevelStructure()");
 
+    if (mpiSize != 16)
+      return;
+
     std::set<int> neighbours;
-    for (InteriorBoundary::iterator it(rankIntBoundary); !it.end(); ++it)
-      neighbours.insert(it.getRank());
+    switch (mpiRank) {
+    case 0:
+      neighbours.insert(1); neighbours.insert(4); neighbours.insert(5);
+      break;
+    case 1:
+      neighbours.insert(0); neighbours.insert(2); neighbours.insert(4); neighbours.insert(5); neighbours.insert(6);
+      break;
+    case 2:
+      neighbours.insert(1); neighbours.insert(3); neighbours.insert(5); neighbours.insert(6); neighbours.insert(7);
+      break;
+    case 3:
+      neighbours.insert(2); neighbours.insert(6); neighbours.insert(7);
+      break;
+    case 4:
+      neighbours.insert(0); neighbours.insert(1); neighbours.insert(5); neighbours.insert(8); neighbours.insert(9);
+      break;
+    case 5:
+      neighbours.insert(0); neighbours.insert(1); neighbours.insert(2); 
+      neighbours.insert(4); neighbours.insert(6);
+      neighbours.insert(8); neighbours.insert(9); neighbours.insert(10); 
+      break;
+    case 6:
+      neighbours.insert(1); neighbours.insert(2); neighbours.insert(3); 
+      neighbours.insert(5); neighbours.insert(7);
+      neighbours.insert(9); neighbours.insert(10); neighbours.insert(11); 
+      break;
+    case 7:
+      neighbours.insert(2); neighbours.insert(3); neighbours.insert(6);  neighbours.insert(10); neighbours.insert(11);
+      break;
+    case 8:
+      neighbours.insert(4); neighbours.insert(5); neighbours.insert(9);  neighbours.insert(12); neighbours.insert(13);
+      break;
+    case 9:
+      neighbours.insert(4); neighbours.insert(5); neighbours.insert(6); 
+      neighbours.insert(8); neighbours.insert(10);
+      neighbours.insert(12); neighbours.insert(13); neighbours.insert(14); 
+      break;
+    case 10:
+      neighbours.insert(5); neighbours.insert(6); neighbours.insert(7); 
+      neighbours.insert(9); neighbours.insert(11);
+      neighbours.insert(13); neighbours.insert(14); neighbours.insert(15); 
+      break;
+    case 11:
+      neighbours.insert(6); neighbours.insert(7); neighbours.insert(10);  neighbours.insert(14); neighbours.insert(15);
+      break;
+    case 12:
+      neighbours.insert(8); neighbours.insert(9); neighbours.insert(13);
+      break;
+    case 13:
+      neighbours.insert(8); neighbours.insert(9); neighbours.insert(10);  neighbours.insert(12); neighbours.insert(14);
+      break;
+    case 14:
+      neighbours.insert(9); neighbours.insert(10); neighbours.insert(11);  neighbours.insert(13); neighbours.insert(15);
+      break;
+    case 15:
+      neighbours.insert(10); neighbours.insert(11); neighbours.insert(14);
+      break;
+    }    
 
-    for (InteriorBoundary::iterator it(otherIntBoundary); !it.end(); ++it)
-      neighbours.insert(it.getRank());
+    TEST_EXIT(neighbours.size() > 0)("Should not happen!\n");
 
     levelData.init(neighbours);
 
-    if (mpiSize != 16)
-      return;
-
     bool multiLevelTest = false;
     Parameters::get("parallel->multi level test", multiLevelTest);
     if (multiLevelTest) {
@@ -1472,7 +1523,7 @@ namespace AMDiS {
   {
     FUNCNAME("MeshDistributor::updateInteriorBoundaryInfo()");
 
-    elObjDb.createRankData(partitionMap);
+    elObjDb.createRankData(partitionMap, levelData);
     createBoundaryData();
 
 #if (DEBUG != 0)
@@ -1515,7 +1566,7 @@ namespace AMDiS {
 				  macroElIndexTypeMap);
 
     // Create mesh element data for this rank.
-    elObjDb.createRankData(partitionMap);
+    elObjDb.createRankData(partitionMap, levelData);
   }
 
 
@@ -1525,10 +1576,19 @@ namespace AMDiS {
 
     // === Clear all relevant data structures. ===
 
-    rankIntBoundary.clear();
-    otherIntBoundary.clear();
-    periodicBoundary.clear();
+    int nLevel = levelData.getLevelNumber();
+    rankIntBoundary.reset(nLevel);
+    otherIntBoundary.reset(nLevel);
+    periodicBoundary.reset(nLevel);
 
+    for (int level = 0; level < nLevel; level++)
+      createBoundaryData(level);  
+  }
+
+
+  void MeshDistributor::createBoundaryData(int level)
+  {
+    FUNCNAME("MeshDistributor::createBoundaryData()");
 
     // === Create interior boundary data structure. ===
 
@@ -1540,7 +1600,7 @@ namespace AMDiS {
 	if (!(objData.count(mpiRank) && objData.size() > 1))
 	  continue;
 
-	int owner = elObjDb.getIterateOwner();
+	int owner = elObjDb.getIterateOwner(level);
 	ElementObjectData& rankBoundEl = objData[mpiRank];
 	
 	AtomicBoundary bound;	    	    
@@ -1574,7 +1634,7 @@ namespace AMDiS {
 	    
 	    bound.type = INTERIOR;
 	    
-	    AtomicBoundary& b = rankIntBoundary.getNewAtomic(it2->first);
+	    AtomicBoundary& b = rankIntBoundary.getNewAtomic(level, it2->first);
 	    b = bound;
 	    if (geoIndex == EDGE)
 	      b.neighObj.reverseMode = 
@@ -1598,7 +1658,7 @@ namespace AMDiS {
 	  
 	  bound.type = INTERIOR;
 	  
-	  AtomicBoundary& b = otherIntBoundary.getNewAtomic(owner);
+	  AtomicBoundary& b = otherIntBoundary.getNewAtomic(level, owner);
 	  b = bound;	    
 	  if (geoIndex == EDGE)
 	    b.rankObj.reverseMode =
@@ -1618,16 +1678,12 @@ namespace AMDiS {
       if (elObjDb.isInRank(it->first.first, mpiRank) == false)
 	continue;
 
-      //      MSG("PERIODIC DOF: %d -> %d with ASOC %d\n", it->first.first, it->first.second, it->second);
-
       ElementObjectData& perDofEl0 = 
 	elObjDb.getElementsInRank(it->first.first)[mpiRank];
 
       for (map<int, ElementObjectData>::iterator elIt = elObjDb.getElementsInRank(it->first.second).begin();
 	   elIt != elObjDb.getElementsInRank(it->first.second).end(); ++elIt) {
 
-	//	MSG("   in el %d %d\n", perDofEl0.elIndex, perDofEl0.ithObject);
-
 	int otherElementRank = elIt->first;
 	ElementObjectData& perDofEl1 = elIt->second;
 
@@ -1651,11 +1707,11 @@ namespace AMDiS {
 	      bound.rankObj.ithObj == 1 ||
 	      bound.rankObj.elIndex == 78 &&
 	      bound.rankObj.ithObj == 2) {
-	    AtomicBoundary& b = periodicBoundary.getNewAtomic(otherElementRank);
+	    AtomicBoundary& b = periodicBoundary.getNewAtomic(level, otherElementRank);
 	    b = bound;
 	  }
 	} else {
-	  AtomicBoundary& b = periodicBoundary.getNewAtomic(otherElementRank);
+	  AtomicBoundary& b = periodicBoundary.getNewAtomic(level, otherElementRank);
 	  b = bound;	    
 	}
       }
@@ -1690,7 +1746,7 @@ namespace AMDiS {
 	
 	bound.type = it->second;
 	
-	AtomicBoundary& b = periodicBoundary.getNewAtomic(otherElementRank);
+	AtomicBoundary& b = periodicBoundary.getNewAtomic(level, otherElementRank);
 	b = bound;
      
 	if (mpiRank > otherElementRank)
@@ -1736,7 +1792,7 @@ namespace AMDiS {
 	
 	bound.type = it->second;
 	
-	AtomicBoundary& b = periodicBoundary.getNewAtomic(otherElementRank);
+	AtomicBoundary& b = periodicBoundary.getNewAtomic(level, otherElementRank);
 	b = bound;
      
 	if (mpiRank > otherElementRank)
@@ -1755,8 +1811,8 @@ namespace AMDiS {
     // === share the bounday.                                                 ===
 
     StdMpi<vector<AtomicBoundary> > stdMpi(mpiComm);
-    stdMpi.send(rankIntBoundary.boundary);
-    stdMpi.recv(otherIntBoundary.boundary);
+    stdMpi.send(rankIntBoundary.boundary[level]);
+    stdMpi.recv(otherIntBoundary.boundary[level]);
     stdMpi.startCommunication();
 
 
@@ -1765,8 +1821,8 @@ namespace AMDiS {
     // === the same order. If not, the atomic boundaries are swaped to the    ===
     // === correct order.                                                     ===
 
-    for (RankToBoundMap::iterator rankIt = otherIntBoundary.boundary.begin();
-	 rankIt != otherIntBoundary.boundary.end(); ++rankIt) {
+    for (RankToBoundMap::iterator rankIt = otherIntBoundary.boundary[level].begin();
+	 rankIt != otherIntBoundary.boundary[level].end(); ++rankIt) {
 
       // === We have received from rank "rankIt->first" the ordered list of   ===
       // === element indices. Now, we have to sort the corresponding list in  ===
@@ -1800,28 +1856,29 @@ namespace AMDiS {
 
     // === Do the same for the periodic boundaries. ===
 
-    if (periodicBoundary.boundary.size() > 0) {
+    if (periodicBoundary.boundary[level].size() > 0) {
       stdMpi.clear();
 
-      InteriorBoundary sendBounds, recvBounds;     
-      for (RankToBoundMap::iterator rankIt = periodicBoundary.boundary.begin();
-	   rankIt != periodicBoundary.boundary.end(); ++rankIt) {
+      InteriorBoundary sendBounds(levelData.getLevelNumber());
+      InteriorBoundary recvBounds(levelData.getLevelNumber());
+      for (RankToBoundMap::iterator rankIt = periodicBoundary.boundary[level].begin();
+	   rankIt != periodicBoundary.boundary[level].end(); ++rankIt) {
 
 	if (rankIt->first == mpiRank)
 	  continue;
 
 	if (rankIt->first < mpiRank)
-	  sendBounds.boundary[rankIt->first] = rankIt->second;
+	  sendBounds.boundary[level][rankIt->first] = rankIt->second;
 	else
-	  recvBounds.boundary[rankIt->first] = rankIt->second;	
+	  recvBounds.boundary[level][rankIt->first] = rankIt->second;	
       }
 
-      stdMpi.send(sendBounds.boundary);
-      stdMpi.recv(recvBounds.boundary);
+      stdMpi.send(sendBounds.boundary[level]);
+      stdMpi.recv(recvBounds.boundary[level]);
       stdMpi.startCommunication();
 
-      for (RankToBoundMap::iterator rankIt = periodicBoundary.boundary.begin();
-	   rankIt != periodicBoundary.boundary.end(); ++rankIt) {
+      for (RankToBoundMap::iterator rankIt = periodicBoundary.boundary[level].begin();
+	   rankIt != periodicBoundary.boundary[level].end(); ++rankIt) {
 
  	if (rankIt->first <= mpiRank)
  	  continue;
@@ -1832,12 +1889,12 @@ namespace AMDiS {
 	  BoundaryObject &recvNeighObj = 
 	    stdMpi.getRecvData()[rankIt->first][j].neighObj;
 
-	  if (periodicBoundary.boundary[rankIt->first][j].neighObj != recvRankObj ||
-	      periodicBoundary.boundary[rankIt->first][j].rankObj != recvNeighObj) {
+	  if (periodicBoundary.boundary[level][rankIt->first][j].neighObj != recvRankObj ||
+	      periodicBoundary.boundary[level][rankIt->first][j].rankObj != recvNeighObj) {
 	    unsigned int k = j + 1;	    
 	    for (; k < rankIt->second.size(); k++)
-	      if (periodicBoundary.boundary[rankIt->first][k].neighObj == recvRankObj &&
-		  periodicBoundary.boundary[rankIt->first][k].rankObj == recvNeighObj)
+	      if (periodicBoundary.boundary[level][rankIt->first][k].neighObj == recvRankObj &&
+		  periodicBoundary.boundary[level][rankIt->first][k].rankObj == recvNeighObj)
 		break;
 	    
 	    // The element must always be found, because the list is just in 
@@ -1851,7 +1908,7 @@ namespace AMDiS {
 	  } 
 	}
       }     
-    } // periodicBoundary.boundary.size() > 0
+    } // periodicBoundary.boundary[level].size() > 0
   }
 
 
@@ -1888,7 +1945,7 @@ namespace AMDiS {
 
       // === Create send DOFs. ===
       for (int geo = FACE; geo >= VERTEX; geo--) {
-	for (InteriorBoundary::iterator it(rankIntBoundary, levelData, level); 
+	for (InteriorBoundary::iterator it(rankIntBoundary, level); 
 	     !it.end(); ++it) {
 	  if (it->rankObj.subObj == geo) {
 	    DofContainer dofs;
@@ -1906,7 +1963,7 @@ namespace AMDiS {
 
       // === Create recv DOFs. ===
       for (int geo = FACE; geo >= VERTEX; geo--) {
-	for (InteriorBoundary::iterator it(otherIntBoundary, levelData, level); 
+	for (InteriorBoundary::iterator it(otherIntBoundary, level); 
 	     !it.end(); ++it) {
 	  if (it->rankObj.subObj == geo) {
 	    DofContainer dofs;
@@ -1922,12 +1979,12 @@ namespace AMDiS {
 	}
       }
     } else {
-      for (InteriorBoundary::iterator it(rankIntBoundary, levelData, level);
+      for (InteriorBoundary::iterator it(rankIntBoundary, level);
 	   !it.end(); ++it)
 	it->rankObj.el->getAllDofs(feSpace, it->rankObj, 
 				   sendDofs.getDofContainer(it.getRank(), feSpace, level));
       
-      for (InteriorBoundary::iterator it(otherIntBoundary, levelData, level); 
+      for (InteriorBoundary::iterator it(otherIntBoundary, level); 
 	   !it.end(); ++it)
 	it->rankObj.el->getAllDofs(feSpace, it->rankObj, 
 				   recvDofs.getDofContainer(it.getRank(), feSpace, level));
@@ -1966,14 +2023,12 @@ namespace AMDiS {
     int nLevels = levelData.getLevelNumber();
     TEST_EXIT_DBG(nLevels >= 1)("Should not happen!\n");
 
-    sendDofs.init(nLevels);
-    recvDofs.init(nLevels);
-    boundaryDofInfo.resize(nLevels);
-
     dofMap.init(levelData, feSpaces, feSpaces, true, true);
     dofMap.setDofComm(sendDofs, recvDofs);
     dofMap.clear();
 
+    createBoundaryDofs();
+
     for (unsigned int i = 0; i < feSpaces.size(); i++)
       updateLocalGlobalNumbering(feSpaces[i]);
 
@@ -2027,22 +2082,10 @@ namespace AMDiS {
 
     int nLevels = levelData.getLevelNumber();
     for (int level = 0; level < nLevels; level++) {
-      createBoundaryDofs(feSpace, level);
-      
-      // All DOFs that must be received are DOFs not owned by rank and have 
-      // therefore to be removed from the set 'rankDofs'.
       DofContainerSet nonRankDofs;
-      for (DofComm::Iterator it(recvDofs, level, feSpace); !it.end(); it.nextRank()) {
-	for (; !it.endDofIter(); it.nextDof()) {
-#if 0
-	  DofContainer::iterator eraseIt = 
-	    find(rankDofs.begin(), rankDofs.end(), it.getDof());
-	  if (eraseIt != rankDofs.end())
-	    rankDofs.erase(eraseIt);
-#endif
+      for (DofComm::Iterator it(recvDofs, level, feSpace); !it.end(); it.nextRank())
+	for (; !it.endDofIter(); it.nextDof())
 	  nonRankDofs.insert(it.getDof());
-	}
-      }
       
       for (unsigned int i = 0; i < rankDofs.size(); i++)
 	if (nonRankDofs.count(rankDofs[i]) == 0)
@@ -2069,6 +2112,8 @@ namespace AMDiS {
   {
     FUNCNAME("MeshDistributor::createPeriodicMap()");
 
+    TEST_EXIT(levelData.getLevelNumber() == 1)("Not yet implemented for multilevel!\n");
+
     // Clear all periodic DOF mappings calculated before. We do it from scratch.
     periodicDofs.init(levelData.getLevelNumber());
     periodicMap.clear();
@@ -2077,7 +2122,7 @@ namespace AMDiS {
     // periodicMap must be still cleared before: if we do repartitioning and
     // there were periodic boundaries in subdomain before and after repartitioning
     // there are no more periodic boundaries.
-    if (periodicBoundary.boundary.size() == 0)
+    if (periodicBoundary.boundary[0].size() == 0)
       return;
 
     for (unsigned int i = 0; i < feSpaces.size(); i++)
@@ -2089,6 +2134,8 @@ namespace AMDiS {
   {
     FUNCNAME("MeshDistributor::createPeriodicMap()");
 
+    TEST_EXIT(levelData.getLevelNumber() == 1)("No yet implemented for multilevel stuff!\n");
+
     StdMpi<vector<int> > stdMpi(mpiComm, false);
 
     // === Each rank traverse its periodic boundaries and sends the DOF      ===
@@ -2096,8 +2143,8 @@ namespace AMDiS {
 
     map<int, vector<int> > rankToDofType;
 
-    for (RankToBoundMap::iterator it = periodicBoundary.boundary.begin();
-	 it != periodicBoundary.boundary.end(); ++it) {
+    for (RankToBoundMap::iterator it = periodicBoundary.boundary[0].begin();
+	 it != periodicBoundary.boundary[0].end(); ++it) {
 
       if (it->first == mpiRank) {
 	// Here we have a periodic boundary within rank's subdomain. So we can
@@ -2122,8 +2169,8 @@ namespace AMDiS {
 	  BoundaryType type = bound.type;
 
 	  for (unsigned int j = 0; j < dofs0.size(); j++) {
-	    DegreeOfFreedom globalDof0 = dofMap[feSpace][*(dofs0[j])].global;
-	    DegreeOfFreedom globalDof1 = dofMap[feSpace][*(dofs1[j])].global;
+	    DegreeOfFreedom globalDof0 = dofMap[feSpace][0][*(dofs0[j])].global;
+	    DegreeOfFreedom globalDof1 = dofMap[feSpace][0][*(dofs1[j])].global;
 
 	    if (!periodicMap.isPeriodicOnBound(feSpace, type, globalDof0))
 	      periodicMap.add(feSpace, type, globalDof0, globalDof1);
@@ -2148,7 +2195,7 @@ namespace AMDiS {
 	// 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(dofMap[feSpace][*(dofs[i])].global);
+	  stdMpi.getSendData(it->first).push_back(dofMap[feSpace][0][*(dofs[i])].global);
 	
 	// Receive from this rank the same number of dofs.
 	stdMpi.recv(it->first, dofs.size());
@@ -2165,8 +2212,8 @@ namespace AMDiS {
     // === DOFs from the other ranks.                                        ===
 
 
-    for (RankToBoundMap::iterator it = periodicBoundary.boundary.begin();
-	 it != periodicBoundary.boundary.end(); ++it) {
+    for (RankToBoundMap::iterator it = periodicBoundary.boundary[0].begin();
+	 it != periodicBoundary.boundary[0].end(); ++it) {
       DofContainer& dofs = periodicDofs.getDofContainer(it->first, feSpace);
       vector<int>& types = rankToDofType[it->first];
 
@@ -2174,7 +2221,7 @@ namespace AMDiS {
 
       // Added the received DOFs to the mapping.
       for (unsigned int i = 0; i < dofs.size(); i++) {
-	int globalDofIndex = dofMap[feSpace][*(dofs[i])].global;
+	int globalDofIndex = dofMap[feSpace][0][*(dofs[i])].global;
 	int mapGlobalDofIndex = stdMpi.getRecvData(it->first)[i];
 	BoundaryType type = types[i];
 
@@ -2189,8 +2236,8 @@ namespace AMDiS {
     StdMpi<PeriodicDofMap> stdMpi2(mpiComm);
 
 
-    for (RankToBoundMap::iterator it = periodicBoundary.boundary.begin();
-	 it != periodicBoundary.boundary.end(); ++it) {
+    for (RankToBoundMap::iterator it = periodicBoundary.boundary[0].begin();
+	 it != periodicBoundary.boundary[0].end(); ++it) {
       if (it->first == mpiRank)
 	continue;
 
@@ -2207,7 +2254,7 @@ namespace AMDiS {
 	boundIt->rankObj.el->getAllDofs(feSpace, boundIt->rankObj, dofs);
 
 	for (unsigned int i = 0; i < dofs.size(); i++) {
-	  DegreeOfFreedom globalDof = dofMap[feSpace][*dofs[i]].global;
+	  DegreeOfFreedom globalDof = dofMap[feSpace][0][*dofs[i]].global;
 
 	  std::set<BoundaryType>& assoc = 
 	    periodicMap.getAssociations(feSpace, globalDof);
diff --git a/AMDiS/src/parallel/MeshDistributor.h b/AMDiS/src/parallel/MeshDistributor.h
index f1b0c2bfab692f88af56ba84794fc0c16d0937d3..0f584268b8f3a2bcde9776bd7f4d4ab4ad25d140 100644
--- a/AMDiS/src/parallel/MeshDistributor.h
+++ b/AMDiS/src/parallel/MeshDistributor.h
@@ -255,8 +255,8 @@ namespace AMDiS {
       createBoundaryDofFlag = flag;
     }
 
-    BoundaryDofInfo& getBoundaryDofInfo(const FiniteElemSpace *feSpace, 
-					int level = 0)
+    BoundaryDofInfo& getBoundaryDofInfo(const FiniteElemSpace *feSpace,
+					int level)
     {
       FUNCNAME("MeshDistributor::getBoundaryDofInfo()");
 
@@ -297,6 +297,8 @@ namespace AMDiS {
 
     void createBoundaryData();
 
+    void createBoundaryData(int level);
+
     void createBoundaryDofs();
 
     void createBoundaryDofs(const FiniteElemSpace *feSpace, int level);
diff --git a/AMDiS/src/parallel/MeshLevelData.h b/AMDiS/src/parallel/MeshLevelData.h
index 9151705db4b4e87a47fb3f1e978c16ee5198c056..0bb461756e455a665ffed8030c1be4b57d4e2fa0 100644
--- a/AMDiS/src/parallel/MeshLevelData.h
+++ b/AMDiS/src/parallel/MeshLevelData.h
@@ -86,6 +86,31 @@ namespace AMDiS {
       return mpiGroups[level];
     }
 
+    int getLevelId(int level, int rank) 
+    {
+      if (level == 0)
+	return rank;
+
+      TEST_EXIT_DBG(level == 1 && rank <= 15)("Should not happen!\n");
+      TEST_EXIT_DBG(MPI::COMM_WORLD.Get_size() == 16)("Should not happen!\n");
+
+      if (rank == 0 || rank == 1 || rank == 4 || rank == 5)
+	return 0;
+
+      if (rank == 2 || rank == 3 || rank == 6 || rank == 7)
+	return 1;
+      
+      if (rank == 8 || rank == 9 || rank == 12 || rank == 13)
+	return 2;
+
+      if (rank == 10 || rank == 11 || rank == 14 || rank == 15)
+	return 3;
+
+      ERROR_EXIT("Should not happen!\n");
+
+      return -1;
+    }
+
     int mapRank(int fromRank, int fromLevel, int toLevel)
     {
       int toRank = -1;
diff --git a/AMDiS/src/parallel/ParallelDebug.cc b/AMDiS/src/parallel/ParallelDebug.cc
index d9a63eedadd85a7202940a0c82f13e27ac241553..fbcac563997bff65bdae71cf7a25ca07fcdd2bfb 100644
--- a/AMDiS/src/parallel/ParallelDebug.cc
+++ b/AMDiS/src/parallel/ParallelDebug.cc
@@ -39,8 +39,8 @@ namespace AMDiS {
 
     // === Send rank's boundary information. ===
 
-    for (RankToBoundMap::iterator rankIt = pdb.rankIntBoundary.boundary.begin();
-	 rankIt != pdb.rankIntBoundary.boundary.end(); ++rankIt) {
+    for (RankToBoundMap::iterator rankIt = pdb.rankIntBoundary.boundary[0].begin();
+	 rankIt != pdb.rankIntBoundary.boundary[0].end(); ++rankIt) {
 
       int nSendInt = rankIt->second.size();
       int* buffer = new int[nSendInt];
@@ -56,8 +56,8 @@ namespace AMDiS {
 
     // === Receive information from other ranks about the interior boundaries. ====
 
-    for (RankToBoundMap::iterator rankIt = pdb.otherIntBoundary.boundary.begin();
-	 rankIt != pdb.otherIntBoundary.boundary.end(); ++rankIt) {
+    for (RankToBoundMap::iterator rankIt = pdb.otherIntBoundary.boundary[0].begin();
+	 rankIt != pdb.otherIntBoundary.boundary[0].end(); ++rankIt) {
       int nRecvInt = rankIt->second.size();
       int *buffer = new int[nRecvInt];
       recvBuffers.push_back(buffer);
@@ -69,8 +69,8 @@ namespace AMDiS {
 
     // === To the last, do the same of periodic boundaries. ===
 
-    for (RankToBoundMap::iterator rankIt = pdb.periodicBoundary.boundary.begin();       
-	 rankIt != pdb.periodicBoundary.boundary.end(); ++rankIt) {
+    for (RankToBoundMap::iterator rankIt = pdb.periodicBoundary.boundary[0].begin();       
+	 rankIt != pdb.periodicBoundary.boundary[0].end(); ++rankIt) {
       if (rankIt->first == pdb.mpiRank)
 	continue;
 
@@ -103,8 +103,8 @@ namespace AMDiS {
     // === and after this the periodic ones.                                   ===
 
     int bufCounter = 0;
-    for (RankToBoundMap::iterator rankIt = pdb.otherIntBoundary.boundary.begin();
-	 rankIt != pdb.otherIntBoundary.boundary.end(); ++rankIt) {
+    for (RankToBoundMap::iterator rankIt = pdb.otherIntBoundary.boundary[0].begin();
+	 rankIt != pdb.otherIntBoundary.boundary[0].end(); ++rankIt) {
 
       TEST_EXIT(rankIt->second.size() == 
 		pdb.otherIntBoundary.boundary[rankIt->first].size())
@@ -112,7 +112,7 @@ namespace AMDiS {
 
       for (unsigned int i = 0; i < rankIt->second.size(); i++) {
 	int elIndex1 = recvBuffers[bufCounter][i];
-	int elIndex2 = pdb.otherIntBoundary.boundary[rankIt->first][i].neighObj.elIndex;
+	int elIndex2 = pdb.otherIntBoundary.boundary[0][rankIt->first][i].neighObj.elIndex;
 
 	TEST_EXIT(elIndex1 == elIndex2)("Wrong element index at interior boundary!\n");
       }
@@ -121,18 +121,18 @@ namespace AMDiS {
     }
 
 
-    for (RankToBoundMap::iterator rankIt = pdb.periodicBoundary.boundary.begin();
-	 rankIt != pdb.periodicBoundary.boundary.end(); ++rankIt) {
+    for (RankToBoundMap::iterator rankIt = pdb.periodicBoundary.boundary[0].begin();
+	 rankIt != pdb.periodicBoundary.boundary[0].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;
+	int elIndex2 = pdb.periodicBoundary.boundary[0][rankIt->first][i].neighObj.elIndex;
 
 	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,
+	   pdb.periodicBoundary.boundary[0][rankIt->first][i].rankObj.elIndex,
 	   rankIt->first, elIndex1, elIndex2);
       }
 
@@ -256,8 +256,8 @@ namespace AMDiS {
     RankToCoords sendCoords;
     map<int, vector<BoundaryType> > rankToDofType;
 
-    for (InteriorBoundary::RankToBoundMap::iterator it = pdb.periodicBoundary.boundary.begin();
-	 it != pdb.periodicBoundary.boundary.end(); ++it) {
+    for (InteriorBoundary::RankToBoundMap::iterator it = pdb.periodicBoundary.boundary[0].begin();
+	 it != pdb.periodicBoundary.boundary[0].end(); ++it) {
       if (it->first == pdb.mpiRank)
 	continue;
 
@@ -479,7 +479,7 @@ namespace AMDiS {
 
     DOFIterator<WorldVector<double> > it(&coords, USED_DOFS);
     for (it.reset(); !it.end(); ++it) {
-      coordsToIndex[(*it)] = pdb.dofMap[feSpace][it.getDOFIndex()].global;
+      coordsToIndex[(*it)] = pdb.dofMap[feSpace][0][it.getDOFIndex()].global;
 //       MSG("   CHECK FOR DOF %d AT COORDS %f %f %f\n",
 // 	  coordsToIndex[(*it)], (*it)[0], (*it)[1], (*it)[2]);
     }
@@ -780,8 +780,8 @@ namespace AMDiS {
     DOFIterator<WorldVector<double> > it(&coords, USED_DOFS);
     for (it.reset(); !it.end(); ++it) {
       file << it.getDOFIndex() << " " 
-	   << pdb.dofMap[feSpace][it.getDOFIndex()].global << " "
-	   << pdb.dofMap[feSpace].isRankDof(it.getDOFIndex());
+	   << pdb.dofMap[feSpace][0][it.getDOFIndex()].global << " "
+	   << pdb.dofMap[feSpace].isRankDof(it.getDOFIndex(), 0);
       for (int i = 0; i < pdb.mesh->getDim(); i++)
 	file << " " << (*it)[i];
       file << "\n";
diff --git a/AMDiS/src/parallel/ParallelDofMapping.cc b/AMDiS/src/parallel/ParallelDofMapping.cc
index 927847cd2c3746e32b0abc29bf915b6f959195b6..d981fee3782399be4c94a02d898b9e9282e7c97e 100644
--- a/AMDiS/src/parallel/ParallelDofMapping.cc
+++ b/AMDiS/src/parallel/ParallelDofMapping.cc
@@ -86,7 +86,8 @@ namespace AMDiS {
     // === Send all global indices of DOFs that are owned by the rank to all ===
     // === other ranks that also include this DOF.                           ===
 
-    StdMpi<vector<int> > stdMpi(levelData->getMpiComm(level));
+    //    StdMpi<vector<int> > stdMpi(levelData->getMpiComm(level));
+    StdMpi<vector<int> > stdMpi(levelData->getMpiComm(0));
 
     for (DofComm::Iterator it(*sendDofs, level, feSpace); 
 	 !it.end(); it.nextRank())
@@ -171,15 +172,15 @@ namespace AMDiS {
     nLocalDofs.resize(nLevel);
     nOverallDofs.resize(nLevel);
     rStartDofs.resize(nLevel);
+    dofToMatIndex.resize(nLevel);
 
     for (int i = 0; i < nLevel; i++) {
       nRankDofs[i] = -1;
       nLocalDofs[i] = -1;
       nOverallDofs[i] = -1;
       rStartDofs[i] = -1;
+      dofToMatIndex[i].clear();
     }
-
-    dofToMatIndex.clear();
   }
 
 
@@ -310,9 +311,7 @@ namespace AMDiS {
   {
     FUNCNAME("ParallelDofMapping::computeMatIndex()");
 
-    TEST_EXIT(level == 0)("Not yet implemented for non-zero level!\n");
-
-    dofToMatIndex.clear();
+    dofToMatIndex[level].clear();
     
     // The offset is always added to the local matrix index. The offset for the
     // DOFs in the first FE spaces is the smalled global index of a DOF that is
@@ -328,12 +327,12 @@ namespace AMDiS {
       // a matrix index.
       DofMap& dofMap = data[feSpaces[i]].getMap(level);
       for (DofMap::iterator it = dofMap.begin(); it != dofMap.end(); ++it) {
-	if (data[feSpaces[i]].isRankDof(it->first)) {
+	if (data[feSpaces[i]].isRankDof(it->first, level)) {
 	  int globalMatIndex = it->second.local + offset;
 	  if (globalIndex)
-	    dofToMatIndex.add(i, it->second.global, globalMatIndex);
+	    dofToMatIndex[level].add(i, it->second.global, globalMatIndex);
 	  else
-	    dofToMatIndex.add(i, it->first, globalMatIndex);
+	    dofToMatIndex[level].add(i, it->first, globalMatIndex);
 	}
       }
       
@@ -351,7 +350,8 @@ namespace AMDiS {
       // === Communicate the matrix indices for all DOFs that are on some ===
       // === interior boundaries.                                         ===
 
-      StdMpi<vector<DegreeOfFreedom> > stdMpi(levelData->getMpiComm(level));
+      //      StdMpi<vector<DegreeOfFreedom> > stdMpi(levelData->getMpiComm(level));
+      StdMpi<vector<DegreeOfFreedom> > stdMpi(levelData->getMpiComm(0));
       for (DofComm::Iterator it(*sendDofs, level, feSpaces[i]); 
 	   !it.end(); it.nextRank()) {
 	vector<DegreeOfFreedom> sendGlobalDofs;
@@ -359,9 +359,9 @@ namespace AMDiS {
 	for (; !it.endDofIter(); it.nextDof())
 	  if (dofMap.count(it.getDofIndex()))
 	    if (globalIndex)
-	      sendGlobalDofs.push_back(dofToMatIndex.get(i, dofMap[it.getDofIndex()].global));
+	      sendGlobalDofs.push_back(dofToMatIndex[level].get(i, dofMap[it.getDofIndex()].global));
 	    else
-	      sendGlobalDofs.push_back(dofToMatIndex.get(i, it.getDofIndex()));
+	      sendGlobalDofs.push_back(dofToMatIndex[level].get(i, it.getDofIndex()));
 	
 	stdMpi.send(it.getRank(), sendGlobalDofs);
       }
@@ -380,9 +380,9 @@ namespace AMDiS {
 	    if (dofMap.count(it.getDofIndex())) {
 	      DegreeOfFreedom d = stdMpi.getRecvData(it.getRank())[counter++];
 	      if (globalIndex)
-		dofToMatIndex.add(i, dofMap[it.getDofIndex()].global, d);
+		dofToMatIndex[level].add(i, dofMap[it.getDofIndex()].global, d);
 	      else
-		dofToMatIndex.add(i, it.getDofIndex(), d);
+		dofToMatIndex[level].add(i, it.getDofIndex(), d);
 	    }
 	  }
 	}
diff --git a/AMDiS/src/parallel/ParallelDofMapping.h b/AMDiS/src/parallel/ParallelDofMapping.h
index 1043fe7535f1f1a4404f7600e28a0a4c7fe40a7f..c4e945113e54cbf54f265362ad11971d6c085836 100644
--- a/AMDiS/src/parallel/ParallelDofMapping.h
+++ b/AMDiS/src/parallel/ParallelDofMapping.h
@@ -121,7 +121,8 @@ namespace AMDiS {
 
     /// Clears all data of the mapping.
     void clear();
-    
+
+#if 0    
     /// Maps a DOF index to both, the local and global index of the mapping. The
     /// global index must not be set.
     MultiIndex& operator[](DegreeOfFreedom d)
@@ -130,6 +131,14 @@ namespace AMDiS {
 
       return dofMap[0][d];
     }
+#else
+    DofMap& operator[](int level)
+    {
+      TEST_EXIT_DBG(level < static_cast<int>(dofMap.size()))("Should not happen!\n");
+      
+      return dofMap[level];
+    }
+#endif
     
     /// Inserts a new DOF to rank's mapping. The DOF is assumed to be owend by
     /// the rank.
@@ -159,7 +168,7 @@ namespace AMDiS {
     }
     
     /// Checks if a given DOF is in the DOF mapping.
-    bool isSet(DegreeOfFreedom dof, int level = 0)
+    bool isSet(DegreeOfFreedom dof, int level)
     {
       return static_cast<bool>(dofMap[level].count(dof));
     }
@@ -167,15 +176,15 @@ namespace AMDiS {
     /// Checks if a given DOF is a rank owned DOF of the DOF mapping. The DOF must
     /// a DOF of the mapping (this is not checked here), otherwise the result is
     /// meaningsless.
-    bool isRankDof(DegreeOfFreedom dof)
+    bool isRankDof(DegreeOfFreedom dof, int level)
     {
-      return !(static_cast<bool>(nonRankDofs[0].count(dof)));
+      return !(static_cast<bool>(nonRankDofs[level].count(dof)));
     }
     
     /// Returns number of DOFs in the mapping.
-    unsigned int size()
+    unsigned int size(int level)
     {
-      return dofMap[0].size();
+      return dofMap[level].size();
     }
     
     /// Returns the raw data of the mapping.
@@ -362,21 +371,21 @@ namespace AMDiS {
 
     /// Returns the global matrix index of a given DOF for a given 
     /// component number.
-    inline int getMatIndex(int ithComponent, DegreeOfFreedom d)
+    inline int getMatIndex(int level, int ithComponent, DegreeOfFreedom d)
     {
-      return dofToMatIndex.get(ithComponent, d);
+      return dofToMatIndex[level].get(ithComponent, d);
     }
 
     /// Returns the local matrix index of a given DOF for a given 
     /// component number.
-    inline int getLocalMatIndex(int ithComponent, DegreeOfFreedom d)
+    inline int getLocalMatIndex(int level, int ithComponent, DegreeOfFreedom d)
     {
       FUNCNAME("ParallelDofMapping::getLocalMatIndex()");
 
-      TEST_EXIT_DBG(data[feSpaces[ithComponent]].isRankDof(d))
+      TEST_EXIT_DBG(data[feSpaces[ithComponent]].isRankDof(d, level))
 	("Should not happen!\n");
 
-      return dofToMatIndex.get(ithComponent, d) - rStartDofs[0];
+      return dofToMatIndex[level].get(ithComponent, d) - rStartDofs[level];
     }
 
     // Writes all data of this object to an output stream.
@@ -455,7 +464,7 @@ namespace AMDiS {
 
     /// Mapping from global DOF indices to global matrix indices under 
     /// consideration of possibly multiple components.
-    DofToMatIndex dofToMatIndex;
+    vector<DofToMatIndex> dofToMatIndex;
   };
 
 }
diff --git a/AMDiS/src/parallel/PetscSolverFeti.cc b/AMDiS/src/parallel/PetscSolverFeti.cc
index 4cfd74ae934f72e33a4c82ff2a9c1bf1c86dc057..9705970ce56d52a085a33033d59f0e00fb331b82 100644
--- a/AMDiS/src/parallel/PetscSolverFeti.cc
+++ b/AMDiS/src/parallel/PetscSolverFeti.cc
@@ -295,8 +295,10 @@ namespace AMDiS {
     for (unsigned int i = 0; i < meshDistributor->getFeSpaces().size(); i++) {
       const FiniteElemSpace *feSpace = meshDistributor->getFeSpace(i);
 
-      createPrimals(feSpace);      
+      createPrimals(feSpace);  
+
       createDuals(feSpace);      
+
       createIndexB(feSpace);
     }
 
@@ -306,6 +308,15 @@ namespace AMDiS {
     if (fetiPreconditioner != FETI_NONE)
       interiorDofMap.update();
 
+    for (unsigned int i = 0; i < meshDistributor->getFeSpaces().size(); i++) {
+      const FiniteElemSpace *feSpace = meshDistributor->getFeSpace(i);
+
+      MSG("TEST DUALS %d %d %d\n",
+	  dualDofMap[feSpace].nLocalDofs[meshLevel], 
+	  dualDofMap[feSpace].nRankDofs[meshLevel], 
+	  dualDofMap[feSpace].nOverallDofs[meshLevel]);
+    }	
+
     for (unsigned int i = 0; i < meshDistributor->getFeSpaces().size(); i++) {
       const FiniteElemSpace *feSpace = meshDistributor->getFeSpace(i);
       createLagrange(feSpace);
@@ -313,20 +324,24 @@ namespace AMDiS {
     lagrangeMap.update();
 
 
+    MSG("FETI-DP data created on mesh level %d\n", meshLevel);
     for (unsigned int i = 0; i < meshDistributor->getFeSpaces().size(); i++) {
       const FiniteElemSpace *feSpace = meshDistributor->getFeSpace(i);
       MSG("FETI-DP data for %d-ith FE space:\n", i);
 
       MSG("  nRankPrimals = %d   nOverallPrimals = %d\n", 
-	  primalDofMap[feSpace].nRankDofs[0], primalDofMap[feSpace].nOverallDofs[0]);
+	  primalDofMap[feSpace].nRankDofs[meshLevel], 
+	  primalDofMap[feSpace].nOverallDofs[meshLevel]);
       
       MSG("  nRankDuals = %d  nOverallDuals = %d\n",
-	  dualDofMap[feSpace].nRankDofs[0], dualDofMap[feSpace].nOverallDofs[0]);
+	  dualDofMap[feSpace].nRankDofs[meshLevel], 
+	  dualDofMap[feSpace].nOverallDofs[meshLevel]);
 
       MSG("  nRankLagrange = %d  nOverallLagrange = %d\n",
-	  lagrangeMap[feSpace].nRankDofs[0], lagrangeMap[feSpace].nOverallDofs[0]);
+	  lagrangeMap[feSpace].nRankDofs[meshLevel], 
+	  lagrangeMap[feSpace].nOverallDofs[meshLevel]);
 
-      TEST_EXIT_DBG(localDofMap[feSpace].size() + primalDofMap[feSpace].size() == 
+      TEST_EXIT_DBG(localDofMap[feSpace].size(meshLevel) + primalDofMap[feSpace].size(meshLevel) == 
 		    static_cast<unsigned int>(feSpace->getAdmin()->getUsedDofs()))
 	("Should not happen!\n");
     }
@@ -358,10 +373,10 @@ namespace AMDiS {
     // === create local indices of the primals starting at zero.          ===
 
     for (DofIndexSet::iterator it = primals.begin(); it != primals.end(); ++it)
-      if (meshDistributor->getDofMap()[feSpace].isRankDof(*it))
-	primalDofMap[feSpace].insertRankDof(0, *it);
+      if (meshDistributor->getDofMap()[feSpace].isRankDof(*it, meshLevel))
+	primalDofMap[feSpace].insertRankDof(meshLevel, *it);
       else
-  	primalDofMap[feSpace].insertNonRankDof(0, *it);
+  	primalDofMap[feSpace].insertNonRankDof(meshLevel, *it);
   }
 
 
@@ -377,7 +392,7 @@ namespace AMDiS {
     for (DofContainer::iterator it = allBoundaryDofs.begin();
 	 it != allBoundaryDofs.end(); ++it)
       if (!isPrimal(feSpace, **it))
-	dualDofMap[feSpace].insertRankDof(0, **it);
+	dualDofMap[feSpace].insertRankDof(meshLevel, **it);
   }
 
   
@@ -385,11 +400,14 @@ namespace AMDiS {
   {
     FUNCNAME("PetscSolverFeti::createLagrange()");
 
+    boundaryDofRanks[feSpace].clear();
+
+    if (dualDofMap[feSpace].nLocalDofs[meshLevel] == 0)
+      return;
+
     // === Create for each dual node that is owned by the rank, the set ===
     // === of ranks that contain this node (denoted by W(x_j)).         ===
 
-    boundaryDofRanks[feSpace].clear();
-
     for (DofComm::Iterator it(meshDistributor->getSendDofs(), meshLevel, feSpace); 
 	 !it.end(); it.nextRank())
       for (; !it.endDofIter(); it.nextDof()) {
@@ -442,18 +460,18 @@ namespace AMDiS {
     // === appropriate number of Lagrange constraints.                      ===
 
     int nRankLagrange = 0;
-    DofMap& dualMap = dualDofMap[feSpace].getMap(0);
+    DofMap& dualMap = dualDofMap[feSpace].getMap(meshLevel);
     for (DofMap::iterator it = dualMap.begin(); it != dualMap.end(); ++it) {
 
-      if (meshDistributor->getDofMap()[feSpace].isRankDof(it->first)) {
-	lagrangeMap[feSpace].insertRankDof(0, it->first, nRankLagrange);
+      if (meshDistributor->getDofMap()[feSpace].isRankDof(it->first, meshLevel)) {
+	lagrangeMap[feSpace].insertRankDof(meshLevel, it->first, nRankLagrange);
 	int degree = boundaryDofRanks[feSpace][it->first].size();
 	nRankLagrange += (degree * (degree - 1)) / 2;
       } else {
-	lagrangeMap[feSpace].insertNonRankDof(0, it->first);
+	lagrangeMap[feSpace].insertNonRankDof(meshLevel, it->first);
       }
     }
-    lagrangeMap[feSpace].nRankDofs[0] = nRankLagrange;
+    lagrangeMap[feSpace].nRankDofs[meshLevel] = nRankLagrange;
   }
 
 
@@ -471,11 +489,11 @@ namespace AMDiS {
     for (int i = 0; i < admin->getUsedSize(); i++) {
       if (admin->isDofFree(i) == false && 
 	  isPrimal(feSpace, i) == false &&
-	  dualDofMap[feSpace].isSet(i) == false) {
-	localDofMap[feSpace].insertRankDof(0, i, nLocalInterior);
+	  isDual(feSpace, i) == false) {
+	localDofMap[feSpace].insertRankDof(meshLevel, i, nLocalInterior);
 
 	if (fetiPreconditioner != FETI_NONE)
-	  interiorDofMap[feSpace].insertRankDof(0, i, nLocalInterior);
+	  interiorDofMap[feSpace].insertRankDof(meshLevel, i, nLocalInterior);
 
 	nLocalInterior++;
       }
@@ -483,9 +501,9 @@ namespace AMDiS {
     
     // === And finally, add the global indicies of all dual nodes. ===
 
-    for (DofMap::iterator it = dualDofMap[feSpace].getMap(0).begin();
-	 it != dualDofMap[feSpace].getMap(0).end(); ++it)
-      localDofMap[feSpace].insertRankDof(0, it->first);
+    for (DofMap::iterator it = dualDofMap[feSpace].getMap(meshLevel).begin();
+	 it != dualDofMap[feSpace].getMap(meshLevel).end(); ++it)
+      localDofMap[feSpace].insertRankDof(meshLevel, it->first);
   }
 
 
@@ -496,8 +514,10 @@ namespace AMDiS {
     // === Create distributed matrix for Lagrange constraints. ===
 
     MatCreateMPIAIJ(mpiComm,
-		    lagrangeMap.getRankDofs(0), localDofMap.getRankDofs(0),
-		    lagrangeMap.getOverallDofs(0), localDofMap.getOverallDofs(0),
+		    lagrangeMap.getRankDofs(meshLevel), 
+		    localDofMap.getRankDofs(meshLevel),
+		    lagrangeMap.getOverallDofs(meshLevel), 
+		    localDofMap.getOverallDofs(meshLevel),
 		    2, PETSC_NULL, 2, PETSC_NULL,
 		    &mat_lagrange);
 
@@ -509,14 +529,14 @@ namespace AMDiS {
     // === constraint.                                                     ===
 
     for (unsigned int k = 0; k < feSpaces.size(); k++) {
-      DofMap &dualMap = dualDofMap[feSpaces[k]].getMap(0);
+      DofMap &dualMap = dualDofMap[feSpaces[k]].getMap(meshLevel);
 
       for (DofMap::iterator it = dualMap.begin(); it != dualMap.end(); ++it) {
 	TEST_EXIT_DBG(boundaryDofRanks[feSpaces[k]].count(it->first))
 	  ("Should not happen!\n");
 	
 	// Global index of the first Lagrange constriant for this node.
-	int index = lagrangeMap.getMatIndex(k, it->first);
+	int index = lagrangeMap.getMatIndex(meshLevel, k, it->first);
 	
 	// Copy set of all ranks that contain this dual node.
 	vector<int> W(boundaryDofRanks[feSpaces[k]][it->first].begin(), 
@@ -527,7 +547,7 @@ namespace AMDiS {
 	for (int i = 0; i < degree; i++) {
 	  for (int j = i + 1; j < degree; j++) {
 	    if (W[i] == mpiRank || W[j] == mpiRank) {
-	      int colIndex = localDofMap.getMatIndex(k, it->first);
+	      int colIndex = localDofMap.getMatIndex(meshLevel, k, it->first);
 	      double value = (W[i] == mpiRank ? 1.0 : -1.0);
 	      MatSetValue(mat_lagrange, index, colIndex, value, INSERT_VALUES);
 	    }
@@ -544,7 +564,7 @@ namespace AMDiS {
 
   void PetscSolverFeti::createSchurPrimalKsp(vector<const FiniteElemSpace*> &feSpaces)
   {
-    FUNCNAME("PetscSolverFeti::createSchurPrimal()");
+    FUNCNAME("PetscSolverFeti::createSchurPrimalKsp()");
 
     if (schurPrimalSolver == 0) {
       MSG("Create iterative schur primal solver!\n");
@@ -552,15 +572,19 @@ namespace AMDiS {
       schurPrimalData.subSolver = subDomainSolver;
       
       VecCreateMPI(mpiComm, 
-		   localDofMap.getRankDofs(0), localDofMap.getOverallDofs(0),
+		   localDofMap.getRankDofs(meshLevel), 
+		   localDofMap.getOverallDofs(meshLevel),
 		   &(schurPrimalData.tmp_vec_b));
       VecCreateMPI(mpiComm, 
-		   primalDofMap.getRankDofs(0), primalDofMap.getOverallDofs(0),
+		   primalDofMap.getRankDofs(meshLevel), 
+		   primalDofMap.getOverallDofs(meshLevel),
 		   &(schurPrimalData.tmp_vec_primal));
 
       MatCreateShell(mpiComm,
-		     primalDofMap.getRankDofs(0), primalDofMap.getRankDofs(0), 
-		     primalDofMap.getOverallDofs(0), primalDofMap.getOverallDofs(0),
+		     primalDofMap.getRankDofs(meshLevel), 
+		     primalDofMap.getRankDofs(meshLevel), 
+		     primalDofMap.getOverallDofs(meshLevel), 
+		     primalDofMap.getOverallDofs(meshLevel),
 		     &schurPrimalData, 
 		     &mat_schur_primal);
       MatShellSetOperation(mat_schur_primal, MATOP_MULT, 
@@ -576,10 +600,10 @@ namespace AMDiS {
 
       double wtime = MPI::Wtime();
 
-      int nRowsRankPrimal = primalDofMap.getRankDofs(0);
-      int nRowsOverallPrimal = primalDofMap.getOverallDofs(0);
-      int nRowsRankB = localDofMap.getRankDofs(0);
-      int nRowsOverallB = localDofMap.getOverallDofs(0);
+      int nRowsRankPrimal = primalDofMap.getRankDofs(meshLevel);
+      int nRowsOverallPrimal = primalDofMap.getOverallDofs(meshLevel);
+      int nRowsRankB = localDofMap.getRankDofs(meshLevel);
+      int nRowsOverallB = localDofMap.getOverallDofs(meshLevel);
 
       Mat matBPi;
       MatCreateMPIAIJ(mpiComm,
@@ -595,7 +619,7 @@ namespace AMDiS {
       map<int, vector<pair<int, double> > > mat_b_primal_cols;
 
       for (int i = 0; i < nRowsRankB; i++) {
-	PetscInt row = localDofMap.getStartDofs(0) + i;
+	PetscInt row = localDofMap.getStartDofs(meshLevel) + i;
 	MatGetRow(subDomainSolver->getMatIntCoarse(), row, &nCols, &cols, &values);
 
 	for (int j = 0; j < nCols; j++)
@@ -606,7 +630,7 @@ namespace AMDiS {
       }
 
       TEST_EXIT(static_cast<int>(mat_b_primal_cols.size()) == 
-		primalDofMap.getLocalDofs(0))
+		primalDofMap.getLocalDofs(meshLevel))
 	("Should not happen!\n");
 
       for (map<int, vector<pair<int, double> > >::iterator it = mat_b_primal_cols.begin();
@@ -627,7 +651,7 @@ namespace AMDiS {
 	VecGetArray(tmpVec, &tmpValues);
 	for (int i  = 0; i < nRowsRankB; i++)
 	  MatSetValue(matBPi, 
-		      localDofMap.getStartDofs(0) + i,
+		      localDofMap.getStartDofs(meshLevel) + i,
 		      it->first,
 		      tmpValues[i],
 		      ADD_VALUES);
@@ -694,18 +718,23 @@ namespace AMDiS {
     fetiData.ksp_schur_primal = &ksp_schur_primal;
 
     VecCreateMPI(mpiComm, 
-		 localDofMap.getRankDofs(0), localDofMap.getOverallDofs(0),
+		 localDofMap.getRankDofs(meshLevel), 
+		 localDofMap.getOverallDofs(meshLevel),
 		 &(fetiData.tmp_vec_b));
     VecCreateMPI(mpiComm,
-		 lagrangeMap.getRankDofs(0), lagrangeMap.getOverallDofs(0),
+		 lagrangeMap.getRankDofs(meshLevel), 
+		 lagrangeMap.getOverallDofs(meshLevel),
 		 &(fetiData.tmp_vec_lagrange));
     VecCreateMPI(mpiComm, 
-		 primalDofMap.getRankDofs(0), primalDofMap.getOverallDofs(0),
+		 primalDofMap.getRankDofs(meshLevel), 
+		 primalDofMap.getOverallDofs(meshLevel),
 		 &(fetiData.tmp_vec_primal));
 
     MatCreateShell(mpiComm,
-		   lagrangeMap.getRankDofs(0), lagrangeMap.getRankDofs(0),
-		   lagrangeMap.getOverallDofs(0), lagrangeMap.getOverallDofs(0),
+		   lagrangeMap.getRankDofs(meshLevel), 
+		   lagrangeMap.getRankDofs(meshLevel),
+		   lagrangeMap.getOverallDofs(meshLevel), 
+		   lagrangeMap.getOverallDofs(meshLevel),
 		   &fetiData, &mat_feti);
     MatShellSetOperation(mat_feti, MATOP_MULT, (void(*)(void))petscMultMatFeti);
 
@@ -746,7 +775,8 @@ namespace AMDiS {
       fetiDirichletPreconData.ksp_interior = &ksp_interior;
       
       VecCreateMPI(mpiComm, 
-		   localDofMap.getRankDofs(0),localDofMap.getOverallDofs(0),
+		   localDofMap.getRankDofs(meshLevel),
+		   localDofMap.getOverallDofs(meshLevel),
 		   &(fetiDirichletPreconData.tmp_vec_b));      
       MatGetVecs(mat_duals_duals, PETSC_NULL, 
 		 &(fetiDirichletPreconData.tmp_vec_duals0));
@@ -756,11 +786,11 @@ namespace AMDiS {
 		 &(fetiDirichletPreconData.tmp_vec_interior));
 
       for (unsigned int i = 0; i < feSpaces.size(); i++) {
-	DofMap &dualMap = dualDofMap[feSpaces[i]].getMap(0);
+	DofMap &dualMap = dualDofMap[feSpaces[i]].getMap(meshLevel);
 	for (DofMap::iterator it = dualMap.begin(); it != dualMap.end(); ++it) {
 	  DegreeOfFreedom d = it->first;
-	  int matIndexLocal = localDofMap.getLocalMatIndex(i, d);
-	  int matIndexDual = dualDofMap.getLocalMatIndex(i, d);
+	  int matIndexLocal = localDofMap.getLocalMatIndex(meshLevel, i, d);
+	  int matIndexDual = dualDofMap.getLocalMatIndex(meshLevel, i, d);
 	  fetiDirichletPreconData.localToDualMap[matIndexLocal] = matIndexDual;
 	}
       }
@@ -777,18 +807,18 @@ namespace AMDiS {
       fetiLumpedPreconData.mat_duals_duals = &mat_duals_duals;
 
       for (unsigned int i = 0; i < feSpaces.size(); i++) {
-	DofMap &dualMap = dualDofMap[feSpaces[i]].getMap(0);
+	DofMap &dualMap = dualDofMap[feSpaces[i]].getMap(meshLevel);
 	for (DofMap::iterator it = dualMap.begin(); it != dualMap.end(); ++it) {
 	  DegreeOfFreedom d = it->first;
-	  int matIndexLocal = localDofMap.getLocalMatIndex(i, d);
-	  int matIndexDual = dualDofMap.getLocalMatIndex(i, d);
+	  int matIndexLocal = localDofMap.getLocalMatIndex(meshLevel, i, d);
+	  int matIndexDual = dualDofMap.getLocalMatIndex(meshLevel, i, d);
 	  fetiLumpedPreconData.localToDualMap[matIndexLocal] = matIndexDual;
 	}
       }
 
       VecCreateMPI(mpiComm, 
-		   localDofMap.getRankDofs(0),
-		   localDofMap.getOverallDofs(0),
+		   localDofMap.getRankDofs(meshLevel),
+		   localDofMap.getOverallDofs(meshLevel),
 		   &(fetiLumpedPreconData.tmp_vec_b));
       MatGetVecs(mat_duals_duals, PETSC_NULL, 
 		 &(fetiLumpedPreconData.tmp_vec_duals0));
@@ -876,20 +906,20 @@ namespace AMDiS {
     vector<const FiniteElemSpace*> feSpaces = getFeSpaces(&vec);
 
     vector<PetscInt> globalIsIndex, localIsIndex;
-    globalIsIndex.reserve(primalDofMap.getLocalDofs(0));
-    localIsIndex.reserve(primalDofMap.getLocalDofs(0));
+    globalIsIndex.reserve(primalDofMap.getLocalDofs(meshLevel));
+    localIsIndex.reserve(primalDofMap.getLocalDofs(meshLevel));
 
     {
       int cnt = 0;
       for (unsigned int i = 0; i < feSpaces.size(); i++) {
-	DofMap& dofMap = primalDofMap[feSpaces[i]].getMap(0);
+	DofMap& dofMap = primalDofMap[feSpaces[i]].getMap(meshLevel);
 	for (DofMap::iterator it = dofMap.begin();it != dofMap.end(); ++it) {
-	  globalIsIndex.push_back(primalDofMap.getMatIndex(i, it->first));
+	  globalIsIndex.push_back(primalDofMap.getMatIndex(meshLevel, i, it->first));
 	  localIsIndex.push_back(cnt++);
 	}
       }
       
-      TEST_EXIT_DBG(cnt == primalDofMap.getLocalDofs(0))
+      TEST_EXIT_DBG(cnt == primalDofMap.getLocalDofs(meshLevel))
 	("Should not happen!\n");
     }
     
@@ -929,14 +959,14 @@ namespace AMDiS {
     for (int i = 0; i < vec.getSize(); i++) {
       DOFVector<double>& dofVec = *(vec.getDOFVector(i));
 
-      for (DofMap::iterator it = localDofMap[feSpaces[i]].getMap(0).begin();
-	   it != localDofMap[feSpaces[i]].getMap(0).end(); ++it) {
-	int petscIndex = localDofMap.getLocalMatIndex(i, it->first);
+      for (DofMap::iterator it = localDofMap[feSpaces[i]].getMap(meshLevel).begin();
+	   it != localDofMap[feSpaces[i]].getMap(meshLevel).end(); ++it) {
+	int petscIndex = localDofMap.getLocalMatIndex(meshLevel, i, it->first);
 	dofVec[it->first] = localSolB[petscIndex];
       }
 
-      for (DofMap::iterator it = primalDofMap[feSpaces[i]].getMap(0).begin();
-	   it != primalDofMap[feSpaces[i]].getMap(0).end(); ++it)
+      for (DofMap::iterator it = primalDofMap[feSpaces[i]].getMap(meshLevel).begin();
+	   it != primalDofMap[feSpaces[i]].getMap(meshLevel).end(); ++it)
 	dofVec[it->first] = localSolPrimal[cnt++];
     }
 
@@ -960,25 +990,20 @@ namespace AMDiS {
     
     // === Create matrices for the FETI-DP method. ===
     
-    int nRowsRankB = localDofMap.getRankDofs(0);
-    int nRowsOverallB = localDofMap.getOverallDofs(0);
-    int nRowsRankPrimal = primalDofMap.getRankDofs(0);
-    int nRowsOverallPrimal = primalDofMap.getOverallDofs(0);
-    
     subDomainSolver->fillPetscMatrix(mat);
    
     
     // === Create matrices for FETI-DP preconditioner. ===
     
     if (fetiPreconditioner != FETI_NONE) {
-      int nRowsDual = dualDofMap.getRankDofs(0);
+      int nRowsDual = dualDofMap.getRankDofs(meshLevel);
 
       MatCreateSeqAIJ(PETSC_COMM_SELF,
 		      nRowsDual, nRowsDual, 60, PETSC_NULL,
 		      &mat_duals_duals);
 
       if (fetiPreconditioner == FETI_DIRICHLET) {
-	int nRowsInterior = interiorDofMap.getRankDofs(0);
+	int nRowsInterior = interiorDofMap.getRankDofs(meshLevel);
 
 	MatCreateSeqAIJ(PETSC_COMM_SELF,
 			nRowsInterior, nRowsInterior, 60, PETSC_NULL,
@@ -992,10 +1017,6 @@ namespace AMDiS {
 			nRowsDual, nRowsInterior, 60, PETSC_NULL,
 			&mat_duals_interior);
       }
-    }
-
-
-    if (fetiPreconditioner != FETI_NONE) {
     
       // === Prepare traverse of sequentially created matrices. ===
       
@@ -1047,21 +1068,21 @@ namespace AMDiS {
 	      if (!rowPrimal && !colPrimal) {
 		if (!isDual(feSpaces[i], *cursor)) {
 		  if (!isDual(feSpaces[j], col(*icursor))) {
-		    int colIndex = interiorDofMap.getLocalMatIndex(j, col(*icursor));
+		    int colIndex = interiorDofMap.getLocalMatIndex(meshLevel, j, col(*icursor));
 		    colsLocal.push_back(colIndex);
 		    valuesLocal.push_back(value(*icursor));
 		  } else {
-		    int colIndex = dualDofMap.getLocalMatIndex(j, col(*icursor));
+		    int colIndex = dualDofMap.getLocalMatIndex(meshLevel, j, col(*icursor));
 		    colsLocalOther.push_back(colIndex);
 		    valuesLocalOther.push_back(value(*icursor));
 		  }
 		} else {
 		  if (!isDual(feSpaces[j], col(*icursor))) {
-		    int colIndex = interiorDofMap.getLocalMatIndex(j, col(*icursor));
+		    int colIndex = interiorDofMap.getLocalMatIndex(meshLevel, j, col(*icursor));
 		    colsLocalOther.push_back(colIndex);
 		    valuesLocalOther.push_back(value(*icursor));
 		  } else {
-		    int colIndex = dualDofMap.getLocalMatIndex(j, col(*icursor));
+		    int colIndex = dualDofMap.getLocalMatIndex(meshLevel, j, col(*icursor));
 		    colsLocal.push_back(colIndex);
 		    valuesLocal.push_back(value(*icursor));
 		  }
@@ -1076,14 +1097,14 @@ namespace AMDiS {
 	      switch (fetiPreconditioner) {
 	      case FETI_DIRICHLET:
 		if (!isDual(feSpaces[i], *cursor)) {
-		  int rowIndex = interiorDofMap.getLocalMatIndex(i, *cursor);
+		  int rowIndex = interiorDofMap.getLocalMatIndex(meshLevel, i, *cursor);
 		  MatSetValues(mat_interior_interior, 1, &rowIndex, colsLocal.size(),
 			       &(colsLocal[0]), &(valuesLocal[0]), INSERT_VALUES);
 		  if (colsLocalOther.size()) 
 		    MatSetValues(mat_interior_duals, 1, &rowIndex, colsLocalOther.size(),
 				 &(colsLocalOther[0]), &(valuesLocalOther[0]), INSERT_VALUES);
 		} else {
-		  int rowIndex = dualDofMap.getLocalMatIndex(i, *cursor);
+		  int rowIndex = dualDofMap.getLocalMatIndex(meshLevel, i, *cursor);
 		  MatSetValues(mat_duals_duals, 1, &rowIndex, colsLocal.size(),
 			       &(colsLocal[0]), &(valuesLocal[0]), INSERT_VALUES);  
 		  if (colsLocalOther.size()) 
@@ -1094,7 +1115,7 @@ namespace AMDiS {
 
 	      case FETI_LUMPED:
 		if (isDual(feSpaces[i], *cursor)) {
-		  int rowIndex = dualDofMap.getLocalMatIndex(i, *cursor);		
+		  int rowIndex = dualDofMap.getLocalMatIndex(meshLevel, i, *cursor);		
 		  MatSetValues(mat_duals_duals, 1, &rowIndex, colsLocal.size(),
 			       &(colsLocal[0]), &(valuesLocal[0]), INSERT_VALUES);
 		}			
@@ -1171,13 +1192,17 @@ namespace AMDiS {
     Vec tmp_b0, tmp_b1, tmp_lagrange0, tmp_primal0, tmp_primal1;
 
     VecCreateMPI(mpiComm, 
-		 localDofMap.getRankDofs(0), localDofMap.getOverallDofs(0), &tmp_b0);
+		 localDofMap.getRankDofs(meshLevel), 
+		 localDofMap.getOverallDofs(meshLevel), &tmp_b0);
     VecCreateMPI(mpiComm, 
-		 localDofMap.getRankDofs(0), localDofMap.getOverallDofs(0), &tmp_b1);
+		 localDofMap.getRankDofs(meshLevel), 
+		 localDofMap.getOverallDofs(meshLevel), &tmp_b1);
     VecCreateMPI(mpiComm,
-		 primalDofMap.getRankDofs(0), primalDofMap.getOverallDofs(0), &tmp_primal0);
+		 primalDofMap.getRankDofs(meshLevel), 
+		 primalDofMap.getOverallDofs(meshLevel), &tmp_primal0);
     VecCreateMPI(mpiComm,
-		 primalDofMap.getRankDofs(0), primalDofMap.getOverallDofs(0), &tmp_primal1);
+		 primalDofMap.getRankDofs(meshLevel), 
+		 primalDofMap.getOverallDofs(meshLevel), &tmp_primal1);
 
     MatGetVecs(mat_lagrange, PETSC_NULL, &tmp_lagrange0);
     MatGetVecs(mat_lagrange, PETSC_NULL, &vec_rhs);
diff --git a/AMDiS/src/parallel/PetscSolverFeti.h b/AMDiS/src/parallel/PetscSolverFeti.h
index e640e7d699e145f04e3e624cfc168500d1fb15f1..e1dfc73121f82296fdee7560fe25846006ea2d02 100644
--- a/AMDiS/src/parallel/PetscSolverFeti.h
+++ b/AMDiS/src/parallel/PetscSolverFeti.h
@@ -171,15 +171,17 @@ namespace AMDiS {
     void printStatistics();
 
     /// Checks whether a given DOF in a given FE space is a primal DOF.
-    inline bool isPrimal(const FiniteElemSpace *feSpace, DegreeOfFreedom dof)
+    inline bool isPrimal(const FiniteElemSpace *feSpace, 
+			 DegreeOfFreedom dof)
     {
-      return primalDofMap[feSpace].isSet(dof);
+      return primalDofMap[feSpace].isSet(dof, meshLevel);
     }
 
     /// Checks whether a given DOF in a give FE space is a dual DOF.
-    inline bool isDual(const FiniteElemSpace *feSpace, DegreeOfFreedom dof)
+    inline bool isDual(const FiniteElemSpace *feSpace, 
+		       DegreeOfFreedom dof)
     {
-      return dualDofMap[feSpace].isSet(dof);
+      return dualDofMap[feSpace].isSet(dof, meshLevel);
     }
 
   protected:
diff --git a/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc b/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc
index 74026bb680381414deb4baa8f4fbea734fcb50b8..5a74eaae43d972d2f5cc4d9d1a1f58ac13c46618 100644
--- a/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc
+++ b/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc
@@ -232,7 +232,7 @@ namespace AMDiS {
 	   cend = end<row>(mat->getBaseMatrix()); cursor != cend; ++cursor) {
 
       // Global index of the current row DOF.
-      int rowIndex = (*dofMap)[feSpace][*cursor].global + dispRowIndex;
+      int rowIndex = (*dofMap)[feSpace][0][*cursor].global + dispRowIndex;
 
       cols.clear();
       values.clear();
@@ -240,7 +240,7 @@ namespace AMDiS {
       for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); 
 	   icursor != icend; ++icursor) {	
 	// Global index of the current column index.
-	int colIndex = (*dofMap)[feSpace][col(*icursor)].global + dispColIndex;
+	int colIndex = (*dofMap)[feSpace][0][col(*icursor)].global + dispColIndex;
 	
 	// Ignore all zero entries, expect it is a diagonal entry.
 	if (value(*icursor) == 0.0 && rowIndex != colIndex)
@@ -267,7 +267,7 @@ namespace AMDiS {
     // Traverse all used DOFs in the dof vector.
     DOFVector<double>::Iterator dofIt(vec, USED_DOFS);
     for (dofIt.reset(); !dofIt.end(); ++dofIt) {
-      int index = (*dofMap)[feSpace][dofIt.getDOFIndex()].global;
+      int index = (*dofMap)[feSpace][0][dofIt.getDOFIndex()].global;
       double value = *dofIt;
 
       VecSetValues(petscVec, 1, &index, &value, ADD_VALUES);
diff --git a/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc b/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc
index 58eaaa653174c32ee183d057b110b7623aa48979..f1dafc82d61dc239522763eca8d25398eae08396 100644
--- a/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc
+++ b/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc
@@ -268,7 +268,7 @@ namespace AMDiS {
       const FiniteElemSpace *colFe = mat->getColFeSpace();
 
       // Global index of the current row DOF.
-      int globalRowDof = (*dofMap)[rowFe][*cursor].global;
+      int globalRowDof = (*dofMap)[rowFe][0][*cursor].global;
 
       // Test if the current row DOF is a periodic DOF.
       bool periodicRow = perMap.isPeriodic(rowFe, globalRowDof);
@@ -277,7 +277,7 @@ namespace AMDiS {
 	// === Row DOF index is not periodic. ===
 
 	// Get PETSc's mat row index.
-	int rowIndex = dofMap->getMatIndex(nRowMat, globalRowDof);
+	int rowIndex = dofMap->getMatIndex(0, nRowMat, globalRowDof);
 
 	cols.clear();
 	values.clear();
@@ -286,11 +286,11 @@ namespace AMDiS {
 	     icursor != icend; ++icursor) {
 
 	  // Global index of the current column index.
-	  int globalColDof = (*dofMap)[colFe][col(*icursor)].global;
+	  int globalColDof = (*dofMap)[colFe][0][col(*icursor)].global;
 	  // Test if the current col dof is a periodic dof.
 	  bool periodicCol = perMap.isPeriodic(colFe, globalColDof);
 	  // Get PETSc's mat col index.
-	  int colIndex = dofMap->getMatIndex(nColMat, globalColDof);
+	  int colIndex = dofMap->getMatIndex(0, nColMat, globalColDof);
 
 	  // Ignore all zero entries, expect it is a diagonal entry.
  	  if (value(*icursor) == 0.0 && rowIndex != colIndex)
@@ -339,7 +339,7 @@ namespace AMDiS {
 	    }
 
 	    for (unsigned int i = 0; i < newCols.size(); i++) {
-	      cols.push_back(dofMap->getMatIndex(nColMat, newCols[i]));
+	      cols.push_back(dofMap->getMatIndex(0, nColMat, newCols[i]));
 	      values.push_back(scaledValue);	      
 	    }
 	  }
@@ -361,7 +361,7 @@ namespace AMDiS {
 	for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); 
 	     icursor != icend; ++icursor) {
 	  // Global index of the current column index.
-	  int globalColDof = (*dofMap)[colFe][col(*icursor)].global;
+	  int globalColDof = (*dofMap)[colFe][0][col(*icursor)].global;
 
 	  // Ignore all zero entries, expect it is a diagonal entry.
  	  if (value(*icursor) == 0.0 && globalRowDof != globalColDof)
@@ -426,8 +426,8 @@ namespace AMDiS {
 	  // === Translate the matrix entries to PETSc's matrix.
 
 	  for (unsigned int i = 0; i < entry.size(); i++) {
-	    int rowIdx = dofMap->getMatIndex(nRowMat, entry[i].first);
-	    int colIdx = dofMap->getMatIndex(nColMat, entry[i].second);
+	    int rowIdx = dofMap->getMatIndex(0, nRowMat, entry[i].first);
+	    int colIdx = dofMap->getMatIndex(0, nColMat, entry[i].second);
 
 	    colsMap[rowIdx].push_back(colIdx);
 	    valsMap[rowIdx].push_back(scaledValue);
@@ -465,14 +465,14 @@ namespace AMDiS {
     // Traverse all used DOFs in the dof vector.
     DOFVector<double>::Iterator dofIt(vec, USED_DOFS);
     for (dofIt.reset(); !dofIt.end(); ++dofIt) {
-      if (rankOnly && !(*dofMap)[feSpace].isRankDof(dofIt.getDOFIndex()))
+      if (rankOnly && !(*dofMap)[feSpace].isRankDof(dofIt.getDOFIndex(), 0))
 	continue;
 
       // Calculate global row index of the DOF.
       DegreeOfFreedom globalRowDof = 
-	(*dofMap)[feSpace][dofIt.getDOFIndex()].global;
+	(*dofMap)[feSpace][0][dofIt.getDOFIndex()].global;
       // Get PETSc's mat index of the row DOF.
-      int index = dofMap->getMatIndex(nRowVec, globalRowDof);
+      int index = dofMap->getMatIndex(0, nRowVec, globalRowDof);
 
       if (perMap.isPeriodic(feSpace, globalRowDof)) {
 	std::set<int>& perAsc = perMap.getAssociations(feSpace, globalRowDof);
@@ -482,7 +482,7 @@ namespace AMDiS {
 	for (std::set<int>::iterator perIt = perAsc.begin(); 
 	     perIt != perAsc.end(); ++perIt) {
 	  int mappedDof = perMap.map(feSpace, *perIt, globalRowDof);
-	  int mappedIndex = dofMap->getMatIndex(nRowVec, mappedDof);
+	  int mappedIndex = dofMap->getMatIndex(0, nRowVec, mappedDof);
 	  VecSetValues(petscVec, 1, &mappedIndex, &value, ADD_VALUES);
 	}
       } else {
@@ -572,11 +572,11 @@ namespace AMDiS {
 	
 	for (cursor_type cursor = begin<row>(bmat), 
 	       cend = end<row>(bmat); cursor != cend; ++cursor) {
-	  int globalRowDof = (*dofMap)[feSpaces[i]][*cursor].global;
+	  int globalRowDof = (*dofMap)[feSpaces[i]][0][*cursor].global;
 
 	  // The corresponding global matrix row index of the current row DOF.
-	  int petscRowIdx = dofMap->getMatIndex(i, globalRowDof);
-	  if ((*dofMap)[feSpaces[i]].isRankDof(*cursor)) {
+	  int petscRowIdx = dofMap->getMatIndex(0, i, globalRowDof);
+	  if ((*dofMap)[feSpaces[i]].isRankDof(*cursor, 0)) {
     	    
 	    // === The current row DOF is a rank DOF, so create the       ===
 	    // === corresponding nnz values directly on rank's nnz data.  ===
@@ -587,7 +587,7 @@ namespace AMDiS {
 	    TEST_EXIT_DBG(localPetscRowIdx >= 0 && localPetscRowIdx < nRankRows)
 	      ("Should not happen! \n Debug info: localRowIdx = %d   globalRowIndx = %d   petscRowIdx = %d   localPetscRowIdx = %d   rStart = %d   nCompontens = %d   nRankRows = %d\n",
 	       *cursor,
-	       (*dofMap)[feSpaces[i]][*cursor].global,
+	       (*dofMap)[feSpaces[i]][0][*cursor].global,
 	       petscRowIdx, 
 	       localPetscRowIdx, 
 	       rankStartIndex,
@@ -598,8 +598,8 @@ namespace AMDiS {
 	    // Traverse all non zero entries in this row.
 	    for (icursor_type icursor = begin<nz>(cursor), 
 		   icend = end<nz>(cursor); icursor != icend; ++icursor) {
-	      int globalColDof = (*dofMap)[feSpaces[j]][col(*icursor)].global;
-	      int petscColIdx = dofMap->getMatIndex(j, globalColDof);
+	      int globalColDof = (*dofMap)[feSpaces[j]][0][col(*icursor)].global;
+	      int petscColIdx = dofMap->getMatIndex(0, j, globalColDof);
 	      
 	      if (value(*icursor) != 0.0 || petscRowIdx == petscColIdx) {
 		// The row DOF is a rank DOF, if also the column is a rank DOF, 
@@ -626,8 +626,8 @@ namespace AMDiS {
 		   icend = end<nz>(cursor); icursor != icend; ++icursor) {
 	      if (value(*icursor) != 0.0) {
 		int globalColDof = 
-		  (*dofMap)[feSpaces[j]][col(*icursor)].global;
-		int petscColIdx = dofMap->getMatIndex(j, globalColDof);
+		  (*dofMap)[feSpaces[j]][0][col(*icursor)].global;
+		int petscColIdx = dofMap->getMatIndex(0, j, globalColDof);
 		
 		sendMatrixEntry[sendToRank].
 		  push_back(make_pair(petscRowIdx, petscColIdx));
diff --git a/AMDiS/src/parallel/PetscSolverSchur.cc b/AMDiS/src/parallel/PetscSolverSchur.cc
index 1ef550dd72929d38ad5e3848c25dbc47f403f91c..38813de583e526909a9eabb60fbfe753b1f3e493 100644
--- a/AMDiS/src/parallel/PetscSolverSchur.cc
+++ b/AMDiS/src/parallel/PetscSolverSchur.cc
@@ -35,7 +35,7 @@ namespace AMDiS {
 	 !it.end(); it.nextRank())
       for (; !it.endDofIter(); it.nextDof()) {
 	boundaryLocalDofs.insert(it.getDofIndex());	  
-	boundaryDofs.insert((*dofMap)[feSpace][it.getDofIndex()].global);
+	boundaryDofs.insert((*dofMap)[feSpace][0][it.getDofIndex()].global);
       }
 
       
@@ -45,9 +45,9 @@ namespace AMDiS {
 
 
     DofContainerSet& edgeDofs = 
-      meshDistributor->getBoundaryDofInfo(feSpace).geoDofs[EDGE];
+      meshDistributor->getBoundaryDofInfo(feSpace, 0).geoDofs[EDGE];
     DofContainerSet& vertexDofs = 
-      meshDistributor->getBoundaryDofInfo(feSpace).geoDofs[VERTEX];
+      meshDistributor->getBoundaryDofInfo(feSpace, 0).geoDofs[VERTEX];
     int nEdgeDofs = edgeDofs.size();
     int nVertexDofs = vertexDofs.size();
 
@@ -72,14 +72,14 @@ namespace AMDiS {
       int counter = rStartEdgeDofs;
       for (DofContainerSet::iterator it = edgeDofs.begin();
 	   it != edgeDofs.end(); ++it)
-	mapGlobalBoundaryDof[(*dofMap)[feSpace][**it].global] = 
+	mapGlobalBoundaryDof[(*dofMap)[feSpace][0][**it].global] = 
 	  counter++;
     }
     {
       int counter = nOverallEdgeDofs + rStartVertexDofs;
       for (DofContainerSet::iterator it = vertexDofs.begin();
 	   it != vertexDofs.end(); ++it)
-	mapGlobalBoundaryDof[(*dofMap)[feSpace][**it].global] = 
+	mapGlobalBoundaryDof[(*dofMap)[feSpace][0][**it].global] = 
 	  counter++;
     }
 #else
@@ -135,7 +135,7 @@ namespace AMDiS {
       stdMpi.getSendData(it.getRank()).reserve(it.getDofs().size());
 
       for (; !it.endDofIter(); it.nextDof()) {
-	int globalSendDof = (*dofMap)[feSpace][it.getDofIndex()].global;
+	int globalSendDof = (*dofMap)[feSpace][0][it.getDofIndex()].global;
 
 	TEST_EXIT_DBG(mapGlobalBoundaryDof.count(globalSendDof))
 	  ("No mapping for boundary DOF %d!\n", globalSendDof);
@@ -155,7 +155,7 @@ namespace AMDiS {
     for (DofComm::Iterator it(meshDistributor->getRecvDofs(), feSpace);
 	 !it.end(); it.nextRank())
       for (; !it.endDofIter(); it.nextDof()) {
-	int globalRecvDof = (*dofMap)[feSpace][it.getDofIndex()].global;
+	int globalRecvDof = (*dofMap)[feSpace][0][it.getDofIndex()].global;
 	mapGlobalBoundaryDof[globalRecvDof] = 
 	  stdMpi.getRecvData(it.getRank())[it.getDofCounter()];
 	boundaryDofs.insert(globalRecvDof);
@@ -302,7 +302,7 @@ namespace AMDiS {
     for (int i = 0; i < nComponents; i++) {
       DOFVector<double>::Iterator dofIt(vec.getDOFVector(i), USED_DOFS);
       for (dofIt.reset(); !dofIt.end(); ++dofIt) {
-	DegreeOfFreedom globalRowDof = (*dofMap)[feSpace][dofIt.getDOFIndex()].global;
+	DegreeOfFreedom globalRowDof = (*dofMap)[feSpace][0][dofIt.getDOFIndex()].global;
 	if (boundaryDofs.count(globalRowDof)) {
 	  int index =
 	    (mapGlobalBoundaryDof[globalRowDof] - rStartBoundaryDofs + nInteriorDofs) * (i + 1);
@@ -373,7 +373,7 @@ namespace AMDiS {
 	   cend = end<row>(mat->getBaseMatrix()); cursor != cend; ++cursor) {
 
       // Global index of the current row DOF.
-      int globalRowDof = (*dofMap)[feSpace][*cursor].global;
+      int globalRowDof = (*dofMap)[feSpace][0][*cursor].global;
      
       colsBoundary.clear();
       colsInterior.clear();
@@ -382,7 +382,7 @@ namespace AMDiS {
       
       for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); 
 	   icursor != icend; ++icursor) {
-	int globalColDof = (*dofMap)[feSpace][col(*icursor)].global;
+	int globalColDof = (*dofMap)[feSpace][0][col(*icursor)].global;
 
 	if (boundaryDofs.count(globalColDof)) {
 	  TEST_EXIT_DBG(mapGlobalBoundaryDof.count(globalColDof))
@@ -441,12 +441,12 @@ namespace AMDiS {
 
     DOFVector<double>::Iterator dofIt(vec, USED_DOFS);
     for (dofIt.reset(); !dofIt.end(); ++dofIt) {
-      if (rankOnly && !(*dofMap)[feSpace].isRankDof(dofIt.getDOFIndex()))
+      if (rankOnly && !(*dofMap)[feSpace].isRankDof(dofIt.getDOFIndex(), 0))
 	continue;
 
       // Calculate global row index of the DOF.
       DegreeOfFreedom globalRowDof = 
-	(*dofMap)[feSpace][dofIt.getDOFIndex()].global;
+	(*dofMap)[feSpace][0][dofIt.getDOFIndex()].global;
       double value = *dofIt;
 
       if (boundaryDofs.count(globalRowDof)) {
diff --git a/AMDiS/src/parallel/SubDomainSolver.cc b/AMDiS/src/parallel/SubDomainSolver.cc
index c9fa411a379773e801b8be2f3d2ca5dc5abfb04f..9d0f7a879b3a8a87f19ebbc518b3208d3c021382 100644
--- a/AMDiS/src/parallel/SubDomainSolver.cc
+++ b/AMDiS/src/parallel/SubDomainSolver.cc
@@ -29,6 +29,10 @@ namespace AMDiS {
     int nRowsRankCoarse = coarseSpaceMap->getRankDofs(level);
     int nRowsOverallCoarse = coarseSpaceMap->getOverallDofs(level);
 
+    MSG("FILL MATRIX IN MPI COMM WITH SIZES %d %d\n",
+	mpiCommInterior.Get_size(),
+	mpiCommCoarseSpace.Get_size());
+
     if (mpiCommInterior.Get_size() == 1) {
       MatCreateSeqAIJ(mpiCommInterior, nRowsRankInterior, nRowsRankInterior,
 		      60, PETSC_NULL, &matIntInt);
@@ -122,33 +126,33 @@ namespace AMDiS {
 	  // === Set matrix values. ===
 
 	  if (rowPrimal) {
-	    int rowIndex = coarseSpaceMap->getMatIndex(i, *cursor);
+	    int rowIndex = coarseSpaceMap->getMatIndex(level, i, *cursor);
 	    for (unsigned int k = 0; k < cols.size(); k++)
-	      cols[k] = coarseSpaceMap->getMatIndex(j, cols[k]);
+	      cols[k] = coarseSpaceMap->getMatIndex(level, j, cols[k]);
 
 	    MatSetValues(matCoarseCoarse, 1, &rowIndex, cols.size(),
 			 &(cols[0]), &(values[0]), ADD_VALUES);
 
 	    if (colsOther.size()) {
 	      for (unsigned int k = 0; k < colsOther.size(); k++)
-		colsOther[k] = interiorMap->getMatIndex(j, colsOther[k]);
+		colsOther[k] = interiorMap->getMatIndex(level, j, colsOther[k]);
  	      
 	      MatSetValues(matCoarseInt, 1, &rowIndex, colsOther.size(),
  			   &(colsOther[0]), &(valuesOther[0]), ADD_VALUES);
 	    }
 	  } else {
-	    int localRowIndex = interiorMap->getLocalMatIndex(i, *cursor);
+	    int localRowIndex = interiorMap->getLocalMatIndex(level, i, *cursor);
 
 	    for (unsigned int k = 0; k < cols.size(); k++)
-	      cols[k] = interiorMap->getLocalMatIndex(j, cols[k]);
+	      cols[k] = interiorMap->getLocalMatIndex(level, j, cols[k]);
 	    
   	    MatSetValues(matIntInt, 1, &localRowIndex, cols.size(),
   			 &(cols[0]), &(values[0]), ADD_VALUES);
 
 	    if (colsOther.size()) {
-	      int globalRowIndex = interiorMap->getMatIndex(i, *cursor);
+	      int globalRowIndex = interiorMap->getMatIndex(level, i, *cursor);
 	      for (unsigned int k = 0; k < colsOther.size(); k++)
-		colsOther[k] = coarseSpaceMap->getMatIndex(j, colsOther[k]);
+		colsOther[k] = coarseSpaceMap->getMatIndex(level, j, colsOther[k]);
 
   	      MatSetValues(matIntCoarse, 1, &globalRowIndex, colsOther.size(),
   			   &(colsOther[0]), &(valuesOther[0]), ADD_VALUES);
@@ -207,10 +211,10 @@ namespace AMDiS {
       for (dofIt.reset(); !dofIt.end(); ++dofIt) {
 	int index = dofIt.getDOFIndex();
 	if (isCoarseSpace(feSpace, index)) {
-	  index = coarseSpaceMap->getMatIndex(i, index);
+	  index = coarseSpaceMap->getMatIndex(level, i, index);
 	  VecSetValue(rhsCoarseSpace, index, *dofIt, ADD_VALUES);
 	} else {
-	  index = interiorMap->getMatIndex(i, index);
+	  index = interiorMap->getMatIndex(level, i, index);
 	  VecSetValue(rhsInterior, index, *dofIt, INSERT_VALUES);
 	}      
       }
diff --git a/AMDiS/src/parallel/SubDomainSolver.h b/AMDiS/src/parallel/SubDomainSolver.h
index 52df9910a23d505b2349f687fa1450b17a3a4fa1..3e9eb8258ff7a10b8d01a381484e74f7c356307b 100644
--- a/AMDiS/src/parallel/SubDomainSolver.h
+++ b/AMDiS/src/parallel/SubDomainSolver.h
@@ -73,9 +73,10 @@ namespace AMDiS {
 
     void solveGlobal(Vec &rhs, Vec &sol);
 
-    inline bool isCoarseSpace(const FiniteElemSpace *feSpace, DegreeOfFreedom dof)
+    inline bool isCoarseSpace(const FiniteElemSpace *feSpace, 
+			      DegreeOfFreedom dof)
     {
-      return (*coarseSpaceMap)[feSpace].isSet(dof);
+      return (*coarseSpaceMap)[feSpace].isSet(dof, level);
     }
 
     inline Vec& getRhsCoarseSpace()