diff --git a/Geo/GRegion.cpp b/Geo/GRegion.cpp
index 60d42b717a4f3f57c90c6ad273b93b21ef09231d..0709934519a3f2a29fa9dedd4def73db9e79972f 100644
--- a/Geo/GRegion.cpp
+++ b/Geo/GRegion.cpp
@@ -31,6 +31,17 @@ GRegion::~GRegion()
   deleteMesh();
 }
 
+void GRegion::set(const std::list<GFace*> f) { 
+  for (std::list<GFace*>::iterator it =  l_faces.begin(); it !=  l_faces.end() ; ++it){
+    (*it)->delRegion(this);
+  }
+  l_faces = f; 
+  for (std::list<GFace*>::iterator it =  l_faces.begin(); it !=  l_faces.end() ; ++it){
+    (*it)->addRegion(this);
+  }
+}
+
+
 void GRegion::deleteMesh()
 {
   for(unsigned int i = 0; i < mesh_vertices.size(); i++) delete mesh_vertices[i];
diff --git a/Geo/GRegion.h b/Geo/GRegion.h
index 1cf1ec2b14fb74b74cef7fcfa0e18e302e26f68f..e6a6733ee6199eb09bea26446dbeb55414a2e580 100644
--- a/Geo/GRegion.h
+++ b/Geo/GRegion.h
@@ -48,7 +48,7 @@ class GRegion : public GEntity {
   // get/set faces that bound the region
   virtual std::list<GFace*> faces() const{ return l_faces; }
   virtual std::list<int> faceOrientations() const{ return l_dirs; }
-  inline void set(const std::list<GFace*> f) { l_faces = f; }
+  void set(const std::list<GFace*> f);
 
   // edges that bound the region
   virtual std::list<GEdge*> edges() const;
diff --git a/Mesh/meshGFaceDelaunayInsertion.cpp b/Mesh/meshGFaceDelaunayInsertion.cpp
index a2e88efa35f1a1877a0fbb69e95fd87a0eef7845..2fd6d76494dad109d40fdf2b3bafbc8709be604c 100644
--- a/Mesh/meshGFaceDelaunayInsertion.cpp
+++ b/Mesh/meshGFaceDelaunayInsertion.cpp
@@ -373,29 +373,6 @@ void connectTris(ITER beg, ITER end)
   }
 }
 
-template <class ITER>
-void connectQuas(ITER beg, ITER end)
-{
-  std::set<edgeXquad> conn;
-  while (beg != end){
-    for (int i = 0; i < 4; i++){
-      edgeXquad fxt(*beg, i);
-      std::set<edgeXquad>::iterator found = conn.find(fxt);
-      if (found == conn.end())
-	conn.insert(fxt);
-      else if (found->t1 != *beg){
-	found->t1->setNeigh(found->i1, *beg);
-	(*beg)->setNeigh(i, found->t1);
-      }
-    }
-    ++beg;
-  }
-}
-
-void connectQuads(std::vector<MQua4*> &l)
-{
-  connectQuas(l.begin(), l.end());
-}
 
 void connectTriangles(std::list<MTri3*> &l)
 {
@@ -583,7 +560,7 @@ bool insertVertex(bool force, GFace *gf, MVertex *v, double *param , MTri3 *t,
     // avoid angles that are too obtuse
     double cosv = ((d1*d1+d2*d2-d3*d3)/(2.*d1*d2));
 
-    if ((d1 < LL * .25 || d2 < LL * .25 || cosv < -0.5) && !force) {
+    if ((d1 < LL * .25 || d2 < LL * .25 || cosv < -.9) && !force) {
       onePointIsTooClose = true;
     }
 
diff --git a/Mesh/meshGFaceDelaunayInsertion.h b/Mesh/meshGFaceDelaunayInsertion.h
index 8782668b315124cfee518ddc8e0827c97ac38b8a..0c6952fe1727f914dcf04ed85b2e22afecaa02da 100644
--- a/Mesh/meshGFaceDelaunayInsertion.h
+++ b/Mesh/meshGFaceDelaunayInsertion.h
@@ -81,48 +81,6 @@ class MTri3
   }
 };
 
-/*        2
-  3 +------------+ 2
-    |            |
-    |            |
-  3 |            | 1
-    |            |
-    |            |
-    +------------+
-  0       0        1 
-	  
-   We require that quads are oriented
-   We'd like to walk into the quad mesh and 
-   create sheets
-   
-   We start from a given quad and one edge
-   We give a path as an array of int's
-   If path[i] == 1 --> 
-      
- */
-
-class MQua4
-{
- protected :
-  MQuadrangle *base;
-  MQua4 *neigh[4];
- public :
- MQua4(MQuadrangle *q) : base(q) {
-    neigh[0] = neigh[1] = neigh[2] = neigh[3] = NULL;}
-  inline MQuadrangle *qua() const { return base; }
-  inline void  setNeigh(int iN , MQua4 *n) { neigh[iN] = n; }
-  inline MQua4 *getNeigh(int iN ) const { return neigh[iN]; }
-  inline int getEdge(MVertex *v1, MVertex *v2){
-    for (int i=0;i<4;i++){
-      MEdge e = base->getEdge(i);
-      if (e.getVertex(0) == v1 && e.getVertex(1) == v2)return i;
-      if (e.getVertex(0) == v2 && e.getVertex(1) == v1)return i;      
-    }
-    return -1;
-  }
-};
-
-
 class compareTri3Ptr
 {
  public:
@@ -134,7 +92,6 @@ class compareTri3Ptr
   }
 };
 
-void connectQuads(std::vector<MQua4*> &);
 void connectTriangles(std::list<MTri3*> &);
 void connectTriangles(std::vector<MTri3*> &);
 void connectTriangles(std::set<MTri3*,compareTri3Ptr> &AllTris);
@@ -163,25 +120,5 @@ struct edgeXface
   }
 };
 
-struct edgeXquad
-{
-  MVertex *v[2];
-  MQua4 * t1;
-  int i1;
-  edgeXquad(MQua4 *_t, int iFac) : t1(_t), i1(iFac)
-  {
-    v[0] = t1->qua()->getVertex(iFac);
-    v[1] = t1->qua()->getVertex((iFac+1)%4);
-    std::sort(v, v + 2);
-  }
-  inline bool operator < ( const edgeXquad &other) const
-  {
-    if(v[0] < other.v[0]) return true;
-    if(v[0] > other.v[0]) return false;
-    if(v[1] < other.v[1]) return true;
-    return false;
-  }
-};
-
 
 #endif
diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp
index 0ed7f546ede8719d4843c1d9a3eb8ff74a7c0ea5..ed0124c00879c2717bb8223f58c833613c60f6a2 100644
--- a/Mesh/meshGRegion.cpp
+++ b/Mesh/meshGRegion.cpp
@@ -19,6 +19,7 @@
 #include "MTriangle.h"
 #include "MQuadrangle.h"
 #include "MTetrahedron.h"
+#include "MPyramid.h"
 #include "BDS.h"
 #include "Context.h"
 #include "GFaceCompound.h"
@@ -30,6 +31,64 @@
 #include "ANN/ANN.h"
 #endif
 
+// hybrid mesh recovery structure
+class splitQuadRecovery {
+  std::multimap<GEntity*, std::pair<MVertex*,MFace> >_data;
+ public : 
+  void add (const MFace &f, MVertex *v, GEntity*ge) ;
+  int buildPyramids (GModel *gm);
+};
+
+void splitQuadRecovery::add (const MFace &f, MVertex *v, GEntity*ge) {
+  _data.insert(std::make_pair(ge, std::make_pair(v,f)));
+}
+
+// re-create quads and 
+int splitQuadRecovery::buildPyramids (GModel *gm) {
+  int NBPY = 0;
+  std::set<MFace,Less_Face> allFaces;
+  for (GModel::fiter it = gm->firstFace(); it != gm->lastFace(); ++it){
+    for (unsigned int i=0; i < (*it)->triangles.size();i++){
+      allFaces.insert ((*it)->triangles[i]->getFace(0));
+      delete (*it)->triangles[i];
+    }
+    (*it)->triangles.clear();
+    for ( std::multimap<GEntity*, std::pair<MVertex*,MFace> >::iterator it2 = _data.lower_bound(*it) ; it2 != _data.upper_bound(*it) ; ++it2) {
+      MVertex *v = it2->second.first;
+      v->onWhat()->mesh_vertices.erase
+	(std::find(v->onWhat()->mesh_vertices.begin(),
+		   v->onWhat()->mesh_vertices.end(),
+		   v));
+      const MFace &f = it2->second.second;
+      std::set<MFace,Less_Face> :: iterator itf0 = allFaces.find(MFace(f.getVertex(0),f.getVertex(1),v));
+      std::set<MFace,Less_Face> :: iterator itf1 = allFaces.find(MFace(f.getVertex(1),f.getVertex(2),v));
+      std::set<MFace,Less_Face> :: iterator itf2 = allFaces.find(MFace(f.getVertex(2),f.getVertex(3),v));
+      std::set<MFace,Less_Face> :: iterator itf3 = allFaces.find(MFace(f.getVertex(3),f.getVertex(0),v));
+      if (itf0 != allFaces.end() && itf1 != allFaces.end() && itf2 != allFaces.end() && itf3 != allFaces.end() ){
+	(*it)->quadrangles.push_back(new MQuadrangle(f.getVertex(0),f.getVertex(1),f.getVertex(2),f.getVertex(3)));
+	allFaces.erase(*itf0);
+	allFaces.erase(*itf1);
+	allFaces.erase(*itf2);
+	allFaces.erase(*itf3);
+
+	//	printf("some pyramids should be created %d regions\n",(*it)->numRegions());
+	for (int iReg = 0; iReg < (*it)->numRegions(); iReg++){
+	  //	  printf("one pyramid is created\n");
+	  if (iReg == 1) {Msg::Fatal("cannot build pyramids on non manifold faces ..."); v = new MVertex (v->x(),v->y(),v->z(),(*it)->getRegion(iReg)); }
+	  else v->setEntity ((*it)->getRegion(iReg));
+	  (*it)->getRegion(iReg)->pyramids.push_back(new MPyramid(f.getVertex(0),f.getVertex(1),f.getVertex(2),f.getVertex(3),v));      
+	  (*it)->getRegion(iReg)->mesh_vertices.push_back(v);
+	  NBPY++;
+	}
+      }
+    }
+    for (std::set<MFace,Less_Face> :: iterator itf = allFaces.begin() ; itf != allFaces.end(); ++itf){
+      (*it)->triangles.push_back(new MTriangle(itf->getVertex(0),itf->getVertex(1),itf->getVertex(2)));
+    }        
+  }
+  return NBPY;
+}
+
 void printVoronoi(GRegion *gr,  std::set<SPoint3> &candidates)
 {
   std::vector<MTetrahedron*> elements = gr->tetrahedra;
@@ -254,6 +313,72 @@ void skeletonFromVoronoi(GRegion *gr, std::set<SPoint3> &voronoiPoles)
 #endif
 }
 
+void getBoundingInfoAndSplitQuads (GRegion *gr, 
+				   std::map<MFace,GEntity*,Less_Face> &allBoundingFaces,
+				   std::set<MVertex*> &allBoundingVertices,
+				   splitQuadRecovery &sqr){
+  
+  std::map<MFace,GEntity*,Less_Face> allBoundingFaces_temp;
+
+  // Get all the faces that are on the boundary
+  std::list<GFace*> faces = gr->faces();
+  std::list<GFace*>::iterator it = faces.begin();
+  while (it != faces.end()){
+    GFace *gf = (*it);
+    for(unsigned int i = 0; i < gf->getNumMeshElements(); i++){
+      allBoundingFaces_temp[gf->getMeshElement(i)->getFace(0)] = gf;
+    }
+    ++it;
+  }
+
+  // if some elements pre-exist in the mesh, then use the
+  // internal faces of those
+
+  for (unsigned int i=0;i<gr->getNumMeshElements();i++){
+    MElement *e = gr->getMeshElement(i);
+    for (int j=0;j<e->getNumFaces();j++){
+      std::map<MFace,GEntity*,Less_Face>::iterator it = allBoundingFaces_temp.find(e->getFace(j));
+      if (it == allBoundingFaces_temp.end())allBoundingFaces_temp[e->getFace(j)] = gr;
+      else allBoundingFaces_temp.erase(it);
+    }
+  }
+  
+  std::map<MFace,GEntity*,Less_Face>::iterator itx = allBoundingFaces_temp.begin();
+  for (; itx != allBoundingFaces_temp.end();++itx){
+    const MFace &f = itx->first;
+    // SPLIT that face into 4 triangular faces 
+    if (f.getNumVertices() == 4){
+      MVertex *v0 = f.getVertex(0); 
+      MVertex *v1 = f.getVertex(1); 
+      MVertex *v2 = f.getVertex(2); 
+      MVertex *v3 = f.getVertex(3); 
+
+      MVertex *newv = new MVertex ((v0->x() + v1->x() + v2->x() + v3->x())*0.25,
+				   (v0->y() + v1->y() + v2->y() + v3->y())*0.25,
+				   (v0->z() + v1->z() + v2->z() + v3->z())*0.25,itx->second); 
+      sqr.add(f,newv,itx->second);
+      allBoundingFaces[MFace(v0,v1,newv)] = itx->second;
+      allBoundingFaces[MFace(v1,v2,newv)] = itx->second;
+      allBoundingFaces[MFace(v2,v3,newv)] = itx->second;
+      allBoundingFaces[MFace(v3,v0,newv)] = itx->second;
+      itx->second->mesh_vertices.push_back(newv);
+      //      myGr->pyramids.push_back(new MPyramid(v0,v1,v2,v3,newv));      
+      allBoundingVertices.insert(v0);
+      allBoundingVertices.insert(v1);
+      allBoundingVertices.insert(v2);
+      allBoundingVertices.insert(v3);
+      allBoundingVertices.insert(newv);
+    }
+    else{
+      allBoundingFaces[f] = itx->second;
+      allBoundingVertices.insert(f.getVertex(0));
+      allBoundingVertices.insert(f.getVertex(1));
+      allBoundingVertices.insert(f.getVertex(2));
+    }
+  }  
+}
+
+
 void getAllBoundingVertices(GRegion *gr, std::set<MVertex*> &allBoundingVertices)
 {
   std::list<GFace*> faces = gr->faces();
@@ -273,10 +398,13 @@ void getAllBoundingVertices(GRegion *gr, std::set<MVertex*> &allBoundingVertices
 
 #if defined(HAVE_TETGEN)
 #include "tetgen.h"
-void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numberedV)
+void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numberedV,  splitQuadRecovery &sqr)
 {
   std::set<MVertex*> allBoundingVertices;
-  getAllBoundingVertices(gr, allBoundingVertices);
+  std::map<MFace,GEntity*,Less_Face> allBoundingFaces;
+  getBoundingInfoAndSplitQuads (gr, allBoundingFaces,allBoundingVertices,sqr);
+  
+  //getAllBoundingVertices(gr, allBoundingVertices);
 
   in.mesh_dim = 3;
   in.firstnumber = 1;
@@ -314,42 +442,29 @@ void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numb
 	I++;
   }
 
-  int nbFace = 0;
-  std::list<GFace*> faces = gr->faces();
-  std::list<GFace*>::iterator it = faces.begin();
-  while(it != faces.end()){
-    GFace *gf = (*it);
-    nbFace += gf->triangles.size();
-    ++it;
-  }
-
-  in.numberoffacets = nbFace;
+  in.numberoffacets = allBoundingFaces.size();
   in.facetlist = new tetgenio::facet[in.numberoffacets];
   in.facetmarkerlist = new int[in.numberoffacets];
-
-  it = faces.begin();
+  
   I = 0;
-  while(it != faces.end()){
-    GFace *gf = (*it);
-    for(unsigned int i = 0; i < gf->triangles.size(); i++){
-      MTriangle *t = gf->triangles[i];
-      tetgenio::facet *f = &in.facetlist[I];
-      tetgenio::init(f);
-      f->numberofholes = 0;
-      f->numberofpolygons = 1;
-      f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
-      tetgenio::polygon *p = &f->polygonlist[0];
-      tetgenio::init(p);
-      p->numberofvertices = 3;
-      p->vertexlist = new int[p->numberofvertices];
-      p->vertexlist[0] = t->getVertex(0)->getIndex();
-      p->vertexlist[1] = t->getVertex(1)->getIndex();
-      p->vertexlist[2] = t->getVertex(2)->getIndex();
-      in.facetmarkerlist[I] = gf->tag();
-      ++I;
-    }
-    ++it;
-  }
+  std::map<MFace,GEntity*,Less_Face>::iterator it = allBoundingFaces.begin();
+  for (; it != allBoundingFaces.end();++it){
+    const MFace &fac = it->first;
+    tetgenio::facet *f = &in.facetlist[I];
+    tetgenio::init(f);
+    f->numberofholes = 0;
+    f->numberofpolygons = 1;
+    f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
+    tetgenio::polygon *p = &f->polygonlist[0];
+    tetgenio::init(p);
+    p->numberofvertices = 3;
+    p->vertexlist = new int[p->numberofvertices];
+    p->vertexlist[0] = fac.getVertex(0)->getIndex();
+    p->vertexlist[1] = fac.getVertex(1)->getIndex();
+    p->vertexlist[2] = fac.getVertex(2)->getIndex();
+    in.facetmarkerlist[I] = (it->second->dim() == 3) ? -it->second->tag() : it->second->tag();
+    ++I;    
+  }  
 }
 
 void TransferTetgenMesh(GRegion *gr, tetgenio &in, tetgenio &out,
@@ -379,7 +494,10 @@ void TransferTetgenMesh(GRegion *gr, tetgenio &in, tetgenio &out,
     GFace *gf = (*it);
     for(unsigned int i = 0; i < gf->triangles.size(); i++)
       delete gf->triangles[i];
+    for(unsigned int i = 0; i < gf->quadrangles.size(); i++)
+      delete gf->quadrangles[i];
     gf->triangles.clear();
+    gf->quadrangles.clear();
     gf->deleteVertexArrays();
   }
 
@@ -397,87 +515,89 @@ void TransferTetgenMesh(GRegion *gr, tetgenio &in, tetgenio &out,
   // nodes for non manifold geometries (single surface connected to
   // volume)
   for(int i = 0; i < out.numberoftrifaces; i++){
-    MVertex *v[3];
-    v[0] = numberedV[out.trifacelist[i * 3 + 0] - 1];
-    v[1] = numberedV[out.trifacelist[i * 3 + 1] - 1];
-    v[2] = numberedV[out.trifacelist[i * 3 + 2] - 1];
-    GFace *gf = gr->model()->getFaceByTag(out.trifacemarkerlist[i]);
-
-    double guess[2] = {0, 0};
-    if (needParam) {
-      int Count = 0;
-      for(int j = 0; j < 3; j++){
-	if(!v[j]->onWhat()){
-	  Msg::Error("Uncategorized vertex %d", v[j]->getNum());
-	}
-	else if(v[j]->onWhat()->dim() == 2){
-	  double uu,vv;
-	  v[j]->getParameter(0, uu);
-	  v[j]->getParameter(1, vv);
-	  guess[0] += uu;
-	  guess[1] += vv;
-	  Count++;
+    if (out.trifacemarkerlist[i] > 0) {
+      MVertex *v[3];
+      v[0] = numberedV[out.trifacelist[i * 3 + 0] - 1];
+      v[1] = numberedV[out.trifacelist[i * 3 + 1] - 1];
+      v[2] = numberedV[out.trifacelist[i * 3 + 2] - 1];
+      // do not recover prismatic faces !!!
+      GFace *gf = gr->model()->getFaceByTag(out.trifacemarkerlist[i]);
+      
+      double guess[2] = {0, 0};
+      if (needParam) {
+	int Count = 0;
+	for(int j = 0; j < 3; j++){
+	  if(!v[j]->onWhat()){
+	    Msg::Error("Uncategorized vertex %d", v[j]->getNum());
+	  }
+	  else if(v[j]->onWhat()->dim() == 2){
+	    double uu,vv;
+	    v[j]->getParameter(0, uu);
+	    v[j]->getParameter(1, vv);
+	    guess[0] += uu;
+	    guess[1] += vv;
+	    Count++;
+	  }
+	  else if(v[j]->onWhat()->dim() == 1){
+	    GEdge *ge = (GEdge*)v[j]->onWhat();
+	    double UU;
+	    v[j]->getParameter(0, UU);
+	    SPoint2 param;
+	    param = ge->reparamOnFace(gf, UU, 1);
+	    guess[0] += param.x();
+	    guess[1] += param.y();
+	    Count++;
+	  }
+	  else if(v[j]->onWhat()->dim() == 0){
+	    SPoint2 param;
+	    GVertex *gv = (GVertex*)v[j]->onWhat();
+	    param = gv->reparamOnFace(gf,1);
+	    guess[0] += param.x();
+	    guess[1] += param.y();
+	    Count++;
+	  }
 	}
-	else if(v[j]->onWhat()->dim() == 1){
-	  GEdge *ge = (GEdge*)v[j]->onWhat();
-	  double UU;
-	  v[j]->getParameter(0, UU);
-	  SPoint2 param;
-	  param = ge->reparamOnFace(gf, UU, 1);
-	  guess[0] += param.x();
-	  guess[1] += param.y();
-	  Count++;
+	if(Count != 0){
+	  guess[0] /= Count;
+	  guess[1] /= Count;
 	}
-	else if(v[j]->onWhat()->dim() == 0){
-	  SPoint2 param;
-	  GVertex *gv = (GVertex*)v[j]->onWhat();
-	  param = gv->reparamOnFace(gf,1);
-	  guess[0] += param.x();
-	  guess[1] += param.y();
-	  Count++;
-	}
-      }
-      if(Count != 0){
-	guess[0] /= Count;
-	guess[1] /= Count;
       }
-    }
-
-    for(int j = 0; j < 3; j++){
-      if(v[j]->onWhat()->dim() == 3){
-        v[j]->onWhat()->mesh_vertices.erase
-          (std::find(v[j]->onWhat()->mesh_vertices.begin(),
-                     v[j]->onWhat()->mesh_vertices.end(),
-                     v[j]));
-        MVertex *v1b;
-        if(needParam){
-          // parametric coordinates should be set for the vertex !
-          // (this is not 100 % safe yet, so we reserve that operation
-          // for high order meshes)
-          GPoint gp = gf->closestPoint(SPoint3(v[j]->x(), v[j]->y(), v[j]->z()), guess);
-          if(gp.g()){
-            v1b = new MFaceVertex(gp.x(), gp.y(), gp.z(), gf, gp.u(), gp.v());
-          }
-          else{
-            v1b = new MVertex(v[j]->x(), v[j]->y(), v[j]->z(), gf);
-            Msg::Warning("The point was not projected back to the surface (%g %g %g)",
-                         v[j]->x(), v[j]->y(), v[j]->z());
-          }
-        }
-        else{
-          v1b = new MVertex(v[j]->x(), v[j]->y(), v[j]->z(), gf);
-        }
-
-        gf->mesh_vertices.push_back(v1b);
-        numberedV[out.trifacelist[i * 3 + j] - 1] = v1b;
-        delete v[j];
-        v[j] = v1b;
+      
+      for(int j = 0; j < 3; j++){
+	if(v[j]->onWhat()->dim() == 3){
+	  v[j]->onWhat()->mesh_vertices.erase
+	    (std::find(v[j]->onWhat()->mesh_vertices.begin(),
+		       v[j]->onWhat()->mesh_vertices.end(),
+		       v[j]));
+	  MVertex *v1b;
+	  if(needParam){
+	    // parametric coordinates should be set for the vertex !
+	    // (this is not 100 % safe yet, so we reserve that operation
+	    // for high order meshes)
+	    GPoint gp = gf->closestPoint(SPoint3(v[j]->x(), v[j]->y(), v[j]->z()), guess);
+	    if(gp.g()){
+	      v1b = new MFaceVertex(gp.x(), gp.y(), gp.z(), gf, gp.u(), gp.v());
+	    }
+	    else{
+	      v1b = new MVertex(v[j]->x(), v[j]->y(), v[j]->z(), gf);
+	      Msg::Warning("The point was not projected back to the surface (%g %g %g)",
+			   v[j]->x(), v[j]->y(), v[j]->z());
+	    }
+	  }
+	  else{
+	    v1b = new MVertex(v[j]->x(), v[j]->y(), v[j]->z(), gf);
+	  }
+	  
+	  gf->mesh_vertices.push_back(v1b);
+	  numberedV[out.trifacelist[i * 3 + j] - 1] = v1b;
+	  delete v[j];
+	  v[j] = v1b;
+	}
       }
-    }
-    MTriangle *t = new MTriangle(v[0], v[1], v[2]);
-    gf->triangles.push_back(t);
+      MTriangle *t = new MTriangle(v[0], v[1], v[2]);
+      gf->triangles.push_back(t);
+    }// do not do anything with prismatic faces
   }
-
   for(int i = 0; i < out.numberoftetrahedra; i++){
     MVertex *v1 = numberedV[out.tetrahedronlist[i * 4 + 0] - 1];
     MVertex *v2 = numberedV[out.tetrahedronlist[i * 4 + 1] - 1];
@@ -494,6 +614,34 @@ static void modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
   buildAdditionalPoints3D (gr);
 }
 
+void _relocateVertex(MVertex *ver,
+		     const std::vector<MElement*> &lt)
+{
+  if(ver->onWhat()->dim() != 3) return;
+  double x = 0, y=0, z=0;
+  int N = 0;
+  bool isPyramid = false;
+  for(unsigned int i = 0; i < lt.size(); i++){
+    double XCG=0,YCG=0,ZCG=0;
+    for (int j=0;j<lt[i]->getNumVertices();j++){
+      XCG += lt[i]->getVertex(j)->x();
+      YCG += lt[i]->getVertex(j)->y();
+      ZCG += lt[i]->getVertex(j)->z();
+    }
+    x += XCG;
+    y += YCG;
+    z += ZCG;
+    if (lt[i]->getNumVertices() == 5) isPyramid = true;
+    N += lt[i]->getNumVertices();
+  }
+  if (isPyramid){
+    ver->x() = x / N;
+    ver->y() = y / N;
+    ver->z() = z / N;
+  }
+}
+
+
 
 void MeshDelaunayVolume(std::vector<GRegion*> &regions)
 {
@@ -523,21 +671,26 @@ void MeshDelaunayVolume(std::vector<GRegion*> &regions)
 
   // mesh with tetgen, possibly changing the mesh on boundaries (leave
   // this in block, so in/out are destroyed before we refine the mesh)
+  splitQuadRecovery sqr;
   {
     tetgenio in, out;
     std::vector<MVertex*> numberedV;
     char opts[128];
-    buildTetgenStructure(gr, in, numberedV);
+    buildTetgenStructure(gr, in, numberedV, sqr);
+    // JFR REMOVED THE -q OPTION BECAUSE MESH SIZES AT VERTICES WERE WRONG ...
+    // COULD BE FIXED IF NEEDED
     if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_DEL ||
        CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_HEX ||
        CTX::instance()->mesh.algo3d == ALGO_3D_MMG3D ||
        CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL_QUAD ||
        CTX::instance()->mesh.algo2d == ALGO_2D_BAMG){
-      sprintf(opts, "-q1.5pY%c",  (Msg::GetVerbosity() < 3) ? 'Q':
+      sprintf(opts, "-pY%c",  (Msg::GetVerbosity() < 3) ? 'Q':
 	      (Msg::GetVerbosity() > 6) ? 'V': '\0');
+      // sprintf(opts, "-q1.5pY%c",  (Msg::GetVerbosity() < 3) ? 'Q':
+      // 	      (Msg::GetVerbosity() > 6) ? 'V': '\0');
     }
     else {
-      sprintf(opts, "-q3.5Ype%c",  (Msg::GetVerbosity() < 3) ? 'Q':
+      sprintf(opts, "-Ype%c",  (Msg::GetVerbosity() < 3) ? 'Q':
       	      (Msg::GetVerbosity() > 6) ? 'V': '\0');
     }
     try{
@@ -608,8 +761,22 @@ void MeshDelaunayVolume(std::vector<GRegion*> &regions)
  }
  else
    if(!Filler::get_nbr_new_vertices() && !LpSmoother::get_nbr_interior_vertices()){
-     insertVerticesInRegion(gr);
+     insertVerticesInRegion(gr);     
    }
+
+ if (sqr.buildPyramids (gr->model())){
+   // relocate vertices if pyramids
+   for(unsigned int k = 0; k < regions.size(); k++){
+     v2t_cont adj;
+     buildVertexToElement(regions[k]->tetrahedra, adj);
+     buildVertexToElement(regions[k]->pyramids, adj);
+     v2t_cont::iterator it = adj.begin();
+     while (it != adj.end()){
+       //_relocateVertex( it->first, it->second);
+       ++it;
+     }
+   }
+ }
 #endif
 }
 
@@ -872,11 +1039,15 @@ void meshGRegion::operator() (GRegion *gr)
 
   std::list<GFace*> faces = gr->faces();
 
+  // REMOVE SANITY CHECK FOR DELAUNAY : PYRAMIDS AVAILABLE
   // sanity check
-  for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++){
-    if((*it)->quadrangles.size()){
-      Msg::Error("Cannot tetrahedralize volume with quadrangles on boundary");
-      return;
+
+  if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL){
+    for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++){
+      if((*it)->quadrangles.size()){
+	Msg::Error("Cannot tetrahedralize volume with quadrangles on boundary");
+	return;
+      }
     }
   }
 
diff --git a/Mesh/meshGRegion.h b/Mesh/meshGRegion.h
index 542ca262745497206d24fbc98b3862c9472ef5e6..84acb4724b19923c34864403e2141bdc3dee079d 100644
--- a/Mesh/meshGRegion.h
+++ b/Mesh/meshGRegion.h
@@ -69,4 +69,6 @@ class adaptMeshGRegion {
   void operator () (GRegion *);
 };
 
+
+
 #endif
diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp
index ca48affd43236c4f973ef25f4cd4c89edc79c1b6..b6fb73a09bb55f4070f8506728f3f6fc80ffd1b2 100644
--- a/Mesh/qualityMeasures.cpp
+++ b/Mesh/qualityMeasures.cpp
@@ -172,12 +172,42 @@ double qmTet(const double &x1, const double &y1, const double &z1,
       return 2. * sqrt(6.) * rhoin / l;
     }
     break;
+  case QMTET_COND:
+    {
+      /// condition number is defined as (see Knupp & Freitag in IJNME) 
+      double INVW[3][3] = {{1,-1./sqrt(3.),-1./sqrt(6.)},{0,2/sqrt(3.),-1./sqrt(6.)},{0,0,sqrt(1.5)}};
+      double A[3][3] = {{x2-x1,y2-y1,z2-z1},{x3-x1,y3-y1,z3-z1},{x4-x1,y4-y1,z4-z1}};
+      double S[3][3],INVS[3][3];
+      matmat(A,INVW,S);
+      *volume = inv3x3(S,INVS) * 2 / sqrt(2);
+      double normS = norm2 (S);
+      double normINVS = norm2 (INVS);
+      return normS * normINVS;      
+    }
   default:
     Msg::Error("Unknown quality measure");
     return 0.;
   }
 }
 
+/*
+double conditionNumberAndDerivativeOfTet(const double &x1, const double &y1, const double &z1,
+					 const double &x2, const double &y2, const double &z2,
+					 const double &x3, const double &y3, const double &z3,
+					 const double &x4, const double &y4, const double &z4){
+
+  double INVW[3][3] = {{1,-1./sqrt(3.),-1./sqrt(6.)},{0,2/sqrt(3.),-1./sqrt(6.)},{0,0,sqrt(1.5)}};
+      double A[3][3] = {{x2-x1,y2-y1,z2-z1},{x3-x1,y3-y1,z3-z1},{x4-x1,y4-y1,z4-z1}};
+      double S[3][3],INVS[3][3];
+      matmat(A,INVW,S);
+      double sigma = inv3x3(S,INVS);
+      double normS = norm2 (S);
+      double normINVS = norm2 (INVS);
+      conditionNumber = normS * normINVS;      
+  
+}
+*/
+
 double mesh_functional_distorsion(MElement *t, double u, double v)
 {
   // compute uncurved element jacobian d_u x and d_v x
diff --git a/Numeric/Numeric.cpp b/Numeric/Numeric.cpp
index d23bc96d5c337fbb6b3c37597c8889195d80dc54..b6ec2dde2a0fd9cb935632d225419b9775a57243 100644
--- a/Numeric/Numeric.cpp
+++ b/Numeric/Numeric.cpp
@@ -35,6 +35,19 @@ double myacos(double a)
   else
     return acos(a);
 }
+double norm2(double a[3][3]) {
+  double norm2sq = 
+    SQU(a[0][0])+
+    SQU(a[0][1])+
+    SQU(a[0][2])+
+    SQU(a[1][0])+
+    SQU(a[1][1])+
+    SQU(a[1][2])+
+    SQU(a[2][0])+
+    SQU(a[2][1])+
+    SQU(a[2][2]);
+  return sqrt(norm2sq);
+}
 
 void matvec(double mat[3][3], double vec[3], double res[3])
 {
diff --git a/Numeric/Numeric.h b/Numeric/Numeric.h
index c7e3294810a59a071ad148458d8981ff4383e313..6d9b879fc1edef83e48d2d5ead00b1a92b738ea5 100644
--- a/Numeric/Numeric.h
+++ b/Numeric/Numeric.h
@@ -65,6 +65,8 @@ inline double norme(double a[3])
   }
   return mod;
 }
+double norm2(double a[3][3]);
+
 void normal3points(double x0, double y0, double z0,
                    double x1, double y1, double z1,
                    double x2, double y2, double z2,