diff --git a/CMakeLists.txt b/CMakeLists.txt
index 05fd38f7b36ab98f7a47898f0ad442d27f81b912..dd7ea8784e3b83e31e807ed8b956bb5ff64245c1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -685,6 +685,8 @@ if(ENABLE_MED OR ENABLE_CGNS)
         endif(ZLIB_FOUND)
       endif(NOT HAVE_LIBZ)
     endif(MED_LIB OR CGNS_LIB)
+  else(HDF5_LIB)
+    message(STATUS "HDF5 not found")
   endif(HDF5_LIB)
 endif(ENABLE_MED OR ENABLE_CGNS)
 
diff --git a/Geo/GModelIO_CGNS.cpp b/Geo/GModelIO_CGNS.cpp
index 93223fa539c2dc224e966a7111a5093078fb7835..8952556a28b2b5058de493e237ddcb8c93b30c7a 100644
--- a/Geo/GModelIO_CGNS.cpp
+++ b/Geo/GModelIO_CGNS.cpp
@@ -609,6 +609,7 @@ int GModel::readCGNS(const std::string &name)
     double ielem = irmax[0] - 1;
     double jelem = irmax[1] - 1;
     double kelem = irmax[2] - 1;
+    printf("Elems %g %g %g\n", ielem, jelem, kelem);
     int order = 1;
     bool done = false;
     while(fmod(ielem / 2.0, 1.0) == 0.0 && fmod(jelem / 2.0, 1.0) == 0.0 && fmod(kelem / 2.0, 1.0) == 0.0 and order < 5) {
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index 6be81f73551efbf2ef336a54881b9d88e986fcd3..9b7280cc1655405861c9e9a64299db117fdcaa1f 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -147,7 +147,7 @@ void MElement::getNode(int num, double &u, double &v, double &w)
 
 void MElement::getShapeFunctions(double u, double v, double w, double s[], int o)
 {
-  const polynomialBasis* fs = getFunctionSpace(o);
+  const nodalBasis* fs = getFunctionSpace(o);
   if(fs) fs->f(u, v, w, s);
   else Msg::Error("Function space not implemented for this type of element");
 }
@@ -155,7 +155,7 @@ void MElement::getShapeFunctions(double u, double v, double w, double s[], int o
 void MElement::getGradShapeFunctions(double u, double v, double w, double s[][3],
                                      int o)
 {
-  const polynomialBasis* fs = getFunctionSpace(o);
+  const nodalBasis* fs = getFunctionSpace(o);
   if(fs) fs->df(u, v, w, s);
   else Msg::Error("Function space not implemented for this type of element");
 }
@@ -163,15 +163,15 @@ void MElement::getGradShapeFunctions(double u, double v, double w, double s[][3]
 void MElement::getHessShapeFunctions(double u, double v, double w, double s[][3][3],
                                      int o)
 {
-  const polynomialBasis* fs = getFunctionSpace(o);
+  const nodalBasis* fs = getFunctionSpace(o);
   if(fs) fs->ddf(u, v, w, s);
   else Msg::Error("Function space not implemented for this type of element");
 }
 
-void MElement::getThirdDerivativeShapeFunctions(double u, double v, double w,
+void MElement::getThirdDerivativeShapeFunctions(double u, double v, double w, 
                                                 double s[][3][3][3], int o)
 {
-  const polynomialBasis* fs = getFunctionSpace(o);
+  const nodalBasis* fs = getFunctionSpace(o);
   if(fs) fs->dddf(u, v, w, s);
   else Msg::Error("Function space not implemented for this type of element");
 }
@@ -1230,6 +1230,13 @@ int MElement::getInfoMSH(const int typeMSH, const char **const name)
   case MSH_PYR_5   : if(name) *name = "Pyramid 5";        return 5;
   case MSH_PYR_13  : if(name) *name = "Pyramid 13";       return 5 + 8;
   case MSH_PYR_14  : if(name) *name = "Pyramid 14";       return 5 + 8 + 1;
+  case MSH_PYR_30  : if(name) *name = "Pyramid 30";       return 5 + 8*2 + 4*1 + 1*4 + 1;  
+  case MSH_PYR_55  : if(name) *name = "Pyramid 55";       return 5 + 8*3 + 4*3 + 1*9 + 5;
+  case MSH_PYR_91  : if(name) *name = "Pyramid 91";       return 91;
+  case MSH_PYR_140 : if(name) *name = "Pyramid 140";      return 140;
+  case MSH_PYR_204 : if(name) *name = "Pyramid 204";      return 204;
+  case MSH_PYR_285 : if(name) *name = "Pyramid 285";      return 285;
+  case MSH_PYR_385 : if(name) *name = "Pyramid 385";      return 385;
   case MSH_POLYH_  : if(name) *name = "Polyhedron";       return 0;
   case MSH_PNT_SUB : if(name) *name = "Point Xfem";       return 1;
   case MSH_LIN_SUB : if(name) *name = "Line Xfem";        return 2;
@@ -1320,6 +1327,96 @@ MElement *MElement::copy(std::map<int, MVertex*> &vertexMap,
   return newEl;
 }
 
+// Gives the parent type corresponding to 
+// any element type.
+// Ex. : MSN_TRI_3 -> TYPE_TRI
+int MElement::ParentTypeFromTag(int tag)
+{
+  switch(tag) {
+    case(MSH_PNT):
+      return TYPE_PNT;
+    case(MSH_LIN_2):    case(MSH_LIN_3):
+    case(MSH_LIN_4):    case(MSH_LIN_5):
+    case(MSH_LIN_6):    case(MSH_LIN_7):
+    case(MSH_LIN_8):    case(MSH_LIN_9):
+    case(MSH_LIN_10):   case(MSH_LIN_11):
+    case(MSH_LIN_B):    case(MSH_LIN_C):
+    case(MSH_LIN_1):
+      return TYPE_LIN;
+    case(MSH_TRI_3):    case(MSH_TRI_6):
+    case(MSH_TRI_9):    case(MSH_TRI_10):
+    case(MSH_TRI_12):   case(MSH_TRI_15):
+    case(MSH_TRI_15I):  case(MSH_TRI_21):
+    case(MSH_TRI_28):   case(MSH_TRI_36):
+    case(MSH_TRI_45):   case(MSH_TRI_55):
+    case(MSH_TRI_66):   case(MSH_TRI_18):
+    case(MSH_TRI_21I):  case(MSH_TRI_24):
+    case(MSH_TRI_27):   case(MSH_TRI_30):
+    case(MSH_TRI_B):    case(MSH_TRI_1):
+      return TYPE_TRI;
+    case(MSH_QUA_4):    case(MSH_QUA_9):
+    case(MSH_QUA_8):    case(MSH_QUA_16):
+    case(MSH_QUA_25):   case(MSH_QUA_36):
+    case(MSH_QUA_12):   case(MSH_QUA_16I):
+    case(MSH_QUA_20):   case(MSH_QUA_49):
+    case(MSH_QUA_64):   case(MSH_QUA_81):
+    case(MSH_QUA_100):  case(MSH_QUA_121):
+    case(MSH_QUA_24):   case(MSH_QUA_28):
+    case(MSH_QUA_32):   case(MSH_QUA_36I):
+    case(MSH_QUA_40):   case(MSH_QUA_1):
+      return TYPE_QUA;
+    case(MSH_TET_4):    case(MSH_TET_10):
+    case(MSH_TET_20):   case(MSH_TET_35):
+    case(MSH_TET_56):   case(MSH_TET_34):
+    case(MSH_TET_52):   case(MSH_TET_84):
+    case(MSH_TET_120):  case(MSH_TET_165):
+    case(MSH_TET_220):  case(MSH_TET_286):
+    case(MSH_TET_74):   case(MSH_TET_100):
+    case(MSH_TET_130):  case(MSH_TET_164):
+    case(MSH_TET_202):  case(MSH_TET_1):
+      return TYPE_TET;
+    case(MSH_PYR_5):    case(MSH_PYR_14):
+    case(MSH_PYR_13):   case(MSH_PYR_30):
+    case(MSH_PYR_55):   case(MSH_PYR_91):
+    case(MSH_PYR_140):  case(MSH_PYR_204):
+    case(MSH_PYR_285):  case(MSH_PYR_385):
+    case(MSH_PYR_29):   case(MSH_PYR_50):
+    case(MSH_PYR_77):   case(MSH_PYR_110):
+    case(MSH_PYR_149):  case(MSH_PYR_194):
+    case(MSH_PYR_245):  case(MSH_PYR_1):
+      return TYPE_PYR;
+    case(MSH_PRI_6):    case(MSH_PRI_18):
+    case(MSH_PRI_15):   case(MSH_PRI_1):
+    case(MSH_PRI_40):   case(MSH_PRI_75):
+    case(MSH_PRI_126):  case(MSH_PRI_196):
+    case(MSH_PRI_288):  case(MSH_PRI_405):
+    case(MSH_PRI_550):  case(MSH_PRI_38):
+    case(MSH_PRI_66):   case(MSH_PRI_102):
+    case(MSH_PRI_146):  case(MSH_PRI_198):
+    case(MSH_PRI_258):  case(MSH_PRI_326):
+      return TYPE_PRI;
+    case(MSH_HEX_8):    case(MSH_HEX_27):
+    case(MSH_HEX_20):   case(MSH_HEX_1):
+    case(MSH_HEX_64):   case(MSH_HEX_125):
+    case(MSH_HEX_216):  case(MSH_HEX_343):
+    case(MSH_HEX_512):  case(MSH_HEX_729):
+    case(MSH_HEX_1000): case(MSH_HEX_56):
+    case(MSH_HEX_98):   case(MSH_HEX_152):
+    case(MSH_HEX_222):  case(MSH_HEX_296):
+    case(MSH_HEX_386):  case(MSH_HEX_488):
+      return TYPE_HEX;
+    case(MSH_POLYG_): case(MSH_POLYG_B):
+      return TYPE_POLYG;
+    case(MSH_POLYH_):
+      return TYPE_POLYH;
+    default:
+      Msg::Error("Unknown type %i, assuming tetrahedron.", tag);
+      return TYPE_TET;
+  }
+}
+
+
+
 MElement *MElementFactory::create(int type, std::vector<MVertex*> &v,
                                   int num, int part, bool owner, MElement *parent,
                                   MElement *d1, MElement *d2)
@@ -1400,6 +1497,13 @@ MElement *MElementFactory::create(int type, std::vector<MVertex*> &v,
   case MSH_LIN_SUB: return new MSubLine(v, num, part, owner, parent);
   case MSH_TRI_SUB: return new MSubTriangle(v, num, part, owner, parent);
   case MSH_TET_SUB: return new MSubTetrahedron(v, num, part, owner, parent);
+  case MSH_PYR_30:  return new MPyramidN(v, 3, num, part);
+  case MSH_PYR_55:  return new MPyramidN(v, 4, num, part);
+  case MSH_PYR_91:  return new MPyramidN(v, 5, num, part);
+  case MSH_PYR_140: return new MPyramidN(v, 6, num, part);
+  case MSH_PYR_204: return new MPyramidN(v, 7, num, part);
+  case MSH_PYR_285: return new MPyramidN(v, 8, num, part);
+  case MSH_PYR_385: return new MPyramidN(v, 9, num, part);
   default:          return 0;
   }
 }
diff --git a/Geo/MElement.h b/Geo/MElement.h
index 67d48a6ca1d891c3923d1950a89f5a242d0c20b4..7abe28e7bbb911cc9e7b3ccb3c503fa9081f2830 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -14,6 +14,7 @@
 #include "MVertex.h"
 #include "MEdge.h"
 #include "MFace.h"
+#include "nodalBasis.h"
 #include "polynomialBasis.h"
 #include "JacobianBasis.h"
 #include "GaussIntegration.h"
@@ -219,7 +220,7 @@ class MElement
   virtual std::string getInfoString();
 
   // get the function space for the element
-  virtual const polynomialBasis* getFunctionSpace(int order=-1) const { return 0; }
+  virtual const nodalBasis* getFunctionSpace(int order=-1) const { return 0; }
 
   // get the function space for the jacobian of the element
   virtual const JacobianBasis* getJacobianFuncSpace(int o=-1) const { return 0; }
@@ -353,6 +354,8 @@ class MElement
                          std::map<MElement*, MElement*> &newParents,
                          std::map<MElement*, MElement*> &newDomains);
 
+  static int ParentTypeFromTag(int tag);
+
 };
 
 class MElementFactory{
diff --git a/Geo/MElementCut.h b/Geo/MElementCut.h
index ebfe8eab5ab99ee3d5b8622adf81fe70fe241752..fa143ddfb4d71e1a28abe70ad531ff8603a63211 100644
--- a/Geo/MElementCut.h
+++ b/Geo/MElementCut.h
@@ -117,7 +117,7 @@ class MPolyhedron : public MElement {
       vol += _parts[i]->getVolume();
     return vol;
   }
-  virtual const polynomialBasis* getFunctionSpace(int order=-1) const
+  virtual const nodalBasis* getFunctionSpace(int order=-1) const
   {
     return (_orig ? _orig->getFunctionSpace(order) : 0);
   }
@@ -258,7 +258,7 @@ class MPolygon : public MElement {
   virtual int getNumChildren() const { return _parts.size(); }
   virtual MElement *getChild(int i) const { return _parts[i]; }
   virtual bool ownsParent() const { return _owner; }
-  virtual const polynomialBasis* getFunctionSpace(int order=-1) const
+  virtual const nodalBasis* getFunctionSpace(int order=-1) const
   {
     return (_orig ? _orig->getFunctionSpace(order) : 0);
   }
@@ -323,7 +323,7 @@ class MLineChild : public MLine {
       delete _orig;
   }
   virtual int getTypeForMSH() const { return MSH_LIN_C; }
-  virtual const polynomialBasis* getFunctionSpace(int order=-1) const
+  virtual const nodalBasis* getFunctionSpace(int order=-1) const
   {
     if(_orig) return _orig->getFunctionSpace(order);
     return 0;
@@ -354,6 +354,7 @@ class MLineChild : public MLine {
   virtual bool ownsParent() const { return _owner; }
 };
 
+
 // -------------------- Border classes
 
 class MTriangleBorder : public MTriangle {
diff --git a/Geo/MHexahedron.cpp b/Geo/MHexahedron.cpp
index 070e21af38ddcd60ba398ac7b556dad4aa201885..38dbab818806c213a7b42583929e9425158e89c9 100644
--- a/Geo/MHexahedron.cpp
+++ b/Geo/MHexahedron.cpp
@@ -6,9 +6,12 @@
 #include "MHexahedron.h"
 #include "Numeric.h"
 #include "Context.h"
+#include "BasisFactory.h"
+#include "nodalBasis.h"
 #include "polynomialBasis.h"
 #include "MQuadrangle.h"
 #include "qualityMeasures.h"
+
 int MHexahedron::getVolumeSign()
 {
   double mat[3][3];
@@ -162,8 +165,8 @@ int MHexahedronN::getNumEdgesRep()
 {
   return 12 * CTX::instance()->mesh.numSubEdges;
 }
-
-const polynomialBasis* MHexahedron::getFunctionSpace(int o) const
+ 
+const nodalBasis* MHexahedron::getFunctionSpace(int o) const
 {
   int order = (o == -1) ? getPolynomialOrder() : o;
 
@@ -171,31 +174,31 @@ const polynomialBasis* MHexahedron::getFunctionSpace(int o) const
 
   if ((nv == 0) && (o == -1)) {
     switch (order) {
-    case 0: return polynomialBases::find(MSH_HEX_1);
-    case 1: return polynomialBases::find(MSH_HEX_8);
-    case 2: return polynomialBases::find(MSH_HEX_20);
-    case 3: return polynomialBases::find(MSH_HEX_56);
-    case 4: return polynomialBases::find(MSH_HEX_98);
-    case 5: return polynomialBases::find(MSH_HEX_152);
-    case 6: return polynomialBases::find(MSH_HEX_222);
-    case 7: return polynomialBases::find(MSH_HEX_296);
-    case 8: return polynomialBases::find(MSH_HEX_386);
-    case 9: return polynomialBases::find(MSH_HEX_488);
+    case 0: return BasisFactory::create(MSH_HEX_1);
+    case 1: return BasisFactory::create(MSH_HEX_8);
+    case 2: return BasisFactory::create(MSH_HEX_20);
+    case 3: return BasisFactory::create(MSH_HEX_56);
+    case 4: return BasisFactory::create(MSH_HEX_98);
+    case 5: return BasisFactory::create(MSH_HEX_152);
+    case 6: return BasisFactory::create(MSH_HEX_222);
+    case 7: return BasisFactory::create(MSH_HEX_296);
+    case 8: return BasisFactory::create(MSH_HEX_386);
+    case 9: return BasisFactory::create(MSH_HEX_488);
     default: Msg::Error("Order %d hex function space not implemented", order);
     }
   }
   else {
     switch (order) {
-    case 0: return polynomialBases::find(MSH_HEX_1);
-    case 1: return polynomialBases::find(MSH_HEX_8);
-    case 2: return polynomialBases::find(MSH_HEX_27);
-    case 3: return polynomialBases::find(MSH_HEX_64);
-    case 4: return polynomialBases::find(MSH_HEX_125);
-    case 5: return polynomialBases::find(MSH_HEX_216);
-    case 6: return polynomialBases::find(MSH_HEX_343);
-    case 7: return polynomialBases::find(MSH_HEX_512);
-    case 8: return polynomialBases::find(MSH_HEX_729);
-    case 9: return polynomialBases::find(MSH_HEX_1000);
+    case 0: return BasisFactory::create(MSH_HEX_1);
+    case 1: return BasisFactory::create(MSH_HEX_8);
+    case 2: return BasisFactory::create(MSH_HEX_27);
+    case 3: return BasisFactory::create(MSH_HEX_64);
+    case 4: return BasisFactory::create(MSH_HEX_125);
+    case 5: return BasisFactory::create(MSH_HEX_216);
+    case 6: return BasisFactory::create(MSH_HEX_343);
+    case 7: return BasisFactory::create(MSH_HEX_512);
+    case 8: return BasisFactory::create(MSH_HEX_729);
+    case 9: return BasisFactory::create(MSH_HEX_1000);
     default: Msg::Error("Order %d hex function space not implemented", order);
     }
   }
diff --git a/Geo/MHexahedron.h b/Geo/MHexahedron.h
index 4cadf664f2197904838c92b82453a9291a436012..d089dbae6141ed459a5c29144bdfd73f26d98860 100644
--- a/Geo/MHexahedron.h
+++ b/Geo/MHexahedron.h
@@ -57,7 +57,7 @@ class MHexahedron : public MElement {
   virtual int getDim() const { return 3; }
   virtual int getNumVertices() const { return 8; }
   virtual MVertex *getVertex(int num){ return _v[num]; }
-  virtual const polynomialBasis* getFunctionSpace(int o=-1) const;
+  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual MVertex *getVertexDIFF(int num)
   {
     static const int map[8] = {2, 3, 7, 6, 0, 1, 5, 4};
diff --git a/Geo/MLine.cpp b/Geo/MLine.cpp
index 3ffe7f1e106e9efdb02c53b42d3a0f6c0740cf57..52d949135342946cfddef890c1fa71e8aa915a86 100644
--- a/Geo/MLine.cpp
+++ b/Geo/MLine.cpp
@@ -5,26 +5,28 @@
 
 #include "GmshDefines.h"
 #include "MLine.h"
+#include "nodalBasis.h"
+#include "BasisFactory.h"
 #include "GaussLegendre1D.h"
 #include "Context.h"
 #include "qualityMeasures.h"
 
-const polynomialBasis* MLine::getFunctionSpace(int o) const
+const nodalBasis* MLine::getFunctionSpace(int o) const
 {
   int order = (o == -1) ? getPolynomialOrder() : o;
   
   switch (order) {
-  case 0: return polynomialBases::find(MSH_LIN_1);
-  case 1: return polynomialBases::find(MSH_LIN_2);
-  case 2: return polynomialBases::find(MSH_LIN_3);
-  case 3: return polynomialBases::find(MSH_LIN_4);
-  case 4: return polynomialBases::find(MSH_LIN_5);
-  case 5: return polynomialBases::find(MSH_LIN_6);
-  case 6: return polynomialBases::find(MSH_LIN_7);
-  case 7: return polynomialBases::find(MSH_LIN_8);
-  case 8: return polynomialBases::find(MSH_LIN_9);
-  case 9: return polynomialBases::find(MSH_LIN_10);
-  case 10: return polynomialBases::find(MSH_LIN_11);
+  case 0: return BasisFactory::create(MSH_LIN_1);
+  case 1: return BasisFactory::create(MSH_LIN_2);
+  case 2: return BasisFactory::create(MSH_LIN_3);
+  case 3: return BasisFactory::create(MSH_LIN_4);
+  case 4: return BasisFactory::create(MSH_LIN_5);
+  case 5: return BasisFactory::create(MSH_LIN_6);
+  case 6: return BasisFactory::create(MSH_LIN_7);
+  case 7: return BasisFactory::create(MSH_LIN_8);
+  case 8: return BasisFactory::create(MSH_LIN_9);
+  case 9: return BasisFactory::create(MSH_LIN_10);
+  case 10: return BasisFactory::create(MSH_LIN_11);
   default: Msg::Error("Order %d line function space not implemented", order);
   }
   return 0;
diff --git a/Geo/MLine.h b/Geo/MLine.h
index 68a22428c501e3b84fcea1e7aa42dcf27d7787b3..0737024bef66db8b72561a58dbdc95ac10ae4475 100644
--- a/Geo/MLine.h
+++ b/Geo/MLine.h
@@ -7,6 +7,7 @@
 #define _MLINE_H_
 
 #include "MElement.h"
+#include "nodalBasis.h"
 
 /*
  * MLine
@@ -71,7 +72,7 @@ class MLine : public MElement {
   {
     MVertex *tmp = _v[0]; _v[0] = _v[1]; _v[1] = tmp;
   }
-  virtual const polynomialBasis* getFunctionSpace(int o=-1) const;
+  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int o=-1) const;
   virtual bool isInside(double u, double v, double w)
   {
diff --git a/Geo/MPyramid.cpp b/Geo/MPyramid.cpp
index 0ae5009b7a03c13457917f57a721a07b65f5d352..7cc20180db60102d2cb438809e1d1857a49832b9 100644
--- a/Geo/MPyramid.cpp
+++ b/Geo/MPyramid.cpp
@@ -5,6 +5,9 @@
 
 #include "MPyramid.h"
 #include "Numeric.h"
+#include "Context.h"
+#include "BergotBasis.h"
+#include "BasisFactory.h"
 
 int MPyramid::getVolumeSign()
 { 
@@ -23,3 +26,337 @@ int MPyramid::getVolumeSign()
   else if(d > 0.) return 1;
   else return 0;
 }
+
+const nodalBasis* MPyramid::getFunctionSpace(int o) const
+{
+  int order = (o == -1) ? getPolynomialOrder() : o;
+
+  int nv = getNumVolumeVertices();
+
+  if ((nv == 0) && (o == -1)) {
+    switch (order) {
+    case 1: return BasisFactory::create(MSH_PYR_5);
+    case 2: return BasisFactory::create(MSH_PYR_14);
+    case 0: return BasisFactory::create(MSH_PYR_1);
+    case 3: return BasisFactory::create(MSH_PYR_29);
+    case 4: return BasisFactory::create(MSH_PYR_50);
+    case 5: return BasisFactory::create(MSH_PYR_77);
+    case 6: return BasisFactory::create(MSH_PYR_110);
+    case 7: return BasisFactory::create(MSH_PYR_149);
+    case 8: return BasisFactory::create(MSH_PYR_194);
+    case 9: return BasisFactory::create(MSH_PYR_245);
+    default: Msg::Error("Order %d pyramid function space not implemented", order);
+    }
+  }
+  else {
+    switch (order) {
+    case 0: return BasisFactory::create(MSH_PYR_1);
+    case 1: return BasisFactory::create(MSH_PYR_5);
+    case 2: return BasisFactory::create(MSH_PYR_14);
+    case 3: return BasisFactory::create(MSH_PYR_30);
+    case 4: return BasisFactory::create(MSH_PYR_55);
+    case 5: return BasisFactory::create(MSH_PYR_91);
+    case 6: return BasisFactory::create(MSH_PYR_140);
+    case 7: return BasisFactory::create(MSH_PYR_204);
+    case 8: return BasisFactory::create(MSH_PYR_285);
+    case 9: return BasisFactory::create(MSH_PYR_385);
+    default: Msg::Error("Order %d pyramid function space not implemented", order);
+    }
+  }
+  return 0;
+}
+
+
+
+
+MPyramidN::~MPyramidN() {}
+
+double MPyramidN::distoShapeMeasure()
+{
+#if defined(HAVE_MESH)
+  _disto = 0.0; //qmDistorsionOfMapping(this);
+#else
+  _disto = 0.;
+#endif
+  return _disto;
+}
+
+int MPyramidN::getNumEdgesRep(){ return 8 * CTX::instance()->mesh.numSubEdges; }
+
+void MPyramidN::getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
+{
+  int numSubEdges = CTX::instance()->mesh.numSubEdges;
+  static double pp[5][3] = {{-1,-1,0},{1,-1,0},{1,1,0},{-1,1,0},{0,0,1}};
+  static int ed [8][2] = {{0,1},{0,3},{0,4},{1,2},{1,4},{2,3},{2,4},{3,4}};
+  int iEdge = num / numSubEdges;
+  int iSubEdge = num % numSubEdges;
+
+  int iVertex1 = ed [iEdge][0];
+  int iVertex2 = ed [iEdge][1];
+  double t1 = (double) iSubEdge / (double) numSubEdges;
+  double u1 = pp[iVertex1][0] * (1.-t1) + pp[iVertex2][0] * t1;
+  double v1 = pp[iVertex1][1] * (1.-t1) + pp[iVertex2][1] * t1;
+  double w1 = pp[iVertex1][2] * (1.-t1) + pp[iVertex2][2] * t1;
+
+  double t2 = (double) (iSubEdge+1) / (double) numSubEdges;
+  double u2 = pp[iVertex1][0] * (1.-t2) + pp[iVertex2][0] * t2;
+  double v2 = pp[iVertex1][1] * (1.-t2) + pp[iVertex2][1] * t2;
+  double w2 = pp[iVertex1][2] * (1.-t2) + pp[iVertex2][2] * t2;
+
+  SPoint3 pnt1, pnt2;
+  pnt(u1,v1,w1,pnt1);
+  pnt(u2,v2,w2,pnt2);
+  x[0] = pnt1.x(); x[1] = pnt2.x();
+  y[0] = pnt1.y(); y[1] = pnt2.y();
+  z[0] = pnt1.z(); z[1] = pnt2.z();
+
+  // not great, but better than nothing
+  static const int f[8] = {0, 1, 0, 2, 2, 3, 2, 3};
+  n[0] = n[1] = getFace(f[iEdge]).normal();  
+}
+
+
+int MPyramidN::getNumFacesRep(){ return 6 * SQU(CTX::instance()->mesh.numSubEdges); }
+
+static void _myGetFaceRep(MPyramid *pyr, int num, double *x, double *y, double *z,
+                          SVector3 *n, int numSubEdges)
+{
+  static double pp[5][3] = {
+    {-1,-1,0},
+    {1,-1,0},
+    {1,1,0},
+    {-1,1,0},
+    {0,0,1}
+  };
+  int iFace    = num / (numSubEdges * numSubEdges);
+  int iSubFace = num % (numSubEdges * numSubEdges);
+
+  if (iFace > 3) {
+    iFace = 4;
+    iSubFace = num % (2*numSubEdges * numSubEdges);
+  }
+
+  int iVertex1, iVertex2, iVertex3, iVertex4;
+
+  if (iFace < 4) {
+    iVertex1 = pyr->faces_pyramid(iFace,0);
+    iVertex2 = pyr->faces_pyramid(iFace,1);
+    iVertex3 = pyr->faces_pyramid(iFace,2);
+  } else {
+    iVertex1 = 0;
+    iVertex2 = 1;
+    iVertex3 = 2;
+    iVertex4 = 3;
+  }
+
+  if (iFace < 4) {
+
+    int ix = 0, iy = 0;
+    int nbt = 0;
+    for (int i = 0; i < numSubEdges; i++){
+      int nbl = (numSubEdges - i - 1) * 2 + 1;
+      nbt += nbl;
+      if (nbt > iSubFace){
+        iy = i;
+        ix = nbl - (nbt - iSubFace);
+        break;
+      }
+    }
+
+    const double d = 1. / numSubEdges;
+
+    SPoint3 pnt1, pnt2, pnt3;
+    double u1, v1, u2, v2, u3, v3;
+    if (ix % 2 == 0){
+      u1 = ix / 2 * d; v1= iy*d;
+      u2 = (ix / 2 + 1) * d ; v2 =  iy * d;
+      u3 = ix / 2 * d ; v3 =  (iy+1) * d;
+    }
+    else{
+      u1 = (ix / 2 + 1) * d; v1= iy * d;
+      u2 = (ix / 2 + 1) * d; v2= (iy + 1) * d;
+      u3 = ix / 2 * d ; v3 =  (iy + 1) * d;
+    }
+
+    double U1 = pp[iVertex1][0] * (1.-u1-v1) + pp[iVertex2][0] * u1 + pp[iVertex3][0] * v1;
+    double U2 = pp[iVertex1][0] * (1.-u2-v2) + pp[iVertex2][0] * u2 + pp[iVertex3][0] * v2;
+    double U3 = pp[iVertex1][0] * (1.-u3-v3) + pp[iVertex2][0] * u3 + pp[iVertex3][0] * v3;
+
+    double V1 = pp[iVertex1][1] * (1.-u1-v1) + pp[iVertex2][1] * u1 + pp[iVertex3][1] * v1;
+    double V2 = pp[iVertex1][1] * (1.-u2-v2) + pp[iVertex2][1] * u2 + pp[iVertex3][1] * v2;
+    double V3 = pp[iVertex1][1] * (1.-u3-v3) + pp[iVertex2][1] * u3 + pp[iVertex3][1] * v3;
+
+    double W1 = pp[iVertex1][2] * (1.-u1-v1) + pp[iVertex2][2] * u1 + pp[iVertex3][2] * v1;
+    double W2 = pp[iVertex1][2] * (1.-u2-v2) + pp[iVertex2][2] * u2 + pp[iVertex3][2] * v2;
+    double W3 = pp[iVertex1][2] * (1.-u3-v3) + pp[iVertex2][2] * u3 + pp[iVertex3][2] * v3;
+
+    pyr->pnt(U1, V1, W1, pnt1);
+    pyr->pnt(U2, V2, W2, pnt2);
+    pyr->pnt(U3, V3, W3, pnt3);
+
+    x[0] = pnt1.x(); x[1] = pnt2.x(); x[2] = pnt3.x();
+    y[0] = pnt1.y(); y[1] = pnt2.y(); y[2] = pnt3.y();
+    z[0] = pnt1.z(); z[1] = pnt2.z(); z[2] = pnt3.z();
+
+    SVector3 d1(x[1] - x[0], y[1] - y[0], z[1] - z[0]);
+    SVector3 d2(x[2] - x[0], y[2] - y[0], z[2] - z[0]);
+    n[0] = crossprod(d1, d2);
+    n[0].normalize();
+    n[1] = n[0];
+    n[2] = n[0];
+
+  } else {
+
+
+    SPoint3 pnt1, pnt2, pnt3;
+    double J1[3][3], J2[3][3], J3[3][3];
+
+    /*
+    0
+    0 1
+    0 1 2
+    0 1 2 3
+    0 1 2 3 4
+    0 1 2 3 4 5
+    */
+
+    // on each layer, we have (numSubEdges) * 2 triangles
+    // ix and iy are the coordinates of the sub-quadrangle
+
+    int io = iSubFace%2;
+    int ix = (iSubFace/2)/numSubEdges;
+    int iy = (iSubFace/2)%numSubEdges;
+
+    const double d = 2. / numSubEdges;
+    double ox = -1. + d*ix;
+    double oy = -1. + d*iy;
+
+    if (io == 0){
+    double U1 =
+      pp[iVertex1][0] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][0] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][0] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][0] * (1.-ox)*(1+oy)*.25;
+    double V1 =
+      pp[iVertex1][1] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][1] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][1] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][1] * (1.-ox)*(1+oy)*.25;
+    double W1 =
+      pp[iVertex1][2] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][2] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][2] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][2] * (1.-ox)*(1+oy)*.25;
+
+    ox += d;
+
+    double U2 =
+      pp[iVertex1][0] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][0] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][0] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][0] * (1.-ox)*(1+oy)*.25;
+    double V2 =
+      pp[iVertex1][1] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][1] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][1] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][1] * (1.-ox)*(1+oy)*.25;
+    double W2 =
+      pp[iVertex1][2] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][2] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][2] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][2] * (1.-ox)*(1+oy)*.25;
+
+    oy += d;
+
+    double U3 =
+      pp[iVertex1][0] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][0] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][0] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][0] * (1.-ox)*(1+oy)*.25;
+    double V3 =
+      pp[iVertex1][1] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][1] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][1] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][1] * (1.-ox)*(1+oy)*.25;
+    double W3 =
+      pp[iVertex1][2] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][2] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][2] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][2] * (1.-ox)*(1+oy)*.25;
+
+    pyr->pnt(U1,V1,W1, pnt1);
+    pyr->pnt(U2,V2,W2, pnt2);
+    pyr->pnt(U3,V3,W3, pnt3);
+    }
+    else{
+    double U1 =
+      pp[iVertex1][0] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][0] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][0] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][0] * (1.-ox)*(1+oy)*.25;
+    double V1 =
+      pp[iVertex1][1] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][1] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][1] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][1] * (1.-ox)*(1+oy)*.25;
+    double W1 =
+      pp[iVertex1][2] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][2] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][2] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][2] * (1.-ox)*(1+oy)*.25;
+
+    ox += d;
+    oy += d;
+
+    double U2 =
+      pp[iVertex1][0] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][0] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][0] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][0] * (1.-ox)*(1+oy)*.25;
+    double V2 =
+      pp[iVertex1][1] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][1] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][1] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][1] * (1.-ox)*(1+oy)*.25;
+    double W2 =
+      pp[iVertex1][2] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][2] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][2] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][2] * (1.-ox)*(1+oy)*.25;
+
+    ox -= d;
+
+    double U3 =
+      pp[iVertex1][0] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][0] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][0] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][0] * (1.-ox)*(1+oy)*.25;
+    double V3 =
+      pp[iVertex1][1] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][1] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][1] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][1] * (1.-ox)*(1+oy)*.25;
+    double W3 =
+      pp[iVertex1][2] * (1.-ox)*(1-oy)*.25 +
+      pp[iVertex2][2] * (1.+ox)*(1-oy)*.25 +
+      pp[iVertex3][2] * (1.+ox)*(1+oy)*.25 +
+      pp[iVertex4][2] * (1.-ox)*(1+oy)*.25;
+
+    pyr->pnt(U1,V1,W1, pnt1);
+    pyr->pnt(U2,V2,W2, pnt2);
+    pyr->pnt(U3,V3,W3, pnt3);
+    }
+
+    n[0] = 1;
+    n[1] = 1;
+    n[2] = 1;
+    x[0] = pnt1.x(); x[1] = pnt2.x(); x[2] = pnt3.x();
+    y[0] = pnt1.y(); y[1] = pnt2.y(); y[2] = pnt3.y();
+    z[0] = pnt1.z(); z[1] = pnt2.z(); z[2] = pnt3.z();
+  }
+}
+
+void MPyramidN::getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
+{
+  _myGetFaceRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges);
+}
diff --git a/Geo/MPyramid.h b/Geo/MPyramid.h
index 065d1186dc74602c09b4c6d561e01984d6ebb580..1277b1d75533e7867ba7605d3c01cc6964c196df 100644
--- a/Geo/MPyramid.h
+++ b/Geo/MPyramid.h
@@ -67,6 +67,7 @@ class MPyramid : public MElement {
   virtual int getDim() const { return 3; }
   virtual int getNumVertices() const { return 5; }
   virtual MVertex *getVertex(int num){ return _v[num]; }
+  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual int getNumEdges(){ return 8; }
   virtual MEdge getEdge(int num)
   {
@@ -122,7 +123,7 @@ class MPyramid : public MElement {
     MVertex *tmp = _v[0]; _v[0] = _v[2]; _v[2] = tmp;
   }
   virtual int getVolumeSign();
-  virtual void getShapeFunctions(double u, double v, double w, double s[], int o)
+  /*virtual void getShapeFunctions(double u, double v, double w, double s[], int o)
   {
     double r = (w != 1.) ? (u * v * w / (1. - w)) : 0.;
     s[0] = 0.25 * ((1. - u) * (1. - v) - w + r);
@@ -131,6 +132,7 @@ class MPyramid : public MElement {
     s[3] = 0.25 * ((1. - u) * (1. + v) - w - r);
     s[4] = w;
   }
+  */
   virtual void getGradShapeFunctions(double u, double v, double w, double s[][3], int o)
   {
     if(w == 1.) {
@@ -450,4 +452,105 @@ class MPyramid14 : public MPyramid {
   }
 };
 
+//------------------------------------------------------------------------------
+
+class MPyramidN : public MPyramid {
+
+ protected:
+  std::vector<MVertex*> _vs;
+  const char _order;
+  double _disto;
+ public:
+  MPyramidN(MVertex* v0, MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4,
+      const std::vector<MVertex*> &v, char order, int num=0, int part=0)
+    : MPyramid(v0, v1, v2, v3, v4, num, part), _vs(v), _order(order), _disto(-1e22)
+  {
+    for (unsigned int i = 0; i < _vs.size(); i++) _vs[i]->setPolynomialOrder(_order);
+    getFunctionSpace(order);
+  }
+
+  MPyramidN(const std::vector<MVertex*> &v, char order, int num=0, int part=0)
+    : MPyramid(v[0], v[1], v[2], v[3], v[4], num, part), _order(order), _disto(-1e22)
+  {
+    for (unsigned int i = 5; i < v.size(); i++ ) _vs.push_back(v[i]);
+    for (unsigned int i = 0; i < _vs.size(); i++) _vs[i]->setPolynomialOrder(_order);
+    getFunctionSpace(order);
+  }
+
+  ~MPyramidN();
+
+  virtual double distoShapeMeasure();
+  virtual int getPolynomialOrder() const { return _order; }
+  virtual int getNumVertices() const { return 5 + _vs.size(); }
+  virtual MVertex *getVertex(int num){ return num < 5 ? _v[num] : _vs[num - 5]; }
+  virtual int getNumEdgeVertices() const { return 8 * (_order - 1); }
+  virtual int getNumFaceVertices() const 
+  {
+    return (_order-1)*(_order-1) + 4 * ((_order - 1) * (_order - 2)) / 2;
+  }
+  virtual void getEdgeVertices(const int num, std::vector<MVertex*> &v) const
+  {
+    v.resize(_order+1);
+    MPyramid::_getEdgeVertices(num, v);
+    int j = 2;
+    const int ie = (num + 1) * (_order - 1);
+    for(int i = num * (_order -1); i != ie; ++i) v[j++] = _vs[i];
+  }
+  virtual void getFaceVertices(const int num, std::vector<MVertex*> &v) const
+  {
+    int j = 3;
+    if (num == 4) {
+      j = 4; 
+      v.resize(_order * _order);
+    }
+    else {
+      v.resize(3 + 3 * (_order - 1) + (_order-1) * (_order - 2) /2);
+    }
+    MPyramid::_getFaceVertices(num, v);
+    int nbVQ =  (_order-1)*(_order-1);
+    int nbVT = (_order - 1) * (_order - 2) / 2;
+    const int ie = (num == 4) ? 4*nbVT + nbVQ : (num+1)*nbVT;
+    for (int i = num*nbVT; i != ie; ++i) v[j++] = _vs[i];
+  }
+  virtual int getNumVolumeVertices() const
+  {
+    switch(getTypeForMSH()){
+    case MSH_PYR_30 : return 1;
+    case MSH_PYR_55 : return 5;
+    case MSH_PYR_91 : return 14;
+    case MSH_PYR_140 : return 30;
+    case MSH_PYR_204 : return 55;
+    case MSH_PYR_285 : return 91;
+    case MSH_PYR_385 : return 140;
+    default : return 0;
+    }
+  }
+  virtual int getTypeForMSH() const
+  {
+    if(_order == 3 && _vs.size() + 5 == 29) return MSH_PYR_29;
+    if(_order == 3 && _vs.size() + 5 == 30) return MSH_PYR_30;
+    if(_order == 4 && _vs.size() + 5 == 50) return MSH_PYR_50;
+    if(_order == 4 && _vs.size() + 5 == 55) return MSH_PYR_55;
+    if(_order == 5 && _vs.size() + 5 == 77) return MSH_PYR_77;
+    if(_order == 5 && _vs.size() + 5 == 91) return MSH_PYR_91;
+    if(_order == 6 && _vs.size() + 5 == 110) return MSH_PYR_110;
+    if(_order == 6 && _vs.size() + 5 == 140) return MSH_PYR_140;
+    if(_order == 7 && _vs.size() + 5 == 149) return MSH_PYR_149;
+    if(_order == 7 && _vs.size() + 5 == 204) return MSH_PYR_204;
+    if(_order == 8 && _vs.size() + 5 == 194) return MSH_PYR_194;
+    if(_order == 8 && _vs.size() + 5 == 285) return MSH_PYR_285;
+    if(_order == 9 && _vs.size() + 5 == 245) return MSH_PYR_245;
+    if(_order == 9 && _vs.size() + 5 == 385) return MSH_PYR_385;
+    return 0;
+  }
+  virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n);
+  virtual int getNumEdgesRep();
+  virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n);
+  virtual int getNumFacesRep();
+  virtual void getNode(int num, double &u, double &v, double &w)
+  {
+    num < 5 ? MPyramid::getNode(num, u, v, w) : MElement::getNode(num, u, v, w);
+  }
+};
+
 #endif
diff --git a/Geo/MSubElement.cpp b/Geo/MSubElement.cpp
index 7640a3eb068d80bb52e076eafe1390e9b805e0d9..60c4e82e15a4f5797dd2ea448b192dd1fc653c39 100644
--- a/Geo/MSubElement.cpp
+++ b/Geo/MSubElement.cpp
@@ -18,7 +18,7 @@ MSubTetrahedron::~MSubTetrahedron()
 
 const polynomialBasis* MSubTetrahedron::getFunctionSpace(int order) const
 {
-  if(_orig) return _orig->getFunctionSpace(order);
+  if(_orig) return (polynomialBasis*)_orig->getFunctionSpace(order);
   return 0;
 }
 
@@ -116,7 +116,7 @@ MSubTriangle::~MSubTriangle()
 
 const polynomialBasis* MSubTriangle::getFunctionSpace(int order) const
 {
-  if(_orig) return _orig->getFunctionSpace(order);
+  if(_orig) return (polynomialBasis*)_orig->getFunctionSpace(order);
   return 0;
 }
 
@@ -211,7 +211,7 @@ MSubLine::~MSubLine()
 
 const polynomialBasis* MSubLine::getFunctionSpace(int order) const
 {
-  if(_orig) return _orig->getFunctionSpace(order);
+  if(_orig) return (polynomialBasis*)_orig->getFunctionSpace(order);
   return 0;
 }
 
@@ -301,7 +301,7 @@ MSubPoint::~MSubPoint()
 
 const polynomialBasis* MSubPoint::getFunctionSpace(int order) const
 {
-  if(_orig) return _orig->getFunctionSpace(order);
+  if(_orig) return (polynomialBasis*)_orig->getFunctionSpace(order);
   return 0;
 }
 
diff --git a/Geo/MTetrahedron.cpp b/Geo/MTetrahedron.cpp
index 7d0cd1509838483e6f1a12328628018598bd71de..1dde8a9e9a5cd385dfd67fde9dc7241e74948d00 100644
--- a/Geo/MTetrahedron.cpp
+++ b/Geo/MTetrahedron.cpp
@@ -7,6 +7,7 @@
 #include "MTetrahedron.h"
 #include "Numeric.h"
 #include "Context.h"
+#include "BasisFactory.h"
 
 #if defined(HAVE_MESH)
 #include "qualityMeasures.h"
@@ -184,7 +185,7 @@ void MTetrahedron::xyz2uvw(double xyz[3], double uvw[3])
   sys3x3(mat, b, uvw, &det);
 }
 
-const polynomialBasis* MTetrahedron::getFunctionSpace(int o) const
+const nodalBasis* MTetrahedron::getFunctionSpace(int o) const
 {
   int order = (o == -1) ? getPolynomialOrder() : o;
 
@@ -192,33 +193,33 @@ const polynomialBasis* MTetrahedron::getFunctionSpace(int o) const
 
   if ((nv == 0) && (o == -1)) {
     switch (order) {
-    case 0: return polynomialBases::find(MSH_TET_1);
-    case 1: return polynomialBases::find(MSH_TET_4);
-    case 2: return polynomialBases::find(MSH_TET_10);
-    case 3: return polynomialBases::find(MSH_TET_20);
-    case 4: return polynomialBases::find(MSH_TET_34);
-    case 5: return polynomialBases::find(MSH_TET_52);
-    case 6: return polynomialBases::find(MSH_TET_74);
-    case 7: return polynomialBases::find(MSH_TET_100);
-    case 8: return polynomialBases::find(MSH_TET_130);
-    case 9: return polynomialBases::find(MSH_TET_164);
-    case 10: return polynomialBases::find(MSH_TET_202);
+    case 0: return BasisFactory::create(MSH_TET_1);
+    case 1: return BasisFactory::create(MSH_TET_4);
+    case 2: return BasisFactory::create(MSH_TET_10);
+    case 3: return BasisFactory::create(MSH_TET_20);
+    case 4: return BasisFactory::create(MSH_TET_34);
+    case 5: return BasisFactory::create(MSH_TET_52);
+    case 6: return BasisFactory::create(MSH_TET_74);
+    case 7: return BasisFactory::create(MSH_TET_100);
+    case 8: return BasisFactory::create(MSH_TET_130);
+    case 9: return BasisFactory::create(MSH_TET_164);
+    case 10: return BasisFactory::create(MSH_TET_202);
     default: Msg::Error("Order %d tetrahedron function space not implemented", order);
     }
   }
   else {
     switch (order) {
-    case 0: return polynomialBases::find(MSH_TET_1);
-    case 1: return polynomialBases::find(MSH_TET_4);
-    case 2: return polynomialBases::find(MSH_TET_10);
-    case 3: return polynomialBases::find(MSH_TET_20);
-    case 4: return polynomialBases::find(MSH_TET_35);
-    case 5: return polynomialBases::find(MSH_TET_56);
-    case 6: return polynomialBases::find(MSH_TET_84);
-    case 7: return polynomialBases::find(MSH_TET_120);
-    case 8: return polynomialBases::find(MSH_TET_165);
-    case 9: return polynomialBases::find(MSH_TET_220);
-    case 10: return polynomialBases::find(MSH_TET_286);
+    case 0: return BasisFactory::create(MSH_TET_1);
+    case 1: return BasisFactory::create(MSH_TET_4);
+    case 2: return BasisFactory::create(MSH_TET_10);
+    case 3: return BasisFactory::create(MSH_TET_20);
+    case 4: return BasisFactory::create(MSH_TET_35);
+    case 5: return BasisFactory::create(MSH_TET_56);
+    case 6: return BasisFactory::create(MSH_TET_84);
+    case 7: return BasisFactory::create(MSH_TET_120);
+    case 8: return BasisFactory::create(MSH_TET_165);
+    case 9: return BasisFactory::create(MSH_TET_220);
+    case 10: return BasisFactory::create(MSH_TET_286);
     default: Msg::Error("Order %d tetrahedron function space not implemented", order);
     }
   }
diff --git a/Geo/MTetrahedron.h b/Geo/MTetrahedron.h
index 0be96dcf11df3c5ff7a8977a7087c48ac1e0e879..2df127b1640bc3c12d7ebd9bae6fd3b709705576 100644
--- a/Geo/MTetrahedron.h
+++ b/Geo/MTetrahedron.h
@@ -128,7 +128,7 @@ class MTetrahedron : public MElement {
   virtual double getCircumRadius();
   virtual double etaShapeMeasure();
   void xyz2uvw(double xyz[3], double uvw[3]);
-  virtual const polynomialBasis* getFunctionSpace(int o=-1) const;
+  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int o=-1) const;
   virtual void getNode(int num, double &u, double &v, double &w)
   {
diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp
index f37cb864725d1760500d0e7821d7be03fcedf98b..746bff9db943ae6c90193e463ccdada64a704174 100644
--- a/Mesh/HighOrder.cpp
+++ b/Mesh/HighOrder.cpp
@@ -22,6 +22,7 @@
 #include "Context.h"
 #include "fullMatrix.h"
 #include "polynomialBasis.h"
+#include "BasisFactory.h"
 
 #define SQU(a)      ((a)*(a))
 
@@ -723,14 +724,16 @@ static void getRegionVertices(GRegion *gr, MElement *incomplete, MElement *ele,
     switch (nPts){
     case 0: return;
     case 1: return;
-    case 2: points = polynomialBases::find(MSH_TET_20)->points; break;
-    case 3: points = polynomialBases::find(MSH_TET_35)->points; break;
-    case 4: points = polynomialBases::find(MSH_TET_56)->points; break;
-    case 5: points = polynomialBases::find(MSH_TET_84)->points; break;
-    case 6: points = polynomialBases::find(MSH_TET_120)->points; break;
-    case 7: points = polynomialBases::find(MSH_TET_165)->points; break;
-    case 8: points = polynomialBases::find(MSH_TET_220)->points; break;
-    case 9: points = polynomialBases::find(MSH_TET_286)->points; break;
+    case 2:
+      BasisFactory::create(MSH_TET_20)->points.print();
+      points = BasisFactory::create(MSH_TET_20)->points; break;
+    case 3: points = BasisFactory::create(MSH_TET_35)->points; break;
+    case 4: points = BasisFactory::create(MSH_TET_56)->points; break;
+    case 5: points = BasisFactory::create(MSH_TET_84)->points; break;
+    case 6: points = BasisFactory::create(MSH_TET_120)->points; break;
+    case 7: points = BasisFactory::create(MSH_TET_165)->points; break;
+    case 8: points = BasisFactory::create(MSH_TET_220)->points; break;
+    case 9: points = BasisFactory::create(MSH_TET_286)->points; break;
     default:
       Msg::Error("getRegionVertices not implemented for order %i", nPts+1);
       break;
@@ -755,17 +758,16 @@ static void getRegionVertices(GRegion *gr, MElement *incomplete, MElement *ele,
     start = (nPts+2)*(nPts+2)*(nPts+2) - (nPts)*(nPts)*(nPts) ;
     break;
   case TYPE_PYR:
-    printf("aaaaaand...\n");
     switch (nPts){
     case 0:
     case 1: return;
-    case 2: points = polynomialBases::find(MSH_PYR_30)->points; break;
-    case 3: points = polynomialBases::find(MSH_PYR_55)->points; break;
-    case 4: points = polynomialBases::find(MSH_PYR_91)->points; break;
-    case 5: points = polynomialBases::find(MSH_PYR_140)->points; break;
-    case 6: points = polynomialBases::find(MSH_PYR_204)->points; break;
-    case 7: points = polynomialBases::find(MSH_PYR_285)->points; break;
-    case 8: points = polynomialBases::find(MSH_PYR_385)->points; break;
+    case 2: points = BasisFactory::create(MSH_PYR_30)->points; break;
+    case 3: points = BasisFactory::create(MSH_PYR_55)->points; break;
+    case 4: points = BasisFactory::create(MSH_PYR_91)->points; break;
+    case 5: points = BasisFactory::create(MSH_PYR_140)->points; break;
+    case 6: points = BasisFactory::create(MSH_PYR_204)->points; break;
+    case 7: points = BasisFactory::create(MSH_PYR_285)->points; break;
+    case 8: points = BasisFactory::create(MSH_PYR_385)->points; break;
     default :
       Msg::Error("getRegionVertices not implemented for order %i", nPts+1);
       break;
@@ -781,9 +783,11 @@ static void getRegionVertices(GRegion *gr, MElement *incomplete, MElement *ele,
     const double t1 = points(k, 0);
     const double t2 = points(k, 1);
     const double t3 = points(k, 2);
+    //printf("inside getRegionVertices, point is %g %g %g\n", t1, t2, t3);
     SPoint3 pos;
     incomplete->pnt(t1, t2, t3, pos);
     v = new MVertex(pos.x(), pos.y(), pos.z(), gr);
+    //printf("inside getRegionVertices, vertex is %g %g %g\n", v->x(), v->y(), v->z());
     gr->mesh_vertices.push_back(v);
     vr.push_back(v);
   }
@@ -1011,39 +1015,167 @@ static void setHighOrder(GRegion *gr, edgeContainer &edgeVertices,
   gr->prisms = prisms2;
 
   std::vector<MPyramid*> pyramids2;
-  for(unsigned int i = 0; i < gr->pyramids.size(); i++){
+  for(unsigned int i = 0; i < gr->pyramids.size(); i++) {
     MPyramid *p = gr->pyramids[i];
     std::vector<MVertex*> ve, vf, vr;
     getEdgeVertices(gr, p, ve, edgeVertices, linear, nPts);
     if (nPts == 1) {
-      if(incomplete){
-	pyramids2.push_back
-	  (new MPyramid13(p->getVertex(0), p->getVertex(1), p->getVertex(2),
-			  p->getVertex(3), p->getVertex(4), ve[0], ve[1], ve[2],
-			  ve[3], ve[4], ve[5], ve[6], ve[7]));
+      if(incomplete) {
+        pyramids2.push_back(new MPyramid13(p->getVertex(0), p->getVertex(1), 
+                            p->getVertex(2), p->getVertex(3), 
+                            p->getVertex(4), ve[0], ve[1], ve[2],
+			                      ve[3], ve[4], ve[5], ve[6], ve[7]));
       }
-      else{
-	getFaceVertices(gr, p, vf, faceVertices, edgeVertices, linear, nPts);
-	pyramids2.push_back
-	  (new MPyramid14(p->getVertex(0), p->getVertex(1), p->getVertex(2),
-			  p->getVertex(3), p->getVertex(4), ve[0], ve[1], ve[2],
-			  ve[3], ve[4], ve[5], ve[6], ve[7], vf[0]));
+      else {
+        getFaceVertices(gr, p, vf, faceVertices, edgeVertices, linear, nPts);
+        pyramids2.push_back
+            (new MPyramid14(p->getVertex(0), p->getVertex(1), p->getVertex(2),
+			                      p->getVertex(3), p->getVertex(4), ve[0], ve[1], ve[2],
+			                      ve[3], ve[4], ve[5], ve[6], ve[7], vf[0]));
       }
     }
     else {
-      Msg::Error("PyramidN generation not implemented");
-      /*
       getFaceVertices(gr, p, vf, faceVertices, edgeVertices, linear, nPts);
       ve.insert(ve.end(), vf.begin(), vf.end());
-      MPyramidN incpl(p->getVertex(0), p->getVertex(1), p->getVertex(2),
-                         p->getVertex(3), p->getVertex(4), ve, nPts + 1);
-      getRegionVertices(gr, &incpl, p, vr, linear, nPts);
+
+      // Creating quads to get the internal vertices
+      /*
+       * P3 : q1 - 21 22 23 24
+       * P4 : q1 - 29 30 32 33 35 36 38 39
+       *      q2 - 31 34 37 40
+       * P5 : q1 - 37 40 38 43 46 44 49 52 50 55 58 56
+       *      q2 - 42 41 48 47 54 53 60 59
+       *      q3 - 39 45 51 57
+       */
+
+      vr.reserve((nPts-1)*(nPts)*(2*(nPts-1)+1)/6);
+      /*for (int tmp = 0; tmp < (nPts-1)*(nPts)*(2*(nPts-1)+1)/6; tmp++) {
+        vr.push_back(0);
+      }*/
+
+      int verts_lvl3[12] = {37,40,38,43,46,44,49,52,50,55,58,56};
+
+      int verts_lvl2[8];
+      if (nPts == 4) {
+        verts_lvl2[0] = 42; verts_lvl2[1] = 41;
+        verts_lvl2[2] = 48; verts_lvl2[3] = 47;
+        verts_lvl2[4] = 54; verts_lvl2[5] = 53;
+        verts_lvl2[6] = 60; verts_lvl2[7] = 59;
+      } else {
+        verts_lvl2[0] = 29; verts_lvl2[1] = 30;
+        verts_lvl2[2] = 35; verts_lvl2[3] = 36;
+        verts_lvl2[4] = 38; verts_lvl2[5] = 39;
+        verts_lvl2[6] = 32; verts_lvl2[7] = 33;
+      }
+
+    int verts_lvl1[4];
+    switch(nPts) {
+      case(4):
+        verts_lvl1[0] = 39;
+        verts_lvl1[1] = 45;
+        verts_lvl1[2] = 51;
+        verts_lvl1[3] = 57;
+        break;
+      case(3):
+        verts_lvl1[0] = 31;
+        verts_lvl1[1] = 37;
+        verts_lvl1[2] = 40;
+        verts_lvl1[3] = 34;     
+        break;
+      case(2):
+        verts_lvl1[0] = 21;
+        verts_lvl1[1] = 23;
+        verts_lvl1[2] = 24;
+        verts_lvl1[3] = 22;
+        break;
+    }
+
+      for (int q = 0; q < nPts - 1; q++) {
+        std::vector<MVertex*> vq, veq;
+        vq.push_back(ve[2*nPts + q]);
+        vq.push_back(ve[4*nPts + q]);
+        vq.push_back(ve[6*nPts + q]);
+        vq.push_back(ve[7*nPts + q]);
+
+        int triverts = nPts*(nPts-1)/2;
+
+        if (nPts-q == 4)
+          for (int f = 0; f < 12; f++)
+            veq.push_back(ve[verts_lvl3[f]-5]);
+        else if (nPts-q == 3)
+          for (int f = 0; f < 8; f++)
+            veq.push_back(ve[verts_lvl2[f]-5]);        
+        else if (nPts-q == 2)
+          for (int f = 0; f < 4; f++)
+            veq.push_back(ve[verts_lvl1[f]-5]);
+
+        if (nPts-q == 2) {
+          MQuadrangle8 incpl2(vq[0], vq[1], vq[2], vq[3],
+                       veq[0], veq[1], veq[2], veq[3]);
+          SPoint3 pointz;
+          incpl2.pnt(0,0,0,pointz);
+          MVertex *v = new MVertex(pointz.x(), pointz.y(), pointz.z(), gr);
+
+          gr->mesh_vertices.push_back(v);
+          std::vector<MVertex*>::iterator cursor = vr.begin();
+          cursor += nPts == 2 ? 0 : 4;
+          vr.insert(cursor, v);
+        }
+        else if (nPts-q == 3) {
+
+          MQuadrangleN incpl2(vq[0], vq[1], vq[2], vq[3], veq, 3);
+          int offsets[4] = {nPts == 4 ? 7 : 0,
+                            nPts == 4 ? 9 : 1,
+                            nPts == 4 ? 11 : 2,
+                            nPts == 4 ? 12 : 3};
+          double quad_v [4][2] = {{-1.0/3.0, -1.0/3.0},
+                               { 1.0/3.0, -1.0/3.0},
+                               { 1.0/3.0,  1.0/3.0},
+                               {-1.0/3.0,  1.0/3.0}};
+          SPoint3 pointz;
+          for (int k = 0; k<4; k++) {
+            incpl2.pnt(quad_v[k][0], quad_v[k][1], 0, pointz);
+            MVertex *v = new MVertex(pointz.x(), pointz.y(), pointz.z(), gr);
+            gr->mesh_vertices.push_back(v);
+            std::vector<MVertex*>::iterator cursor = vr.begin();
+            cursor += offsets[k];
+            vr.insert(cursor, v);
+          }
+        }
+        else if (nPts-q == 4) {
+          MQuadrangleN incpl2(vq[0], vq[1], vq[2], vq[3], veq, 4);
+          int offsets[9] = {0, 1, 2, 3, 5, 8, 10, 6, 13};
+          double quad_v [9][2] = {
+                               { -0.5, -0.5},
+                               {  0.5, -0.5},
+                               {  0.5,  0.5},
+                               { -0.5,  0.5},
+                               {  0.0, -0.5},
+                               {  0.5,  0.0},
+                               {  0.0,  0.5},                               
+                               { -0.5,  0.0},
+                               {  0.0,  0.0}
+                                 };
+          SPoint3 pointz;
+          for (int k = 0; k<9; k++) {
+            incpl2.pnt(quad_v[k][0], quad_v[k][1], 0, pointz);
+            MVertex *v = new MVertex(pointz.x(), pointz.y(), pointz.z(), gr);
+            gr->mesh_vertices.push_back(v);
+            std::vector<MVertex*>::iterator cursor = vr.begin();
+            cursor += offsets[k];
+            vr.insert(cursor, v);
+          }
+
+
+        }
+
+      }
       ve.insert(ve.end(), vr.begin(), vr.end());
-      printf("Hmmm, let's see : %d\n", nPts);
       MPyramid *n = new MPyramidN(p->getVertex(0), p->getVertex(1), p->getVertex(2),
-				  p->getVertex(3), p->getVertex(4), ve, nPts + 1);
+				                          p->getVertex(3), p->getVertex(4), ve, nPts + 1);
       pyramids2.push_back(n);
-      */
+      SPoint3 test_pnt;
+      n->pnt(-1,-1,0, test_pnt);
     }
     delete p;
   }
diff --git a/Mesh/highOrderTools.cpp b/Mesh/highOrderTools.cpp
index 2e966677a2b9f32b08b7cecb78ad6ee20cbad761..b2d2cb06af000d66646449d7e74eaf6bc9f78a66 100644
--- a/Mesh/highOrderTools.cpp
+++ b/Mesh/highOrderTools.cpp
@@ -469,7 +469,7 @@ void highOrderTools::computeStraightSidedPositions ()
     for (unsigned int i=0;i<(*it)->triangles.size();i++){
       MTriangle *t = (*it)->triangles[i];
       MFace face = t->getFace(0);
-      const polynomialBasis* fs = t->getFunctionSpace();
+      const nodalBasis* fs = t->getFunctionSpace();
       for (int j=0;j<t->getNumVertices();j++){
         if (t->getVertex(j)->onWhat() == *it){
           const double t1 = fs->points(j, 0);
@@ -484,7 +484,7 @@ void highOrderTools::computeStraightSidedPositions ()
       //      printf("coucou quad %d\n",i);
       MQuadrangle *q = (*it)->quadrangles[i];
       MFace face = q->getFace(0);
-      const polynomialBasis* fs = q->getFunctionSpace();
+      const nodalBasis* fs = q->getFunctionSpace();
       for (int j=0;j<q->getNumVertices();j++){
         if (q->getVertex(j)->onWhat() == *it){
           const double t1 = fs->points(j, 0);
@@ -509,7 +509,7 @@ void highOrderTools::computeStraightSidedPositions ()
           (*it)->tetrahedra[i]->getVertex(1),
           (*it)->tetrahedra[i]->getVertex(2),
           (*it)->tetrahedra[i]->getVertex(3));
-      const polynomialBasis* fs = t->getFunctionSpace();
+      const nodalBasis* fs = t->getFunctionSpace();
       for (int j=0;j<t->getNumVertices();j++){
         if (t->getVertex(j)->onWhat() == *it){
           double t1 = fs->points(j, 0);
@@ -532,7 +532,7 @@ void highOrderTools::computeStraightSidedPositions ()
           (*it)->hexahedra[i]->getVertex(5),
           (*it)->hexahedra[i]->getVertex(6),
           (*it)->hexahedra[i]->getVertex(7));
-      const polynomialBasis* fs = h->getFunctionSpace();
+      const nodalBasis* fs = h->getFunctionSpace();
       for (int j=0;j<h->getNumVertices();j++){
         if (h->getVertex(j)->onWhat() == *it){
           double t1 = fs->points(j, 0);
diff --git a/Numeric/BasisFactory.cpp b/Numeric/BasisFactory.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..56f38633cab15172ff58a50d2dc7f5730238b7dd
--- /dev/null
+++ b/Numeric/BasisFactory.cpp
@@ -0,0 +1,216 @@
+// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-B-> Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#include "GmshDefines.h"
+#include "GmshMessage.h"
+#include "polynomialBasis.h"
+#include "pyramidalBasis.h"
+#include "pointsGenerators.h"
+#include "BasisFactory.h"
+
+std::map<int, nodalBasis*> BasisFactory::fs;
+
+const nodalBasis* BasisFactory::create(int elementType) {
+
+  // If the Basis has already been built, return it.
+  std::map<int, nodalBasis*>::const_iterator it = fs.find(elementType);
+  if (it != fs.end()) {
+    return it->second;
+  }
+  // Get the parent type to see which kind of basis
+  // we want to create
+  int parentType = MElement::ParentTypeFromTag(elementType);
+  nodalBasis* B = 0;
+
+  switch(parentType) {
+    case(TYPE_PNT):
+    case(TYPE_LIN):
+    case(TYPE_TRI):
+    case(TYPE_QUA):
+    case(TYPE_PRI):
+    case(TYPE_TET):
+    case(TYPE_HEX):
+      B = new polynomialBasis();
+      break;
+    case(TYPE_PYR):
+      B = new pyramidalBasis();
+      break;
+    default:
+      Msg::Error("Unknown type of element.");
+      return 0;
+  }
+  B->parentType = parentType;
+
+  // There is currently only 1 type of basis for any
+  // element type, hence we use the element type as the
+  // basis type.
+  B->type = elementType;
+  switch(elementType) {
+    case MSH_PNT     : B->order = 0; B->serendip = false; break;
+    case MSH_LIN_1   : B->order = 0; B->serendip = false; break;
+    case MSH_LIN_2   : B->order = 1; B->serendip = false; break;
+    case MSH_LIN_3   : B->order = 2; B->serendip = false; break;
+    case MSH_LIN_4   : B->order = 3; B->serendip = false; break;
+    case MSH_LIN_5   : B->order = 4; B->serendip = false; break;
+    case MSH_LIN_6   : B->order = 5; B->serendip = false; break;
+    case MSH_LIN_7   : B->order = 6; B->serendip = false; break;
+    case MSH_LIN_8   : B->order = 7; B->serendip = false; break;
+    case MSH_LIN_9   : B->order = 8; B->serendip = false; break;
+    case MSH_LIN_10  : B->order = 9; B->serendip = false; break;
+    case MSH_LIN_11  : B->order = 10;B->serendip = false; break;
+    case MSH_TRI_1   : B->order = 0; B->serendip = false; break;
+    case MSH_TRI_3   : B->order = 1; B->serendip = false; break;
+    case MSH_TRI_6   : B->order = 2; B->serendip = false; break;
+    case MSH_TRI_10  : B->order = 3; B->serendip = false; break;
+    case MSH_TRI_15  : B->order = 4; B->serendip = false; break;
+    case MSH_TRI_21  : B->order = 5; B->serendip = false; break;
+    case MSH_TRI_28  : B->order = 6; B->serendip = false; break;
+    case MSH_TRI_36  : B->order = 7; B->serendip = false; break;
+    case MSH_TRI_45  : B->order = 8; B->serendip = false; break;
+    case MSH_TRI_55  : B->order = 9; B->serendip = false; break;
+    case MSH_TRI_66  : B->order = 10;B->serendip = false; break;
+    case MSH_TRI_9   : B->order = 3; B->serendip = true;  break;
+    case MSH_TRI_12  : B->order = 4; B->serendip = true;  break;
+    case MSH_TRI_15I : B->order = 5; B->serendip = true;  break;
+    case MSH_TRI_18  : B->order = 6; B->serendip = true;  break;
+    case MSH_TRI_21I : B->order = 7; B->serendip = true;  break;
+    case MSH_TRI_24  : B->order = 8; B->serendip = true;  break;
+    case MSH_TRI_27  : B->order = 9; B->serendip = true;  break;
+    case MSH_TRI_30  : B->order = 10;B->serendip = true;  break;
+    case MSH_TET_1   : B->order = 0; B->serendip = false; break;
+    case MSH_TET_4   : B->order = 1; B->serendip = false; break;
+    case MSH_TET_10  : B->order = 2; B->serendip = false; break;
+    case MSH_TET_20  : B->order = 3; B->serendip = false; break;
+    case MSH_TET_35  : B->order = 4; B->serendip = false; break;
+    case MSH_TET_56  : B->order = 5; B->serendip = false; break;
+    case MSH_TET_84  : B->order = 6; B->serendip = false; break;
+    case MSH_TET_120 : B->order = 7; B->serendip = false; break;
+    case MSH_TET_165 : B->order = 8; B->serendip = false; break;
+    case MSH_TET_220 : B->order = 9; B->serendip = false; break;
+    case MSH_TET_286 : B->order = 10;B->serendip = false; break;
+    case MSH_TET_34  : B->order = 4; B->serendip = true;  break;
+    case MSH_TET_52  : B->order = 5; B->serendip = true;  break;
+    case MSH_TET_74  : B->order = 6; B->serendip = true;  break;
+    case MSH_TET_100 : B->order = 7; B->serendip = true;  break;
+    case MSH_TET_130 : B->order = 8; B->serendip = true;  break;
+    case MSH_TET_164 : B->order = 9; B->serendip = true;  break;
+    case MSH_TET_202 : B->order = 10;B->serendip = true;  break;
+    case MSH_QUA_1   : B->order = 0; B->serendip = false; break;
+    case MSH_QUA_4   : B->order = 1; B->serendip = false; break;
+    case MSH_QUA_9   : B->order = 2; B->serendip = false; break;
+    case MSH_QUA_16  : B->order = 3; B->serendip = false; break;
+    case MSH_QUA_25  : B->order = 4; B->serendip = false; break;
+    case MSH_QUA_36  : B->order = 5; B->serendip = false; break;
+    case MSH_QUA_49  : B->order = 6; B->serendip = false; break;
+    case MSH_QUA_64  : B->order = 7; B->serendip = false; break;
+    case MSH_QUA_81  : B->order = 8; B->serendip = false; break;
+    case MSH_QUA_100 : B->order = 9; B->serendip = false; break;
+    case MSH_QUA_121 : B->order = 10;B->serendip = false; break;
+    case MSH_QUA_8   : B->order = 2; B->serendip = true;  break;
+    case MSH_QUA_12  : B->order = 3; B->serendip = true;  break;
+    case MSH_QUA_16I : B->order = 4; B->serendip = true;  break;
+    case MSH_QUA_20  : B->order = 5; B->serendip = true;  break;
+    case MSH_QUA_24  : B->order = 6; B->serendip = true;  break;
+    case MSH_QUA_28  : B->order = 7; B->serendip = true;  break;
+    case MSH_QUA_32  : B->order = 8; B->serendip = true;  break;
+    case MSH_QUA_36I : B->order = 9; B->serendip = true;  break;
+    case MSH_QUA_40  : B->order = 10;B->serendip = true;  break;
+    case MSH_PRI_1   : B->order = 0; B->serendip = false; break;
+    case MSH_PRI_6   : B->order = 1; B->serendip = false; break;
+    case MSH_PRI_18  : B->order = 2; B->serendip = false; break;
+    case MSH_HEX_8   : B->order = 1; B->serendip = false; break;
+    case MSH_HEX_27  : B->order = 2; B->serendip = false; break;
+    case MSH_HEX_64  : B->order = 3; B->serendip = false; break;
+    case MSH_HEX_125 : B->order = 4; B->serendip = false; break;
+    case MSH_HEX_216 : B->order = 5; B->serendip = false; break;
+    case MSH_HEX_343 : B->order = 6; B->serendip = false; break;
+    case MSH_HEX_512 : B->order = 7; B->serendip = false; break;
+    case MSH_HEX_729 : B->order = 8; B->serendip = false; break;
+    case MSH_HEX_1000: B->order = 9; B->serendip = false; break;
+    case MSH_HEX_20  : B->order = 2; B->serendip = false; break;
+    case MSH_HEX_56  : B->order = 3; B->serendip = true;  break;
+    case MSH_HEX_98  : B->order = 4; B->serendip = true;  break;
+    case MSH_HEX_152 : B->order = 5; B->serendip = true;  break;
+    case MSH_HEX_222 : B->order = 6; B->serendip = true;  break;
+    case MSH_HEX_296 : B->order = 7; B->serendip = true;  break;
+    case MSH_HEX_386 : B->order = 8; B->serendip = true;  break;
+    case MSH_HEX_488 : B->order = 9; B->serendip = true;  break;
+    case MSH_PYR_1   : B->order = 0; B->serendip = false; break;
+    case MSH_PYR_5   : B->order = 1; B->serendip = false; break;
+    case MSH_PYR_14  : B->order = 2; B->serendip = false; break;
+    case MSH_PYR_30  : B->order = 3; B->serendip = false; break;
+    case MSH_PYR_55  : B->order = 4; B->serendip = false; break;
+    case MSH_PYR_91  : B->order = 5; B->serendip = false; break;
+    case MSH_PYR_140 : B->order = 6; B->serendip = false; break;
+    case MSH_PYR_204 : B->order = 7; B->serendip = false; break;
+    case MSH_PYR_285 : B->order = 8; B->serendip = false; break;
+    case MSH_PYR_385 : B->order = 9; B->serendip = false; break;
+    case MSH_PYR_29  : B->order = 3; B->serendip = true; break;
+    case MSH_PYR_50  : B->order = 4; B->serendip = true; break;
+    case MSH_PYR_77  : B->order = 5; B->serendip = true; break;
+    case MSH_PYR_110 : B->order = 6; B->serendip = true; break;
+    case MSH_PYR_149 : B->order = 7; B->serendip = true; break;
+    case MSH_PYR_194 : B->order = 8; B->serendip = true; break;
+    case MSH_PYR_245 : B->order = 9; B->serendip = true; break;    
+
+    default :
+      Msg::Error("Unknown function space %d: reverting to TET_4", elementType);
+      B->parentType = TYPE_TET; B->order = 1; B->serendip = false; break;
+  }
+
+  // Here is where we do create the basis. 
+  switch (B->parentType) {
+  case TYPE_PNT :
+    B->numFaces = 1;
+    B->dimension = 0;
+    B->points = gmshGeneratePointsLine(0);
+    break;
+  case TYPE_LIN :
+    B->numFaces = 2;
+    B->dimension = 1;
+    B->points = gmshGeneratePointsLine(B->order);
+    break;
+  case TYPE_TRI :
+    B->numFaces = 3;
+    B->dimension = 2;
+    B->points = gmshGeneratePointsTriangle(B->order, B->serendip);
+    break;
+  case TYPE_QUA :
+    B->numFaces = 4;
+    B->dimension = 2;
+    B->points = gmshGeneratePointsQuadrangle(B->order, B->serendip);
+    break;
+  case TYPE_TET :
+    B->numFaces = 4;
+    B->dimension = 3;
+    B->points = gmshGeneratePointsTetrahedron(B->order, B->serendip);
+    B->points.print();
+    break;
+  case TYPE_PRI :
+    B->numFaces = 5;
+    B->dimension = 3;
+    B->points = gmshGeneratePointsPrism(B->order, B->serendip);
+    break;
+  case TYPE_HEX :
+    B->numFaces = 6;
+    B->dimension = 3;
+    B->points = gmshGeneratePointsHexahedron(B->order, B->serendip);
+    break;
+  case TYPE_PYR :
+    B->numFaces = 5;
+    B->dimension = 3;
+    B->points = gmshGeneratePointsPyramid(B->order, B->serendip);
+    break;
+  default:
+    Msg::Error("Unknown element type!\n");
+  }
+
+  B->initialize();
+
+  fs.insert(std::make_pair(elementType, B));
+
+  return fs[elementType];
+
+}
diff --git a/Numeric/BasisFactory.h b/Numeric/BasisFactory.h
new file mode 100644
index 0000000000000000000000000000000000000000..691a8340d29088da2d715d2a632e642041ce0afa
--- /dev/null
+++ b/Numeric/BasisFactory.h
@@ -0,0 +1,24 @@
+// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#ifndef BASISFACTORY_H
+#define BASISFACTORY_H
+
+#include "MElement.h"
+#include "MPyramid.h"
+#include "nodalBasis.h"
+
+class BasisFactory
+{
+  private:
+    static std::map<int, nodalBasis*> fs;
+
+  public:
+    // Caution: the returned pointer should be
+    // checked against 0.
+    static const nodalBasis* create(int elementType);
+};
+
+#endif
\ No newline at end of file
diff --git a/Numeric/BergotBasis.cpp b/Numeric/BergotBasis.cpp
index bc8ce13da41f92770cebeafd83f486dae3c5fcfc..e361960798f64e78940a03ef197e3f4b28ce98b0 100644
--- a/Numeric/BergotBasis.cpp
+++ b/Numeric/BergotBasis.cpp
@@ -5,6 +5,11 @@
 
 #include "BergotBasis.h"
 
+/*BergotBasis::BergotBasis() {
+
+
+}*/
+
 BergotBasis::BergotBasis(int p): order(p)
 {
   // allocate function information and fill
@@ -13,7 +18,8 @@ BergotBasis::BergotBasis(int p): order(p)
   jOrder = new int[size()];
   kOrder = new int[size()];
 
-  legendre = new LegendrePolynomials(order);
+  LegendrePolynomials lp(p);
+  legendre = lp;
 
   int index = 0;
   for (int i=0;i<=order;i++) {
@@ -26,22 +32,21 @@ BergotBasis::BergotBasis(int p): order(p)
         kOrder[index] = k;
 
         if (jacobi.find(mIJ) == jacobi.end()) {
-          jacobi[mIJ] = new JacobiPolynomials(2*mIJ+2,0,order);
+          JacobiPolynomials jp(2*mIJ+2,0,order);
+          jacobi[mIJ] = jp;
         }
       }
     }
   }
 }
 
+
 BergotBasis::~BergotBasis()
 {
   delete [] iOrder;
   delete [] jOrder;
   delete [] kOrder;
 
-  delete legendre;
-  std::map<int,JacobiPolynomials*>::iterator jIter = jacobi.begin();
-  for (;jIter!=jacobi.end();++jIter) delete jIter->second;
 }
 
 int BergotBasis::size() const
@@ -54,21 +59,22 @@ void BergotBasis::f(double u, double v, double w, double* val) const
   double uhat = (w == 1.) ? 1 : u/(1.-w);
 
   std::vector<double> uFcts(order+1);
-  legendre->f(uhat,&(uFcts[0]));
+  //double uFcts[order+1];
+  legendre.f(uhat,&(uFcts[0]));
 
   double vhat = (w == 1.) ? 1 : v/(1.-w);
   std::vector<double> vFcts(order+1);
-  legendre->f(vhat,&(vFcts[0]));
+  legendre.f(vhat,&(vFcts[0]));
 
   double what = 2.*w - 1.;
   std::map<int,double* > wFcts;
-  std::map<int,JacobiPolynomials*>::const_iterator jIter=jacobi.begin();
+  std::map<int,JacobiPolynomials>::const_iterator jIter=jacobi.begin();
 
   for (;jIter!=jacobi.end();jIter++) {
     int a = jIter->first;
     wFcts[a] = new double[order + 1];
     double* wf = wFcts[a];
-    jIter->second->f(what,wf);
+    jIter->second.f(what,wf);
   }
 
   // recombine to find shape function values
@@ -93,33 +99,32 @@ void BergotBasis::f(double u, double v, double w, double* val) const
   }
 }
 
-void BergotBasis::df(double u, double v, double w, double grads[][3]) const
+inline void BergotBasis::df(double u, double v, double w, double grads[][3]) const
 {
   std::vector<double> uFcts(order+1);
-  legendre->f(u,&(uFcts[0]));
+  legendre.f(u,&(uFcts[0]));
 
   std::vector<double> uGrads(order+1);
-  legendre->df(u,&(uGrads[0]));
+  legendre.df(u,&(uGrads[0]));
 
   std::vector<double> vFcts(order+1);
-  legendre->f(v,&(vFcts[0]));
-
- std::vector<double> vGrads(order+1);
-  legendre->df(v,&(vGrads[0]));
+  legendre.f(v,&(vFcts[0]));
 
+  std::vector<double> vGrads(order+1);
+  legendre.df(v,&(vGrads[0]));
 
   std::map<int,double* > wFcts;
   std::map<int,double* > wGrads;
-  std::map<int,JacobiPolynomials*>::const_iterator jIter=jacobi.begin();
+  std::map<int,JacobiPolynomials>::const_iterator jIter=jacobi.begin();
 
   for (;jIter!=jacobi.end();jIter++) {
     int a = jIter->first;
     wFcts[a] = new double[order+1];
     double* wf = wFcts[a];
-    jIter->second->f(w,wf);
+    jIter->second.f(w,wf);
     wGrads[a] = new double[order+1];
     double* wg = wGrads[a];
-    jIter->second->df(w,wg);
+    jIter->second.df(w,wg);
   }
 
   // now recombine to find the shape function gradients
diff --git a/Numeric/BergotBasis.h b/Numeric/BergotBasis.h
index cecf7b1bbe7e6f0c7a2bee7eaacf82ac8bfbfb4e..0a68e68ce46ae34cb3db150fd8799ae812c54c5f 100644
--- a/Numeric/BergotBasis.h
+++ b/Numeric/BergotBasis.h
@@ -6,18 +6,22 @@
 #ifndef BERGOTBASIS_H
 #define BERGOTBASIS_H
 
+#include "nodalBasis.h"
 #include "polynomialBasis.h"
 #include "jacobiPolynomials.h"
 #include "legendrePolynomials.h"
 
-class BergotBasis : public polynomialBasis {
+class BergotBasis : public nodalBasis {
  public:
 
+  BergotBasis() {};
   BergotBasis(int p);
   ~BergotBasis();
 
   void f(double u, double v, double w, double *val) const;
-  void df(double u, double v, double w, double grads[][3]) const;
+  inline void df(double u, double v, double w, double grads[][3]) const;
+
+  void initialize() {};
 
  private:
   int order; //!< maximal order of surrounding functional spaces (on triangle / quad)
@@ -27,10 +31,10 @@ class BergotBasis : public polynomialBasis {
   int *kOrder; //!< order of \f$\hat \zeta \f$ polynomial
 
   //! list of Legendre polynomials up to order p
-  LegendrePolynomials* legendre;
+  LegendrePolynomials legendre;
 
   //! list of Jacobi polynomials up to order p in function of index i (\f$ \alpha = 2*i + 2\f$)
-  std::map<int,JacobiPolynomials*> jacobi;
+  std::map<int,JacobiPolynomials> jacobi;
 
   int size() const;
 
diff --git a/Numeric/CMakeLists.txt b/Numeric/CMakeLists.txt
index 62bab4da4f03f835e9f700770b972d44bad3d9f4..aa2bb2bb932f5a5e7a23a0dd2df366f98ef1419a 100644
--- a/Numeric/CMakeLists.txt
+++ b/Numeric/CMakeLists.txt
@@ -6,9 +6,11 @@
 set(SRC
   Numeric.cpp
     fullMatrix.cpp
+  BasisFactory.cpp
     polynomialBasis.cpp
     JacobianBasis.cpp
     BergotBasis.cpp
+    pyramidalBasis.cpp
     jacobiPolynomials.cpp
     legendrePolynomials.cpp
   pointsGenerators.cpp
diff --git a/Numeric/jacobiPolynomials.h b/Numeric/jacobiPolynomials.h
index 7b88a950c1be2b35727ca225166e8ef7f3c5c1f5..0b9919cc5f5afd01b2ea1cfda53c93a8d1fe5bb2 100644
--- a/Numeric/jacobiPolynomials.h
+++ b/Numeric/jacobiPolynomials.h
@@ -11,6 +11,7 @@
 class JacobiPolynomials {
 
  public:
+  JacobiPolynomials() {};
   JacobiPolynomials(double a, double b, int o);
   ~JacobiPolynomials();
 
diff --git a/Numeric/legendrePolynomials.cpp b/Numeric/legendrePolynomials.cpp
index 3968e53c4eb48dee71f19fbfac5235cf273030c6..b0cc7281c14b5b3ed8bbab47c1925d395bfee216 100644
--- a/Numeric/legendrePolynomials.cpp
+++ b/Numeric/legendrePolynomials.cpp
@@ -5,8 +5,10 @@
 
 #include "legendrePolynomials.h"
 
-LegendrePolynomials::LegendrePolynomials(int o): n(o) {}
-LegendrePolynomials::~LegendrePolynomials() {;}
+LegendrePolynomials::LegendrePolynomials(int o): n(o) {
+
+}
+LegendrePolynomials::~LegendrePolynomials() {}
 
 void LegendrePolynomials::f(double u, double *val) const
 {
diff --git a/Numeric/legendrePolynomials.h b/Numeric/legendrePolynomials.h
index ce7dd998b99f72adec4af6ca31e93aae01f6caa6..a7d9a497c1fe7dad03e4e106138b06805c933e03 100644
--- a/Numeric/legendrePolynomials.h
+++ b/Numeric/legendrePolynomials.h
@@ -11,6 +11,7 @@
 class LegendrePolynomials {
 
  public:
+  LegendrePolynomials() {};
   LegendrePolynomials(int o);
   ~LegendrePolynomials();
 
diff --git a/Numeric/nodalBasis.h b/Numeric/nodalBasis.h
new file mode 100644
index 0000000000000000000000000000000000000000..94791d6bc7ba7be9fdb515446d9f7997ba032395
--- /dev/null
+++ b/Numeric/nodalBasis.h
@@ -0,0 +1,32 @@
+// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#ifndef BASIS_H
+#define BASIS_H
+
+#include "fullMatrix.h"
+
+class nodalBasis {
+
+ public:
+  int type, parentType, order, dimension, numFaces;
+  bool serendip;
+  fullMatrix<double> points;
+
+  virtual void initialize() {};
+
+  // Basis functions evaluation
+  inline virtual void f(double u, double v, double w, double *sf) const {};
+  inline void f(fullMatrix<double> &coord, fullMatrix<double> &sf) const;
+
+  // Basis functions gradients evaluation
+  inline virtual void df(double u, double v, double w, double grads[][3]) const {};
+  inline void df(fullMatrix<double> &coord, fullMatrix<double> &dfm) const;
+  
+  inline void ddf(double u, double v, double w, double grads[][3][3]) const {};
+  inline void dddf(double u, double v, double w, double grads[][3][3][3]) const {};
+
+};
+#endif
\ No newline at end of file
diff --git a/Numeric/pointsGenerators.cpp b/Numeric/pointsGenerators.cpp
index c340ca51d66bb7ec7a7e0801d78b2f2c810532cf..aa14897fe739f2f96beef6a1b861183f8753ca36 100644
--- a/Numeric/pointsGenerators.cpp
+++ b/Numeric/pointsGenerators.cpp
@@ -430,7 +430,6 @@ fullMatrix<double> gmshGeneratePointsTetrahedron(int order, bool serendip)
   }
 
   points.scale(overOrder);
-  points.print();
   return points;
 
 }
@@ -778,9 +777,5 @@ fullMatrix<double> gmshGeneratePointsPyramid(int order, bool serendip)
         }
       }
     }
-    for (int i = 0; i < points.size1(); i++) {
-      printf("Point(%d) %g, %g, %g\n", i, points(i,0),points(i,1),points(i,2));
-    }
-    printf("number of points : %d\n\n", nbPoints);
     return points;
 }
diff --git a/Numeric/polynomialBasis.cpp b/Numeric/polynomialBasis.cpp
index 1922abd238990e89adeeaf916d690ec09fe4b04e..ea67a22634c9f32d7c237a81fdb582dc1f785000 100644
--- a/Numeric/polynomialBasis.cpp
+++ b/Numeric/polynomialBasis.cpp
@@ -42,6 +42,8 @@ static void printClosure(polynomialBasis::clCont &fullClosure,
 }
 */
 
+
+
 int polynomialBasis::getTag(int parentTag, int order, bool serendip)
 {
   switch (parentTag) {
@@ -131,7 +133,7 @@ int polynomialBasis::getTag(int parentTag, int order, bool serendip)
   }
 }
 
-static fullMatrix<double> generate1DMonomials(int order)
+fullMatrix<double> generate1DMonomials(int order)
 {
   fullMatrix<double> monomials(order + 1, 1);
   for (int i = 0; i < order + 1; i++) monomials(i, 0) = i;
@@ -964,7 +966,6 @@ static fullMatrix<double> generateLagrangeMonomialCoefficients
   (const fullMatrix<double>& monomial, const fullMatrix<double>& point)
 {
   if(monomial.size1() != point.size1() || monomial.size2() != point.size2()){
-    Msg::Info("Here");
     Msg::Fatal("Wrong sizes for Lagrange coefficients generation %d %d -- %d %d",
          monomial.size1(),point.size1(),
          monomial.size2(),point.size2() );
@@ -1538,6 +1539,82 @@ static void generateClosureOrder0(polynomialBasis::clCont &closure, int nb)
 
 std::map<int, polynomialBasis> polynomialBases::fs;
 
+
+void polynomialBasis::initialize()
+{
+  switch(parentType) {
+    case TYPE_PNT:
+      monomials = generate1DMonomials(0);
+      break;
+    case TYPE_LIN:
+      monomials = generate1DMonomials(order);
+      generate1dVertexClosure(closures, order);
+      generate1dVertexClosureFull(fullClosures, closureRef, order);
+      break;
+    case TYPE_TRI:
+      monomials = serendip ? generatePascalSerendipityTriangle(order) :
+                    generatePascalTriangle(order);
+      if (order == 0) {
+        generateClosureOrder0(closures, 6);
+        generateClosureOrder0(fullClosures, 6);
+        closureRef.resize(6,0);
+      }
+      else {
+        generate2dEdgeClosure(closures, order);
+        generate2dEdgeClosureFull(fullClosures, closureRef, order, 3, serendip);
+      }
+      break;
+    case TYPE_QUA:
+      monomials = serendip ? generatePascalQuadSerendip(order) :
+                    generatePascalQuad(order);
+      if (order == 0) {
+        generateClosureOrder0(closures, 8);
+        generateClosureOrder0(fullClosures, 8);
+        closureRef.resize(8, 0);
+      }
+      else {
+        generate2dEdgeClosure(closures, order, 4);
+        generate2dEdgeClosureFull(fullClosures, closureRef, order, 4, serendip);
+      }
+      break;
+    case TYPE_TET:
+      monomials = serendip ? generatePascalSerendipityTetrahedron(order) :
+                    generatePascalTetrahedron(order);
+      if (order == 0) {
+        generateClosureOrder0(closures,24);
+        generateClosureOrder0(fullClosures, 24);
+        closureRef.resize(24, 0);
+      }
+      else {
+        generateFaceClosureTet(closures, order);
+        generateFaceClosureTetFull(fullClosures, closureRef, order, serendip);
+      }
+      break;
+    case TYPE_PRI:
+      monomials = generatePascalPrism(order);
+      if (order == 0) {
+        generateClosureOrder0(closures,48);
+        generateClosureOrder0(fullClosures,48);
+        closureRef.resize(48, 0);
+      }
+      else {
+        generateFaceClosurePrism(closures, order);
+        generateFaceClosurePrismFull(fullClosures, closureRef, order);
+      }
+      break;
+    case TYPE_HEX:
+      monomials = generatePascalHex(order, serendip);
+      generateFaceClosureHex(closures, order, serendip, points);
+      generateFaceClosureHexFull(fullClosures, closureRef, order, serendip, points);
+      break;
+  }
+  
+  this->points.print();
+  coefficients = generateLagrangeMonomialCoefficients(monomials, points);
+
+}
+
+
 const polynomialBasis *polynomialBases::find(int tag)
 {
   std::map<int, polynomialBasis>::const_iterator it = fs.find(tag);
diff --git a/Numeric/polynomialBasis.h b/Numeric/polynomialBasis.h
index 7b1988c4e8d8ee16e4fb25fb3a4509f2417520e0..72e5a01c2d34b0f2edccd27aa4455013a4ab90ed 100644
--- a/Numeric/polynomialBasis.h
+++ b/Numeric/polynomialBasis.h
@@ -10,6 +10,7 @@
 #include <map>
 #include <vector>
 #include "fullMatrix.h"
+#include "nodalBasis.h"
 #include <iostream>
 
 #define SQU(a)  ((a)*(a))
@@ -65,15 +66,20 @@ inline double pow_int(const double &a, const int &n)
   }
 }
 
-class polynomialBasis
+fullMatrix<double> generate1DMonomials(int order);
+
+
+
+
+class polynomialBasis : public nodalBasis
 {
   // integrationOrder, closureId => df/dXi
   mutable std::map<int,std::vector<fullMatrix<double> > > _dfAtFace;
  public:
   // for now the only implemented polynomial basis are nodal poly
   // basis, we use the type of the corresponding gmsh element as type
-  int type, parentType, order, dimension;
-  bool serendip;
+  //int type, parentType, order, dimension;
+  //bool serendip;
   class closure : public std::vector<int> {
     public:
     int type;
@@ -89,10 +95,13 @@ class polynomialBasis
   // quad face)
   clCont closures, fullClosures;
   std::vector<int> closureRef;
-  fullMatrix<double> points;
+  //fullMatrix<double> points;
   fullMatrix<double> monomials;
   fullMatrix<double> coefficients;
   int numFaces;
+
+  void initialize();
+
   inline int getNumShapeFunctions() const {return coefficients.size1();}
   // for a given face/edge, with both a sign and a rotation, give an
   // ordered list of nodes on this face/edge
diff --git a/Numeric/pyramidalBasis.cpp b/Numeric/pyramidalBasis.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf84f8832f88de579e8366bc4eb2cd4e7a840fb4
--- /dev/null
+++ b/Numeric/pyramidalBasis.cpp
@@ -0,0 +1,60 @@
+// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#include "pyramidalBasis.h"
+
+pyramidalBasis::pyramidalBasis()
+{
+
+}
+
+void pyramidalBasis::initialize()
+{
+
+  BergotBasis bb(order);
+  bergot = bb;
+
+  int n = order+1;
+  int num_points = n*(n+1)*(2*n+1)/6;
+  if (serendip and order > 2) {
+    num_points -= (order-2)*((order-2)+1)*(2*(order-2)+1)/6;
+  }
+
+  VDMinv = new fullMatrix<double>(num_points, num_points);
+
+  // Invert the Vandermonde matrix
+  fullMatrix<double> VDM = fullMatrix<double>(num_points, num_points);
+  for (int j = 0; j < num_points; j++) {
+    double f[num_points];
+    bergot.f(points(j,0), points(j,1), points(j, 2), f);
+    for (int i = 0; i < num_points; i++) {
+      VDM(i,j) = f[i];
+    }
+  }
+  VDM.invert(*VDMinv);
+}
+  
+inline void pyramidalBasis::f(double u, double v, double w, double *val) const
+{
+  int n = order+1;
+  int num_points = n*(n+1)*(2*n+1)/6;
+
+  double f[n*n*n];
+  bergot.f(u,v,w, f);
+
+  for (int i = 0; i < num_points; i++) {
+    val[i] = 0.0;
+    for (int j = 0; j < num_points; j++) {
+      val[i] += (*VDMinv)(i,j)*f[j];
+    }
+  }
+}
+
+inline void pyramidalBasis::df(double u, double v, double w, double grads[][3]) const
+{
+
+}
+
+
diff --git a/Numeric/pyramidalBasis.h b/Numeric/pyramidalBasis.h
new file mode 100644
index 0000000000000000000000000000000000000000..1055d039e8980cf18bdbe424a3468ae763dc031e
--- /dev/null
+++ b/Numeric/pyramidalBasis.h
@@ -0,0 +1,34 @@
+// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#ifndef PYRAMIDALBASIS_H
+#define PYRAMIDALBASIS_H
+
+#include "fullMatrix.h"
+
+#include "nodalBasis.h"
+#include "BergotBasis.h"
+
+class pyramidalBasis: public nodalBasis
+{
+ private:
+  // Inverse of the Vandermonde matrix
+  fullMatrix<double>* VDMinv;
+
+  // Orthogonal basis for the pyramid
+  BergotBasis bergot;
+  
+ public:
+  pyramidalBasis();
+
+  inline void f(double u, double v, double w, double *val) const;
+  inline void df(double u, double v, double w, double grads[][3]) const;
+
+  void initialize();
+
+};
+
+
+#endif
\ No newline at end of file
diff --git a/Post/PViewDataGModel.cpp b/Post/PViewDataGModel.cpp
index 3935fd52356d70585ca9a220704471966cf3b87d..b54f7b204b307d9bc41d02a50f77c0d270dfc1ee 100644
--- a/Post/PViewDataGModel.cpp
+++ b/Post/PViewDataGModel.cpp
@@ -143,7 +143,7 @@ bool PViewDataGModel::finalize(bool computeMinMax, const std::string &interpolat
           // the mesh is curved
           MElement *e = _getOneElementOfGivenType(model, it->first);
           if(e && e->getPolynomialOrder() > 1 && e->getFunctionSpace()){
-            const polynomialBasis *fs = e->getFunctionSpace();
+            const polynomialBasis *fs = (polynomialBasis*) e->getFunctionSpace();
             setInterpolationMatrices(it->first, *(it->second[0]), *(it->second[1]),
                                      fs->coefficients, fs->monomials);
           }
@@ -173,7 +173,7 @@ bool PViewDataGModel::finalize(bool computeMinMax, const std::string &interpolat
       if(!haveInterpolationMatrices(types[i])){
         MElement *e = _getOneElementOfGivenType(model, types[i]);
         if(e){
-          const polynomialBasis *fs = e->getFunctionSpace();
+          const polynomialBasis *fs = (polynomialBasis*) e->getFunctionSpace();
           if(fs){
             if(e->getPolynomialOrder() > 1){
               if(_type == ElementData){
diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
index 20f7035bc0555ea2e53bdb976e5a9a07c286bb6c..e940e8b3951b390ea1331087a49b14e757a3cdad 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
@@ -70,7 +70,7 @@ Mesh::Mesh(GEntity *ge, const std::set<MElement*> &els, std::set<MVertex*> &toFi
   for(std::set<MElement*>::const_iterator it = els.begin(); it != els.end(); ++it, ++iEl) {
     MElement *el = *it;
     _el[iEl] = el;
-    const polynomialBasis *lagrange = el->getFunctionSpace();
+    const polynomialBasis *lagrange = (polynomialBasis*) el->getFunctionSpace();
     const bezierBasis *bezier = JacobianBasis::find(lagrange->type)->bezier;
     if (_lag2Bez.find(lagrange->type) == _lag2Bez.end()) {
       _gradShapeFunctions[lagrange->type] = computeGSF(lagrange, bezier);
@@ -236,8 +236,8 @@ void Mesh::distSqToStraight(std::vector<double> &dSq)
   std::vector<SPoint3> sxyz(nVert());
   for (int iEl = 0; iEl < nEl(); iEl++) {
     MElement *el = _el[iEl];
-    const polynomialBasis *lagrange = el->getFunctionSpace();
-    const polynomialBasis *lagrange1 = el->getFunctionSpace(1);
+    const polynomialBasis *lagrange = (polynomialBasis*)el->getFunctionSpace();
+    const polynomialBasis *lagrange1 = (polynomialBasis*)el->getFunctionSpace(1);
     int nV = lagrange->points.size1();
     int nV1 = lagrange1->points.size1();
     for (int i = 0; i < nV1; ++i) {
diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
index 4eb27f3f4dcdbef2449f3f608f232d7f3c5fb23c..610a41b858b5f6ffb0095e267cd824bde472627a 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
@@ -51,9 +51,8 @@ void OptHomMessage (const char *s, ...) {
 
 double distMaxStraight (MElement *el)
 {
-
-  const polynomialBasis *lagrange = el->getFunctionSpace();
-  const polynomialBasis *lagrange1 = el->getFunctionSpace(1);
+  const polynomialBasis *lagrange = (polynomialBasis*)el->getFunctionSpace();
+  const polynomialBasis *lagrange1 = (polynomialBasis*)el->getFunctionSpace(1);
   int nV = lagrange->points.size1();
   int nV1 = lagrange1->points.size1();
   SPoint3 sxyz[256];