diff --git a/AMDiS/src/parallel/MeshDistributor.cc b/AMDiS/src/parallel/MeshDistributor.cc
index 1d5a8724a23fd3e2f0fe88a76078a930f7b8c9c0..cb6ef6463b9476c16abfcafeb01bfbe30de1920d 100644
--- a/AMDiS/src/parallel/MeshDistributor.cc
+++ b/AMDiS/src/parallel/MeshDistributor.cc
@@ -78,7 +78,7 @@ namespace AMDiS {
       partitioner(NULL),
       nRankDofs(0),
       nOverallDofs(0),
-      rstart(0),
+      rStartDofs(0),
       deserialized(false),
       writeSerializationFile(false),
       repartitioningAllowed(false),
@@ -1837,13 +1837,13 @@ namespace AMDiS {
 	
     // Get displacment for global rank DOF ordering and global DOF number.
     nRankDofs = rankDofs.size();
-    mpi::getDofNumbering(mpiComm, nRankDofs, rstart, nOverallDofs);
+    mpi::getDofNumbering(mpiComm, nRankDofs, rStartDofs, nOverallDofs);
 
 
     // Stores for all rank owned DOFs a new global index.
     DofIndexMap rankDofsNewGlobalIndex;
     for (int i = 0; i < nRankDofs; i++)
-      rankDofsNewGlobalIndex[rankDofs[i]] = i + rstart;
+      rankDofsNewGlobalIndex[rankDofs[i]] = i + rStartDofs;
 
 
     // === Send and receive new DOF indices. ===
@@ -1906,7 +1906,7 @@ namespace AMDiS {
     MSG("------------- Debug information -------------\n");
     MSG("nRankDofs = %d\n", nRankDofs);
     MSG("nOverallDofs = %d\n", nOverallDofs);
-    MSG("rstart %d\n", rstart);
+    MSG("rStartDofs %d\n", rStartDofs);
 
     stringstream oss;
     oss << debugOutputDir << "elementIndex-" << mpiRank << ".vtu";
@@ -2170,7 +2170,7 @@ namespace AMDiS {
     serialize(out, periodicDof);
     serialize(out, periodicDofAssociations);
 
-    SerUtil::serialize(out, rstart);
+    SerUtil::serialize(out, rStartDofs);
     SerUtil::serialize(out, macroElementNeighbours);
 
     int nSize = allMacroElements.size();
@@ -2231,7 +2231,7 @@ namespace AMDiS {
     deserialize(in, periodicDof);
     deserialize(in, periodicDofAssociations);
 
-    SerUtil::deserialize(in, rstart);
+    SerUtil::deserialize(in, rStartDofs);
     SerUtil::deserialize(in, macroElementNeighbours);
 
     int nSize = 0;
diff --git a/AMDiS/src/parallel/MeshDistributor.h b/AMDiS/src/parallel/MeshDistributor.h
index 63dd4aa55aacb4b524b04965117b8eb44f968e20..63d3491000eb024e06ad4d64b55c959bf4bbca58 100644
--- a/AMDiS/src/parallel/MeshDistributor.h
+++ b/AMDiS/src/parallel/MeshDistributor.h
@@ -136,6 +136,12 @@ namespace AMDiS {
       return nRankDofs;
     }
 
+    /// Returns \ref rStartDofs, the first global DOF index owned by rank.
+    inline int getStartDofs()
+    {
+      return rStartDofs;
+    }
+
     /// Returns \ref nOverallDofs, the global number of DOFs.
     inline int getNumberOverallDofs()
     {
@@ -225,11 +231,6 @@ namespace AMDiS {
       return lastMeshChangeIndex;
     }
 
-    inline int getRstart()
-    {
-      return rstart;
-    }
-
     inline int getMpiRank()
     {
       return mpiRank;
@@ -521,6 +522,9 @@ namespace AMDiS {
     /// Number of DOFs in the rank mesh.
     int nRankDofs;
 
+    /// Is the index of the first global DOF index, which is owned by the rank.
+    int rStartDofs;
+
     /// Number of DOFs in the whole domain.
     int nOverallDofs;
 
@@ -604,10 +608,6 @@ namespace AMDiS {
     /// repartitioned.
     vector<DOFVector<double>*> interchangeVectors;
 		        
-    /// Is the index of the first row of the linear system, which is owned by 
-    /// the rank.
-    int rstart;
-
     /** \brief
      * If the problem definition has been read from a serialization file, this 
      * variable is true, otherwise it is false. This variable is used to stop the
diff --git a/AMDiS/src/parallel/PetscProblemStat.cc b/AMDiS/src/parallel/PetscProblemStat.cc
index d5e4d9b176c7b924d96888f22767a1147334234c..7fe043f5ff035378642c524d4b8fec91be3145fe 100644
--- a/AMDiS/src/parallel/PetscProblemStat.cc
+++ b/AMDiS/src/parallel/PetscProblemStat.cc
@@ -25,7 +25,8 @@ namespace AMDiS {
 
   PetscProblemStat::PetscProblemStat(string nameStr,
 				     ProblemIterationInterface *problemIteration)
-    : ParallelProblemStatBase(nameStr, problemIteration)
+    : ParallelProblemStatBase(nameStr, problemIteration),
+      deleteSolver(true)
   {
     FUNCNAME("PetscProblemStat::PetscProblemStat()");
 
@@ -54,6 +55,14 @@ namespace AMDiS {
   }
 
 
+  PetscProblemStat::PetscProblemStat(string nameStr,
+				     PetscSolver *solver)
+    : ParallelProblemStatBase(nameStr, NULL),
+      petscSolver(solver),
+      deleteSolver(false)
+  {}
+
+
   void PetscProblemStat::initialize(Flag initFlag, 
 				    ProblemStatSeq* adoptProblem,
 				    Flag adoptFlag)
diff --git a/AMDiS/src/parallel/PetscProblemStat.h b/AMDiS/src/parallel/PetscProblemStat.h
index 07a837b40f355f05b28ede2d042bec03d38407c6..491c4d0c6685ff2b0e45cd86693681e0183a6873 100644
--- a/AMDiS/src/parallel/PetscProblemStat.h
+++ b/AMDiS/src/parallel/PetscProblemStat.h
@@ -40,9 +40,13 @@ namespace AMDiS {
     PetscProblemStat(std::string nameStr, 
 		     ProblemIterationInterface *problemIteration = NULL);
 
+    PetscProblemStat(std::string nameStr,
+		     PetscSolver *solver);
+
     ~PetscProblemStat()
     {
-      delete petscSolver;
+      if (deleteSolver)
+	delete petscSolver;
     }
 
     void initialize(Flag initFlag,
@@ -55,6 +59,8 @@ namespace AMDiS {
 
   protected:
     PetscSolver *petscSolver;
+
+    bool deleteSolver;
   };
 
   typedef PetscProblemStat ParallelProblemStat;
diff --git a/AMDiS/src/parallel/PetscSolver.cc b/AMDiS/src/parallel/PetscSolver.cc
index 6751f1c9c5e1a6d22a7c5743a850b09f67ea62c4..e6013895dd9c62fa911e49d09efc363ba76b8731 100644
--- a/AMDiS/src/parallel/PetscSolver.cc
+++ b/AMDiS/src/parallel/PetscSolver.cc
@@ -40,4 +40,35 @@ namespace AMDiS {
     }
   }
 
+
+  void PetscSolver::copyVec(Vec& originVec, Vec& destVec, 
+			    vector<int>& originIndex, vector<int>& destIndex)
+  {
+    FUNCNAME("PetscSolver::copyVec()");
+
+    IS originIs, destIs;
+    ISCreateGeneral(PETSC_COMM_WORLD, 
+		    originIndex.size(), 
+		    &(originIndex[0]),
+		    PETSC_USE_POINTER,
+		    &originIs);
+
+    ISCreateGeneral(PETSC_COMM_WORLD, 
+		    destIndex.size(), 
+		    &(destIndex[0]),
+		    PETSC_USE_POINTER,
+		    &destIs);
+
+    VecScatter scatter;
+    VecScatterCreate(originVec, originIs, destVec, destIs, &scatter);
+    VecScatterBegin(scatter, originVec, destVec,
+		    INSERT_VALUES, SCATTER_FORWARD);
+    VecScatterEnd(scatter, originVec, destVec,
+		  INSERT_VALUES, SCATTER_FORWARD);
+
+    ISDestroy(&originIs);
+    ISDestroy(&destIs);    
+    VecScatterDestroy(&scatter);
+  }
+
 }
diff --git a/AMDiS/src/parallel/PetscSolver.h b/AMDiS/src/parallel/PetscSolver.h
index 925d9cd4579b2f47a3203963f4f2962b51a757b9..c9548837358cf7bcb44e6ccb3dc5a320e31bf33f 100644
--- a/AMDiS/src/parallel/PetscSolver.h
+++ b/AMDiS/src/parallel/PetscSolver.h
@@ -90,6 +90,20 @@ namespace AMDiS {
 			   bool iterationCounter = true,
 			   bool residual = true);
 
+    /** \brief
+     * Copies between to PETSc vectors by using different index sets for the
+     * origin and the destination vectors.
+     *
+     * \param[in]   originVec    The PETSc vector from which we copy from.
+     * \param[out]  destVec      The PETSc vector we copy too.
+     * \param[in]   originIndex  Set of global indices referring to the 
+     *                           origin vector.
+     * \param[in]   destIndex    Set of global indices referring to the
+     *                           destination vector.
+     */
+    void copyVec(Vec& originVec, Vec& destVec, 
+		 vector<int>& originIndex, vector<int>& destIndex);
+
   protected:
     MeshDistributor *meshDistributor;
     
diff --git a/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc b/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc
index 6c1a856ca6ce6aa8fcb5b84c64f27e1c4152615e..9c3ff4a07e9b789476b322d632dad217418e5d4b 100644
--- a/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc
+++ b/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc
@@ -25,22 +25,14 @@ namespace AMDiS {
 
     double wtime = MPI::Wtime();
     nComponents = mat->getNumRows();
-    int nRankRows = meshDistributor->getNumberRankDofs() * nComponents;
-    int nOverallRows = meshDistributor->getNumberOverallDofs() * nComponents;
-
-    // === Create PETSc vector (solution and a temporary vector). ===
-
-    VecCreateMPI(PETSC_COMM_WORLD, nRankRows, nOverallRows, &petscSolVec);
-    VecCreateMPI(PETSC_COMM_WORLD, nRankRows, nOverallRows, &petscTmpVec);
-
+    int nRankRows = meshDistributor->getNumberRankDofs();
+    int nOverallRows = meshDistributor->getNumberOverallDofs();
 
 #if (DEBUG != 0)
     MSG("Fill petsc matrix 1 needed %.5f seconds\n", MPI::Wtime() - wtime);
 #endif
 
-    nestMat = new Mat*[nComponents];
-    for (int i = 0; i < nComponents; i++)
-      nestMat[i] = new Mat[nComponents];
+    nestMat.resize(nComponents * nComponents);
 
     // === Transfer values from DOF matrices to the PETSc matrix. === 
 
@@ -51,16 +43,17 @@ namespace AMDiS {
 			  nRankRows, nRankRows,
 			  nOverallRows, nOverallRows,
 			  30, PETSC_NULL, 30, PETSC_NULL,
-			  &(nestMat[i][j]));
-
-	  setDofMatrix(nestMat[i][j], (*mat)[i][j]);
+			  &(nestMat[i * nComponents + j]));
+	  setDofMatrix(nestMat[i * nComponents + j], (*mat)[i][j]);
+	  MatAssemblyBegin(nestMat[i * nComponents + j], MAT_FINAL_ASSEMBLY);
+	  MatAssemblyEnd(nestMat[i * nComponents + j], MAT_FINAL_ASSEMBLY);
 	} else {
-	  nestMat[i][j] = PETSC_NULL;
+	  nestMat[i * nComponents + j] = PETSC_NULL;
 	}
 
     MatCreateNest(PETSC_COMM_WORLD, 
 		  nComponents, PETSC_NULL, nComponents, PETSC_NULL, 
-		  &(nestMat[0][0]), &petscMatrix);
+		  &(nestMat[0]), &petscMatrix);
 
 #if (DEBUG != 0)
     MSG("Fill petsc matrix 2 needed %.5f seconds\n", MPI::Wtime() - wtime);
@@ -71,12 +64,11 @@ namespace AMDiS {
 
     // === Init PETSc solver. ===
     KSPCreate(PETSC_COMM_WORLD, &solver);
-    KSPGetPC(solver, &pc);
     KSPSetOperators(solver, petscMatrix, petscMatrix, SAME_NONZERO_PATTERN); 
-    KSPSetTolerances(solver, 0.0, 1e-8, PETSC_DEFAULT, PETSC_DEFAULT);
-    KSPSetType(solver, KSPBCGS);
     KSPSetFromOptions(solver);
-    PCSetFromOptions(pc);
+
+    KSPGetPC(solver, &pc);
+    setBlockPreconditioner(pc);
 
     MSG("Fill petsc matrix needed %.5f seconds\n", MPI::Wtime() - wtime);
   }
@@ -89,15 +81,22 @@ namespace AMDiS {
     TEST_EXIT_DBG(vec)("NO DOF vector defined!\n");
 
     nComponents = vec->getSize();
-    int nRankRows = meshDistributor->getNumberRankDofs() * nComponents;
-    int nOverallRows = meshDistributor->getNumberOverallDofs() * nComponents;
+    int nRankRows = meshDistributor->getNumberRankDofs();
+    int nOverallRows = meshDistributor->getNumberOverallDofs();
 
-    VecCreateMPI(PETSC_COMM_WORLD, nRankRows, nOverallRows, &petscRhsVec);
+    nestVec.resize(nComponents);
 
-    // === Transfer values from DOF vector to the PETSc vector. === 
+    for (int i = 0; i < nComponents; i++) {
+      VecCreateMPI(PETSC_COMM_WORLD, nRankRows, nOverallRows, &(nestVec[i]));
 
-    for (int i = 0; i < nComponents; i++)
-      setDofVector(petscRhsVec, vec->getDOFVector(i), nComponents, i);
+      setDofVector(nestVec[i], vec->getDOFVector(i));
+      
+      VecAssemblyBegin(nestVec[i]);
+      VecAssemblyEnd(nestVec[i]);
+    }
+
+    VecCreateNest(PETSC_COMM_WORLD, nComponents, PETSC_NULL, 
+		  &(nestVec[0]), &petscRhsVec);
 
     VecAssemblyBegin(petscRhsVec);
     VecAssemblyEnd(petscRhsVec);
@@ -110,21 +109,24 @@ namespace AMDiS {
     FUNCNAME("PetscSolverGlobalBlockMatrix::solvePetscMatrix()");
 
     // PETSc.
-    KSPSolve(solver, petscRhsVec, petscSolVec);
+    KSPSolve(solver, petscRhsVec, petscRhsVec);
 
     // === Transfere values from PETSc's solution vectors to the DOF vectors. ===
-    int nRankDofs = meshDistributor->getNumberRankDofs();
-    PetscScalar *vecPointer;
-    VecGetArray(petscSolVec, &vecPointer);
-
     for (int i = 0; i < nComponents; i++) {
       DOFVector<double> &dofvec = *(vec.getDOFVector(i));
+
+      Vec tmp;
+      VecNestGetSubVec(petscRhsVec, i, &tmp);
+
+      int nRankDofs = meshDistributor->getNumberRankDofs();
+      PetscScalar *vecPointer;
+      VecGetArray(tmp, &vecPointer);
+
       for (int j = 0; j < nRankDofs; j++)
-	dofvec[meshDistributor->mapLocalToDofIndex(j)] = 
-	  vecPointer[i * nComponents + j]; 
-    }
+	dofvec[meshDistributor->mapLocalToDofIndex(j)] = vecPointer[j]; 
 
-    VecRestoreArray(petscSolVec, &vecPointer);
+      VecRestoreArray(tmp, &vecPointer);
+    }
 
 
     // === Synchronize DOFs at common DOFs, i.e., DOFs that correspond to ===
@@ -132,12 +134,10 @@ namespace AMDiS {
     meshDistributor->synchVector(vec);
 
 
-    // Print iteration counter and residual norm of the solution.
-    printSolutionInfo(adaptInfo);
-
-
     // === Destroy PETSc's variables. ===
     VecDestroy(&petscRhsVec);
+    for (int i = 0; i < nComponents; i++)
+      VecDestroy(&(nestVec[i]));
   }
 
 
@@ -145,20 +145,12 @@ namespace AMDiS {
   {
     FUNCNAME("PetscSolverGlobalBlockMatrix::destroyMatrixData()");
 
+    for (unsigned int i = 0; i < nestMat.size(); i++)
+      if (nestMat[i] != PETSC_NULL)
+	MatDestroy(&(nestMat[i]));
+
     MatDestroy(&petscMatrix);
     KSPDestroy(&solver);
-    VecDestroy(&petscSolVec);
-    VecDestroy(&petscTmpVec);
-
-    for (int i = 0; i < nComponents; i++) {
-      for (int j = 0; j < nComponents; j++) {
-	if (nestMat[i][j] != PETSC_NULL)
-	  MatDestroy(&(nestMat[i][j]));
-      }
-
-      delete[] nestMat[i];
-    }
-    delete[] nestMat;
   }
 
 
@@ -209,32 +201,22 @@ namespace AMDiS {
 	cols.push_back(colIndex);
 	values.push_back(value(*icursor));
       }
-      
-      MatSetValues(petscMatrix, 1, &rowIndex, cols.size(), 
-		   &(cols[0]), &(values[0]), ADD_VALUES);	
+
+      MatSetValues(petscMat, 1, &rowIndex, cols.size(), 
+ 		   &(cols[0]), &(values[0]), ADD_VALUES);	
     }
   }
   
   
   void PetscSolverGlobalBlockMatrix::setDofVector(Vec& petscVec, 
-						  DOFVector<double>* vec, 
-						  int nComponents,
-						  int row,
-						  bool rankOnly)
+						  DOFVector<double>* vec)
   {
     FUNCNAME("PetscSolverGlobalBlockMatrix::setDofVector()");
 
     // Traverse all used DOFs in the dof vector.
     DOFVector<double>::Iterator dofIt(vec, USED_DOFS);
     for (dofIt.reset(); !dofIt.end(); ++dofIt) {
-      if (rankOnly && !meshDistributor->getIsRankDof(dofIt.getDOFIndex()))
-	continue;
-
-      // Calculate global row index of the DOF.
-      DegreeOfFreedom globalRowDof = 
-	meshDistributor->mapLocalToGlobal(dofIt.getDOFIndex());
-      // Calculate PETSc index of the row DOF.
-      int index = nComponents * row + globalRowDof;
+      int index = meshDistributor->mapLocalToGlobal(dofIt.getDOFIndex());
       double value = *dofIt;
 
       VecSetValues(petscVec, 1, &index, &value, ADD_VALUES);
diff --git a/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.h b/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.h
index 98e0255a679973611cbf7cdc3e22468e06829013..31250c1a09bd632240aad241dd4058e6037b1181 100644
--- a/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.h
+++ b/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.h
@@ -52,11 +52,18 @@ namespace AMDiS {
     void setDofMatrix(Mat& petscMat, DOFMatrix* mat);
 
     /// Takes a DOF vector and sends its values to a given PETSc vector.
-    void setDofVector(Vec& petscVec, DOFVector<double>* vec, 
-		      int nComponents, int row, bool rankOnly = false);
+    void setDofVector(Vec& petscVec, DOFVector<double>* vec);
+
+    
+    virtual void setBlockPreconditioner(PC &pc)
+    {
+      PCSetFromOptions(pc);    
+    }
 
   protected:
-    Mat **nestMat;
+    vector<Mat> nestMat;
+
+    vector<Vec> nestVec;
 
     int nComponents;
   };
diff --git a/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc b/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc
index 21c1057672b22744637737dce056f34cd96b72f3..dcc05c0c1e5e8a5d4ac3506b15e5162c4604de16 100644
--- a/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc
+++ b/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc
@@ -66,9 +66,9 @@ namespace AMDiS {
 #if (DEBUG != 0)
     int a, b;
     MatGetOwnershipRange(petscMatrix, &a, &b);
-    TEST_EXIT(a == meshDistributor->getRstart() * nComponents)
+    TEST_EXIT(a == meshDistributor->getStartDofs() * nComponents)
       ("Wrong matrix ownership range!\n");
-    TEST_EXIT(b == meshDistributor->getRstart() * nComponents + nRankRows)
+    TEST_EXIT(b == meshDistributor->getStartDofs() * nComponents + nRankRows)
       ("Wrong matrix ownership range!\n");
 #endif
 
@@ -552,7 +552,7 @@ namespace AMDiS {
 	    
 	    // This is the local row index of the local PETSc matrix.
 	    int localPetscRowIdx = 
-	      petscRowIdx - meshDistributor->getRstart() * nComponents;
+	      petscRowIdx - meshDistributor->getStartDofs() * nComponents;
 	    
 	    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",
@@ -560,7 +560,7 @@ namespace AMDiS {
 	       meshDistributor->mapLocalToGlobal(*cursor), 
 	       petscRowIdx, 
 	       localPetscRowIdx, 
-	       meshDistributor->getRstart(), 
+	       meshDistributor->getStartDofs(), 
 	       nComponents, 
 	       nRankRows);
 	    
@@ -574,8 +574,8 @@ namespace AMDiS {
 	      if (value(*icursor) != 0.0 || petscRowIdx == petscColIdx) {
 		// The row DOF is a rank DOF, if also the column is a rank DOF, 
 		// increment the d_nnz values for this row, otherwise the o_nnz value.
-		if (petscColIdx >= meshDistributor->getRstart() * nComponents && 
-		    petscColIdx < meshDistributor->getRstart() * nComponents + nRankRows)
+		if (petscColIdx >= meshDistributor->getStartDofs() * nComponents && 
+		    petscColIdx < meshDistributor->getStartDofs() * nComponents + nRankRows)
 		  d_nnz[localPetscRowIdx]++;
 		else
 		  o_nnz[localPetscRowIdx]++;
@@ -626,14 +626,14 @@ namespace AMDiS {
 	  int r = it->second[i].first;
 	  int c = it->second[i].second;
 
-	  int localRowIdx = r - meshDistributor->getRstart() * nComponents;
+	  int localRowIdx = r - meshDistributor->getStartDofs() * nComponents;
 
 	  TEST_EXIT_DBG(localRowIdx >= 0 && localRowIdx < nRankRows)
 	    ("Got row index %d/%d (nRankRows = %d) from rank %d. Should not happen!\n",
 	     r, localRowIdx, nRankRows, it->first);
 	  
-	  if (c < meshDistributor->getRstart() * nComponents || 
-	      c >= meshDistributor->getRstart() * nComponents + nRankRows)
+	  if (c < meshDistributor->getStartDofs() * nComponents || 
+	      c >= meshDistributor->getStartDofs() * nComponents + nRankRows)
 	    o_nnz[localRowIdx]++;
 	  else
 	    d_nnz[localRowIdx]++;