diff --git a/Geo/GEdge.cpp b/Geo/GEdge.cpp
index a724c9beb94cd85c90619a5008b74550aaa92646..b96ace6065ddfbe7fdbb0c2d235af1dbb5f53030 100644
--- a/Geo/GEdge.cpp
+++ b/Geo/GEdge.cpp
@@ -175,29 +175,14 @@ SPoint2 GEdge::reparamOnFace(const GFace *face, double epar,int dir) const
 
 double GEdge::curvature(double par) const
 {
-  double eps1 = 1.e-5;
-  double eps2 = 1.e-5;
-
-  Range<double> r = parBounds(0);
-  if(r.low() == par) eps2 = 0;
-  if(r.high() == par) eps1 = 0;
-
-  SVector3 n1 = firstDer(par - eps1);
-  SVector3 n2 = firstDer(par + eps2);
-
-  GPoint P1 = point(par - eps1);
-  GPoint P2 = point(par + eps2);
-
-  double D = sqrt ((P1.x() - P2.x()) * (P1.x() - P2.x()) +
-                   (P1.y() - P2.y()) * (P1.y() - P2.y()) +
-                   (P1.z() - P2.z()) * (P1.z() - P2.z()));
+  SVector3 d1 = firstDer(par);
+  SVector3 d2 = secondDer(par);
+  
+  double one_over_norm = 1. / norm(d1);
 
-  n1.normalize();
-  n2.normalize();
-  const double one_over_D = 1. / D;
-  SVector3 d = one_over_D * (n2 - n1);
-  return norm(d);
+  SVector3 cross_prod = crossprod(d1,d2);
   
+  return ( norm(cross_prod) * one_over_norm * one_over_norm * one_over_norm );
 }
 
 double GEdge::length(const double &u0, const double &u1, const int nbQuadPoints)
diff --git a/Geo/GFace.cpp b/Geo/GFace.cpp
index 2d9772dd049f5ab376ad579751768c35eef41560..d715c6f93ebfdde34d5032b0d524f93c16248abf 100644
--- a/Geo/GFace.cpp
+++ b/Geo/GFace.cpp
@@ -14,6 +14,7 @@
 #include "VertexArray.h"
 #include "GmshMatrix.h"
 #include "Numeric.h"
+#include "EigSolve.h"
 
 #if defined(HAVE_GMSH_EMBEDDED)
 #include "GmshEmbedded.h"
@@ -441,7 +442,7 @@ void GFace::getMeanPlaneData(double plan[3][3]) const
       plan[i][j] = meanPlane.plan[i][j];
 }
 
-double GFace::curvature(const SPoint2 &param) const
+double GFace::curvatureDiv(const SPoint2 &param) const
 {
   if (geomType() == Plane) return 0;
 
@@ -449,7 +450,7 @@ double GFace::curvature(const SPoint2 &param) const
   // curv = div n = dnx/dx + dny/dy + dnz/dz
   // dnx/dx = dnx/du du/dx + dnx/dv dv/dx
 
-  const double eps = 1.e-3;
+  const double eps = 1.e-5;
 
   Pair<SVector3,SVector3> der = firstDer(param);
 
@@ -462,20 +463,82 @@ double GFace::curvature(const SPoint2 &param) const
   du.normalize();
   dv.normalize();
 
-  SVector3 n1 = normal(SPoint2(param.x() - eps, param.y()));
-  SVector3 n2 = normal(SPoint2(param.x() + eps, param.y()));
-  SVector3 n3 = normal(SPoint2(param.x(), param.y() - eps));
-  SVector3 n4 = normal(SPoint2(param.x(), param.y() + eps));
+  SVector3 n1,n2,n3,n4;
+  if( param.x() - eps < 0.0 ) {
+    n1 = normal(SPoint2(param.x(),       param.y()));
+    n2 = normal(SPoint2(param.x() + eps, param.y()));
+  } else {
+    n1 = normal(SPoint2(param.x() - eps, param.y()));
+    n2 = normal(SPoint2(param.x(),       param.y()));
+  }
+  if( param.y() - eps < 0.0 ) {
+    n3 = normal(SPoint2(param.x(), param.y()      ));
+    n4 = normal(SPoint2(param.x(), param.y() + eps));
+  } else {
+    n3 = normal(SPoint2(param.x(), param.y() - eps));
+    n4 = normal(SPoint2(param.x(), param.y()      ));
+  }
+
+  SVector3 dndu = 100000 * (n2 - n1);
+  SVector3 dndv = 100000 * (n4 - n3);
 
-  SVector3 dndu = 500 * (n2 - n1);
-  SVector3 dndv = 500 * (n4 - n3);
+  SVector3 dudu = SVector3();
+  SVector3 dvdv = SVector3();
+  SVector3 dudv = SVector3();
+  secondDer(param,&dudu,&dvdv,&dudv);
 
   double ddu = dot(dndu,du);
   double ddv = dot(dndv,dv);
   
-  double c = std::max(fabs(ddu),fabs(ddv))/detJ;
-  // Msg::Info("c = %g detJ %g", c, detJ);
-  return c;
+  return ( fabs(ddu) + fabs(ddv) ) / detJ;
+}
+
+double GFace::curvatureMax(const SPoint2 &param) const
+{
+  if (geomType() == Plane) return 0.;
+
+  double eigVal[2], eigVec[8];
+  getMetricEigenVectors(param, eigVal, eigVec);
+
+  return fabs(eigVal[1]);
+}
+
+double GFace::curvatures(const SPoint2 &param,
+                         SVector3 *dirMax,
+                         SVector3 *dirMin,
+                         double *curvMax,
+                         double *curvMin) const
+{
+  Pair<SVector3,SVector3> D1 = firstDer(param);
+
+  if (geomType() == Plane)
+    {
+      *dirMax = D1.first();
+      *dirMin = D1.second();
+      *curvMax = 0.;
+      *curvMin = 0.;
+      return 0.;
+    }
+
+  if (geomType() == Sphere)
+    {
+      *dirMax = D1.first();
+      *dirMin = D1.second();
+      *curvMax = curvatureDiv(param);
+      *curvMin = *curvMax;
+      return *curvMax;
+    }
+
+  double eigVal[2], eigVec[8];
+  getMetricEigenVectors(param, eigVal, eigVec);
+
+  // curvatures and main directions
+  *curvMax = fabs(eigVal[1]);
+  *curvMin = fabs(eigVal[0]);
+  *dirMax = eigVec[1] * D1.first() + eigVec[3] * D1.second();
+  *dirMin = eigVec[0] * D1.first() + eigVec[2] * D1.second();
+  
+  return *curvMax;
 }
 
 double GFace::getMetricEigenvalue(const SPoint2 &)
@@ -484,6 +547,73 @@ double GFace::getMetricEigenvalue(const SPoint2 &)
   return 0.;
 }
 
+// eigen values are absolute values and sorted from min to max of absolute values
+// eigen vectors are the corresponding COLUMNS of eigVec
+void GFace::getMetricEigenVectors(const SPoint2 &param,
+                                  double eigVal[2],
+                                  double eigVec[4]) const
+{
+  // first derivatives
+  Pair<SVector3,SVector3> D1 = firstDer(param);
+  SVector3 du = D1.first();
+  SVector3 dv = D1.second();
+  SVector3 nor = crossprod(du, dv); nor.normalize();
+
+  // second derivatives
+  SVector3 dudu = SVector3();
+  SVector3 dvdv = SVector3();
+  SVector3 dudv = SVector3();
+  secondDer(param,&dudu,&dvdv,&dudv);
+
+  // first form
+  double form1[2][2];
+  form1[0][0] = normSq(du);
+  form1[1][1] = normSq(dv);
+  form1[0][1] = form1[1][0] = dot(du,dv);
+
+  // second form
+  double form2[2][2];
+  form2[0][0] = dot(nor,dudu);
+  form2[1][1] = dot(nor,dvdv);
+  form2[0][1] = form2[1][0] = dot(nor,dudv);
+
+  // inverse of first form
+  double inv_form1[2][2];
+  double inv_det_form1 = 1. / ( form1[0][0] * form1[1][1] - form1[1][0] * form1[0][1] );
+  inv_form1[0][0] = inv_det_form1 * form1[1][1];
+  inv_form1[1][1] = inv_det_form1 * form1[0][0];
+  inv_form1[1][0] = inv_form1[0][1] = -1 * inv_det_form1 * form1[0][1];
+
+  // N = (inverse of form1) X (form2)
+  double N[4]; // { N00 N01 N10 N11 }
+  N[0] = inv_form1[0][0] * form2[0][0] + inv_form1[0][1] * form2[1][0];
+  N[1] = inv_form1[0][0] * form2[0][1] + inv_form1[0][1] * form2[1][1];
+  N[2] = inv_form1[1][0] * form2[0][0] + inv_form1[1][1] * form2[1][0];
+  N[3] = inv_form1[1][0] * form2[0][1] + inv_form1[1][1] * form2[1][1];
+  
+  // eigen values and vectors of N
+  int work1[2];
+  double work2[2];
+  double eigValI[2];
+  if ( EigSolve(2,2,N,eigVal,eigValI,eigVec,work1,work2) != 1 ) {
+    Msg::Warning("Problem in eigen vectors computation");
+    printf(" N: %f %f %f %f\n",N[0],N[1],N[2],N[3]);
+    printf(" * Eigen values:\n     %f + i * %f\n     %f + i * %f\n",
+           eigVal[0],eigValI[0],eigVal[1],eigValI[1]);
+    printf(" * Eigen vectors (trust it only if eigen values are real):\n");
+    printf("     ( %f, %f ),\n     ( %f, %f ).\n",
+           eigVec[0],eigVec[2],eigVec[1],eigVec[3]);
+    throw;
+  }
+  if ( fabs(eigValI[0]) > 1.e-12 ||  fabs(eigValI[1]) > 1.e-12 ) {
+    Msg::Error("Found imaginary eigenvalues");
+  }
+
+  eigVal[0] = fabs(eigVal[0]);
+  eigVal[1] = fabs(eigVal[1]);
+  EigSort(2, eigVal, eigValI, eigVec);
+}
+
 void GFace::XYZtoUV(const double X, const double Y, const double Z,
                     double &U, double &V, const double relax,
                     const bool onSurface) const
diff --git a/Geo/GFace.h b/Geo/GFace.h
index b1033498a254a1ab97b50b1cfb62f94c2f008624..814bb3db4589678a6b8157577e7fe6ad7307e3a8 100644
--- a/Geo/GFace.h
+++ b/Geo/GFace.h
@@ -128,6 +128,11 @@ class GFace : public GEntity
   // stereographic mappings of the sphere that is used in 2D mesh
   // generation !
   virtual double getMetricEigenvalue(const SPoint2 &);
+  
+  // eigen values are absolute values and sorted from min to max of absolute values
+  // eigen vectors are the COLUMNS of eigVec
+  virtual void getMetricEigenVectors(const SPoint2 &param, 
+                                     double eigVal[2], double eigVec[4]) const;
 
   // return the parmater location on the face given a point in space
   // that is on the face
@@ -145,8 +150,23 @@ class GFace : public GEntity
   // return the first derivate of the face at the parameter location
   virtual Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const = 0;
 
-  // return the curvature i.e. the divergence of the normal
-  virtual double curvature(const SPoint2 &param) const;
+  // compute the second derivates of the face at the parameter location
+  // (default implementation by central differences)
+  // the derivates have to be allocated before calling this function
+  virtual void secondDer(const SPoint2 &param, 
+                         SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const = 0;
+
+  // return the curvature computed as the divergence of the normal
+  virtual double curvatureDiv(const SPoint2 &param) const;
+
+  // return the maximum curvature at a point
+  virtual double curvatureMax(const SPoint2 &param) const;
+
+  // compute the min and max curvatures and the corresponding directions
+  // return the max curvature
+  // outputs have to be allocated before calling this function
+  virtual double curvatures(const SPoint2 &param, SVector3 *dirMax, SVector3 *dirMin,
+                            double *curvMax, double *curvMin) const;
 
   // return a type-specific additional information string
   virtual std::string getAdditionalInfoString();
diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp
index a98014f468ff7d4cc37e98911e8a792f359e38f4..ac25984062206961790560a660b8a7d7384f4a62 100644
--- a/Geo/GFaceCompound.cpp
+++ b/Geo/GFaceCompound.cpp
@@ -559,6 +559,12 @@ Pair<SVector3,SVector3> GFaceCompound::firstDer(const SPoint2 &param) const
   return Pair<SVector3, SVector3>(dXdu,dXdv);
 } 
 
+void GFaceCompound::secondDer(const SPoint2 &param, 
+                              SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const
+{
+  Msg::Error("Computation of the second derivatives not implemented for compound faces");
+}
+
 static void GFaceCompoundBB(void *a, double*mmin, double*mmax)
 {
   GFaceCompoundTriangle *t = (GFaceCompoundTriangle *)a;
diff --git a/Geo/GFaceCompound.h b/Geo/GFaceCompound.h
index d4ce6647aaa219e0a9fdd41e4eab80d68c1b6a50..e1587a3de0451acdb084d63e8ba58450af837b40 100644
--- a/Geo/GFaceCompound.h
+++ b/Geo/GFaceCompound.h
@@ -70,7 +70,8 @@ public:
   virtual ~GFaceCompound();
   Range<double> parBounds(int i) const { return Range<double>(0, 1); } 
   virtual GPoint point(double par1, double par2) const; 
-  virtual Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const; 
+  virtual Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const;
+  virtual void secondDer(const SPoint2 &, SVector3 *, SVector3 *, SVector3 *) const; 
   virtual GEntity::GeomType geomType() const { return CompoundSurface; }
   ModelType getNativeType() const { return GmshModel; }
   void * getNativePtr() const { return 0; }
diff --git a/Geo/GeoInterpolation.cpp b/Geo/GeoInterpolation.cpp
index 3b7f66ad7cc9c30dc67d8734367f2dc32b6c3da1..a43fdf65f65c044e60efc0d479d2430d7668be04 100644
--- a/Geo/GeoInterpolation.cpp
+++ b/Geo/GeoInterpolation.cpp
@@ -601,7 +601,7 @@ static Vertex InterpolateExtrudedSurface(Surface *s, double u, double v)
 
 Vertex InterpolateSurface(Surface *s, double u, double v, int derivee, int u_v)
 {
-  if(derivee) {
+  if( derivee == 1 ) {
     double eps = 1.e-6;
     Vertex D[4];
     if(u_v == 1) {
@@ -629,6 +629,44 @@ Vertex InterpolateSurface(Surface *s, double u, double v, int derivee, int u_v)
                   (D[1].Pos.Z - D[0].Pos.Z) / eps);
   }
 
+  else if ( derivee == 2 ) {
+    double eps = 1.e-6;
+    Vertex D[2];
+    if(u_v == 1) { // dudu
+      if(u - eps < 0.0) {
+        D[0] = InterpolateSurface(s, u, v, 1, 1);
+        D[1] = InterpolateSurface(s, u + eps, v, 1, 1);
+      }
+      else {
+        D[0] = InterpolateSurface(s, u - eps, v, 1, 1);
+        D[1] = InterpolateSurface(s, u, v, 1, 1);
+      }
+    }
+    else if(u_v == 2) { // dvdv
+      if(v - eps < 0.0) {
+        D[0] = InterpolateSurface(s, u, v, 1, 2);
+        D[1] = InterpolateSurface(s, u, v + eps, 1, 2);
+      }
+      else {
+        D[0] = InterpolateSurface(s, u, v - eps, 1, 2);
+        D[1] = InterpolateSurface(s, u, v, 1, 2);
+      }
+    }
+    else { // dudv
+      if(v - eps < 0.0) {
+        D[0] = InterpolateSurface(s, u, v, 1, 1);
+        D[1] = InterpolateSurface(s, u, v + eps, 1, 1);
+      }
+      else {
+        D[0] = InterpolateSurface(s, u, v - eps, 1, 1);
+        D[1] = InterpolateSurface(s, u, v, 1, 1);
+      }
+    }
+    return Vertex((D[1].Pos.X - D[0].Pos.X) / eps,
+                  (D[1].Pos.Y - D[0].Pos.Y) / eps,
+                  (D[1].Pos.Z - D[0].Pos.Z) / eps);
+  }
+
   if(s->geometry){
     SPoint3 p = s->geometry->point(u, v);
     return Vertex(p.x(), p.y(), p.z());
diff --git a/Geo/OCCFace.cpp b/Geo/OCCFace.cpp
index 9fda93d3a9b5c735eaf795e213c23a0a2b84b5ec..bfb3493b3e6037332cb46e96bde1a6f4011f247e 100644
--- a/Geo/OCCFace.cpp
+++ b/Geo/OCCFace.cpp
@@ -122,6 +122,18 @@ Pair<SVector3,SVector3> OCCFace::firstDer(const SPoint2 &param) const
                                  SVector3(dv.X(), dv.Y(), dv.Z()));
 }
 
+void OCCFace::secondDer(const SPoint2 &param,
+                        SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const
+{
+  gp_Pnt pnt;
+  gp_Vec du, dv, duu, dvv, duv;
+  occface->D2(param.x(), param.y(), pnt, du, dv, duu, dvv, duv);
+
+  *dudu = SVector3(duu.X(), duu.Y(), duu.Z());
+  *dvdv = SVector3(dvv.X(), dvv.Y(), dvv.Z());
+  *dudv = SVector3(duv.X(), duv.Y(), duv.Z());
+}
+
 GPoint OCCFace::point(double par1, double par2) const
 {
   double pp[2] = {par1, par2};
@@ -187,7 +199,7 @@ GEntity::GeomType OCCFace::geomType() const
   return Unknown;
 }
 
-double OCCFace::curvature(const SPoint2 &param) const
+double OCCFace::curvatureMax(const SPoint2 &param) const
 {
   const double eps = 1.e-12;
   BRepAdaptor_Surface sf(s, Standard_True);
@@ -200,6 +212,37 @@ double OCCFace::curvature(const SPoint2 &param) const
   return std::max(fabs(prop.MinCurvature()), fabs(prop.MaxCurvature()));
 }
 
+double OCCFace::curvatures(const SPoint2 &param,
+                           SVector3 *dirMax,
+                           SVector3 *dirMin,
+                           double *curvMax,
+                           double *curvMin) const
+{
+  const double eps = 1.e-12;
+  BRepAdaptor_Surface sf(s, Standard_True);
+  BRepLProp_SLProps prop(sf, 2, eps);
+  prop.SetParameters (param.x(),param.y());
+
+  if (!prop.IsCurvatureDefined()){
+    return -1.;
+  }
+
+  *curvMax = std::max(fabs(prop.MinCurvature()), fabs(prop.MaxCurvature()));
+  *curvMin = std::min(fabs(prop.MinCurvature()), fabs(prop.MaxCurvature()));
+
+  gp_Dir dMax = gp_Dir();
+  gp_Dir dMin = gp_Dir();
+  prop.CurvatureDirections(dMax,dMin);
+  (*dirMax)[0] = dMax.X();
+  (*dirMax)[1] = dMax.Y();
+  (*dirMax)[2] = dMax.Z();
+  (*dirMin)[0] = dMin.X();
+  (*dirMin)[1] = dMin.Y();
+  (*dirMin)[2] = dMin.Z();
+
+  return *curvMax;
+}
+
 bool OCCFace::containsPoint(const SPoint3 &pt) const
 { 
   if(geomType() == Plane){
diff --git a/Geo/OCCFace.h b/Geo/OCCFace.h
index e2c38ceea6ad07e07b673d72c8505cb392de16b7..8a7c41fa077c2626441ba639520e7a812f580c28 100644
--- a/Geo/OCCFace.h
+++ b/Geo/OCCFace.h
@@ -30,12 +30,15 @@ class OCCFace : public GFace {
   virtual GPoint closestPoint(const SPoint3 & queryPoint, const double initialGuess[2]) const; 
   virtual bool containsPoint(const SPoint3 &pt) const;  
   virtual SVector3 normal(const SPoint2 &param) const; 
-  virtual Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const; 
+  virtual Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const;
+  virtual void secondDer(const SPoint2 &param, SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const;
   virtual GEntity::GeomType geomType() const; 
   ModelType getNativeType() const { return OpenCascadeModel; }
   void * getNativePtr() const { return (void*)&s; }
   virtual SPoint2 parFromPoint(const SPoint3 &) const;
-  virtual double curvature(const SPoint2 &param) const;
+  virtual double curvatureMax(const SPoint2 &param) const;
+  virtual double curvatures(const SPoint2 &param, SVector3 *dirMax, SVector3 *dirMin,
+                            double *curvMax, double *curvMin) const;
   surface_params getSurfaceParams() const;
 };
 
diff --git a/Geo/OCCVertex.cpp b/Geo/OCCVertex.cpp
index 16f52706f3158962a17bb4386fb67e9b263667fd..2c75f8cbc52d62412171512aecb5c44aa44d14cf 100644
--- a/Geo/OCCVertex.cpp
+++ b/Geo/OCCVertex.cpp
@@ -45,7 +45,7 @@ double max_surf_curvature(const GVertex *gv, double x, double y, double z,
   double curv = 1.e-22;
   while(it != faces.end()){
     SPoint2 par = gv->reparamOnFace((*it), 1);
-    double cc = (*it)->curvature(par);
+    double cc = (*it)->curvatureDiv(par);
     if(cc > 0) curv = std::max(curv, cc);
     ++it;
   }  
diff --git a/Geo/STensor3.h b/Geo/STensor3.h
index 42d5a64f202a9c975b12059e8dfb95737404c8fe..f27143814fb73e7f9eff4c95c43d551a6d731d41 100644
--- a/Geo/STensor3.h
+++ b/Geo/STensor3.h
@@ -89,12 +89,17 @@ class SMetric3 {
     setMat(m3);
     return *this;
   }
-  void eig (gmshMatrix<double> &V, gmshVector<double> &S) {
+  void eig (gmshMatrix<double> &V, gmshVector<double> &S) const {
     gmshMatrix<double> me(3,3),right(3,3);
     gmshVector<double> im(3);
     getMat(me);
     me.eig(V,S,im,right);
   }
+  void print() const {
+    printf("  %f\t%f\t%f\n",_val[0],_val[1],_val[3]);
+    printf("  %f\t%f\t%f\n",_val[1],_val[2],_val[4]);
+    printf("  %f\t%f\t%f\n",_val[3],_val[4],_val[5]);
+  }
 };
 
 // scalar product with respect to the metric
diff --git a/Geo/SVector3.h b/Geo/SVector3.h
index 9102ba2844503565dc1306d7d16e8ac48202c831..149180993587ce740af28f3a16228a17dfac836c 100644
--- a/Geo/SVector3.h
+++ b/Geo/SVector3.h
@@ -7,6 +7,7 @@
 #define _SVECTOR3_H_
 
 #include "SPoint3.h"
+#include <string>
 
 // concrete class for vector of size 3
 class SVector3 {
@@ -21,10 +22,12 @@ class SVector3 {
   SVector3(double x, double y, double z) : P(x, y, z) {}
   SVector3(double v) : P(v, v, v) {}
   SVector3(const double *array) : P(array) {}
+  SVector3(const SVector3& v) : P(v.P) {}
   inline double x(void) const { return P.x(); }
   inline double y(void) const { return P.y(); }
   inline double z(void) const { return P.z(); }
   inline double norm() { return sqrt(P[0] * P[0] + P[1] * P[1] + P[2] * P[2]); }
+  inline double normSq() { return (P[0] * P[0] + P[1] * P[1] + P[2] * P[2]); }
   double normalize() 
   { 
     double n = norm(); if(n){ P[0] /= n; P[1] /= n; P[2] /= n; }
@@ -62,6 +65,8 @@ class SVector3 {
     return *this;
   }
   operator double *() { return P; }
+  void print(std::string name="") const
+  { printf("Vector \'%s\':  %f  %f  %f\n",name.c_str(),P[0],P[1],P[2]); }
 };
 
 inline double dot(const SVector3 &a, const SVector3 &b)
@@ -70,6 +75,9 @@ inline double dot(const SVector3 &a, const SVector3 &b)
 inline double norm(const SVector3 &v)
 { return sqrt(dot(v, v)); }
 
+inline double normSq(const SVector3 &v)
+{ return dot(v, v); }
+
 inline SVector3 crossprod(const SVector3 &a, const SVector3 &b)
 { return SVector3(a.y() * b.z() - b.y() * a.z(), 
                   -(a.x() * b.z() - b.x() * a.z()), 
diff --git a/Geo/discreteFace.cpp b/Geo/discreteFace.cpp
index d6927f745a554858c9fa8b81e6ad261fc6be1f0b..ead70a6610540706030a0e53aecb9ff79d69d9b6 100644
--- a/Geo/discreteFace.cpp
+++ b/Geo/discreteFace.cpp
@@ -100,3 +100,9 @@ Pair<SVector3, SVector3> discreteFace::firstDer(const SPoint2 &param) const
   Msg::Error("Cannot evaluate derivative on discrete face");
   return Pair<SVector3, SVector3>();
 }
+
+void discreteFace::secondDer(const SPoint2 &param, 
+                             SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const
+{
+  Msg::Error("Cannot evaluate derivative on discrete face");
+}
diff --git a/Geo/discreteFace.h b/Geo/discreteFace.h
index bca7f3cac8d39b18e8de1a089096cd945ad6f20d..2e1b4309eafc7da4e46ce3723c8fb86482f144a4 100644
--- a/Geo/discreteFace.h
+++ b/Geo/discreteFace.h
@@ -19,6 +19,8 @@ class discreteFace : public GFace {
   virtual SVector3 normal(const SPoint2 &param) const;
   virtual GEntity::GeomType geomType() const { return DiscreteSurface; }
   virtual Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const;
+  virtual void secondDer(const SPoint2 &param, 
+                         SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const;
   void setBoundEdges( std::vector<discreteEdge*> edges );
 };
 
diff --git a/Geo/fourierFace.cpp b/Geo/fourierFace.cpp
index a564ab9a6aafca0395b78ab044ae13de2a5a031c..4203b1acfff3ae25441845a2a17a6cf1cff4657c 100644
--- a/Geo/fourierFace.cpp
+++ b/Geo/fourierFace.cpp
@@ -71,4 +71,10 @@ Pair<SVector3, SVector3> fourierFace::firstDer(const SPoint2 &param) const
   return Pair<SVector3, SVector3>();
 }
 
+void fourierFace::secondDer(const SPoint2 &param, 
+                            SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const
+{
+  Msg::Error("Computation of the second derivatives not implemented for fourer face");
+}
+
 #endif
diff --git a/Geo/fourierFace.h b/Geo/fourierFace.h
index 09412d30dcaf301faaaad7f78b249b6dbe10e1d9..2c5cfb017167f20fbbde5b72751b73c52f102498 100644
--- a/Geo/fourierFace.h
+++ b/Geo/fourierFace.h
@@ -29,6 +29,7 @@ class fourierFace : public GFace {
   virtual SVector3 normal(const SPoint2 &param) const; 
   virtual GEntity::GeomType geomType() const;
   virtual Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const;
+  virtual void secondDer(const SPoint2 &, SVector3 *, SVector3 *, SVector3 *) const; 
   ModelType getNativeType() const { return FourierModel; }
   void * getNativePtr() const { return face; } 
 };
diff --git a/Geo/gmshFace.cpp b/Geo/gmshFace.cpp
index 3d46a89b6bada39a85124941aa2477fbea8a1665..923e1e87334a50acf7d1e0b1ab4d1da21d3a0239 100644
--- a/Geo/gmshFace.cpp
+++ b/Geo/gmshFace.cpp
@@ -165,6 +165,24 @@ Pair<SVector3,SVector3> gmshFace::firstDer(const SPoint2 &param) const
   }
 }
 
+void gmshFace::secondDer(const SPoint2 &param, 
+                         SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const
+{
+  if(s->Typ == MSH_SURF_PLAN && !s->geometry){
+    *dudu = SVector3(0.,0.,0.);
+    *dvdv = SVector3(0.,0.,0.);
+    *dudv = SVector3(0.,0.,0.);
+  }
+  else{
+    Vertex vuu = InterpolateSurface(s, param[0], param[1], 2, 1);
+    Vertex vvv = InterpolateSurface(s, param[0], param[1], 2, 2);
+    Vertex vuv = InterpolateSurface(s, param[0], param[1], 2, 3);
+    *dudu = SVector3(vuu.Pos.X,vuu.Pos.Y,vuu.Pos.Z);
+    *dvdv = SVector3(vvv.Pos.X,vvv.Pos.Y,vvv.Pos.Z);
+    *dudv = SVector3(vuv.Pos.X,vuv.Pos.Y,vuv.Pos.Z);
+  }
+}
+
 GPoint gmshFace::point(double par1, double par2) const
 {
   double pp[2] = {par1, par2};
diff --git a/Geo/gmshFace.h b/Geo/gmshFace.h
index cd2fb927180c25160956219737993377ba2a682a..c5c1aba83fd7c987cee9478bd9ccade6a4bcf8d9 100644
--- a/Geo/gmshFace.h
+++ b/Geo/gmshFace.h
@@ -26,6 +26,7 @@ class gmshFace : public GFace {
   virtual double getMetricEigenvalue(const SPoint2 &);  
   virtual SVector3 normal(const SPoint2 &param) const; 
   virtual Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const; 
+  virtual void secondDer(const SPoint2 &param, SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const;
   virtual GEntity::GeomType geomType() const; 
   ModelType getNativeType() const { return GmshModel; }
   void * getNativePtr() const { return s; }
diff --git a/Mesh/BDS.cpp b/Mesh/BDS.cpp
index 8e8b718777b6aa92d9965a5e67f64d4992f2cb78..5183002a463138f0dd4b88073c5f70e058b5cbee 100644
--- a/Mesh/BDS.cpp
+++ b/Mesh/BDS.cpp
@@ -55,19 +55,19 @@ void outputScalarField(std::list<BDS_Face*> t, const char *iii, int param, GFace
 		    pts[1]->X, pts[1]->Y, pts[1]->Z,
 		    pts[2]->X, pts[2]->Y, pts[2]->Z,
 		    pts[3]->X, pts[3]->Y, pts[3]->Z,
-		    gf->curvature(SPoint2(pts[0]->u, pts[0]->v)),
-		    gf->curvature(SPoint2(pts[1]->u, pts[1]->v)),	
-		    gf->curvature(SPoint2(pts[2]->u, pts[2]->v)),
-		    gf->curvature(SPoint2(pts[3]->u, pts[3]->v)));
+		    gf->curvatureDiv(SPoint2(pts[0]->u, pts[0]->v)),
+		    gf->curvatureDiv(SPoint2(pts[1]->u, pts[1]->v)),	
+		    gf->curvatureDiv(SPoint2(pts[2]->u, pts[2]->v)),
+		    gf->curvatureDiv(SPoint2(pts[3]->u, pts[3]->v)));
 	  }
 	  else{
 	    fprintf(f, "ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
 		    pts[0]->X, pts[0]->Y, pts[0]->Z,
 		    pts[1]->X, pts[1]->Y, pts[1]->Z,
 		    pts[2]->X, pts[2]->Y, pts[2]->Z,
-		    gf->curvature(SPoint2(pts[0]->u, pts[0]->v)),
-		    gf->curvature(SPoint2(pts[1]->u, pts[1]->v)),
-		    gf->curvature(SPoint2(pts[2]->u, pts[2]->v)));
+		    gf->curvatureDiv(SPoint2(pts[0]->u, pts[0]->v)),
+		    gf->curvatureDiv(SPoint2(pts[1]->u, pts[1]->v)),
+		    gf->curvatureDiv(SPoint2(pts[2]->u, pts[2]->v)));
 	  }
 	}
       }
diff --git a/Mesh/BackgroundMesh.cpp b/Mesh/BackgroundMesh.cpp
index 5cb04d200006b2a8f22ec6f9d502aec77b7d41fe..6e68114106d52f3247775c1f7a18b9f29a1e2bd4 100644
--- a/Mesh/BackgroundMesh.cpp
+++ b/Mesh/BackgroundMesh.cpp
@@ -41,7 +41,7 @@ static double max_surf_curvature(const GEdge *ge, double u)
   std::list<GFace *>::iterator it = faces.begin();
   while(it != faces.end()){
     SPoint2 par = ge->reparamOnFace((*it), u, 1);
-    double cc = (*it)->curvature(par);
+    double cc = (*it)->curvatureDiv(par);
     val = std::max(cc, val);
     ++it;
   }  
@@ -90,7 +90,7 @@ static double LC_MVertex_CURV(GEntity *ge, double U, double V)
   case 2:
     {
       GFace *gf = (GFace *)ge;
-      Crv = gf->curvature(SPoint2(U, V));
+      Crv = gf->curvatureDiv(SPoint2(U, V));
     }
     break;
   }