diff --git a/Common/OpenFile.cpp b/Common/OpenFile.cpp
index 387ae02d0bdb2257408b0e62db8c90b6d1e97e8e..887740cbd529ccf5b1955137faabcc648fc9da72 100644
--- a/Common/OpenFile.cpp
+++ b/Common/OpenFile.cpp
@@ -362,7 +362,7 @@ int MergeFile(std::string fileName, bool warnIfMissing)
         GModel* tmp2 = GModel::current();
         GModel* tmp = new GModel();
         tmp->readMSH(fileName);
-        GeomMeshMatcher::instance()->match(tmp2, tmp);
+        status = GeomMeshMatcher::instance()->match(tmp2, tmp);
         delete tmp;
       } else
 	status = GModel::current()->readMSH(fileName);
diff --git a/Geo/GFace.cpp b/Geo/GFace.cpp
index 9eda7e6c0a91eb57b3a92207f8b6ff256c6453d6..2aac4d62041ee378e27f35eec6335a9b1a5efeff 100644
--- a/Geo/GFace.cpp
+++ b/Geo/GFace.cpp
@@ -22,8 +22,27 @@
 #include "meshGFaceOptimize.h"
 #include "meshGFaceLloyd.h"
 
+#if defined(HAVE_BFGS)
+#include "stdafx.h"
+#include "optimization.h"
+#endif
+
 #define SQU(a)      ((a)*(a))
 
+class data_wrapper{
+ private:
+  const GFace* gf;
+  SPoint3 point;
+ public:
+  data_wrapper() {gf = NULL; point = SPoint3();}
+  ~data_wrapper() {}
+  const GFace* get_face() {return gf;}
+  void set_face(const GFace* face) {gf = face;}
+  SPoint3 get_point() {return point;}
+  void set_point(SPoint3 _point) {point = SPoint3(_point);}
+};
+
+
 GFace::GFace(GModel *model, int tag)
   : GEntity(model, tag), r1(0), r2(0), compound(0), va_geom_triangles(0)
 {
@@ -906,11 +925,113 @@ SPoint2 GFace::parFromPoint(const SPoint3 &p, bool onSurface) const
   return SPoint2(U, V);
 }
 
+#if defined(QUASINEWTON)
+// Callback function for BFGS
+void bfgs_callback(const alglib::real_1d_array& x, double& func, alglib::real_1d_array& grad, void* ptr) {
+  data_wrapper* w = static_cast<data_wrapper*>(ptr);
+  SPoint3 p = w->get_point();
+  const GFace* gf = w->get_face();
+
+  // Value of the objective
+  GPoint pnt = gf->point(x[0], x[1]);
+  SPoint3 spnt(pnt.x(), pnt.y(), pnt.z());
+  func = p.distance(spnt);
+  //printf("func : %f\n", func);
+
+  // Value of the gradient
+  std::vector<double> values(2);
+  Pair<SVector3, SVector3> der = gf->firstDer(SPoint2(x[0], x[1]));
+  grad[0] = -2./(2.0*func) * (der.left().x() + der.left().y() + der.left().z());
+  grad[1] = -2./(2.0*func) * (der.right().x() + der.right().y() + der.right().z());
+  //printf("Gradients %f %f\n", grad[0], grad[1]);
+}
+#endif
+
 GPoint GFace::closestPoint(const SPoint3 &queryPoint, const double initialGuess[2]) const
 {
+#if defined(QUASINEWTON)
+
+  //
+  // Creating the optimisation problem
+  //
+  alglib::ae_int_t dim = 2;
+  alglib::ae_int_t corr = 2; // Num of corrections in the scheme in [3,7] 
+  alglib::minlbfgsstate state;
+  alglib::real_1d_array x; // = "[0.5,0.5]";
+  std::vector<double> initial_conditions(dim);
+
+  double min_dist = 1e18;
+  double min_u = 0.5;
+  double min_v = 0.5;
+
+  Range<double> uu = parBounds(0);
+  Range<double> vv = parBounds(1);
+
+  double initial_guesses = 1000.0;
+  for(double u = uu.low(); u<=uu.high(); u+=(uu.high()-uu.low())/initial_guesses) {
+    printf("%f\n", u);
+    for(double v = vv.low(); v<=vv.high(); v+=(vv.high()-vv.low())/initial_guesses) {
+      GPoint pnt = point(u, v);
+      printf("(point) : %f %f %f\n", pnt.x(), pnt.y(), pnt.z());
+      SPoint3 spnt(pnt.x(), pnt.y(), pnt.z());
+      double dist = queryPoint.distance(spnt);
+      if (dist < min_dist) {
+	printf("min_dist %f\n", dist);
+	min_dist = dist;
+	min_u = u;
+	min_v = v;
+	GPoint pnt = point(min_u, min_v);
+      }
+    }
+  }
+
+  initial_conditions[0] = min_u;
+  initial_conditions[1] = min_v;
+
+  printf("Initial conditions : %f %f\n", min_u, min_v);
+  GPoint pnt = point(min_u, min_v);
+  printf("Initial conditions (point) : %f %f %f\n", pnt.x(), pnt.y(), pnt.z());
+
+  x.setcontent(dim, &initial_conditions[0]);
+
+
+
+
+  minlbfgscreate(2, corr, x, state);
+
+  //
+  // Defining the stopping criterion
+  //
+  double epsg = 0.0;
+  double epsf = 0.0;
+  double epsx = 0.0;
+  alglib::ae_int_t maxits = 500;
+
+  minlbfgssetcond(state,epsg,epsf,epsx,maxits);
+
+  //
+  // Solving the problem
+  //
+
+  data_wrapper w;
+  w.set_point(queryPoint);
+  w.set_face(this);
+
+  minlbfgsoptimize(state,bfgs_callback,NULL,&w);
+
+  //
+  // Getting the results
+  //
+  alglib::minlbfgsreport rep;
+
+  minlbfgsresults(state,x,rep);
+
+  return point(x[0],x[1]);
+#else
   Msg::Error("Closest point not implemented for this type of surface");
   SPoint2 p = parFromPoint(queryPoint, false);
   return point(p);
+#endif
 }
 
 bool GFace::containsParam(const SPoint2 &pt) const
diff --git a/Geo/GeoInterpolation.cpp b/Geo/GeoInterpolation.cpp
index 5f4b827b5d8464e8bd8b0bc39476a31c290b463a..93dca7bc3396ce42dbe74d78e0fa48fe21c991e2 100644
--- a/Geo/GeoInterpolation.cpp
+++ b/Geo/GeoInterpolation.cpp
@@ -295,6 +295,9 @@ Vertex InterpolateCurve(Curve *c, double u, int derivee)
   switch (c->Typ) {
 
   case MSH_SEGM_LINE:
+#if defined(QUASINEWTON)
+    printf("MSH_SEGM_LINE\n");
+#endif
     N = List_Nbr(c->Control_Points);
     i = (int)((double)(N - 1) * u);
     while(i >= N - 1)
@@ -415,6 +418,10 @@ Vertex InterpolateCurve(Curve *c, double u, int derivee)
     break;
 
   case MSH_SEGM_DISCRETE:
+#if defined(QUASINEWTON)
+    printf("MSH_SEGM_DISCRETE\n");
+#endif
+
     Msg::Debug("Cannot interpolate discrete curve");
     break;
 
@@ -448,6 +455,9 @@ static Vertex TransfiniteQua(Vertex c1, Vertex c2, Vertex c3, Vertex c4,
                      s1.Pos.Y, s2.Pos.Y, s3.Pos.Y, s4.Pos.Y, u, v);
   V.Pos.Z = TRAN_QUA(c1.Pos.Z, c2.Pos.Z, c3.Pos.Z, c4.Pos.Z,
                      s1.Pos.Z, s2.Pos.Z, s3.Pos.Z, s4.Pos.Z, u, v);
+  //printf("TRANQUA %f %f %f %f %f %f %f %f\n", c1.Pos.Z, c2.Pos.Z, c3.Pos.Z, c4.Pos.Z,
+  //                   s1.Pos.Z, s2.Pos.Z, s3.Pos.Z, s4.Pos.Z);
+  //printf("V.Pos.Z %f\n", V.Pos.Z);
   return (V);
 }
 
@@ -592,6 +602,17 @@ static Vertex InterpolateRuledSurface(Surface *s, double u, double v)
     V[1] = InterpolateCurve(C[1], C[1]->ubeg + (C[1]->uend - C[1]->ubeg) * v, 0);
     V[2] = InterpolateCurve(C[2], C[2]->ubeg + (C[2]->uend - C[2]->ubeg) * (1. - u), 0);
     V[3] = InterpolateCurve(C[3], C[3]->ubeg + (C[3]->uend - C[3]->ubeg) * (1. - v), 0);
+#if defined(QUASINEWTON)
+    printf("----- u %f v %f\n", u, v);
+    printf("S[0] %f %f %f\n", S[0]->Pos.X, S[0]->Pos.Y,S[0]->Pos.Z);
+    printf("S[1] %f %f %f\n", S[1]->Pos.X, S[1]->Pos.Y,S[1]->Pos.Z);
+    printf("S[2] %f %f %f\n", S[2]->Pos.X, S[2]->Pos.Y,S[2]->Pos.Z);
+    printf("S[3] %f %f %f\n", S[3]->Pos.X, S[3]->Pos.Y,S[3]->Pos.Z);
+    printf("V[0] %f %f %f\n", V[0].Pos.X, V[0].Pos.Y,V[0].Pos.Z);
+    printf("V[1] %f %f %f\n", V[1].Pos.X, V[1].Pos.Y,V[1].Pos.Z);
+    printf("V[2] %f %f %f\n", V[2].Pos.X, V[2].Pos.Y,V[2].Pos.Z);
+    printf("V[3] %f %f %f\n", V[3].Pos.X, V[3].Pos.Y,V[3].Pos.Z);
+#endif
     T = TransfiniteQua(V[0], V[1], V[2], V[3], *S[0], *S[1], *S[2], *S[3], u, v);
     if(isSphere) TransfiniteSph(*S[0], *O, &T);
   }
diff --git a/Geo/GeomMeshMatcher.cpp b/Geo/GeomMeshMatcher.cpp
index b56dfcb6b7d20c9375dd2df7511ef1719e1ff36b..07258e90aa688808a256fda75987ec8bfd80a2cb 100644
--- a/Geo/GeomMeshMatcher.cpp
+++ b/Geo/GeomMeshMatcher.cpp
@@ -155,7 +155,7 @@ GeomMeshMatcher::matchVertices(GModel* m1, GModel *m2, bool& ok)
     //m2->add(*vert);
 
   Msg::Info("Vertices matched : %i / %i (%i)\n", num_matched_vertices, num_total_vertices, num_mesh_vertices);
-  if(num_matched_vertices != num_total_vertices) ok = false;
+  //if(num_matched_vertices != num_total_vertices) ok = false;
   return (coresp_v);
 }
 
@@ -225,16 +225,17 @@ GeomMeshMatcher::matchEdges(GModel* m1, GModel* m2,
     choice->setTag(((GEdge*) *entity1)->tag());
 
     // This reverses the edge if it's not parametrized in the right direction
+/*
     if (choice->getBeginVertex() == findMatching<GVertex*>(*coresp_v,v2) &&
         choice->getEndVertex() == findMatching<GVertex*>(*coresp_v,v1)) {
       Msg::Info("Wrong parametrization direction, reversing.");
       choice->reverse();
     }
-
-    for (unsigned int v = 0; v < ((GEdge*) choice)->getNumMeshVertices(); v++) {
+*/
+    /*for (unsigned int v = 0; v < ((GEdge*) choice)->getNumMeshVertices(); v++) {
       if (((GEdge*) choice)->getMeshVertex(v)->onWhat()->dim() > 0)
 	((GEdge*) choice)->getMeshVertex(v)->setEntity((GEdge*) *entity1);
-    }
+    }*/
     num_matched_edges++;
   }
 
@@ -301,10 +302,10 @@ GeomMeshMatcher:: matchFaces(GModel* m1, GModel* m2,
     coresp_f->push_back(Pair<GFace*,GFace*>((GFace*) *entity1 ,
                                              choice));
     choice->setTag(((GFace*) *entity1)->tag());
-    for (unsigned int v = 0; v < ((GFace*) choice)->getNumMeshVertices(); v++) {
+    /*for (unsigned int v = 0; v < ((GFace*) choice)->getNumMeshVertices(); v++) {
       if(((GFace*) choice)->getMeshVertex(v)->onWhat()->dim() > 1)
 	((GFace*) choice)->getMeshVertex(v)->setEntity((GFace*) *entity1);
-    }
+    }*/
 
     num_matched_faces++;
   }
@@ -400,10 +401,10 @@ GeomMeshMatcher::matchRegions(GModel* m1, GModel* m2,
                                              choice));
        choice->setTag(((GRegion*) *entity1)->tag());
 
-    for (unsigned int v = 0; v < ((GRegion*) choice)->getNumMeshVertices(); v++) {
-      if ( ((GRegion*) choice)->getMeshVertex(v)->onWhat()->dim() > 2)
-	((GRegion*) choice)->getMeshVertex(v)->setEntity((GRegion*) *entity1);
-    }
+    //for (unsigned int v = 0; v < ((GRegion*) choice)->getNumMeshVertices(); v++) {
+    //  if ( ((GRegion*) choice)->getMeshVertex(v)->onWhat()->dim() > 2)
+    //    ((GRegion*) choice)->getMeshVertex(v)->setEntity((GRegion*) *entity1);
+    //}
        num_matched_regions++;
     }
   }
@@ -597,6 +598,7 @@ int GeomMeshMatcher::forceTomatch(GModel *geom, GModel *mesh, const double TOL)
 
 static void copy_vertices (GVertex *to, GVertex *from, std::map<MVertex*,MVertex*> &_mesh_to_geom){
   if (from) {
+    to->deleteMesh();
     for (int i=0;i<from->mesh_vertices.size();i++){
       MVertex *v_from = from->mesh_vertices[i];
       MVertex *v_to = new MVertex (v_from->x(),v_from->y(),v_from->z(), to);
@@ -614,19 +616,25 @@ static void copy_vertices (GRegion *to, GRegion *from, std::map<MVertex*,MVertex
   }
 }
 static void copy_vertices (GEdge *to, GEdge *from, std::map<MVertex*,MVertex*> &_mesh_to_geom){
+  to->deleteMesh();
   for (int i=0;i<from->mesh_vertices.size();i++){
     MVertex *v_from = from->mesh_vertices[i];
-    double t = to->parFromPoint ( SPoint3(v_from->x(),v_from->y(),v_from->z() ) );
+    double t;
+    GPoint gp = to->closestPoint(SPoint3(v_from->x(),v_from->y(),v_from->z()), t );
     MEdgeVertex *v_to = new MEdgeVertex (v_from->x(),v_from->y(),v_from->z(), to, t );
     to->mesh_vertices.push_back(v_to);
     _mesh_to_geom[v_from] = v_to;
   }
 }
 static void copy_vertices (GFace *to, GFace *from, std::map<MVertex*,MVertex*> &_mesh_to_geom){
+  printf("Starting Face %d, with %d vertices\n", to->tag(),  from->mesh_vertices.size());
   for (int i=0;i<from->mesh_vertices.size();i++){
     MVertex *v_from = from->mesh_vertices[i];
-    SPoint2 uv = to->parFromPoint ( SPoint3(v_from->x(),v_from->y(),v_from->z() ) );
-    MFaceVertex *v_to = new MFaceVertex (v_from->x(),v_from->y(),v_from->z(), to, uv.x(),uv.y() );
+    double uv[2];
+    GPoint gp = to->closestPoint ( SPoint3(v_from->x(),v_from->y(),v_from->z()), uv );
+    printf("Original point %f %f %f\n", v_from->x(), v_from->y(), v_from->z());
+    printf("New point %f %f %f\n", gp.x(), gp.y(), gp.z());
+    MFaceVertex *v_to = new MFaceVertex (v_from->x(),v_from->y(),v_from->z(), to, uv[0],uv[1] );
     to->mesh_vertices.push_back(v_to);
     _mesh_to_geom[v_from] = v_to;
   }
@@ -635,12 +643,14 @@ static void copy_vertices (GFace *to, GFace *from, std::map<MVertex*,MVertex*> &
 template <class ELEMENT>
 static void copy_elements (std::vector<ELEMENT*> &to, std::vector<ELEMENT*> &from, std::map<MVertex*,MVertex*> &_mesh_to_geom){
   MElementFactory toto;
-  for (int i=0;i < to.size();i++){
+  to.clear();
+  for (int i=0;i < from.size();i++){
     ELEMENT *e = from[i];
     std::vector<MVertex*> nodes;
-    for(int j=0;j<e->getNumVertices();j++)
+    for(int j=0;j<e->getNumVertices();j++) {
       nodes.push_back(_mesh_to_geom[e->getVertex(j)]);
-    to.push_back( (ELEMENT*)(toto.create(e->getType(), nodes) ));
+    }
+    to.push_back( (ELEMENT*)(toto.create(e->getTypeForMSH(), nodes) ));
   }
 }
 
@@ -693,7 +703,6 @@ int GeomMeshMatcher::match(GModel *geom, GModel *mesh)
         //std::vector<Pair<GRegion*, GRegion*> >* coresp_r =
         matchRegions(geom, mesh, coresp_f,ok);
         if (ok) {
-          //mesh->writeMSH("out.msh",2.0,false,true);
 	  std::map<MVertex*,MVertex*> _mesh_to_geom;
 	  copy_vertices(geom, mesh, _mesh_to_geom);
 	  copy_elements(geom, mesh, _mesh_to_geom);
diff --git a/Geo/gmshFace.cpp b/Geo/gmshFace.cpp
index caca1f867ef1383a34031c1e7b87e5862229e871..9943da7498c3456c5febc45e059d22d381083da5 100644
--- a/Geo/gmshFace.cpp
+++ b/Geo/gmshFace.cpp
@@ -217,6 +217,7 @@ GPoint gmshFace::point(double par1, double par2) const
   }
 }
 
+#if not defined(QUASINEWTON)
 GPoint gmshFace::closestPoint(const SPoint3 & qp, const double initialGuess[2]) const
 {
   if (s->Typ == MSH_SURF_PLAN && !s->geometry){
@@ -257,6 +258,7 @@ GPoint gmshFace::closestPoint(const SPoint3 & qp, const double initialGuess[2])
     return GPoint(-1.e22, -1.e22, -1.e22, 0, u);
   return GPoint(v.Pos.X, v.Pos.Y, v.Pos.Z, this, u);
 }
+#endif
 
 SPoint2 gmshFace::parFromPoint(const SPoint3 &qp, bool onSurface) const
 {
diff --git a/Geo/gmshFace.h b/Geo/gmshFace.h
index a0d1666c3c6e134e75708540f47bd36b2fd1ad98..67d0a3ce357f7d79b1d9cf7dbfa76a0e49882c6f 100644
--- a/Geo/gmshFace.h
+++ b/Geo/gmshFace.h
@@ -21,9 +21,11 @@ class gmshFace : public GFace {
   virtual ~gmshFace(){}
   Range<double> parBounds(int i) const; 
   void setModelEdges(std::list<GEdge*> &);
-  virtual GPoint point(double par1, double par2) const; 
+  virtual GPoint point(double par1, double par2) const;
+#if not defined(QUASINEWTON)
   virtual GPoint closestPoint(const SPoint3 &queryPoint, 
                               const double initialGuess[2]) const; 
+#endif
   virtual bool containsPoint(const SPoint3 &pt) const;  
   virtual double getMetricEigenvalue(const SPoint2 &);  
   virtual SVector3 normal(const SPoint2 &param) const;