diff --git a/Common/GmshMessage.cpp b/Common/GmshMessage.cpp
index 8ecda644534339ecf15df467982ecc1b1dc4f532..19ab3ea7e4cccbedf166af117b238d6a922c8364 100644
--- a/Common/GmshMessage.cpp
+++ b/Common/GmshMessage.cpp
@@ -19,6 +19,10 @@
 #include <mpi.h>
 #endif
 
+#if defined(HAVE_PETSC)
+#include <petsc.h>
+#endif
+
 #if defined(HAVE_FLTK)
 #include <FL/fl_ask.H>
 #include "FlGui.h"
@@ -62,6 +66,9 @@ void Msg::Init(int argc, char **argv)
   MPI_Comm_rank(MPI_COMM_WORLD, &_commRank);
   MPI_Comm_size(MPI_COMM_WORLD, &_commSize);
   MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
+#endif
+#if defined(HAVE_PETSC)
+  PetscInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL);
 #endif
   time_t now;
   time(&now);
@@ -84,6 +91,9 @@ void Msg::Exit(int level)
   // this calls the annoying "report this crash to the mothership"
   // window... so just exit!
   if(level){
+#if defined(HAVE_PETSC)
+    PetscFinalize();
+#endif
 #if defined(HAVE_MPI)
     MPI_Finalize();
 #endif
diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp
index fc3b57ad2ce1c62806db8133afa7cd3988ea6777..8532990ff5c07f6e04ccab57cefdef2db387e0dc 100644
--- a/Geo/GFaceCompound.cpp
+++ b/Geo/GFaceCompound.cpp
@@ -26,6 +26,7 @@
 #include "linearSystemTAUCS.h"
 #include "linearSystemCSR.h"
 #include "linearSystemFull.h"
+#include "linearSystemPETSc.h"
 
 static void fixEdgeToValue(GEdge *ed, double value, dofManager<double, double> &myAssembler)
 {
@@ -481,10 +482,12 @@ GFaceCompound::GFaceCompound(GModel *m, int tag, std::list<GFace*> &compound,
 {
 
   if (!_lsys) {
-#if defined(HAVE_GMM)
-    linearSystemGmm<double> * _lsysb = new linearSystemGmm<double>;
+#if defined(HAVE_PETSC)
+    _lsys = new linearSystemPETSc<double>;
+#elif defined(HAVE_GMM)
+    linearSystemGmm<double> *_lsysb = new linearSystemGmm<double>;
     _lsysb->setGmres(1);
-    _lsys=_lsysb;
+    _lsys = _lsysb;
 #else
     _lsys = new linearSystemFull<double>;
 #endif
diff --git a/Solver/linearSystemPETSc.h b/Solver/linearSystemPETSc.h
new file mode 100644
index 0000000000000000000000000000000000000000..e1b826c7b6e7a8571e74a5b3dd7d392b5e2d7afa
--- /dev/null
+++ b/Solver/linearSystemPETSc.h
@@ -0,0 +1,192 @@
+// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#ifndef _LINEAR_SYSTEM_PETSC_H_
+#define _LINEAR_SYSTEM_PETSC_H_
+
+// Interface to PETSc 3.x
+
+// Options for PETSc can be provided on the command line, or in the file
+// ~/.petscrc. 
+//
+// By default, we use the following options (GMRES iterative solver,
+// 1.e-8 relative tolerance with ILU(6) preconditioner and RCMK
+// renumbering):
+//
+//   -pc_type ilu
+//   -pc_factor_levels 6
+//   -pc_factor_mat_ordering rcm
+//   -ksp_rtol 1.e-8
+//
+// Other useful options include:
+//
+//   -ksp_gmres_restart 100
+//   -ksp_monitor
+//   ...
+//
+// To use a direct solver (a sparse lu) instead of an iterative
+// solver, use
+//
+//   -ksp_type preonly
+//   -pc_type lu
+//
+// When PETSc is compiled with external solvers (UMFPACK, SuperLU,
+// etc.), they can be accessed simply by changing the matrix type. For
+// example, with umfpack:
+//
+//   -pc_factor_mat_solver_package umfpack
+
+#include "GmshConfig.h"
+#include "GmshMessage.h"
+#include "linearSystem.h"
+
+#if defined(HAVE_PETSC)
+#include <petsc.h>
+#include <petscksp.h>
+
+template <class scalar>
+class linearSystemPETSc : public linearSystem<scalar> {
+ private:
+  int _e;
+  bool _isAllocated;
+  Mat _a;
+  Vec _b, _x;
+  void _try(int ierr) const { CHKERRABORT(PETSC_COMM_WORLD, ierr); }
+ public:
+  linearSystemPETSc() : _isAllocated(false) {}
+  virtual ~linearSystemPETSc(){ clear(); }
+  virtual bool isAllocated() const { return _isAllocated; }
+  virtual void allocate(int nbRows)
+  {
+    clear();
+    _try(MatCreate(PETSC_COMM_WORLD, &_a)); 
+    _try(MatSetSizes(_a, PETSC_DECIDE, PETSC_DECIDE, nbRows, nbRows));
+    // override the default options with the ones from the option
+    // database (if any)
+    _try(MatSetFromOptions(_a));
+    // preallocation option must be set after other options
+    PetscInt prealloc = 200;
+    PetscTruth set;
+    PetscOptionsGetInt(PETSC_NULL, "-petsc_prealloc", &prealloc, &set);
+    _try(MatSeqAIJSetPreallocation(_a, prealloc, PETSC_NULL));
+    _try(VecCreate(PETSC_COMM_WORLD, &_x));
+    _try(VecSetSizes(_x, PETSC_DECIDE, nbRows));
+    // override the default options with the ones from the option
+    // database (if any)
+    _try(VecSetFromOptions(_x));
+    _try(VecDuplicate(_x, &_b));
+    _isAllocated = true;
+  }
+  virtual void clear()
+  {
+    if(_isAllocated){
+      _try(MatDestroy(_a));
+      _try(VecDestroy(_x));
+      _try(VecDestroy(_b));
+    }
+    _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");
+    return 0;
+  }
+  virtual void addToRightHandSide(int row, scalar val)
+  {
+    PetscInt i = row;
+    PetscScalar s = val;
+    _try(VecSetValues(_b, 1, &i, &s, ADD_VALUES));
+  }
+  virtual scalar getFromRightHandSide(int row) const
+  {
+    PetscScalar *tmp;
+    _try(VecGetArray(_b, &tmp));
+    PetscScalar s = tmp[row];
+    _try(VecRestoreArray(_b, &tmp));
+    // FIXME specialize this routine
+#if defined(PETSC_USE_COMPLEX)
+    return s.real();
+#else
+    return s;
+#endif
+  }
+  virtual scalar getFromSolution(int row) const
+  {
+    PetscScalar *tmp;
+    _try(VecGetArray(_x, &tmp));
+    PetscScalar s = tmp[row];
+    _try(VecRestoreArray(_x, &tmp));
+#if defined(PETSC_USE_COMPLEX)
+    return s.real();
+#else
+    return s;
+#endif
+  }
+  virtual void zeroMatrix()
+  {
+    _try(MatZeroEntries(_a));
+  }
+  virtual void zeroRightHandSide()
+  {
+    _try(VecZeroEntries(_b));
+  }
+  virtual int systemSolve()
+  {
+    _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY));
+    _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY));
+    _try(VecAssemblyBegin(_b));
+    _try(VecAssemblyEnd(_b));
+    KSP ksp;
+    _try(KSPCreate(PETSC_COMM_WORLD, &ksp));
+    _try(KSPSetOperators(ksp, _a, _a, DIFFERENT_NONZERO_PATTERN));
+    PC pc;
+    _try(KSPGetPC(ksp, &pc));
+    // set some default options
+    _try(PCSetType(pc, PCILU));
+    _try(PCFactorSetMatOrderingType(pc, MATORDERING_RCM));
+    _try(PCFactorSetLevels(pc, 6));
+    _try(KSPSetTolerances(ksp, 1.e-8, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT));
+    // override the default options with the ones from the option
+    // database (if any)
+    _try(KSPSetFromOptions(ksp));
+    _try(KSPSolve(ksp, _b, _x));
+    _try(KSPView(ksp, PETSC_VIEWER_STDOUT_SELF));
+    PetscInt its;
+    _try(KSPGetIterationNumber(ksp, &its));
+    Msg::Info("%d iterations", its);
+  }
+};
+
+#else
+
+template <class scalar>
+class linearSystemPetsc : public linearSystem<scalar> {
+ public :
+  linearSystemGmm()
+  {
+    Msg::Error("PETSc is not available in this version of Gmsh");
+  }
+  virtual bool isAllocated() const { return false; }
+  virtual void allocate(int nbRows) {}
+  virtual void clear(){}
+  virtual void addToMatrix(int row, int col, scalar val) {}
+  virtual scalar getFromMatrix(int row, int col) const { return 0.; }
+  virtual void addToRightHandSide(int row, scalar val) {}
+  virtual scalar getFromRightHandSide(int row) const { return 0.; }
+  virtual scalar getFromSolution(int row) const { return 0.; }
+  virtual void zeroMatrix() {}
+  virtual void zeroRightHandSide() {}
+  virtual int systemSolve() { return 0; }
+}; 
+
+#endif
+
+#endif