diff --git a/Geo/MQuadrangle.cpp b/Geo/MQuadrangle.cpp
index a948b4b9b169f1069caa2e8c02b4acf38f9a99eb..cac071cbb16b5119d8924d684601f0019fe34c3e 100644
--- a/Geo/MQuadrangle.cpp
+++ b/Geo/MQuadrangle.cpp
@@ -317,17 +317,6 @@ double MQuadrangle::gammaShapeMeasure(){
 }
 
 
-double MQuadrangle::distoShapeMeasure()
-{
-#if defined(HAVE_MESH)
-  //  return qmTriangleAngles(this);
-  return qmDistorsionOfMapping(this);
-#else
-  return 0.;
-#endif
-}
-
-
 double MQuadrangle::angleShapeMeasure()
 {
 #if defined(HAVE_MESH)
diff --git a/Geo/MQuadrangle.h b/Geo/MQuadrangle.h
index 5eb78ee5049b14cc7a8fade4d920bbcdddc37a98..1036738ad38fc01da64f9a33a058608d1dc3e6c9 100644
--- a/Geo/MQuadrangle.h
+++ b/Geo/MQuadrangle.h
@@ -148,7 +148,6 @@ class MQuadrangle : public MElement {
   }
   virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts);
   virtual double angleShapeMeasure();
-  virtual double distoShapeMeasure();
   // Computes the minimum inradius of the all the circles tangents to
   // 3 of the 4 edges of the quad. If the 4 points of the quad are not
   // planar, we compute the mean plane due to the least-square
diff --git a/Geo/MTetrahedron.cpp b/Geo/MTetrahedron.cpp
index 23cf8e8e6c3cfcbe52995260c202bc2e609ff9cd..614fd85bf17b161b2c3a93f17654291d713f7310 100644
--- a/Geo/MTetrahedron.cpp
+++ b/Geo/MTetrahedron.cpp
@@ -44,82 +44,6 @@ double MTetrahedron::getCircumRadius()
 #endif
 }
 
-void MTetrahedron10::scaledJacRange(double &jmin, double &jmax){
-
-  // the fastest available algo for computing scaled jacobians for
-  // quadratic tetrahedron
-  const int nbNodT = 10;
-  const int nbBezT = 20;
-  static int done = 0;
-  static fullMatrix<double> gsf[nbBezT];
-  const JacobianBasis *jac_basis = getJacobianFuncSpace();
-  if (!done){
-    double gs[nbNodT][3];
-    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++){
-	a(j,0) = gs[j][0];
-	a(j,1) = gs[j][1];
-	a(j,2) = gs[j][2];
-      }
-      gsf[i]= a;
-    }
-    done=1;
-  }
-
-  double x[nbNodT];for (int i=0;i<nbNodT;i++)x[i] = getVertex(i)->x();
-  double y[nbNodT];for (int i=0;i<nbNodT;i++)y[i] = getVertex(i)->y();
-  double z[nbNodT];for (int i=0;i<nbNodT;i++)z[i] = getVertex(i)->z();
-
-  SVector3 v1 (x[1] - x[0],y[1] - y[0],z[1] - z[0]);
-  SVector3 v2 (x[2] - x[0],y[2] - y[0],z[2] - z[0]);
-  SVector3 v3 (x[3] - x[0],y[3] - y[0],z[3] - z[0]);
-
-  // take absolute value for quite complex reasons
-  // straight sided element may be WRONG while curved
-  // one is OK
-  const double ss = fabs(1./dot(crossprod(v1,v2),v3));
-
-  double jac[3][3];
-  static fullVector<double>Ji(nbBezT);
-  for (int i=0;i < nbBezT;i++){
-    jac[0][0] = jac[0][1] = jac[0][2] = 0.;
-    jac[1][0] = jac[1][1] = jac[1][2] = 0.;
-    jac[2][0] = jac[2][1] = jac[2][2] = 0.;
-    fullMatrix<double> &g = gsf[i];
-    for (int j = 0; j < nbNodT; j++) {
-      for (int k = 0; k < 3; k++) {
-	const double gg = g(j, k);
-	jac[k][0] += x[j] * gg;
-	jac[k][1] += y[j] * gg;
-	jac[k][2] += z[j] * gg;
-      }
-    }
-    const double dJ = jac[0][0] * jac[1][1] * jac[2][2] + jac[0][2] * jac[1][0] * jac[2][1] +
-      jac[0][1] * jac[1][2] * jac[2][0] - jac[0][2] * jac[1][1] * jac[2][0] -
-      jac[0][0] * jac[1][2] * jac[2][1] - jac[0][1] * jac[1][0] * jac[2][2];
-    Ji(i) = dJ * ss;
-  }
-  static fullVector<double> Bi( nbBezT );
-  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());
-}
-
-double MTetrahedron::distoShapeMeasure()
-{
-#if defined(HAVE_MESH)
-  return qmDistorsionOfMapping(this);
-#else
-  return 0.;
-#endif
-}
-
 double MTetrahedron::getInnerRadius()
 {
   // radius of inscribed sphere = 3 * Volume / sum(Area_i)
diff --git a/Geo/MTetrahedron.h b/Geo/MTetrahedron.h
index d0e5e9cae82f934bf64b3baa9be8ccbfd10d7066..5eb4f6b89e796b4f4239c7f5900fda6f82f64629 100644
--- a/Geo/MTetrahedron.h
+++ b/Geo/MTetrahedron.h
@@ -123,7 +123,6 @@ class MTetrahedron : public MElement {
   virtual double getVolume();
   virtual int getVolumeSign(){ return (getVolume() >= 0) ? 1 : -1; }
   virtual double gammaShapeMeasure();
-  virtual double distoShapeMeasure();
   virtual double getInnerRadius();
   virtual double getCircumRadius();
   virtual double etaShapeMeasure();
@@ -213,7 +212,6 @@ class MTetrahedron10 : public MTetrahedron {
     for(int i = 0; i < 6; i++) _vs[i]->setPolynomialOrder(2);
   }
   ~MTetrahedron10(){}
-  virtual void scaledJacRange(double &jmin, double &jmax);
   virtual int getPolynomialOrder() const { return 2; }
   virtual int getNumVertices() const { return 10; }
   virtual MVertex *getVertex(int num){ return num < 4 ? _v[num] : _vs[num - 4]; }
diff --git a/Geo/MTriangle.cpp b/Geo/MTriangle.cpp
index 518675aaf416896387c3ba13bebbb1807598c76e..6b7929109870528515c841b672b6757b0f72344e 100644
--- a/Geo/MTriangle.cpp
+++ b/Geo/MTriangle.cpp
@@ -36,15 +36,6 @@ double MTriangle::getVolume()
   return norm(crossprod(v1, v2)) / 2.;
 }
 
-double MTriangle::distoShapeMeasure()
-{
-#if defined(HAVE_MESH)
-  return qmDistorsionOfMapping(this);
-#else
-  return 0.;
-#endif
-}
-
 double MTriangle::getInnerRadius()
 {
   // radius of inscribed circle = 2 * Area / sum(Line_i)
diff --git a/Geo/MTriangle.h b/Geo/MTriangle.h
index 6a2168e4ef0b495f548ef0106e56f7f0fcd4a9ac..49cf7ecfeda33547d0fcc8a50742a98aa67ccf92 100644
--- a/Geo/MTriangle.h
+++ b/Geo/MTriangle.h
@@ -52,7 +52,6 @@ class MTriangle : public MElement {
   virtual int getDim() const { return 2; }
   virtual double etaShapeMeasure();
   virtual double gammaShapeMeasure();
-  virtual double distoShapeMeasure();
   virtual double getInnerRadius();
   virtual double getOuterRadius();
   virtual double angleShapeMeasure();
diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp
index 46a8a908c283299c3f9e209a537a0e36da716138..3a6e4a5f9a77f64f779728bb8c1c6089954d7312 100644
--- a/Mesh/qualityMeasures.cpp
+++ b/Mesh/qualityMeasures.cpp
@@ -208,242 +208,6 @@ double conditionNumberAndDerivativeOfTet(const double &x1, const double &y1, con
 }
 */
 
-double mesh_functional_distorsion_2D(MElement *t, double u, double v)
-{
-  // compute uncurved element jacobian d_u x and d_v x
-  double mat[3][3];
-  t->getPrimaryJacobian(u, v, 0, mat);
-  // t->getJacobian(u,v,0,mat);
-  double v1[3] = {mat[0][0], mat[0][1], mat[0][2]};
-  double v2[3] = {mat[1][0], mat[1][1], mat[1][2]};
-  double normal1[3];
-  prodve(v1, v2, normal1);
-  double nn = norm3(normal1);
-
-  // compute uncurved element jacobian d_u x and d_v x
-
-  t->getJacobian(u, v, 0, mat);
-  double v1b[3] = {mat[0][0], mat[0][1], mat[0][2]};
-  double v2b[3] = {mat[1][0], mat[1][1], mat[1][2]};
-  double normal[3];
-  prodve(v1b, v2b, normal);
-
-  //  printf("%g %g %g -- %g %g %g - %g\n",mat[0][0], mat[0][1], mat[0][2],mat[1][0], mat[1][1], mat[1][2],nn);
-
-  double sign = 1.0;
-  prosca(normal1, normal, &sign);
-  //  double det = (norm3(normal) / nn)  * (sign > 0 ? 1. : -1.);
-
-  //  printf("%g %g : %g : %g n1 (%g,%g,%g)\n",u,v,sign,det, normal1[0], normal1[1], normal1[2]);
-  //  for (int i=0;i<t->getNumVertices();i++){
-  //    printf("COORD (%d) = %g %g %g\n",i,t->getVertex(i)->x(),t->getVertex(i)->y(),t->getVertex(i)->z());
-  //  }
-  //  printf("n (%g,%g,%g)\n", normal1[0], normal1[1], normal1[2]);
-
-  return sign/(nn*nn);
-}
-
-static double MINQ (double a, double b, double c){
-  if (a == 0) return std::min(a+b+c,c);
-  double xmin = -b/(2*a);
-  if (xmin < 0 || xmin > 1)return std::min(c,a+b+c);
-  return std::min(c,std::min(a+b+c,a * xmin * xmin + b * xmin + c));
-}
-
-
-double mesh_functional_distorsion_p2_bezier_refined(MTriangle *t)
-{
-  double J1 =mesh_functional_distorsion_2D(t,0.0,0.0);
-  double J2 =mesh_functional_distorsion_2D(t,1.0,0.0);
-  double J3 =mesh_functional_distorsion_2D(t,0.0,1.0);
-  double J4 =mesh_functional_distorsion_2D(t,0.5,0.0);
-  double J5 =mesh_functional_distorsion_2D(t,0.5,0.5);
-  double J6 =mesh_functional_distorsion_2D(t,0.0,0.5);
-
-  double J36 =mesh_functional_distorsion_2D(t,0.0,.75);
-  double J35 =mesh_functional_distorsion_2D(t,0.25,.75);
-  double J56 =mesh_functional_distorsion_2D(t,0.25,.5);
-
-  double J16 =mesh_functional_distorsion_2D(t,0.0,.25);
-  double J14 =mesh_functional_distorsion_2D(t,0.25,.0);
-  double J46 =mesh_functional_distorsion_2D(t,0.25,.25);
-
-
-  double J45 =mesh_functional_distorsion_2D(t,0.5,.25);
-  double J52 =mesh_functional_distorsion_2D(t,0.75,.25);
-  double J24 =mesh_functional_distorsion_2D(t,0.75,.0);
-
-  double d[15] = {
-    J1,J6,J4,2*J16-0.5*(J1+J6),2*J14-0.5*(J1+J4),2*J46-0.5*(J6+J4),
-    J3,J5,2*J36-0.5*(J3+J6),2*J35-0.5*(J3+J5),2*J56-0.5*(J5+J6),
-    J2,2*J45-0.5*(J4+J5),2*J52-0.5*(J5+J2),2*J24-0.5*(J2+J4)};
-  return  *std::min_element(d,d+15);
-}
-
-double mesh_functional_distorsion_p2_exact(MTriangle *t)
-{
-  double J1 =mesh_functional_distorsion_2D(t,0.0,0.0);
-  double J2 =mesh_functional_distorsion_2D(t,1.0,0.0);
-  double J3 =mesh_functional_distorsion_2D(t,0.0,1.0);
-  double J4 =mesh_functional_distorsion_2D(t,0.5,0.0);
-  double J5 =mesh_functional_distorsion_2D(t,0.5,0.5);
-  double J6 =mesh_functional_distorsion_2D(t,0.0,0.5);
-
-  const double a = J1;
-  const double b = -3*J1-J2+4*J4;
-  const double c = -3*J1-J3+4*J6;
-  const double d = 4*(J1-J4+J5-J6);
-  const double e = 2*(J1+J2-2*J4);
-  const double f = 2*(J1+J3-2*J6);
-
-  double js[3] = {
-    MINQ (2*(J1+J2-2*J4), -3*J1-J2+4*J4, J1),
-    MINQ (2*(J1+J3-2*J6), -3*J1-J3+4*J6, J1),
-    MINQ (2*(J3+J2-2*J5), -3*J2-J3+4*J5, J2)
-  };
-  double min_interm =  *std::min_element(js,js+3);
-
-  double mat[2][2] = {{2*e,d},{d,2*f}};
-  double x[2], rhs[2] = {-b,-c};
-
-  if (!sys2x2(mat,rhs,x))return min_interm;
-
-  const double ximin = x[0];
-  const double etamin  = x[1];
-
-  if (ximin> 0 && etamin > 0 && 1-ximin-etamin>0){
-    const double m4 = a+b*ximin+c*etamin+d*ximin*etamin+
-      e*ximin*ximin + f*etamin*etamin;
-    /*
-    if (m4 < min_interm && (m4 < .9 || m4 > 1.1)){
-      printf("m4  = %g xi = %g eta  = %g min_interm = %g min_edges = %g %g %g\n",m4,ximin,etamin,min_interm, MINQ (e,b,a), MINQ (f,c,a), MINQ (-d+e+f,b-c+d-2*f,a+c+f));
-      FILE *f = fopen ("t.pos","w");
-      fprintf(f,"ST2(%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0){%g,%g,%g,%g,%g,%g}\n",
-	      t->getVertex(0)->x(),t->getVertex(0)->y(),
-	      t->getVertex(1)->x(),t->getVertex(1)->y(),
-	      t->getVertex(2)->x(),t->getVertex(2)->y(),
-	      t->getVertex(3)->x(),t->getVertex(3)->y(),
-	      t->getVertex(4)->x(),t->getVertex(4)->y(),
-	      t->getVertex(5)->x(),t->getVertex(5)->y(),
-	    J1,J2,J3,J4,J5,J6);
-      fclose(f);
-      getchar();
-    }
-    */
-    return std::min(m4, min_interm);
-  }
-  return min_interm;
-}
-
-double mesh_functional_distorsion_pN(MElement *t)
-{
-  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;
-    }
-
-    Ji(i) = mesh_functional_distorsion_2D(t,u,v);
-  }
-
-  fullVector<double> Bi( jac->getNumJacNodes() );
-  jac->lag2Bez(Ji,Bi);
-  return *std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size());
-}
-
-double qmDistorsionOfMapping (MTriangle *e)
-{
-  //  return 1.0;
-  if (e->getPolynomialOrder() == 1) return 1.0;
-  else if  (e->getPolynomialOrder() == 2) {
-    //    const double exact = mesh_functional_distorsion_p2_exact(e);
-    const double bezier= mesh_functional_distorsion_pN(e);
-    //    if (bezier < .1){
-    //      const double bezier_refined= mesh_functional_distorsion_p2_bezier_refined(e);
-    //      return bezier_refined;
-    //    }
-    /*
-    if (exact < .99 || exact > 1.01){
-      FILE *f = fopen ("statistics.dat","a");
-      fprintf(f,"%12.5E %12.5E %12.5E\n",exact,bezier,bezier_refined);
-      fclose(f);
-
-      if (exact > 0 && bezier < 0){
-	f = fopen ("t.pos","w");
-	double J1 =mesh_functional_distorsion(e,0.0,0.0);
-	double J2 =mesh_functional_distorsion(e,1.0,0.0);
-	double J3 =mesh_functional_distorsion(e,0.0,1.0);
-	double J4 =mesh_functional_distorsion(e,0.5,0.0);
-	double J5 =mesh_functional_distorsion(e,0.5,0.5);
-	double J6 =mesh_functional_distorsion(e,0.0,0.5);
-	fprintf(f,"ST2(%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0){%g,%g,%g,%g,%g,%g}\n",
-		e->getVertex(0)->x(),e->getVertex(0)->y(),
-		e->getVertex(1)->x(),e->getVertex(1)->y(),
-		e->getVertex(2)->x(),e->getVertex(2)->y(),
-		e->getVertex(3)->x(),e->getVertex(3)->y(),
-		e->getVertex(4)->x(),e->getVertex(4)->y(),
-		e->getVertex(5)->x(),e->getVertex(5)->y(),
-		J1,J2,J3,J4,J5,J6);
-	fclose(f);
-	getchar();
-      }
-    }
-  */
-    return bezier;
-  }
-  else return  mesh_functional_distorsion_pN(e);
-}
-
-double qmDistorsionOfMapping (MQuadrangle *e)
-{
-  //  return 1.0;
-  if (e->getPolynomialOrder() == 1) return 1.0;
-  else return mesh_functional_distorsion_pN(e);
-}
-
-
-double mesh_functional_distorsion_3D(MElement *t, double u, double v, double w)
-{
-  // compute uncurved element jacobian d_u x and d_v x
-  double mat[3][3];
-  const double det1 = t->getPrimaryJacobian(u, v, w, mat);
-//  const double det1 = det3x3(mat);
-  const double detN = t->getJacobian(u, v, w, mat);
-//  const double detN = det3x3(mat);
-  if (det1 == 0 || detN == 0) return 0;
-  double dist = detN / det1;
-  return dist;
-}
-
-double qmDistorsionOfMapping(MTetrahedron *t)
-{
-  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->getNumJacNodes() );
-  jac->lag2Bez(Ji,Bi);
-  /*
-     jac->matrixLag2Bez.print("Lag2Bez");
-
-      jac->points.print("Points");
-      t->getFunctionSpace(t->getPolynomialOrder())->points.print("lagrangianNodes");
-      t->getFunctionSpace(t->getPolynomialOrder())->monomials.print("Monomials");
-      t->getFunctionSpace(t->getPolynomialOrder())->coefficients.print("Coefficients");
-  */
-
-  return *std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size());
-}
-
 double qmTriangleAngles (MTriangle *e) {
   double a = 500;
   double worst_quality = std::numeric_limits<double>::max();
diff --git a/Mesh/qualityMeasures.h b/Mesh/qualityMeasures.h
index dfc8984e0f8780b078d86b9358e0ce8613535de0..ce740497283661a9ce16c850ec89dca16b6e1fd5 100644
--- a/Mesh/qualityMeasures.h
+++ b/Mesh/qualityMeasures.h
@@ -17,10 +17,6 @@ class MElement;
 enum qualityMeasure4Triangle {QMTRI_RHO, QMTRI_COND};
 enum qualityMeasure4Tet{QMTET_1, QMTET_2, QMTET_3, QMTET_ONE, QMTET_COND};
 
-double qmDistorsionOfMapping (MQuadrangle *e);
-double qmDistorsionOfMapping (MTriangle *e);
-double qmDistorsionOfMapping (MTetrahedron *e);
-
 double qmTriangleAngles (MTriangle *e);
 double qmQuadrangleAngles (MQuadrangle *e);
 
diff --git a/Numeric/JacobianBasis.cpp b/Numeric/JacobianBasis.cpp
index 0ebc8979fc3733e48bcd152d325fc7c025d186cb..95f49ec23a58b35e57fefa3aac89ea48109c0434 100644
--- a/Numeric/JacobianBasis.cpp
+++ b/Numeric/JacobianBasis.cpp
@@ -11,7 +11,7 @@
 #include "pyramidalBasis.h"
 #include "pointsGenerators.h"
 #include "BasisFactory.h"
-#include "MElement.h"
+#include "Numeric.h"
 
 // Bezier Exponents
 static fullMatrix<double> generate1DExponents(int order)
@@ -935,6 +935,25 @@ static fullMatrix<double> generateSubDivisor
 
 
 
+// Convert Bezier points to Lagrange points
+static fullMatrix<double> bez2LagPoints(bool dim1, bool dim2, bool dim3, const fullMatrix<double> &bezierPoints)
+{
+
+  const int numPt = bezierPoints.size1();
+  fullMatrix<double> lagPoints(numPt,3);
+
+  for (int i=0; i<numPt; i++) {
+    lagPoints(i,0) = dim1 ? -1. + 2*bezierPoints(i,0) : bezierPoints(i,0);
+    lagPoints(i,1) = dim2 ? -1. + 2*bezierPoints(i,1) : bezierPoints(i,1);
+    lagPoints(i,2) = dim3 ? -1. + 2*bezierPoints(i,2) : bezierPoints(i,2);
+  }
+
+  return lagPoints;
+
+}
+
+
+
 std::map<int, bezierBasis> bezierBasis::_bbs;
 const bezierBasis *bezierBasis::find(int tag)
 {
@@ -948,9 +967,10 @@ const bezierBasis *bezierBasis::find(int 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.);
-    B.matrixBez2Lag.resize(B.points.size1(),B.points.size1(),0.);
+    B.bezierPoints = gmshGeneratePointsPyramid(B.order,false);
+    B.lagPoints = B.bezierPoints;
+    B.matrixLag2Bez.resize(B.bezierPoints.size1(),B.bezierPoints.size1(),0.);
+    B.matrixBez2Lag.resize(B.bezierPoints.size1(),B.bezierPoints.size1(),0.);
     for (int i=0; i<B.matrixBez2Lag.size1(); ++i) {
       B.matrixLag2Bez(i,i) = 1.;
       B.matrixBez2Lag(i,i) = 1.;
@@ -965,14 +985,16 @@ const bezierBasis *bezierBasis::find(int tag)
         B.dim = 0;
         B.numLagPts = 1;
         B.exponents = generate1DExponents(0);
-        B.points    = generate1DPoints(0);
+        B.bezierPoints = generate1DPoints(0);
+        B.lagPoints = B.bezierPoints;
         dimSimplex = 0;
         break;
       case TYPE_LIN : {
         B.dim = 1;
         B.numLagPts = 2;
         B.exponents = generate1DExponents(B.order);
-        B.points    = generate1DPoints(B.order);
+        B.bezierPoints = generate1DPoints(B.order);
+        B.lagPoints = bez2LagPoints(true,false,false,B.bezierPoints);
         dimSimplex = 0;
         subPoints = generateSubPointsLine(0);
         break;
@@ -981,7 +1003,8 @@ const bezierBasis *bezierBasis::find(int tag)
         B.dim = 2;
         B.numLagPts = 3;
         B.exponents = generateExponentsTriangle(B.order);
-        B.points    = gmshGeneratePointsTriangle(B.order,false);
+        B.bezierPoints = gmshGeneratePointsTriangle(B.order,false);
+        B.lagPoints = B.bezierPoints;
         dimSimplex = 2;
         subPoints = generateSubPointsTriangle(B.order);
         break;
@@ -990,7 +1013,8 @@ const bezierBasis *bezierBasis::find(int tag)
         B.dim = 2;
         B.numLagPts = 4;
         B.exponents = generateExponentsQuad(B.order);
-        B.points    = generatePointsQuad(B.order,false);
+        B.bezierPoints = generatePointsQuad(B.order,false);
+        B.lagPoints = bez2LagPoints(true,true,false,B.bezierPoints);
         dimSimplex = 0;
         subPoints = generateSubPointsQuad(B.order);
         //      B.points.print("points");
@@ -1000,7 +1024,8 @@ const bezierBasis *bezierBasis::find(int tag)
         B.dim = 3;
         B.numLagPts = 4;
         B.exponents = generateExponentsTetrahedron(B.order);
-        B.points    = gmshGeneratePointsTetrahedron(B.order,false);
+        B.bezierPoints = gmshGeneratePointsTetrahedron(B.order,false);
+        B.lagPoints = B.bezierPoints;
         dimSimplex = 3;
         subPoints = generateSubPointsTetrahedron(B.order);
         break;
@@ -1009,7 +1034,8 @@ const bezierBasis *bezierBasis::find(int tag)
         B.dim = 3;
         B.numLagPts = 6;
         B.exponents = generateExponentsPrism(B.order);
-        B.points    = generatePointsPrism(B.order, false);
+        B.bezierPoints = generatePointsPrism(B.order, false);
+        B.lagPoints = bez2LagPoints(false,false,true,B.bezierPoints);
         dimSimplex = 2;
         subPoints = generateSubPointsPrism(B.order);
         break;
@@ -1018,7 +1044,8 @@ const bezierBasis *bezierBasis::find(int tag)
         B.dim = 3;
         B.numLagPts = 8;
         B.exponents = generateExponentsHex(B.order);
-        B.points    = generatePointsHex(B.order, false);
+        B.bezierPoints = generatePointsHex(B.order, false);
+        B.lagPoints = bez2LagPoints(true,true,true,B.bezierPoints);
         dimSimplex = 0;
         subPoints = generateSubPointsHex(B.order);
         break;
@@ -1028,16 +1055,17 @@ const bezierBasis *bezierBasis::find(int tag)
         B.dim = 3;
         B.numLagPts = 4;
         B.exponents = generateExponentsTetrahedron(0);
-        B.points    = gmshGeneratePointsTetrahedron(0, false);
+        B.bezierPoints = gmshGeneratePointsTetrahedron(0, false);
+        B.lagPoints = B.bezierPoints;
         dimSimplex = 3;
         subPoints = generateSubPointsTetrahedron(0);
         break;
       }
     }
-    B.matrixBez2Lag = generateBez2LagMatrix(B.exponents, B.points, B.order, dimSimplex);
+    B.matrixBez2Lag = generateBez2LagMatrix(B.exponents, B.bezierPoints, B.order, dimSimplex);
     B.matrixBez2Lag.invert(B.matrixLag2Bez);
     B.subDivisor = generateSubDivisor(B.exponents, subPoints, B.matrixLag2Bez, B.order, dimSimplex);
-    B.numDivisions = (int) pow(2., (int) B.points.size2());
+    B.numDivisions = (int) pow(2., (int) B.bezierPoints.size2());
   }
 
   return &B;
@@ -1120,7 +1148,7 @@ JacobianBasis::JacobianBasis(int tag)
   xBar /= numPrimMapNodes;
   yBar /= numPrimMapNodes;
   zBar /= numPrimMapNodes;
-  double barDPsi[numPrimMapNodes][3];
+  double (*barDPsi)[3] = new double[numPrimMapNodes][3];
   primMapBasis->df(xBar, yBar, zBar, barDPsi);
   primGradShapeBarX.resize(numPrimMapNodes);
   primGradShapeBarY.resize(numPrimMapNodes);
@@ -1130,6 +1158,7 @@ JacobianBasis::JacobianBasis(int tag)
     primGradShapeBarY(j) = barDPsi[j][1];
     primGradShapeBarZ(j) = barDPsi[j][2];
   }
+  delete[] barDPsi;
 
 }
 
@@ -1192,7 +1221,7 @@ double JacobianBasis::getPrimNormal2D(const fullMatrix<double> &nodesXYZ, fullMa
     dxyzdXbar(2) += primGradShapeBarX(j)*nodesXYZ(j,2);
     dxyzdYbar(0) += primGradShapeBarY(j)*nodesXYZ(j,0);
     dxyzdYbar(1) += primGradShapeBarY(j)*nodesXYZ(j,1);
-    dxyzdYbar(2) += primGradShapeBarX(j)*nodesXYZ(j,2);
+    dxyzdYbar(2) += primGradShapeBarY(j)*nodesXYZ(j,2);
   }
 
   result(0,2) = dxyzdXbar(0) * dxyzdYbar(1) - dxyzdXbar(1) * dxyzdYbar(0);
@@ -1309,6 +1338,165 @@ void JacobianBasis::getSignedJacobian(const fullMatrix<double> &nodesXYZ,
 
 
 
+// Calculate (signed) Jacobian at mapping's nodes for one element, given vectors for regularization
+// of line and surface Jacobians in 3D
+void JacobianBasis::getSignedJacAndGradients(const fullMatrix<double> &nodesXYZ,
+                                             const fullMatrix<double> &normals,
+                                             fullMatrix<double> &JDJ) const
+{
+
+  switch (bezier->dim) {
+
+    case 0 : {
+      for (int i = 0; i < numJacNodes; i++) {
+        for (int j = 0; j < numMapNodes; j++) {
+          JDJ (i,j) = 0.;
+          JDJ (i,j+1*numMapNodes) = 0.;
+          JDJ (i,j+2*numMapNodes) = 0.;
+        }
+        JDJ(i,3*numMapNodes) = 1.;
+      }
+      break;
+    }
+
+    case 1 : {
+      fullMatrix<double> dxyzdX(numJacNodes,3), dxyzdY(numJacNodes,3);
+      gradShapeMatX.mult(nodesXYZ, dxyzdX);
+      for (int i = 0; i < numJacNodes; i++) {
+        const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2);
+        const double &dxdY = normals(0,0), &dydY = normals(0,1), &dzdY = normals(0,2);
+        const double &dxdZ = normals(1,0), &dydZ = normals(1,1), &dzdZ = normals(1,2);
+        for (int j = 0; j < numMapNodes; j++) {
+          const double &dPhidX = gradShapeMatX(i,j);
+          JDJ (i,j) = dPhidX * dydY * dzdZ + dPhidX * dzdY * dydZ;
+          JDJ (i,j+1*numMapNodes) = dPhidX * dzdY * dxdZ - dPhidX * dxdY * dzdZ;
+          JDJ (i,j+2*numMapNodes) = dPhidX * dxdY * dydZ - dPhidX * dydY * dxdZ;
+        }
+        JDJ(i,3*numMapNodes) = calcDet3D(dxdX,dydX,dzdX,dxdY,dydY,dzdY,dxdZ,dydZ,dzdZ);
+      }
+      break;
+    }
+
+    case 2 : {
+      fullMatrix<double> dxyzdX(numJacNodes,3), dxyzdY(numJacNodes,3);
+      gradShapeMatX.mult(nodesXYZ, dxyzdX);
+      gradShapeMatY.mult(nodesXYZ, dxyzdY);
+      for (int i = 0; i < numJacNodes; i++) {
+        const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2);
+        const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2);
+        const double &dxdZ = normals(0,0), &dydZ = normals(0,1), &dzdZ = normals(0,2);
+        for (int j = 0; j < numMapNodes; j++) {
+          const double &dPhidX = gradShapeMatX(i,j);
+          const double &dPhidY = gradShapeMatY(i,j);
+          JDJ (i,j) =
+            dPhidX * dydY * dzdZ + dzdX * dPhidY * dydZ +
+            dPhidX * dzdY * dydZ - dydX * dPhidY * dzdZ;
+          JDJ (i,j+1*numMapNodes) =
+            dxdX * dPhidY * dzdZ +
+            dPhidX * dzdY * dxdZ - dzdX * dPhidY * dxdZ
+                                 - dPhidX * dxdY * dzdZ;
+          JDJ (i,j+2*numMapNodes) =
+                                   dPhidX * dxdY * dydZ +
+            dydX * dPhidY * dxdZ - dPhidX * dydY * dxdZ -
+            dxdX * dPhidY * dydZ;
+        }
+        JDJ(i,3*numMapNodes) = calcDet3D(dxdX,dydX,dzdX,dxdY,dydY,dzdY,dxdZ,dydZ,dzdZ);
+      }
+      break;
+    }
+
+    case 3 : {
+      fullMatrix<double> dxyzdX(numJacNodes,3), dxyzdY(numJacNodes,3), dxyzdZ(numJacNodes,3);
+      gradShapeMatX.mult(nodesXYZ, dxyzdX);
+      gradShapeMatY.mult(nodesXYZ, dxyzdY);
+      gradShapeMatZ.mult(nodesXYZ, dxyzdZ);
+      for (int i = 0; i < numJacNodes; i++) {
+        const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2);
+        const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2);
+        const double &dxdZ = dxyzdZ(i,0), &dydZ = dxyzdZ(i,1), &dzdZ = dxyzdZ(i,2);
+        for (int j = 0; j < numMapNodes; j++) {
+          const double &dPhidX = gradShapeMatX(i,j);
+          const double &dPhidY = gradShapeMatY(i,j);
+          const double &dPhidZ = gradShapeMatZ(i,j);
+          JDJ (i,j) =
+            dPhidX * dydY * dzdZ + dzdX * dPhidY * dydZ +
+            dydX * dzdY * dPhidZ - dzdX * dydY * dPhidZ -
+            dPhidX * dzdY * dydZ - dydX * dPhidY * dzdZ;
+          JDJ (i,j+1*numMapNodes) =
+            dxdX * dPhidY * dzdZ + dzdX * dxdY * dPhidZ +
+            dPhidX * dzdY * dxdZ - dzdX * dPhidY * dxdZ -
+            dxdX * dzdY * dPhidZ - dPhidX * dxdY * dzdZ;
+          JDJ (i,j+2*numMapNodes) =
+            dxdX * dydY * dPhidZ + dPhidX * dxdY * dydZ +
+            dydX * dPhidY * dxdZ - dPhidX * dydY * dxdZ -
+            dxdX * dPhidY * dydZ - dydX * dxdY * dPhidZ;
+        }
+        JDJ(i,3*numMapNodes) = calcDet3D(dxdX,dydX,dzdX,dxdY,dydY,dzdY,dxdZ,dydZ,dzdZ);
+      }
+      break;
+    }
+
+  }
+
+}
+
+
+
+void JacobianBasis::getMetricMinAndGradients(const fullMatrix<double> &nodesXYZ,
+                                             const fullMatrix<double> &nodesXYZStraight,
+                                             fullVector<double> &lambdaJ , fullMatrix<double> &gradLambdaJ) const
+{
+
+  // jacobian of the straight elements (only triangles for now)
+  SPoint3 v0(nodesXYZ(0,0),nodesXYZ(0,1),nodesXYZ(0,2));
+  SPoint3 v1(nodesXYZ(1,0),nodesXYZ(1,1),nodesXYZ(1,2));
+  SPoint3 v2(nodesXYZ(2,0),nodesXYZ(2,1),nodesXYZ(2,2));
+  SPoint3 *IXYZ[3] = {&v0, &v1, &v2};
+  double jaci[2][2] = {
+    {IXYZ[1]->x() - IXYZ[0]->x(), IXYZ[2]->x() - IXYZ[0]->x()},
+    {IXYZ[1]->y() - IXYZ[0]->y(), IXYZ[2]->y() - IXYZ[0]->y()}
+  };
+  double invJaci[2][2];
+  inv2x2(jaci, invJaci);
+
+  for (int l = 0; l < numJacNodes; l++) {
+    double jac[2][2] = {{0., 0.}, {0., 0.}};
+    for (int i = 0; i < numMapNodes; i++) {
+      const double &dPhidX = gradShapeMatX(l,i);
+      const double &dPhidY = gradShapeMatY(l,i);
+      const double dpsidx = dPhidX * invJaci[0][0] + dPhidY * invJaci[1][0];
+      const double dpsidy = dPhidX * invJaci[0][1] + dPhidY * invJaci[1][1];
+      jac[0][0] += nodesXYZ(i,0) * dpsidx;
+      jac[0][1] += nodesXYZ(i,0) * dpsidy;
+      jac[1][0] += nodesXYZ(i,1) * dpsidx;
+      jac[1][1] += nodesXYZ(i,1) * dpsidy;
+    }
+    const double dxdx = jac[0][0] * jac[0][0] + jac[0][1] * jac[0][1];
+    const double dydy = jac[1][0] * jac[1][0] + jac[1][1] * jac[1][1];
+    const double dxdy = jac[0][0] * jac[1][0] + jac[0][1] * jac[1][1];
+    const double sqr = sqrt((dxdx - dydy) * (dxdx - dydy) + 4 * dxdy * dxdy);
+    const double osqr = sqr > 1e-8 ? 1/sqr : 0;
+    lambdaJ(l) = 0.5 * (dxdx + dydy - sqr);
+    const double axx = (1 - (dxdx - dydy) * osqr) * jac[0][0] - 2 * dxdy * osqr * jac[1][0];
+    const double axy = (1 - (dxdx - dydy) * osqr) * jac[0][1] - 2 * dxdy * osqr * jac[1][1];
+    const double ayx = -2 * dxdy * osqr * jac[0][0] + (1 - (dydy - dxdx) * osqr) * jac[1][0];
+    const double ayy = -2 * dxdy * osqr * jac[0][1] + (1 - (dydy - dxdx) * osqr) * jac[1][1];
+    const double axixi   = axx * invJaci[0][0] + axy * invJaci[0][1];
+    const double aetaeta = ayx * invJaci[1][0] + ayy * invJaci[1][1];
+    const double aetaxi  = ayx * invJaci[0][0] + ayy * invJaci[0][1];
+    const double axieta  = axx * invJaci[1][0] + axy * invJaci[1][1];
+    for (int i = 0; i < numMapNodes; i++) {
+      const double &dPhidX = gradShapeMatX(l,i);
+      const double &dPhidY = gradShapeMatY(l,i);
+      gradLambdaJ(l, i + 0 * numMapNodes) = axixi * dPhidX + axieta * dPhidY;
+      gradLambdaJ(l, i + 1 * numMapNodes) = aetaxi * dPhidX + aetaeta * dPhidY;
+    }
+  }
+
+}
+
+
+
 // Calculate (signed) Jacobian at mapping's nodes for several elements
 // TODO: Optimize and test 1D & 2D
 void JacobianBasis::getSignedJacobian(const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
diff --git a/Numeric/JacobianBasis.h b/Numeric/JacobianBasis.h
index 801ccb63c908e842669fb6332369b332d82299d0..c24fc3e5c9b207d8e39bcc284a5b1aa713b04dc1 100644
--- a/Numeric/JacobianBasis.h
+++ b/Numeric/JacobianBasis.h
@@ -21,7 +21,7 @@ class bezierBasis {
   int numDivisions;
   // the 'numLagPts' first exponents are related to 'Lagrangian' values
   fullMatrix<double> exponents; // exponents of Bezier FF
-  fullMatrix<double> points; // sampling point
+  fullMatrix<double> bezierPoints, lagPoints; // sampling point
   fullMatrix<double> matrixLag2Bez, matrixBez2Lag;
   fullMatrix<double> subDivisor;
   static const bezierBasis *find(int);
@@ -35,12 +35,14 @@ class JacobianBasis {
   fullVector<double> primGradShapeBarX, primGradShapeBarY, primGradShapeBarZ;
   fullMatrix<double> matrixPrimJac2Jac;                                   // Lifts Lagrange basis of primary Jac. to Lagrange basis of Jac.
   int numJacNodes, numMapNodes, numPrimJacNodes, numPrimMapNodes;
+  inline const fullMatrix<double> &getPoints() const { return bezier->lagPoints; }
  public :
   static const JacobianBasis *find(int);
   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 getNumJacNodes() const { return numJacNodes; }
+  inline int getNumMapNodes() const { return numMapNodes; }
+  inline int getNumPrimJacNodes() const { return numPrimJacNodes; }
+  inline int getNumPrimMapNodes() const { return numPrimMapNodes; }
   inline int getNumDivisions() const { return bezier->numDivisions; }
   inline int getNumSubNodes() const { return bezier->subDivisor.size1(); }
   inline int getNumLagPts() const { return bezier->numLagPts; }
@@ -48,6 +50,11 @@ class JacobianBasis {
   double getPrimNormal2D(const fullMatrix<double> &nodesXYZ, fullMatrix<double> &result) const;
   void getSignedJacobian(const fullMatrix<double> &nodesXYZ,
                          const fullMatrix<double> &normals, fullVector<double> &jacobian) const;
+  void getSignedJacAndGradients(const fullMatrix<double> &nodesXYZ,
+                                const fullMatrix<double> &normals, fullMatrix<double> &JDJ) const;
+  void getMetricMinAndGradients(const fullMatrix<double> &nodesXYZ,
+                                const fullMatrix<double> &nodesXYZStraight,
+                                fullVector<double> &lambdaJ , fullMatrix<double> &gradLambdaJ) const;
   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;
diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
index 12c2c6dedfcacdf4ee4e2644021c47319bf8c1fb..08398951b89659e78805abe5d62e3a90f43b78e6 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
@@ -8,28 +8,6 @@
 
 
 
-std::map<int, fullMatrix<double> > Mesh::_gradShapeFunctions;
-
-
-
-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 = jac->getPoints();
-  if (lagrange->parentType == TYPE_QUA) {
-    for (int i = 0; i < bezierPoints.size1(); ++i) {
-      bezierPoints(i, 0) = -1 + 2 * bezierPoints(i, 0);
-      bezierPoints(i, 1) = -1 + 2 * bezierPoints(i, 1);
-    }
-  }
-
-  fullMatrix<double> allDPsi;
-  lagrange->df(bezierPoints, allDPsi);
-  return allDPsi;
-}
-
-
-
 Mesh::Mesh(GEntity *ge, const std::set<MElement*> &els, std::set<MVertex*> &toFix, int method) :
     _ge(ge)
 {
@@ -67,16 +45,12 @@ Mesh::Mesh(GEntity *ge, const std::set<MElement*> &els, std::set<MVertex*> &toFi
   _indPCEl.resize(nElements);
   int iEl = 0;
   for(std::set<MElement*>::const_iterator it = els.begin(); it != els.end(); ++it, ++iEl) {
-    MElement *el = *it;
-    _el[iEl] = el;
-    const nodalBasis *lagrange = el->getFunctionSpace();
-    const JacobianBasis *jac = JacobianBasis::find(lagrange->type);
-    if (_gradShapeFunctions.find(lagrange->type) == _gradShapeFunctions.end())
-      _gradShapeFunctions[lagrange->type] = computeGSF(lagrange, jac);
+    _el[iEl] = *it;
+    const JacobianBasis *jac = _el[iEl]->getJacobianFuncSpace();
     _nBezEl[iEl] = jac->getNumJacNodes();
-    _nNodEl[iEl] = lagrange->points.size1();
-    for (int iVEl = 0; iVEl < lagrange->points.size1(); iVEl++) {
-      MVertex *vert = el->getVertex(iVEl);
+    _nNodEl[iEl] = jac->getNumMapNodes();
+    for (int iVEl = 0; iVEl < jac->getNumMapNodes(); iVEl++) {
+      MVertex *vert = _el[iEl]->getVertex(iVEl);
       int iV = addVert(vert);
       _el2V[iEl].push_back(iV);
       const int nPCV = _pc->nCoord(vert);
@@ -105,8 +79,8 @@ Mesh::Mesh(GEntity *ge, const std::set<MElement*> &els, std::set<MVertex*> &toFi
 
   // Set normals to 2D elements (with magnitude of inverse Jacobian) or initial Jacobians of 3D elements
   if (_dim == 2) {
-    _normEl.resize(nEl());
-    for (int iEl = 0; iEl < nEl(); iEl++) _normEl[iEl] = getNormalEl(iEl);
+    _scaledNormEl.resize(nEl());
+    for (int iEl = 0; iEl < nEl(); iEl++) calcScaledNormalEl2D(iEl);
   }
   else {
     _invStraightJac.resize(nEl(),1.);
@@ -125,34 +99,25 @@ Mesh::Mesh(GEntity *ge, const std::set<MElement*> &els, std::set<MVertex*> &toFi
 
 
 
-SVector3 Mesh::getNormalEl(int iEl)
+void Mesh::calcScaledNormalEl2D(int iEl)
 {
 
-  switch (_el[iEl]->getType()) {
-    case TYPE_TRI: {
-      const int iV0 = _el2V[iEl][0], iV1 = _el2V[iEl][1], iV2 = _el2V[iEl][2];
-      SVector3 v10 = _xyz[iV1]-_xyz[iV0], v20 = _xyz[iV2]-_xyz[iV0];
-      SVector3 n = crossprod(v10, v20);
-      double xxx = n.norm();
-      n *= 1./(xxx*xxx);
-      return n;
-      break;
-    }
-    case TYPE_QUA: {
-      const int iV0 = _el2V[iEl][0], iV1 = _el2V[iEl][1], iV3 = _el2V[iEl][3];
-      SVector3 v10 = _xyz[iV1]-_xyz[iV0], v30 = _xyz[iV3]-_xyz[iV0];
-      SVector3 n = crossprod(v10, v30);
-      double xxx = n.norm();
-      n *= 4./(xxx*xxx);
-      return n;
-      break;
-    }
-    default:
-      std::cout << "ERROR: getNormalEl: Unknown element type" << std::endl;
-      break;
+  const JacobianBasis *jac = _el[iEl]->getJacobianFuncSpace();
+
+  fullMatrix<double> primNodesXYZ(jac->getNumPrimMapNodes(),3);
+  for (int i=0; i<jac->getNumPrimMapNodes(); i++) {
+    const int &iV = _el2V[iEl][i];
+    primNodesXYZ(i,0) = _xyz[iV].x();
+    primNodesXYZ(i,1) = _xyz[iV].y();
+    primNodesXYZ(i,2) = _xyz[iV].z();
   }
 
-  return SVector3(0.);  // Just to avoid compilation warnings...
+  _scaledNormEl[iEl].resize(1,3);
+  const double norm = jac->getPrimNormal2D(primNodesXYZ,_scaledNormEl[iEl]);
+
+  _scaledNormEl[iEl](0,0) /= norm;         // Re-scaling normal here is faster than an
+  _scaledNormEl[iEl](0,1) /= norm;         // extra scaling operation on the Jacobian
+  _scaledNormEl[iEl](0,2) /= norm;
 
 }
 
@@ -262,56 +227,32 @@ void Mesh::updateGEntityPositions()
 }
 
 
+
 void Mesh::metricMinAndGradients(int iEl, std::vector<double> &lambda , std::vector<double> &gradLambda)
 {
-  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];
-  fullVector<double> lambdaJ(nbBez), lambdaB(nbBez);
-  fullMatrix<double> gradLambdaJ(nbBez, 2 * nbNod);
-  fullMatrix<double> gradLambdaB(nbBez, 2 * nbNod);
-
-  // jacobian of the straight elements (only triangles for now)
-  SPoint3 *IXYZ[3] = {&_ixyz[_el2V[iEl][0]], &_ixyz[_el2V[iEl][1]], &_ixyz[_el2V[iEl][2]]};
-  double jaci[2][2] = {
-    {IXYZ[1]->x() - IXYZ[0]->x(), IXYZ[2]->x() - IXYZ[0]->x()},
-    {IXYZ[1]->y() - IXYZ[0]->y(), IXYZ[2]->y() - IXYZ[0]->y()}
-  };
-  double invJaci[2][2];
-  inv2x2(jaci, invJaci);
+
+  const JacobianBasis *jacBasis = _el[iEl]->getJacobianFuncSpace();
+  const int &numJacNodes = jacBasis->getNumJacNodes();
+  const int &numMapNodes = jacBasis->getNumMapNodes(), &numPrimMapNodes = jacBasis->getNumPrimMapNodes();
+  fullVector<double> lambdaJ(numJacNodes), lambdaB(numJacNodes);
+  fullMatrix<double> gradLambdaJ(numJacNodes, 2 * numMapNodes);
+  fullMatrix<double> gradLambdaB(numJacNodes, 2 * numMapNodes);
   
-  for (int l = 0; l < nbBez; l++) {
-    fullMatrix<double> dPsi(gsf, l * 3, 3);
-    double jac[2][2] = {{0., 0.}, {0., 0.}};
-    for (int i = 0; i < nbNod; i++) {
-      int &iVi = _el2V[iEl][i];
-      const double dpsidx = dPsi(i, 0) * invJaci[0][0] + dPsi(i, 1) * invJaci[1][0];
-      const double dpsidy = dPsi(i, 0) * invJaci[0][1] + dPsi(i, 1) * invJaci[1][1];
-      jac[0][0] += _xyz[iVi].x() * dpsidx;
-      jac[0][1] += _xyz[iVi].x() * dpsidy;
-      jac[1][0] += _xyz[iVi].y() * dpsidx;
-      jac[1][1] += _xyz[iVi].y() * dpsidy;
-    }
-    const double dxdx = jac[0][0] * jac[0][0] + jac[0][1] * jac[0][1];
-    const double dydy = jac[1][0] * jac[1][0] + jac[1][1] * jac[1][1];
-    const double dxdy = jac[0][0] * jac[1][0] + jac[0][1] * jac[1][1];
-    const double sqr = sqrt((dxdx - dydy) * (dxdx - dydy) + 4 * dxdy * dxdy);
-    const double osqr = sqr > 1e-8 ? 1/sqr : 0;
-    lambdaJ(l) = 0.5 * (dxdx + dydy - sqr);
-    const double axx = (1 - (dxdx - dydy) * osqr) * jac[0][0] - 2 * dxdy * osqr * jac[1][0];
-    const double axy = (1 - (dxdx - dydy) * osqr) * jac[0][1] - 2 * dxdy * osqr * jac[1][1];
-    const double ayx = -2 * dxdy * osqr * jac[0][0] + (1 - (dydy - dxdx) * osqr) * jac[1][0];
-    const double ayy = -2 * dxdy * osqr * jac[0][1] + (1 - (dydy - dxdx) * osqr) * jac[1][1];
-    const double axixi   = axx * invJaci[0][0] + axy * invJaci[0][1];
-    const double aetaeta = ayx * invJaci[1][0] + ayy * invJaci[1][1];
-    const double aetaxi  = ayx * invJaci[0][0] + ayy * invJaci[0][1];
-    const double axieta  = axx * invJaci[1][0] + axy * invJaci[1][1];
-    for (int i = 0; i < nbNod; i++) {
-      gradLambdaJ(l, i + 0 * nbNod) = axixi * dPsi(i, 0) + axieta * dPsi(i, 1);
-      gradLambdaJ(l, i + 1 * nbNod) = aetaxi * dPsi(i, 0) + aetaeta * dPsi(i, 1);
+  // Coordinates of nodes
+  fullMatrix<double> nodesXYZ(numMapNodes,3), nodesXYZStraight(numPrimMapNodes,3);
+  for (int i = 0; i < numMapNodes; i++) {
+    int &iVi = _el2V[iEl][i];
+    nodesXYZ(i,0) = _xyz[iVi].x();
+    nodesXYZ(i,1) = _xyz[iVi].y();
+    nodesXYZ(i,2) = _xyz[iVi].z();
+    if (i < numPrimMapNodes) {
+      nodesXYZStraight(i,0) = _ixyz[iVi].x();
+      nodesXYZStraight(i,1) = _ixyz[iVi].y();
+      nodesXYZStraight(i,2) = _ixyz[iVi].z();
     }
   }
+
+  jacBasis->getMetricMinAndGradients(nodesXYZ,nodesXYZStraight,lambdaJ,gradLambdaJ);
   
   //l2b.mult(lambdaJ, lambdaB);
   //l2b.mult(gradLambdaJ, gradLambdaB);
@@ -319,19 +260,19 @@ void Mesh::metricMinAndGradients(int iEl, std::vector<double> &lambda , std::vec
   gradLambdaB = gradLambdaJ;
 
   int iPC = 0;
-  std::vector<SPoint3> gXyzV(nbBez);
-  std::vector<SPoint3> gUvwV(nbBez);
-  for (int l = 0; l < nbBez; l++) {
+  std::vector<SPoint3> gXyzV(numJacNodes);
+  std::vector<SPoint3> gUvwV(numJacNodes);
+  for (int l = 0; l < numJacNodes; l++) {
     lambda[l] = lambdaB(l);
   }
-  for (int i = 0; i < nbNod; i++) {
+  for (int i = 0; i < numMapNodes; i++) {
     int &iFVi = _el2FV[iEl][i];
     if (iFVi >= 0) {
-      for (int l = 0; l < nbBez; l++) {
-        gXyzV [l] = SPoint3(gradLambdaB(l,i+0*nbNod),gradLambdaB(l,i+1*nbNod),/*BDB(l,i+2*nbNod)*/ 0.);
+      for (int l = 0; l < numJacNodes; l++) {
+        gXyzV [l] = SPoint3(gradLambdaB(l,i+0*numMapNodes),gradLambdaB(l,i+1*numMapNodes),/*BDB(l,i+2*nbNod)*/ 0.);
       }
       _pc->gXyz2gUvw(_freeVert[iFVi],_uvw[iFVi],gXyzV,gUvwV);
-      for (int l = 0; l < nbBez; l++) {
+      for (int l = 0; l < numJacNodes; l++) {
         gradLambda[indGSJ(iEl,l,iPC)] = gUvwV[l][0];
         if (_nPCFV[iFVi] >= 2) gradLambda[indGSJ(iEl,l,iPC+1)] = gUvwV[l][1];
         if (_nPCFV[iFVi] == 3) gradLambda[indGSJ(iEl,l,iPC+2)] = gUvwV[l][2];
@@ -341,120 +282,54 @@ void Mesh::metricMinAndGradients(int iEl, std::vector<double> &lambda , std::vec
   }
 }
 
-/*
-  A faster version that computes jacobians and their gradients
-
-  Terms of jacobian are of the form  J_{11} = dX / dU        
-
-  X = \sum \phi_j X_{j}
-
-  d J_{11} / dX_k = d \phi_k / du    
-
- */
-
 
 
 void Mesh::scaledJacAndGradients(int iEl, std::vector<double> &sJ , std::vector<double> &gSJ) {
+
+  const JacobianBasis *jacBasis = _el[iEl]->getJacobianFuncSpace();
+  const int &numJacNodes = jacBasis->getNumJacNodes();
+  const int &numMapNodes = jacBasis->getNumMapNodes();
+  fullMatrix<double> JDJ (numJacNodes,3*numMapNodes+1);
+  fullMatrix<double> BDB (numJacNodes,3*numMapNodes+1);
   
-  // if (_dim == 2 && !projJac){
-  //   //    printf("coucou\n");
-  //   gradScaledJac(iEl,gSJ);
-  //   scaledJac(iEl,sJ);    
-  //   return;
-  // }
-  
-  SVector3 n ;
-  if (_dim == 2)
-    n = _normEl[iEl];
-  
-  //  std::vector<double> OLD = sJ;
-  //  std::vector<double> OLD = gSJ;
-  //  gradScaledJac(iEl,OLD);
-  //  scaledJac(iEl,OLD);
-
-  const JacobianBasis *jacBasis = JacobianBasis::find(_el[iEl]->getTypeForMSH());
-  fullMatrix<double> &gsf = _gradShapeFunctions[_el[iEl]->getTypeForMSH()];
-  const int nbBez = _nBezEl[iEl];
-  const int nbNod = _nNodEl[iEl];
-  fullMatrix<double> JDJ (nbBez,3*nbNod+1);
-  fullMatrix<double> BDB (nbBez,3*nbNod+1);
-  
-  double jac[3][3];
-  for (int l = 0; l < nbBez; l++) {
-    fullMatrix<double> dPsi(gsf, l * 3, 3);
-
-    jac[0][0] = jac[0][1] = jac[0][2] = 0.;
-    jac[1][0] = jac[1][1] = jac[1][2] = 0.;
-    jac[2][0] = (_dim == 2) ? n.x() : 0.0; jac[2][1] = (_dim == 2) ? n.y() : 0.0; jac[2][2] = (_dim == 2) ? n.z() : 0.0;
-
-    const double INVJ = (_dim == 3) ? _invStraightJac[iEl] : 1.0;
-    for (int i = 0; i < nbNod; i++) {
-      int &iVi = _el2V[iEl][i];
-      const double x = _xyz[iVi].x();
-      const double y = _xyz[iVi].y();
-      const double z = _xyz[iVi].z();
-      for (int k = 0; k < _dim; k++) {
-	const double gg = dPsi(i, k);
-	jac[k][0] += x * gg;
-	jac[k][1] += y * gg;
-	jac[k][2] += z * gg;
-      }
-    }
-    for (int i = 0; i < nbNod; i++) {
-      JDJ (l,i+0*nbNod) = 
-	( dPsi(i, 0) * jac[1][1] * jac[2][2] + jac[0][2] *  dPsi(i, 1) * jac[2][1] +
-	 jac[0][1] * jac[1][2] *  dPsi(i, 2) - jac[0][2] * jac[1][1] *  dPsi(i, 2) -
-	  dPsi(i, 0) * jac[1][2] * jac[2][1] - jac[0][1] *  dPsi(i, 1) * jac[2][2])
-	* INVJ; 
-      JDJ (l,i+1*nbNod) = 
-	(jac[0][0] * dPsi(i, 1) * jac[2][2] + jac[0][2] * jac[1][0] * dPsi(i, 2) +
-	 dPsi(i, 0) * jac[1][2] * jac[2][0] - jac[0][2] * dPsi(i, 1) * jac[2][0] -
-	 jac[0][0] * jac[1][2] * dPsi(i, 2) - dPsi(i, 0) * jac[1][0] * jac[2][2])
-	* INVJ; 
-      JDJ (l,i+2*nbNod) = 
-	(jac[0][0] * jac[1][1] * dPsi(i, 2) + dPsi(i, 0) * jac[1][0] * jac[2][1] +
-	 jac[0][1] * dPsi(i, 1) * jac[2][0] - dPsi(i, 0) * jac[1][1] * jac[2][0] -
-	 jac[0][0] * dPsi(i, 1) * jac[2][1] - jac[0][1] * jac[1][0] * dPsi(i, 2))
-	* INVJ; 
-    }    
-    const double dJ = 
-      jac[0][0] * jac[1][1] * jac[2][2] + jac[0][2] * jac[1][0] * jac[2][1] +
-      jac[0][1] * jac[1][2] * jac[2][0] - jac[0][2] * jac[1][1] * jac[2][0] -
-      jac[0][0] * jac[1][2] * jac[2][1] - jac[0][1] * jac[1][0] * jac[2][2];
-    JDJ(l,3*nbNod) = dJ * INVJ;        
+  // Coordinates of nodes
+  fullMatrix<double> nodesXYZ(numMapNodes,3), normals(_dim,3);
+  for (int i = 0; i < numMapNodes; i++) {
+    int &iVi = _el2V[iEl][i];
+    nodesXYZ(i,0) = _xyz[iVi].x();
+    nodesXYZ(i,1) = _xyz[iVi].y();
+    nodesXYZ(i,2) = _xyz[iVi].z();
   }
+
+  // Calculate Jacobian and gradients, scale if 3D (already scaled by regularization normals in 2D)
+  jacBasis->getSignedJacAndGradients(nodesXYZ,_scaledNormEl[iEl],JDJ);
+  if (_dim == 3) JDJ.scale(_invStraightJac[iEl]);
   
-  //  (N_b x N_b) x (N_b x 3*N_n + 1) 
+  // Transform Jacobian and gradients from Lagrangian to Bezier basis
   jacBasis->lag2Bez(JDJ,BDB);
 
-  // the scaled jacobian
-  //  printf("ELEMENT %d\n",iEl);
-  for (int l = 0; l < nbBez; l++) {
-    sJ [l] = BDB (l,3*nbNod);    
-    //    printf("OLD %12.5E NEW %12.5E\n",OLD[l],sJ[l]);
-  }
+  // Scaled jacobian
+  for (int l = 0; l < numJacNodes; l++) sJ [l] = BDB (l,3*numMapNodes);
 
-  // gradients of the scaled jacobian
+  // Gradients of the scaled jacobian
   int iPC = 0;
-  std::vector<SPoint3> gXyzV(nbBez);
-  std::vector<SPoint3> gUvwV(nbBez);
-  for (int i = 0; i < nbNod; i++) {
+  std::vector<SPoint3> gXyzV(numJacNodes);
+  std::vector<SPoint3> gUvwV(numJacNodes);
+  for (int i = 0; i < numMapNodes; i++) {
     int &iFVi = _el2FV[iEl][i];
     if (iFVi >= 0) {
-      for (int l = 0; l < nbBez; l++) {
-	gXyzV [l] = SPoint3(BDB(l,i+0*nbNod),BDB(l,i+1*nbNod),BDB(l,i+2*nbNod));
-      }
+      for (int l = 0; l < numJacNodes; l++)
+        gXyzV [l] = SPoint3(BDB(l,i+0*numMapNodes),BDB(l,i+1*numMapNodes),BDB(l,i+2*numMapNodes));
       _pc->gXyz2gUvw(_freeVert[iFVi],_uvw[iFVi],gXyzV,gUvwV);
-      for (int l = 0; l < nbBez; l++) {
-	gSJ[indGSJ(iEl,l,iPC)] = gUvwV[l][0];
-	if (_nPCFV[iFVi] >= 2) gSJ[indGSJ(iEl,l,iPC+1)] = gUvwV[l][1];
-	if (_nPCFV[iFVi] == 3) gSJ[indGSJ(iEl,l,iPC+2)] = gUvwV[l][2];
-	//	if (fabs(OLD[indGSJ(iEl,l,iPC+2)]-gSJ[indGSJ(iEl,l,iPC+2)]) > 1.e-6)
-	//	  printf("OLD = %12.5E new = %12.5E\n",OLD[indGSJ(iEl,l,iPC+2)],gSJ[indGSJ(iEl,l,iPC+2)]);
+      for (int l = 0; l < numJacNodes; l++) {
+        gSJ[indGSJ(iEl,l,iPC)] = gUvwV[l][0];
+        if (_nPCFV[iFVi] >= 2) gSJ[indGSJ(iEl,l,iPC+1)] = gUvwV[l][1];
+        if (_nPCFV[iFVi] == 3) gSJ[indGSJ(iEl,l,iPC+2)] = gUvwV[l][2];
       }
       iPC += _nPCFV[iFVi];
     } 
   }
+
 }
 
 
diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.h b/contrib/HighOrderMeshOptimizer/OptHomMesh.h
index a7fa37a76848e2fb834036ea05b8d957423f3c67..0a716ae5a2760fc45126aaf2e3b4a21289d7e26a 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomMesh.h
+++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.h
@@ -60,31 +60,28 @@ private:
 
   GEntity *_ge;
   int _dim;
-  int _nPC;                                     // Total nb. of parametric coordinates
-
-  std::vector<MElement*> _el;                   // List of elements
-  std::vector<SVector3> _normEl;                // Normals to 2D elements
-  std::vector<double> _invStraightJac;          // Initial Jacobians for 3D elements
-  std::vector<MVertex*> _vert, _freeVert;       // List of vert., free vert.
-  std::vector<int> _fv2V;                       // Index of free vert. -> index of vert.
-  std::vector<bool> _forced;                    // Is vertex forced?
-  std::vector<SPoint3> _xyz, _ixyz;             // Physical coord. of ALL vertices (current, straight, init.)
-  std::vector<SPoint3> _uvw, _iuvw;             // Parametric coord. of FREE vertices (current, straight, init.)
-  std::vector<int> _startPCFV;                  // Start index of parametric coordinates for a free vertex
-  std::vector<int> _nPCFV;                      // Number of parametric coordinates for a free vertex
-  std::vector<std::vector<int> > _el2FV, _el2V; // Free vertices, vertices in element
-  std::vector<int> _nBezEl, _nNodEl;            // Number of Bezier poly. and nodes for an el.
-  std::vector<std::vector<int> > _indPCEl;      // Index of parametric coord. for an el.
+  int _nPC;                                       // Total nb. of parametric coordinates
+
+  std::vector<MElement*> _el;                     // List of elements
+  std::vector<fullMatrix<double> > _scaledNormEl; // Normals to 2D elements for Jacobian regularization and scaling
+  std::vector<double> _invStraightJac;            // Initial Jacobians for 3D elements
+  std::vector<MVertex*> _vert, _freeVert;         // List of vert., free vert.
+  std::vector<int> _fv2V;                         // Index of free vert. -> index of vert.
+  std::vector<bool> _forced;                      // Is vertex forced?
+  std::vector<SPoint3> _xyz, _ixyz;               // Physical coord. of ALL vertices (current, straight, init.)
+  std::vector<SPoint3> _uvw, _iuvw;               // Parametric coord. of FREE vertices (current, straight, init.)
+  std::vector<int> _startPCFV;                    // Start index of parametric coordinates for a free vertex
+  std::vector<int> _nPCFV;                        // Number of parametric coordinates for a free vertex
+  std::vector<std::vector<int> > _el2FV, _el2V;   // Free vertices, vertices in element
+  std::vector<int> _nBezEl, _nNodEl;              // Number of Bezier poly. and nodes for an el.
+  std::vector<std::vector<int> > _indPCEl;        // Index of parametric coord. for an el.
 
   ParamCoord *_pc;
-  bool projJac;                                 // Using "projected" Jacobians or not
-
-  static std::map<int, fullMatrix<double> >  _gradShapeFunctions; // gradients of shape functions at Bezier points 
+  bool projJac;                                   // Using "projected" Jacobians or not
 
   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 JacobianBasis *jac);
+  void calcScaledNormalEl2D(int iEl);
   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; }