diff --git a/Mesh/BDS.cpp b/Mesh/BDS.cpp
index 8b75cbfa54074cc61c0d060a14fa173e7e273126..0864c228595516e29106c98eafc1c93fc1487066 100644
--- a/Mesh/BDS.cpp
+++ b/Mesh/BDS.cpp
@@ -1,4 +1,4 @@
-// $Id: BDS.cpp,v 1.94 2008-01-24 09:35:41 remacle Exp $
+// $Id: BDS.cpp,v 1.95 2008-01-26 17:47:58 remacle Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -221,18 +221,23 @@ BDS_Edge *BDS_Mesh::recover_edge(int num1, int num2, std::set<EdgeToRecover> *e2
 	  e = (*it);
 	  //	  if (e->p1->iD >= 0 && e->p2->iD >= 0)Msg(INFO," %d %d %g %g - %g %g",e->p1->iD,e->p2->iD,e->p1->u,e->p1->v,e->p2->u,e->p2->v);
 	  if (!e->deleted && e->p1 != p1 && e->p1 != p2 && e->p2 != p1 && e->p2 != p2)
+// 	    if (e->p1->iD == 99 || e->p2->iD == 99) {
+// 	      printf("%d %d %d %d\n",e->p1->iD,e->p2->iD,p1->iD,p2->iD);
+// 	      printf("%g %g,%g %g,%g %g,%g %g\n",e->p1->u, e->p1->v,e->p2->u, e->p2->v,p1->u,p1->v,p2->u,p2->v);
+// 	    }
 	    if(Intersect_Edges_2d(e->p1->u, e->p1->v,
 				  e->p2->u, e->p2->v,
 				  p1->u, p1->v,
 				  p2->u, p2->v))
 	      {
+		//		printf("intersect\n");
 		if (e2r && e2r->find(EdgeToRecover(e->p1->iD,e->p2->iD,0)) != e2r->end())
 		  {
 		    std::set<EdgeToRecover>::iterator itr1 = e2r->find(EdgeToRecover(e->p1->iD,e->p2->iD,0));		    
 		    std::set<EdgeToRecover>::iterator itr2 = e2r->find(EdgeToRecover(num1,num2,0));		    
-		    //		    Msg(WARNING," edge %d %d on model edge %d cannot be recovered because it intersects %d %d on model edge %d",
-		    //			num1,num2,itr2->ge->tag(),
-		    //			e->p1->iD,e->p2->iD,itr1->ge->tag());
+		    Msg(WARNING," edge %d %d on model edge %d cannot be recovered because it intersects %d %d on model edge %d",
+			num1,num2,itr2->ge->tag(),
+			e->p1->iD,e->p2->iD,itr1->ge->tag());
 
 		    // now throw a class that contains the diagnostic
 		    not_recovered->insert (EdgeToRecover( num1 , num2, itr2->ge));
@@ -249,6 +254,7 @@ BDS_Edge *BDS_Mesh::recover_edge(int num1, int num2, std::set<EdgeToRecover> *e2
 // 	    num1,num2,ix);	
 // 	ix = 0;
 //       }
+//      printf("%d %d\n",intersected.size(),ix);
       
       if (!intersected.size() || ix > 1000)
 	{
@@ -265,7 +271,9 @@ BDS_Edge *BDS_Mesh::recover_edge(int num1, int num2, std::set<EdgeToRecover> *e2
 	}
       
       int ichoice = ix++ % intersected.size();
-      swap_edge ( intersected[ichoice] , BDS_SwapEdgeTestQuality (false) );	       
+      bool success = swap_edge ( intersected[ichoice] , BDS_SwapEdgeTestQuality (false,false) );	       
+//       printf("trying to swop %d %d = %d (%d %d)\n",intersected[ichoice]->p1->iD,intersected[ichoice]->p2->iD,success,
+// 	     intersected[ichoice]->deleted,intersected[ichoice]->numfaces());
     }
   return 0;
 }
@@ -375,24 +383,6 @@ BDS_Face *BDS_Mesh::add_quadrangle(BDS_Edge * e1, BDS_Edge * e2,
   return t;
 }
 
-
-// BDS_Tet *BDS_Mesh::add_tet(int p1, int p2, int p3, int p4)
-// {
-//   BDS_Edge *e1 = add_edge(p1, p2);
-//   BDS_Edge *e2 = add_edge(p2, p3);
-//   BDS_Edge *e3 = add_edge(p3, p1);
-//   BDS_Edge *e4 = add_edge(p1, p4);
-//   BDS_Edge *e5 = add_edge(p2, p4);
-//   BDS_Edge *e6 = add_edge(p3, p4);
-//   BDS_Face *t1 = add_triangle(e1, e2, e3);
-//   BDS_Face *t2 = add_triangle(e1, e4, e5);
-//   BDS_Face *t3 = add_triangle(e2, e6, e5);
-//   BDS_Face *t4 = add_triangle(e3, e4, e6);
-//   BDS_Tet *t = new BDS_Tet(t1, t2, t3, t4);
-//   tets.push_back(t);
-//   return t;
-// }
-
 void BDS_Mesh::del_face(BDS_Face * t)
 {
   t->e1->del(t);
@@ -404,11 +394,9 @@ void BDS_Mesh::del_face(BDS_Face * t)
 
 void BDS_Mesh::del_edge(BDS_Edge * e)
 {
-  // edges.erase(e);
   e->p1->del(e);
   e->p2->del(e);
   e->deleted = true;
-  // edges_to_delete.insert(e);
 }
 
 void BDS_Mesh::del_point(BDS_Point * p)
@@ -477,12 +465,6 @@ void recur_tag(BDS_Face * t, BDS_GeomEntity * g)
 double PointLessThanLexicographic::t = 0;
 double BDS_Vector::t = 0;
 
-bool BDS_Mesh::import_view(PView *view, const double tolerance)
-{
-  Msg(GERROR, "View import must be reinterfaced");
-  return false;
-}
-
 template < class IT > void DESTROOOY(IT beg, IT end)
 {
   while(beg != end) {
@@ -550,22 +532,6 @@ bool BDS_Mesh::split_edge(BDS_Edge * e, BDS_Point *mid)
   BDS_Point *p2 = e->p2;
 
   e->oppositeof(op);
-
-//   double qt1 = qmTriangle(p1,op[0],mid,QMTRI_RHO);
-//   double qt2 = qmTriangle(p2,op[0],mid,QMTRI_RHO);
-//   double qt3 = qmTriangle(p1,op[1],mid,QMTRI_RHO);
-//   double qt4 = qmTriangle(p2,op[1],mid,QMTRI_RHO);
-//   if (qt1 < 1.e-5 || qt2 < 1.e-5 || qt3 < 1.e-5 || qt4 < 1.e-5)
-//     {
-//       return false;
-//     }
-
-
-  
-//   double l1 = sqrt((op[0]->X-op[1]->X) *(op[0]->X-op[1]->X) +
-//    		   (op[0]->Y-op[1]->Y) *(op[0]->Y-op[1]->Y) +
-//    		   (op[0]->Z-op[1]->Z) *(op[0]->Z-op[1]->Z) );
-//   if (l1 < 0.1* mid->lc()) return false;
   
   BDS_Point *pts1[4];
   e->faces(0)->getNodes(pts1);
@@ -613,14 +579,6 @@ bool BDS_Mesh::split_edge(BDS_Edge * e, BDS_Point *mid)
   BDS_Edge *mid_op2 = new BDS_Edge(mid, op[1]);
   edges.push_back(mid_op2);
 
-  //  p1_mid->target_length = t_l;
-  //  op1_mid->target_length = t_l;
-  //  mid_p2->target_length = t_l;
-  //  mid_op2->target_length = t_l;
-
-  // printf("split ends 1 %d (%d %d) %d %d \n",
-  //         p1_op1->numfaces(), p1->iD, op[0]->iD, 
-  //         op1_mid->numfaces(),p1_mid->numfaces());
   BDS_Face *t1, *t2, *t3, *t4;
   if(orientation == 1) {
     t1 = new BDS_Face(op1_mid, p1_op1, p1_mid);
@@ -660,157 +618,39 @@ bool BDS_Mesh::split_edge(BDS_Edge * e, BDS_Point *mid)
   return true;
 }
 
-
-void BDS_Mesh::saturate_edge(BDS_Edge * e, std::vector<BDS_Point *> &mids)
-{
-  BDS_Point *op[2];
-  BDS_Point *p1 = e->p1;
-  BDS_Point *p2 = e->p2;
-
-  BDS_Point *pts1[4];
-  e->faces(0)->getNodes(pts1);
-
-  int orientation = 0;
-  for(int i = 0; i < 3; i++) {
-    if(pts1[i] == p1) {
-      if(pts1[(i + 1) % 3] == p2)
-        orientation = 1;
-      else
-        orientation = -1;
-
-      break;
-    }
-  }
-
-  //  printf("sat %d\n",mids.size());
-
-  // we should project 
-  e->oppositeof(op);
-  BDS_GeomEntity *g1 = 0, *g2 = 0, *ge = e->g;
-
-  BDS_Edge *p1_op1 = find_edge(p1, op[0], e->faces(0));
-  BDS_Edge *op1_p2 = find_edge(op[0], p2, e->faces(0));
-  BDS_Edge *p1_op2 = find_edge(p1, op[1], e->faces(1));
-  BDS_Edge *op2_p2 = find_edge(op[1], p2, e->faces(1));
-
-  if(e->faces(0)) {
-    g1 = e->faces(0)->g;
-    del_face(e->faces(0));
-  }
-  // not a bug !!!
-  if(e->faces(0)) {
-    g2 = e->faces(0)->g;
-    del_face(e->faces(0));
-  }
-
-  //  double t_l = e->target_length;
-
-  del_edge(e);
-
-  // create all the sub-edges of e 
-  std::vector<BDS_Edge*> subs;
-  for (unsigned int i = 0; i < mids.size() + 1; i++)
-    {
-      BDS_Point *a,*b;
-      if (i == 0)a = p1;
-      else a = mids[i-1];
-      if (i == mids.size())b = p2;
-      else b = mids[i];
-      BDS_Edge *sub = new BDS_Edge(a, b);
-      //      printf("%g %g -> %g %g\n",a->X,a->Y,b->X,b->Y);
-      edges.push_back(sub); 
-      subs.push_back(sub);
-      sub->g = ge;
-    }
-  // create edges that connect op1 and op2
-  std::vector<BDS_Edge*> conn1,conn2;
-  for (unsigned int i = 0; i < mids.size(); i++)
-    {
-      BDS_Edge *c1 = new BDS_Edge(mids[i], op[0]);
-      edges.push_back(c1); 
-      conn1.push_back(c1);
-      BDS_Edge *c2 = new BDS_Edge(mids[i], op[1]);
-      edges.push_back(c2); 
-      conn2.push_back(c2);
-      c1->g = g1;
-      c2->g = g2;
-      mids[i]->g = ge;
-    }
-
-  // create the triangles
-
-  for (unsigned int i = 0; i < mids.size() + 1; i++)
-    {
-      BDS_Edge *e1,*e2,*e3=subs[i];
-
-      //      printf("--> %d %g %g ->%d  %g %g\n",e3->p1->iD,e3->p1->X,e3->p1->Y,e3->p2->iD,e3->p2->X,e3->p2->Y);
-
-
-      if (i==0)e1 = p1_op1;
-      else e1 = conn1[i-1];
-      if (i==mids.size())e2 = op1_p2;
-      else e2 = conn1[i];
-
-//       printf("--> %d %g %g ->%d  %g %g\n",e1->p1->iD,e1->p1->X,e1->p1->Y,e1->p2->iD,e1->p2->X,e1->p2->Y);
-//       printf("--> %d %g %g ->%d  %g %g\n",e2->p1->iD,e2->p1->X,e2->p1->Y,e2->p2->iD,e2->p2->X,e2->p2->Y);
-
-      BDS_Face *t1;
-      if(orientation == 1)
-	t1 = new BDS_Face(e3, e2, e1);
-      else 
-	t1 = new BDS_Face(e3, e1, e2);
-
-
-      if (i==0)e1 = p1_op2;
-      else e1 = conn2[i-1];
-      if (i==mids.size())e2 = op2_p2;
-      else e2 = conn2[i];
-
-      BDS_Face *t2;
-      if(orientation != 1)
-	t2 = new BDS_Face(e3, e2, e1);
-      else 
-	t2 = new BDS_Face(e3, e1, e2);
-      t1->g = g1;
-      t2->g = g2;
-
-      triangles.push_back(t1);
-      triangles.push_back(t2);
-    }
-  // config has changed
-  p1->config_modified = true;
-  p2->config_modified = true;
-  op[0]->config_modified = true;
-  op[1]->config_modified = true;
-}
-
-
 // This function does actually the swap without taking into account
 // the feasability of the operation. Those conditions have to be
 // taken into account before doing the edge swap
 
 bool BDS_SwapEdgeTestQuality::operator () (BDS_Point *_p1,BDS_Point *_p2,
 					   BDS_Point *_q1,BDS_Point *_q2) const
-{
+{  
+  if (!testSmallTriangles){
+    
+    double p1 [2] = {_p1->u,_p1->v};
+    double p2 [2] = {_p2->u,_p2->v};
+    double op1[2] = {_q1->u,_q1->v};
+    double op2[2] = {_q2->u,_q2->v};
+    
+
+    double ori_t1 = gmsh::orient2d(op1, p1, op2);
+    double ori_t2 = gmsh::orient2d(op1, op2, p2);
+    
+    //    printf("%d %d %d %d %g %g\n",_p1->iD,_p2->iD,_q1->iD,_q2->iD,ori_t1,ori_t2);
+    return ( ori_t1 * ori_t2 > 0 ); // the quadrangle was strictly convex !
+  }
+
 
    double s1 = fabs(surface_triangle_param(_p1,_p2,_q1)); 
    double s2 = fabs(surface_triangle_param(_p1,_p2,_q2)); 
    double s3 = fabs(surface_triangle_param(_p1,_q1,_q2)); 
    double s4 = fabs(surface_triangle_param(_p2,_q1,_q2)); 
-   if (fabs(s1+s2-s3-s4) > 1.e-10 * (s1+s2))return false;
-   if (s3 < .02 * (s1+s2) || s4 < .02 * (s1+s2))return false;
+   if (fabs(s1+s2-s3-s4) > 1.e-12 * (s1+s2))return false;
+   if (s3 < .02 * (s1+s2) || s4 < .02 * (s1+s2))
+     return false;
    return true;
 		   
 
-   double p1 [2] = {_p1->u,_p1->v};
-   double p2 [2] = {_p2->u,_p2->v};
-   double op1[2] = {_q1->u,_q1->v};
-   double op2[2] = {_q2->u,_q2->v};
-
-   double ori_t1 = gmsh::orient2d(op1, p1, op2);
-   double ori_t2 = gmsh::orient2d(op1, op2, p2);
-   
-   return ( ori_t1 * ori_t2 > 0 ); // the quadrangle was strictly convex !
 }
 
 bool BDS_SwapEdgeTestQuality::operator () (BDS_Point *_p1,BDS_Point *_p2,BDS_Point *_p3,
@@ -848,8 +688,6 @@ bool BDS_SwapEdgeTestQuality::operator () (BDS_Point *_p1,BDS_Point *_p2,BDS_Poi
 
 }
 
-
-
 void swap_config(BDS_Edge * e, 
 		 BDS_Point **p11,BDS_Point **p12,BDS_Point **p13,
 		 BDS_Point **p21,BDS_Point **p22,BDS_Point **p23,
@@ -1410,16 +1248,21 @@ bool BDS_Mesh::smooth_point_centroid(BDS_Point * p, GFace *gf, bool test_quality
     //    printf("%22.15E %22.15E\n",snew,sold);
     if ( snew < .1 * sold) return false;
 
-    if (test_quality){
+    if (1 || test_quality){
       p->X = gp.x();
       p->Y = gp.y();
       p->Z = gp.z();
       newWorst = std::min(newWorst,qmTriangle(*it,QMTRI_RHO));
+      double norm1[3],norm2[3];
+      normal_triangle(n[0],n[1],n[2],norm1);
       p->X = oldX;
       p->Y = oldY;
       p->Z = oldZ;
+      normal_triangle(n[0],n[1],n[2],norm2);
       oldWorst = std::min(oldWorst,qmTriangle(*it,QMTRI_RHO));
-    }
+      double ps; prosca (norm1,norm2,&ps);
+      if (ps < .5)return false;
+  }
     ++it;
   }
   
diff --git a/Mesh/BDS.h b/Mesh/BDS.h
index baaaeccbceee0e5aca43ddcb3b9622731ad6e0ba..72847258181073ca3a0f8492e4e77b37b5df3b5b 100644
--- a/Mesh/BDS.h
+++ b/Mesh/BDS.h
@@ -379,9 +379,9 @@ class BDS_SwapEdgeTest
 
 class BDS_SwapEdgeTestQuality : public BDS_SwapEdgeTest
 {
-  bool testQuality;
+  bool testQuality, testSmallTriangles;
  public:
-  BDS_SwapEdgeTestQuality (bool a) : testQuality(a){}
+  BDS_SwapEdgeTestQuality (bool a, bool b=true) : testQuality(a),testSmallTriangles(b){}
   virtual bool operator() (BDS_Point *p1,BDS_Point *p2,
 			   BDS_Point *q1,BDS_Point *q2) const ; 
   virtual bool operator() (BDS_Point *p1,BDS_Point *p2, BDS_Point *p3,
@@ -466,14 +466,12 @@ public:
   bool smooth_point_centroid(BDS_Point * p, GFace *gf, bool test_quality = false);
   bool move_point(BDS_Point *p , double X, double Y, double Z);
   bool split_edge(BDS_Edge *, BDS_Point *);
-  void saturate_edge(BDS_Edge *, std::vector<BDS_Point *>&);
+  bool split_face(BDS_Face *, BDS_Point *);
   bool edge_constraint    ( BDS_Point *p1, BDS_Point *p2 );
   bool recombine_edge    ( BDS_Edge *e );
   // Global operators
   void cleanup();
   void recombineIntoQuads (const double angle, GFace *gf);
-  // io's 
-  bool import_view(PView *view, const double tolerance);
 };
 
 void outputScalarField(std::list < BDS_Face * >t, const char *fn, int param);
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index 8825799e98bcac0ed7e2983a83cb9b64ca96eddc..02dd505bd1dcd5766191bdde50060c0cbfe333eb 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -1,4 +1,4 @@
-// $Id: meshGFace.cpp,v 1.112 2008-01-24 09:35:41 remacle Exp $
+// $Id: meshGFace.cpp,v 1.113 2008-01-26 17:47:58 remacle Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -1280,9 +1280,9 @@ bool gmsh2DMeshGeneratorPeriodic ( GFace *gf , bool debug = true)
   if (!AlgoDelaunay2D ( gf ))
     {
       gmshRefineMeshBDS (gf,*m,CTX.mesh.refine_steps,true);
-      gmshOptimizeMeshBDS(gf, *m, 2,&recover_map);
+      gmshOptimizeMeshBDS(gf, *m, 2);
       gmshRefineMeshBDS (gf,*m,-CTX.mesh.refine_steps,false);
-      gmshOptimizeMeshBDS(gf, *m, -2,&recover_map);
+      gmshOptimizeMeshBDS(gf, *m, 2,&recover_map);
 
       if (gf->meshAttributes.recombine)
 	{
@@ -1424,7 +1424,7 @@ void meshGFace::operator() (GFace *gf)
     {
       Msg(DEBUG1, "Generating the mesh");
       if(noseam (gf) || gf->getNativeType() == GEntity::GmshModel || gf->edgeLoops.empty()){
-	//gmsh2DMeshGenerator(gf,0, true);
+	//	gmsh2DMeshGenerator(gf,0, true);
 	gmsh2DMeshGenerator(gf,0, false);
       }
       else{
diff --git a/Mesh/meshGFaceBDS.cpp b/Mesh/meshGFaceBDS.cpp
index 4c9b80ff4e6120c94378f606441dc4ffbc4ad257..dbb4cfe6db5d7dd7f57e0ca5d5392ca95d80c827 100644
--- a/Mesh/meshGFaceBDS.cpp
+++ b/Mesh/meshGFaceBDS.cpp
@@ -1,4 +1,4 @@
-// $Id: meshGFaceBDS.cpp,v 1.1 2008-01-24 09:35:41 remacle Exp $
+// $Id: meshGFaceBDS.cpp,v 1.2 2008-01-26 17:47:58 remacle Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -65,6 +65,30 @@ inline double computeEdgeLinearLength(BDS_Point *p1, BDS_Point *p2, GFace *f,
   return l1+l2;
 }
 
+inline double computeEdgeMiddleCoord(BDS_Point *p1, BDS_Point *p2, GFace *f,
+				     double SCALINGU, double SCALINGV)
+{
+
+  if (f->geomType() == GEntity::Plane)
+    return 0.5;
+
+  GPoint GP = f->point (SPoint2(0.5*(p1->u+p2->u)*SCALINGU,0.5*(p1->v+p2->v)*SCALINGV));
+
+  const double dx1 = p1->X-GP.x();
+  const double dy1 = p1->Y-GP.y();
+  const double dz1 = p1->Z-GP.z();
+  const double l1 = sqrt(dx1*dx1+dy1*dy1+dz1*dz1);
+  const double dx2 = p2->X-GP.x();
+  const double dy2 = p2->Y-GP.y();
+  const double dz2 = p2->Z-GP.z();
+  const double l2 = sqrt(dx2*dx2+dy2*dy2+dz2*dz2);
+
+  if (l1 > l2)
+    return 0.25 * (l1+l2) / l1;
+  else
+    return 0.25 * (3*l2-l1)/l2;
+}
+
 inline double computeEdgeLinearLength(BDS_Edge *e, GFace *f, double SCALINGU, double SCALINGV)
 {
   if (f->geomType() == GEntity::Plane)
@@ -386,6 +410,7 @@ void splitEdgePass ( GFace *gf, BDS_Mesh &m, double MAXE_, int &nb_split)
       if ((*it)->numfaces() == 2 && (lone >  MAXE_)){
 	
 	const double coord = 0.5;
+	//const double coord = computeEdgeMiddleCoord((*it)->p1,(*it)->p2,gf,m.scalingU,m.scalingV);
 	BDS_Point *mid ;
 	mid  = m.add_point(++m.MAXPOINTNUMBER,
 			   coord * (*it)->p1->u + (1 - coord) * (*it)->p2->u,
@@ -438,7 +463,6 @@ void smoothVertexPass(GFace *gf, BDS_Mesh &m, int &nb_smooth, bool q)
   }
 }
 
-
 void gmshRefineMeshBDS (GFace *gf, 
 			BDS_Mesh &m, 
 			const int NIT, 
@@ -554,6 +578,104 @@ void gmshRefineMeshBDS (GFace *gf,
   Msg(DEBUG1," ---------------------------------------");
 }
 
+void allowAppearanceofEdge (BDS_Point *p1, BDS_Point *p2){
+}
+
+
+void invalidEdgesPeriodic(BDS_Mesh &m, 
+			  std::map<BDS_Point*,MVertex*> *recover_map,
+			  std::set<BDS_Edge*> &toSplit)
+{
+
+  // first look for degenerated vertices
+
+  std::list<BDS_Edge*>::iterator it = m.edges.begin();
+  std::set<MVertex *> degenerated;
+  while (it != m.edges.end()){
+    BDS_Edge *e = *it;
+    if (!e->deleted && e->numfaces() == 1){
+      std::map<BDS_Point*,MVertex*>::iterator itp1 = recover_map->find(e->p1);
+      std::map<BDS_Point*,MVertex*>::iterator itp2 = recover_map->find(e->p2);    
+      if (itp1 != recover_map->end() && 
+	  itp2 != recover_map->end() && 
+	  itp1->second == itp2->second){
+	degenerated.insert(itp1->second);
+      }
+    }
+    ++it;
+  }
+
+  //  printf("%d degenerated\n",degenerated.size());
+
+  toSplit.clear();
+  it = m.edges.begin();
+  std::map< std::pair < MVertex*, BDS_Point*> , BDS_Edge *> touchPeriodic;
+  while (it != m.edges.end()){
+    BDS_Edge *e = *it;
+    if (!e->deleted && e->numfaces() == 2){
+      std::map<BDS_Point*,MVertex*>::iterator itp1 = recover_map->find(e->p1);
+      std::map<BDS_Point*,MVertex*>::iterator itp2 = recover_map->find(e->p2);    
+      if (itp1 != recover_map->end() && 
+	  itp2 != recover_map->end() && 
+	  itp1->second == itp2->second) toSplit.insert(e);
+      else if (itp1 != recover_map->end() && itp2 == recover_map->end()){
+	std::pair<MVertex*,BDS_Point*> a ( itp1->second, e->p2 );
+	std::map< std::pair < MVertex*, BDS_Point*> , BDS_Edge *> :: iterator itf = 
+	  touchPeriodic.find (a);
+	if (itf == touchPeriodic.end()) touchPeriodic[a] = e;
+	else if (degenerated.find(itp1->second)==degenerated.end()){toSplit.insert(e);toSplit.insert(itf->second);}
+      }    
+      else if (itp1 == recover_map->end() && itp2 != recover_map->end()){
+	std::pair<MVertex*,BDS_Point*> a ( itp2->second, e->p1 );
+	std::map< std::pair < MVertex*, BDS_Point*> , BDS_Edge *> :: iterator itf = 
+	  touchPeriodic.find (a);
+	if (itf == touchPeriodic.end()) touchPeriodic[a] = e;
+	else if (degenerated.find(itp2->second)==degenerated.end()){toSplit.insert(e);toSplit.insert(itf->second);}
+      }    
+    }
+    ++it;
+  }
+  //  printf("%d edges to splitounette\n",toSplit.size());
+}
+
+// consider p1 and p2, 2 vertices that are different in the parametric
+// plane BUT are the same in the real plane
+// consider a vertex v that is internal
+// if p1 is the start and the end of a degenerated edge, then allow edges p1 v and p2 v
+// if not do not allow p1 v and p2 v, split them
+// if p1 p2 exists and it is internal, split it
+
+int gmshSolveInvalidPeriodic(GFace *gf, 
+			     BDS_Mesh &m, 
+			     std::map<BDS_Point*,MVertex*> *recover_map){
+  //  return 0;
+  std::set<BDS_Edge*> toSplit;
+  invalidEdgesPeriodic(m,recover_map,toSplit);
+  std::set<BDS_Edge*>::iterator ite = toSplit.begin();
+  //	printf("%d edges to split\n",toSplit.size());
+  for (;ite !=toSplit.end();++ite){    
+    BDS_Edge *e = *ite;
+    if (!e->deleted && e->numfaces() == 2){
+      const double coord = 0.5;
+      BDS_Point *mid ;
+      //      printf("%d %d\n",e->p1->iD,e->p2->iD);
+      mid  = m.add_point(++m.MAXPOINTNUMBER,
+			 coord * e->p1->u + (1 - coord) * e->p2->u,
+			 coord * e->p1->v + (1 - coord) * e->p2->v,gf);	
+      mid->lcBGM() = BGM_MeshSize(gf,
+				  (coord * e->p1->u + (1 - coord) * e->p2->u)*m.scalingU,
+				  (coord * e->p1->v + (1 - coord) * e->p2->v)*m.scalingV,
+				  mid->X,mid->Y,mid->Z);
+      mid->lc() = 0.5 * ( e->p1->lc() +  e->p2->lc() );		  
+      if(!m.split_edge ( e, mid )) m.del_point(mid);
+    }
+  }
+  int nb_smooth;
+  if (toSplit.size())smoothVertexPass ( gf,m,nb_smooth,true);
+  m.cleanup();  
+  return toSplit.size();
+}
+
 void gmshOptimizeMeshBDS(GFace *gf, 
 			 BDS_Mesh &m, 
 			 const int NIT, 
@@ -562,101 +684,54 @@ void gmshOptimizeMeshBDS(GFace *gf,
   int nb_swap;
   gmshDelaunayizeBDS ( gf, m, nb_swap );
 
-
   for (int ITER = 0;ITER < 3;ITER++){
-    int nb_smooth;
-    smoothVertexPass ( gf,m,nb_smooth,true);
-
     double LIMIT = .1;
     for (int KK=0;KK<4;KK++){
       // swap edges that provide a better configuration
       int NN1 = m.edges.size();
       int NN2 = 0;
       std::list<BDS_Edge*>::iterator it = m.edges.begin();
-      while (1)
-	{
-	  if (NN2++ >= NN1)break;
-	  if (evalSwapForOptimize(*it,gf,m))	
-	    m.swap_edge ( *it , BDS_SwapEdgeTestQuality(false));
-	  ++it;
-	}
-      m.cleanup();  
-    }
-    
-
-    // then collapse small edges (take care not to create overlapping triangles)
-    
-    // in case of periodic surfaces, split all edges that are problematic
-    for (int KK=0;KK<1;KK++){
-      int NN1 = m.edges.size();
-      int NN2 = 0;
-      std::list<BDS_Edge*>::iterator it = m.edges.begin();
-      std::vector<BDS_Edge *> toSplit;
       while (1){
 	if (NN2++ >= NN1)break;
-	if((*it)->numfaces() == 2){
-	  if (recover_map){
-	    std::map<BDS_Point*,MVertex*>::iterator itp1 = recover_map->find((*it)->p1);
-	    std::map<BDS_Point*,MVertex*>::iterator itp2 = recover_map->find((*it)->p2);
-	    BDS_Point *op[2];
-	    (*it)->oppositeof (op);
-	    std::map<BDS_Point*,MVertex*>::iterator itp3 = recover_map->find(op[0]);
-	    std::map<BDS_Point*,MVertex*>::iterator itp4 = recover_map->find(op[1]);
-	    
-	    // this edge goes from one side to the other of the periodic parametric space !
-	    if (itp1 != recover_map->end() && itp2 != recover_map->end() && itp1->second == itp2->second)
-	      toSplit.push_back(*it);
-	    // this edge is internal but the 2 adjacent triangles are the same in the real space
-	    if (itp3 != recover_map->end() && itp4 != recover_map->end() && itp3->second == itp4->second)
-	      {
-		// the first point is internal, split both edges that go from this one to the two opposites (that are the same)
-		BDS_Edge *e1 , *e2 ;
-		//		  printf ("edge prob %d %d\n",(*it)->p1->iD,(*it)->p2->iD);
-		if (itp1 == recover_map->end()){
-		  e1 = m.find_edge ((*it)->p1,itp3->first);
-		  e2 = m.find_edge ((*it)->p1,itp4->first);
-		  if (e1 && e1->numfaces() == 2)
-		    toSplit.push_back(e1);
-		  if (e2 && e2->numfaces() == 2)
-		    toSplit.push_back(e2);
-		}
-		else if (itp2 == recover_map->end()){
-		  e1 = m.find_edge ((*it)->p2,itp3->first);
-		  e2 = m.find_edge ((*it)->p2,itp4->first);
-		  if (e1 && e1->numfaces() == 2)
-		    toSplit.push_back(e1);				      
-		  if (e2 && e2->numfaces() == 2)
-		    toSplit.push_back(e2);
-		}
-		else{
-		  printf("zarbi\n");
-		}
-	      }
-	    //	      toSplit.push_back(*it);	    
-	  }
-	}
+	if (evalSwapForOptimize(*it,gf,m))	
+	  m.swap_edge ( *it , BDS_SwapEdgeTestQuality(false));
 	++it;
       }
-      //	printf("%d edges to split\n",toSplit.size());
-      for (int i=0;i<toSplit.size();i++){
-	BDS_Edge *e = toSplit[i];
-	if (!e->deleted){
-	  const double coord = 0.5;
-	  BDS_Point *mid ;
-	  mid  = m.add_point(++m.MAXPOINTNUMBER,
-			     coord * e->p1->u + (1 - coord) * e->p2->u,
-			     coord * e->p1->v + (1 - coord) * e->p2->v,gf);	
-	  //	    printf("%d %d %d\n",e->p1->iD,e->p2->iD,mid->iD);
-	  mid->lcBGM() = BGM_MeshSize(gf,
-				      (coord * e->p1->u + (1 - coord) * e->p2->u)*m.scalingU,
-				      (coord * e->p1->v + (1 - coord) * e->p2->v)*m.scalingV,
-				      mid->X,mid->Y,mid->Z);
-	  mid->lc() = 0.5 * ( e->p1->lc() +  e->p2->lc() );		  
-	  if(!m.split_edge ( e, mid )) m.del_point(mid);
-	}
-      }
       m.cleanup();  
+      int nb_smooth;
+      smoothVertexPass ( gf,m,nb_smooth,true);
     }
   }
+
+  int nbSplit = 0;
+  if (recover_map){
+    while(gmshSolveInvalidPeriodic(gf,m,recover_map)){}  
+  }
 }
 
+// DELAUNAY BDS
+
+
+
+// void delaunayPointInsertionBDS ( GFace *gf, BDS_Mesh &m, BDS_Vertex *v, BDS_Face *f){
+//   const double p[2] = {v->u,v->v};
+
+//   BDS_Edge *e1 = f->e1;
+//   BDS_Edge *e2 = f->e2;
+//   BDS_Edge *e3 = f->e3;
+
+//   m.split_face ( f , v );
+  
+//   recur_delaunay_swap ( e1 );
+//   recur_delaunay_swap ( e2 );
+//   recur_delaunay_swap ( e3 );
+
+//   return;
+
+//   BDS_Point *n2[4];
+//   f1->getNodes(n1);
+
+//   const double a[2] = {v->u,v->v};
+//   const double b[2] = {v->u,v->v};
+//   const double c[2] = {v->u,v->v};
+// } 
diff --git a/benchmarks/testsuite/testsuite.sh b/benchmarks/testsuite/testsuite.sh
index 9b53505ece00ba2b499c3389df1aaca6e629bc50..5099c38143c6cfcbf8d248866446ffc02d637af1 100755
--- a/benchmarks/testsuite/testsuite.sh
+++ b/benchmarks/testsuite/testsuite.sh
@@ -9,5 +9,6 @@ date >> statreport.dat
 ../../bin/gmsh sphere_Rhino3D_default.igs -clscale 1 -v 0 -2 -append_statreport statreport.dat
 ../../bin/gmsh Cone_1.brep -clscale 1 -v 0 -2 -append_statreport statreport.dat
 ../../bin/gmsh Cylinder_1.brep -clscale 1 -v 0 -2 -append_statreport statreport.dat
+../../bin/gmsh Torus_1.brep -clscale 300 -v 0 -2 -append_statreport statreport.dat
 ../../bin/gmsh A319.geo -clscale 3 -v 0 -2 -append_statreport statreport.dat