diff --git a/Numeric/GmshMatrix.cpp b/Numeric/fullMatrix.cpp
similarity index 87%
rename from Numeric/GmshMatrix.cpp
rename to Numeric/fullMatrix.cpp
index 286df546a452f2a30e0d319a7a4c5ea9e7a17540..69928a6f359742a691b557f0ee9de49e18ec2f62 100644
--- a/Numeric/GmshMatrix.cpp
+++ b/Numeric/fullMatrix.cpp
@@ -6,7 +6,7 @@
 #include <complex>
 #include <string.h>
 #include "GmshConfig.h"
-#include "GmshMatrix.h"
+#include "fullMatrix.h"
 #include "GmshMessage.h"
 
 //#if defined(_MSC_VER)
@@ -39,7 +39,7 @@ extern "C" {
 }
 
 template<> 
-void gmshMatrix<double>::mult(const gmshMatrix<double> &b, gmshMatrix<double> &c)
+void fullMatrix<double>::mult(const fullMatrix<double> &b, fullMatrix<double> &c)
 {
   int M = c.size1(), N = c.size2(), K = _c;
   int LDA = _r, LDB = b.size1(), LDC = c.size1();
@@ -49,8 +49,8 @@ void gmshMatrix<double>::mult(const gmshMatrix<double> &b, gmshMatrix<double> &c
 }
 
 template<> 
-void gmshMatrix<std::complex<double> >::mult(const gmshMatrix<std::complex<double> > &b, 
-                                             gmshMatrix<std::complex<double> > &c)
+void fullMatrix<std::complex<double> >::mult(const fullMatrix<std::complex<double> > &b, 
+                                             fullMatrix<std::complex<double> > &c)
 {
   int M = c.size1(), N = c.size2(), K = _c;
   int LDA = _r, LDB = b.size1(), LDC = c.size1();
@@ -60,7 +60,7 @@ void gmshMatrix<std::complex<double> >::mult(const gmshMatrix<std::complex<doubl
 }
 
 template<> 
-void gmshMatrix<double>::gemm(gmshMatrix<double> &a, gmshMatrix<double> &b, 
+void fullMatrix<double>::gemm(fullMatrix<double> &a, fullMatrix<double> &b, 
                               double alpha, double beta)
 {
   int M = size1(), N = size2(), K = a.size2();
@@ -70,8 +70,8 @@ void gmshMatrix<double>::gemm(gmshMatrix<double> &a, gmshMatrix<double> &b,
 }
 
 template<> 
-void gmshMatrix<std::complex<double> >::gemm(gmshMatrix<std::complex<double> > &a, 
-                                             gmshMatrix<std::complex<double> > &b, 
+void fullMatrix<std::complex<double> >::gemm(fullMatrix<std::complex<double> > &a, 
+                                             fullMatrix<std::complex<double> > &b, 
                                              std::complex<double> alpha, 
                                              std::complex<double> beta)
 {
@@ -82,7 +82,7 @@ void gmshMatrix<std::complex<double> >::gemm(gmshMatrix<std::complex<double> > &
 }
 
 template<> 
-void gmshMatrix<double>::mult(const gmshVector<double> &x, gmshVector<double> &y)
+void fullMatrix<double>::mult(const fullVector<double> &x, fullVector<double> &y)
 {
   int M = _r, N = _c, LDA = _r, INCX = 1, INCY = 1;
   double alpha = 1., beta = 0.;
@@ -91,8 +91,8 @@ void gmshMatrix<double>::mult(const gmshVector<double> &x, gmshVector<double> &y
 }
 
 template<> 
-void gmshMatrix<std::complex<double> >::mult(const gmshVector<std::complex<double> > &x, 
-                                             gmshVector<std::complex<double> > &y)
+void fullMatrix<std::complex<double> >::mult(const fullVector<std::complex<double> > &x, 
+                                             fullVector<std::complex<double> > &y)
 {
   int M = _r, N = _c, LDA = _r, INCX = 1, INCY = 1;
   std::complex<double> alpha = 1., beta = 0.;
@@ -123,7 +123,7 @@ extern "C" {
 }
 
 template<> 
-bool gmshMatrix<double>::invertInPlace()
+bool fullMatrix<double>::invertInPlace()
 {
   int N = size1(), nrhs = N, lda = N, ldb = N, info;
   int *ipiv = new int[N];
@@ -148,8 +148,8 @@ bool gmshMatrix<double>::invertInPlace()
 
 
 template<> 
-bool gmshMatrix<double>::eig(gmshMatrix<double> &VL, gmshVector<double> &DR,
-                             gmshVector<double> &DI, gmshMatrix<double> &VR,
+bool fullMatrix<double>::eig(fullMatrix<double> &VL, fullVector<double> &DR,
+                             fullVector<double> &DI, fullMatrix<double> &VR,
                              bool sortRealPart)
 {
   int N = size1(), info;
@@ -193,7 +193,7 @@ bool gmshMatrix<double>::eig(gmshMatrix<double> &VL, gmshVector<double> &DR,
 }
 
 template<> 
-bool gmshMatrix<double>::lu_solve(const gmshVector<double> &rhs, gmshVector<double> &result)
+bool fullMatrix<double>::lu_solve(const fullVector<double> &rhs, fullVector<double> &result)
 {
   int N = size1(), nrhs = 1, lda = N, ldb = N, info;
   int *ipiv = new int[N];
@@ -209,7 +209,7 @@ bool gmshMatrix<double>::lu_solve(const gmshVector<double> &rhs, gmshVector<doub
 }
 
 template<>
-bool gmshMatrix<double>::invert(gmshMatrix<double> &result)
+bool fullMatrix<double>::invert(fullMatrix<double> &result)
 {
   int M = size1(), N = size2(), lda = size1(), info;
   int *ipiv = new int[std::min(M, N)];
@@ -231,9 +231,9 @@ bool gmshMatrix<double>::invert(gmshMatrix<double> &result)
 }
 
 template<> 
-double gmshMatrix<double>::determinant() const
+double fullMatrix<double>::determinant() const
 {
-  gmshMatrix<double> tmp(*this);
+  fullMatrix<double> tmp(*this);
   int M = size1(), N = size2(), lda = size1(), info;
   int *ipiv = new int[std::min(M, N)];
   F77NAME(dgetrf)(&M, &N, tmp._data, &lda, ipiv, &info);
@@ -253,12 +253,12 @@ double gmshMatrix<double>::determinant() const
 }
 
 template<> 
-bool gmshMatrix<double>::svd(gmshMatrix<double> &V, gmshVector<double> &S)
+bool fullMatrix<double>::svd(fullMatrix<double> &V, fullVector<double> &S)
 {
-  gmshMatrix<double> VT(V.size2(), V.size1());
+  fullMatrix<double> VT(V.size2(), V.size1());
   int M = size1(), N = size2(), LDA = size1(), LDVT = VT.size1(), info;
   int LWORK = std::max(3 * std::min(M, N) + std::max(M, N), 5 * std::min(M, N));
-  gmshVector<double> WORK(LWORK);
+  fullVector<double> WORK(LWORK);
   F77NAME(dgesvd)("O", "A", &M, &N, _data, &LDA, S._data, _data, &LDA,
                   VT._data, &LDVT, WORK._data, &LWORK, &info);
   V = VT.transpose();
diff --git a/Numeric/GmshMatrix.h b/Numeric/fullMatrix.h
similarity index 77%
rename from Numeric/GmshMatrix.h
rename to Numeric/fullMatrix.h
index f8604f1312e413349aaf451ec78466c3b9a31ea3..982a86dc17373729d29adfbe5d5ad82c1ebd33b7 100644
--- a/Numeric/GmshMatrix.h
+++ b/Numeric/fullMatrix.h
@@ -11,27 +11,27 @@
 #include "GmshConfig.h"
 #include "GmshMessage.h"
 
-template <class scalar> class gmshMatrix;
+template <class scalar> class fullMatrix;
 
 template <class scalar>
-class gmshVector
+class fullVector
 {
  private:
   int _r;
   scalar *_data;
-  friend class gmshMatrix<scalar>;
+  friend class fullMatrix<scalar>;
  public:
-  gmshVector(int r) : _r(r)
+  fullVector(int r) : _r(r)
   {
     _data = new scalar[_r];
     scale(0.);
   }
-  gmshVector(const gmshVector<scalar> &other) : _r(other._r)
+  fullVector(const fullVector<scalar> &other) : _r(other._r)
   {
     _data = new scalar[_r];
     for(int i = 0; i < _r; ++i) _data[i] = other._data[i];
   }
-  ~gmshVector() { if(_data) delete [] _data; }
+  ~fullVector() { if(_data) delete [] _data; }
   inline scalar operator () (int i) const
   {
     return _data[i];
@@ -55,7 +55,7 @@ class gmshVector
       for(int i = 0; i < _r; ++i) _data[i] *= s;
   }
 
-  inline scalar operator *(const gmshVector<scalar> & other)
+  inline scalar operator *(const fullVector<scalar> & other)
   {
     scalar s = 0.0;
     for(int i = 0; i < _r; ++i) s += _data[i]*other._data[i];
@@ -73,27 +73,27 @@ class gmshVector
 };
 
 template <class scalar>
-class gmshMatrix
+class fullMatrix
 {
  private:
   int _r, _c;
   scalar *_data;
  public:
-  gmshMatrix(int r, int c) : _r(r), _c(c)
+  fullMatrix(int r, int c) : _r(r), _c(c)
   {
     _data = new scalar[_r * _c];
     scale(0.);
   }
-  gmshMatrix(const gmshMatrix<scalar> &other) : _r(other._r), _c(other._c)
+  fullMatrix(const fullMatrix<scalar> &other) : _r(other._r), _c(other._c)
   {
     _data = new scalar[_r * _c];
     gM_memcpy(other);
   }
-  gmshMatrix() : _r(0), _c(0), _data(0) {}
-  ~gmshMatrix() { if(_data) delete [] _data; }
+  fullMatrix() : _r(0), _c(0), _data(0) {}
+  ~fullMatrix() { if(_data) delete [] _data; }
   inline int size1() const { return _r; }
   inline int size2() const { return _c; }
-  gmshMatrix<scalar> & operator = (const gmshMatrix<scalar> &other)
+  fullMatrix<scalar> & operator = (const fullMatrix<scalar> &other)
   {
     if(this != &other){
       _r = other._r; 
@@ -103,7 +103,7 @@ class gmshMatrix
     }
     return *this;
   }
-  void gM_memcpy(const gmshMatrix<scalar> &other)
+  void gM_memcpy(const fullMatrix<scalar> &other)
   {
     for(int i = 0; i < _r * _c; ++i) _data[i] = other._data[i];
   }
@@ -115,14 +115,14 @@ class gmshMatrix
   {
     return _data[i + _r * j];
   }
-  void copy(const gmshMatrix<scalar> &a, int i0, int ni, int j0, int nj, 
+  void copy(const fullMatrix<scalar> &a, int i0, int ni, int j0, int nj, 
             int desti0, int destj0)
   {
     for(int i = i0, desti = desti0; i < i0 + ni; i++, desti++)
       for(int j = j0, destj = destj0; j < j0 + nj; j++, destj++)
         (*this)(desti, destj) = a(i, j);
   }
-  void mult(const gmshMatrix<scalar> &b, gmshMatrix<scalar> &c)
+  void mult(const fullMatrix<scalar> &b, fullMatrix<scalar> &c)
 #if !defined(HAVE_BLAS)
   {
     c.scale(0.);
@@ -133,11 +133,11 @@ class gmshMatrix
   }
 #endif
   ;
-  void gemm(gmshMatrix<scalar> &a, gmshMatrix<scalar> &b, 
+  void gemm(fullMatrix<scalar> &a, fullMatrix<scalar> &b, 
             scalar alpha=1., scalar beta=1.)
 #if !defined(HAVE_BLAS)
   {
-    gmshMatrix<scalar> temp(a.size1(), b.size2());
+    fullMatrix<scalar> temp(a.size1(), b.size2());
     a.mult(b, temp);
     temp.scale(alpha);
     scale(beta);
@@ -160,13 +160,13 @@ class gmshMatrix
   {
     for(int i = 0; i < _r * _c; ++i) _data[i] += a;
   }
-  inline void add(const gmshMatrix<scalar> &m) 
+  inline void add(const fullMatrix<scalar> &m) 
   {
     for(int i = 0; i < size1(); i++)
       for(int j = 0; j < size2(); j++)
         (*this)(i, j) += m(i, j);
   }
-  void mult(const gmshVector<scalar> &x, gmshVector<scalar> &y)
+  void mult(const fullVector<scalar> &x, fullVector<scalar> &y)
 #if !defined(HAVE_BLAS)
   {
     y.scale(0.);
@@ -176,9 +176,9 @@ class gmshMatrix
   }
 #endif
   ;
-  inline gmshMatrix<scalar> transpose()
+  inline fullMatrix<scalar> transpose()
   {
-    gmshMatrix<scalar> T(size2(), size1());
+    fullMatrix<scalar> T(size2(), size1());
     for(int i = 0; i < size1(); i++)
       for(int j = 0; j < size2(); j++)
         T(j, i) = (*this)(i, j);
@@ -197,7 +197,7 @@ class gmshMatrix
         _data[j + _r * i] = t;
       }
   }
-  bool lu_solve(const gmshVector<scalar> &rhs, gmshVector<scalar> &result)
+  bool lu_solve(const fullVector<scalar> &rhs, fullVector<scalar> &result)
 #if !defined(HAVE_LAPACK)
   {
     Msg::Error("LU factorization requires LAPACK");
@@ -213,10 +213,10 @@ class gmshMatrix
   }
 #endif
   ;
-  bool eig(gmshMatrix<scalar> &VL, // left eigenvectors 
-           gmshVector<double> &DR, // Real part of eigenvalues
-           gmshVector<double> &DI, // Im part of eigen
-           gmshMatrix<scalar> &VR,
+  bool eig(fullMatrix<scalar> &VL, // left eigenvectors 
+           fullVector<double> &DR, // Real part of eigenvalues
+           fullVector<double> &DI, // Im part of eigen
+           fullMatrix<scalar> &VR,
            bool sortRealPart=false) // if true: sorted from min 'DR' to max 'DR'
 #if !defined(HAVE_LAPACK)
   {
@@ -225,7 +225,7 @@ class gmshMatrix
   }
 #endif
   ;
-  bool invert(gmshMatrix<scalar> &result)
+  bool invert(fullMatrix<scalar> &result)
 #if !defined(HAVE_LAPACK)
   {
     Msg::Error("LU factorization requires LAPACK");
@@ -233,11 +233,11 @@ class gmshMatrix
   }
 #endif
   ;
-  gmshMatrix<scalar> cofactor(int i, int j) const 
+  fullMatrix<scalar> cofactor(int i, int j) const 
   {
     int ni = size1();
     int nj = size2();
-    gmshMatrix<scalar> cof(ni - 1, nj - 1);
+    fullMatrix<scalar> cof(ni - 1, nj - 1);
     for(int I = 0; I < ni; I++){
       for(int J = 0; J < nj; J++){
         if(J != j && I != i)
@@ -254,7 +254,7 @@ class gmshMatrix
   }
 #endif
   ;
-  bool svd(gmshMatrix<scalar> &V, gmshVector<scalar> &S)
+  bool svd(fullMatrix<scalar> &V, fullVector<scalar> &S)
 #if !defined(HAVE_LAPACK)
   {
     Msg::Error("Singular value decomposition requires LAPACK");
diff --git a/Numeric/functionSpace.cpp b/Numeric/functionSpace.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..60dbf13ce84f542c02218038f5792e7e846d2723
--- /dev/null
+++ b/Numeric/functionSpace.cpp
@@ -0,0 +1,672 @@
+// 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>.
+//
+// Contributor(s):
+//   Koen Hillewaert
+//
+
+#include "GmshDefines.h"
+#include "GmshMessage.h"
+#include "functionSpace.h"
+
+static fullMatrix<double> generate1DMonomials(int order)
+{
+  fullMatrix<double> monomials(order + 1, 1);
+  for (int i = 0; i < order + 1; i++) monomials(i, 0) = i;
+  return monomials;
+}
+
+static fullMatrix<double> generate1DPoints(int order)
+{
+  fullMatrix<double> line(order + 1, 1);
+  line(0, 0) = -1.;
+  line(1, 0) =  1.;
+  double dd = 2. / order;
+  for (int i = 2; i < order + 1; i++) line(i, 0) = -1. + dd * (i - 1);
+  return line;
+}
+
+static fullMatrix<double> generatePascalTriangle(int order)
+{
+  fullMatrix<double> monomials((order + 1) * (order + 2) / 2, 2);
+  int index = 0;
+  for (int i = 0; i <= order; i++) {
+    for (int j = 0; j <= i; j++) {
+      monomials(index, 0) = i - j;
+      monomials(index, 1) = j;
+      index++;
+    }
+  }
+  return monomials;
+}
+
+// generate the exterior hull of the Pascal triangle for Serendipity element
+
+static fullMatrix<double> generatePascalSerendipityTriangle(int order)
+{
+  fullMatrix<double> monomials(3 * order, 2);
+
+  monomials(0, 0) = 0;
+  monomials(0, 1) = 0;
+  
+  int index = 1;
+  for (int i = 1; i <= order; i++) {
+    if (i == order) {
+      for (int j = 0; j <= i; j++) {
+        monomials(index, 0) = i - j;
+        monomials(index, 1) = j;
+        index++;
+      }
+    }
+    else {
+      monomials(index, 0) = i;
+      monomials(index, 1) = 0;
+      index++;
+      monomials(index, 0) = 0;
+      monomials(index, 1) = i;
+      index++;
+    }
+  }
+  return monomials;
+}
+
+// generate the monomials subspace of all monomials of order exactly == p
+
+static fullMatrix<double> generateMonomialSubspace(int dim, int p)
+{
+  fullMatrix<double> monomials;
+  
+  switch (dim) {
+  case 1:
+    monomials = fullMatrix<double>(1, 1);
+    monomials(0, 0) = p;
+    break;
+  case 2:
+    monomials = fullMatrix<double>(p + 1, 2);
+    for (int k = 0; k <= p; k++) {
+      monomials(k, 0) = p - k;
+      monomials(k, 1) = k;
+    }
+    break;
+  case 3:
+    monomials = fullMatrix<double>((p + 1) * (p + 2) / 2, 3);
+    int index = 0;
+    for (int i = 0; i <= p; i++) {
+      for (int k = 0; k <= p - i; k++) {
+        monomials(index, 0) = p - i - k;
+        monomials(index, 1) = k;
+        monomials(index, 2) = i;
+        index++;
+      }
+    }
+    break;
+  }
+  return monomials;
+}
+
+// generate external hull of the Pascal tetrahedron
+
+static fullMatrix<double> generatePascalSerendipityTetrahedron(int order)
+{
+  int nbMonomials = 4 + 6 * std::max(0, order - 1) + 
+    4 * std::max(0, (order - 2) * (order - 1) / 2);
+  fullMatrix<double> monomials(nbMonomials, 3);
+
+  monomials.set_all(0);
+  int index = 1;
+  for (int p = 1; p < order; p++) {
+    for (int i = 0; i < 3; i++) {
+      int j = (i + 1) % 3;
+      int k = (i + 2) % 3;
+      for (int ii = 0; ii < p; ii++) {
+        monomials(index, i) = p - ii;
+        monomials(index, j) = ii;
+        monomials(index, k) = 0;
+        index++;
+      }
+    }
+  }
+  fullMatrix<double> monomialsMaxOrder = generateMonomialSubspace(3, order);
+  int nbMaxOrder = monomialsMaxOrder.size1();
+  monomials.copy(monomialsMaxOrder, 0, nbMaxOrder, 0, 3, index, 0);
+  return monomials;
+}
+
+// generate Pascal tetrahedron
+
+static fullMatrix<double> generatePascalTetrahedron(int order)
+{
+  int nbMonomials = (order + 1) * (order + 2) * (order + 3) / 6;
+
+  fullMatrix<double> monomials(nbMonomials, 3);
+
+  int index = 0;
+  for (int p = 0; p <= order; p++) {
+    fullMatrix<double> monOrder = generateMonomialSubspace(3, p);
+    int nb = monOrder.size1();
+    monomials.copy(monOrder, 0, nb, 0, 3, index, 0);
+    index += nb;
+  }
+
+  return monomials;
+}  
+
+static int nbdoftriangle(int order) { return (order + 1) * (order + 2) / 2; }
+//static int nbdoftriangleserendip(int order) { return 3 * order; }
+
+//KH : caveat : node coordinates are not yet coherent with node numbering associated
+//              to numbering of principal vertices of face !!!!
+
+// uv surface - orientation v0-v2-v1
+static void nodepositionface0(int order, double *u, double *v, double *w)
+{
+  int ndofT = nbdoftriangle(order);
+  if (order == 0) { u[0] = 0.; v[0] = 0.; w[0] = 0.; return; }
+  
+  u[0]= 0.;    v[0]= 0.;    w[0] = 0.;
+  u[1]= 0.;    v[1]= order; w[1] = 0.;
+  u[2]= order; v[2]= 0.;    w[2] = 0.;
+
+  // edges
+  for (int k = 0; k < (order - 1); k++){
+    u[3 + k] = 0.; 
+    v[3 + k] = k + 1; 
+    w[3 + k] = 0.;
+
+    u[3 + order - 1 + k] = k + 1;
+    v[3 + order - 1 + k] = order - 1 - k ; 
+    w[3 + order - 1 + k] = 0.;
+
+    u[3 + 2 * (order - 1) + k] = order - 1 - k;
+    v[3 + 2 * (order - 1) + k] = 0.;
+    w[3 + 2 * (order - 1) + k] = 0.;
+  }
+  
+  if (order > 2){
+    int nbdoftemp = nbdoftriangle(order - 3);
+    nodepositionface0(order - 3, &u[3 + 3 * (order - 1)], &v[3 + 3 * (order - 1)], 
+                      &w[3 + 3* (order - 1)]);
+    for (int k = 0; k < nbdoftemp; k++){
+      u[3 + k + 3 * (order - 1)] = u[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
+      v[3 + k + 3 * (order - 1)] = v[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
+      w[3 + k + 3 * (order - 1)] = w[3 + k + 3 * (order - 1)] * (order - 3);
+    }
+  }
+  for (int k = 0; k < ndofT; k++){
+    u[k] = u[k] / order;
+    v[k] = v[k] / order;
+    w[k] = w[k] / order;
+  }
+}
+
+// uw surface - orientation v0-v1-v3
+static void nodepositionface1(int order, double *u, double *v, double *w)
+{
+   int ndofT = nbdoftriangle(order);
+   if (order == 0) { u[0] = 0.; v[0] = 0.; w[0] = 0.; return; }
+   
+   u[0] = 0.;    v[0]= 0.;  w[0] = 0.;
+   u[1] = order; v[1]= 0.;  w[1] = 0.;
+   u[2] = 0.;    v[2]= 0.;  w[2] = order;
+   // edges
+   for (int k = 0; k < (order - 1); k++){
+     u[3 + k] = k + 1; 
+     v[3 + k] = 0.; 
+     w[3 + k] = 0.;
+     
+     u[3 + order - 1 + k] = order - 1 - k;
+     v[3 + order - 1 + k] = 0.;
+     w[3 + order - 1+ k ] = k + 1; 
+     
+     u[3 + 2 * (order - 1) + k] = 0. ;
+     v[3 + 2 * (order - 1) + k] = 0.;
+     w[3 + 2 * (order - 1) + k] = order - 1 - k; 
+   }
+   if (order > 2){
+     int nbdoftemp = nbdoftriangle(order - 3);
+     nodepositionface1(order - 3, &u[3 + 3 * (order - 1)], &v[3 + 3 * (order -1 )],
+                       &w[3 + 3 * (order - 1)]);
+     for (int k = 0; k < nbdoftemp; k++){
+       u[3 + k + 3 * (order - 1)] = u[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
+       v[3 + k + 3 * (order - 1)] = v[3 + k + 3 * (order - 1)] * (order - 3);
+       w[3 + k + 3 * (order - 1)] = w[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
+     }
+   }
+   for (int k = 0; k < ndofT; k++){
+     u[k] = u[k] / order;
+     v[k] = v[k] / order;
+     w[k] = w[k] / order;
+   }
+}
+
+// vw surface - orientation v0-v3-v2
+static void nodepositionface2(int order, double *u, double *v, double *w)
+{
+   int ndofT = nbdoftriangle(order);
+   if (order == 0) { u[0] = 0.; v[0] = 0.; return; }
+   
+   u[0]= 0.; v[0]= 0.;    w[0] = 0.;
+   u[1]= 0.; v[1]= 0.;    w[1] = order;
+   u[2]= 0.; v[2]= order; w[2] = 0.;
+   // edges
+   for (int k = 0; k < (order - 1); k++){
+     
+     u[3 + k] = 0.;
+     v[3 + k] = 0.;
+     w[3 + k] = k + 1;
+
+     u[3 + order - 1 + k] = 0.;
+     v[3 + order - 1 + k] = k + 1;
+     w[3 + order - 1 + k] = order - 1 - k;
+     
+     u[3 + 2 * (order - 1) + k] = 0.;
+     v[3 + 2 * (order - 1) + k] = order - 1 - k;
+     w[3 + 2 * (order - 1) + k] = 0.;
+   }
+   if (order > 2){
+     int nbdoftemp = nbdoftriangle(order - 3);
+     nodepositionface2(order - 3, &u[3 + 3 * (order - 1)], &v[3 + 3 * (order - 1)],
+                       &w[3 + 3 * (order - 1)]);
+     for (int k = 0; k < nbdoftemp; k++){
+       u[3 + k + 3 * (order - 1)] = u[3 + k + 3 * (order - 1)] * (order - 3);
+       v[3 + k + 3 * (order - 1)] = v[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
+       w[3 + k + 3 * (order - 1)] = w[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
+     }
+   }
+   for (int k = 0; k < ndofT; k++){
+     u[k] = u[k] / order;
+     v[k] = v[k] / order;
+     w[k] = w[k] / order;
+   }
+}
+
+// uvw surface  - orientation v3-v1-v2
+static void nodepositionface3(int order,  double *u,  double *v,  double *w)
+{
+   int ndofT = nbdoftriangle(order);
+   if (order == 0) { u[0] = 0.; v[0] = 0.; w[0] = 0.; return; }
+   
+   u[0]= 0.;    v[0]= 0.;    w[0] = order;
+   u[1]= order; v[1]= 0.;    w[1] = 0.;
+   u[2]= 0.;    v[2]= order; w[2] = 0.;
+   // edges
+   for (int k = 0; k < (order - 1); k++){
+
+     u[3 + k] = k + 1;
+     v[3 + k] = 0.;
+     w[3 + k] = order - 1 - k;
+
+     u[3 + order - 1 + k] = order - 1 - k;
+     v[3 + order - 1 + k] = k + 1;
+     w[3 + order - 1 + k] = 0.;
+     
+     u[3 + 2 * (order - 1) + k] = 0.;
+     v[3 + 2 * (order - 1) + k] = order - 1 - k; 
+     w[3 + 2 * (order - 1) + k] = k + 1;
+   }
+   if (order > 2){
+     int nbdoftemp = nbdoftriangle(order - 3);
+     nodepositionface3(order - 3, &u[3 + 3 * (order - 1)], &v[3 + 3 * (order - 1)],
+                       &w[3 + 3 * (order - 1)]);
+     for (int k = 0; k < nbdoftemp; k++){
+       u[3 + k + 3 * (order - 1)] = u[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
+       v[3 + k + 3 * (order - 1)] = v[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
+       w[3 + k + 3 * (order - 1)] = w[3 + k + 3 * (order - 1)] * (order - 3) + 1.;
+     }
+   }
+   for (int k = 0; k < ndofT; k++){
+     u[k] = u[k] / order;
+     v[k] = v[k] / order;
+     w[k] = w[k] / order;
+   }
+}
+
+static fullMatrix<double> gmshGeneratePointsTetrahedron(int order, bool serendip) 
+{
+  int nbPoints = 
+    (serendip ?
+     4 +  6 * std::max(0, order - 1) + 4 * std::max(0, (order - 2) * (order - 1) / 2) :
+     (order + 1) * (order + 2) * (order + 3) / 6);
+  
+  fullMatrix<double> point(nbPoints, 3);
+
+  double overOrder = (order == 0 ? 1. : 1. / order);
+
+  point(0, 0) = 0.;
+  point(0, 1) = 0.;
+  point(0, 2) = 0.;
+
+  if (order > 0) {
+    point(1, 0) = order;
+    point(1, 1) = 0;
+    point(1, 2) = 0;
+    
+    point(2, 0) = 0.;
+    point(2, 1) = order;
+    point(2, 2) = 0.;
+    
+    point(3, 0) = 0.;
+    point(3, 1) = 0.;
+    point(3, 2) = order;
+
+    // edges e5 and e6 switched in original version, opposite direction
+    // the template has been defined in table edges_tetra and faces_tetra (MElement.h)
+    
+    if (order > 1) {
+      for (int k = 0; k < (order - 1); k++) {
+        point(4 + k, 0) = k + 1;
+        point(4 +      order - 1  + k, 0) = order - 1 - k;
+        point(4 + 2 * (order - 1) + k, 0) = 0.; 
+        point(4 + 3 * (order - 1) + k, 0) = 0.;
+        // point(4 + 4 * (order - 1) + k, 0) = order - 1 - k;
+        // point(4 + 5 * (order - 1) + k, 0) = 0.;
+        point(4 + 4 * (order - 1) + k, 0) = 0.;
+        point(4 + 5 * (order - 1) + k, 0) = k+1;
+        
+        point(4 + k, 1) = 0.;
+        point(4 +      order - 1  + k, 1) = k + 1;
+        point(4 + 2 * (order - 1) + k, 1) = order - 1 - k; 
+        point(4 + 3 * (order - 1) + k, 1) = 0.;
+        //         point(4 + 4 * (order - 1) + k, 1) = 0.;
+        //         point(4 + 5 * (order - 1) + k, 1) = order - 1 - k;
+        point(4 + 4 * (order - 1) + k, 1) = k+1;
+        point(4 + 5 * (order - 1) + k, 1) = 0.;
+        
+        point(4 + k, 2) = 0.;
+        point(4 +      order - 1  + k, 2) = 0.;
+        point(4 + 2 * (order - 1) + k, 2) = 0.; 
+        point(4 + 3 * (order - 1) + k, 2) = order - 1 - k;
+        point(4 + 4 * (order - 1) + k, 2) = order - 1 - k;
+        point(4 + 5 * (order - 1) + k, 2) = order - 1 - k;
+      }
+      
+      if (order > 2) {
+        int ns = 4 + 6 * (order - 1);
+        int nbdofface = nbdoftriangle(order - 3);
+        
+        double *u = new double[nbdofface];
+        double *v = new double[nbdofface];
+        double *w = new double[nbdofface];
+        
+        nodepositionface0(order - 3, u, v, w);
+
+        // u-v plane
+        
+        for (int i = 0; i < nbdofface; i++){
+          point(ns + i, 0) = u[i] * (order - 3) + 1.;
+          point(ns + i, 1) = v[i] * (order - 3) + 1.;
+          point(ns + i, 2) = w[i] * (order - 3);
+        }
+        
+        ns = ns + nbdofface;
+
+        // u-w plane
+        
+        nodepositionface1(order - 3, u, v, w);
+        
+        for (int i=0; i < nbdofface; i++){
+          point(ns + i, 0) = u[i] * (order - 3) + 1.;
+          point(ns + i, 1) = v[i] * (order - 3) ;
+          point(ns + i, 2) = w[i] * (order - 3) + 1.;
+        }
+
+        // v-w plane 
+        
+        ns = ns + nbdofface;
+
+        nodepositionface2(order - 3, u, v, w);
+        
+        for (int i = 0; i < nbdofface; i++){
+          point(ns + i, 0) = u[i] * (order - 3);
+          point(ns + i, 1) = v[i] * (order - 3) + 1.;
+          point(ns + i, 2) = w[i] * (order - 3) + 1.;
+        }
+
+        // u-v-w plane 
+        
+        ns = ns + nbdofface;
+
+        nodepositionface3(order - 3, u, v, w);
+
+        for (int i = 0; i < nbdofface; i++){
+          point(ns + i, 0) = u[i] * (order - 3) + 1.;
+          point(ns + i, 1) = v[i] * (order - 3) + 1.;
+          point(ns + i, 2) = w[i] * (order - 3) + 1.;
+        }
+
+        ns = ns + nbdofface;
+
+        delete [] u;
+        delete [] v;
+        delete [] w;
+        
+        if (!serendip && order > 3) {
+  
+          fullMatrix<double> interior = gmshGeneratePointsTetrahedron(order - 4, false);
+          for (int k = 0; k < interior.size1(); k++) {
+            point(ns + k, 0) = 1. + interior(k, 0) * (order - 4);
+            point(ns + k, 1) = 1. + interior(k, 1) * (order - 4);
+            point(ns + k, 2) = 1. + interior(k, 2) * (order - 4);
+          }
+        }
+      }
+    }
+  }
+  
+  point.scale(overOrder);  
+  return point;
+}
+
+static fullMatrix<double> gmshGeneratePointsTriangle(int order, bool serendip) 
+{
+  int nbPoints = serendip ? 3 * order : (order + 1) * (order + 2) / 2;
+  fullMatrix<double> point(nbPoints, 2);
+  
+  point(0, 0) = 0;
+  point(0, 1) = 0;
+  
+  double dd = 1. / order;
+
+  if (order > 0) {
+    point(1, 0) = 1;
+    point(1, 1) = 0;
+    point(2, 0) = 0;
+    point(2, 1) = 1;
+    
+    int index = 3;
+    
+    if (order > 1) {
+      
+      double ksi = 0;
+      double eta = 0;
+      
+      for (int i = 0; i < order - 1; i++, index++) {
+        ksi += dd;
+        point(index, 0) = ksi;
+        point(index, 1) = eta;
+      }
+      
+      ksi = 1.;
+      
+      for (int i = 0; i < order - 1; i++, index++) {
+        ksi -= dd;
+        eta += dd;
+        point(index, 0) = ksi;
+        point(index, 1) = eta;
+      } 
+        
+      eta = 1.;
+      ksi = 0.;
+
+      for (int i = 0; i < order - 1; i++, index++) {
+        eta -= dd;
+        point(index, 0) = ksi;
+        point(index, 1) = eta;
+      } 
+
+      if (order > 2 && !serendip) {
+        fullMatrix<double> inner = gmshGeneratePointsTriangle(order - 3, serendip);
+        inner.scale(1. - 3. * dd);
+        inner.add(dd);
+        point.copy(inner, 0, nbPoints - index, 0, 2, index, 0);
+      }
+    }
+  }
+  return point;  
+}
+
+static fullMatrix<double> generateLagrangeMonomialCoefficients
+  (const fullMatrix<double>& monomial, const fullMatrix<double>& point) 
+{
+  if(monomial.size1() != point.size1() || monomial.size2() != point.size2()){
+    Msg::Fatal("Wrong sizes for Lagrange coefficients generation");
+    return fullMatrix<double>(1, 1);
+  }
+  
+  int ndofs = monomial.size1();
+  int dim = monomial.size2();
+  
+  fullMatrix<double> Vandermonde(ndofs, ndofs);
+  for (int i = 0; i < ndofs; i++) {
+    for (int j = 0; j < ndofs; j++) {
+      double dd = 1.;
+      for (int k = 0; k < dim; k++) dd *= pow(point(j, k), monomial(i, k));
+      Vandermonde(i, j) = dd;
+    }
+  }
+
+  fullMatrix<double> coefficient(ndofs, ndofs);
+  Vandermonde.invert(coefficient);
+  return coefficient;
+}
+
+std::map<int, functionSpace> functionSpaces::fs;
+
+const functionSpace &functionSpaces::find(int tag) 
+{
+  std::map<int, functionSpace>::const_iterator it = fs.find(tag);
+  if (it != fs.end()) return it->second;
+  
+  functionSpace F;
+  
+  switch (tag){
+  case MSH_PNT:
+    F.monomials = generate1DMonomials(0);
+    F.points    = generate1DPoints(0);
+    break;
+  case MSH_LIN_2 :
+    F.monomials = generate1DMonomials(1);
+    F.points    = generate1DPoints(1);
+    break;
+  case MSH_LIN_3 :
+    F.monomials = generate1DMonomials(2);
+    F.points    = generate1DPoints(2);
+    break;
+  case MSH_LIN_4:
+    F.monomials = generate1DMonomials(3);
+    F.points    = generate1DPoints(3);
+    break;
+  case MSH_LIN_5:
+    F.monomials = generate1DMonomials(4);
+    F.points    = generate1DPoints(4);
+    break;
+  case MSH_LIN_6:
+    F.monomials = generate1DMonomials(5);
+    F.points    = generate1DPoints(5);
+    break;  
+  case MSH_TRI_3 :
+    F.monomials = generatePascalTriangle(1);
+    F.points =    gmshGeneratePointsTriangle(1, false);
+    break;
+  case MSH_TRI_6 :
+    F.monomials = generatePascalTriangle(2);
+    F.points =    gmshGeneratePointsTriangle(2, false);
+    break;
+  case MSH_TRI_9 :
+    F.monomials = generatePascalSerendipityTriangle(3);
+    F.points =    gmshGeneratePointsTriangle(3, true);
+    break;
+  case MSH_TRI_10 :
+    F.monomials = generatePascalTriangle(3);
+    F.points =    gmshGeneratePointsTriangle(3, false);
+    break;
+  case MSH_TRI_12 :
+    F.monomials = generatePascalSerendipityTriangle(4);
+    F.points =    gmshGeneratePointsTriangle(4, true);
+    break;
+  case MSH_TRI_15 :
+    F.monomials = generatePascalTriangle(4);
+    F.points =    gmshGeneratePointsTriangle(4, false);
+    break;
+  case MSH_TRI_15I :
+    F.monomials = generatePascalSerendipityTriangle(5);
+    F.points =    gmshGeneratePointsTriangle(5, true);
+    break;
+  case MSH_TRI_21 :
+    F.monomials = generatePascalTriangle(5);
+    F.points =    gmshGeneratePointsTriangle(5, false);
+    break;
+  case MSH_TET_4 :
+    F.monomials = generatePascalTetrahedron(1);
+    F.points =    gmshGeneratePointsTetrahedron(1, false);
+    break;
+  case MSH_TET_10 :
+    F.monomials = generatePascalTetrahedron(2);
+    F.points =    gmshGeneratePointsTetrahedron(2, false);
+    break;
+  case MSH_TET_20 :
+    F.monomials = generatePascalTetrahedron(3);
+    F.points =    gmshGeneratePointsTetrahedron(3, false);
+    break;
+  case MSH_TET_35 :
+    F.monomials = generatePascalTetrahedron(4);
+    F.points =    gmshGeneratePointsTetrahedron(4, false);
+    break;
+  case MSH_TET_34 :
+    F.monomials = generatePascalSerendipityTetrahedron(4);
+    F.points =    gmshGeneratePointsTetrahedron(4, true);
+    break;
+  case MSH_TET_52 :
+    F.monomials = generatePascalSerendipityTetrahedron(5);
+    F.points =    gmshGeneratePointsTetrahedron(5, true);
+    break;
+  case MSH_TET_56 :
+    F.monomials = generatePascalTetrahedron(5);
+    F.points =    gmshGeneratePointsTetrahedron(5, false);
+    break;
+  default :
+    Msg::Error("Unknown function space %d: reverting to TET_4", tag);
+    F.monomials = generatePascalTetrahedron(1);
+    F.points =    gmshGeneratePointsTetrahedron(1, false);
+    break;
+  }  
+  F.coefficients = generateLagrangeMonomialCoefficients(F.monomials, F.points);
+  fs.insert(std::make_pair(tag, F));
+  return fs[tag];
+}
+
+std::map<std::pair<int, int>, fullMatrix<double> > functionSpaces::injector;
+
+const fullMatrix<double> &functionSpaces::findInjector(int tag1, int tag2)
+{
+  std::pair<int,int> key(tag1,tag2);
+  std::map<std::pair<int, int>, fullMatrix<double> >::const_iterator it = injector.find(key);
+  if (it != injector.end()) return it->second;
+
+  const functionSpace& fs1 = find(tag1);
+  const functionSpace& fs2 = find(tag2);
+
+  fullMatrix<double> inj(fs1.points.size1(),fs2.points.size1());
+  
+  double sf[256];
+  
+  for (int i = 0; i < fs1.points.size1(); i++) {
+    fs2.f(fs1.points(i, 0), fs1.points(i, 1), fs1.points(i, 2), sf);
+    for (int j = 0; j < fs2.points.size1(); j++) inj(i, j) = sf[j];
+  }
+
+  injector.insert(std::make_pair(key, inj));
+  return injector[key];
+}
diff --git a/Numeric/functionSpace.h b/Numeric/functionSpace.h
new file mode 100644
index 0000000000000000000000000000000000000000..9ba14b7d84ca57c12faf1a762819c1b7c3863208
--- /dev/null
+++ b/Numeric/functionSpace.h
@@ -0,0 +1,107 @@
+// 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 _FUNCTION_SPACE_H_
+#define _FUNCTION_SPACE_H_
+
+#include <math.h>
+#include <map>
+#include "fullMatrix.h"
+
+struct functionSpace 
+{
+  fullMatrix<double> points;
+  fullMatrix<double> monomials;
+  fullMatrix<double> coefficients;
+  inline void evaluateMonomials(double u, double v, double w, double p[]) const 
+  {
+    for (int j = 0; j < monomials.size1(); j++) {
+      p[j] = pow(u, (int)monomials(j, 0));
+      if (monomials.size2() > 1) p[j] *= pow(v, (int)monomials(j, 1));
+      if (monomials.size2() > 2) p[j] *= pow(w, (int)monomials(j, 2));
+    }
+  }
+  inline void f(double u, double v, double w, double *sf) const
+  {
+    double p[256];
+    evaluateMonomials(u, v, w, p);
+    for (int i = 0; i < coefficients.size1(); i++) {
+      sf[i] = 0;
+      for (int j = 0; j < coefficients.size2(); j++) {
+        sf[i] += coefficients(i, j) * p[j];
+      }
+    }
+  }
+  inline void df(double u, double v, double w, double grads[][3]) const
+  {
+    switch (monomials.size2()) {
+    case 1:
+      for (int i = 0; i < coefficients.size1(); i++){
+        grads[i][0] = 0;
+        grads[i][1] = 0;
+        grads[i][2] = 0;
+        for(int j = 0; j < coefficients.size2(); j++){
+          if ((monomials)(j, 0) > 0)
+            grads[i][0] += (coefficients)(i, j) * 
+              pow(u, (monomials)(j, 0) - 1) * (monomials)(j, 0);
+        }
+      }
+      break;
+    case 2:
+      for (int i = 0; i < coefficients.size1(); i++){
+        grads[i][0] = 0;
+        grads[i][1] = 0;
+        grads[i][2] = 0;
+        for(int j = 0; j < coefficients.size2(); j++){
+          if ((monomials)(j, 0) > 0)
+            grads[i][0] += (coefficients)(i, j) *
+              pow(u, (monomials)(j, 0) - 1) * (monomials)(j, 0) *
+              pow(v, (monomials)(j, 1));
+          if ((monomials)(j, 1) > 0)
+            grads[i][1] += (coefficients)(i, j) *
+              pow(u, (monomials)(j, 0)) *
+              pow(v, (monomials)(j, 1) - 1) * (monomials)(j, 1);
+        }
+      }
+      break;
+    case 3:
+      for (int i = 0; i < coefficients.size1(); i++){
+        grads[i][0] = 0;
+        grads[i][1] = 0;
+        grads[i][2] = 0;
+        for(int j = 0; j < coefficients.size2(); j++){
+          if ((monomials)(j, 0) > 0)
+            grads[i][0] += (coefficients)(i, j) *
+              pow(u, (monomials)(j, 0) - 1) * (monomials)(j, 0) *
+              pow(v, (monomials)(j, 1)) *
+              pow(w, (monomials)(j, 2));
+          if ((monomials)(j, 1) > 0)
+            grads[i][1] += (coefficients)(i, j) *
+              pow(u, (monomials)(j, 0)) *
+              pow(v, (monomials)(j, 1) - 1) * (monomials)(j, 1) *
+              pow(w, (monomials)(j, 2));
+          if ((monomials)(j, 2) > 0)
+            grads[i][2] += (coefficients)(i, j) *
+              pow(u, (monomials)(j, 0)) *
+              pow(v, (monomials)(j, 1)) *
+              pow(w, (monomials)(j, 2) - 1) * (monomials)(j, 2);
+        }
+      }
+      break;
+    }
+  }
+};
+
+class functionSpaces 
+{
+ private:
+  static std::map<int, functionSpace> fs;
+  static std::map<std::pair<int, int>, fullMatrix<double> > injector;
+ public :
+  static const functionSpace &find(int);
+  static const fullMatrix<double> &findInjector(int, int);
+};
+
+#endif
diff --git a/Post/PViewDataGModel.cpp b/Post/PViewDataGModel.cpp
index 629ecf8f0264d598c906cfec2944550903d328af..c82b6eb39635ee862cdbf05ee9f209259c494b54 100644
--- a/Post/PViewDataGModel.cpp
+++ b/Post/PViewDataGModel.cpp
@@ -93,7 +93,7 @@ bool PViewDataGModel::finalize()
 void PViewDataGModel::_addInterpolationMatricesForElement(MElement *e)
 {
   int type = e->getType();
-  const gmshFunctionSpace *fs = e->getFunctionSpace();
+  const functionSpace *fs = e->getFunctionSpace();
   if(fs){
     if(e->getPolynomialOrder() > 1)
       setInterpolationMatrices(type, fs->coefficients, fs->monomials,