diff --git a/CMakeLists.txt b/CMakeLists.txt
index 49910df4771d8d951551a61d54a82c9967c8c469..1ccfa7725264c3f4bd49ce53ab2354b9284ba573 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -96,7 +96,8 @@ set(GMSH_API
     Geo/SVector3.h Geo/STensor3.h Geo/SBoundingBox3d.h Geo/Pair.h Geo/Range.h 
     Geo/SOrientedBoundingBox.h Geo/CellComplex.h Geo/ChainComplex.h Geo/Cell.h
     Geo/Homology.h Geo/Chain.h Geo/partitionEdge.h Geo/CGNSOptions.h Geo/gmshLevelset.h
-  Mesh/meshGEdge.h Mesh/meshGFace.h Mesh/meshGFaceOptimize.h Mesh/meshPartition.h
+  Mesh/meshGEdge.h Mesh/meshGFace.h Mesh/meshGFaceOptimize.h
+  Mesh/MeshGFaceElliptic.h Mesh/meshPartition.h
     Mesh/meshGFaceDelaunayInsertion.h Mesh/simple3D.h Mesh/meshPartitionOptions.h 
     Mesh/directions3D.h Mesh/Voronoi3D.h Mesh/Levy3D.h Mesh/periodical.h
   Numeric/mathEvaluator.h
diff --git a/Mesh/CMakeLists.txt b/Mesh/CMakeLists.txt
index bb03a19a771ddf0b048ed2bc29cbba2c7fed1ca0..d216d4f2dbed417d322117b70c9d6e3a2c7af768 100644
--- a/Mesh/CMakeLists.txt
+++ b/Mesh/CMakeLists.txt
@@ -8,6 +8,7 @@ set(SRC
     meshGEdge.cpp 
       meshGEdgeExtruded.cpp
     meshGFace.cpp 
+    meshGFaceElliptic.cpp
       meshGFaceTransfinite.cpp meshGFaceExtruded.cpp 
       meshGFaceBamg.cpp meshGFaceBDS.cpp meshGFaceDelaunayInsertion.cpp 
       meshGFaceLloyd.cpp meshGFaceOptimize.cpp 
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index 5937c0c2d76cf364ecc8357ab9b9d2a14e4dd6a2..e5d2d9329cff7b87005f2e5a0aeebd37ff8a94ac 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -25,6 +25,7 @@
 #include "MTriangle.h"
 #include "MQuadrangle.h"
 #include "CenterlineField.h"
+#include "meshGFaceElliptic.h"
 #include "Context.h"
 #include "GPoint.h"
 #include "GmshMessage.h"
@@ -43,10 +44,6 @@
 #include "multiscalePartition.h"
 #include "meshGFaceLloyd.h"
 #include "meshGFaceBoundaryLayers.h"
-#if defined(HAVE_ANN)
-#include <ANN/ANN.h>
-#endif
-
 
 static void copyMesh(GFace *source, GFace *target)
 {
@@ -1643,6 +1640,7 @@ static void createRegularTwoCircleGrid (Centerline *center, GFace *gf)
 #endif;
 }
 
+>>>>>>> .r12521
 static bool meshGeneratorElliptic(GFace *gf, bool debug = true)
 {
 #if defined(HAVE_ANN)
@@ -1658,10 +1656,10 @@ static bool meshGeneratorElliptic(GFace *gf, bool debug = true)
   //printf(" nbBounds = %d  (face %d) \n", nbBoundaries, gf->tag());
 
   if (center && recombine && nbBoundaries == 2) {
-    printf("need for elliptic grid generator \n");
-    createRegularTwoCircleGrid(center, gf);
+    printf("--> need for elliptic grid generator \n");
+    bool success  = createRegularTwoCircleGrid(center, gf);
     //solveElliptic();
-    return true;
+    return success;
   }
   else return false;
 
@@ -2108,9 +2106,10 @@ void meshGFace::operator() (GFace *gf, bool print)
   Msg::Debug("Generating the mesh");
 
   if(meshGeneratorElliptic(gf)){
-    printf("elliptic grid generator for face %d  \n", gf->tag());
+    printf("--> elliptic grid generator for face %d done \n", gf->tag());
+    //return;
   }
-  //else if
+
   if ((gf->getNativeType() != GEntity::AcisModel ||
        (!gf->periodic(0) && !gf->periodic(1))) &&
       (noSeam(gf) || gf->getNativeType() == GEntity::GmshModel ||
diff --git a/Mesh/meshGFaceElliptic.cpp b/Mesh/meshGFaceElliptic.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9ac94b28829d8b900cd814dbfcdf315b963feb91
--- /dev/null
+++ b/Mesh/meshGFaceElliptic.cpp
@@ -0,0 +1,534 @@
+// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#include <stack>
+#include "GmshConfig.h"
+#include "meshGFaceElliptic.h"
+#include "qualityMeasures.h"
+#include "GFace.h"
+#include "GEdge.h"
+#include "GEdgeCompound.h"
+#include "GVertex.h"
+#include "GModel.h"
+#include "MVertex.h"
+#include "MTriangle.h"
+#include "MQuadrangle.h"
+#include "MLine.h"
+#include "BackgroundMesh.h"
+#include "Numeric.h"
+#include "GmshMessage.h"
+#include "Generator.h"
+#include "Context.h"
+#include "OS.h"
+#include "SVector3.h"
+#include "SPoint3.h"
+#include "fullMatrix.h"
+#include "CenterlineField.h"
+#if defined(HAVE_ANN)
+#include <ANN/ANN.h>
+#endif
+
+#define TRAN_QUAD(c1,c2,c3,c4,s1,s2,s3,s4,u,v) \
+    (1.-u)*c4+u*c2+(1.-v)*c1+v*c3-((1.-u)*(1.-v)*s1+u*(1.-v)*s2+u*v*s3+(1.-u)*v*s4)
+
+
+static void printQuads(GFace *gf, fullMatrix<SPoint2> uv, std::vector<MQuadrangle*> quads,  int iter){
+
+  char name[234];
+  sprintf(name,"quadUV_%d_%d.pos", gf->tag(), iter);
+  FILE *f = fopen(name,"w");
+  fprintf(f,"View \"%s\" {\n",name);
+
+  for (unsigned int i = 0; i < uv.size1(); i++)
+    for (unsigned int j = 0; j < uv.size2(); j++)
+      fprintf(f,"SP(%g,%g,%g) {%d};\n", uv(i,j).x(), uv(i,j).y(), 0.0, i);
+
+  fprintf(f,"};\n");
+  fclose(f);
+
+  char name3[234];
+  sprintf(name3,"quadXYZ_%d_%d.pos", gf->tag(), iter);
+  FILE *f3 = fopen(name3,"w");
+  fprintf(f3,"View \"%s\" {\n",name3);
+  for (unsigned int i = 0; i < quads.size(); i++){
+    quads[i]->writePOS(f3,true,false,false,false,false,false);
+  }
+  fprintf(f3,"};\n");
+  fclose(f3);
+
+}
+
+static void printParamGrid(GFace *gf, std::vector<MVertex*> vert1, std::vector<MVertex*> vert2, 
+			   std::vector<MVertex*> e01, std::vector<MVertex*> e10, 
+			   std::vector<MVertex*> e23, std::vector<MVertex*> e32, 
+			   std::vector<MVertex*> e02, std::vector<MVertex*> e13, 
+			   std::vector<MQuadrangle*> quads)
+{
+
+  std::vector<SPoint2> p1,p2;
+  for (unsigned int i = 0; i< vert1.size(); i++){
+    SPoint2 pi;
+    reparamMeshVertexOnFace(vert1[i], gf, pi);
+    p1.push_back(pi);
+  }
+  for (unsigned int j = 0; j< vert2.size(); j++){
+    SPoint2 pj;
+    reparamMeshVertexOnFace(vert2[j], gf, pj);
+    p2.push_back(pj);
+  }
+
+
+  char name[234];
+  sprintf(name,"paramGrid_%d.pos", gf->tag());
+  FILE *f = fopen(name,"w");
+  fprintf(f,"View \"%s\" {\n",name);
+  
+  for (unsigned int i = 0; i < p1.size(); i++)
+    fprintf(f,"SP(%g,%g,%g) {%d};\n", p1[i].x(), p1[i].y(), 0.0, i);
+  
+  for (unsigned int j = 0; j < p2.size(); j++)
+    fprintf(f,"SP(%g,%g,%g) {%d};\n", p2[j].x(), p2[j].y(), 0.0, 100+j);
+  
+  fprintf(f,"};\n");
+  fclose(f);
+
+  char name2[234];
+  sprintf(name2,"paramEdges_%d.pos", gf->tag());
+  FILE *f2 = fopen(name2,"w");
+  fprintf(f2,"View \"%s\" {\n",name2);
+  
+  for (unsigned int i = 0; i < e01.size(); i++){
+     SPoint2 pi; reparamMeshVertexOnFace(e01[i], gf, pi);
+    fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 1);
+  }
+
+  for (unsigned int i = 0; i < e10.size(); i++){
+    SPoint2 pi; reparamMeshVertexOnFace(e10[i], gf, pi);
+    fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 10);
+  }
+
+  for (unsigned int i = 0; i < e23.size(); i++){
+    SPoint2 pi; reparamMeshVertexOnFace(e23[i], gf, pi);
+    fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 23);
+  }
+
+  for (unsigned int i = 0; i < e32.size(); i++){
+    SPoint2 pi; reparamMeshVertexOnFace(e32[i], gf, pi);
+    fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 32);
+  }
+
+  for (unsigned int i = 0; i < e02.size(); i++){
+    SPoint2 pi; reparamMeshVertexOnFace(e02[i], gf, pi);
+    fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 2);
+  }
+
+  for (unsigned int i = 0; i < e13.size(); i++){
+    SPoint2 pi; reparamMeshVertexOnFace(e13[i], gf, pi);
+    fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 13);
+  }
+  fprintf(f2,"};\n");
+  fclose(f2);
+
+  char name3[234];
+  sprintf(name3,"quadXYZ_%d.pos", gf->tag());
+  FILE *f3 = fopen(name3,"w");
+  fprintf(f3,"View \"%s\" {\n",name3);
+  for (unsigned int i = 0; i < quads.size(); i++){
+    quads[i]->writePOS(f3,true,false,false,false,false,false);
+  }
+  fprintf(f3,"};\n");
+  fclose(f3);
+ 
+  return;
+  
+}
+
+static void createQuadsFromUV(GFace *gf, fullMatrix<SPoint2> &uv,  std::vector<MQuadrangle*> &newq,  std::vector<MVertex*> &newv){
+
+  newq.clear(); 
+  newv.clear();
+  
+  int MM = uv.size1();
+  int NN = uv.size2();
+  std::vector<std::vector<MVertex*> > tab(MM);
+  for(int i = 0; i < MM; i++) tab[i].resize(NN);
+
+  for (int i = 0; i < MM; i++){
+    for (int j = 0; j < NN; j++){
+      GPoint gp = gf->point(uv(i,j));
+      if (!gp.succeeded()) printf("** AH new vertex not created p=%g %g \n", uv(i,j).x(), uv(i,j).y());
+      MVertex *vnew = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
+      tab[i][j] = vnew;
+      if (i != 0 && j != 0 && i != uv.size1()-1 && j != uv.size2()-1) 
+	newv.push_back(vnew);
+    }
+  }
+
+  // create quads
+  for (int i=0;i<MM-1;i++){
+    for (int j=0;j<NN-1;j++){
+      MQuadrangle *qnew = new MQuadrangle (tab[i][j],tab[i][j+1],tab[i+1][j+1],tab[i+1][j]);
+      newq.push_back(qnew);
+    }
+  }
+
+  return;
+
+}
+static std::vector<MVertex*> saturateEdgeRegular (GFace *gf, SPoint2 p1, SPoint2 p2, 
+						  double H,  double L, 
+						  int M, std::vector<SPoint2> &pe){
+
+  std::vector<MVertex*> pts;
+  for (int i=1;i<M;i++){
+    //double s = ((double)i/((double)(M)));
+    
+    double y = ((double)(i))*H/M;
+    double Yy = cosh(M_PI*y/L) - tanh(M_PI*H/L)*sinh(M_PI*y/L);
+    double YyH = cosh(M_PI*H/L) - tanh(M_PI*H/L)*sinh(M_PI*H/L);
+    double s = (1 - Yy)/(1.-YyH);
+        
+    SPoint2 p = p1 + (p2-p1)*s;
+    pe.push_back(p);
+
+    GPoint gp = gf->point(p);
+    if (!gp.succeeded()) printf("** AH new vertex not created p=%g %g \n", p.x(), p.y());
+    MVertex *v = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
+
+    if (!v){ pts.clear(); pts.resize(0); return pts;}
+    pts.push_back(v);
+  }
+  return pts;
+}
+
+//elliptic surface grid generator
+//see eq. 9.26 page 9-24 in handbook of grid generation
+static void ellipticSmoother(fullMatrix<SPoint2> uv, GFace* gf, 
+			     std::vector<MQuadrangle*> &newq, 
+			     std::vector<MVertex*> &newv){
+
+  int nbSmooth = 100;
+  int N = uv.size1();
+  int M = uv.size2();
+
+  for (int k = 0; k< nbSmooth; k++){
+    double norm = 0.0;
+    for (int i=1; i<N-1; i++){
+      for (int j = 1; j<M-1; j++){
+	Pair<SVector3, SVector3> der = gf->firstDer(uv(i,j));
+	SVector3 du = der.first();
+	SVector3 dv = der.second();
+	double g11 = dot(du,du);
+	double g12 = dot(du,dv);
+	double g22 = dot(dv,dv);
+	double over =  1./(4.*(g11+g22));
+	double uk = over*(2.*g22*(uv(i+1,j).x()+uv(i-1,j).x())+
+			  2.*g11*(uv(i,j+1).x()+uv(i,j-1).x())-
+			  1.*g12*(uv(i+1,j+1).x()-uv(i-1,j+1).x()));
+	double vk = over*(2.*g22*(uv(i+1,j).y()+uv(i-1,j).y())+
+			  2.*g11*(uv(i,j+1).y()+uv(i,j-1).y())-
+			  1.*g12*(uv(i+1,j+1).y()-uv(i-1,j+1).y()));
+	norm += sqrt((uv(i,j).x()-uk)*(uv(i,j).x()-uk)+(uv(i,j).y()-vk)*(uv(i,j).y()-vk));
+	uv(i,j) = SPoint2(uk,vk);
+      }
+    }  
+    //printf("Elliptic smoother iter (%d) = %g \n", k, norm);
+    printQuads(gf, uv, newq, k+1);
+  }
+
+  createQuadsFromUV(gf, uv, newq, newv);
+  printQuads(gf, uv, newq, 100);
+
+}
+
+//create initial grid points MxN using transfinite interpolation
+/*
+  c4          N              c3
+  +--------------------------+
+  |       |      |    |      |
+  |       |      |    |      |
+  +--------------------------+  M
+  |       |      |    |      |
+  |       |      |    |      |
+  +--------------------------+
+ c1                          c2
+             N
+*/
+static void createRegularGrid (GFace *gf,
+			       MVertex *v1, SPoint2 &c1,
+			       std::vector<MVertex*> &e12, std::vector<SPoint2> &pe12, int sign12,
+			       MVertex *v2, SPoint2 &c2,
+			       std::vector<MVertex*> &e23, std::vector<SPoint2> &pe23, int sign23,
+			       MVertex *v3, SPoint2 &c3,
+			       std::vector<MVertex*> &e34,std::vector<SPoint2> &pe34, int sign34,
+			       MVertex *v4, SPoint2 &c4,
+			       std::vector<MVertex*> &e41, std::vector<SPoint2> &pe41,int sign41,
+			       std::vector<MQuadrangle*> &q, 
+			       std::vector<MVertex*> &newv, 
+			       fullMatrix<SPoint2> &uv)
+{
+  int N = e12.size();
+  int M = e23.size();
+
+  uv.resize(M+2,N+2);
+  printf("uv =%d %d \n", uv.size1(), uv.size2());
+
+  char name3[234];
+  sprintf(name3,"quadParam_%d.pos", gf->tag());
+  FILE *f3 = fopen(name3,"w");
+  fprintf(f3,"View \"%s\" {\n",name3);
+
+  std::vector<std::vector<MVertex*> > tab(M+2);
+  for(int i = 0; i <= M+1; i++) tab[i].resize(N+2);
+
+  tab[0][0] = v1;
+  tab[0][N+1] = v2;
+  tab[M+1][N+1] = v3;
+  tab[M+1][0] = v4;
+  uv(0,0) = c1;
+  uv(0,N+1) = c2;
+  uv(M+1,N+1) = c3;
+  uv(M+1,0) = c4;
+  for (int i=0;i<N;i++){
+    tab[0][i+1]   = sign12 > 0 ? e12 [i] : e12 [N-i-1];
+    tab[M+1][i+1] = sign34 < 0 ? e34 [i] : e34 [N-i-1];
+    uv(0,i+1)   = sign12 > 0 ? pe12 [i] : pe12 [N-i-1];
+    uv(M+1,i+1) = sign34 < 0 ? pe34 [i] : pe34 [N-i-1];
+  }
+  for (int i=0;i<M;i++){
+    tab[i+1][N+1] = sign23 > 0 ? e23 [i] : e23 [M-i-1];
+    tab[i+1][0]   = sign41 < 0 ? e41 [i] : e41 [M-i-1];
+    uv(i+1,N+1) = sign23 > 0 ? pe23 [i] : pe23 [M-i-1];
+    uv(i+1,0)   = sign41 < 0 ? pe41 [i] : pe41 [M-i-1];
+  }
+
+  for (int i=0;i<N;i++){
+    for (int j=0;j<M;j++){
+      double u = (double) (i+1)/ ((double)(N+1));
+      double v = (double) (j+1)/ ((double)(M+1));
+      MVertex *v12 = (sign12 >0) ? e12[i] : e12 [N-1-i];
+      MVertex *v23 = (sign23 >0) ? e23[j] : e23 [M-1-j];
+      MVertex *v34 = (sign34 <0) ? e34[i] : e34 [N-1-i];
+      MVertex *v41 = (sign41 <0) ? e41[j] : e41 [M-1-j];
+      SPoint2 p12; reparamMeshVertexOnFace(v12, gf, p12);
+      SPoint2 p23; reparamMeshVertexOnFace(v23, gf, p23);
+      SPoint2 p34; reparamMeshVertexOnFace(v34, gf, p34);
+      SPoint2 p41; reparamMeshVertexOnFace(v41, gf, p41);
+      double Up = TRAN_QUAD(p12.x(), p23.x(), p34.x(), p41.x(),
+			   c1.x(),c2.x(),c3.x(),c4.x(),u,v);
+      double Vp = TRAN_QUAD(p12.y(), p23.y(), p34.y(), p41.y(),
+			   c1.y(),c2.y(),c3.y(),c4.y(),u,v);
+      fprintf(f3,"SP(%g,%g,%g) {%d};\n", Up, Vp, 0.0, 1);
+ 
+      if ((p12.x() && p12.y() == -1.0) || (p23.x() && p23.y() == -1.0) ||
+          (p34.x() && p34.y() == -1.0) || (p41.x() && p41.y() == -1.0)) {
+        Msg::Error("Wrong param -1");
+        return;
+      }
+      
+      SPoint2 pij(Up,Vp);
+           
+      GPoint gp = gf->point(pij);
+      if (!gp.succeeded()) printf("** AH new vertex not created p=%g %g \n", Up, Vp);
+      MVertex *vnew = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
+      newv.push_back(vnew);
+
+      uv(j+1,i+1) = pij;
+      tab[j+1][i+1] = vnew;
+    }
+  }
+
+  // create quads
+  for (int i=0;i<=N;i++){
+    for (int j=0;j<=M;j++){
+      MQuadrangle *qnew = new MQuadrangle (tab[j][i],tab[j][i+1],tab[j+1][i+1],tab[j+1][i]);
+      q.push_back(qnew);
+    }
+  }
+
+  fprintf(f3,"};\n");
+  fclose(f3);
+
+}
+
+static void updateFaceQuads(GFace *gf, std::vector<MQuadrangle*> &quads, std::vector<MVertex*> &newv){
+
+  printf("face has before %d quads %d tris  %d vert \n ", gf->quadrangles.size(), gf->triangles.size(), gf->mesh_vertices.size());
+  for (unsigned int i = 0; i < quads.size(); i++){
+    gf->quadrangles.push_back(quads[i]);
+    for (int j=0;j<4;j++){
+      MVertex *v = quads[i]->getVertex(j);
+    }
+  }
+  for(int i = 0; i < newv.size(); i++){
+    gf->mesh_vertices.push_back(newv[i]);
+  }
+  printf("face has after %d quads %d tris   %d vert  \n ", gf->quadrangles.size(), gf->triangles.size(), gf->mesh_vertices.size());
+
+}
+
+bool createRegularTwoCircleGrid (Centerline *center, GFace *gf)
+{
+
+  std::list<GEdge*> bedges = gf->edges();
+  std::list<GEdge*>::iterator itb = bedges.begin();
+  std::list<GEdge*>::iterator ite = bedges.end(); ite--;
+  GEdge *ge1 =  (*itb)->getCompound();
+  GEdge *ge2 =  (*ite)->getCompound();
+  int N = ge1->mesh_vertices.size() + 1;
+  int N2 = ge2->mesh_vertices.size() + 1;
+  if (N != N2 || N%2 != 0){
+    Msg::Error("You should have an equal pair number of points in centerline field N =%d N2=%d\n", N, N2);
+    return false;
+  }
+
+  //vert1 is the outer circle 
+  //vert2 is the inner circle
+  //         - - - -
+  //       -         -
+  //     -      -      -
+  //   v0-  v2-   -v3   -v1
+  //     -      -      -
+  //      -          -
+  //         - - - -
+
+  std::vector<MVertex*> vert1, vert2, vert_temp;
+  vert1.push_back(ge1->getBeginVertex()->mesh_vertices[0]);
+  vert2.push_back(ge2->getBeginVertex()->mesh_vertices[0]);
+  for(int i = 0; i < N-1; i++) {
+    vert1.push_back(ge1->mesh_vertices[i]);
+    vert2.push_back(ge2->mesh_vertices[i]);
+  }
+  SPoint2 pv1; reparamMeshVertexOnFace(vert1[0], gf, pv1);
+  SPoint2 pv2; reparamMeshVertexOnFace(vert2[0], gf, pv2);
+  SPoint2 pv1b; reparamMeshVertexOnFace(vert1[1], gf, pv1b);
+  SPoint2 pv2b; reparamMeshVertexOnFace(vert2[1], gf, pv2b);
+  SPoint2 pv1c; reparamMeshVertexOnFace(vert1[2], gf, pv1c);
+  SPoint2 pv2c; reparamMeshVertexOnFace(vert2[2], gf, pv2c);
+  SVector3 vec1(pv1b.x()-pv1.x(),pv1b.y()-pv1.y() , 0.0);
+  SVector3 vec1b(pv1c.x()-pv1b.x(),pv1c.y()-pv1b.y() ,0.0);
+  SVector3 vec2(pv2b.x()-pv2.x(),pv2b.y()-pv2.y() ,0.0);
+  SVector3 vec2b(pv2c.x()-pv2b.x(),pv2c.y()-pv2b.y() , 0.0);
+  int sign2 =  (dot(crossprod(vec1,vec1b),crossprod(vec2,vec2b)) < 0)  ?   -1 : +1 ;
+  double n1 = sqrt(pv1.x()*pv1.x()+pv1.y()*pv1.y());
+  double n2 = sqrt(pv2.x()*pv2.x()+pv2.y()*pv2.y());
+  if (n2 > n1) {
+    vert_temp = vert1;
+    vert1.clear(); 
+    vert1 = vert2;
+    vert2.clear();
+    vert2 = vert_temp;
+  }
+
+#if defined(HAVE_ANN)
+  ANNpointArray nodes = annAllocPts(N, 3);
+  ANNidxArray index  = new ANNidx[1];
+  ANNdistArray dist = new ANNdist[1];
+  for (int ind = 0; ind < N; ind++){
+    SPoint2 pp2; reparamMeshVertexOnFace(vert2[ind], gf, pp2);
+    nodes[ind][0] =  pp2.x();
+    nodes[ind][1] =  pp2.y();
+    nodes[ind][2] =  0.0;
+  }
+  ANNkd_tree *kdtree = new ANNkd_tree(nodes, N, 3);
+  SPoint2 pp1; reparamMeshVertexOnFace(vert1[0], gf, pp1);
+  double xyz[3] = {pp1.x(), pp1.y(),0.0};
+  kdtree->annkSearch(xyz, 1, index, dist);
+  int close_ind = index[0];
+  double length = sqrt((vert1[0]->x()-vert2[close_ind]->x())*(vert1[0]->x()-vert2[close_ind]->x())+
+		       (vert1[0]->y()-vert2[close_ind]->y())*(vert1[0]->y()-vert2[close_ind]->y())+
+		       (vert1[0]->z()-vert2[close_ind]->z())*(vert1[0]->z()-vert2[close_ind]->z()));
+
+  double rad = center->operator()(vert1[0]->x(), vert1[0]->y(), vert1[0]->z());
+  double arc = 2*M_PI*rad;
+  double lc =  arc/N;
+  int M = length/lc;
+  printf("length =%g  arc=%g  \n", length,  arc);
+
+  delete kdtree;
+  delete[]index;
+  delete[]dist;
+  annDeallocPts(nodes);
+#endif;
+
+  MVertex *v0 = vert1[0]; SPoint2 p0; reparamMeshVertexOnFace(v0, gf, p0);
+  MVertex *v1 = vert1[N/2]; SPoint2 p1; reparamMeshVertexOnFace(v1, gf, p1);
+  MVertex *v2 = vert2[close_ind]; SPoint2 p2; reparamMeshVertexOnFace(v2, gf, p2);
+  MVertex *v3 = vert2[(close_ind+N/2)%N]; SPoint2 p3; reparamMeshVertexOnFace(v3, gf, p3);
+
+  printf("grid N = %d M = %d\n", N , M);
+  //printf("v2 =%d v3=%d \n", close_ind, (close_ind+N/2)%N);
+  std::vector<MVertex*> e01,e10,e23,e32;//edges without first and last vertex
+  for (int i=1;i<N/2;i++) e01.push_back(vert1[i]);
+  for (int i=N/2+1;i<N;i++) e10.push_back(vert1[i]);
+  for (int i=1;i<N/2;i++) e23.push_back(vert2[(close_ind+i)%N]);
+  for (int i=N/2+1;i<N;i++) e32.push_back(vert2[(close_ind+i)%N]);
+  
+  std::vector<SPoint2> pe01, pe10, pe23, pe32;
+  for (unsigned int i = 0; i < e01.size(); i++){
+     SPoint2 p01; reparamMeshVertexOnFace(e01[i], gf, p01);
+     SPoint2 p10; reparamMeshVertexOnFace(e10[i], gf, p10);
+     SPoint2 p23; reparamMeshVertexOnFace(e23[i], gf, p23);
+     SPoint2 p32; reparamMeshVertexOnFace(e32[i], gf, p32);
+     pe01.push_back(p01);
+     pe10.push_back(p10);
+     pe23.push_back(p23);
+     pe32.push_back(p32);
+  }
+
+  std::vector<SPoint2> pe02, pe13;
+  std::vector<MVertex*> e02 = saturateEdgeRegular (gf,p0,p2,length, arc, M+1, pe02); 
+  std::vector<MVertex*> e13 = saturateEdgeRegular (gf,p1,p3,length, arc, M+1, pe13); 
+
+  printf("N/2 edges size =%d %d \n", pe01.size(), pe10.size());
+  printf("M edges size =%d %d \n", pe02.size(), pe13.size());
+
+  std::vector<MVertex*> e_inner1 = e23;
+  std::vector<MVertex*> e_inner2 = e32;
+  std::vector<SPoint2> pe_inner1 = pe23;
+  std::vector<SPoint2> pe_inner2 = pe32;
+  if (sign2 <0){
+    e_inner1 = e32;
+    e_inner2 = e23;
+    pe_inner1 = pe32;
+    pe_inner2 = pe23;
+  }
+
+  std::vector<MQuadrangle*> quads, smoothQuad;
+  std::vector<MVertex*> newv, smoothv;
+  fullMatrix<SPoint2> uv1, uv2;
+  createRegularGrid (gf,
+  		     v0, p0,
+  		     e01, pe01, +1,
+  		     v1,p1,
+  		     e13, pe13, +1,
+  		     v3,p3,
+		     e_inner1, pe_inner1, -sign2,
+  		     v2,p2,
+  		     e02, pe02, -1,
+  		     quads, newv, uv1);
+
+  printQuads(gf, uv1, quads, 0);
+  ellipticSmoother(uv1, gf, smoothQuad, smoothv);
+  
+  createRegularGrid (gf,
+  		     v0,p0,
+  		     e02, pe02,  +1,
+  		     v2,p2,
+  		     e_inner2, pe_inner2, -sign2,
+  		     v3,p3,
+  		     e13, pe13, -1,
+  		     v1,p1,
+  		     e10, pe10, +1,
+  		     quads, newv, uv2);
+
+  //updateFaceQuads(gf, quads, newv);
+  //ellipticSmoother
+
+  printParamGrid(gf, vert1, vert2, e01,e10,e23,e32,e02,e13, quads);
+  return true;
+
+}
+
diff --git a/Mesh/meshGFaceElliptic.h b/Mesh/meshGFaceElliptic.h
new file mode 100644
index 0000000000000000000000000000000000000000..2c6db1515ff488668b76fb7871e2385cc19d3d6d
--- /dev/null
+++ b/Mesh/meshGFaceElliptic.h
@@ -0,0 +1,24 @@
+// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#ifndef _MESH_GFACE_ELLIPTIC_H_
+#define _MESH_GFACE_ELLIPTIC_H_
+
+#include <map>
+#include <vector>
+#include "MElement.h"
+#include "MEdge.h"
+#include "STensor3.h"
+
+class GFace;
+class GVertex;
+class MVertex;
+class Centerline;
+
+
+bool createRegularTwoCircleGrid (Centerline *center, GFace *gf);
+
+
+#endif
diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp
index 64b09c5ae2552af63846215b8b50813bf0850013..a724bb4edbe77a80d1f65a9c9f91d65cbea60c0f 100644
--- a/Mesh/meshGFaceOptimize.cpp
+++ b/Mesh/meshGFaceOptimize.cpp
@@ -791,9 +791,7 @@ std::vector<MVertex*> saturateEdge (GFace *gf, SPoint2 p1, SPoint2 p2, int n){
   |       |      |    |      |
   +--------------------------+
  c1                          c2
-
              N
-
 */
 #define TRAN_QUA(c1,c2,c3,c4,s1,s2,s3,s4,u,v) \
     (1.-u)*c4+u*c2+(1.-v)*c1+v*c3-((1.-u)*(1.-v)*s1+u*(1.-v)*s2+u*v*s3+(1.-u)*v*s4)
@@ -813,6 +811,11 @@ void createRegularMesh (GFace *gf,
   int N = e12.size();
   int M = e23.size();
 
+ char name3[234];
+  sprintf(name3,"quadParam_%d.pos", gf->tag());
+  FILE *f3 = fopen(name3,"w");
+  fprintf(f3,"View \"%s\" {\n",name3);
+
   //create points using transfinite interpolation
 
   std::vector<std::vector<MVertex*> > tab(M+2);
@@ -847,6 +850,8 @@ void createRegularMesh (GFace *gf,
 			   c1.x(),c2.x(),c3.x(),c4.x(),u,v);
       double Vp = TRAN_QUA(p12.y(), p23.y(), p34.y(), p41.y(),
 			   c1.y(),c2.y(),c3.y(),c4.y(),u,v);
+      fprintf(f3,"SP(%g,%g,%g) {%d};\n", Up, Vp, 0.0, 1.);
+ 
       // printf("v1=%d v2=%d v3=%d v4=%d \n", v1->getNum(), v2->getNum(), v3->getNum(), v4->getNum());
       // printf("c1=%g %g, c2=%g %g, c3=%g %g, c4=%g,%g \n", c1.x(),c1.y(),c2.x(),c2.y(),c3.x(),c3.y(),c4.x(),c4.y());
       // printf("p1=%g %g, p2=%g %g, p3=%g %g, p4=%g,%g \n", p12.x(),p12.x(),p23.x(),p23.y(),p34.x(),p34.y(),p41.x(),p41.y());
@@ -869,6 +874,10 @@ void createRegularMesh (GFace *gf,
       q.push_back(qnew);
     }
   }
+
+  fprintf(f3,"};\n");
+  fclose(f3);
+
 }
 
 void updateQuadCavity (GFace *gf,
@@ -1845,8 +1854,8 @@ static void _relocateVertexOpti(GFace *gf, MVertex *ver,
 }
 #endif
 
-static void _relocateVertex(GFace *gf, MVertex *ver,
-                            const std::vector<MElement*> &lt)
+void _relocateVertex(GFace *gf, MVertex *ver,
+		     const std::vector<MElement*> &lt)
 {
   double R;
   SPoint3 c;
diff --git a/Mesh/meshGFaceOptimize.h b/Mesh/meshGFaceOptimize.h
index 0918ce4335f2158179af9a0b6fbc8639548ec8cf..b41a9a39b77e3518f74c31187e808a80c305aba9 100644
--- a/Mesh/meshGFaceOptimize.h
+++ b/Mesh/meshGFaceOptimize.h
@@ -58,17 +58,8 @@ void buildEdgeToElements(std::vector<MElement*> &tris, e2t_cont &adj);
 
 void laplaceSmoothing(GFace *gf, int niter=1);
 
-void createRegularMesh (GFace *gf,
-			 MVertex *v1, SPoint2 &c1,
-			 std::vector<MVertex*> &e12, int sign12,
-			 MVertex *v2, SPoint2 &c2,
-			 std::vector<MVertex*> &e23, int sign23,
-			 MVertex *v3, SPoint2 &c3,
-			 std::vector<MVertex*> &e34, int sign34,
-			 MVertex *v4, SPoint2 &c4,
-			 std::vector<MVertex*> &e41, int sign41,
-			std::vector<MQuadrangle*> &q);
-std::vector<MVertex*> saturateEdge (GFace *gf, SPoint2 p1, SPoint2 p2, int n);
+void _relocateVertex(GFace *gf, MVertex *ver,
+		     const std::vector<MElement*> &lt);
 
 /*
 void edgeSwappingLawson(GFace *gf);