diff --git a/Geo/GEdgeCompound.cpp b/Geo/GEdgeCompound.cpp
index 63a1aad70838ba979207647186fd4f72cec026dd..d57a348d5c7fec6513b1a35552f84dce2b7cba0d 100644
--- a/Geo/GEdgeCompound.cpp
+++ b/Geo/GEdgeCompound.cpp
@@ -41,7 +41,7 @@ GEdgeCompound::GEdgeCompound(GModel *m, int tag, std::vector<GEdge*> &compound,
 GEdgeCompound::GEdgeCompound(GModel *m, int tag, std::vector<GEdge*> &compound)
   : GEdge(m, tag, 0 , 0), _compound(compound)
 {
-  orderEdges ();
+  orderEdges();
   int N = _compound.size();
   v0 = _orientation[0] ? _compound[0]->getBeginVertex() : _compound[0]->getEndVertex();
   v1 = _orientation[N-1] ? _compound[N-1]->getEndVertex() :  _compound[N-1]->getBeginVertex();
@@ -56,6 +56,7 @@ GEdgeCompound::GEdgeCompound(GModel *m, int tag, std::vector<GEdge*> &compound)
 
 void GEdgeCompound::orderEdges()
 {
+
   std::vector<GEdge*> _c ;
   std::list<GEdge*> edges ;
 
diff --git a/Geo/STensor3.h b/Geo/STensor3.h
index 2ef74c6f4d62325b4f83290793f81f9f81dd5e57..31f5d3950c669ec39886ba8ec93d867e9adf24a7 100644
--- a/Geo/STensor3.h
+++ b/Geo/STensor3.h
@@ -199,6 +199,24 @@ class STensor3 {
     static int _index[3][3] = {{0,1,2},{3,4,5},{6,7,8}};
     return _index[i][j];
   }
+  inline void set_m11(double x){  _val[0] = x; }
+  inline void set_m21(double x){  _val[1] = x; }
+  inline void set_m31(double x){  _val[2] = x; }
+  inline void set_m12(double x){  _val[3] = x; }
+  inline void set_m22(double x){  _val[4] = x; }
+  inline void set_m32(double x){  _val[5] = x; }
+  inline void set_m13(double x){  _val[6] = x; }
+  inline void set_m23(double x){  _val[7] = x; }
+  inline void set_m33(double x){  _val[8] = x; }
+  inline double get_m11(){ return _val[0]; }
+  inline double get_m21(){ return _val[1]; }
+  inline double get_m31(){ return _val[2]; }
+  inline double get_m12(){ return _val[3]; }
+  inline double get_m22(){ return _val[4]; }
+  inline double get_m32(){ return _val[5]; }
+  inline double get_m13(){ return _val[6]; }
+  inline double get_m23(){ return _val[7]; }
+  inline double get_m33(){ return _val[8]; }
   void getMat(fullMatrix<double> &mat) const
   {
     for (int i = 0; i < 3; i++){
diff --git a/Mesh/CenterlineField.cpp b/Mesh/CenterlineField.cpp
index 849b98494a510a57f2fbcfa0ec819cbc2d2d8354..c0c3cb5c2c2f095ff4c1b687bea48221659f8d1c 100644
--- a/Mesh/CenterlineField.cpp
+++ b/Mesh/CenterlineField.cpp
@@ -39,6 +39,8 @@
 #include "Curvature.h"
 #include "MElement.h"
 #include "Context.h"
+#include "directions3D.h"
+#include "meshGRegion.h"
 
 #if defined(HAVE_ANN)
 #include <ANN/ANN.h>
@@ -769,7 +771,7 @@ void Centerline::extrudeBoundaryLayerWall(GEdge* gin, std::vector<GEdge*> boundE
   SVector3 pc(nodes[index[0]][0], nodes[index[0]][1], nodes[index[0]][2]);
   SVector3 nc = ps-pc;
   if (dot(ne,nc) < 0) dir = 1;
-  if (dir ==1 && hLayer > 0 ) hLayer *= -1.0;
+  if (dir == 1 && hLayer > 0 ) hLayer *= -1.0;
 
   //int shift = 0;
   //if(is_cut) shift = NE;
@@ -791,7 +793,7 @@ void Centerline::extrudeBoundaryLayerWall(GEdge* gin, std::vector<GEdge*> boundE
     //if double extruded layer
     if (nbElemSecondLayer > 0){
       std::vector<GEntity*> extrudedESec = current->extrudeBoundaryLayer
-      	(gfc, nbElemSecondLayer,  hSecondLayer, dir ? 0 : 1, -5);
+      	(eFace, nbElemSecondLayer,  hSecondLayer, dir, -5);
       GFace *eFaceSec = (GFace*) extrudedESec[0];
       eFaceSec->addPhysicalEntity(9);                    //tag 9
       current->setPhysicalName("outerSecondWall", 2, 9);//dim 2 tag 9
@@ -799,6 +801,7 @@ void Centerline::extrudeBoundaryLayerWall(GEdge* gin, std::vector<GEdge*> boundE
       eRegionSec->addPhysicalEntity(10);             //tag 10
       current->setPhysicalName("wallVolume", 3, 10);//dim 3 tag 10
     }
+    //end double extrusion 
 
     for (unsigned int j = 2; j < extrudedE.size(); j++){
       GFace *elFace = (GFace*) extrudedE[j];
@@ -1147,6 +1150,12 @@ void  Centerline::operator() (double x, double y, double z, SMetric3 &metr, GEnt
    SVector3 dir_a = p1-p0; dir_a.normalize();
    SVector3 dir_n(xyz[0]-p0.x(), xyz[1]-p0.y(), xyz[2]-p0.z()); dir_n.normalize();
    SVector3 dir_cross  = crossprod(dir_a,dir_n); dir_cross.normalize();
+   // if (ge->dim()==3){
+   //   printf("coucou dim ==3 !!!!!!!!!!!!!!! \n");
+   //   SVector3 d1,d2,d3;
+   //   computeCrossField(x,y,z,d1,d2,d3);
+   //   exit(1);
+   // }
 
    //find discrete curvature at closest vertex
    Curvature& curvature = Curvature::getInstance();
@@ -1239,6 +1248,20 @@ SMetric3 Centerline::metricBasedOnSurfaceCurvature(SVector3 dirMin, SVector3 dir
   return curvMetric;
 }
 
+void Centerline::computeCrossField(double x,double y,double z,
+				   SVector3 &d1, SVector3 &d2,  SVector3 &d3)
+{
+
+  //Le code suivant permet d'obtenir les trois vecteurs orthogonaux en un point.
+  // int NumSmooth = 10;//CTX::instance()->mesh.smoothCrossField
+  // Matrix m2;
+  // if(NumSmooth)
+  //   m2 = Frame_field::findCross(x,y,z);
+  // else
+  //   m2 = Frame_field::search(x,y,z);
+  
+}
+
 void Centerline::printSplit() const
 {
   FILE * f = fopen("mySPLIT.pos","w");
diff --git a/Mesh/CenterlineField.h b/Mesh/CenterlineField.h
index 7c964863f57cba122a5278fce859a747eac5b443..abf5d57f9038ff58c3e2a61797a7612d76a6cbc7 100644
--- a/Mesh/CenterlineField.h
+++ b/Mesh/CenterlineField.h
@@ -121,6 +121,9 @@ class Centerline : public Field{
   //anisotropic operator
   void operator() (double x, double y, double z, SMetric3 &metr, GEntity *ge=0);
 
+  void computeCrossField(double x,double y,double z,
+			 SVector3 &d1, SVector3 &d2,  SVector3 &d3);
+
   //import the 1D mesh of the centerlines (in vtk format)
   //and fill the vector of lines
   void importFile(std::string fileName);
diff --git a/Mesh/Levy3D.cpp b/Mesh/Levy3D.cpp
index 143f713ee209d8bfa843af4eedb9f0f9ce27345b..9159e439718c8b308160e8049da4e4a734f1406d 100644
--- a/Mesh/Levy3D.cpp
+++ b/Mesh/Levy3D.cpp
@@ -874,9 +874,7 @@ double LpCVT::get_size(double x,double y,double z){
 
 Tensor LpCVT::get_tensor(double x,double y,double z){
   Tensor t;
-  Matrix m;
-
-  m = Frame_field::search(x,y,z);
+  STensor3 m = Frame_field::search(x,y,z);
 
   t.set_t11(m.get_m11());
   t.set_t21(m.get_m12());
diff --git a/Mesh/Matrix.h b/Mesh/Matrix.h
index 81ef1227aac8e05f7aa3137e56f9ce36e8b7a3a6..83de7598a469e14855cb9af528511cb4b028f31a 100644
--- a/Mesh/Matrix.h
+++ b/Mesh/Matrix.h
@@ -11,75 +11,41 @@
 
 class Matrix{
  private:
-  double m11,m21,m31,m12,m22,m32,m13,m23,m33;
- public:
+  double _val[9];
+  public:
   Matrix(){
-    m11 = 1.0;
-    m21 = 0.0;
-    m31 = 0.0;
-    m12 = 0.0;
-    m22 = 1.0;
-    m32 = 0.0;
-    m13 = 0.0;
-    m23 = 0.0;
-    m33 = 1.0;
+    /* m11 = 1.0; */
+    /* m21 = 0.0; */
+    /* m31 = 0.0; */
+    /* m12 = 0.0; */
+    /* m22 = 1.0; */
+    /* m32 = 0.0; */
+    /* m13 = 0.0; */
+    /* m23 = 0.0; */
+    /* m33 = 1.0; */
+    _val[0] = _val[4] = _val[8] = 1.0;
+    _val[1] = _val[2] = _val[3] = 0.0;
+    _val[5] = _val[6] = _val[7] = 0.0;
   }
   ~Matrix(){}
-  void set_m11(double x){ m11 = x; }
-  void set_m21(double x){ m21 = x; }
-  void set_m31(double x){ m31 = x; }
-  void set_m12(double x){ m12 = x; }
-  void set_m22(double x){ m22 = x; }
-  void set_m32(double x){ m32 = x; }
-  void set_m13(double x){ m13 = x; }
-  void set_m23(double x){ m23 = x; }
-  void set_m33(double x){ m33 = x; }
-  double get_m11(){ return m11; }
-  double get_m21(){ return m21; }
-  double get_m31(){ return m31; }
-  double get_m12(){ return m12; }
-  double get_m22(){ return m22; }
-  double get_m32(){ return m32; }
-  double get_m13(){ return m13; }
-  double get_m23(){ return m23; }
-  double get_m33(){ return m33; }
+  void set_m11(double x){  _val[0] = x; }
+  void set_m21(double x){  _val[1] = x; }
+  void set_m31(double x){  _val[2] = x; }
+  void set_m12(double x){  _val[3] = x; }
+  void set_m22(double x){  _val[4] = x; }
+  void set_m32(double x){  _val[5] = x; }
+  void set_m13(double x){  _val[6] = x; }
+  void set_m23(double x){  _val[7] = x; }
+  void set_m33(double x){  _val[8] = x; }
+  double get_m11(){ return _val[0]; }
+  double get_m21(){ return _val[1]; }
+  double get_m31(){ return _val[2]; }
+  double get_m12(){ return _val[3]; }
+  double get_m22(){ return _val[4]; }
+  double get_m32(){ return _val[5]; }
+  double get_m13(){ return _val[6]; }
+  double get_m23(){ return _val[7]; }
+  double get_m33(){ return _val[8]; }
 };
 
-/*
-double Matrix::get_m11(){ return m11; }
-double Matrix::get_m21(){ return m21; }
-double Matrix::get_m31(){ return m31; }
-double Matrix::get_m12(){ return m12; }
-double Matrix::get_m22(){ return m22; }
-double Matrix::get_m32(){ return m32; }
-double Matrix::get_m13(){ return m13; }
-double Matrix::get_m23(){ return m23; }
-double Matrix::get_m33(){ return m33; }
-
-
-Matrix::Matrix(){
-  m11 = 1.0;
-  m21 = 0.0;
-  m31 = 0.0;
-  m12 = 0.0;
-  m22 = 1.0;
-  m32 = 0.0;
-  m13 = 0.0;
-  m23 = 0.0;
-  m33 = 1.0;
-}
-Matrix::~Matrix(){}
-
-void Matrix::set_m11(double new_m11){ m11 = new_m11; }
-void Matrix::set_m21(double new_m21){ m21 = new_m21; }
-void Matrix::set_m31(double new_m31){ m31 = new_m31; }
-void Matrix::set_m12(double new_m12){ m12 = new_m12; }
-void Matrix::set_m22(double new_m22){ m22 = new_m22; }
-void Matrix::set_m32(double new_m32){ m32 = new_m32; }
-void Matrix::set_m13(double new_m13){ m13 = new_m13; }
-void Matrix::set_m23(double new_m23){ m23 = new_m23; }
-void Matrix::set_m33(double new_m33){ m33 = new_m33; }
-*/
-
-
 #endif
diff --git a/Mesh/cross3D.h b/Mesh/cross3D.h
index ce0c88e424049181b574357feaf2cd0753b58adb..c3289e88a1ad68e12b811001a589a6f95f36afd4 100644
--- a/Mesh/cross3D.h
+++ b/Mesh/cross3D.h
@@ -12,8 +12,6 @@
 #include <ostream>
 using std::ostream;
 
-#include "Matrix.h"
-
 
 /* Defined in SVector3.h */
 /* double angle(const SVector3 v, const SVector3 w) { */
@@ -112,8 +110,8 @@ public:
     b = (crossprod(a,Ex).norm() < 1e-2) ? Ey : Ex;
     scnd = crossprod(crossprod(frst, b), frst).unit();
   }
-  cross3D(const Matrix &x){
-    Matrix m = x;
+  cross3D(const STensor3 &x){
+    STensor3 m = x;
     SVector3 a(m.get_m11(), m.get_m21(), m.get_m31());
     SVector3 b(m.get_m12(), m.get_m22(), m.get_m32());
     frst = a.unit();
@@ -318,8 +316,8 @@ Qtn cross3D::rotationToOnSurf(const cross3D &y) const{
   return R2;
 }
 
-Matrix convert(const cross3D x){
-  Matrix m;
+STensor3 convert(const cross3D x){
+  STensor3 m;
   SVector3 v; 
   v = x.getFrst() ; m.set_m11(v[0]); m.set_m21(v[1]); m.set_m31(v[2]);
   v = x.getScnd() ; m.set_m12(v[0]); m.set_m22(v[1]); m.set_m32(v[2]);
diff --git a/Mesh/directions3D.cpp b/Mesh/directions3D.cpp
index b453e9a40d59b61211e32431a790aaa9a4705011..17f951430c1de952f682ced70bd2ad6c4b72724e 100644
--- a/Mesh/directions3D.cpp
+++ b/Mesh/directions3D.cpp
@@ -20,6 +20,8 @@
 #include "linearSystemFull.h"
 #endif
 
+
+
 /****************class Frame_field****************/
 
 Frame_field::Frame_field(){}
@@ -31,7 +33,7 @@ void Frame_field::init_region(GRegion* gr){
   MVertex* vertex;
   GFace* gf;
   std::list<GFace*> faces;
-  Matrix m;
+  STensor3 m(1.0);
 
   Nearest_point::init_region(gr);	
 	
@@ -48,13 +50,13 @@ void Frame_field::init_region(GRegion* gr){
   duplicate = annAllocPts(temp.size(),3);
 
   index = 0;
-  for(std::map<MVertex*,Matrix>::iterator it=temp.begin(); it != temp.end(); it++){
+  for(std::map<MVertex*,STensor3>::iterator it=temp.begin(); it != temp.end(); it++){
     vertex = it->first;
     m = it->second;
     duplicate[index][0] = vertex->x();
     duplicate[index][1] = vertex->y();
     duplicate[index][2] = vertex->z();
-    field.push_back(std::pair<MVertex*,Matrix>(vertex,m));
+    field.push_back(std::pair<MVertex*,STensor3>(vertex,m));
     index++;
   }
 
@@ -63,7 +65,7 @@ void Frame_field::init_region(GRegion* gr){
 }
 
 void Frame_field::init_face(GFace* gf){
-  // Fills the auxiliary std::map "temp" with a pair <vertex, Matrix>
+  // Fills the auxiliary std::map "temp" with a pair <vertex, STensor3>
   // for each vertex of the face gf. 
   unsigned int i;
   int j;
@@ -74,7 +76,7 @@ void Frame_field::init_face(GFace* gf){
   MVertex* vertex;
   MElement* element;
   MElementOctree* octree;
-  Matrix m;
+  STensor3 m(1.0);
 
   backgroundMesh::set(gf);
   octree = backgroundMesh::current()->get_octree();
@@ -102,7 +104,7 @@ void Frame_field::init_face(GFace* gf){
 	    ok = translate(gf,octree,vertex,SPoint2(average_x,average_y),v1,v2);
 	  }
 	  else{
-        ok = improved_translate(gf,vertex,v1,v2);
+	    ok = improved_translate(gf,vertex,v1,v2);
 	  }
       
       if(ok){
@@ -119,7 +121,7 @@ void Frame_field::init_face(GFace* gf){
 	m.set_m13(v3.x());
 	m.set_m23(v3.y());
 	m.set_m33(v3.z());
-	temp.insert(std::pair<MVertex*,Matrix>(vertex,m));
+	temp.insert(std::pair<MVertex*,STensor3>(vertex,m));
       }
     }
   }
@@ -212,7 +214,7 @@ bool Frame_field::improved_translate(GFace* gf,MVertex* vertex,SVector3& v1,SVec
   return 1;
 }
 
-Matrix Frame_field::search(double x,double y,double z){
+STensor3 Frame_field::search(double x,double y,double z){
   // Determines the frame/cross at location (x,y,z)
   int index=0;
 #if defined(HAVE_ANN)
@@ -239,7 +241,7 @@ Matrix Frame_field::search(double x,double y,double z){
   return field[index].second;
 }
 
-Matrix Frame_field::combine(double x,double y,double z){
+STensor3 Frame_field::combine(double x,double y,double z){
   // Determines the frame/cross at location (x,y,z)
   // Alternative to Frame_field::search
   bool ok;
@@ -247,7 +249,7 @@ Matrix Frame_field::combine(double x,double y,double z){
   SVector3 vec,other;
   SVector3 vec1,vec2,vec3;
   SVector3 final1,final2;
-  Matrix m,m2;
+  STensor3 m(1.0),m2(1.0);
 	
   m = search(x,y,z);
   m2 = m;
@@ -323,8 +325,8 @@ void Frame_field::print_field1(){
   SPoint3 p;
   SPoint3 p1,p2,p3,p4,p5,p6;
   MVertex* vertex;
-  std::map<MVertex*,Matrix>::iterator it;
-  Matrix m;
+  std::map<MVertex*,STensor3>::iterator it;
+  STensor3 m(1.0);
 
   k = 0.05;
   std::ofstream file("frame1.pos");
@@ -373,7 +375,7 @@ void Frame_field::print_field2(GRegion* gr){
   SPoint3 p1,p2,p3,p4,p5,p6;
   MVertex* vertex;
   MElement* element;
-  Matrix m;
+  STensor3 m(1.0);
 
   k = 0.05;
   std::ofstream file("frame2.pos");
@@ -456,7 +458,7 @@ int Frame_field::build_vertex_to_vertices(GEntity* gr, int onWhat, bool initiali
     unsigned int n = pElem->getNumVertices();
     for(unsigned int j=0; j<n; j++){
       MVertex* pVertex = pElem->getVertex(j);
-      if(pVertex->onWhat()->dim() != onWhat) continue;
+      if(onWhat >0 && pVertex->onWhat()->dim() != onWhat) continue;
 
       std::map<MVertex*,std::set<MVertex*> >::iterator it = vertex_to_vertices.find(pVertex);
       if(it != vertex_to_vertices.end()){
@@ -581,10 +583,10 @@ void Frame_field::initFace(GFace* gf){
       Area += crossprod(V2-V0,V1-V0);
     }
     Area.normalize(); // average normal over neighbour face elements
-    Matrix m = convert(cross3D(Area));
-    std::map<MVertex*, Matrix>::iterator iter = crossField.find(it->first);
+    STensor3 m = convert(cross3D(Area));
+    std::map<MVertex*, STensor3>::iterator iter = crossField.find(it->first);
     if(iter == crossField.end())
-      crossField.insert(std::pair<MVertex*, Matrix>(it->first,m));
+      crossField.insert(std::pair<MVertex*, STensor3>(it->first,m));
     else
       crossField[it->first] = m;
   }
@@ -594,8 +596,24 @@ void Frame_field::initFace(GFace* gf){
   // compute cumulative cross-data vertices x elements for the whole contour of gf
   std::list<GEdge*> edges = gf->edges();
   vertex_to_elements.clear();
-  for( std::list<GEdge*>::const_iterator it=edges.begin(); it!=edges.end(); it++)
+  //Replace edges by their compounds
+   std::set<GEdge*> mySet;
+   std::list<GEdge*>::iterator it = edges.begin();
+   while(it != edges.end()){
+    if((*it)->getCompound()){
+      GEdge *gec = (GEdge*)(*it)->getCompound();
+      mySet.insert(gec);
+    }
+    else{
+      mySet.insert(*it);
+    }
+    ++it;
+   }
+   edges.clear();
+   edges.insert(edges.begin(), mySet.begin(), mySet.end());
+  for( std::list<GEdge*>::const_iterator it=edges.begin(); it!=edges.end(); it++){
     build_vertex_to_elements(*it,false);
+  }
 
   // align crosses of the contour of "gf" with the tangent to the contour
   for(std::map<MVertex*, std::set<MElement*> >::const_iterator it
@@ -611,13 +629,13 @@ void Frame_field::initFace(GFace* gf){
     SVector3 tangent = edg1.scaledTangent() + edg2.scaledTangent();
     tangent.normalize();
 
-    std::map<MVertex*, Matrix>::iterator iter = crossField.find(pVertex);
+    std::map<MVertex*, STensor3>::iterator iter = crossField.find(pVertex);
     if(iter == crossField.end()) {
       std::cout << "This should not happen: cross not found 1" << std::endl; 
       exit(1);
     }
     cross3D x(cross3D((*iter).second));
-    Matrix m = convert(cross3D(x.getFrst(), tangent));
+    STensor3 m = convert(cross3D(x.getFrst(), tangent));
     crossField[pVertex] = m;
   }
 
@@ -642,7 +660,7 @@ void Frame_field::initFace(GFace* gf){
     MVertex* pVertex0 = it->first;
     if(pVertex0->onWhat()->dim() != 2) continue;
 
-    std::map<MVertex*, Matrix>::iterator iter = crossField.find(pVertex0);
+    std::map<MVertex*, STensor3>::iterator iter = crossField.find(pVertex0);
     cross3D y;
     if(iter == crossField.end()){
       std::cout << "This should not happen: cross not found 2" << std::endl;
@@ -663,9 +681,9 @@ void Frame_field::initFace(GFace* gf){
     }
     cross3D x = cross3D((*iter).second); //nearest cross on contour, x.getFrst() is the normal
 
-    //Matrix m = convert(cross3D(x.getFrst(),y.getScnd()));
+    //STensor3 m = convert(cross3D(x.getFrst(),y.getScnd()));
     SVector3 v1 = y.getFrst();
-    Matrix m = convert( y.rotate(conj(x.rotationToOnSurf(y)))); //rotation around the normal
+    STensor3 m = convert( y.rotate(conj(x.rotationToOnSurf(y)))); //rotation around the normal
     SVector3 v2 = y.getFrst();
     if(fabs(angle(v1,v2)) > 1e-8){
       std::cout << "This should not happen: rotation affected the normal" << std::endl; 
@@ -694,22 +712,22 @@ void Frame_field::initRegion(GRegion* gr, int n){
     // Find the index of the nearest cross on the contour, using annTree
     int index = findAnnIndex(pVertex0->point());
     MVertex* pVertex = listVertices[index];
-    Matrix m = crossField[pVertex];
-    crossField.insert(std::pair<MVertex*, Matrix>(pVertex0,m));
+    STensor3 m = crossField[pVertex];
+    crossField.insert(std::pair<MVertex*, STensor3>(pVertex0,m));
   }
   deleteAnnData();
   buildAnnData(gr,3);
 }
 
-Matrix Frame_field::findCross(double x, double y, double z){
+STensor3 Frame_field::findCross(double x, double y, double z){
   int index = Frame_field::findAnnIndex(SPoint3(x,y,z));
   MVertex* pVertex = Frame_field::listVertices[index];
   return crossField[pVertex];
 }
 
-double Frame_field::findBarycenter(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter, Matrix &m0){
+double Frame_field::findBarycenter(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter, STensor3 &m0){
   double theta, gradient, energy;
-  Matrix m;
+  STensor3 m;
   SVector3 axis;
   bool debug = false;
 
@@ -726,7 +744,7 @@ double Frame_field::findBarycenter(std::map<MVertex*, std::set<MVertex*> >::cons
     MVertex *pVertex = *it;
     if(pVertex->getNum() == pVertex0->getNum()) 
       std::cout << "This should not happen!" << std::endl;
-    std::map<MVertex*, Matrix>::const_iterator itB = crossField.find(pVertex);
+    std::map<MVertex*, STensor3>::const_iterator itB = crossField.find(pVertex);
     if(itB == crossField.end()){ // not found
       std::cout << "This should not happen: cross not found 4" << std::endl; exit(1);
     }
@@ -785,7 +803,7 @@ double Frame_field::smoothRegion(GRegion *gr, int n){
 }
 
 double Frame_field::smooth(){
-  Matrix m, m0;
+  STensor3 m(1.0), m0(1.0);
   double enew, eold;
 
   double energy = 0;
@@ -794,7 +812,7 @@ double Frame_field::smooth(){
 
     //MVertex* pVertex0 = iter->first;
     SVector3 T(0, 0, 0);
-    std::map<MVertex*, Matrix>::iterator itA = crossField.find(iter->first);
+    std::map<MVertex*, STensor3>::iterator itA = crossField.find(iter->first);
     if(itA == crossField.end()){
       std::cout << "This should not happen" << std::endl; exit(1);
     }
@@ -814,7 +832,7 @@ double Frame_field::smooth(){
   return energy;
 }
 
-void Frame_field::save(const std::vector<std::pair<SPoint3, Matrix> > data, 
+void Frame_field::save(const std::vector<std::pair<SPoint3, STensor3> > data, 
 		       const std::string& filename){
   const cross3D origin(SVector3(1,0,0), SVector3(0,1,0));
   SPoint3 p1;
@@ -823,7 +841,7 @@ void Frame_field::save(const std::vector<std::pair<SPoint3, Matrix> > data,
   file << "View \"cross field\" {\n";
   for(unsigned int i=0; i<data.size(); i++){
     SPoint3 p = data[i].first;
-    Matrix m = data[i].second;
+    STensor3 m = data[i].second;
     double val1 = eulerAngleFromQtn(cross3D(m).rotationTo(origin)), val2=val1;
     p1 = SPoint3(p.x() + k*m.get_m11(),
 		 p.y() + k*m.get_m21(),
@@ -854,25 +872,133 @@ void Frame_field::save(const std::vector<std::pair<SPoint3, Matrix> > data,
   file.close();
 }
 
+void Frame_field::recur_connect_vert(MVertex *v,
+				     STensor3 &cross,
+				     std::multimap<MVertex*,MVertex*> &v2v,
+				     std::set<MVertex*> &touched){
+
+  if (touched.find(v) != touched.end()) return;
+  touched.insert(v);
+  //std::map<MVertex*, STensor3>::iterator iterv = crossField.find(v);
+  //STensor3 cross = iterv->second;
+
+  for (std::multimap <MVertex*,MVertex*>::iterator it = v2v.lower_bound(v);
+       it != v2v.upper_bound(v) ; ++it){
+    MVertex *nextV = it->second;
+
+    //change orientation 
+    ///------------------
+    printf("*********************** Changing orientation \n");
+
+    //compute dot product (N0,R0,A0)^T dot (Ni,Ri,Ai)
+    //where N,R,A are the normal, radial and axial direction s
+    std::map<MVertex*, STensor3>::iterator iter = crossField.find(nextV);
+    STensor3 nextCross = iter->second;
+    STensor3 crossT = cross.transpose();
+    STensor3 prod = crossT.operator*=(nextCross);
+    cross.print("cross ");
+    nextCross.print("nextCross ");
+    prod.print("product");
+    fullMatrix<double> mat(3,3); prod.getMat(mat);
+  
+    //find biggest dot product
+    fullVector<int> Id(3);
+    for (int i = 0; i < 3; i++){
+      double maxVal = 0.0;
+      for (int j = 0; j < 3; j++){
+	double val = fabs(mat(i,j));
+	if( val > maxVal ){
+	  maxVal  = val;
+	  Id(i) = j;
+	}
+      }
+    }
+  
+    if (Id(0) +Id(1)+ Id(2) != 3 || (Id(0) == 1 && Id(1)==1 && Id(2)==1)) {
+      std::cout << "This should not happen: sum should be 0+1+2" << std::endl; 
+      printf("Id =%d %d %d \n", Id(0), Id(1), Id(2));
+      //exit(1); 
+      return;
+    }
+
+    //create new cross
+    fullMatrix<double> newmat(3,3); 
+    for (int i = 0; i < 3; i++){
+     for (int j = 0; j < 3; j++){
+       newmat(i,j) = nextCross(Id(j),i);
+     }
+    }
+ 
+    STensor3 newcross; 
+    newcross.setMat(newmat);
+    crossField[iter->first] = newcross;
+    newcross.print("newcross");  
+
+    //continue recursion
+    recur_connect_vert (nextV, newcross, v2v,touched); 
+  }
+
+}
+void Frame_field::continuousCrossField(GRegion *gr, GFace *gf){
+ 
+  printf("continuous cross field \n");
+  
+  //start from a vertex of a face
+  std::list<GFace*> faces = gr->faces();	
+  bool foundFace = false;
+  for(std::list<GFace*>::const_iterator iter=faces.begin(); iter!=faces.end(); iter++){
+    if (*iter == gf){
+      foundFace = true;
+      break;
+    }
+  }
+  if (!foundFace){
+    std::cout << "This should not happen: face does not belong to region" << std::endl; 
+    exit(1);
+  }
+
+  //build connectivity
+  build_vertex_to_vertices(gr, -1, true);
+  std::multimap<MVertex*,MVertex*> v2v;
+  for(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter 
+  	= vertex_to_vertices.begin(); iter != vertex_to_vertices.end(); ++iter){
+    MVertex *v = iter->first;
+    std::set<MVertex*> mySet  = iter->second;
+    for (std::set<MVertex*>::iterator it = mySet.begin(); it!=mySet.end(); ++it){
+      v2v.insert(std::make_pair(v,*it));
+    }
+  }
+
+  //recursive loop
+  MVertex *beginV = gf->getMeshVertex(0);
+  std::set<MVertex*> touched;
+  std::map<MVertex*, STensor3>::iterator iter = crossField.find(beginV);
+  STensor3 bCross = iter->second;
+  recur_connect_vert (beginV,bCross,v2v,touched);
+ 
+}
+
 void Frame_field::saveCrossField(const std::string& filename, double scale, bool full){
   const cross3D origin(SVector3(1,0,0), SVector3(0,1,0));
   SPoint3 p1;
   double k = scale;
   std::ofstream file(filename.c_str());
   file << "View \"cross field\" {\n";
-  for(std::map<MVertex*, Matrix>::const_iterator it = crossField.begin(); 
+  for(std::map<MVertex*, STensor3>::const_iterator it = crossField.begin(); 
       it != crossField.end(); it++){
     SPoint3 p = it->first->point();
-    Matrix m = it->second;
+    STensor3 m = it->second;
     double val1 = eulerAngleFromQtn(cross3D(m).rotationTo(origin))*180./M_PI, val2=val1;
+    //double val1=1.0, val2=1.0;
     p1 = SPoint3(p.x() + k*m.get_m11(),
 		 p.y() + k*m.get_m21(),
-		 p.z() + k*m.get_m31());
+		 p.z() + k*m.get_m31()); 
     print_segment(p,p1,val1,val2,file);
     p1 = SPoint3(p.x() - k*m.get_m11(),
 		 p.y() - k*m.get_m21(),
 		 p.z() - k*m.get_m31());
     if(full) print_segment(p,p1,val1,val2,file);
+    //val1=2.0; val2=2.0;
     p1 = SPoint3(p.x() + k*m.get_m12(),
 		 p.y() + k*m.get_m22(),
 		 p.z() + k*m.get_m32());
@@ -881,6 +1007,7 @@ void Frame_field::saveCrossField(const std::string& filename, double scale, bool
 		 p.y() - k*m.get_m22(),
 		 p.z() - k*m.get_m32());
     if(full) print_segment(p,p1,val1,val2,file);
+    //val1=3.0; val2=3.0;
     p1 = SPoint3(p.x() + k*m.get_m13(),
 		 p.y() + k*m.get_m23(),
 		 p.z() + k*m.get_m33());
@@ -1563,9 +1690,9 @@ void Nearest_point::clear(){
 
 /****************static declarations****************/
 
-std::map<MVertex*,Matrix> Frame_field::temp;
-std::vector<std::pair<MVertex*,Matrix> > Frame_field::field;
-std::map<MVertex*, Matrix> Frame_field::crossField;
+std::map<MVertex*,STensor3> Frame_field::temp;
+std::vector<std::pair<MVertex*,STensor3> > Frame_field::field;
+std::map<MVertex*, STensor3> Frame_field::crossField;
 std::map<MEdge, double, Less_Edge> Frame_field::crossDist;
 std::map<MVertex*,std::set<MVertex*> > Frame_field::vertex_to_vertices;
 std::map<MVertex*,std::set<MElement*> > Frame_field::vertex_to_elements;
diff --git a/Mesh/directions3D.h b/Mesh/directions3D.h
index 6316bf4fdb256b354f322379bac9a5a9f2e71810..ce418ef83456a78b7ee3090dbb09199ad51d4394 100644
--- a/Mesh/directions3D.h
+++ b/Mesh/directions3D.h
@@ -16,18 +16,18 @@
 #include <ANN/ANN.h>
 #endif
 #include "yamakawa.h"
-#include "Matrix.h"
+#include "STensor3.h"
 
 struct lowerThan {
-  bool operator() (const std::pair<int, Matrix>& lhs, const std::pair<int, Matrix>& rhs) const
+  bool operator() (const std::pair<int, STensor3>& lhs, const std::pair<int, STensor3>& rhs) const
   {return lhs.first < rhs.first;}
 };
 
 class Frame_field{
  private:
-  static std::map<MVertex*, Matrix> temp;
-  static std::vector<std::pair<MVertex*, Matrix> > field;
-  static std::map<MVertex*, Matrix> crossField;
+  static std::map<MVertex*, STensor3> temp;
+  static std::vector<std::pair<MVertex*, STensor3> > field;
+  static std::map<MVertex*, STensor3> crossField;
   static std::map<MEdge, double, Less_Edge> crossDist;
   static std::vector<MVertex*> listVertices;
 #if defined(HAVE_ANN)
@@ -42,8 +42,8 @@ class Frame_field{
   static void init_face(GFace*);
   static bool translate(GFace*,MElementOctree*,MVertex*,SPoint2,SVector3&,SVector3&);
   static bool improved_translate(GFace*,MVertex*,SVector3&,SVector3&);
-  static Matrix search(double,double,double);
-  static Matrix combine(double,double,double);
+  static STensor3 search(double,double,double);
+  static STensor3 combine(double,double,double);
   static bool inside_domain(MElementOctree*,double,double);
   static double get_ratio(GFace*,SPoint2);
   static void print_field1();
@@ -57,16 +57,18 @@ class Frame_field{
   static int buildAnnData(GEntity* ge, int dim);
   static void deleteAnnData();
   static int findAnnIndex(SPoint3 p);
-  static Matrix findCross(double x, double y, double z);
+  static STensor3 findCross(double x, double y, double z);
   static void initFace(GFace* gf);
   static void initRegion(GRegion* gr, int n);
   static double smoothFace(GFace *gf, int n);
   static double smoothRegion(GRegion *gr, int n);
   static double smooth();
-  static double findBarycenter(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter, Matrix &m0);
-  static void save(const std::vector<std::pair<SPoint3, Matrix> > data, 
+  static double findBarycenter(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter, STensor3 &m0);
+  static void save(const std::vector<std::pair<SPoint3, STensor3> > data, 
 		   const std::string& filename);
   static void saveCrossField(const std::string& filename, double scale, bool full=true);
+  static void continuousCrossField(GRegion *gr, GFace *gf);
+  static void recur_connect_vert(MVertex *v,STensor3 &cross, std::multimap<MVertex*,MVertex*> &v2v,  std::set<MVertex*> &touched);
   static void save_energy(GRegion* gr, const std::string& filename);
   static void save_dist(const std::string& filename);
   static void checkAnnData(GEntity* ge, const std::string& filename);
diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp
index 3c9fc1b91e9630a152c9060b346f421d8ed1277c..6e254cf5f4ef7732835888aa1a021e0e20b677e0 100644
--- a/Mesh/meshGRegion.cpp
+++ b/Mesh/meshGRegion.cpp
@@ -27,6 +27,7 @@
 #include "meshGRegionMMG3D.h"
 #include "simple3D.h"
 #include "Levy3D.h"
+#include "directions3D.h"
 
 #if defined(HAVE_ANN)
 #include "ANN/ANN.h"
@@ -205,125 +206,6 @@ void printVoronoi(GRegion *gr,  std::set<SPoint3> &candidates)
 
 }
 
-void skeletonFromVoronoi(GRegion *gr, std::set<SPoint3> &voronoiPoles)
-{
-  std::vector<MTetrahedron*> elements = gr->tetrahedra;
-  std::list<GFace*> allFaces = gr->faces();
-
-  std::set<SPoint3> candidates;
-  std::set<SPoint3> seeds;
-
-  printf("computing box and barycenters\n");
-  double Dmax = -1.0;
-  std::list<GFace*>::iterator itf =  allFaces.begin();
-  for(; itf != allFaces.end(); itf ++){
-    SBoundingBox3d bbox = (*itf)->bounds();
-    SVector3 dd(bbox.max(), bbox.min());
-    //if( (*itf)->tag()==5904 || (*itf)->tag()==5902  || (*itf)->tag()==5906) {
-    //if( (*itf)->tag()==6 || (*itf)->tag()==28){
-    if( (*itf)->tag() !=1 ) {
-      Dmax = std::max(Dmax,norm(dd));
-      seeds.insert(bbox.center());
-    }
-  }
-  printf("Dmax =%g \n", Dmax);
-
-  printf("printing skeleton nodes \n");
-  FILE *outfile;
-  outfile = fopen("skeletonNodes.pos", "w");
-  fprintf(outfile, "View \"skeleton nodes\" {\n");
-  for(unsigned int i = 0; i < elements.size(); i++){
-    MTetrahedron *ele = elements[i];
-    SPoint3 pc = ele->circumcenter();
-    double x[3] = {pc.x(), pc.y(), pc.z()};
-    double uvw[3];
-    ele->xyz2uvw(x, uvw);
-
-    std::set<SPoint3>::const_iterator it2 = voronoiPoles.find(pc);
-
-    if(ele->isInside(uvw[0], uvw[1], uvw[2]) &&
-       it2 != voronoiPoles.end()){
-      double radius =  ele->getCircumRadius();
-      if(radius > Dmax/10.) {
-      	candidates.insert(pc);
-	fprintf(outfile,"SP(%g,%g,%g)  {%g};\n",
-		pc.x(), pc.y(), pc.z(),  radius);
-      }
-   }
-  }
-  fprintf(outfile,"};\n");
-  fclose(outfile);
-
-  printf("Ann computation of neighbours and writing edges\n");
-
-#if defined(HAVE_ANN)
-  FILE *outfile2;
-  outfile2 = fopen("skeletonEdges.pos", "w");
-  fprintf(outfile2, "View \"skeleton edges\" {\n");
-
-  ANNkd_tree *_kdtree;
-  ANNpointArray _zeronodes;
-  ANNidxArray _index;
-  ANNdistArray _dist;
-
-  std::set<SPoint3>::iterator itseed = seeds.begin();
-  SPoint3 beginPt=*itseed;
-  seeds.erase(itseed);
-  itseed = seeds.begin();
-  for(; itseed != seeds.end(); itseed++){
-    printf("seed =%g %g %g \n", (*itseed).x(), (*itseed).y(), (*itseed).z());
-    candidates.insert(*itseed);
-  }
-  printf("begin seed =%g %g %g \n", beginPt.x(), beginPt.y(), beginPt.z());
-
-  double color = 1.;
-  while(candidates.size()>0){
-
-  _zeronodes = annAllocPts(candidates.size(), 3);
-  std::set<SPoint3>::iterator itset = candidates.begin();
-  int i=0;
-  for(; itset != candidates.end(); itset++){
-    _zeronodes[i][0] = (*itset).x();
-    _zeronodes[i][1] = (*itset).y();
-    _zeronodes[i][2] = (*itset).z();
-    i++;
-  }
-  _kdtree = new ANNkd_tree(_zeronodes, candidates.size(), 3);
-  _index = new ANNidx[1];
-  _dist = new ANNdist[1];
-
-  double xyz[3] = {beginPt.x(), beginPt.y(), beginPt.z()};
-  _kdtree->annkSearch(xyz, 1, _index, _dist);
-  SPoint3 endPt( _zeronodes[_index[0]][0], _zeronodes[_index[0]][1], _zeronodes[_index[0]][2]);
-  fprintf(outfile2,"SL(%g,%g,%g,%g,%g,%g)  {%g,%g};\n",
-	  beginPt.x(), beginPt.y(), beginPt.z(),
-	  endPt.x(), endPt.y(), endPt.z(),
-	  color, color);
-
-   std::set<SPoint3>::iterator itse=seeds.find(endPt);
-   std::set<SPoint3>::iterator its=candidates.find(endPt);
-   if(itse != seeds.end()){
-     printf("found seed =%g %g %g \n", endPt.x(), endPt.y(), endPt.z());
-     seeds.erase(itse);
-     beginPt = *(seeds.begin());
-     std::set<SPoint3>::iterator itsee=candidates.find(beginPt);
-     if (itsee != candidates.end()) candidates.erase(itsee);
-     color=color*2.;
-   }
-   else   beginPt=endPt;
-
-   if(its != candidates.end()) candidates.erase(its);
-
-  delete _kdtree;
-  annDeallocPts(_zeronodes);
-  delete [] _index;
-  delete [] _dist;
-  }
-
-  fprintf(outfile2,"};\n");
-  fclose(outfile2);
-#endif
-}
 
 void getBoundingInfoAndSplitQuads(GRegion *gr,
                                   std::map<MFace,GEntity*,Less_Face> &allBoundingFaces,
@@ -734,15 +616,9 @@ void MeshDelaunayVolume(std::vector<GRegion*> &regions)
   // restore the initial set of faces
   gr->set(faces);
 
-  // EMI Voronoi for centerlines
-  if (Msg::GetVerbosity() == 20) {
-    std::set<SPoint3> candidates;
-    printVoronoi(gr, candidates);
-    skeletonFromVoronoi(gr, candidates);
-  }
-
   modifyInitialMeshForTakingIntoAccountBoundaryLayers(gr);
 
+
   // now do insertion of points
  if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_DEL)
    bowyerWatsonFrontalLayers(gr, false);
@@ -756,6 +632,24 @@ void MeshDelaunayVolume(std::vector<GRegion*> &regions)
      insertVerticesInRegion(gr);
    }
 
+  // //emi test frame field
+  // int NumSmooth = 10;//CTX::instance()->mesh.smoothCrossField
+  // std::cout << "NumSmooth = " << NumSmooth << std::endl;
+  // if(NumSmooth && (gr->dim() == 3)){
+  //   double scale = gr->bounds().diag()*1e-2;
+  //   Frame_field::initRegion(gr,NumSmooth);
+  //   Frame_field::saveCrossField("cross0.pos",scale);
+  //   Frame_field::smoothRegion(gr,NumSmooth);
+  //   Frame_field::saveCrossField("cross1.pos",scale);
+  //   GFace *gf = GModel::current()->getFaceByTag(2);
+  //   Frame_field::continuousCrossField(gr,gf);
+  //   Frame_field::saveCrossField("cross2.pos",scale);
+  // }
+  // Frame_field::init_region(gr);
+  // Frame_field::clear();
+  // exit(1);
+  // //fin test emi
+
  if (sqr.buildPyramids (gr->model())){
    // relocate vertices if pyramids
    for(unsigned int k = 0; k < regions.size(); k++){
diff --git a/Mesh/simple3D.cpp b/Mesh/simple3D.cpp
index 612bc149f87603496d2c5d32906cab51ca157149..e729a105101d391bbb018ce213b65689118769d4 100644
--- a/Mesh/simple3D.cpp
+++ b/Mesh/simple3D.cpp
@@ -500,7 +500,7 @@ void Filler::treat_region(GRegion* gr){
 
 Metric Filler::get_metric(double x,double y,double z){
   Metric m;
-  Matrix m2;
+  STensor3 m2;
   if(CTX::instance()->mesh.smoothCrossField){
     m2 = Frame_field::findCross(x,y,z);
   }
diff --git a/benchmarks/2d/naca12_2d.geo b/benchmarks/2d/naca12_2d.geo
index dafab665c4533c3d17554c149ec7df4e358488c5..7b84f7f498e61d78818163961dd3800ec3b0c710 100644
--- a/benchmarks/2d/naca12_2d.geo
+++ b/benchmarks/2d/naca12_2d.geo
@@ -1,3 +1,4 @@
+Mesh.LcIntegrationPrecision = 1.e-2;
 lc = .033 ;
 lc2 = 2.2 ;
 lc3 = .033 ;
@@ -223,21 +224,19 @@ Line(8) = {1003,1000};
 Line Loop(9) = {6,7,8,5};
 Line Loop(10) = {2,3,4,1};
 Plane Surface(11) = {9,10};
-
-//Physical Surface(11)={11};
-//Point(9999) = {0.6,0,0,1};
+//Recombine Surface {11};
 
 Field[2] = BoundaryLayer;
 //Field[2].NodesList = {1};
 //Field[2].EdgesList = {1,2,3,4};
 Field[2].EdgesList = {1,2,3,4};
 Field[2].hfar = 1.5;
-Field[2].hwall_n = 0.001;
+Field[2].hwall_n = 0.0008;
 Field[2].hwall_t = 0.01;
-Field[2].ratio = 1.3;
+Field[2].ratio = 1.2;
 Field[2].thickness = .03;
 Field[2].IntersectMetrics = 1;
-//Background Field = 2;
+Background Field = 2;
 
 Field[1] = Box;
 Field[1].VIn = 0.01;
@@ -251,6 +250,6 @@ Field[1].ZMin = -1;
 
 Field[3] = MinAniso;
 Field[3].FieldsList = {1, 2};
-Background Field = 2;
-//BoundaryLayer Field = 2;
-//Recombine Surface {11};
+//Background Field = 2;
+BoundaryLayer Field = 2;
+
diff --git a/benchmarks/centerlines/cyl_centerlines.geo b/benchmarks/centerlines/cyl_centerlines.geo
index 09309bff8c20d3dd7e6d8c70984327040b9aeda8..b7f307b0634cd3781a787d6f6395ceed39d7f991 100644
--- a/benchmarks/centerlines/cyl_centerlines.geo
+++ b/benchmarks/centerlines/cyl_centerlines.geo
@@ -1,4 +1,4 @@
-Mesh.Algorithm = 7; //(1=MeshAdapt, 2=Automatic, 5=Delaunay, 6=Frontal, 7=bamg, 8=delquad)
+Mesh.Algorithm = 1; //(1=MeshAdapt, 2=Automatic, 5=Delaunay, 6=Frontal, 7=bamg, 8=delquad)
 Mesh.Algorithm3D = 7; //(1=tetgen, 4=netgen, 7=mmg3D
 
 Mesh.LcIntegrationPrecision = 1.e-3;