diff --git a/Common/Gmsh.cpp b/Common/Gmsh.cpp
index b181ec6effaaf2c760458cadd4cdce4fb1d64b1a..e9d281fc03504d83d3f6c0d76232a1047d967a91 100644
--- a/Common/Gmsh.cpp
+++ b/Common/Gmsh.cpp
@@ -45,8 +45,8 @@ int GmshInitialize(int argc, char **argv)
   GMSH_PluginManager::instance()->registerDefaultPlugins();
 #endif
 
-  // Check for buggy obsolete GSL versions
-  check_gsl();
+  // Initialize numeric library (gsl, robust predicates)
+  Init_Numeric();
   return 1;
 }
 
diff --git a/Mesh/BDS.cpp b/Mesh/BDS.cpp
index ede3847246d09b85496378505c22fc9944f6955a..445a327db835e7f2c872359664efd1d1066dfa55 100644
--- a/Mesh/BDS.cpp
+++ b/Mesh/BDS.cpp
@@ -12,9 +12,6 @@
 #include "meshGFaceDelaunayInsertion.h"
 #include "qualityMeasures.h"
 
-bool test_move_point_parametric_triangle(BDS_Point *p, double u, double v, BDS_Face *t);
-bool test_move_point_parametric_quad(BDS_Point *p, double u, double v, BDS_Face *t);
-
 void outputScalarField(std::list<BDS_Face*> t, const char *iii, int param, GFace *gf)
 {
   FILE *f = fopen(iii, "w");
@@ -85,8 +82,8 @@ BDS_Vector::BDS_Vector(const BDS_Point &p2, const BDS_Point &p1)
 {
 }
 
-void vector_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3,
-                     double c[3])
+static void vector_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3,
+                            double c[3])
 {
   double a[3] = {p1->X - p2->X, p1->Y - p2->Y, p1->Z - p2->Z};
   double b[3] = {p1->X - p3->X, p1->Y - p3->Y, p1->Z - p3->Z};
@@ -95,8 +92,8 @@ void vector_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3,
   c[0] = a[1] * b[2] - a[2] * b[1];
 }
 
-void vector_triangle_parametric(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3,
-                                double &c)
+static void vector_triangle_parametric(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3,
+                                       double &c)
 {
   double a[2] = {p1->u - p2->u, p1->v - p2->v};
   double b[2] = {p1->u - p3->u, p1->v - p3->v};
@@ -110,14 +107,14 @@ void normal_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3,
   norme(c);
 }
 
-double surface_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3)
+static double surface_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3)
 {
   double c[3];
   vector_triangle(p1, p2, p3, c);
   return 0.5 * sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2]);
 }
 
-double surface_triangle_param(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3)
+static double surface_triangle_param(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3)
 {
   double c;
   vector_triangle_parametric(p1, p2, p3, c);
@@ -967,6 +964,91 @@ int BDS_Edge::numTriangles() const
   return NT;
 }
 
+// use robust predicates for not allowing to revert a triangle by
+// moving one of its vertices
+
+static bool test_move_point_parametric_quad(BDS_Point *p, double u, double v, BDS_Face *t)
+{       
+  BDS_Point *pts[4];
+  t->getNodes(pts);
+
+  double pa[2] = {pts[0]->u, pts[0]->v};
+  double pb[2] = {pts[1]->u, pts[1]->v};
+  double pc[2] = {pts[2]->u, pts[2]->v};
+  double pd[2] = {pts[3]->u, pts[3]->v};
+
+  double ori_init1 = gmsh::orient2d(pa, pb, pc);
+  double ori_init2 = gmsh::orient2d(pc, pd, pa);
+
+  if(p == pts[0]){ 
+    pa[0] = u; 
+    pa[1] = v; 
+  }
+  else if(p == pts[1]){
+    pb[0] = u;
+    pb[1] = v;
+  }
+  else if(p == pts[2]){
+    pc[0] = u;
+    pc[1] = v;
+  }
+  else if(p == pts[3]){
+    pd[0] = u;
+    pd[1] = v;
+  }
+  else{
+    Msg::Error("Something wrong in move_point_parametric_quad");
+    return false;
+  }
+  
+  double ori_final1 = gmsh::orient2d(pa, pb, pc);
+  double ori_final2 = gmsh::orient2d(pc, pd, pa);
+  // allow to move a point when a triangle was flat
+  return ori_init1*ori_final1 > 0 && ori_init2*ori_final2 > 0 ;
+}
+
+static bool test_move_point_parametric_triangle(BDS_Point *p, double u, double v, BDS_Face *t)
+{       
+  if (t->e4)
+    return test_move_point_parametric_quad(p,u,v,t);
+  BDS_Point *pts[4];
+  t->getNodes(pts);
+
+  double pa[2] = {pts[0]->u, pts[0]->v};
+  double pb[2] = {pts[1]->u, pts[1]->v};
+  double pc[2] = {pts[2]->u, pts[2]->v};
+
+  double a[2] = {pb[0] - pa[0], pb[1] - pa[1]};
+  double b[2] = {pc[0] - pa[0], pc[1] - pa[1]};
+
+  double area_init = fabs(a[0] * b[1] - a[1] * b[0]);
+
+  if(area_init == 0.0) return true;
+
+  double ori_init = gmsh::orient2d(pa, pb, pc);
+
+  if(p == pts[0]){ 
+    pa[0] = u; 
+    pa[1] = v; 
+  }
+  else if(p == pts[1]){
+    pb[0] = u;
+    pb[1] = v;
+  }
+  else if(p == pts[2]){
+    pc[0] = u;
+    pc[1] = v;
+  }
+  else
+    return false;
+  
+  double area_final = fabs(a[0] * b[1] - a[1] * b[0]);
+  if(area_final < 0.1 * area_init) return false;
+  double ori_final = gmsh::orient2d(pa, pb, pc);
+  // allow to move a point when a triangle was flat
+  return ori_init*ori_final > 0;
+}
+
 bool BDS_Mesh::collapse_edge_parametric(BDS_Edge *e, BDS_Point *p)
 {
   if(e->numfaces() != 2)
@@ -1069,186 +1151,6 @@ bool BDS_Mesh::collapse_edge_parametric(BDS_Edge *e, BDS_Point *p)
   return true;
 }
 
-// use robust predicates for not allowing to revert a triangle by
-// moving one of its vertices
-
-bool test_move_point_parametric_triangle(BDS_Point *p, double u, double v, BDS_Face *t)
-{       
-  if (t->e4)
-    return test_move_point_parametric_quad(p,u,v,t);
-  BDS_Point *pts[4];
-  t->getNodes(pts);
-
-  double pa[2] = {pts[0]->u, pts[0]->v};
-  double pb[2] = {pts[1]->u, pts[1]->v};
-  double pc[2] = {pts[2]->u, pts[2]->v};
-
-  double a[2] = {pb[0] - pa[0], pb[1] - pa[1]};
-  double b[2] = {pc[0] - pa[0], pc[1] - pa[1]};
-
-  double area_init = fabs(a[0] * b[1] - a[1] * b[0]);
-
-  if(area_init == 0.0) return true;
-
-  double ori_init = gmsh::orient2d(pa, pb, pc);
-
-  if(p == pts[0]){ 
-    pa[0] = u; 
-    pa[1] = v; 
-  }
-  else if(p == pts[1]){
-    pb[0] = u;
-    pb[1] = v;
-  }
-  else if(p == pts[2]){
-    pc[0] = u;
-    pc[1] = v;
-  }
-  else
-    return false;
-  
-  double area_final = fabs(a[0] * b[1] - a[1] * b[0]);
-  if(area_final < 0.1 * area_init) return false;
-  double ori_final = gmsh::orient2d(pa, pb, pc);
-  // allow to move a point when a triangle was flat
-  return ori_init*ori_final > 0;
-}
-
-bool test_move_point_parametric_quad(BDS_Point *p, double u, double v, BDS_Face *t)
-{       
-  BDS_Point *pts[4];
-  t->getNodes(pts);
-
-  double pa[2] = {pts[0]->u, pts[0]->v};
-  double pb[2] = {pts[1]->u, pts[1]->v};
-  double pc[2] = {pts[2]->u, pts[2]->v};
-  double pd[2] = {pts[3]->u, pts[3]->v};
-
-  double ori_init1 = gmsh::orient2d(pa, pb, pc);
-  double ori_init2 = gmsh::orient2d(pc, pd, pa);
-
-  if(p == pts[0]){ 
-    pa[0] = u; 
-    pa[1] = v; 
-  }
-  else if(p == pts[1]){
-    pb[0] = u;
-    pb[1] = v;
-  }
-  else if(p == pts[2]){
-    pc[0] = u;
-    pc[1] = v;
-  }
-  else if(p == pts[3]){
-    pd[0] = u;
-    pd[1] = v;
-  }
-  else{
-    Msg::Error("Something wrong in move_point_parametric_quad");
-    return false;
-  }
-  
-  double ori_final1 = gmsh::orient2d(pa, pb, pc);
-  double ori_final2 = gmsh::orient2d(pc, pd, pa);
-  // allow to move a point when a triangle was flat
-  return ori_init1*ori_final1 > 0 && ori_init2*ori_final2 > 0 ;
-}
-
-// d^2_i = (x^2_i - x)^T M (x_i - x)  
-//       = M11 (x_i - x)^2 + 2 M21 (x_i-x)(y_i-y) + M22 (y_i-y)^2        
-
-struct smoothVertexData{
-  BDS_Point *p;
-  GFace *gf;
-  double scalu, scalv;
-  std::list<BDS_Face*> ts;
-}; 
-
-double smoothing_objective_function(double U, double V, BDS_Point *v, 
-                                    std::list<BDS_Face*> &ts, double su, double sv,
-                                    GFace *gf)
-{
-  GPoint gp = gf->point(U * su, V * sv);
-
-  const double oldX = v->X;
-  const double oldY = v->Y;
-  const double oldZ = v->Z;
-  v->X = gp.x();
-  v->Y = gp.y();
-  v->Z = gp.z();
-
-  std::list<BDS_Face*>::iterator it = ts.begin();
-  std::list<BDS_Face*>::iterator ite = ts.end();
-  double qMin = 1.;
-  while(it != ite) {
-    BDS_Face *t = *it;
-    qMin = std::min(qmTriangle(*it, QMTRI_RHO), qMin);
-    ++it;
-  }
-  v->X = oldX;
-  v->Y = oldY;
-  v->Z = oldZ;
-  return -qMin;  
-}
-
-void deriv_smoothing_objective_function(double U, double V, 
-                                        double &F, double &dFdU, double &dFdV,
-                                        void *data)
-{
-  smoothVertexData *svd = (smoothVertexData*)data;
-  BDS_Point *v = svd->p;
-  const double LARGE = 1.e5;
-  const double SMALL = 1./LARGE;
-  F = smoothing_objective_function(U, V, v, svd->ts, 
-                                   svd->scalu, svd->scalv, svd->gf);
-  double F_U = smoothing_objective_function(U + SMALL, V, v, svd->ts, 
-                                            svd->scalu, svd->scalv, svd->gf);
-  double F_V = smoothing_objective_function(U, V + SMALL, v, svd->ts,
-                                            svd->scalu, svd->scalv, svd->gf);
-  dFdU = (F_U - F) * LARGE;
-  dFdV = (F_V - F) * LARGE;
-}
-
-double smooth_obj(double U, double V, void *data)
-{
-  smoothVertexData *svd = (smoothVertexData*)data;
-  return smoothing_objective_function(U, V, svd->p, svd->ts,
-                                      svd->scalu, svd->scalv, svd->gf); 
-}
-
-void optimize_vertex_position(GFace *GF, BDS_Point *data, double su, double sv)
-{
-  if(data->g && data->g->classif_degree <= 1) return;
-  smoothVertexData vd;
-  vd.p = data;
-  vd.scalu = su;
-  vd.scalv = sv;
-  vd.gf = GF;
-  data->getTriangles(vd.ts);
-  double U = data->u, V = data->v, val;
-
-  val = smooth_obj(U, V, &vd);
-  if(val < -.90) return;
-
-  minimize_2(smooth_obj, deriv_smoothing_objective_function, &vd, 5, U,V,val);
-  std::list<BDS_Face*>::iterator it = vd.ts.begin();
-  std::list<BDS_Face*>::iterator ite = vd.ts.end();
-  while(it != ite) {
-    BDS_Face *t = *it;
-    if(!test_move_point_parametric_triangle(data, U, V, t)){
-      return;          
-    }
-    ++it;
-  }
-  
-  data->u = U;
-  data->v = V;
-  GPoint gp = GF->point(U * su, V * sv);
-  data->X = gp.x();
-  data->Y = gp.y();
-  data->Z = gp.z();  
-}
-
 bool BDS_Mesh::smooth_point_centroid(BDS_Point *p, GFace *gf, bool test_quality)
 {
   if(!p->config_modified) return false;
diff --git a/Mesh/BDS.h b/Mesh/BDS.h
index ca16a8c848155b5951688aa4aa3148e24eef11b9..e8ba1572ac7ee5448b7888cabe5c14e58167ece2 100644
--- a/Mesh/BDS.h
+++ b/Mesh/BDS.h
@@ -28,17 +28,6 @@ class GFace;
 class GEdge;
 class GVertex;
 
-void vector_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3, double c[3]); 
-void normal_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3, double c[3]); 
-double surface_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3); 
-double surface_triangle_param(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3); 
-void optimize_vertex_position(GFace *GF, BDS_Point *data, double su, double sv);
-void swap_config(BDS_Edge *e, 
-                 BDS_Point **p11, BDS_Point **p12, BDS_Point **p13,
-                 BDS_Point **p21, BDS_Point **p22, BDS_Point **p23,
-                 BDS_Point **p31, BDS_Point **p32, BDS_Point **p33,
-                 BDS_Point **p41, BDS_Point **p42, BDS_Point **p43);
-
 class BDS_GeomEntity
 {
 public:
@@ -468,6 +457,12 @@ class BDS_Mesh
   void cleanup();
 };
 
+void normal_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3, double c[3]); 
+void swap_config(BDS_Edge *e, 
+                 BDS_Point **p11, BDS_Point **p12, BDS_Point **p13,
+                 BDS_Point **p21, BDS_Point **p22, BDS_Point **p23,
+                 BDS_Point **p31, BDS_Point **p32, BDS_Point **p33,
+                 BDS_Point **p41, BDS_Point **p42, BDS_Point **p43);
 void outputScalarField(std::list<BDS_Face*> t, const char *fn, int param, GFace *gf=0);
 void recur_tag(BDS_Face *t, BDS_GeomEntity *g);
 int Intersect_Edges_2d(double x1, double y1, double x2, double y2,
diff --git a/Mesh/gmshSmoothHighOrder.cpp b/Mesh/gmshSmoothHighOrder.cpp
index 5aa4e049fc03bfdde81374001c94609f992806aa..e5ea84bcb15879546b83da5e2edc36422a615bad 100644
--- a/Mesh/gmshSmoothHighOrder.cpp
+++ b/Mesh/gmshSmoothHighOrder.cpp
@@ -380,10 +380,9 @@ void optimizeNodeLocations(GFace *gf, smoothVertexDataHON &vdN, double eps = .2)
   double F = -smooth_obj_HighOrderN(uv, &vdN);
   if (F < eps){
     double val;
-    minimize_N(2 * vdN.v.size(), 
-               smooth_obj_HighOrderN, 
+    minimize_N(2 * vdN.v.size(), smooth_obj_HighOrderN, 
                deriv_smoothing_objective_function_HighOrderN, 
-               &vdN, 1, uv,val);
+               &vdN, 1, uv, val);
     double Fafter = -smooth_obj_HighOrderN(uv, &vdN);
     printf("%12.5E %12.5E\n", F, Fafter);
     if (F < Fafter){
@@ -399,20 +398,18 @@ void optimizeNodeLocations(GFace *gf, smoothVertexDataHON &vdN, double eps = .2)
   }
 }
 
-double angle3Points ( MVertex *p1, MVertex *p2, MVertex *p3 )
+double angle3Points(MVertex *p1, MVertex *p2, MVertex *p3)
 {
-  SVector3 a(p1->x()-p2->x(),p1->y()-p2->y(),p1->z()-p2->z());
-  SVector3 b(p3->x()-p2->x(),p3->y()-p2->y(),p3->z()-p2->z());
-  SVector3 c = crossprod(a,b);
+  SVector3 a(p1->x() - p2->x(), p1->y() - p2->y(), p1->z() - p2->z());
+  SVector3 b(p3->x() - p2->x(), p3->y() - p2->y(), p3->z() - p2->z());
+  SVector3 c = crossprod(a, b);
   double sinA = c.norm();
-  double cosA = dot(a,b);
+  double cosA = dot(a, b);
   //  printf("%d %d %d -> %g %g\n",p1->iD,p2->iD,p3->iD,cosA,sinA);
-  return atan2 (sinA,cosA);  
+  return atan2 (sinA, cosA);  
 }
 
-/*
-A curvilinear edge smooth and swap
-*/
+// A curvilinear edge smooth and swap
 
 typedef std::map<std::pair<MVertex*, MVertex*>, std::vector<MElement*> > edge2tris;
 
@@ -517,47 +514,7 @@ bool optimizeHighOrderMesh(GFace *gf, edgeContainer &edgeVertices)
       e2t[p].push_back(t);
     }
   }
-  /*
-  v2t_cont :: iterator it = adjv.begin();      
-  while (it != adjv.end()){
-    MVertex *ver= it->first;
-    GEntity *ge = ver->onWhat();
-    if (ge->dim() == 2){
-      double initu,initv;
-      ver->getParameter(0, initu);
-      ver->getParameter(1, initv);        
-
-      smoothVertexDataHON vdN;
-      vdN.ts = it->second;
-      for (int i=0;i<vdN.ts.size();i++){
-        MTriangle *t = vdN.ts[i];
-      }
 
-      vdN.v = e;
-      vdN.gf = gf;
-
-      double val;      
-      double F = -smooth_obj_HighOrder(initu,initv, &vd);
-      if (F < .2){
-        minimize_2(smooth_obj_HighOrder, 
-             deriv_smoothing_objective_function_HighOrder, &vd, 1, initu,initv,val);
-        double Fafter = -smooth_obj_HighOrder(initu,initv, &vd);
-        if (F < Fafter){
-          success = true;
-          ver->setParameter(0,initu);
-          ver->setParameter(1,initv);
-          GPoint gp = gf->point(initu,initv);
-          ver->x() = gp.x();
-          ver->y() = gp.y();
-          ver->z() = gp.z();  
-        }
-      }                         
-    }
-    ++it;
-  }
-  */
-  bool success = false;
-  
   for(edge2tris::iterator it = e2t.begin(); it != e2t.end(); ++it){
     std::pair<MVertex*, MVertex*> edge = it->first;
     std::vector<MVertex*> e;
@@ -584,7 +541,7 @@ bool optimizeHighOrderMesh(GFace *gf, edgeContainer &edgeVertices)
     }
   }
 
-  return success;
+  return true;
 }
 
 static void parametricCoordinates(MVertex *v, GFace *gf, double &uu, double &vv)
diff --git a/Mesh/meshGRegionLocalMeshMod.cpp b/Mesh/meshGRegionLocalMeshMod.cpp
index 2dddd409d2367acc1586bb20eb3aee40ab95d757..9f2623bf81decec21248eca4f12e18226aacd137 100644
--- a/Mesh/meshGRegionLocalMeshMod.cpp
+++ b/Mesh/meshGRegionLocalMeshMod.cpp
@@ -142,7 +142,6 @@ void BuildSwapPattern4(SwapPattern *sc)
   sc->trianguls = trgul ;
 }
 
-
 void BuildSwapPattern5(SwapPattern *sc)
 {
   static int trgl[][3] = 
@@ -202,10 +201,10 @@ void BuildSwapPattern7(SwapPattern *sc)
   sc->trianguls = trgul ;
 }
 
-bool gmshEdgeSwap (std::vector<MTet4 *> &newTets,
-                   MTet4 *tet, 
-                   int iLocalEdge,
-                   const gmshQualityMeasure4Tet &cr)
+bool gmshEdgeSwap(std::vector<MTet4 *> &newTets,
+                  MTet4 *tet, 
+                  int iLocalEdge,
+                  const gmshQualityMeasure4Tet &cr)
 {
   std::vector<MTet4*> cavity;
   std::vector<MTet4*> outside;
@@ -753,28 +752,29 @@ double smoothing_objective_function_3D(double X, double Y, double Z,
   return -qMin;  
 }
 
-void deriv_smoothing_objective_function_3D(double X, double Y, double Z, 
-                                           double &F, 
-                                           double &dFdX, double &dFdY, double &dFdZ,
-                                           void *data)
+void deriv_smoothing_objective_function_3D(double *XYZ, double *dF,
+                                           double &F, void *data)
 {
   smoothVertexData3D *svd = (smoothVertexData3D*)data;
   MVertex *v = svd->v;
-  const double LARGE = svd->LC*1.e5;
-  const double SMALL = 1./LARGE;
-  F = smoothing_objective_function_3D(X, Y, Z, v, svd->ts);
-  double F_X = smoothing_objective_function_3D(X + SMALL, Y, Z, v, svd->ts);
-  double F_Y = smoothing_objective_function_3D(X, Y + SMALL, Z, v, svd->ts);
-  double F_Z = smoothing_objective_function_3D(X, Y, Z + SMALL, v, svd->ts);
-  dFdX = (F_X - F) * LARGE;
-  dFdY = (F_Y - F) * LARGE;
-  dFdZ = (F_Z - F) * LARGE;
+  const double LARGE = svd->LC * 1.e5;
+  const double SMALL = 1. / LARGE;
+  F = smoothing_objective_function_3D(XYZ[0], XYZ[1], XYZ[2], v, svd->ts);
+  double F_X = smoothing_objective_function_3D
+    (XYZ[0] + SMALL, XYZ[1], XYZ[2], v, svd->ts);
+  double F_Y = smoothing_objective_function_3D
+    (XYZ[0], XYZ[1] + SMALL, XYZ[2], v, svd->ts);
+  double F_Z = smoothing_objective_function_3D
+    (XYZ[0], XYZ[1], XYZ[2] + SMALL, v, svd->ts);
+  dF[0] = (F_X - F) * LARGE;
+  dF[1] = (F_Y - F) * LARGE;
+  dF[2] = (F_Z - F) * LARGE;
 }
 
-double smooth_obj_3D(double X, double Y, double Z, void *data)
+double smooth_obj_3D(double *XYZ, void *data)
 {
   smoothVertexData3D *svd = (smoothVertexData3D*)data;
-  return smoothing_objective_function_3D(X, Y, Z, svd->v, svd->ts); 
+  return smoothing_objective_function_3D(XYZ[0], XYZ[1], XYZ[2], svd->v, svd->ts); 
 }
 
 bool gmshSmoothVertexOptimize(MTet4 *t, 
@@ -789,13 +789,11 @@ bool gmshSmoothVertexOptimize(MTet4 *t,
   vd.LC = 1.0; // WRONG
   gmshBuildVertexCavity_recur(t, t->tet()->getVertex(iVertex), vd.ts);
 
-  double xopti = vd.v->x();
-  double yopti = vd.v->y();
-  double zopti = vd.v->z();
+  double xyzopti[3] = {vd.v->x(), vd.v->y(), vd.v->z()};
 
   double val;
-  minimize_3(smooth_obj_3D, deriv_smoothing_objective_function_3D, &vd, 4,
-             xopti, yopti, zopti, val);
+  minimize_N(3, smooth_obj_3D, deriv_smoothing_objective_function_3D, &vd, 4,
+             xyzopti, val);
 
   double vTot = 0;
 
@@ -810,9 +808,9 @@ bool gmshSmoothVertexOptimize(MTet4 *t,
   double y = t->tet()->getVertex(iVertex)->y();
   double z = t->tet()->getVertex(iVertex)->z();
 
-  t->tet()->getVertex(iVertex)->x() = xopti;
-  t->tet()->getVertex(iVertex)->y() = yopti;
-  t->tet()->getVertex(iVertex)->z() = zopti;
+  t->tet()->getVertex(iVertex)->x() = xyzopti[0];
+  t->tet()->getVertex(iVertex)->y() = xyzopti[1];
+  t->tet()->getVertex(iVertex)->z() = xyzopti[2];
 
   double newQuals[2000];
   if(vd.ts.size() >= 2000){
diff --git a/Numeric/GmshMatrix.h b/Numeric/GmshMatrix.h
index dc72f506634934aa03a6f2dfe4f41bcc4467a320..5a359830021e7fe5319e9b409676dc92264ffebb 100644
--- a/Numeric/GmshMatrix.h
+++ b/Numeric/GmshMatrix.h
@@ -12,26 +12,22 @@
 
 #if defined(HAVE_BLAS)
 extern "C" {
-  void dgemm_(const char *transa, const char *transb,
-              int *l, int *n, int *m, double *alpha, 
-              const void *a, int *lda, void *b, int *ldb, 
-              double *beta, void *c, int *ldc);
-  void dgemv_(const char *trans, int *m, int *n, double *alpha,
-              void *a, int *lda, void *x, int *incx,
-              double *beta, void *y, int *incy);
+  void dgemm_(const char *transa, const char *transb, int *m, int *n, int *k, 
+              double *alpha, double *a, int *lda, double *b, int *ldb, 
+              double *beta, double *c, int *ldc);
+  void dgemv_(const char *trans, int *m, int *n, double *alpha, double *a, 
+              int *lda, double *x, int *incx, double *beta, double *y, int *incy);
 }
 #endif
 
 #if defined(HAVE_LAPACK)
 extern "C" {
-  void dgesv_(const int *N, const int *nrhs, double *A, const int *lda, 
-              int *ipiv, double *b, const int *ldb, int *info);
-  void dgetrf_(const int *M, const int *N, double *A, const int *lda, 
-               int *ipiv, int *info);
-  void dgesvd_(const char* jobu, const char *jobvt, const int *M, const int *N,
-               double *A, const int *lda, double *S, double* U, const int *ldu,
-               double *VT, const int *ldvt, double *work, const int *lwork, 
-               const int *info);
+  void dgesv_(int *N, int *nrhs, double *A, int *lda, int *ipiv, 
+              double *b, int *ldb, int *info);
+  void dgetrf_(int *M, int *N, double *A, int *lda, int *ipiv, int *info);
+  void dgesvd_(const char* jobu, const char *jobvt, int *M, int *N,
+               double *A, int *lda, double *S, double* U, int *ldu,
+               double *VT, int *ldvt, double *work, int *lwork, int *info);
 }
 #endif
 
@@ -132,11 +128,12 @@ class Gmsh_Matrix
   }
   inline void mult(const Gmsh_Matrix<SCALAR> &b, Gmsh_Matrix<SCALAR> &c)
   {
-#if 0 // defined(HAVE_BLAS)
-    void dgemm_(const char *transa, const char *transb,
-                int *l, int *n, int *m, double *alpha, 
-                const void *a, int *lda, void *b, int *ldb, 
-                double *beta, void *c, int *ldc);
+#if defined(HAVE_BLAS)
+    int M = c.size1(), N = c.size2(), K = _c;
+    int LDA = _r, LDB = b.size1(), LDC = c.size1();
+    double alpha = 1., beta = 0.;
+    dgemm_("N", "N", &M, &N, &K, &alpha, _data, &LDA, b._data, &LDB, 
+           &beta, c._data, &LDC);
 #else
     c.scale(0.);
     for(int i = 0; i < _r; i++)
@@ -145,19 +142,19 @@ class Gmsh_Matrix
 	  c._data[i + _r * j] += (*this)(i, k) * b(k, j);
 #endif
   }
-  inline void blas_dgemm(const Gmsh_Matrix<SCALAR> &b, Gmsh_Matrix<SCALAR> &c, 
-			 const SCALAR alpha=1., const SCALAR beta=1.)
+  inline void blas_dgemm(Gmsh_Matrix<SCALAR> &a, Gmsh_Matrix<SCALAR> &b, 
+			 SCALAR alpha=1., SCALAR beta=1.)
   {
-#if 0 // defined(HAVE_BLAS)
-    void dgemm_(const char *transa, const char *transb,
-                int *l, int *n, int *m, double *alpha, 
-                const void *a, int *lda, void *b, int *ldb, 
-                double *beta, void *c, int *ldc);
+#if defined(HAVE_BLAS)
+    int M = size1(), N = size2(), K = a.size2();
+    int LDA = a.size1(), LDB = b.size1(), LDC = size1();
+    dgemm_("N", "N", &M, &N, &K, &alpha, a._data, &LDA, b._data, &LDB, 
+           &beta, _data, &LDC);
 #else
-    Gmsh_Matrix<SCALAR> temp(b.size1(), c.size2());
-    temp.mult(b, c);
-    scale(beta);
+    Gmsh_Matrix<SCALAR> temp(a.size1(), b.size2());
+    a.mult(b, temp);
     temp.scale(alpha);
+    scale(beta);
     add(temp);
 #endif
   }
@@ -184,10 +181,11 @@ class Gmsh_Matrix
   }
   inline void mult(const Gmsh_Vector<SCALAR> &x, Gmsh_Vector<SCALAR> &y)
   {
-#if 0 //defined(HAVE_BLAS)
-  void dgemv_(const char *trans, int *m, int *n, double *alpha,
-              void *a, int *lda, void *x, int *incx,
-              double *beta, void *y, int *incy);
+#if defined(HAVE_BLAS)
+    int M = _r, N = _c, LDA = _r, INCX = 1, INCY = 1;
+    double alpha = 1., beta = 0.;
+    dgemv_("N", &M, &N, &alpha, _data, &LDA, x._data, &INCX,
+           &beta, y._data, &INCY);
 #else
     y.scale(0.);
     for(int i = 0; i < _r; i++)
@@ -362,10 +360,10 @@ class GSL_Matrix
   {
     gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1., _data, b._data, 0., c._data);
   }
-  inline void blas_dgemm(const GSL_Matrix &x, GSL_Matrix &b, 
-			 const double alpha=1., const double beta=1.)
+  inline void blas_dgemm(GSL_Matrix &a, GSL_Matrix &b, 
+			 double alpha=1., double beta=1.)
   {      
-    gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, alpha, x._data, b._data, beta, _data);
+    gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, alpha, a._data, b._data, beta, _data);
   }
   inline void set_all(const double &m) 
   {
@@ -384,9 +382,9 @@ class GSL_Matrix
   {
     gsl_matrix_add(_data, m._data);
   }
-  inline void mult(const GSL_Vector &x, GSL_Vector &b)
+  inline void mult(const GSL_Vector &x, GSL_Vector &y)
   {
-    gsl_blas_dgemv(CblasNoTrans, 1., _data, x._data, 0., b._data);
+    gsl_blas_dgemv(CblasNoTrans, 1., _data, x._data, 0., y._data);
   }
   inline GSL_Matrix transpose()
   {
diff --git a/Numeric/Numeric.cpp b/Numeric/Numeric.cpp
index 35b4256978912cfdfdfb54727ddc0d2ebcaa02f0..b6f63a77f10823e3cd49280fe46809feca377c80 100644
--- a/Numeric/Numeric.cpp
+++ b/Numeric/Numeric.cpp
@@ -26,7 +26,7 @@ void my_gsl_msg(const char *reason, const char *file, int line,
   Msg::Error("GSL: %s (%s, line %d)", reason, file, line);
 }
 
-int check_gsl()
+int Init_Numeric()
 {
   // set new error handler
   gsl_set_error_handler(&my_gsl_msg);
@@ -143,7 +143,7 @@ double brent(double ax, double bx, double cx,
   b = gsl_min_fminimizer_x_minimum(s);
 
   if(status != GSL_SUCCESS)
-    Msg::Error("minimization did not converge: f(%g) = %g", b, fn1(b, NULL));
+    Msg::Error("Minimization did not converge: f(%g) = %g", b, fn1(b, NULL));
   
   *xmin = b;
   gsl_min_fminimizer_free(s);
@@ -235,194 +235,29 @@ void newt(double x[], int n, int *check,
   gsl_vector_free(xx);
 }
 
-static double (*f_stat) (double, double, void *data); 
-static void (*df_stat) (double, double, double &, double &, double &, void *data);
-static double (*f_stat3) (double, double, double, void *data); 
-static void (*df_stat3) (double, double, double, double &, double &, 
-                         double &, double &,void *data);
 static double (*f_statN) (double*, void *data); 
-static void (*df_statN) (double*, double *, double &,void *data);
 
-static double fobj(const gsl_vector * x, void * data)
-{
-  double u, v;
-  u = gsl_vector_get(x, 0);
-  v = gsl_vector_get(x, 1);
-  return f_stat(u, v, data);
-}
-
-static double fobj3(const gsl_vector * x, void * data)
-{
-  double u, v,w;
-  u = gsl_vector_get(x, 0);
-  v = gsl_vector_get(x, 1);
-  w = gsl_vector_get(x, 2);
-  return f_stat3(u, v, w, data);
-}
+static void (*df_statN) (double*, double*, double &, void *data);
 
-static double fobjN (const gsl_vector * x, void * data)
+static double fobjN (const gsl_vector *x, void *data)
 {
   return f_statN(x->data, data);
 }
 
-static void dfobj (const gsl_vector * x, void * params, gsl_vector * g)
-{
-  double u, v, f, duf, dvf;
-  u = gsl_vector_get(x, 0);
-  v = gsl_vector_get(x, 1);
-  df_stat(u, v, f, duf, dvf, params);
-  gsl_vector_set(g, 0, duf);
-  gsl_vector_set(g, 1, dvf);
-}
-
-static void dfobj3 (const gsl_vector * x, void * params, gsl_vector * g)
-{
-  double u, v, w,f, duf, dvf,dwf;
-  u = gsl_vector_get(x, 0);
-  v = gsl_vector_get(x, 1);
-  w = gsl_vector_get(x, 2);
-  df_stat3(u, v, w, f, duf, dvf, dwf, params);
-  gsl_vector_set(g, 0, duf);
-  gsl_vector_set(g, 1, dvf);
-  gsl_vector_set(g, 2, dwf);
-}
-
-static void dfobjN(const gsl_vector * x, void * params, gsl_vector * g)
+static void dfobjN(const gsl_vector *x, void *params, gsl_vector *g)
 {
   double f;
-  df_statN(x->data, g->data,f,params);
+  df_statN(x->data, g->data, f, params);
 }
 
-static void fdfobj(const gsl_vector * x, void * params, double * f, gsl_vector * g)
+static void fdfobjN(const gsl_vector *x, void *params, double *f, gsl_vector *g)
 {
-  double u, v, duf, dvf;
-  u = gsl_vector_get(x, 0);
-  v = gsl_vector_get(x, 1);
-  df_stat(u, v, *f, duf, dvf, params);
-  gsl_vector_set(g, 0, duf);
-  gsl_vector_set(g, 1, dvf);
+  df_statN(x->data, g->data, *f, params);
 }
 
-static void fdfobj3(const gsl_vector * x, void * params, double * f, gsl_vector * g)
-{
-  double u, v, w,duf, dvf,dwf;
-  u = gsl_vector_get(x, 0);
-  v = gsl_vector_get(x, 1);
-  w = gsl_vector_get(x, 2);
-  df_stat3(u, v, w, *f, duf, dvf, dwf, params);
-  gsl_vector_set(g, 0, duf);
-  gsl_vector_set(g, 1, dvf);
-  gsl_vector_set(g, 2, dwf);
-}
-
-static void fdfobjN(const gsl_vector * x, void * params, double * f, gsl_vector * g)
-{
-  df_statN(x->data,g->data,*f,params);
-}
-
-void minimize_2(double (*f) (double, double, void *data), 
-                void (*df) (double, double, double &, double &, double &, void *data) ,
-                void *data,int niter,
-                double &U, double &V, double &res)
-{
-  f_stat = f;
-  df_stat = df;
-
-  int iter = 0;
-  int status;
-  
-  const gsl_multimin_fdfminimizer_type *T;
-  gsl_multimin_fdfminimizer *s;
-  gsl_vector *x;
-  gsl_multimin_function_fdf my_func;
-
-  my_func.f = &fobj;
-  my_func.df = &dfobj;
-  my_func.fdf = &fdfobj;
-  my_func.n = 2;
-  my_func.params = data;
-
-  x = gsl_vector_alloc (2);
-  gsl_vector_set (x, 0, U);
-  gsl_vector_set (x, 1, V);
-
-  T = gsl_multimin_fdfminimizer_conjugate_fr;
-  s = gsl_multimin_fdfminimizer_alloc (T, 2);
-
-  gsl_multimin_fdfminimizer_set(s, &my_func, x, 0.01, 1e-4);
-
-  do{
-    iter++;
-    status = gsl_multimin_fdfminimizer_iterate(s);
-    if(status)
-      break;
-    status = gsl_multimin_test_gradient(s->gradient, 1e-3);
-  }
-  while (status == GSL_CONTINUE && iter < niter);
-
-  U = gsl_vector_get(s->x, 0);
-  V = gsl_vector_get(s->x, 1);
-  res = s->f;
-  gsl_multimin_fdfminimizer_free (s);
-  gsl_vector_free (x);
-}                                           
-
-void minimize_3(double (*f) (double, double, double,void *data), 
-                void (*df) (double  , double  , double , 
-                            double &, double &, double &, double &,
-                            void *data) ,
-                void *data,int niter,
-                double &U, double &V, double &W, double &res)
-{
-  f_stat3 = f;
-  df_stat3 = df;
-  
-  int iter = 0;
-  int status;
-  
-  const gsl_multimin_fdfminimizer_type *T;
-  gsl_multimin_fdfminimizer *s;
-  gsl_vector *x;
-  gsl_multimin_function_fdf my_func;
-
-  my_func.f = &fobj3;
-  my_func.df = &dfobj3;
-  my_func.fdf = &fdfobj3;
-  my_func.n = 3;
-  my_func.params = data;
-
-  x = gsl_vector_alloc (3);
-  gsl_vector_set(x, 0, U);
-  gsl_vector_set(x, 1, V);
-  gsl_vector_set(x, 2, W);
-
-  T = gsl_multimin_fdfminimizer_conjugate_fr;
-  s = gsl_multimin_fdfminimizer_alloc(T, 3);
-
-  gsl_multimin_fdfminimizer_set (s, &my_func, x, 0.01, 1e-4);
-  
-  do{
-    iter++;
-    status = gsl_multimin_fdfminimizer_iterate (s);
-    if (status)
-      break;
-    status = gsl_multimin_test_gradient (s->gradient, 1e-3);
-  }
-  while (status == GSL_CONTINUE && iter < niter);
-
-  U = gsl_vector_get (s->x, 0);
-  V = gsl_vector_get (s->x, 1);
-  W = gsl_vector_get (s->x, 2);
-  res = s->f;
-  gsl_multimin_fdfminimizer_free (s);
-  gsl_vector_free (x);
-}                                           
-
-void minimize_N(int N, 
-                double (*f) (double*,void *data), 
-                void (*df)  (double*,double*,double &,void *data) ,
-                void *data,int niter,
-                double *U, double &res)
+void minimize_N(int N, double (*f)(double*, void *data), 
+                void (*df)(double*, double*, double &, void *data),
+                void *data, int niter, double *U, double &res)
 {
   f_statN = f;
   df_statN = df;
@@ -441,38 +276,37 @@ void minimize_N(int N,
   my_func.n = N;
   my_func.params = data;
 
-  x = gsl_vector_alloc (N);
-  for (int i=0;i<N;i++)
-    gsl_vector_set (x, i, U[i]);
+  x = gsl_vector_alloc(N);
+  for (int i = 0; i < N; i++)
+    gsl_vector_set(x, i, U[i]);
 
   T = gsl_multimin_fdfminimizer_conjugate_fr;
-  s = gsl_multimin_fdfminimizer_alloc (T, N);
+  s = gsl_multimin_fdfminimizer_alloc(T, N);
 
-  gsl_multimin_fdfminimizer_set (s, &my_func, x, 0.01, 1e-4);
+  gsl_multimin_fdfminimizer_set(s, &my_func, x, 0.01, 1e-4);
 
   do{
     iter++;
-    status = gsl_multimin_fdfminimizer_iterate (s);
+    status = gsl_multimin_fdfminimizer_iterate(s);
     
     if (status)
       break;
     
-    status = gsl_multimin_test_gradient (s->gradient, 1e-3);
+    status = gsl_multimin_test_gradient(s->gradient, 1e-3);
   }
   while (status == GSL_CONTINUE && iter < niter);
   
-  for (int i=0;i<N;i++)
-    U[i] = gsl_vector_get (s->x, i);
+  for (int i = 0; i < N; i++)
+    U[i] = gsl_vector_get(s->x, i);
   res = s->f;
-  gsl_multimin_fdfminimizer_free (s);
-  gsl_vector_free (x);
+  gsl_multimin_fdfminimizer_free(s);
+  gsl_vector_free(x);
 }                                           
 
 #else
 
-int check_gsl()
+int Init_Numeric()
 {
-  // initilize robust geometric predicates
   gmsh::exactinit() ;
   return 1;
 }
@@ -489,23 +323,6 @@ void newt(double x[], int n, int *check,
   Msg::Error("Gmsh must be compiled with GSL support for newt");
 }
 
-void minimize_2(double (*f) (double, double, void *data), 
-                void (*df) (double, double, double &, double &, double &, void *data) ,
-                void *data,int niter,
-                double &U, double &V, double &res)
-{
-  Msg::Error("Gmsh must be compiled with GSL support for minimize_2");
-}
-
-void minimize_3(double (*f) (double, double, double, void *data), 
-                void (*df) (double, double, double , double &, double &, 
-                            double &, double &, void *data) ,
-                void *data,int niter,
-                double &U, double &V, double &W, double &res)
-{
-  Msg::Error("Gmsh must be compiled with GSL support for minimize_3");
-}
-
 void minimize_N(int N, double (*f) (double*, void *data), 
                 void (*df) (double*, double*, double &, void *data) ,
                 void *data,int niter,
diff --git a/Numeric/Numeric.h b/Numeric/Numeric.h
index 4dc536ba36853c274213c25ed8d5be8ac83736c9..7d3b29e374305f4eb4795decc701d0f21242bb7d 100644
--- a/Numeric/Numeric.h
+++ b/Numeric/Numeric.h
@@ -8,20 +8,11 @@
 
 #include "NumericEmbedded.h"
 
-int check_gsl();
+int Init_Numeric();
 double brent(double ax, double bx, double cx,
              double (*f) (double), double tol, double *xmin);
 void newt(double x[], int n, int *check,
           void (*func) (int, double[], double[]));
-void minimize_2(double (*f) (double, double, void *data), 
-                void (*df) (double, double, double &, double &, double &, void *data),
-                void *data,int niter,
-                double &U, double &V, double &res);
-void minimize_3(double (*f) (double, double, double, void *data), 
-                void (*df) (double, double, double , double &, double &, 
-                            double &, double &, void *data),
-                void *data,int niter,
-                double &U, double &V, double &W, double &res);
 void minimize_N(int N, double (*f) (double*, void *data), 
                 void (*df) (double*, double*, double &, void *data),
                 void *data,int niter,
diff --git a/configure b/configure
index 6b661cfdcce59e7edc2e31e6f2fd104e7356a323..7735f0be9b289ccaa119cb2429a3ad659fc2674b 100755
--- a/configure
+++ b/configure
@@ -576,7 +576,7 @@ PACKAGE_VERSION=
 PACKAGE_STRING=
 PACKAGE_BUGREPORT=
 
-ac_unique_file="Parser/Gmsh.y"
+ac_unique_file="Geo/GModel.h"
 # Factoring default headers for most tests.
 ac_includes_default="\
 #include <stdio.h>
@@ -5254,8 +5254,6 @@ fi
 echo "${ECHO_T}$ac_cv_lib_fftw3_main" >&6; }
 if test $ac_cv_lib_fftw3_main = yes; then
   FFTW3="yes"
-else
-  FFTW3="no"
 fi
 
     if test "x${FFTW3}" != "xyes"; then
diff --git a/configure.in b/configure.in
index 3f7eb290f4ffcc5b60e19ed8c04ad2104f6456c5..8e7e30ffe543b9424ba219b6a342c609946b39af 100644
--- a/configure.in
+++ b/configure.in
@@ -5,12 +5,8 @@ dnl bugs and problems to <gmsh@geuz.org>.
 
 dnl Process this file with autoconf to produce the configure script.
 
-dnl Note: each CHECK_LIB adds the found library to LIBS, which serves
-dnl implicitly when checking for the next one. So one should check
-dnl in reverse order! (start with -lm, ...)
-
 dnl Check that this is the gmsh source tree
-AC_INIT(Parser/Gmsh.y)
+AC_INIT(Geo/GModel.h)
 
 dnl Parse '--with' command-line options
 AC_ARG_WITH(fltk-prefix,
@@ -679,7 +675,7 @@ if test "x$enable_fm" != "xno"; then
     if test "x${FFTW3_PREFIX}" != "x"; then
       LDFLAGS="-L${FFTW3_PREFIX}/lib ${LDFLAGS}"
     fi
-    AC_CHECK_LIB(fftw3,main,FFTW3="yes",FFTW3="no")
+    AC_CHECK_LIB(fftw3,main,FFTW3="yes")
     if test "x${FFTW3}" != "xyes"; then
       FM=no
       AC_MSG_WARN([Could not find FFTW3: disabling FourierModel.])