diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp
index 0cbbb498d80e812e373a666cd72baea16d56c2d1..eccdc6bf93a18c5287aac8c55b7ab39bf017fe02 100644
--- a/Geo/GFaceCompound.cpp
+++ b/Geo/GFaceCompound.cpp
@@ -1100,7 +1100,8 @@ void GFaceCompound::parametrize(iterationStep step, typeOfMapping tom) const
 
   for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){
     MVertex *v = *itv;
-    double value = myAssembler.getDofValue(v, 0, 1);
+    double value;
+   myAssembler.getDofValue(value, v, 0, 1);
    std::map<MVertex*,SPoint3>::iterator itf = coordinates.find(v);    
     if(itf == coordinates.end()){
       SPoint3 p(0, 0, 0);
@@ -1348,8 +1349,9 @@ bool GFaceCompound::parametrize_conformal() const
 
   for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){
     MVertex *v = *itv;
-    double value1 = myAssembler.getDofValue(v,0,1);
-    double value2 = myAssembler.getDofValue(v,0,2);
+    double value1, value2; 
+    myAssembler.getDofValue(value1, v,0,1);
+    myAssembler.getDofValue(value2, v,0,2);
     coordinates[v] = SPoint3(value1,value2,0.0);
   }
 
diff --git a/Mesh/BackgroundMesh.cpp b/Mesh/BackgroundMesh.cpp
index 9deb77cb6bc77238fd811735a525e2a32737664c..7822b83d7ec5b8c598ebc8b526a24a7a3b76b538 100644
--- a/Mesh/BackgroundMesh.cpp
+++ b/Mesh/BackgroundMesh.cpp
@@ -371,8 +371,7 @@ void backgroundMesh::propagate1dMesh(GFace *_gf)
   for ( ; itv2 != _2Dto3D.end(); ++itv2){
     MVertex *v_2D = itv2->first;
     MVertex *v_3D = itv2->second;
-    double value = myAssembler.getDofValue(v_3D, 0, 1);
-    _sizes[v_2D] = value;
+    myAssembler.getDofValue(_sizes[v_2D], v_3D, 0, 1);
   }
   delete _lsys;
 #endif
@@ -473,8 +472,7 @@ void backgroundMesh::updateSizes(GFace *_gf)
   for ( ; itv2 != _2Dto3D.end(); ++itv2){
     MVertex *v_2D = itv2->first;
     MVertex *v_3D = itv2->second;
-    double value = myAssembler.getDofValue(v_3D, 0, 1);
-    _sizes[v_2D] = value;
+    myAssembler.getDofValue(_sizes[v_2D], v_3D, 0, 1);
   }
   delete _lsys;
 #endif
diff --git a/Mesh/highOrderSmoother.cpp b/Mesh/highOrderSmoother.cpp
index 95957bee56a67395824e8432fd3c64457f43c155..281cde696c9e9b889d18c708d75074e97ffd82e5 100644
--- a/Mesh/highOrderSmoother.cpp
+++ b/Mesh/highOrderSmoother.cpp
@@ -599,8 +599,9 @@ double highOrderSmoother::smooth_metric_(std::vector<MElement*>  & v,
       if ((*it)->onWhat()->dim() == 2){
 	SPoint2 param;
 	reparamMeshVertexOnFace((*it), gf, param);  
-	SPoint2 dparam (myAssembler.getDofValue((*it), 0, getTag()),
-			myAssembler.getDofValue((*it), 1, getTag()));
+	SPoint2 dparam;
+  myAssembler.getDofValue(dparam[0], (*it), 0, getTag());
+  myAssembler.getDofValue(dparam[1], (*it), 1, getTag());
 	SPoint2 newp = param+dparam;
 	dx += newp.x() * newp.x() + newp.y() * newp.y();
 	(*it)->setParameter(0, newp.x());
@@ -715,9 +716,13 @@ void highOrderSmoother::smooth(std::vector<MElement*> &all)
   }
   
   for (it = verticesToMove.begin(); it != verticesToMove.end(); ++it){
-    it->first->x() += myAssembler.getDofValue(it->first, 0, getTag());
-    it->first->y() += myAssembler.getDofValue(it->first, 1, getTag());
-    it->first->z() += myAssembler.getDofValue(it->first, 2, getTag());
+    double ax, ay, az;
+    myAssembler.getDofValue(ax, it->first, 0, getTag());
+    myAssembler.getDofValue(ay, it->first, 1, getTag());
+    myAssembler.getDofValue(az, it->first, 2, getTag());
+    it->first->x() += ax;
+    it->first->y() += ay;
+    it->first->z() += az;
   }
 
   // delete matrices and vectors
diff --git a/Numeric/fullMatrix.h b/Numeric/fullMatrix.h
index 5d5a5f878e3c329cab904a3e63813c25a17f1b83..04630c7ae53d15b0cb8022530662ef3844a7934e 100644
--- a/Numeric/fullMatrix.h
+++ b/Numeric/fullMatrix.h
@@ -63,6 +63,8 @@ class fullVector
   {
     if(s == 0.) 
       for(int i = 0; i < _r; ++i) _data[i] = 0.;
+    else if (s == -1.)
+      for(int i = 0; i < _r; ++i) _data[i] = -_data[i];
     else 
       for(int i = 0; i < _r; ++i) _data[i] *= s;
   }
diff --git a/Plugin/Distance.cpp b/Plugin/Distance.cpp
index a5cb8df70e4480ece4de55d9fc82c069608dbb43..bb5634416319a46bdf538dbb9149f025e03760b3 100644
--- a/Plugin/Distance.cpp
+++ b/Plugin/Distance.cpp
@@ -188,7 +188,9 @@ PView *GMSH_DistancePlugin::execute(PView *v)
   for(std::map<MVertex*,double >::iterator itv = distance_map2.begin(); 
       itv !=distance_map2.end() ; ++itv){
     MVertex *v = itv->first;
-    double value = std::min(0.9999, myAssembler.getDofValue(v, 0, 1));
+    double value;
+    myAssembler.getDofValue(value, v, 0, 1);
+    value = std::min(0.9999, value);
     double dist = -mu * log(1. - value);
     itv->second = dist;
   }
diff --git a/Solver/CMakeLists.txt b/Solver/CMakeLists.txt
index fbeea2c22e3a8dda43b855a75318918c3db6debf..d297e54425c6abb19e7586f38ef3622c6312d419 100644
--- a/Solver/CMakeLists.txt
+++ b/Solver/CMakeLists.txt
@@ -6,6 +6,7 @@
 set(SRC
   linearSystem.cpp
   linearSystemCSR.cpp
+  linearSystemPETSc.cpp
   groupOfElements.cpp
   elasticityTerm.cpp
   elasticitySolver.cpp
diff --git a/Solver/dofManager.h b/Solver/dofManager.h
index 9df7b57f883e83a374654f98e8a15b5015f5d357..31a1fb782bc3b59d5b667a13840a382271b73a63 100644
--- a/Solver/dofManager.h
+++ b/Solver/dofManager.h
@@ -48,12 +48,18 @@ template<class T> struct dofTraits
 {
   typedef T VecType;
   typedef T MatType;
+  inline static void mult (VecType &r, const MatType &m, const VecType &v) { r = m*v;}
+  inline static void neg (VecType &r) { r = -r;} 
+  inline static void setToZero (VecType &r) { r = 0;} 
 };
 
-template<class T> struct dofTraits<fullVector<T> >
+template<class T> struct dofTraits<fullMatrix<T> >
 {
-  typedef fullVector<T> VecType;
+  typedef fullMatrix<T> VecType;
   typedef fullMatrix<T> MatType;
+  inline static void mult (VecType &r, const MatType &m, const VecType &v) { m.mult(v, r);}
+  inline static void neg (VecType &r) { r.scale(-1.);} 
+  inline static void setToZero (VecType &r) { r.scale(0);} 
 };
 /*
 template<> struct dofTraits<fullVector<std::complex<double> > >
@@ -159,24 +165,30 @@ class dofManager{
     return dataVec(0.0);
   }
 
-  inline dataVec getDofValue(int ent, int type) const
+  inline void getDofValue(dataVec &v, int ent, int type) const
   {
     Dof key(ent, type);
     {  
       typename std::map<Dof, dataVec>::const_iterator it = fixed.find(key);
-      if (it != fixed.end()) return it->second;
+      if (it != fixed.end()){
+        v = it->second;
+        return;
+      }
     }
     {
       std::map<Dof, int>::const_iterator it = unknown.find(key);
-      if (it != unknown.end())
-        return _current->getFromSolution(it->second);
+      if (it != unknown.end()){
+        v = _current->getFromSolution(it->second);
+        return;
+      }
     }
-    return dataVec(0.0);
+    dofTraits<T>::setToZero(v);
   }
-  inline dataVec getDofValue(MVertex *v, int iComp, int iField) const
+  inline dataVec getDofValue(dataVec &value, MVertex *v, int iComp, int iField) const
   {
-    return getDofValue(v->getNum(), Dof::createTypeWithTwoInts(iComp, iField));
+    getDofValue(value, v->getNum(), Dof::createTypeWithTwoInts(iComp, iField));
   }
+
   inline void assemble(const Dof &R, const Dof &C, const dataMat &value)
   {
     if (!_current->isAllocated()) _current->allocate(unknown.size());
@@ -189,8 +201,12 @@ class dofManager{
       }
       else{
         typename std::map<Dof,  dataVec>::iterator itFixed = fixed.find(C);
-        if (itFixed != fixed.end()){
-          _current->addToRightHandSide(itR->second, -value * itFixed->second);
+        if (itFixed != fixed.end()) {
+          // tmp = -value * itFixed->second
+          dataVec tmp(itFixed->second);
+          dofTraits<T>::mult(tmp , value, itFixed->second);
+          dofTraits<T>::neg(tmp);
+          _current->addToRightHandSide(itR->second, tmp);
         }
       }
     }
@@ -220,7 +236,11 @@ class dofManager{
           else{
             typename std::map<Dof,  dataVec>::iterator itFixed = fixed.find(C[j]);
             if (itFixed != fixed.end()){
-              _current->addToRightHandSide(NR[i], -m(i,j) * itFixed->second);
+              // tmp = -m(i,j) * itFixed->second
+              dataVec tmp(itFixed->second);
+              dofTraits<T>::mult(tmp , m(i,j), itFixed->second);
+              dofTraits<T>::neg(tmp);
+              _current->addToRightHandSide(NR[i], tmp);
             }
           }
         }
@@ -272,7 +292,11 @@ class dofManager{
           {
             typename std::map<Dof,  dataVec>::iterator itFixed = fixed.find(R[j]);
             if (itFixed != fixed.end()){
-              _current->addToRightHandSide(NR[i], -m(i, j) * itFixed->second);
+              // tmp = -m(i,j) * itFixed->second
+              dataVec tmp(itFixed->second);
+              dofTraits<T>::mult(tmp , m(i,j), itFixed->second);
+              dofTraits<T>::neg(tmp);
+              _current->addToRightHandSide(NR[i], tmp);
             }
           }
         }
@@ -336,5 +360,4 @@ class dofManager{
       return 0;
   }
 };
-
 #endif
diff --git a/Solver/elasticitySolver.cpp b/Solver/elasticitySolver.cpp
index 047e83fdbc4a798b4e94e2deb8bb7acd471acc7f..65540b388c94fbea3910aa7c8b355ceeafd2d324 100644
--- a/Solver/elasticitySolver.cpp
+++ b/Solver/elasticitySolver.cpp
@@ -225,9 +225,9 @@ static double vonMises(dofManager<double> *a, MElement *e,
   double valy[256];
   double valz[256];
   for (int k = 0; k < e->getNumVertices(); k++){
-    valx[k] = a->getDofValue(e->getVertex(k), 0, _tag);
-    valy[k] = a->getDofValue(e->getVertex(k), 1, _tag);
-    valz[k] = a->getDofValue(e->getVertex(k), 2, _tag);
+    a->getDofValue(valx[k], e->getVertex(k), 0, _tag);
+    a->getDofValue(valy[k], e->getVertex(k), 1, _tag);
+    a->getDofValue(valz[k], e->getVertex(k), 2, _tag);
   }
   double gradux[3];
   double graduy[3];
diff --git a/Solver/function.cpp b/Solver/function.cpp
index aadd3c0699dcaa41a3852188ed4074aadc17b99b..2d65bc040e931ddf15f1c3881bf1467e6348b0a7 100644
--- a/Solver/function.cpp
+++ b/Solver/function.cpp
@@ -447,7 +447,7 @@ void function::registerBindings(binding *b){
   mb->setDescription("return the unique instance of this class");
   cb->setParentClass<function>();
 
-  cb = b->addClass<functionSolution>("functionNormals");
+  cb = b->addClass<functionNormals>("functionNormals");
   cb->setDescription("A function to access the face normals. This is a single-instance class, use the 'get' member to access the instance.");
   mb = cb->addMethod("get",&functionNormals::get);
   mb->setDescription("return the unique instance of this class");
diff --git a/Solver/linearSystem.cpp b/Solver/linearSystem.cpp
index 32d0022012270307683079dfb7c76e92a6912e02..84193cd788e023e160c51d5d02d75012b06dd1cf 100644
--- a/Solver/linearSystem.cpp
+++ b/Solver/linearSystem.cpp
@@ -28,19 +28,13 @@ void linearSystem<double>::registerBindings(binding *b){
   cb->setParentClass<linearSystem<double> >();
 #endif
 
-#ifdef HAVE_PETSC
-  cb = b->addClass<linearSystemPETSc<double> >("linearSystemPETSc");
-  cb->setDescription("A linear system solver, based on PETSc");
-  cm = cb->setConstructor<linearSystemPETSc<double> >();
-  cm->setDescription ("A new PETSc<double> solver");
-  cm->setArgNames(NULL);
-  cb->setParentClass<linearSystem<double> >();
-#endif
-
   cb = b->addClass<linearSystemFull<double> >("linearSystemFull");
   cb->setDescription("A linear system solver, based on LAPACK (full matrices)");
   cm = cb->setConstructor<linearSystemFull<double> >();
   cm->setDescription ("A new Lapack based <double> solver");
   cm->setArgNames(NULL);
   cb->setParentClass<linearSystem<double> >();
+#ifdef HAVE_PETSC
+  linearSystemPETScRegisterBindings (b);
+#endif
 }
diff --git a/Solver/linearSystemPETSc.cpp b/Solver/linearSystemPETSc.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c77af8d464bb156544d4bc3cf5bde89ac1812911
--- /dev/null
+++ b/Solver/linearSystemPETSc.cpp
@@ -0,0 +1,110 @@
+#include "GmshConfig.h"
+#if defined HAVE_PETSC
+#include "linearSystemPETSc.h"
+#include "fullMatrix.h"
+template <>
+void linearSystemPETSc<fullMatrix<double> >::addToMatrix(int row, int col, fullMatrix<double> val)
+{
+  for (int ii = 0; ii<val.size1(); ii++)
+    for (int jj = 0; jj < ii; jj ++) {
+      double buff = val(ii,jj);
+      val(ii,jj) = val (jj,ii);
+      val(jj,ii) = buff;
+    }
+  PetscInt i = row, j = col;
+  _try(MatSetValuesBlocked(_a, 1, &i, 1, &j, &val(0,0), ADD_VALUES));
+}
+template<>
+void linearSystemPETSc<fullMatrix<double> >::addToRightHandSide(int row, fullMatrix<double> val)
+{
+  for (int ii = 0; ii < _blockSize; ii ++) {
+    PetscInt i = row * _blockSize + ii;
+    _try(VecSetValues(_b, 1, &i, &val(ii,0), ADD_VALUES));
+  }
+}
+
+template<>
+fullMatrix<double> linearSystemPETSc<fullMatrix<double> >::getFromMatrix(int row, int col) const
+{
+  Msg::Error("getFromMatrix not implemented for PETSc");
+  return fullMatrix<double>(0,0);
+}
+
+template<>
+fullMatrix<double> linearSystemPETSc<fullMatrix<double> >::getFromRightHandSide(int row) const
+{
+  fullMatrix<double> val(_blockSize,1);
+  PetscScalar *tmp;
+  _try(VecGetArray(_b, &tmp));
+  for (int i=0; i<_blockSize; i++) {
+    PetscScalar s = tmp[row*_blockSize+i];
+#if defined(PETSC_USE_COMPLEX)
+    val(i,0) = s.real();
+#else
+    val(i,0) = s;
+#endif
+  }
+  _try(VecRestoreArray(_b, &tmp));
+  return val;
+}
+
+template<>
+fullMatrix<double> linearSystemPETSc<fullMatrix<double> >::getFromSolution(int row) const
+{
+  fullMatrix<double> val(_blockSize,1);
+  PetscScalar *tmp;
+  _try(VecGetArray(_x, &tmp));
+  for (int i=0; i<_blockSize; i++) {
+    PetscScalar s = tmp[row*_blockSize+i];
+#if defined(PETSC_USE_COMPLEX)
+    val(i,0) = s.real();
+#else
+    val(i,0) = s;
+#endif
+  }
+  _try(VecRestoreArray(_x, &tmp));
+  return val;
+}
+
+template<>
+void linearSystemPETSc<fullMatrix<double> >::allocate(int nbRows) {
+  clear();
+  _try(MatCreate(PETSC_COMM_WORLD, &_a)); 
+  _try(MatSetSizes(_a, PETSC_DECIDE, PETSC_DECIDE, nbRows*_blockSize, nbRows*_blockSize));
+  _try(MatSetType(_a, MATSEQBAIJ));
+  // override the default options with the ones from the option
+  // database (if any)
+  _try(MatSetFromOptions(_a));
+  _try(MatSeqBAIJSetPreallocation(_a, _blockSize, 4, NULL)); //todo preAllocate off-diagonal part
+  //_try(MatMPIBAIJSetPreallocation(_a, _blockSize, 4, NULL, 0, NULL)); //todo preAllocate off-diagonal part
+  _try(VecCreate(PETSC_COMM_WORLD, &_x));
+  _try(VecSetSizes(_x, PETSC_DECIDE, nbRows*_blockSize));
+  // override the default options with the ones from the option
+  // database (if any)
+  _try(VecSetFromOptions(_x));
+  _try(VecDuplicate(_x, &_b));
+  _isAllocated = true;
+}
+
+#include "Bindings.h"
+void linearSystemPETScRegisterBindings(binding *b) {
+  classBinding *cb;
+  methodBinding *cm;
+  cb = b->addClass<linearSystemPETSc<double> >("linearSystemPETSc");
+  cb->setDescription("A linear system solver, based on PETSc");
+  cm = cb->setConstructor<linearSystemPETSc<double> >();
+  cm->setDescription ("A new PETSc<double> solver");
+  cb->setParentClass<linearSystem<double> >();
+  cm->setArgNames(NULL);
+  cm = cb->addMethod("systemSolve", &linearSystem<fullMatrix<double> >::systemSolve);
+  cm->setDescription("compute x = A^{-1}b");
+
+  cb = b->addClass<linearSystemPETSc<fullMatrix<double> > >("linearSystemPETScBlock");
+  cb->setDescription("A linear system solver, based on PETSc");
+  cm = cb->setConstructor<linearSystemPETSc<fullMatrix<double> >, int>();
+  cm->setDescription ("A new PETScBlock<double> solver (we probably should get rid of the blockSize argument)");
+  cm->setArgNames("blockSize", NULL);
+  cm = cb->addMethod("systemSolve", &linearSystem<fullMatrix<double> >::systemSolve);
+  cm->setDescription("compute x = A^{-1}b");
+}
+#endif // HAVE_PETSC
diff --git a/Solver/linearSystemPETSc.h b/Solver/linearSystemPETSc.h
index acc4a040e0147c60b9f0c25dbd52ff936c36508c..d17a14c333e13d8dd001a04007fa240ac19f6806 100644
--- a/Solver/linearSystemPETSc.h
+++ b/Solver/linearSystemPETSc.h
@@ -44,13 +44,13 @@
 
 template <class scalar>
 class linearSystemPETSc : public linearSystem<scalar> {
- private:
+  int _blockSize; // for block Matrix
   bool _isAllocated;
   Mat _a;
   Vec _b, _x;
   void _try(int ierr) const { CHKERRABORT(PETSC_COMM_WORLD, ierr); }
  public:
-  linearSystemPETSc() : _isAllocated(false) {}
+  linearSystemPETSc(int blockSize = -1) : _isAllocated(false) {_blockSize = blockSize;}
   virtual ~linearSystemPETSc(){ clear(); }
   virtual bool isAllocated() const { return _isAllocated; }
   virtual void allocate(int nbRows)
@@ -83,12 +83,6 @@ class linearSystemPETSc : public linearSystem<scalar> {
     }
     _isAllocated = false;
   }
-  virtual void addToMatrix(int row, int col, scalar val)
-  {
-    PetscInt i = row, j = col;
-    PetscScalar s = val;
-    _try(MatSetValues(_a, 1, &i, 1, &j, &s, ADD_VALUES));
-  }
   virtual scalar getFromMatrix(int row, int col) const
   {
     Msg::Error("getFromMatrix not implemented for PETSc");
@@ -113,6 +107,12 @@ class linearSystemPETSc : public linearSystem<scalar> {
     return s;
 #endif
   }
+  virtual void addToMatrix(int row, int col, scalar val)
+  {
+    PetscInt i = row, j = col;
+    PetscScalar s = val;
+    _try(MatSetValues(_a, 1, &i, 1, &j, &s, ADD_VALUES));
+  }
   virtual scalar getFromSolution(int row) const
   {
     PetscScalar *tmp;
@@ -152,6 +152,9 @@ class linearSystemPETSc : public linearSystem<scalar> {
     // override the default options with the ones from the option
     // database (if any)
     _try(KSPSetFromOptions(ksp));
+    PetscViewer view;
+    PetscViewerASCIIOpen(PETSC_COMM_WORLD,"mat.out", &view);
+    _try(MatView(_a, view));
     _try(KSPSolve(ksp, _b, _x));
     _try(KSPView(ksp, PETSC_VIEWER_STDOUT_SELF));
     PetscInt its;
@@ -161,6 +164,10 @@ class linearSystemPETSc : public linearSystem<scalar> {
   Mat &getMatrix(){ return _a; }
 };
 
+class binding;
+void linearSystemPETScRegisterBindings(binding *b);
+
+
 #else
 
 template <class scalar>
diff --git a/Solver/multiscaleLaplace.cpp b/Solver/multiscaleLaplace.cpp
index 73637c6874988773357f77d50ec26b078ab3591a..29acbb5a29e68499d37a2b2866448167afabd3b0 100644
--- a/Solver/multiscaleLaplace.cpp
+++ b/Solver/multiscaleLaplace.cpp
@@ -1199,7 +1199,8 @@ void multiscaleLaplace::parametrize_method (multiscaleLaplaceLevel & level,
     int count = 0;
     for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){
       MVertex *v = *itv;
-      double value = myAssembler.getDofValue(v, 0, 1);      
+      double value;
+      myAssembler.getDofValue(value, v, 0, 1);      
       if (step == 0)solution[v] = SPoint2(value,0);
       else solution[v] = SPoint2(solution[v][0],value);
     }