diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index b07ae2fdc2f4a4dae308232a098a3b8e7dd84fa8..ab0e1cb43af5f31ccd0b84cd4d5c838dfdff5d81 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -113,21 +113,20 @@ void MElement::scaledJacRange(double &jmin, double &jmax)
   jmin = jmax = 1.0;
 #if defined(HAVE_MESH)
   if (getPolynomialOrder() == 1) return;
-  const JacobianBasis *jac = getJacobianFuncSpace();                       // Calc signed Jacobian
-  const bezierBasis *bez = jac->bezier;
-  const int numJacNodes = bez->points.size1();
-  fullVector<double> Ji(numJacNodes);
-  jac->getSignedJacobian(this,Ji);
-  const JacobianBasis *jac1 = getJacobianFuncSpace(1);                     // Calc signed primary Jacobian
-  const int numJac1Nodes = jac1->bezier->points.size1();
-  fullVector<double> J1i(numJac1Nodes), J1Ji(numJacNodes);
-  jac1->getSignedJacobian(this,J1i);
-  for (int i=0; i<numJac1Nodes; i++) if (J1i(i) == 0) std::cout << "DBGTT: el " << getNum() << ", Ji1(" << i << ") == 0!\n";
-  jac->primJac2Jac.mult(J1i,J1Ji);
-  fullVector<double> SJi(numJacNodes);                                     // Calc scaled Jacobian
+  const JacobianBasis *jac = getJacobianFuncSpace(),*jac1 = getJacobianFuncSpace(1);    // Jac. and prim. Jac. basis
+  const int numJacNodes = jac->getNumJacNodes(), numJac1Nodes = jac1->getNumJacNodes();
+  const int numMapNodes = jac->getNumMapNodes(), numMap1Nodes = jac1->getNumMapNodes();
+  const int dim = getDim();
+  fullMatrix<double> nodesXYZ(numMapNodes,dim), nodesXYZ1(numMap1Nodes,dim);
+  getNodesCoord(nodesXYZ);
+  nodesXYZ1.copy(nodesXYZ,0,numMap1Nodes,0,dim,0,0);
+  fullVector<double> Ji(numJacNodes), J1i(numJac1Nodes), J1Ji(numJacNodes);
+  jac->getSignedJacobian(nodesXYZ,Ji);
+  jac1->getSignedJacobian(nodesXYZ1,J1i);
+  jac->primJac2Jac(J1i,J1Ji);
+  fullVector<double> SJi(numJacNodes), Bi(numJacNodes);                                 // Calc scaled Jacobian -> Bezier
   for (int i=0; i<numJacNodes; i++) SJi(i) = Ji(i)/J1Ji(i);
-  fullVector<double> Bi(numJacNodes);                                      // Transform to Bezier basis
-  bez->matrixLag2Bez.mult(SJi,Bi);
+  jac->lag2Bez(SJi,Bi);
   jmin = *std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size());
   jmax = *std::max_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size());
 #endif
@@ -412,6 +411,34 @@ double MElement::getPrimaryJacobian(double u, double v, double w, double jac[3][
   return _computeDeterminantAndRegularize(this, jac);
 }
 
+void MElement::getSignedJacobian(fullVector<double> &jacobian, int o)
+{
+  const int dim = getDim(), numNodes = getNumVertices();
+  fullMatrix<double> nodesXYZ(numNodes,dim);
+  getNodesCoord(nodesXYZ);
+  getJacobianFuncSpace(o)->getSignedJacobian(nodesXYZ,jacobian);
+}
+
+void MElement::getNodesCoord(fullMatrix<double> &nodesXYZ)
+{
+  const int dim = getDim(), numNodes = getNumShapeFunctions();
+  if (dim <= 1)
+    for (int i = 0; i < numNodes; i++) nodesXYZ(i,0) = getShapeFunctionNode(i)->x();
+  else if (dim == 2)
+    for (int i = 0; i < numNodes; i++) {
+      MVertex *v = getShapeFunctionNode(i);
+      nodesXYZ(i,0) = v->x();
+      nodesXYZ(i,1) = v->y();
+    }
+  else if (dim == 3)
+    for (int i = 0; i < numNodes; i++) {
+      MVertex *v = getShapeFunctionNode(i);
+      nodesXYZ(i,0) = v->x();
+      nodesXYZ(i,1) = v->y();
+      nodesXYZ(i,2) = v->z();
+    }
+}
+
 void MElement::pnt(double u, double v, double w, SPoint3 &p)
 {
   double x = 0., y = 0., z = 0.;
diff --git a/Geo/MElement.h b/Geo/MElement.h
index c6f3a61af706a66e862f80d6dfb5f43d0ba5673b..1b56081c8cc0272dc219b1f8fd6b3285bdf82ba4 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -264,6 +264,8 @@ class MElement
   {
     double jac[3][3]; return getJacobian(u, v, w, jac);
   }
+  void getSignedJacobian(fullVector<double> &jacobian, int o = -1);
+  void getNodesCoord(fullMatrix<double> &nodesXYZ);
   virtual int getNumShapeFunctions(){ return getNumVertices(); }
   virtual int getNumPrimaryShapeFunctions(){ return getNumPrimaryVertices(); }
   virtual MVertex *getShapeFunctionNode(int i){ return getVertex(i); }
diff --git a/Geo/MTetrahedron.cpp b/Geo/MTetrahedron.cpp
index 6265eb91fe33eab526a17eaaf100ec0350d1803b..23cf8e8e6c3cfcbe52995260c202bc2e609ff9cd 100644
--- a/Geo/MTetrahedron.cpp
+++ b/Geo/MTetrahedron.cpp
@@ -8,6 +8,7 @@
 #include "Numeric.h"
 #include "Context.h"
 #include "BasisFactory.h"
+#include "JacobianBasis.h"
 
 #if defined(HAVE_MESH)
 #include "qualityMeasures.h"
@@ -51,13 +52,13 @@ void MTetrahedron10::scaledJacRange(double &jmin, double &jmax){
   const int nbBezT = 20;
   static int done = 0;
   static fullMatrix<double> gsf[nbBezT];
-  const bezierBasis *jac_basis = getJacobianFuncSpace()->bezier;
+  const JacobianBasis *jac_basis = getJacobianFuncSpace();
   if (!done){
     double gs[nbNodT][3];
-    for (int i=0;i<jac_basis->points.size1();i++){
-      const double u = jac_basis->points(i,0);
-      const double v = jac_basis->points(i,1);
-      const double w = jac_basis->points(i,2);
+    for (int i=0;i<jac_basis->getNumJacNodes();i++){
+      const double u = jac_basis->getPoints()(i,0);
+      const double v = jac_basis->getPoints()(i,1);
+      const double w = jac_basis->getPoints()(i,2);
       getGradShapeFunctions(u,v,w,gs);
       fullMatrix<double> a (nbNodT,3);
       for (int j=0;j < nbNodT;j++){
@@ -104,7 +105,7 @@ void MTetrahedron10::scaledJacRange(double &jmin, double &jmax){
     Ji(i) = dJ * ss;
   }
   static fullVector<double> Bi( nbBezT );
-  jac_basis->matrixLag2Bez.mult(Ji,Bi);
+  jac_basis->lag2Bez(Ji,Bi);
   //  printf("%22.15E\n",*std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size()));
   jmin= *std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size());
   jmax= *std::max_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size());
diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp
index 37b5f13bf460590ebaa3174e5a8a09a35b1ff3f6..46a8a908c283299c3f9e209a537a0e36da716138 100644
--- a/Mesh/qualityMeasures.cpp
+++ b/Mesh/qualityMeasures.cpp
@@ -337,11 +337,11 @@ double mesh_functional_distorsion_p2_exact(MTriangle *t)
 
 double mesh_functional_distorsion_pN(MElement *t)
 {
-  const bezierBasis *jac = t->getJacobianFuncSpace()->bezier;
-  fullVector<double>Ji(jac->points.size1());
-  for (int i=0;i<jac->points.size1();i++){
-    double u = jac->points(i,0);
-    double v = jac->points(i,1);
+  const JacobianBasis *jac = t->getJacobianFuncSpace();
+  fullVector<double>Ji(jac->getNumJacNodes());
+  for (int i=0;i<jac->getNumJacNodes();i++){
+    double u = jac->getPoints()(i,0);
+    double v = jac->getPoints()(i,1);
     if (t->getType() == TYPE_QUA){
       u = -1 + 2*u;
       v = -1 + 2*v;
@@ -350,8 +350,8 @@ double mesh_functional_distorsion_pN(MElement *t)
     Ji(i) = mesh_functional_distorsion_2D(t,u,v);
   }
 
-  fullVector<double> Bi( jac->matrixLag2Bez.size1() );
-  jac->matrixLag2Bez.mult(Ji,Bi);
+  fullVector<double> Bi( jac->getNumJacNodes() );
+  jac->lag2Bez(Ji,Bi);
   return *std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size());
 }
 
@@ -421,17 +421,17 @@ double mesh_functional_distorsion_3D(MElement *t, double u, double v, double w)
 
 double qmDistorsionOfMapping(MTetrahedron *t)
 {
-  const bezierBasis *jac = t->getJacobianFuncSpace()->bezier;
-  fullVector<double>Ji(jac->points.size1());
-  for (int i=0;i<jac->points.size1();i++){
-    const double u = jac->points(i,0);
-    const double v = jac->points(i,1);
-    const double w = jac->points(i,2);
+  const JacobianBasis *jac = t->getJacobianFuncSpace();
+  fullVector<double>Ji(jac->getNumJacNodes());
+  for (int i=0;i<jac->getNumJacNodes();i++){
+    const double u = jac->getPoints()(i,0);
+    const double v = jac->getPoints()(i,1);
+    const double w = jac->getPoints()(i,2);
     Ji(i) = mesh_functional_distorsion_3D(t,u,v,w);
   }
 
-  fullVector<double> Bi( jac->matrixLag2Bez.size1() );
-  jac->matrixLag2Bez.mult(Ji,Bi);
+  fullVector<double> Bi( jac->getNumJacNodes() );
+  jac->lag2Bez(Ji,Bi);
   /*
      jac->matrixLag2Bez.print("Lag2Bez");
 
diff --git a/Numeric/JacobianBasis.cpp b/Numeric/JacobianBasis.cpp
index 2a37328a38e4fa3e95fe220c64cb47fe0363db6e..a28fbe0554aa1dbb606efaa528461b2090caf931 100644
--- a/Numeric/JacobianBasis.cpp
+++ b/Numeric/JacobianBasis.cpp
@@ -935,27 +935,6 @@ static fullMatrix<double> generateSubDivisor
 
 
 
-static void generateGradShapes(JacobianBasis &jfs, const fullMatrix<double> &points, const nodalBasis *F)
-{
-
-  fullMatrix<double> allDPsi;
-  F->df(points, allDPsi);
-
-  const int NBez = points.size1(), NLag = allDPsi.size1();
-  jfs.gradShapeMatX.resize(NBez,NLag);
-  jfs.gradShapeMatY.resize(NBez,NLag);
-  jfs.gradShapeMatZ.resize(NBez,NLag);
-  for (int i=0; i<NBez; i++)
-    for (int j=0; j<NLag; j++) {
-      jfs.gradShapeMatX(i,j) = allDPsi(j,3*i);
-      jfs.gradShapeMatY(i,j) = allDPsi(j,3*i+1);
-      jfs.gradShapeMatZ(i,j) = allDPsi(j,3*i+2);
-    }
-
-}
-
-
-
 std::map<int, bezierBasis> bezierBasis::_bbs;
 const bezierBasis *bezierBasis::find(int tag)
 {
@@ -967,6 +946,7 @@ const bezierBasis *bezierBasis::find(int tag)
   B.order = MElement::OrderFromTag(tag);
 
   if (MElement::ParentTypeFromTag(tag) == TYPE_PYR) {
+    B.dim = 3;
     B.numLagPts = 5;
     B.points = gmshGeneratePointsPyramid(B.order,false);
     B.matrixLag2Bez.resize(B.points.size1(),B.points.size1(),0.);
@@ -982,12 +962,14 @@ const bezierBasis *bezierBasis::find(int tag)
     std::vector< fullMatrix<double> > subPoints;
     switch (MElement::ParentTypeFromTag(tag)) {
       case TYPE_PNT :
+        B.dim = 0;
         B.numLagPts = 1;
         B.exponents = generate1DExponents(0);
         B.points    = generate1DPoints(0);
         dimSimplex = 0;
         break;
       case TYPE_LIN : {
+        B.dim = 1;
         B.numLagPts = 2;
         B.exponents = generate1DExponents(B.order);
         B.points    = generate1DPoints(B.order);
@@ -996,6 +978,7 @@ const bezierBasis *bezierBasis::find(int tag)
         break;
       }
       case TYPE_TRI : {
+        B.dim = 2;
         B.numLagPts = 3;
         B.exponents = generateExponentsTriangle(B.order);
         B.points    = gmshGeneratePointsTriangle(B.order,false);
@@ -1004,6 +987,7 @@ const bezierBasis *bezierBasis::find(int tag)
         break;
       }
       case TYPE_QUA : {
+        B.dim = 2;
         B.numLagPts = 4;
         B.exponents = generateExponentsQuad(B.order);
         B.points    = generatePointsQuad(B.order,false);
@@ -1013,6 +997,7 @@ const bezierBasis *bezierBasis::find(int tag)
         break;
       }
       case TYPE_TET : {
+        B.dim = 3;
         B.numLagPts = 4;
         B.exponents = generateExponentsTetrahedron(B.order);
         B.points    = gmshGeneratePointsTetrahedron(B.order,false);
@@ -1021,6 +1006,7 @@ const bezierBasis *bezierBasis::find(int tag)
         break;
       }
       case TYPE_PRI : {
+        B.dim = 3;
         B.numLagPts = 6;
         B.exponents = generateExponentsPrism(B.order);
         B.points    = generatePointsPrism(B.order, false);
@@ -1029,6 +1015,7 @@ const bezierBasis *bezierBasis::find(int tag)
         break;
       }
       case TYPE_HEX : {
+        B.dim = 3;
         B.numLagPts = 8;
         B.exponents = generateExponentsHex(B.order);
         B.points    = generatePointsHex(B.order, false);
@@ -1038,6 +1025,7 @@ const bezierBasis *bezierBasis::find(int tag)
       }
       default : {
         Msg::Error("Unknown function space %d: reverting to TET_1", tag);
+        B.dim = 3;
         B.numLagPts = 4;
         B.exponents = generateExponentsTetrahedron(0);
         B.points    = gmshGeneratePointsTetrahedron(0, false);
@@ -1057,30 +1045,18 @@ const bezierBasis *bezierBasis::find(int tag)
 
 
 
-static void generatePrimJac2Jac(JacobianBasis &jfs, const nodalBasis *primJacBasis)
+JacobianBasis::JacobianBasis(int tag)
 {
-  const int numJacNodes = jfs.bezier->points.size1(), numPrimJacSF = primJacBasis->getNumShapeFunctions();
-  jfs.primJac2Jac.resize(numJacNodes,numPrimJacSF);
-  primJacBasis->f(jfs.bezier->points,jfs.primJac2Jac);
-}
-
 
-
-std::map<int, JacobianBasis> JacobianBasis::_fs;
-const JacobianBasis *JacobianBasis::find(int tag)
-{
-  std::map<int, JacobianBasis>::const_iterator it = _fs.find(tag);
-  if (it != _fs.end()) return &it->second;
-  JacobianBasis &J = _fs[tag];
   int jacType, primJacType;
+
   if (MElement::ParentTypeFromTag(tag) == TYPE_PYR) {
     switch (tag) {
     case MSH_PYR_5 : jacType = MSH_PYR_14; primJacType = MSH_PYR_14; break;   // TODO: Order 1, Jac. "order" 2, check this
     case MSH_PYR_14 : jacType = MSH_PYR_91; primJacType = MSH_PYR_14; break;  // TODO: Order 2, Jac. "order" 5, check this
     case MSH_PYR_30 : jacType = MSH_PYR_285; primJacType = MSH_PYR_14; break; // TODO: Order 3, Jac. "order" 8, check this
     default :
-      Msg::Error("Unknown Jacobian function space for element type %d: reverting to PYR_5", tag);
-      J.bezier = bezierBasis::find(MSH_PYR_14);
+      Msg::Error("Unknown Jacobian function space for element type %d", tag);
       break;
     }
   }
@@ -1103,54 +1079,74 @@ const JacobianBasis *JacobianBasis::find(int tag)
     jacType = polynomialBasis::getTag(parentType, jacobianOrder, false);
     primJacType = polynomialBasis::getTag(parentType, primJacobianOrder, false);
   }
-  J.bezier = bezierBasis::find(jacType);
+
+  // Store Bezier basis
+  bezier = bezierBasis::find(jacType);
+
+  // Store shape function gradients of mapping at Jacobian nodes
   const nodalBasis *mapBasis = BasisFactory::create(tag);
-  generateGradShapes(J, J.bezier->points, mapBasis);
+  fullMatrix<double> allDPsi;
+  mapBasis->df(getPoints(), allDPsi);
+  const int numJacNodes = getPoints().size1(), numMapNodes = allDPsi.size1();
+  gradShapeMatX.resize(numJacNodes,numMapNodes);
+  gradShapeMatY.resize(numJacNodes,numMapNodes);
+  gradShapeMatZ.resize(numJacNodes,numMapNodes);
+  for (int i=0; i<numJacNodes; i++)
+    for (int j=0; j<numMapNodes; j++) {
+      gradShapeMatX(i,j) = allDPsi(j,3*i);
+      gradShapeMatY(i,j) = allDPsi(j,3*i+1);
+      gradShapeMatZ(i,j) = allDPsi(j,3*i+2);
+    }
+
+  // Compute matrix for lifting from primary Jacobian basis to Jacobian basis
   const nodalBasis *primJacBasis = BasisFactory::create(primJacType);
-  generatePrimJac2Jac(J, primJacBasis);
-  return &J;
+  const int numPrimJacSF = primJacBasis->getNumShapeFunctions();
+  matrixPrimJac2Jac.resize(numJacNodes,numPrimJacSF);
+  primJacBasis->f(getPoints(),matrixPrimJac2Jac);
+
 }
 
 
 
-void JacobianBasis::getSignedJacobian(MElement *el, fullVector<double> &jacobian) const
+std::map<int, JacobianBasis*> JacobianBasis::_fs;
+const JacobianBasis *JacobianBasis::find(int tag)
 {
 
-  const int numVertices = gradShapeMatX.size2(), numJacNodes = gradShapeMatX.size1();
+  std::map<int, JacobianBasis*>::const_iterator it = _fs.find(tag);
+  if (it != _fs.end()) return it->second;
+
+  JacobianBasis *B = new JacobianBasis(tag);
+  _fs.insert(std::make_pair(tag, B));
+  return B;
+
+}
+
+
 
-  switch (el->getDim()) {
+void JacobianBasis::getSignedJacobian(const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const
+{
+
+  switch (bezier->dim) {
 
     case 1 : {
+      const int numVertices = gradShapeMatX.size2();
       fullVector<double> nodesX(numVertices);
-      for (int i = 0; i < numVertices; i++) {
-        nodesX(i) = el->getShapeFunctionNode(i)->x();
-      }
+      nodesXYZ.copyOneColumn(nodesX,0);
       gradShapeMatX.mult(nodesX, jacobian);
       break;
     }
 
     case 2 : {
-      fullMatrix<double> nodesXY(numVertices,2);
-      for (int i = 0; i < numVertices; i++) {
-        MVertex *v = el->getShapeFunctionNode(i);
-        nodesXY(i,0) = v->x();
-        nodesXY(i,1) = v->y();
-      }
+      const int numJacNodes = gradShapeMatX.size1();
       fullMatrix<double> dxydX(numJacNodes,2), dxydY(numJacNodes,2);
-      gradShapeMatX.mult(nodesXY, dxydX);
-      gradShapeMatY.mult(nodesXY, dxydY);
+      gradShapeMatX.mult(nodesXYZ, dxydX);
+      gradShapeMatY.mult(nodesXYZ, dxydY);
       for (int i = 0; i < numJacNodes; i++) jacobian(i) = dxydX(i,0)*dxydY(i,1)-dxydX(i,1)*dxydY(i,0);
       break;
     }
 
     case 3 : {
-      fullMatrix<double> nodesXYZ(numVertices,3);
-      for (int i = 0; i < numVertices; i++) {
-        MVertex *v = el->getShapeFunctionNode(i);
-        nodesXYZ(i,0) = v->x();
-        nodesXYZ(i,1) = v->y();
-        nodesXYZ(i,2) = v->z();
-      }
+      const int numJacNodes = gradShapeMatX.size1();
       fullMatrix<double> dxyzdX(numJacNodes,3), dxyzdY(numJacNodes,3), dxyzdZ(numJacNodes,3);
       gradShapeMatX.mult(nodesXYZ, dxyzdX);
       gradShapeMatY.mult(nodesXYZ, dxyzdY);
@@ -1168,3 +1164,51 @@ void JacobianBasis::getSignedJacobian(MElement *el, fullVector<double> &jacobian
   }
 
 }
+
+
+
+void JacobianBasis::getSignedJacobian(const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
+                                      const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const
+{
+
+  switch (bezier->dim) {
+
+    case 1 : {
+      gradShapeMatX.mult(nodesX, jacobian);
+      break;
+    }
+
+    case 2 : {
+      const int numJacNodes = gradShapeMatX.size1(), numEl = nodesX.size2();
+      fullMatrix<double> dxdX(numJacNodes,numEl), dydX(numJacNodes,numEl);
+      fullMatrix<double> dxdY(numJacNodes,numEl), dydY(numJacNodes,numEl);
+      gradShapeMatX.mult(nodesX, dxdX); gradShapeMatX.mult(nodesY, dydX);
+      gradShapeMatY.mult(nodesX, dxdY); gradShapeMatY.mult(nodesY, dydY);
+      for (int iEl = 0; iEl < numEl; iEl++)
+        for (int i = 0; i < numJacNodes; i++)
+          jacobian(i,iEl) = dxdX(i,iEl)*dydY(i,iEl)-dydX(i,iEl)*dxdY(i,iEl);
+      break;
+    }
+
+    case 3 : {
+      const int numJacNodes = gradShapeMatX.size1(), numEl = nodesX.size2();
+      fullMatrix<double> dxdX(numJacNodes,numEl), dydX(numJacNodes,numEl), dzdX(numJacNodes,numEl);
+      fullMatrix<double> dxdY(numJacNodes,numEl), dydY(numJacNodes,numEl), dzdY(numJacNodes,numEl);
+      fullMatrix<double> dxdZ(numJacNodes,numEl), dydZ(numJacNodes,numEl), dzdZ(numJacNodes,numEl);
+      gradShapeMatX.mult(nodesX, dxdX); gradShapeMatX.mult(nodesY, dydX); gradShapeMatX.mult(nodesZ, dzdX);
+      gradShapeMatY.mult(nodesX, dxdY); gradShapeMatY.mult(nodesY, dydY); gradShapeMatY.mult(nodesZ, dzdY);
+      gradShapeMatZ.mult(nodesX, dxdZ); gradShapeMatZ.mult(nodesY, dydZ); gradShapeMatZ.mult(nodesZ, dzdZ);
+      for (int iEl = 0; iEl < numEl; iEl++)
+        for (int i = 0; i < numJacNodes; i++)
+          jacobian(i,iEl) = dxdX(i,iEl)*dydY(i,iEl)*dzdZ(i,iEl)
+                          + dxdY(i,iEl)*dydZ(i,iEl)*dzdX(i,iEl)
+                          + dydX(i,iEl)*dzdY(i,iEl)*dxdZ(i,iEl)
+                          - dxdZ(i,iEl)*dydY(i,iEl)*dzdX(i,iEl)
+                          - dxdY(i,iEl)*dydX(i,iEl)*dzdZ(i,iEl)
+                          - dydZ(i,iEl)*dzdY(i,iEl)*dxdX(i,iEl);
+      break;
+    }
+
+  }
+
+}
diff --git a/Numeric/JacobianBasis.h b/Numeric/JacobianBasis.h
index c7cf23c4785deb236ece3673edfdffac2937f93a..d5761cdde3410246a396dcabc37d24a5c8fc1894 100644
--- a/Numeric/JacobianBasis.h
+++ b/Numeric/JacobianBasis.h
@@ -16,7 +16,7 @@ class bezierBasis {
  private :
   static std::map<int, bezierBasis> _bbs;
  public :
-  int order;
+  int dim, order;
   int numLagPts;
   int numDivisions;
   // the 'numLagPts' first exponents are related to 'Lagrangian' values
@@ -29,13 +29,34 @@ class bezierBasis {
 
 class JacobianBasis {
  private:
-  static std::map<int, JacobianBasis> _fs;
- public :
+  static std::map<int, JacobianBasis*> _fs;
   const bezierBasis *bezier;
   fullMatrix<double> gradShapeMatX, gradShapeMatY, gradShapeMatZ;
-  fullMatrix<double> primJac2Jac;                                   // Lifts Lagrange basis of primary Jac. to Lagrange basis of Jac.
+  fullMatrix<double> matrixPrimJac2Jac;                                   // Lifts Lagrange basis of primary Jac. to Lagrange basis of Jac.
+ public :
   static const JacobianBasis *find(int);
-  void getSignedJacobian(MElement *el, fullVector<double> &jacobian) const;
+  JacobianBasis(int tag);
+  inline int getNumJacNodes() const { return gradShapeMatX.size1(); }
+  inline int getNumMapNodes() const { return gradShapeMatX.size2(); }
+  inline const fullMatrix<double> &getPoints() const { return bezier->points; }
+  inline int getNumDivisions() const { return bezier->numDivisions; }
+  inline int getNumSubNodes() const { return bezier->subDivisor.size1(); }
+  inline int getNumLagPts() const { return bezier->numLagPts; }
+  void getSignedJacobian(const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const;
+  void getSignedJacobian(const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
+                         const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const;
+  inline void lag2Bez(const fullVector<double> &jac, fullVector<double> &bez) const {
+    bezier->matrixLag2Bez.mult(jac,bez);
+  }
+  inline void lag2Bez(const fullMatrix<double> &jac, fullMatrix<double> &bez) const {
+    bezier->matrixLag2Bez.mult(jac,bez);
+  }
+  inline void primJac2Jac(const fullVector<double> &primJac, fullVector<double> &jac) const {
+    matrixPrimJac2Jac.mult(primJac,jac);
+  }
+  inline void subDivisor(const fullVector<double> &bez, fullVector<double> &result) const {
+    bezier->subDivisor.mult(bez,result);
+  }
 };
 
 #endif
diff --git a/Plugin/AnalyseCurvedMesh.cpp b/Plugin/AnalyseCurvedMesh.cpp
index 87036b090cb269966054012fee95fef3cdb3ded4..efbc446b1a5ed5457f7fe53191cd70eae42d60fd 100644
--- a/Plugin/AnalyseCurvedMesh.cpp
+++ b/Plugin/AnalyseCurvedMesh.cpp
@@ -228,23 +228,39 @@ void GMSH_AnalyseCurvedMeshPlugin::checkValidity(MElement *const*el,
     Msg::Error("Jacobian function space not implemented for type of element %d", el[0]->getNum());
     return;
   }
-  const bezierBasis *bb = jfs->bezier;
-
-  int numSamplingPt = bb->points.size1();
+  const int numSamplingPt = jfs->getNumJacNodes(), numSamplingPt1 = jfs1->getNumJacNodes();
+  const int numMapNodes = jfs->getNumMapNodes(), numMapNodes1 = jfs1->getNumMapNodes();
+  const int dim = el[0]->getDim();
 
 #ifdef _ANALYSECURVEDMESH_BLAS_
   fullMatrix<double> jacobianB(numSamplingPt, numEl);
   fullMatrix<double> jacBezB(numSamplingPt, numEl);
-  fullVector<double> jac1B(jfs1->bezier->points.size1(), numEl);
+  fullMatrix<double> jac1B(numSamplingPt1, numEl);
   fullVector<double> jacBez, jacobian, jac1;
 
-  jfs->getSignedJacobian(el, jacobianB);
-  jfs1->getSignedJacobian(el, jac1B);
-  bb->matrixLag2Bez.mult(jacobianB, jacBezB);
+  fullMatrix<double> nodesX(numMapNodes, numEl), nodesY(numMapNodes, numEl), nodesZ(numMapNodes, numEl);
+  fullMatrix<double> nodesX1(numMapNodes, numEl), nodesY1(numMapNodes, numEl), nodesZ1(numMapNodes, numEl);
+  for (int k = 0; k < numEl; ++k)
+    for (int i = 0; i < numMapNodes; ++i)
+    {
+      MVertex *v = (el[k])->getShapeFunctionNode(i);
+      nodesX(i,k) = v->x();
+      nodesY(i,k) = v->y();
+      nodesZ(i,k) = v->z();
+      if (i < numMapNodes1) {
+        nodesX1(i,k) = nodesX(i,k);
+        nodesY1(i,k) = nodesY(i,k);
+        nodesZ1(i,k) = nodesZ(i,k);
+      }
+    }
+
+  jfs->getSignedJacobian(nodesX, nodesY, nodesZ, jacobianB);
+  jfs1->getSignedJacobian(nodesX1, nodesY1, nodesZ1, jac1B);
+  jfs->lag2Bez(jacobianB, jacBezB);
 #else
   fullVector<double> jacobian(numSamplingPt);
   fullVector<double> jacBez(numSamplingPt);
-  fullVector<double> jac1(jfs1->bezier->points.size1());
+  fullVector<double> jac1(numSamplingPt1);
 #endif
 
   for (int k = 0; k < numEl; ++k) {
@@ -254,8 +270,11 @@ void GMSH_AnalyseCurvedMeshPlugin::checkValidity(MElement *const*el,
     jacobian.setAsProxy(jacobianB, k);
     jac1.setAsProxy(jac1B, k);
 #else
-    jfs->getSignedJacobian(el[k], jacobian);
-    jfs1->getSignedJacobian(el[k], jac1);
+    fullMatrix<double> nodesXYZ(numMapNodes,dim), nodesXYZ1(numMapNodes1,dim);
+    el[k]->getNodesCoord(nodesXYZ);
+    nodesXYZ1.copy(nodesXYZ,0,numMapNodes1,0,dim,0,0);
+    jfs->getSignedJacobian(nodesXYZ,jacobian);
+    jfs1->getSignedJacobian(nodesXYZ1,jac1);
 #endif
 
     // AmJ : avgJ is not the average Jac for quad, prism or hex
@@ -281,7 +300,7 @@ void GMSH_AnalyseCurvedMeshPlugin::checkValidity(MElement *const*el,
     }
 
 #ifndef _ANALYSECURVEDMESH_BLAS_
-    bb->matrixLag2Bez.mult(jacobian, jacBez);
+    jfs->lag2Bez(jacobian, jacBez);
 #endif
 
     for (i = 0; i < jacBez.size() && jacBez(i) > _bezBreak * avgJ; ++i);
@@ -296,7 +315,7 @@ void GMSH_AnalyseCurvedMeshPlugin::checkValidity(MElement *const*el,
       continue;
     }
     else {
-      int result = subDivision(bb, jacBez, _maxDepth-1);
+      int result = subDivision(jfs, jacBez, _maxDepth-1);
       if (result < 0) {
         invalids.push_back(el[k]);
         ++_numInvalid;
@@ -313,16 +332,16 @@ void GMSH_AnalyseCurvedMeshPlugin::checkValidity(MElement *const*el,
   }
 }
 
-int GMSH_AnalyseCurvedMeshPlugin::subDivision(const bezierBasis *bb,
+int GMSH_AnalyseCurvedMeshPlugin::subDivision(const JacobianBasis *jb,
                                               const fullVector<double> &jacobian,
                                               int depth)
 {
-  fullVector<double> newJacobian(bb->subDivisor.size1());
-  bb->subDivisor.mult(jacobian, newJacobian);
+  fullVector<double> newJacobian(jb->getNumSubNodes());
+  jb->subDivisor(jacobian, newJacobian);
 
-  for (int i = 0; i < bb->numDivisions; i++)
-  for (int j = 0; j < bb->numLagPts; j++)
-  if (newJacobian(i * bb->points.size1() + j) <= _jacBreak)
+  for (int i = 0; i < jb->getNumDivisions(); i++)
+  for (int j = 0; j < jb->getNumLagPts(); j++)
+  if (newJacobian(i * jb->getNumJacNodes() + j) <= _jacBreak)
     return -1;
 
   int i = 0;
@@ -338,9 +357,9 @@ int GMSH_AnalyseCurvedMeshPlugin::subDivision(const bezierBasis *bb,
     std::vector<int> negTag, posTag;
     bool zeroTag = false;
 
-    for (int i = 0; i < bb->numDivisions; i++) {
+    for (int i = 0; i < jb->getNumDivisions(); i++) {
       subJacobian.setAsProxy(newJacobian, i * jacobian.size(), jacobian.size());
-      int tag = subDivision(bb, subJacobian, depth-1);
+      int tag = subDivision(jb, subJacobian, depth-1);
 
       if (tag < 0)
         negTag.push_back(tag);
@@ -433,25 +452,42 @@ void GMSH_AnalyseCurvedMeshPlugin::computeMinMax(MElement *const*el, int numEl,
     Msg::Error("Jacobian function space not implemented for type of element %d", el[0]->getNum());
     return;
   }
-  const bezierBasis *bb = jfs->bezier;
 
-  int numSamplingPt = bb->points.size1();
+  const int numSamplingPt = jfs->getNumJacNodes(), numSamplingPt1 = jfs1->getNumJacNodes();
+  const int numMapNodes = jfs->getNumMapNodes(), numMapNodes1 = jfs1->getNumMapNodes();
+  const int dim = el[0]->getDim();
 
 #ifdef _ANALYSECURVEDMESH_BLAS_
   fullMatrix<double> jacobianB(numSamplingPt, numEl);
   fullMatrix<double> jacBezB(numSamplingPt, numEl);
-  fullVector<double> jac1B(jfs1->bezier->points.size1(), numEl);
+  fullMatrix<double> jac1B(numSamplingPt1, numEl);
   fullVector<double> jacBez, jacobian, jac1;
 
-  jfs->getSignedJacobian(el, jacobianB);
-  jfs1->getSignedJacobian(el, jac1B);
-  bb->matrixLag2Bez.mult(jacobianB, jacBezB);
+  fullMatrix<double> nodesX(numMapNodes, numEl), nodesY(numMapNodes, numEl), nodesZ(numMapNodes, numEl);
+  fullMatrix<double> nodesX1(numMapNodes1, numEl), nodesY1(numMapNodes1, numEl), nodesZ1(numMapNodes1, numEl);
+  for (int k = 0; k < numEl; ++k)
+    for (int i = 0; i < numMapNodes; ++i)
+    {
+      MVertex *v = (el[k])->getShapeFunctionNode(i);
+      nodesX(i,k) = v->x();
+      nodesY(i,k) = v->y();
+      nodesZ(i,k) = v->z();
+      if (i < numMapNodes1) {
+        nodesX1(i,k) = nodesX(i,k);
+        nodesY1(i,k) = nodesY(i,k);
+        nodesZ1(i,k) = nodesZ(i,k);
+      }
+    }
+
+  jfs->getSignedJacobian(nodesX, nodesY, nodesZ, jacobianB);
+  jfs1->getSignedJacobian(nodesX, nodesY, nodesZ, jac1B);
+  jfs->lag2Bez(jacobianB, jacBezB);
 #else
   fullVector<double> jacobian(numSamplingPt);
   fullVector<double> jacBez(numSamplingPt);
-  fullVector<double> jac1(jfs1->bezier->points.size1());
+  fullVector<double> jac1(numSamplingPt1);
 #endif
-  fullVector<double> subJacBez(bb->subDivisor.size1());
+  fullVector<double> subJacBez(jfs->getNumSubNodes());
 
   _min_Javg = 1.7e308;
   _max_Javg = -1.7e308;
@@ -468,9 +504,12 @@ void GMSH_AnalyseCurvedMeshPlugin::computeMinMax(MElement *const*el, int numEl,
     jacobian.setAsProxy(jacobianB, k);
     jac1.setAsProxy(jac1B, k);
 #else
-    jfs->getSignedJacobian(el[k], jacobian);
-    jfs1->getSignedJacobian(el[k], jac1);
-    bb->matrixLag2Bez.mult(jacobian, jacBez);
+    fullMatrix<double> nodesXYZ(numMapNodes,dim), nodesXYZ1(numMapNodes1,dim);
+    el[k]->getNodesCoord(nodesXYZ);
+    nodesXYZ1.copy(nodesXYZ,0,numMapNodes1,0,dim,0,0);
+    jfs->getSignedJacobian(nodesXYZ,jacobian);
+    jfs1->getSignedJacobian(nodesXYZ1,jac1);
+    jfs->lag2Bez(jacobian, jacBez);
 #endif
 
     // AmJ : avgJ is not the average Jac for quad, prism or hex
@@ -522,7 +561,7 @@ void GMSH_AnalyseCurvedMeshPlugin::computeMinMax(MElement *const*el, int numEl,
         pqMin.pop();
         delete bj;
 
-        for (int i = 0; i < bb->numDivisions; i++) {
+        for (int i = 0; i < jfs->getNumDivisions(); i++) {
           jacBez.setAsProxy(subJacBez, i * numSamplingPt, numSamplingPt);
           bj = new BezierJacobian(jacBez, jfs, currentDepth);
           pqMin.push(bj);
@@ -555,7 +594,7 @@ void GMSH_AnalyseCurvedMeshPlugin::computeMinMax(MElement *const*el, int numEl,
         pqMax.pop();
         delete bj;
 
-        for (int i = 0; i < bb->numDivisions; i++) {
+        for (int i = 0; i < jfs->getNumDivisions(); i++) {
           jacBez.setAsProxy(subJacBez, i * numSamplingPt, numSamplingPt);
           bj = new BezierJacobian(jacBez, jfs, currentDepth);
           pqMax.push(bj);
@@ -690,7 +729,7 @@ BezierJacobian::BezierJacobian(fullVector<double> &v, const JacobianBasis *jfs,
 
   _minJ = _maxJ = v(0);
   int i = 1;
-  for (; i < jfs->bezier->numLagPts; i++) {
+  for (; i < jfs->getNumLagPts(); i++) {
     if (_minJ > v(i)) _minJ = v(i);
     if (_maxJ < v(i)) _maxJ = v(i);
   }
diff --git a/Plugin/AnalyseCurvedMesh.h b/Plugin/AnalyseCurvedMesh.h
index fbbb2c76a9152c2dfd780f9f9617c3c450ce13c8..73b933f2344d22da7e896b2a94addb73172a93a3 100644
--- a/Plugin/AnalyseCurvedMesh.h
+++ b/Plugin/AnalyseCurvedMesh.h
@@ -49,7 +49,7 @@ class GMSH_AnalyseCurvedMeshPlugin : public GMSH_PostPlugin
     void checkValidity(int toDo);
     void computeMinMax(std::map<int, std::vector<double> > *data = 0);
     void computeMinMax(MElement *const *, int numEl, std::map<int, std::vector<double> > *data = 0);
-    int subDivision(const bezierBasis*, const fullVector<double>&, int depth);
+    int subDivision(const JacobianBasis *, const fullVector<double>&, int depth);
     void hideValid_ShowInvalid(std::vector<MElement*> &invalids);
 };
 
@@ -72,7 +72,7 @@ private:
 public:
   BezierJacobian(fullVector<double> &, const JacobianBasis *, int depth);
   void subDivisions(fullVector<double> &vect) const
-    {_jfs->bezier->subDivisor.mult(_jacBez, vect);}
+    {_jfs->subDivisor(_jacBez, vect);}
   
   inline int depth() const {return _depthSub;}
   inline double minJ() const {return _minJ;}
diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
index a74db6c0ea3594c8898f6f744d071c17404cfd8e..12c2c6dedfcacdf4ee4e2644021c47319bf8c1fb 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
@@ -9,14 +9,13 @@
 
 
 std::map<int, fullMatrix<double> > Mesh::_gradShapeFunctions;
-std::map<int, fullMatrix<double> > Mesh::_lag2Bez;
 
 
 
-fullMatrix<double> Mesh::computeGSF(const nodalBasis *lagrange, const bezierBasis *bezier)
+fullMatrix<double> Mesh::computeGSF(const nodalBasis *lagrange, const JacobianBasis *jac)
 {
   // bezier points are defined in the [0,1] x [0,1] quad
-  fullMatrix<double> bezierPoints = bezier->points;
+  fullMatrix<double> bezierPoints = jac->getPoints();
   if (lagrange->parentType == TYPE_QUA) {
     for (int i = 0; i < bezierPoints.size1(); ++i) {
       bezierPoints(i, 0) = -1 + 2 * bezierPoints(i, 0);
@@ -71,12 +70,10 @@ Mesh::Mesh(GEntity *ge, const std::set<MElement*> &els, std::set<MVertex*> &toFi
     MElement *el = *it;
     _el[iEl] = el;
     const nodalBasis *lagrange = el->getFunctionSpace();
-    const bezierBasis *bezier = JacobianBasis::find(lagrange->type)->bezier;
-    if (_lag2Bez.find(lagrange->type) == _lag2Bez.end()) {
-      _gradShapeFunctions[lagrange->type] = computeGSF(lagrange, bezier);
-      _lag2Bez[lagrange->type] = bezier->matrixLag2Bez;
-    }
-    _nBezEl[iEl] = bezier->points.size1();
+    const JacobianBasis *jac = JacobianBasis::find(lagrange->type);
+    if (_gradShapeFunctions.find(lagrange->type) == _gradShapeFunctions.end())
+      _gradShapeFunctions[lagrange->type] = computeGSF(lagrange, jac);
+    _nBezEl[iEl] = jac->getNumJacNodes();
     _nNodEl[iEl] = lagrange->points.size1();
     for (int iVEl = 0; iVEl < lagrange->points.size1(); iVEl++) {
       MVertex *vert = el->getVertex(iVEl);
@@ -375,8 +372,8 @@ void Mesh::scaledJacAndGradients(int iEl, std::vector<double> &sJ , std::vector<
   //  gradScaledJac(iEl,OLD);
   //  scaledJac(iEl,OLD);
 
+  const JacobianBasis *jacBasis = JacobianBasis::find(_el[iEl]->getTypeForMSH());
   fullMatrix<double> &gsf = _gradShapeFunctions[_el[iEl]->getTypeForMSH()];
-  const fullMatrix<double> &l2b = _lag2Bez[_el[iEl]->getTypeForMSH()];
   const int nbBez = _nBezEl[iEl];
   const int nbNod = _nNodEl[iEl];
   fullMatrix<double> JDJ (nbBez,3*nbNod+1);
@@ -428,7 +425,7 @@ void Mesh::scaledJacAndGradients(int iEl, std::vector<double> &sJ , std::vector<
   }
   
   //  (N_b x N_b) x (N_b x 3*N_n + 1) 
-  l2b.mult(JDJ,BDB);
+  jacBasis->lag2Bez(JDJ,BDB);
 
   // the scaled jacobian
   //  printf("ELEMENT %d\n",iEl);
diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.h b/contrib/HighOrderMeshOptimizer/OptHomMesh.h
index 87bdd18ffd7ce7cc4fb4e9d97ec6e9aab178eaf2..a7fa37a76848e2fb834036ea05b8d957423f3c67 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomMesh.h
+++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.h
@@ -80,12 +80,11 @@ private:
   bool projJac;                                 // Using "projected" Jacobians or not
 
   static std::map<int, fullMatrix<double> >  _gradShapeFunctions; // gradients of shape functions at Bezier points 
-  static std::map<int, fullMatrix<double> >  _lag2Bez; // gradients of shape functions at Bezier points 
 
   int addVert(MVertex* vert);
   int addFreeVert(MVertex* vert, const int iV, const int nPCV, std::set<MVertex*> &toFix);
   SVector3 getNormalEl(int iEl);
-  static fullMatrix<double> computeGSF(const nodalBasis *lagrange, const bezierBasis *bezier);
+  static fullMatrix<double> computeGSF(const nodalBasis *lagrange, const JacobianBasis *jac);
   static inline int indJB2DBase(int nNod, int l, int i, int j) { return (l*nNod+i)*nNod+j; }
   inline int indJB2D(int iEl, int l, int i, int j) { return indJB2DBase(_nNodEl[iEl],l,i,j); }
   static inline int indJB3DBase(int nNod, int l, int i, int j, int m) { return ((l*nNod+i)*nNod+j)*nNod+m; }