diff --git a/AMDiS/CMakeLists.txt b/AMDiS/CMakeLists.txt
index 971e990c48dd39670478afae58ae88f26b9f3953..4c77ee6a2e57fbe6a6582a4f70871b3706020207 100644
--- a/AMDiS/CMakeLists.txt
+++ b/AMDiS/CMakeLists.txt
@@ -162,6 +162,7 @@ SET(AMDIS_SRC ${SOURCE_DIR}/AdaptBase.cc
 	      ${SOURCE_DIR}/io/PngReader.cc
 	      ${SOURCE_DIR}/io/PngWriter.cc
 	      ${SOURCE_DIR}/io/PovrayWriter.cc
+	      ${SOURCE_DIR}/io/Spreadsheet.cc
 	      ${SOURCE_DIR}/io/ValueReader.cc
 	      ${SOURCE_DIR}/io/ValueWriter.cc
 	      ${SOURCE_DIR}/io/VtkWriter.cc
diff --git a/AMDiS/src/AMDiS.h b/AMDiS/src/AMDiS.h
index dc878e1d8f5786a0ce08a25d9ba9390743a19575..2df55bcdca8dd2f8fb20d8f163f62c73a0b51305 100644
--- a/AMDiS/src/AMDiS.h
+++ b/AMDiS/src/AMDiS.h
@@ -122,6 +122,7 @@
 #include "io/MacroWriter.h"
 #include "io/PngWriter.h"
 #include "io/PovrayWriter.h"
+#include "io/Spreadsheet.h"
 #include "io/ValueReader.h"
 #include "io/ValueWriter.h"
 #include "io/VtkWriter.h"
diff --git a/AMDiS/src/io/DofWriter.cc b/AMDiS/src/io/DofWriter.cc
index 788165cde1b218fd32bb5ffa8dc5e53218edfb6e..02b6593734960314b761d9524e18bffb5b8741e7 100644
--- a/AMDiS/src/io/DofWriter.cc
+++ b/AMDiS/src/io/DofWriter.cc
@@ -16,7 +16,9 @@
 
 namespace AMDiS {
 
-  void DofWriter::writeFile(std::string filename, std::vector<DOFVector<double>*> &vec)
+  using namespace std;
+
+  void DofWriter::writeFile(string filename, vector<DOFVector<double>*> &vec)
   {
     FUNCNAME("DofWriter::writeFile()");
 
@@ -25,13 +27,14 @@ namespace AMDiS {
     Mesh *mesh = feSpace->getMesh();
     const BasisFunction* basFcts = feSpace->getBasisFcts();
     int nBasFcts = basFcts->getNumber();
-    std::vector<DegreeOfFreedom> dofVec(nBasFcts);
+    vector<DegreeOfFreedom> dofVec(nBasFcts);
     
     TraverseStack stack;
     ElInfo *elInfo = 
       stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS);
     while (elInfo) {
-      basFcts->getLocalIndices(elInfo->getElement(), feSpace->getAdmin(), dofVec);
+      basFcts->getLocalIndices(elInfo->getElement(), 
+			       feSpace->getAdmin(), dofVec);
       for (int i = 0; i < nBasFcts; i++) {
 	DimVec<double> *baryCoords = basFcts->getCoords(i);
 	elInfo->coordToWorld(*baryCoords, coordDof[dofVec[i]]);
@@ -40,7 +43,7 @@ namespace AMDiS {
       elInfo = stack.traverseNext(elInfo);
     }   
     
-    std::ofstream outfile;
+    ofstream outfile;
     outfile.open(filename.c_str());
     outfile.precision(10);
     
@@ -53,7 +56,7 @@ namespace AMDiS {
       
       for (unsigned int i = 0; i < vec.size(); i++) 
 	outfile << (*(vec[i]))[it.getDOFIndex()] << " ";
-      outfile << std::endl;
+      outfile << endl;
     }   
     
     outfile.close();
diff --git a/AMDiS/src/io/Spreadsheet.cc b/AMDiS/src/io/Spreadsheet.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5cb39df11ceebf3a60061c0b99107a179b80c1f7
--- /dev/null
+++ b/AMDiS/src/io/Spreadsheet.cc
@@ -0,0 +1,88 @@
+//
+// Software License for AMDiS
+//
+// Copyright (c) 2010 Dresden University of Technology 
+// All rights reserved.
+// Authors: Simon Vey, Thomas Witkowski et al.
+//
+// This file is part of AMDiS
+//
+// See also license.opensource.txt in the distribution.
+
+
+#include <algorithm>
+#include <fstream>
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+#include "Spreadsheet.h"
+#include "Global.h"
+
+namespace AMDiS {
+  
+  using namespace std;
+  using namespace boost;
+
+  using boost::lexical_cast;
+  
+  void Spreadsheet::write(string filename)
+  {
+    int nRows = static_cast<int>(data.size());
+    int maxDataLength = 0;
+    
+    for (int i = 0; i < nRows; i++)
+      maxDataLength = std::max(maxDataLength, static_cast<int>(data[i].size()));
+
+    for (int i = 0; i < nRows; i++)
+      data[i].resize(maxDataLength, 0.0);
+
+    ofstream file;
+    file.open(filename.c_str());
+
+    for (int i = 0; i < nRows; i++) {
+      for (int j = 0; j < maxDataLength; j++) {
+	file << data[i][j];
+	if (j + 1 < maxDataLength)
+	  file << " ";
+	else 
+	  file << "\n";
+      }
+    }
+
+    file.close();
+  }
+
+
+  void Spreadsheet::read(string filename)
+  {
+    data.clear();
+
+    string line;
+    vector<string> lineSplit;
+
+    ifstream file;
+    file.open(filename.c_str());
+
+    while (!file.eof()) {
+      getline(file, line);
+      split(lineSplit, line, is_any_of(" ,"));
+
+      if (lineSplit.size() == 0)
+	continue;
+
+      if ((lineSplit.size() == 1) && (lineSplit[0] == ""))
+	continue;
+
+      if (lineSplit[0].find("#") == 0)
+	continue;
+
+      vector<double> lineData(lineSplit.size());
+      for (unsigned int i = 0; i < lineSplit.size(); i++)
+	lineData[i] = lexical_cast<double>(lineSplit[i]);
+
+      data.push_back(lineData);
+    }
+
+    file.close();
+  }
+
+}
diff --git a/AMDiS/src/io/Spreadsheet.h b/AMDiS/src/io/Spreadsheet.h
new file mode 100644
index 0000000000000000000000000000000000000000..795c6bd9a8059d87ed9c9c76d14c836015a5507d
--- /dev/null
+++ b/AMDiS/src/io/Spreadsheet.h
@@ -0,0 +1,77 @@
+// ============================================================================
+// ==                                                                        ==
+// == Amdis - Adaptive multidimensional simulations                          ==
+// ==                                                                        ==
+// ==  http://www.amdis-fem.org                                              ==
+// ==                                                                        ==
+// ============================================================================
+//
+// Software License for AMDiS
+//
+// Copyright (c) 2010 Dresden University of Technology 
+// All rights reserved.
+// Authors: Simon Vey, Thomas Witkowski et al.
+//
+// This file is part of AMDiS
+//
+// See also license.opensource.txt in the distribution.
+
+
+
+/** \file Spreadsheet.h */
+
+#ifndef AMDIS_SPREADSHEET_H
+#define AMDIS_SPREADSHEET_H
+
+#include <vector>
+#include <string>
+
+namespace AMDiS {
+
+  using namespace std;
+
+  /** 
+   * \brief 
+   * Implements basic support to read and write tables of data (all are 
+   * assumed to be of type double. The files are written in ASCII mode and
+   * allow to use comments (lines that start with #).
+   */
+  class Spreadsheet
+  {
+  public:
+    typedef vector<vector<double> > DataType;
+
+    Spreadsheet()
+      : data(0)
+    {}
+
+    void addData(vector<double> &d)
+    {
+      data.push_back(d);
+    }
+
+    void addData(DataType &d)
+    {
+      data.insert(data.end(), d.begin(), d.end());
+    }
+
+    void setData(DataType &d)
+    {
+      data = d;
+    }
+
+    DataType& getData()
+    {
+      return data;
+    }
+
+    void write(string filename);
+
+    void read(string filename);
+
+  protected:
+    DataType data;
+  };
+}
+
+#endif
diff --git a/AMDiS/src/parallel/MeshDistributor.h b/AMDiS/src/parallel/MeshDistributor.h
index 29be59ba6d154a4cdf3a52a108974e4a4ccc1a90..27be4794c97d38598f0716d9f9711e896ef96d20 100644
--- a/AMDiS/src/parallel/MeshDistributor.h
+++ b/AMDiS/src/parallel/MeshDistributor.h
@@ -168,26 +168,11 @@ namespace AMDiS {
       return feSpaces;
     }
 
-    /** \brief
-     * Returns the number of DOFs in rank's domain for a given FE space.
-     *
-     * \param[in]  feSpace  If the FE space is defined, the function returns
-     *                      the number of DOFs for this FE space. If this
-     *                      parameter is not specified, the function assumes
-     *                      that there is only one FE space and returns the
-     *                      number of DOFs for this one.
-     */
-    inline int getNumberRankDofs(const FiniteElemSpace *feSpace = NULL) 
+    /// Returns the number of DOFs in rank's domain for a given FE space.
+    inline int getNumberRankDofs(const FiniteElemSpace *feSpace) 
     {
       FUNCNAME("MeshDistributor::getNumberRankDofs()");
 
-      if (feSpace == NULL) {
-	TEST_EXIT_DBG(dofFeData.size() == 1)
-	  ("More than one FE space defined!\n");
-
-	return dofFeData.begin()->second.nRankDofs;
-      }
-
       TEST_EXIT_DBG(dofFeData.count(feSpace))("Should not happen!\n");
 
       return dofFeData[feSpace].nRankDofs;
@@ -232,26 +217,11 @@ namespace AMDiS {
       return result;
     }
 
-    /** \brief
-     * Returns the global number of DOFs for a given FE space.
-     *
-     * \param[in]  feSpace  If the FE space is defined, the function returns
-     *                      the number of DOFs for this FE space. If this
-     *                      parameter is not specified, the function assumes
-     *                      that there is only one FE space and returns the
-     *                      number of DOFs for this one.
-     */
-    inline int getNumberOverallDofs(const FiniteElemSpace *feSpace = NULL)
+    ///  Returns the global number of DOFs for a given FE space.
+    inline int getNumberOverallDofs(const FiniteElemSpace *feSpace)
     {
       FUNCNAME("MeshDistributor::getNumberOverallDofs()");
 
-      if (feSpace == NULL) {
-	TEST_EXIT_DBG(dofFeData.size() == 1)
-	  ("More than one FE space defined!\n");
-
-	return dofFeData.begin()->second.nOverallDofs;
-      }
-
       TEST_EXIT_DBG(dofFeData.count(feSpace))("Should not happen!\n");
 
       return dofFeData[feSpace].nOverallDofs;
diff --git a/AMDiS/src/parallel/PetscSolverFeti.cc b/AMDiS/src/parallel/PetscSolverFeti.cc
index 6918f7c5dc64ace0c7d0e791dd660875ca5eb1cf..e0ab38be8ab1c088b39391ce79383c8081cceece 100644
--- a/AMDiS/src/parallel/PetscSolverFeti.cc
+++ b/AMDiS/src/parallel/PetscSolverFeti.cc
@@ -228,8 +228,19 @@ namespace AMDiS {
     TEST_EXIT_DBG(meshLevel + 1 == meshDistributor->getMeshLevelData().getLevelNumber())
       ("Mesh hierarchy does not contain %d levels!\n", meshLevel + 1);
 
-    if (subDomainSolver == NULL)
-      subDomainSolver = new SubDomainSolver(meshDistributor, mpiComm, mpiSelfComm);
+    if (subDomainSolver == NULL) {
+      if (meshLevel == 0) {
+	subDomainSolver = 
+	  new SubDomainSolver(meshDistributor, mpiComm, mpiSelfComm);
+      } else {
+	MeshLevelData& levelData = meshDistributor->getMeshLevelData();
+
+	subDomainSolver = 
+	  new SubDomainSolver(meshDistributor, 
+			      levelData.getMpiComm(meshLevel - 1),
+			      levelData.getMpiComm(meshLevel));
+      }
+    }
 
     primalDofMap.init(mpiComm, feSpaces, meshDistributor->getFeSpaces(), 
 		      true, true);
@@ -375,10 +386,8 @@ namespace AMDiS {
     for (DofComm::Iterator it(meshDistributor->getSendDofs(), meshLevel, feSpace);
 	 !it.end(); it.nextRank())
       for (; !it.endDofIter(); it.nextDof())
-	if (!isPrimal(feSpace, it.getDofIndex())) {
-	  MSG("SEND TO RANK %d\n", it.getRank());
+	if (!isPrimal(feSpace, it.getDofIndex()))
 	  stdMpi.getSendData(it.getRank()).push_back(boundaryDofRanks[feSpace][it.getDofIndex()]);
-	}
 
     stdMpi.updateSendDataSize();
 
@@ -388,7 +397,6 @@ namespace AMDiS {
       for (; !it.endDofIter(); it.nextDof()) {
 	if (!isPrimal(feSpace, it.getDofIndex())) {
 	  recvFromRank = true;
-	  MSG("RECV FROM RANK %d\n", it.getRank());
 	  break;
 	}
       }
diff --git a/AMDiS/src/parallel/PetscSolverFeti.h b/AMDiS/src/parallel/PetscSolverFeti.h
index 38de4e8e1414ac22663efe0b327578c13a1ebef6..4853314d19cda5ac4af864d2fe8e4f4b02f4c6c7 100644
--- a/AMDiS/src/parallel/PetscSolverFeti.h
+++ b/AMDiS/src/parallel/PetscSolverFeti.h
@@ -83,11 +83,21 @@ namespace AMDiS {
       return primalDofMap.getOverallDofs();
     }
 
+    int getNumberOfRankPrimals()
+    {
+      return primalDofMap.getRankDofs();
+    }
+
     int getNumberOfDuals()
     {
       return dualDofMap.getOverallDofs();
     }
 
+    int getNumberOfRankDuals()
+    {
+      return dualDofMap.getRankDofs();
+    }
+
   protected:
     /// Defines which boundary nodes are primal. Creates global index of
     /// the primal variables.
diff --git a/test/mpi/src/test0002.cc b/test/mpi/src/test0002.cc
index fe62ba2684d7780deae7a5a6c83462ef7f0d3e79..c8135eb350b43fe51be22987f2624103272066bb 100644
--- a/test/mpi/src/test0002.cc
+++ b/test/mpi/src/test0002.cc
@@ -36,6 +36,41 @@ BOOST_AUTO_TEST_CASE(amdis_mpi_feti)
 
   BOOST_REQUIRE(feti.getNumberOfPrimals() == 21);
   BOOST_REQUIRE(feti.getNumberOfDuals() == 48);
+
+
+
+  Spreadsheet sheet;
+  sheet.read("data/data0002a");
+  vector<double> data = sheet.getData()[MPI::COMM_WORLD.Get_rank()];
+  
+  const FiniteElemSpace *feSpace = ellipt.getFeSpace(0);
+  vector<double> testData;
+  testData.push_back(feti.getNumberOfRankPrimals());
+  testData.push_back(feti.getNumberOfRankDuals());
+  testData.push_back(meshDist->getNumberRankDofs(feSpace));
+  testData.push_back(meshDist->getStartDofs(feSpace));
+  testData.push_back(meshDist->getNumberOverallDofs(feSpace));
+
+  BOOST_REQUIRE(data.size() - 1 == testData.size());
+  BOOST_REQUIRE(equal(data.begin() + 1, data.end(), testData.begin()));
+
+  ellipt.getRefinementManager()->globalRefine(mesh, 6);
+  meshDist->checkMeshChange();
+  feti.createFetiData();
+
+
+
+  sheet.read("data/data0002b");
+  data = sheet.getData()[MPI::COMM_WORLD.Get_rank()];
+  testData.clear();
+  testData.push_back(feti.getNumberOfRankPrimals());
+  testData.push_back(feti.getNumberOfRankDuals());
+  testData.push_back(meshDist->getNumberRankDofs(feSpace));
+  testData.push_back(meshDist->getStartDofs(feSpace));
+  testData.push_back(meshDist->getNumberOverallDofs(feSpace));
+
+  BOOST_REQUIRE(data.size() - 1 == testData.size());
+  BOOST_REQUIRE(equal(data.begin() + 1, data.end(), testData.begin()));
 }