From fa055b8a85c04216da092b3f76f8a875f9d43241 Mon Sep 17 00:00:00 2001
From: Jean-Francois Remacle <jean-francois.remacle@uclouvain.be>
Date: Tue, 7 May 2013 14:38:44 +0000
Subject: [PATCH] modified boundary layers spallart almaras is kinda working

---
 Geo/CMakeLists.txt                            |   2 +
 Geo/GModel.h                                  |   9 +
 Geo/OCCFace.cpp                               |  26 ++-
 Geo/STensor3.cpp                              |   2 +
 .../boundaryLayersData.cpp                    | 177 ++++++++++++++--
 Geo/boundaryLayersData.h                      | 107 ++++++++++
 Geo/intersectCurveSurface.cpp                 |  45 ++--
 Geo/intersectCurveSurface.h                   |   1 +
 Mesh/CMakeLists.txt                           |   2 +-
 Mesh/Field.cpp                                |  36 ++++
 Mesh/Field.h                                  |   3 +
 Mesh/meshGEdge.cpp                            |  62 +++++-
 Mesh/meshGFace.cpp                            |   8 +-
 Mesh/meshGFaceBoundaryLayers.h                | 194 ------------------
 Mesh/meshGRegion.cpp                          |   6 +-
 Mesh/meshGRegionBoundaryLayers.cpp            |   2 +-
 Mesh/meshGRegionDelaunayInsertion.cpp         |  23 ++-
 Mesh/surfaceFiller.cpp                        |  37 +++-
 Mesh/yamakawa.cpp                             |   8 +-
 Numeric/Numeric.cpp                           |   4 +
 Numeric/simpleFunction.h                      |   2 +-
 benchmarks/3d/submarine/submarine_simple.geo  |  21 +-
 wrappers/gmshpy/gmshGeo.i                     |   2 +
 23 files changed, 498 insertions(+), 281 deletions(-)
 rename Mesh/meshGFaceBoundaryLayers.cpp => Geo/boundaryLayersData.cpp (68%)
 create mode 100644 Geo/boundaryLayersData.h
 delete mode 100644 Mesh/meshGFaceBoundaryLayers.h

diff --git a/Geo/CMakeLists.txt b/Geo/CMakeLists.txt
index f257938696..f241e458cd 100644
--- a/Geo/CMakeLists.txt
+++ b/Geo/CMakeLists.txt
@@ -4,6 +4,8 @@
 # bugs and problems to the public mailing list <gmsh@geuz.org>.
 
 set(SRC
+  boundaryLayersData.cpp
+  distanceToMesh.cpp
   intersectCurveSurface.cpp
   GEntity.cpp STensor3.cpp
     GVertex.cpp GEdge.cpp GFace.cpp GRegion.cpp
diff --git a/Geo/GModel.h b/Geo/GModel.h
index 9b6e59444f..5f6dbf1d73 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -17,6 +17,7 @@
 #include "GRegion.h"
 #include "SPoint3.h"
 #include "SBoundingBox3d.h"
+#include "boundaryLayersData.h"
 template <class scalar> class simpleFunction;
 
 class FM_Internals;
@@ -151,10 +152,15 @@ class GModel
   std::set<int> meshPartitions;
   int partitionSize[2];
 
+  // boundary layer columns i.e. list of vertices that form columns
+  // in boundary layers
+  BoundaryLayerColumns _columns; 
+
  public:
   GModel(std::string name="");
   virtual ~GModel();
 
+
   // the static list of all loaded models
   static std::vector<GModel*> list;
 
@@ -266,6 +272,9 @@ class GModel
   std::vector<GEdge*> bindingsGetEdges();
   std::vector<GVertex*> bindingsGetVertices();
 
+  // get the boundary layer columns
+  BoundaryLayerColumns *getColumns () {return &_columns;}
+
   // add/remove an entity in the model
   void add(GRegion *r) { regions.insert(r); }
   void add(GFace *f) { faces.insert(f); }
diff --git a/Geo/OCCFace.cpp b/Geo/OCCFace.cpp
index ebe176dd46..a3dfb968c3 100644
--- a/Geo/OCCFace.cpp
+++ b/Geo/OCCFace.cpp
@@ -163,8 +163,30 @@ void OCCFace::secondDer(const SPoint2 &param,
 GPoint OCCFace::point(double par1, double par2) const
 {
   double pp[2] = {par1, par2};
-  gp_Pnt val = occface->Value(par1, par2);
-  return GPoint(val.X(), val.Y(), val.Z(), this, pp);
+  double umin2, umax2, vmin2, vmax2;
+  ShapeAnalysis::GetFaceUVBounds(s, umin2, umax2, vmin2, vmax2);
+  
+  double du = umax2 - umin2;
+  double dv = vmax2 - vmin2;
+
+  if (par1 > (umax2+.1*du) || par1 < (umin2-.1*du) ||
+      par2 > (vmax2+.1*dv) || par2 < (vmin2-.1*dv))
+    {
+      GPoint p(0,0,0, this, pp);
+      p.setNoSuccess();
+      return p;
+    }
+
+  try{
+    gp_Pnt val;
+    val = occface->Value(par1, par2);
+    return GPoint(val.X(), val.Y(), val.Z(), this, pp);
+  }
+  catch(Standard_OutOfRange){
+    GPoint p(0,0,0, this, pp);
+    p.setNoSuccess();
+    return p;
+  }
 }
 
 GPoint OCCFace::closestPoint(const SPoint3 &qp, const double initialGuess[2]) const
diff --git a/Geo/STensor3.cpp b/Geo/STensor3.cpp
index a282ad4f04..63ba5ed059 100644
--- a/Geo/STensor3.cpp
+++ b/Geo/STensor3.cpp
@@ -51,6 +51,8 @@ SMetric3 intersection (const SMetric3 &m1, const SMetric3 &m2)
 // preserve orientation of m1 !!!
 SMetric3 intersection_conserveM1 (const SMetric3 &m1, const SMetric3 &m2)
 {
+  // we should do
+  // return intersection (m1,m2);
   fullMatrix<double> V(3,3);
   fullVector<double> S(3);
   m1.eig(V,S,true);
diff --git a/Mesh/meshGFaceBoundaryLayers.cpp b/Geo/boundaryLayersData.cpp
similarity index 68%
rename from Mesh/meshGFaceBoundaryLayers.cpp
rename to Geo/boundaryLayersData.cpp
index fc8850ef30..6b01a2c6f7 100644
--- a/Mesh/meshGFaceBoundaryLayers.cpp
+++ b/Geo/boundaryLayersData.cpp
@@ -9,7 +9,7 @@
 #include "MLine.h"
 #include "MTriangle.h"
 #include "MEdge.h"
-#include "meshGFaceBoundaryLayers.h"
+#include "boundaryLayersData.h"
 #include "Field.h"
 
 SVector3 interiorNormal (SPoint2 p1, SPoint2 p2, SPoint2 p3)
@@ -90,11 +90,105 @@ void buildMeshMetric(GFace *gf, double *uv, SMetric3 &m, double metric[3])
   metric[2] = res[1][1];
 }
 
-BoundaryLayerColumns* buildAdditionalPoints2D (GFace *gf)
+edgeColumn BoundaryLayerColumns::getColumns(MVertex *v1, MVertex *v2 , int side)
+{
+  Equal_Edge aaa;
+  MEdge e(v1, v2);
+  std::map<MVertex*,BoundaryLayerFan>::const_iterator it1 = _fans.find(v1);
+  std::map<MVertex*,BoundaryLayerFan>::const_iterator it2 = _fans.find(v2);
+  int N1 = getNbColumns(v1) ;
+  int N2 = getNbColumns(v2) ;
+  
+  
+  int nbSides = _normals.count(e);
+  
+  // if (nbSides != 1)printf("I'm here %d sides\n",nbSides);
+  // Standard case, only two extruded columns from the two vertices
+  if (N1 == 1 && N2 == 1) return edgeColumn(getColumn(v1,0),getColumn(v2,0));
+  // one fan on
+  if (nbSides == 1){
+    if (it1 != _fans.end() && it2 == _fans.end() ){
+      if (aaa(it1->second._e1,e))
+	return edgeColumn(getColumn (v1,0),getColumn(v2,0));
+      else
+	return edgeColumn(getColumn (v1,N1-1),getColumn(v2,0));
+    }
+    if (it2 != _fans.end() && it1 == _fans.end() ){
+      if (aaa(it2->second._e1,e))
+	return edgeColumn(getColumn (v1,0),getColumn(v2,0));
+      else
+	return edgeColumn(getColumn (v1,0),getColumn(v2,N2-1));
+    }
+    if (it2 != _fans.end() && it1 != _fans.end() ){
+      int c1, c2;
+      if (aaa(it1->second._e1,e))
+	c1 =  0;
+      else
+	c1 = N1-1;
+      if (aaa(it2->second._e1,e))
+	c2 =  0;
+      else
+	c2 = N2-1;
+      return edgeColumn(getColumn (v1,c1),getColumn(v2,c2));
+    }
+    // fan on the right
+    if (N1 == 1 || N2 == 2){
+      const BoundaryLayerData & c10 = getColumn(v1,0);
+      const BoundaryLayerData & c20 = getColumn(v2,0);
+      const BoundaryLayerData & c21 = getColumn(v2,1);
+      if (dot(c10._n,c20._n) > dot(c10._n,c21._n) ) return edgeColumn(c10,c20);
+      else return edgeColumn(c10,c21);
+    }
+    // fan on the left
+    if (N1 == 2 || N2 == 1){
+      const BoundaryLayerData & c10 = getColumn(v1,0);
+      const BoundaryLayerData & c11 = getColumn(v1,1);
+      const BoundaryLayerData & c20 = getColumn(v2,0);
+      if (dot(c10._n,c20._n) > dot(c11._n,c20._n) ) return edgeColumn(c10,c20);
+      else return edgeColumn(c11,c20);
+    }
+    
+    //      Msg::Error ("Impossible Boundary Layer Configuration : one side and no fans %d %d",N1,N2);
+    // FIXME WRONG
+    return N1 ? edgeColumn (getColumn (v1,0),getColumn(v1,0)) :
+      edgeColumn (getColumn (v2,0),getColumn(v2,0));
+  }
+  else if (nbSides == 2){
+    int i1=0,i2=1,j1=0,j2=1;
+    if (it1 != _fans.end()){
+      i1 =  aaa(it1->second._e1,e) ? 0 : N1-1;
+      i2 = !aaa(it1->second._e1,e) ? 0 : N1-1;
+    }
+    if (it2 != _fans.end()){
+      j1 =  aaa(it2->second._e1,e) ? 0 : N2-1;
+      j2 = !aaa(it2->second._e1,e) ? 0 : N2-1;
+    }
+    const BoundaryLayerData & c10 = getColumn(v1,i1);
+    const BoundaryLayerData & c11 = getColumn(v1,i2);
+    const BoundaryLayerData & c20 = getColumn(v2,j1);
+    const BoundaryLayerData & c21 = getColumn(v2,j2);
+    
+    if (side == 0){
+      if (dot(c10._n,c20._n) > dot(c10._n,c21._n) ) return edgeColumn(c10,c20);
+      else return edgeColumn(c10,c21);
+    }
+    if (side == 1){
+      if (dot(c11._n,c20._n) > dot(c11._n,c21._n) ) return edgeColumn(c11,c20);
+      else return edgeColumn(c11,c21);
+    }
+  }
+  
+  Msg::Error("Not yet Done in BoundaryLayerData nbSides = %d, ",nbSides );
+  static BoundaryLayerData error;
+  static edgeColumn error2(error, error);
+  return error2;
+}
+
+
+bool buildAdditionalPoints2D (GFace *gf, BoundaryLayerColumns *_columns)
 {
-  //  return 0;
 #if !defined(HAVE_ANN)
-  return 0;
+  return false;
 #else
 
   FieldManager *fields = gf->model()->getFields();
@@ -104,11 +198,11 @@ BoundaryLayerColumns* buildAdditionalPoints2D (GFace *gf)
   Field *bl_field = fields->get(fields->getBoundaryLayerField());
   BoundaryLayerField *blf = dynamic_cast<BoundaryLayerField*> (bl_field);
 
-  if (!blf)return 0;
+  if (!blf)return false;
 
   double _treshold = blf->fan_angle * M_PI / 180 ;
 
-  BoundaryLayerColumns * _columns = new BoundaryLayerColumns;
+  //  BoundaryLayerColumns * _columns = new BoundaryLayerColumns;
 
   // assume a field that i) gives us the closest point on one of the BL components
   // ii) Gives us mesh sizes in the 3 directions.
@@ -120,18 +214,19 @@ BoundaryLayerColumns* buildAdditionalPoints2D (GFace *gf)
   std::list<GEdge*>::iterator ite = edges.begin();
   std::set<MVertex*> _vertices;
   while(ite != edges.end()){
-    for(unsigned int i = 0; i< (*ite)->lines.size(); i++){
-      MVertex *v1 = (*ite)->lines[i]->getVertex(0);
-      MVertex *v2 = (*ite)->lines[i]->getVertex(1);
-      _columns->_non_manifold_edges.insert(std::make_pair(v1,v2));
-      _columns->_non_manifold_edges.insert(std::make_pair(v2,v1));
-      _vertices.insert(v1);
-      _vertices.insert(v2);
+    if (blf->isEdgeBL ((*ite)->tag())){
+      for(unsigned int i = 0; i< (*ite)->lines.size(); i++){
+	MVertex *v1 = (*ite)->lines[i]->getVertex(0);
+	MVertex *v2 = (*ite)->lines[i]->getVertex(1);
+	_columns->_non_manifold_edges.insert(std::make_pair(v1,v2));
+	_columns->_non_manifold_edges.insert(std::make_pair(v2,v1));
+	_vertices.insert(v1);
+	  _vertices.insert(v2);
+      }
     }
     ++ite;
   }
-
-  //  printf("%d boundary points\n",_vertices.size());
+  if (!_vertices.size())return false;
 
   // assume that the initial mesh has been created i.e. that there exist
   // triangles inside the domain. Triangles are used to define
@@ -215,12 +310,12 @@ BoundaryLayerColumns* buildAdditionalPoints2D (GFace *gf)
       _dirs.push_back(x1);
       x2.normalize();
       _dirs.push_back(x2);
-      printf("%g %g vs %g %g\n",N1[0].x(),N1[0].y(),N1[1].x(),N1[1].y());
-      printf("%g %g vs %g %g\n",N2[0].x(),N2[0].y(),N3[0].x(),N3[0].y());
-      printf("%g %g vs %g %g\n",x1.x(),x1.y(),x2.x(),x2.y());
+      //      printf("%g %g vs %g %g\n",N1[0].x(),N1[0].y(),N1[1].x(),N1[1].y());
+      //      printf("%g %g vs %g %g\n",N2[0].x(),N2[0].y(),N3[0].x(),N3[0].y());
+      //      printf("%g %g vs %g %g\n",x1.x(),x1.y(),x2.x(),x2.y());
     }
     // STANDARD CASE, one vertex connected to two neighboring vertices
-    if (_connections.size() == 2){
+    else if (_connections.size() == 2){
       MEdge e1 (*it,_connections[0]);
       MEdge e2 (*it,_connections[1]);
       //LL = 0.5 * (e1.length() + e2.length());
@@ -288,6 +383,48 @@ BoundaryLayerColumns* buildAdditionalPoints2D (GFace *gf)
 	  }
 	}
       }
+    }    
+    else if (_connections.size() == 1){
+      MEdge e1 (*it,_connections[0]);
+      SPoint2 p0,p1;
+      reparamMeshEdgeOnFace(*it,_connections[0], gf, p0, p1);
+      std::vector<SVector3> N1;
+      for (std::multimap<MEdge,SVector3,Less_Edge>::iterator itm =
+             _columns->_normals.lower_bound(e1);
+	    itm != _columns->_normals.upper_bound(e1); ++itm) N1.push_back(itm->second);
+      // two sides at that point : end point of one embedded edge       
+      // the fan angle is equal to PI
+      
+      if (N1.size() == 2){
+	int fanSize = M_PI /  _treshold;
+	printf("%g %g --> %g %g \n",e1.getVertex(0)->x(),e1.getVertex(0)->y(),
+	       e1.getVertex(1)->x(),e1.getVertex(1)->y());
+	printf("N1.size = %d %g %g %g %g\n",N1.size(),N1[0].x(),N1[0].y(),N1[1].x(),N1[1].y());
+
+	double alpha1 = atan2(N1[0].y(),N1[0].x());
+	double alpha2 = atan2(N1[1].y(),N1[1].x());
+	double alpha3 = atan2(p1.y()-p0.y(),p1.x()-p0.x());
+	double AMAX = std::max(alpha1,alpha2);
+	double AMIN = std::min(alpha1,alpha2);
+	if (alpha3 > AMAX){
+	  AMIN += M_PI;
+	  AMAX += M_PI;
+	} 
+	if ( AMAX - AMIN >= M_PI){
+	  double temp = AMAX;
+	  AMAX = AMIN + 2*M_PI;
+	  AMIN = temp;
+	}
+	_columns->addFan (*it,e1,e1,true);
+	for (int i=-1; i<=fanSize; i++){
+	  double t = (double)(i+1)/ (fanSize+1);
+	  double alpha = t * AMAX + (1.-t)* AMIN;
+	  SVector3 x (cos(alpha),sin(alpha),0);
+	  printf("%d %g %g %g\n",i,x.x(),x.y(),alpha);
+	  x.normalize();
+	  _dirs.push_back(x);
+	}
+      }
     }
 
     //    if (_dirs.size() > 1)printf("%d directions\n",_dirs.size());
@@ -389,7 +526,7 @@ BoundaryLayerColumns* buildAdditionalPoints2D (GFace *gf)
 
   // END OF DEBUG STUFF
 
-  return _columns;
+  return 1;
 #endif
 }
 
diff --git a/Geo/boundaryLayersData.h b/Geo/boundaryLayersData.h
new file mode 100644
index 0000000000..be5f0d13b4
--- /dev/null
+++ b/Geo/boundaryLayersData.h
@@ -0,0 +1,107 @@
+// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh@geuz.org>.
+
+#ifndef _BNDRYLRDATA_
+#define _BNDRYLRDATA_
+
+#include "SVector3.h"
+#include "STensor3.h"
+#include "MEdge.h"
+#include <map>
+#include <set>
+
+class Field;
+class GFace;
+class GRegion;
+class MTriangle;
+
+struct BoundaryLayerData
+{
+  SVector3 _n;
+  std::vector<MVertex*> _column;
+  std::vector<SMetric3> _metrics;
+  BoundaryLayerData(){}
+  BoundaryLayerData(const SVector3 & dir,
+                    std::vector<MVertex*> column,
+                    std::vector<SMetric3> metrics)
+    : _n(dir), _column(column), _metrics(metrics){}
+};
+
+struct BoundaryLayerFan
+{
+  MEdge _e1, _e2;
+  bool sense;
+  BoundaryLayerFan(MEdge e1, MEdge e2 , bool s = true)
+    : _e1(e1),_e2(e2) , sense (s){}
+};
+
+struct edgeColumn {
+  const BoundaryLayerData &_c1, &_c2;
+  edgeColumn(const BoundaryLayerData &c1, const BoundaryLayerData &c2)
+    : _c1(c1), _c2(c2){}
+};
+
+class BoundaryLayerColumns
+{
+  std::multimap<MVertex*, BoundaryLayerData>  _data;
+  std::map<MVertex*, BoundaryLayerFan> _fans;
+public:
+  size_t size () const {return _data.size();}
+  typedef std::multimap<MVertex*,BoundaryLayerData>::iterator iter;
+  typedef std::map<MVertex*, BoundaryLayerFan>::iterator iterf;
+  std::multimap<MVertex*, MVertex*> _non_manifold_edges;
+  std::multimap<MVertex*,MTriangle*> _non_manifold_faces;
+  std::multimap<MEdge, SVector3, Less_Edge> _normals;
+  iter begin() { return _data.begin(); }
+  iter end() { return _data.end(); }
+  iterf beginf() { return _fans.begin(); }
+  iterf endf() { return _fans.end(); }
+  BoundaryLayerColumns (){}
+  inline void addColumn(const SVector3 &dir, MVertex* v,
+                        std::vector<MVertex*> _column,
+                        std::vector<SMetric3> _metrics)
+  {
+    _data.insert (std::make_pair(v,BoundaryLayerData(dir, _column,_metrics)));
+  }
+  inline void addFan(MVertex *v, MEdge e1, MEdge e2, bool s)
+  {
+    _fans.insert(std::make_pair(v,BoundaryLayerFan(e1,e2,s)));
+  }
+  inline const BoundaryLayerData &getColumn(MVertex *v, MEdge e)
+  {
+    std::map<MVertex*,BoundaryLayerFan>::const_iterator it = _fans.find(v);
+    int N = getNbColumns(v) ;
+    if (N == 1) return getColumn(v, 0);
+    Equal_Edge aaa;
+    if (it != _fans.end()){
+      if (aaa(it->second._e1, e))
+	return getColumn(v, 0);
+      else
+	return getColumn(v, N-1);
+    }
+    Msg::Error("Cannot handle embedded lines in boundary layers");
+    static BoundaryLayerData error;
+    return error;
+  }
+  edgeColumn getColumns(MVertex *v1, MVertex *v2 , int side);
+  inline int getNbColumns(MVertex *v) { return _data.count(v); }
+  inline const BoundaryLayerData &getColumn(MVertex *v, int iColumn)
+  {
+    int count = 0;
+    for(std::multimap<MVertex*,BoundaryLayerData>::iterator itm  = _data.lower_bound(v);
+        itm != _data.upper_bound(v); ++itm){
+      if (count++ == iColumn) return itm->second;
+    }
+    static BoundaryLayerData error;
+    return error;
+  }
+  void filterPoints();
+};
+
+bool buildAdditionalPoints2D (GFace *gf, BoundaryLayerColumns * ) ;
+bool buildAdditionalPoints3D (GRegion *gr, BoundaryLayerColumns * ) ;
+void buildMeshMetric(GFace *gf, double *uv, SMetric3 &m, double metric[3]);
+
+#endif
diff --git a/Geo/intersectCurveSurface.cpp b/Geo/intersectCurveSurface.cpp
index 7ac1ed2584..c125bef4ab 100644
--- a/Geo/intersectCurveSurface.cpp
+++ b/Geo/intersectCurveSurface.cpp
@@ -15,22 +15,30 @@ struct intersectCurveSurfaceData
   { }
 
   bool apply (double newPoint[3]){
-    fullVector<double> uvt(3);
-    uvt(0) = newPoint[0];
-    uvt(1) = newPoint[1];
-    uvt(2) = newPoint[2];
-    fullVector<double> res(3);
-    _kaboom(uvt,res,this);
-    //    printf("start with %12.5E\n",res.norm());
-    if (res.norm() < epsilon)return true;
-
-    if(newton_fd(_kaboom, uvt, this)){
-      //      printf("--- CONVERGED -----------\n");
-      newPoint[0] = uvt(0);
-      newPoint[1] = uvt(1);
-      newPoint[2] = uvt(2);
-      return true;
-    }    
+    try {
+      fullVector<double> uvt(3);
+      uvt(0) = newPoint[0];
+      uvt(1) = newPoint[1];
+      uvt(2) = newPoint[2];
+      fullVector<double> res(3);
+      _kaboom(uvt,res,this);
+      //      printf("start with %12.5E\n",res.norm());
+      if (res.norm() < epsilon)return true;
+      
+      
+      if(newton_fd(_kaboom, uvt, this)){
+	//      printf("--- CONVERGED -----------\n");
+	newPoint[0] = uvt(0);
+	newPoint[1] = uvt(1);
+	newPoint[2] = uvt(2);
+	//	printf("newton done\n");
+	return true;
+      }    
+    }
+    catch (...){
+      //      printf("intersect curve surface failed !\n");
+    }
+    //    printf("newton failsed\n");
     return false;
   }
 };
@@ -38,12 +46,15 @@ struct intersectCurveSurfaceData
 void _kaboom(fullVector<double> &uvt, 
 	     fullVector<double> &res, void *_data){
   intersectCurveSurfaceData *data = (intersectCurveSurfaceData*)_data;
+  //  printf("coucuo1 %g %g\n",uvt(0),uvt(1));
   SPoint3 s = data->s(uvt(0),uvt(1));
+  //  printf("coucuo1\n");
   SPoint3 c = data->c(uvt(2));
+  //  printf("coucuo1\n");
   res(0) = s.x() - c.x();
   res(1) = s.y() - c.y();
   res(2) = s.z() - c.z();
-  //  printf("%g %g %g vs %g %g %g \n",s.x(),s.y(),s.z(),c.x(),c.y(),c.z());
+  //    printf("%g %g %g vs %g %g %g \n",s.x(),s.y(),s.z(),c.x(),c.y(),c.z());
 }
 
 int intersectCurveSurface (curveFunctor &c, surfaceFunctor & s, double uvt[3], double epsilon){
diff --git a/Geo/intersectCurveSurface.h b/Geo/intersectCurveSurface.h
index b3c14a7375..4c9fb5d247 100644
--- a/Geo/intersectCurveSurface.h
+++ b/Geo/intersectCurveSurface.h
@@ -35,6 +35,7 @@ public :
   surfaceFunctorGFace(const GFace *_gf) : gf(_gf) {}
   virtual SPoint3 operator () (double u, double v) const {
     GPoint gp =  gf->point(u,v);
+    if (! gp.succeeded())throw gf;
     return SPoint3(gp.x(),gp.y(),gp.z());
   }
 };
diff --git a/Mesh/CMakeLists.txt b/Mesh/CMakeLists.txt
index b50d4d34d6..5d365bec22 100644
--- a/Mesh/CMakeLists.txt
+++ b/Mesh/CMakeLists.txt
@@ -12,7 +12,7 @@ set(SRC
       meshGFaceTransfinite.cpp meshGFaceExtruded.cpp 
       meshGFaceBamg.cpp meshGFaceBDS.cpp meshGFaceDelaunayInsertion.cpp 
       meshGFaceLloyd.cpp meshGFaceOptimize.cpp 
-      meshGFaceQuadrilateralize.cpp meshGFaceBoundaryLayers.cpp
+      meshGFaceQuadrilateralize.cpp 
     meshGRegion.cpp meshGRegionBoundaryLayers.cpp
       meshGRegionDelaunayInsertion.cpp meshGRegionTransfinite.cpp 
       meshGRegionExtruded.cpp  meshGRegionCarveHole.cpp 
diff --git a/Mesh/Field.cpp b/Mesh/Field.cpp
index 0f4ea7073a..b6ed27696d 100644
--- a/Mesh/Field.cpp
+++ b/Mesh/Field.cpp
@@ -1859,6 +1859,42 @@ double BoundaryLayerField::operator() (double x, double y, double z, GEntity *ge
   return std::min (hfar,lc);
 }
 
+// assume that the closest point is one of the model vertices
+void BoundaryLayerField::computeFor1dMesh (double x, double y, double z,
+					   SMetric3 &metr)
+{
+  double xpk,ypk,zpk;
+  double distk = 1.e22;
+  for(std::list<int>::iterator it = nodes_id.begin();
+      it != nodes_id.end(); ++it) {
+    GVertex *v = GModel::current()->getVertexByTag(*it);    
+    double xp = v->x();
+    double yp = v->y();
+    double zp = v->z();
+    const double dist = sqrt ((x-xp)*(x-xp)+
+			      (y-yp)*(y-yp)+
+			      (z-zp)*(z-zp));
+    if (dist < distk){
+      distk = dist;
+      xpk=xp;
+      ypk=yp;
+      zpk=zp;
+    }
+  }
+
+  const double ll1   = (distk*(ratio-1) + hwall_n) / (1. + 0.5 * (ratio - 1));
+    //const double ll1   = (distk*(ratio-1) + hwall_n) / (1.);
+  double lc_n  = std::min(ll1,hfar);
+
+  if (distk > thickness) lc_n = hfar;
+  lc_n = std::max(lc_n, CTX::instance()->mesh.lcMin);
+  lc_n = std::min(lc_n, CTX::instance()->mesh.lcMax);
+  SVector3 t1= SVector3(x-xpk,y-ypk,z-zpk);
+  t1.normalize();
+  metr = buildMetricTangentToCurve(t1,lc_n,lc_n);  
+}
+
+
 void BoundaryLayerField::operator() (AttractorField *cc, double dist,
                                      double x, double y, double z,
                                      SMetric3 &metr, GEntity *ge)
diff --git a/Mesh/Field.h b/Mesh/Field.h
index 4ebfe745f7..743267a7b7 100644
--- a/Mesh/Field.h
+++ b/Mesh/Field.h
@@ -156,6 +156,9 @@ class BoundaryLayerField : public Field {
   virtual double operator() (double x, double y, double z, GEntity *ge=0);
   virtual void operator() (double x, double y, double z, SMetric3 &metr, GEntity *ge=0);
   bool isFaceBL (int iF) const {return std::find(faces_id.begin(),faces_id.end(),iF) != faces_id.end();}
+  bool isEdgeBL (int iE) const {return std::find(edges_id.begin(),edges_id.end(),iE) != edges_id.end();}
+  bool isVertexBL (int iV) const {return std::find(nodes_id.begin(),nodes_id.end(),iV) != nodes_id.end();}
+  void computeFor1dMesh(double x, double y, double z, SMetric3 &metr);
 };
 #endif
 class FieldOptionString : public FieldOption
diff --git a/Mesh/meshGEdge.cpp b/Mesh/meshGEdge.cpp
index 3bcd86a9d3..65d0172e13 100644
--- a/Mesh/meshGEdge.cpp
+++ b/Mesh/meshGEdge.cpp
@@ -9,6 +9,7 @@
 #include "GEdge.h"
 #include "MLine.h"
 #include "BackgroundMesh.h"
+#include "boundaryLayersData.h"
 #include "Numeric.h"
 #include "GmshMessage.h"
 #include "Context.h"
@@ -96,6 +97,16 @@ static double F_Lc(GEdge *ge, double t)
 
 static double F_Lc_aniso(GEdge *ge, double t)
 {
+#if defined(HAVE_ANN)
+  FieldManager *fields = ge->model()->getFields();
+  BoundaryLayerField *blf = 0;
+  Field *bl_field = fields->get(fields->getBoundaryLayerField());
+  blf = dynamic_cast<BoundaryLayerField*> (bl_field);
+#else
+  bool blf = false;
+#endif
+  
+
   GPoint p = ge->point(t);
   SMetric3 lc_here;
 
@@ -110,6 +121,14 @@ static double F_Lc_aniso(GEdge *ge, double t)
   else
     lc_here = BGM_MeshMetric(ge, t, 0, p.x(), p.y(), p.z());
 
+#if defined(HAVE_ANN)
+  if (blf && !blf->isEdgeBL(ge->tag())){
+    SMetric3 lc_bgm;
+    blf->computeFor1dMesh ( p.x(), p.y(), p.z() , lc_bgm );
+    lc_here = intersection_conserveM1 (lc_here, lc_bgm );			    
+  }
+#endif
+
   SVector3 der = ge->firstDer(t);
   double lSquared = dot(der, lc_here, der);
   return sqrt(lSquared);
@@ -294,15 +313,17 @@ static void printFandPrimitive(int tag, std::vector<IntPoint> &Points)
 }
 */
 
+void createBoundaryLayerPointsForGEdge (GEdge *ge, double &t_begin, double &t_end)
+{
+}
+
 void meshGEdge::operator() (GEdge *ge)
 {
 #if defined(HAVE_ANN)
   FieldManager *fields = ge->model()->getFields();
   BoundaryLayerField *blf = 0;
-  if(fields->getBackgroundField() > 0){
-    Field *bl_field = fields->get(fields->getBoundaryLayerField());
-    blf = dynamic_cast<BoundaryLayerField*> (bl_field);
-  }
+  Field *bl_field = fields->get(fields->getBoundaryLayerField());
+  blf = dynamic_cast<BoundaryLayerField*> (bl_field);
 #else
   bool blf = false;
 #endif
@@ -372,9 +393,7 @@ void meshGEdge::operator() (GEdge *ge)
     N = ge->meshAttributes.nbPointsTransfinite;
   }
   else{
-    if (CTX::instance()->mesh.algo2d == ALGO_2D_BAMG
-	//	|| CTX::instance()->mesh.algo2d == ALGO_2D_PACK_PRLGRMS
-	|| blf){
+    if (CTX::instance()->mesh.algo2d == ALGO_2D_BAMG || blf){
       a = Integration(ge, t_begin, t_end, F_Lc_aniso, Points,
                       CTX::instance()->mesh.lcIntegrationPrecision);
     }
@@ -391,8 +410,7 @@ void meshGEdge::operator() (GEdge *ge)
     }
     a = smoothPrimitive(ge, sqrt(CTX::instance()->mesh.smoothRatio), Points);
     N = std::max(ge->minimumMeshSegments() + 1, (int)(a + 1.99));
-   
-}
+  }
 
   // force odd number of points if blossom is used for recombination
   if(ge->meshAttributes.method != MESH_TRANSFINITE &&
@@ -477,6 +495,32 @@ void meshGEdge::operator() (GEdge *ge)
     v0->z() = beg_p.z();
   }
 
+  if (blf && !blf->isEdgeBL(ge->tag()))
+    {      
+      GVertex *g0 = ge->getBeginVertex();
+      GVertex *g1 = ge->getEndVertex();
+      BoundaryLayerColumns* _columns = ge->model()->getColumns();
+      MVertex * v0 = g0->mesh_vertices[0];
+      MVertex * v1 = g1->mesh_vertices[0];
+      std::vector<MVertex*> invert;
+      std::vector<SMetric3> _metrics;
+      for(unsigned int i = 0; i < mesh_vertices.size() ; i++)
+	{
+	  invert.push_back(mesh_vertices[mesh_vertices.size() - i - 1]);
+	  _metrics.push_back(SMetric3(1.0));
+	}
+      SVector3 t (v1->x()-v0->x(), v1->y()-v0->y(),v1->z()-v0->z());
+      t.normalize();
+      if (blf->isVertexBL(g0->tag())){
+	  _columns->addColumn(t, v0, mesh_vertices,_metrics);
+	  //	  printf ("coucou %d %d %g %g %d\n",ge->tag(),g1->tag(),t.x(),t.y(),mesh_vertices.size());
+      }
+      if (blf->isVertexBL(g1->tag())){
+	  _columns->addColumn(t*-1.0, v1,invert,_metrics);
+	  //	  printf ("coucou %d %d\n",ge->tag(),g0->tag());
+
+      }      
+    }
   ge->meshStatistics.status = GEdge::DONE;
 }
 
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index e2d9778a58..4f463cceb5 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -43,7 +43,7 @@
 #include "Context.h"
 #include "multiscalePartition.h"
 #include "meshGFaceLloyd.h"
-#include "meshGFaceBoundaryLayers.h"
+#include "boundaryLayersData.h"
 
 inline double myAngle(const SVector3 &a, const SVector3 &b, const SVector3 &d)
 {
@@ -622,7 +622,7 @@ void filterOverlappingElements(int dim, std::vector<MElement*> &e,
       }
     }
     if (intersection){
-      printf("intersection found\n");
+      //      printf("intersection found\n");
       einter.push_back(el);
     }
     else {
@@ -633,9 +633,9 @@ void filterOverlappingElements(int dim, std::vector<MElement*> &e,
 
 void modifyInitialMeshForTakingIntoAccountBoundaryLayers(GFace *gf)
 {
-  BoundaryLayerColumns *_columns = buildAdditionalPoints2D (gf);
+  BoundaryLayerColumns* _columns = gf->model()->getColumns();
+  if (!buildAdditionalPoints2D (gf, _columns))return;
 
-  if (!_columns)return;
 
   std::set<MEdge,Less_Edge> bedges;
 
diff --git a/Mesh/meshGFaceBoundaryLayers.h b/Mesh/meshGFaceBoundaryLayers.h
deleted file mode 100644
index e6b4917ccd..0000000000
--- a/Mesh/meshGFaceBoundaryLayers.h
+++ /dev/null
@@ -1,194 +0,0 @@
-// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle
-//
-// See the LICENSE.txt file for license information. Please report all
-// bugs and problems to the public mailing list <gmsh@geuz.org>.
-
-#ifndef _MESHGFACE_BNDRYLR_
-#define _MESHGFACE_BNDRYLR_
-
-#include "SVector3.h"
-#include "STensor3.h"
-#include "MEdge.h"
-#include <map>
-#include <set>
-
-class Field;
-class GFace;
-class GRegion;
-class MTriangle;
-
-struct BoundaryLayerData
-{
-  SVector3 _n;
-  std::vector<MVertex*> _column;
-  std::vector<SMetric3> _metrics;
-  BoundaryLayerData(){}
-  BoundaryLayerData(const SVector3 & dir,
-                    std::vector<MVertex*> column,
-                    std::vector<SMetric3> metrics)
-    : _n(dir), _column(column), _metrics(metrics){}
-};
-
-struct BoundaryLayerFan
-{
-  MEdge _e1, _e2;
-  bool sense;
-  BoundaryLayerFan(MEdge e1, MEdge e2 , bool s = true)
-    : _e1(e1),_e2(e2) , sense (s){}
-};
-
-struct edgeColumn {
-  const BoundaryLayerData &_c1, &_c2;
-  edgeColumn(const BoundaryLayerData &c1, const BoundaryLayerData &c2)
-    : _c1(c1), _c2(c2){}
-};
-
-class BoundaryLayerColumns
-{
-  std::multimap<MVertex*, BoundaryLayerData>  _data;
-  std::map<MVertex*, BoundaryLayerFan> _fans;
-public:
-  typedef std::multimap<MVertex*,BoundaryLayerData>::iterator iter;
-  typedef std::map<MVertex*, BoundaryLayerFan>::iterator iterf;
-  std::multimap<MVertex*, MVertex*> _non_manifold_edges;
-  std::multimap<MVertex*,MTriangle*> _non_manifold_faces;
-  std::multimap<MEdge, SVector3, Less_Edge> _normals;
-  iter begin() { return _data.begin(); }
-  iter end() { return _data.end(); }
-  iterf beginf() { return _fans.begin(); }
-  iterf endf() { return _fans.end(); }
-  BoundaryLayerColumns (){}
-  inline void addColumn(const SVector3 &dir, MVertex* v,
-                        std::vector<MVertex*> _column,
-                        std::vector<SMetric3> _metrics)
-  {
-    _data.insert (std::make_pair(v,BoundaryLayerData(dir, _column,_metrics)));
-  }
-  inline void addFan(MVertex *v, MEdge e1, MEdge e2, bool s)
-  {
-    _fans.insert(std::make_pair(v,BoundaryLayerFan(e1,e2,s)));
-  }
-  inline const BoundaryLayerData &getColumn(MVertex *v, MEdge e)
-  {
-    std::map<MVertex*,BoundaryLayerFan>::const_iterator it = _fans.find(v);
-    int N = getNbColumns(v) ;
-    if (N == 1) return getColumn(v, 0);
-    Equal_Edge aaa;
-    if (it != _fans.end()){
-      if (aaa(it->second._e1, e))
-	return getColumn(v, 0);
-      else
-	return getColumn(v, N-1);
-    }
-    Msg::Error("Cannot handle embedded lines in boundary layers");
-    static BoundaryLayerData error;
-    return error;
-  }
-  inline edgeColumn getColumns(MVertex *v1, MVertex *v2 , int side)
-  {
-    Equal_Edge aaa;
-    MEdge e(v1, v2);
-    std::map<MVertex*,BoundaryLayerFan>::const_iterator it1 = _fans.find(v1);
-    std::map<MVertex*,BoundaryLayerFan>::const_iterator it2 = _fans.find(v2);
-    int N1 = getNbColumns(v1) ;
-    int N2 = getNbColumns(v2) ;
-
-    int nbSides = _normals.count(e);
-
-    // if (nbSides != 1)printf("I'm here %d sides\n",nbSides);
-    // Standard case, only two extruded columns from the two vertices
-    if (N1 == 1 && N2 == 1) return edgeColumn(getColumn(v1,0),getColumn(v2,0));
-    // one fan on
-    if (nbSides == 1){
-      if (it1 != _fans.end() && it2 == _fans.end() ){
-	if (aaa(it1->second._e1,e))
-	  return edgeColumn(getColumn (v1,0),getColumn(v2,0));
-	else
-	  return edgeColumn(getColumn (v1,N1-1),getColumn(v2,0));
-      }
-      if (it2 != _fans.end() && it1 == _fans.end() ){
-	if (aaa(it2->second._e1,e))
-	  return edgeColumn(getColumn (v1,0),getColumn(v2,0));
-	else
-	  return edgeColumn(getColumn (v1,0),getColumn(v2,N2-1));
-      }
-      if (it2 != _fans.end() && it1 != _fans.end() ){
-	int c1, c2;
-	if (aaa(it1->second._e1,e))
-	  c1 =  0;
-	else
-	  c1 = N1-1;
-	if (aaa(it2->second._e1,e))
-	  c2 =  0;
-	else
-	  c2 = N2-1;
-	return edgeColumn(getColumn (v1,c1),getColumn(v2,c2));
-      }
-
-      if (N1 == 1 || N2 == 2){
-	const BoundaryLayerData & c10 = getColumn(v1,0);
-	const BoundaryLayerData & c20 = getColumn(v2,0);
-	const BoundaryLayerData & c21 = getColumn(v2,1);
-	if (dot(c10._n,c20._n) > dot(c10._n,c21._n) ) return edgeColumn(c10,c20);
-	else return edgeColumn(c10,c21);
-      }
-      if (N1 == 2 || N2 == 1){
-	const BoundaryLayerData & c10 = getColumn(v1,0);
-	const BoundaryLayerData & c11 = getColumn(v1,1);
-	const BoundaryLayerData & c20 = getColumn(v2,0);
-	if (dot(c10._n,c20._n) > dot(c11._n,c20._n) ) return edgeColumn(c10,c20);
-	else return edgeColumn(c11,c20);
-      }
-
-      Msg::Error ("Impossible Boundary Layer Configuration : one side and no fans %d %d",N1,N2);
-      // FIXME WRONG
-      return N1 ? edgeColumn (getColumn (v1,0),getColumn(v1,0)) :
-        edgeColumn (getColumn (v2,0),getColumn(v2,0));
-    }
-    else if (nbSides == 2){
-      if (it1 == _fans.end() && it2 == _fans.end() ){
-	if (N1 != 2 || N2 != 2){
-	  Msg::Error ("Impossible Boundary Layer Configuration");
-	  // FIXME WRONG
-	  return N1 ? edgeColumn (getColumn (v1,0),getColumn(v1,0)) :
-            edgeColumn (getColumn (v2,0),getColumn(v2,0));
-	}
-	const BoundaryLayerData & c10 = getColumn(v1,0);
-	const BoundaryLayerData & c11 = getColumn(v1,1);
-	const BoundaryLayerData & c20 = getColumn(v2,0);
-	const BoundaryLayerData & c21 = getColumn(v2,1);
-	if (side == 0){
-	  if (dot(c10._n,c20._n) > dot(c10._n,c21._n) ) return edgeColumn(c10,c20);
-	  else return edgeColumn(c10,c21);
-	}
-	if (side == 1){
-	  if (dot(c11._n,c20._n) > dot(c11._n,c21._n) ) return edgeColumn(c11,c20);
-	  else return edgeColumn(c11,c21);
-	}
-      }
-    }
-
-    Msg::Error("Not yet Done in BoundaryLayerData");
-    static BoundaryLayerData error;
-    static edgeColumn error2(error, error);
-    return error2;
-  }
-  inline int getNbColumns(MVertex *v) { return _data.count(v); }
-  inline const BoundaryLayerData &getColumn(MVertex *v, int iColumn)
-  {
-    int count = 0;
-    for(std::multimap<MVertex*,BoundaryLayerData>::iterator itm  = _data.lower_bound(v);
-        itm != _data.upper_bound(v); ++itm){
-      if (count++ == iColumn) return itm->second;
-    }
-    static BoundaryLayerData error;
-    return error;
-  }
-  void filterPoints();
-};
-
-BoundaryLayerColumns * buildAdditionalPoints2D (GFace *gf) ;
-BoundaryLayerColumns * buildAdditionalPoints3D (GRegion *gr) ;
-void buildMeshMetric(GFace *gf, double *uv, SMetric3 &m, double metric[3]);
-
-#endif
diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp
index 4e78b3f24e..3d6203a167 100644
--- a/Mesh/meshGRegion.cpp
+++ b/Mesh/meshGRegion.cpp
@@ -9,7 +9,7 @@
 #include "GmshMessage.h"
 #include "meshGRegion.h"
 #include "meshGFaceOptimize.h"
-#include "meshGFaceBoundaryLayers.h"
+#include "boundaryLayersData.h"
 #include "meshGRegionDelaunayInsertion.h"
 #include "GModel.h"
 #include "GRegion.h"
@@ -484,7 +484,7 @@ void TransferTetgenMesh(GRegion *gr, tetgenio &in, tetgenio &out,
 
 static void modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
 {
-  buildAdditionalPoints3D (gr);
+  //  buildAdditionalPoints3D (gr);
 }
 
 void _relocateVertex(MVertex *ver,
@@ -959,7 +959,7 @@ void meshGRegion::operator() (GRegion *gr)
   }
 
   // replace discreteFaces by their compounds
-  if(gr->geomType() == GEntity::CompoundVolume){
+  if( 1 || gr->geomType() == GEntity::CompoundVolume){
     std::set<GFace*> mySet;
     std::list<GFace*>::iterator it = faces.begin();
     while(it != faces.end()){
diff --git a/Mesh/meshGRegionBoundaryLayers.cpp b/Mesh/meshGRegionBoundaryLayers.cpp
index 315b74d70e..2310bcd56e 100644
--- a/Mesh/meshGRegionBoundaryLayers.cpp
+++ b/Mesh/meshGRegionBoundaryLayers.cpp
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh@geuz.org>.
 
-#include "meshGFaceBoundaryLayers.h"
+#include "boundaryLayersData.h"
 #include "GModel.h"
 #include "GRegion.h"
 #include "MTriangle.h"
diff --git a/Mesh/meshGRegionDelaunayInsertion.cpp b/Mesh/meshGRegionDelaunayInsertion.cpp
index f7ebac6393..77f2469970 100644
--- a/Mesh/meshGRegionDelaunayInsertion.cpp
+++ b/Mesh/meshGRegionDelaunayInsertion.cpp
@@ -402,19 +402,19 @@ bool insertVertexB(std::list<faceXtet> &shell,
   while (it != shell.end()){
     MTetrahedron *tr = new MTetrahedron(it->getVertex(0), it->getVertex(1), it->getVertex(2), v);
 
-    double lc = .25 * (vSizes[tr->getVertex(0)->getIndex()] +
-		       vSizes[tr->getVertex(1)->getIndex()] +
-		       vSizes[tr->getVertex(2)->getIndex()] +
-		       vSizes[tr->getVertex(3)->getIndex()]);
-    double lcBGM = .25 * (vSizesBGM[tr->getVertex(0)->getIndex()] +
-			  vSizesBGM[tr->getVertex(1)->getIndex()] +
-			  vSizesBGM[tr->getVertex(2)->getIndex()] +
-			  vSizesBGM[tr->getVertex(3)->getIndex()]);
-    double LL = std::min(lc, lcBGM);
+    //    double lc = .25 * (vSizes[tr->getVertex(0)->getIndex()] +
+    //		       vSizes[tr->getVertex(1)->getIndex()] +
+    //		       vSizes[tr->getVertex(2)->getIndex()] +
+    //		       vSizes[tr->getVertex(3)->getIndex()]);
+    //    double lcBGM = .25 * (vSizesBGM[tr->getVertex(0)->getIndex()] +
+    //			  vSizesBGM[tr->getVertex(1)->getIndex()] +
+    //			  vSizesBGM[tr->getVertex(2)->getIndex()] +
+    //			  vSizesBGM[tr->getVertex(3)->getIndex()]);
+    //    double LL = std::min(lc, lcBGM);
 
     MTet4 *t4 = myFactory.Create(tr, vSizes, vSizesBGM);
     t4->setOnWhat(t->onWhat());
-
+    /*
     double d1 = sqrt((it->v[0]->x() - v->x()) * (it->v[0]->x() - v->x()) +
                      (it->v[0]->y() - v->y()) * (it->v[0]->y() - v->y()) +
                      (it->v[0]->z() - v->z()) * (it->v[0]->z() - v->z()));
@@ -426,6 +426,7 @@ bool insertVertexB(std::list<faceXtet> &shell,
                      (it->v[2]->z() - v->z()) * (it->v[2]->z() - v->z()));
 
     if (d1 < LL * .25 || d2 < LL * .25 || d3 < LL * .25) onePointIsTooClose = true;
+    */
     newTets[k++] = t4;
     // all new tets are pushed front in order to ba able to destroy
     // them if the cavity is not star shaped around the new vertex.
@@ -1282,7 +1283,7 @@ void insertVerticesInRegion (GRegion *gr)
     // Normally, a tet mesh contains about 6 times more tets than
     // vertices. This allows to clean up the set of tets when lots of
     // deleted ones are present in the mesh
-    if(allTets.size() > 7 * vSizes.size() && ITER > 20000){
+    if(allTets.size() > 7 * vSizes.size() && ITER > 1000){
       memoryCleanup(myFactory, allTets);
     }
   }
diff --git a/Mesh/surfaceFiller.cpp b/Mesh/surfaceFiller.cpp
index f547098ba3..c1c7a170a1 100644
--- a/Mesh/surfaceFiller.cpp
+++ b/Mesh/surfaceFiller.cpp
@@ -181,6 +181,10 @@ bool compute4neighbors (GFace *gf,   // the surface
 			SPoint2 newP[4][NUMDIR], // look into other directions 
 			SMetric3 &metricField, FILE *crossf = 0) // the mesh metric
 {
+
+  Range<double> rangeU = gf->parBounds(0);
+  Range<double> rangeV = gf->parBounds(1);
+
   // we assume that v is on surface gf
 
   // get the parameter of the point on the surface
@@ -247,14 +251,17 @@ bool compute4neighbors (GFace *gf,   // the surface
     // t1 . s2 = a E + b N --> solve the 2 x 2 system
     // and get covariant coordinates a and b
     double rhs1[2] = {dot(t1,s1),dot(t1,s2)}, covar1[2];
+    bool singular = false;
     if (!sys2x2(metric,rhs1,covar1)){
-      Msg::Info("Argh");
+      Msg::Info("Argh surface %d %g %g %g -- %g %g %g -- %g %g",gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z(),size_1,size_2);
       covar1[1] = 1.0; covar1[0] = 0.0;
+      singular = true;
     }
     double rhs2[2] = {dot(t2,s1),dot(t2,s2)}, covar2[2];
     if (!sys2x2(metric,rhs2,covar2)){
-      Msg::Info("Argh");
+      Msg::Info("Argh surface %d %g %g %g -- %g %g %g",gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z());
       covar2[0] = 1.0; covar2[1] = 0.0;
+      singular = true;
     }
     
     // transform the sizes with respect to the metric
@@ -263,18 +270,22 @@ bool compute4neighbors (GFace *gf,   // the surface
     // of size1 in direction v, it should be sqrt(v^T M v) * size1
     double l1 = sqrt(covar1[0]*covar1[0]+covar1[1]*covar1[1]);
     double l2 = sqrt(covar2[0]*covar2[0]+covar2[1]*covar2[1]);
-
   
     covar1[0] /= l1;covar1[1] /= l1;
     covar2[0] /= l2;covar2[1] /= l2;
 
-
-    const double size_param_1  = size_1 / sqrt (  M*covar1[0]*covar1[0]+
+    double size_param_1  = size_1 / sqrt (  M*covar1[0]*covar1[0]+
 						  2*E*covar1[1]*covar1[0]+
 						  N*covar1[1]*covar1[1]);
-    const double size_param_2  = size_2 / sqrt (  M*covar2[0]*covar2[0]+
-						  2*E*covar2[1]*covar2[0]+
+    double size_param_2  = size_2 / sqrt (  M*covar2[0]*covar2[0]+
+						  2*E*covar2[1]*covar2[0]+					    
 						  N*covar2[1]*covar2[1]);
+    if (singular){
+      size_param_1 = size_param_2 = std::min (size_param_1,size_param_2);
+    }
+
+    //    printf("%12.5E %12.5E\n", size_param_1, size_param_2);
+
     
     //    if (v_center->onWhat() != gf && gf->tag() == 3)
     //      printf("M = (%g %g %g) L = %g %g LP = %g %g\n",metricField(0,0),metricField(1,1),metricField(0,1),l1,l2,size_param_1,size_param_2);
@@ -312,6 +323,10 @@ bool compute4neighbors (GFace *gf,   // the surface
     // surface
     double ERR[4];
     for (int i=0;i<4;i++){                                              //
+      //      if (newPoint[i][0] < rangeU.low())newPoint[i][0] = rangeU.low(); 
+      //      if (newPoint[i][0] > rangeU.high())newPoint[i][0] = rangeU.high(); 
+      //      if (newPoint[i][1] < rangeV.low())newPoint[i][1] = rangeV.low(); 
+      //      if (newPoint[i][1] > rangeV.high())newPoint[i][1] = rangeV.high(); 
       GPoint pp = gf->point(SPoint2(newPoint[i][0], newPoint[i][1]));
       double D = sqrt ((pp.x() - v_center->x())*(pp.x() - v_center->x()) + 
 		       (pp.y() - v_center->y())*(pp.y() - v_center->y()) + 
@@ -320,7 +335,7 @@ bool compute4neighbors (GFace *gf,   // the surface
       //      printf("L = %12.5E D = %12.5E ERR = %12.5E\n",L,D,100*fabs(D-L)/(D+L));
     }
 
-    if (0 && goNonLinear){//---------------------------------------------------//
+    if (1 && goNonLinear){//---------------------------------------------------//
       surfaceFunctorGFace ss (gf);                                        //
       SVector3 dirs[4] = {t1*(-1.0),t2*(-1.0),t1*(1.0),t2*(1.0)};                     //      
       for (int i=0;i<4;i++){                                              //
@@ -330,7 +345,7 @@ bool compute4neighbors (GFace *gf,   // the surface
 	  curveFunctorCircle cf (dirs[i],n,				 
 				 SVector3(v_center->x(),v_center->y(),v_center->z()),
 				 L);
-	  if (intersectCurveSurface (cf,ss,uvt,size_param_1*1.e-5)){          //
+	  if (intersectCurveSurface (cf,ss,uvt,size_param_1*1.e-3)){          //
 	    GPoint pp = gf->point(SPoint2(uvt[0],uvt[1]));
 	    double D = sqrt ((pp.x() - v_center->x())*(pp.x() - v_center->x()) + 
 			     (pp.y() - v_center->y())*(pp.y() - v_center->y()) + 
@@ -346,10 +361,12 @@ bool compute4neighbors (GFace *gf,   // the surface
 	      //	      printf("%12.5E vs %12.5E : %12.5E  %12.5E vs %12.5E  %12.5E \n",ERR[i],newErr,newPoint[i][0],newPoint[i][1],uvt[0],uvt[1]);
 	      newPoint[i][0] = uvt[0];                                        //
 	      newPoint[i][1] = uvt[1];                                        //
-	    }                                                                 //
+	    }                                                                 //	    
+	    //	    printf("OK\n");
 	  }
 	  else{
 	    Msg::Debug("Cannot put a new point on Surface %d",gf->tag());
+	    //	    printf("NOT OK\n");
 	  }
 	}
       }                                                                   //
diff --git a/Mesh/yamakawa.cpp b/Mesh/yamakawa.cpp
index 598fe22729..5a1afbe259 100755
--- a/Mesh/yamakawa.cpp
+++ b/Mesh/yamakawa.cpp
@@ -338,17 +338,17 @@ void Recombinator::execute(GRegion* gr){
   build_tuples(gr);
   init_markings(gr);
 
+  Msg::Info("Building Connectivity...");
   build_vertex_to_vertices(gr);
   build_vertex_to_elements(gr);
-  printf("connectivity\n");
 
   potential.clear();
   patern1(gr);
-  printf("patern no. 1\n");
+  Msg::Info("Hex-merging patern nb. 1...");
   patern2(gr);
-  printf("patern no. 2\n");
+  Msg::Info("Hex-merging patern nb. 2...");
   patern3(gr);
-  printf("patern no. 3\n");
+  Msg::Info("Hex-merging patern nb. 3...");
 
   std::sort(potential.begin(),potential.end());
 
diff --git a/Numeric/Numeric.cpp b/Numeric/Numeric.cpp
index 1a124c83c5..0dd9bc3f03 100644
--- a/Numeric/Numeric.cpp
+++ b/Numeric/Numeric.cpp
@@ -684,10 +684,13 @@ bool newton_fd(void (*func)(fullVector<double> &, fullVector<double> &, void *),
       func(x, feps, data);
       for (int i = 0; i < N; i++){
         J(i, j) = (feps(i) - f(i)) / h;
+	//	printf("J(%d,%d) = %12.5E \n",i,j,J(i,j));
       }
       x(j) -= h;
     }
 
+    //    printf("done\n");
+
     if (N == 1)
       dx(0) = f(0) / J(0, 0);
     else
@@ -697,6 +700,7 @@ bool newton_fd(void (*func)(fullVector<double> &, fullVector<double> &, void *),
     for (int i = 0; i < N; i++)
       x(i) -= relax * dx(i);
 
+    //    printf("dx = %12.5E\n",dx.norm());
     if(dx.norm() < tolx) return true;
   }
   return false;
diff --git a/Numeric/simpleFunction.h b/Numeric/simpleFunction.h
index 61754fc94a..313e2139f7 100644
--- a/Numeric/simpleFunction.h
+++ b/Numeric/simpleFunction.h
@@ -15,7 +15,7 @@ class simpleFunction {
   scalar _val;
   bool _hasDerivatives;
  public :
- simpleFunction(scalar val=0.0) : _val(val), _hasDerivatives(false){}
+ simpleFunction(scalar val =0.0) : _val(val), _hasDerivatives(false){}
   virtual ~simpleFunction(){}
   virtual bool hasDerivatives() {return _hasDerivatives;};
   virtual scalar operator () (double x, double y, double z) const { return _val; }
diff --git a/benchmarks/3d/submarine/submarine_simple.geo b/benchmarks/3d/submarine/submarine_simple.geo
index 2873ebf3a9..d00489aa7e 100644
--- a/benchmarks/3d/submarine/submarine_simple.geo
+++ b/benchmarks/3d/submarine/submarine_simple.geo
@@ -1,11 +1,24 @@
-lc = 200;
+lc = 25;
 Mesh.CharacteristicLengthMin = lc;
 Mesh.CharacteristicLengthMax = lc;
+Mesh.Smoothing = 0;
 
-Merge "submarine.stp";
+Merge "submarine.brep";
+
+
+Compound Surface(1034) = {12};
 
 Physical Surface(1) = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
-Physical Surface(2) = {12};
+Physical Surface(2) = {1034};
 Physical Surface(3) = {11};
-Physical Volume(4) = {1};
 
+MeshAlgorithm Surface {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,1034}  9;
+MeshAlgorithm Surface {12}  5;
+Mesh.Recombine3DAll = 1;
+Mesh.Algorithm3D = 9;
+Delete {Volume {1};}
+//Compound Volume(1035) = {1};
+
+Surface Loop(1000) = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1034};
+Volume(1001) = {1000};
+Physical Volume(1) = {1001};
diff --git a/wrappers/gmshpy/gmshGeo.i b/wrappers/gmshpy/gmshGeo.i
index 6390afe435..512247447d 100644
--- a/wrappers/gmshpy/gmshGeo.i
+++ b/wrappers/gmshpy/gmshGeo.i
@@ -37,6 +37,7 @@
   #include "SBoundingBox3d.h"
   #include "Curvature.h"
   #include "simpleFunction.h"
+  #include "distanceToMesh.h"
   #include "GeomMeshMatcher.h"
 %}
 
@@ -95,6 +96,7 @@ namespace std {
 %include "SBoundingBox3d.h"
 %include "Curvature.h"
 %include "gmshLevelset.h"
+%include "distanceToMesh.h"
 %include "GeomMeshMatcher.h"
 
 
-- 
GitLab