diff --git a/Common/Options.cpp b/Common/Options.cpp
index c96f6face5f37f7f80a83594db691f30f31047b0..8b597cb5654c66893b331c1aae83373c5e67f77f 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -5176,12 +5176,10 @@ double opt_mesh_recombine_all(OPT_ARGS_NUM)
 
 double opt_mesh_recombine3d_all(OPT_ARGS_NUM)
 {
-#if defined(HAVE_FLTK)
   if(action & GMSH_SET){
     CTX::instance()->mesh.recombine3DAll = (int)val;
-#if defined(HAVE_FLTK)
-#endif
   }
+#if defined(HAVE_FLTK)
   if(FlGui::available() && (action & GMSH_GUI)){
     FlGui::instance()->options->mesh.butt[22]->value
       (CTX::instance()->mesh.recombine3DAll);
diff --git a/Geo/GFace.h b/Geo/GFace.h
index 40c7d66ba97d6ad95c043621e3b022a9c91719b1..e24a6ff8be6f3cf12d8778751f589469595eeba8 100644
--- a/Geo/GFace.h
+++ b/Geo/GFace.h
@@ -93,6 +93,11 @@ class GFace : public GEntity
   // edges that bound the face
   virtual std::list<GEdge*> edges() const { return l_edges; }
   virtual std::list<int> edgeOrientations() const { return l_dirs; }
+  inline bool containsEdge (int iEdge) const {
+    for (std::list<GEdge*>::const_iterator it = l_edges.begin() ; it !=l_edges.end() ; ++it)
+      if ((*it)->tag() == iEdge) return true;
+    return false;
+  }
 
   // edges that are embedded in the face
   virtual std::list<GEdge*> embeddedEdges() const { return embedded_edges; }
diff --git a/Geo/GModelIO_MESH.cpp b/Geo/GModelIO_MESH.cpp
index f15e22d4b02a2c62cd0049076ad2b45232035d12..7f43d9c57c57bffd32434baec211aca3448e1f60 100644
--- a/Geo/GModelIO_MESH.cpp
+++ b/Geo/GModelIO_MESH.cpp
@@ -109,8 +109,7 @@ int GModel::readMESH(const std::string &name)
         for(int i = 0; i < nbe; i++) {
           if(!fgets(buffer, sizeof(buffer), fp)) break;
           int n[6], cl;
-          sscanf(buffer, "%d %d %d %d %d %d %d", &n[0], &n[1], &n[2],
-                 &n[3], &n[4], &n[5], &cl);
+          sscanf(buffer, "%d %d %d %d %d %d %d", &n[0], &n[1], &n[2], &n[3], &n[4], &n[5],&cl);
           for(int j = 0; j < 6; j++) n[j]--;
           std::vector<MVertex*> vertices;
           if(!getVertices(6, n, vertexVector, vertices)) return 0;
@@ -155,8 +154,7 @@ int GModel::readMESH(const std::string &name)
         for(int i = 0; i < nbe; i++) {
           if(!fgets(buffer, sizeof(buffer), fp)) break;
           int n[10], cl;
-          sscanf(buffer, "%d %d %d %d %d %d %d %d %d %d %d", &n[0], &n[1], &n[2],
-                 &n[3], &n[4], &n[5], &n[6], &n[7], &n[9], &n[8], &cl);
+          sscanf(buffer, "%d %d %d %d %d %d %d %d %d %d %d", &n[0], &n[1], &n[2], &n[3],&n[4], &n[5], &n[6], &n[7], &n[9], &n[8], &cl);
           for(int j = 0; j < 10; j++) n[j]--;
           std::vector<MVertex*> vertices;
           if(!getVertices(10, n, vertexVector, vertices)) return 0;
@@ -204,7 +202,7 @@ int GModel::writeMESH(const std::string &name, int elementTagType,
 
   int numVertices = indexMeshVertices(saveAll);
 
-  fprintf(fp, " MeshVersionFormatted 1\n");
+  fprintf(fp, " MeshVersionFormatted 2\n");
   fprintf(fp, " Dimension\n");
   fprintf(fp, " 3\n");
 
diff --git a/Geo/Geo.cpp b/Geo/Geo.cpp
index cb40e80db9f39cc868abeda76984043f657d1a29..8b30928fa84ef7af39228e2da13e9fc832ffae09 100644
--- a/Geo/Geo.cpp
+++ b/Geo/Geo.cpp
@@ -631,6 +631,7 @@ Volume *Create_Volume(int Num, int Typ)
   pV->SurfacesOrientations = List_Create(1, 2, sizeof(int));
   pV->SurfacesByTag = List_Create(1, 2, sizeof(int));
   pV->Extrude = NULL;
+  pV->Recombine3D = 0;
   return pV;
 }
 
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index 9a5f07bfe76cd206f99c747942a0ae075065c82a..0ccec167fbcf3b871adf0ec771db8927279afed5 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -1067,7 +1067,12 @@ void MElement::writeMESH(FILE *fp, int elementTagType, int elementary,
 {
   setVolumePositive();
   for(int i = 0; i < getNumVertices(); i++)
-    fprintf(fp, " %d", getVertex(i)->getIndex());
+    if (getTypeForMSH() == MSH_TET_10 && i == 8)
+      fprintf(fp, " %d", getVertex(9)->getIndex());
+    else if (getTypeForMSH() == MSH_TET_10 && i == 9)
+      fprintf(fp, " %d", getVertex(8)->getIndex());
+    else
+      fprintf(fp, " %d", getVertex(i)->getIndex());
   fprintf(fp, " %d\n", (elementTagType == 3) ? _partition :
           (elementTagType == 2) ? physical : elementary);
 }
diff --git a/Geo/gmshFace.cpp b/Geo/gmshFace.cpp
index 22b32a04d6f5dd59fac3c1abcd017de249e9b8a7..ea18b06527c3d73fb9d71b6af0f483b7d2c6421c 100644
--- a/Geo/gmshFace.cpp
+++ b/Geo/gmshFace.cpp
@@ -15,6 +15,7 @@
 #include "Context.h"
 #include "MTriangle.h"
 #include "VertexArray.h"
+#include "Field.h"
 
 gmshFace::gmshFace(GModel *m, Surface *face)
   : GFace(m, face->Num), s(face)
@@ -330,7 +331,7 @@ bool gmshFace::containsPoint(const SPoint3 &pt) const
 bool gmshFace::buildSTLTriangulation(bool force)
 {
   return false;
-  /*
+  
   if(va_geom_triangles){
     if(force)
       delete va_geom_triangles;
@@ -341,31 +342,34 @@ bool gmshFace::buildSTLTriangulation(bool force)
   stl_vertices.clear();
   stl_triangles.clear();
 
-  contextMeshOptions _temp = CTX::instance()->mesh;
 
-  CTX::instance()->mesh.lcFromPoints = 0;
-  CTX::instance()->mesh.lcFromCurvature = 1;
-  CTX::instance()->mesh.lcExtendFromBoundary = 0;
-  CTX::instance()->mesh.scalingFactor = 1;
-  CTX::instance()->mesh.lcFactor = 1;
-  CTX::instance()->mesh.order = 1;
-  CTX::instance()->mesh.lcIntegrationPrecision = 1.e-5;
-  std::for_each(l_edges.begin(), l_edges.end(), meshGEdge(true));
-  meshGFace mesher (false,true);
-  mesher(this);
-  printf("%d triangles face %d\n",triangles_stl.size(),tag());
-  CTX::instance()->mesh = _temp;
+  if (!triangles.size()){
+    contextMeshOptions _temp = CTX::instance()->mesh;
+    FieldManager *fields = model()->getFields();
+    int BGM  = fields->getBackgroundField();
+    fields->setBackgroundField(0);
+    CTX::instance()->mesh.lcFromPoints = 0;
+    CTX::instance()->mesh.lcFromCurvature = 1;
+    CTX::instance()->mesh.lcExtendFromBoundary = 0;
+    CTX::instance()->mesh.scalingFactor = 1;
+    CTX::instance()->mesh.lcFactor = 1;
+    CTX::instance()->mesh.order = 1;
+    CTX::instance()->mesh.lcIntegrationPrecision = 1.e-3;
+    //  CTX::instance()->mesh.Algorithm = 5;    
+    model()->mesh(2);    
+    CTX::instance()->mesh = _temp;
+    fields->setBackgroundField(fields->get(BGM));
+  }
 
   std::map<MVertex*,int> _v;
   int COUNT =0;
-  for (int j = 0; j < triangles_stl.size(); j++){
-    int C[3];
+  for (int j = 0; j < triangles.size(); j++){
     for (int i=0;i<3;i++){
       std::map<MVertex*,int>::iterator it =
-        _v.find(triangles_stl[j]->getVertex(j));
+        _v.find(triangles[j]->getVertex(j));
       if (it != _v.end()){
         stl_triangles.push_back(COUNT);
-        _v[triangles_stl[j]->getVertex(j)] = COUNT++;
+        _v[triangles[j]->getVertex(j)] = COUNT++;
       }
       else stl_triangles.push_back(it->second);
     }
@@ -396,5 +400,5 @@ bool gmshFace::buildSTLTriangulation(bool force)
   }
   va_geom_triangles->finalize();
   return true;
-  */
+  
 }
diff --git a/Geo/gmshRegion.cpp b/Geo/gmshRegion.cpp
index fcec42f11be6a8aebe08b96dd90959cfbcdc8ed7..499fcca1f3ee40ec8e96ab448f522c6b975d5bd0 100644
--- a/Geo/gmshRegion.cpp
+++ b/Geo/gmshRegion.cpp
@@ -39,6 +39,7 @@ gmshRegion::gmshRegion(GModel *m, ::Volume *volume)
       Msg::Error("Unknown surface %d", is);
   }
   resetMeshAttributes();
+
 }
 
 void gmshRegion::resetMeshAttributes()
diff --git a/Graphics/drawPost.cpp b/Graphics/drawPost.cpp
index 08d19d862d8c59b1f068395ee89be836d09320f9..0e2f9671e0a4a6d00b5143c109dbacc8695c9f30 100644
--- a/Graphics/drawPost.cpp
+++ b/Graphics/drawPost.cpp
@@ -68,8 +68,19 @@ static void drawArrays(drawContext *ctx, PView *p, VertexArray *va, GLint type,
         double v0 = char2float(*n0), v1 = char2float(*n1);
         ctx->drawTaperedCylinder(opt->lineWidth, v0, v1, 0., 1., x, y, z, opt->light);
       }
-      else
+      else if (opt->lineType == 1)
         ctx->drawCylinder(opt->lineWidth, x, y, z, opt->light);
+      else { /// 2D (for now) MNT DIAGRAMS FOR FRAMES
+	float l = sqrt ((p0[0]-p1[0])*(p0[0]-p1[0]) + (p0[1]-p1[1])*(p0[1]-p1[1]) + (p0[2]-p1[2])*(p0[2]-p1[2]) );
+        char *n0 = va->getNormalArray(3 * i);
+        char *n1 = va->getNormalArray(3 * (i + 1));
+        double v0 = char2float(*n0), v1 = char2float(*n1);
+	float dir [3] = {(p1[0]-p0[0])/l , (p1[1]-p0[1])/l , (p1[2]-p0[2])/l };
+	printf("%g %g %g %g %g %g\n",v0,v1,p0[0],p0[1],p1[0],p1[1]);
+	ctx->drawVector(1, 0, 
+			p0[0] - dir[1] * v0 , p0[1] + dir[0] * v0 , 0.0,
+			p1[0] - dir[1] * v1 , p1[1] + dir[0] * v1 , 0.0,opt->light);
+      }
     }
   }
   else{
diff --git a/Mesh/Field.cpp b/Mesh/Field.cpp
index 20289b0b80fe0a9cf4bc7de12ea206cd877aa398..2c4ca6d83174f4d2a4ca11a8c61cbc744ab87986 100644
--- a/Mesh/Field.cpp
+++ b/Mesh/Field.cpp
@@ -1667,20 +1667,16 @@ class AttractorField : public Field
       offset.push_back(0);
       for(std::list<int>::iterator it = faces_id.begin();
           it != faces_id.end(); ++it) {
-        Surface *s = FindSurface(*it);
-        if(!s) {
-          GFace *f = GModel::current()->getFaceByTag(*it);
-	  if (f){
-	    SBoundingBox3d bb = f->bounds();
-	    SVector3 dd = bb.max() - bb.min();
-	    double maxDist = dd.norm() / n_nodes_by_edge ;
-	    f->fillPointCloud(maxDist, &points, &uvpoints);
-	    offset.push_back(points.size());
-	  }
+	GFace *f = GModel::current()->getFaceByTag(*it);
+	if (f){
+	  SBoundingBox3d bb = f->bounds();
+	  SVector3 dd = bb.max() - bb.min();
+	  double maxDist = dd.norm() / n_nodes_by_edge ;
+	  f->fillPointCloud(maxDist, &points, &uvpoints);
+	  offset.push_back(points.size());
 	}
       }
-
-
+       
       int totpoints =
 	nodes_id.size() +
 	(n_nodes_by_edge-2) * edges_id.size() +
@@ -1697,47 +1693,27 @@ class AttractorField : public Field
       int k = 0;
       for(std::list<int>::iterator it = nodes_id.begin();
           it != nodes_id.end(); ++it) {
-        Vertex *v = FindPoint(*it);
-        if(v) {
-          getCoord(v->Pos.X, v->Pos.Y, v->Pos.Z, zeronodes[k][0],
-                   zeronodes[k][1], zeronodes[k][2]);
+	GVertex *gv = GModel::current()->getVertexByTag(*it);
+	if(gv) {
+	  getCoord(gv->x(), gv->y(), gv->z(), zeronodes[k][0],
+		   zeronodes[k][1], zeronodes[k][2], gv);
 	  _infos[k++] = AttractorInfo(*it,0,0,0);
         }
-        else {
-          GVertex *gv = GModel::current()->getVertexByTag(*it);
-          if(gv) {
-            getCoord(gv->x(), gv->y(), gv->z(), zeronodes[k][0],
-                     zeronodes[k][1], zeronodes[k][2], gv);
-	    _infos[k++] = AttractorInfo(*it,0,0,0);
-          }
-        }
       }
       for(std::list<int>::iterator it = edges_id.begin();
           it != edges_id.end(); ++it) {
-        Curve *c = FindCurve(*it);
-        if(c) {
-          for(int i = 1; i < n_nodes_by_edge -1 ; i++) {
-            double u = (double)i / (n_nodes_by_edge - 1);
-            Vertex V = InterpolateCurve(c, u, 0);
-            getCoord(V.Pos.X, V.Pos.Y, V.Pos.Z, zeronodes[k][0],
-                     zeronodes[k][1], zeronodes[k][2]);
+	GEdge *e = GModel::current()->getEdgeByTag(*it);
+	if(e) {
+	  for(int i = 1; i < n_nodes_by_edge - 1; i++) {
+	    double u = (double)i / (n_nodes_by_edge - 1);
+	    Range<double> b = e->parBounds(0);
+	    double t = b.low() + u * (b.high() - b.low());
+	    GPoint gp = e->point(t);
+	    getCoord(gp.x(), gp.y(), gp.z(), zeronodes[k][0],
+		     zeronodes[k][1], zeronodes[k][2], e);
 	    _infos[k++] = AttractorInfo(*it,1,u,0);
           }
         }
-        else {
-	  GEdge *e = GModel::current()->getEdgeByTag(*it);
-          if(e) {
-            for(int i = 1; i < n_nodes_by_edge - 1; i++) {
-              double u = (double)i / (n_nodes_by_edge - 1);
-              Range<double> b = e->parBounds(0);
-              double t = b.low() + u * (b.high() - b.low());
-              GPoint gp = e->point(t);
-              getCoord(gp.x(), gp.y(), gp.z(), zeronodes[k][0],
-                       zeronodes[k][1], zeronodes[k][2], e);
-	      _infos[k++] = AttractorInfo(*it,1,u,0);
-            }
-          }
-        }
       }
       // This can lead to weird results as we generate attractors over
       // the whole parametric plane (we should really use a mesh,
@@ -1745,49 +1721,37 @@ class AttractorField : public Field
       int count = 0;
       for(std::list<int>::iterator it = faces_id.begin();
           it != faces_id.end(); ++it) {
-        Surface *s = FindSurface(*it);
-        if(s) {
-          for(int i = 0; i < n_nodes_by_edge; i++) {
-            for(int j = 0; j < n_nodes_by_edge; j++) {
-              double u = (double)i / (n_nodes_by_edge - 1);
-              double v = (double)j / (n_nodes_by_edge - 1);
-              Vertex V = InterpolateSurface(s, u, v, 0, 0);
-              getCoord(V.Pos.X, V.Pos.Y, V.Pos.Z, zeronodes[k][0],
-                       zeronodes[k][1], zeronodes[k][2]);
-	      _infos[k++] = AttractorInfo(*it,2,u,v);
-            }
-          }
-        }
-        else {
-          GFace *f = GModel::current()->getFaceByTag(*it);
-          if(f) {
-	    if (points.size()){
-	      for(int j = offset[count]; j < offset[count+1];j++) {
-		zeronodes[k][0] = points[j].x();
-		zeronodes[k][1] = points[j].y();
-		zeronodes[k][2] = points[j].z();
-		_infos[k++] = AttractorInfo(*it,2,uvpoints[j].x(),uvpoints[j].y());
-	      }
-	      count++;
+	GFace *f = GModel::current()->getFaceByTag(*it);
+	if(f) {
+	  if (points.size()){
+	    for(int j = offset[count]; j < offset[count+1];j++) {
+	      zeronodes[k][0] = points[j].x();
+	      zeronodes[k][1] = points[j].y();
+	      zeronodes[k][2] = points[j].z();
+	      _infos[k++] = AttractorInfo(*it,2,uvpoints[j].x(),uvpoints[j].y());
 	    }
-	    else{
-	      for(int i = 0; i < n_nodes_by_edge; i++) {
-		for(int j = 0; j < n_nodes_by_edge; j++) {
-		  double u = (double)i / (n_nodes_by_edge - 1);
-		  double v = (double)j / (n_nodes_by_edge - 1);
-		  Range<double> b1 = ge->parBounds(0);
-		  Range<double> b2 = ge->parBounds(1);
-		  double t1 = b1.low() + u * (b1.high() - b1.low());
-		  double t2 = b2.low() + v * (b2.high() - b2.low());
-		  GPoint gp = f->point(t1, t2);
-		  getCoord(gp.x(), gp.y(), gp.z(), zeronodes[k][0],
-			   zeronodes[k][1], zeronodes[k][2], f);
-		  _infos[k++] = AttractorInfo(*it,2,u,v);
-		}
+	    count++;
+	  }
+	  else{
+	    for(int i = 0; i < n_nodes_by_edge; i++) {
+	      for(int j = 0; j < n_nodes_by_edge; j++) {
+		double u = (double)i / (n_nodes_by_edge - 1);
+		double v = (double)j / (n_nodes_by_edge - 1);
+		Range<double> b1 = f->parBounds(0);
+		Range<double> b2 = f->parBounds(1);
+		double t1 = b1.low() + u * (b1.high() - b1.low());
+		double t2 = b2.low() + v * (b2.high() - b2.low());
+		GPoint gp = f->point(t1, t2);
+		getCoord(gp.x(), gp.y(), gp.z(), zeronodes[k][0],
+			 zeronodes[k][1], zeronodes[k][2], f);
+		_infos[k++] = AttractorInfo(*it,2,u,v);
 	      }
-            }
-          }
-        }
+	    }
+	  }
+	}
+	else {
+	  printf("face %d not yet created\n",*it);
+	}
       }
       kdtree = new ANNkd_tree(zeronodes, totpoints, 3);
       update_needed = false;
@@ -1991,24 +1955,37 @@ void BoundaryLayerField::operator() (double x, double y, double z,
 
   current_distance = 1.e22;
   current_closest = 0;
-  SMetric3 v (1./MAX_LC);
   std::vector<SMetric3> hop;
+  SMetric3 v (1./(CTX::instance()->mesh.lcMax*CTX::instance()->mesh.lcMax));
+  hop.push_back(v);
   for (std::list<AttractorField*>::iterator it = _att_fields.begin();
        it != _att_fields.end(); ++it){
     double cdist = (*(*it)) (x, y, z);
+    AttractorInfo ainfo= (*it)->getAttractorInfo().first;
     SPoint3 CLOSEST= (*it)->getAttractorInfo().second;
 
-    SMetric3 localMetric;
-    if (iIntersect){
-      (*this)(*it, cdist,x, y, z, localMetric, ge);
-      hop.push_back(localMetric);
+    bool doNotConsider = false;
+    if (ge->dim () == ainfo.dim && ge->tag() == ainfo.ent){
+      //      doNotConsider = true;
     }
-    if (cdist < current_distance){
-      if (!iIntersect)(*this)(*it, cdist,x, y, z, localMetric, ge);
-      current_distance = cdist;
-      current_closest = *it;
-      v = localMetric;
-      _closest_point = CLOSEST;
+    else if (ge->dim () == 1 && ainfo.dim == 2){
+      GFace *gf = ge->model()->getFaceByTag(ainfo.ent);
+      //     if (gf->containsEdge(ge->tag()))doNotConsider  = true;      
+    } 
+    
+    if (!doNotConsider) {
+      SMetric3 localMetric;
+      if (iIntersect){
+	(*this)(*it, cdist,x, y, z, localMetric, ge);
+	hop.push_back(localMetric);
+      }
+      if (cdist < current_distance){
+	if (!iIntersect)(*this)(*it, cdist,x, y, z, localMetric, ge);
+	current_distance = cdist;
+	current_closest = *it;
+	v = localMetric;
+	_closest_point = CLOSEST;
+      }
     }
   }
   if (iIntersect)
diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp
index f9f18e67617452c3d972612f30d9d56770e91df3..e1e33cdfe6bb16e700cc0bace0d37b0ba8bd712a 100644
--- a/Mesh/Generator.cpp
+++ b/Mesh/Generator.cpp
@@ -577,7 +577,18 @@ static void Mesh3D(GModel *m)
   // quality reasons)
   std::vector<std::vector<GRegion*> > connected;
   FindConnectedRegions(delaunay, connected);
+
+  /*
   for(unsigned int i = 0; i < connected.size(); i++){
+    for(unsigned j=0;j<connected[i].size();j++){
+      GRegion *gr = connected[i][j];
+      std::list<GFace*> f = gr->faces();
+      for (std::list<GFace*>::iterator it = f.begin();
+	   it != f.end() ; ++it) quadsToTriangles (*it,1000000);
+    }
+  }
+  */
+  for(unsigned int i = 0; i < connected.size(); i++){    
     MeshDelaunayVolume(connected[i]);
 
     //Additional code for hex mesh begin
@@ -598,7 +609,6 @@ static void Mesh3D(GModel *m)
 	post.execute(0);
       }
     }
-
   }
 
   double t2 = Cpu();
diff --git a/Mesh/meshGEdge.cpp b/Mesh/meshGEdge.cpp
index 329c80fa33760431a97a7b1462c2784c2663fbe4..8ef3ca968eb61eb675c4524515a8e1ba5b9b82f1 100644
--- a/Mesh/meshGEdge.cpp
+++ b/Mesh/meshGEdge.cpp
@@ -372,7 +372,9 @@ void meshGEdge::operator() (GEdge *ge)
     N = ge->meshAttributes.nbPointsTransfinite;
   }
   else{
-    if (CTX::instance()->mesh.algo2d == ALGO_2D_BAMG  || blf ){ // CTX::instance()->mesh.algo2d == ALGO_2D_PACK_PRLGRMS
+    if (CTX::instance()->mesh.algo2d == ALGO_2D_BAMG 
+	//	|| CTX::instance()->mesh.algo2d == ALGO_2D_PACK_PRLGRMS 
+	|| blf){
       a = Integration(ge, t_begin, t_end, F_Lc_aniso, Points,
                       CTX::instance()->mesh.lcIntegrationPrecision);
     }
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index a877511ec008769c9fe000d1b43db1fd7c42c51f..4f8e82092c1ec5204e66719241b3d5de7596b8e6 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -305,8 +305,9 @@ static void remeshUnrecoveredEdges(std::map<MVertex*, BDS_Point*> &recoverMapInv
 static bool algoDelaunay2D(GFace *gf)
 {
 
-  if(!noSeam(gf))
-    return false;
+  // FIXME  
+  //  if(!noSeam(gf))
+  //    return false;
 
   if(gf->getMeshingAlgo() == ALGO_2D_DELAUNAY ||
      gf->getMeshingAlgo() == ALGO_2D_BAMG ||
@@ -1762,6 +1763,36 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
     //    }
   }
 
+  /// This is a structure that we need only for periodic cases
+  /// We will duplicate the vertices (MVertex) that are on seams
+  /// 
+  /*
+  {
+    std::map<MVertex*, BDS_Point*> invertMap;
+    std::map<BDS_Point*, MVertex*>::iterator it = recoverMap.begin();
+    std::map<BDS_Point*, MVertex*>::iterator it = recoverMap.begin();
+    while(it != recoverMap.end()){
+      // we have twice vertex MVertex with 2 different coordinates
+      std::map<MVertex*, BDS_Point*>::iterator invIt = invertMap.find((*it)->second);
+      if (invIt != invertMap.end()){
+	BDS_Point* bds1 = (*invIt)->second; 	
+	BDS_Point* bds2 = (*it)->first;
+	MVertex  * mv1  =  (*it)->second;
+	// create a new "fake" vertex that will be destroyed afterwards
+	double t;
+	mv1->getParameter(0,t);
+	MVertex  * mv2  = new MEdgeVertex (mv1->x(),mv1->y(),mv1->z(),mv1->onWhat(), t);
+	(*it)->second = mv2;
+	std::map<BDS_Point*, MVertex*>::iterator itTemp = it;
+	++it;
+	recoverMap.erase(itTemp);	
+      }
+      else ++it;
+      invertMap[it->second] = it->first;
+    }
+  }
+  */
+
   // fill the small gmsh structures
   {
     std::set<BDS_Point*, PointLessThan>::iterator itp = m->points.begin();
@@ -1777,6 +1808,7 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
     }
   }
 
+  std::map<MTriangle*, BDS_Face*> invert_map;
   {
     std::list<BDS_Face*>::iterator itt = m->triangles.begin();
     while (itt != m->triangles.end()){
@@ -1791,8 +1823,12 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
           // when a singular point is present, degenerated triangles
           // may be created, for example on a sphere that contains one
           // pole
-          if(v1 != v2 && v1 != v3 && v2 != v3)
+          if(v1 != v2 && v1 != v3 && v2 != v3){
+	    // we are in the periodic case. if we aim at
+	    // using delaunay mesh generation in thoses cases, 
+	    // we should double some of the vertices
             gf->triangles.push_back(new MTriangle(v1, v2, v3));
+	  }
         }
         else{
           MVertex *v4 = recoverMap[n[3]];
@@ -1849,7 +1885,7 @@ void deMeshGFace::operator() (GFace *gf)
 }
 
 // for debugging, change value from -1 to -100;
-int debugSurface = -1; //-1;
+int debugSurface = -100; //-1;
 
 void meshGFace::operator() (GFace *gf, bool print)
 {
diff --git a/Mesh/meshGFaceDelaunayInsertion.cpp b/Mesh/meshGFaceDelaunayInsertion.cpp
index b603d895b8989f37333ba84c91968f7ef4a2bdf5..1f066c9b47fa04f46cec22813923d45fd99c2d39 100644
--- a/Mesh/meshGFaceDelaunayInsertion.cpp
+++ b/Mesh/meshGFaceDelaunayInsertion.cpp
@@ -1534,8 +1534,8 @@ void bowyerWatsonParallelograms(GFace *gf)
       packed[i]->getParameter(1,newPoint[1]);
       delete packed[i];
       double metric[3];
-      buildMetric(gf, newPoint, metrics[i], metric);
-	    //buildMetric(gf, newPoint, metric);
+      //      buildMetric(gf, newPoint, metrics[i], metric);
+      buildMetric(gf, newPoint, metric);
 
       bool success = insertAPoint( gf, AllTris.begin(), newPoint, metric, DATA , AllTris, 0, oneNewTriangle, &oneNewTriangle);
       if (!success) oneNewTriangle = 0;
diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp
index 7d119ce2dd09ad3c4a5b5ac20032c5008896bef3..b5bb52269d883b728df408c488716d1e8f059506 100644
--- a/Mesh/meshGFaceOptimize.cpp
+++ b/Mesh/meshGFaceOptimize.cpp
@@ -2182,7 +2182,7 @@ void laplaceSmoothing(GFace *gf, int niter, bool infinity_norm)
 
 int untangleInvalidQuads(GFace *gf, int niter)
 {
-  //  return;
+  //  return 0;
   int N = 0;
 #if defined(HAVE_BFGS)
   v2t_cont adj;
diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp
index 14916f6f1a4d44d78be28212128aac2a3eab1d38..3c9fc1b91e9630a152c9060b346f421d8ed1277c 100644
--- a/Mesh/meshGRegion.cpp
+++ b/Mesh/meshGRegion.cpp
@@ -1031,6 +1031,7 @@ void meshNormalsPointOutOfTheRegion(GRegion *gr)
 
 void meshGRegion::operator() (GRegion *gr)
 {
+
   gr->model()->setCurrentMeshEntity(gr);
 
   if(gr->geomType() == GEntity::DiscreteVolume) return;
diff --git a/Mesh/surfaceFiller.cpp b/Mesh/surfaceFiller.cpp
index 371ebc628c20ac4b97be44c2e8ada54da9c33b16..f20fcf562d49bd9d83fdfe96b9e1ab18503ff028 100644
--- a/Mesh/surfaceFiller.cpp
+++ b/Mesh/surfaceFiller.cpp
@@ -18,8 +18,9 @@
 #include "BackgroundMesh.h"
 #include "intersectCurveSurface.h"
 
-static const double FACTOR = .71;
+static const double FACTOR = .81;
 static const int NUMDIR = 3;
+//static const double DIRS [NUMDIR] = {0.0};
 static const double DIRS [NUMDIR] = {0.0, M_PI/20.,-M_PI/20.};
 
 /// a rectangle in the tangent plane is transformed
@@ -35,6 +36,7 @@ struct surfacePointWithExclusionRegion {
   SPoint2 _p[4][NUMDIR];
   SPoint2 _q[4];
   SMetric3 _meshMetric;
+  double _distanceSummed;
   /*
          + p3
     p4   |    
@@ -44,12 +46,23 @@ struct surfacePointWithExclusionRegion {
 
 */
 
-  surfacePointWithExclusionRegion (MVertex *v, SPoint2 p[4][NUMDIR], SMetric3 & meshMetric){
-    _meshMetric = meshMetric;
+  surfacePointWithExclusionRegion (MVertex *v, SPoint2 p[4][NUMDIR], SMetric3 & meshMetric, surfacePointWithExclusionRegion *father = 0){
     _v = v;
+    _meshMetric = meshMetric;
     _center = (p[0][0]+p[1][0]+p[2][0]+p[3][0])*.25;
     for (int i=0;i<4;i++)_q[i] = _center + (p[i][0]+p[(i+1)%4][0]-_center*2)*FACTOR;
     for (int i=0;i<4;i++)for (int j=0;j<NUMDIR;j++)_p[i][j] = p[i][j];
+
+    if (!father){
+      fullMatrix<double> V(3,3);
+      fullVector<double> S(3);
+      meshMetric.eig(V,S);
+      double l = std::max(std::max(S(0),S(1)),S(2));
+      _distanceSummed = sqrt(1/(l*l));
+    }
+    else {
+      _distanceSummed = father->_distanceSummed + distance (father->_v,_v);
+    }
   }
   bool inExclusionZone (const SPoint2 &p){
     double mat[2][2];
@@ -88,6 +101,19 @@ struct my_wrapper {
   my_wrapper (SPoint2 sp) : _tooclose (false), _p(sp) {}
 };
 
+class compareSurfacePointWithExclusionRegionPtr
+{
+ public:
+  inline bool operator () (const surfacePointWithExclusionRegion *a, const surfacePointWithExclusionRegion *b)  const
+  {
+    if(a->_distanceSummed > b->_distanceSummed) return false;
+    if(a->_distanceSummed < b->_distanceSummed) return true;
+    return a<b;
+  }
+};
+
+
+
 
 bool rtree_callback(surfacePointWithExclusionRegion *neighbour,void* point){
   my_wrapper *w = static_cast<my_wrapper*>(point);
@@ -294,7 +320,8 @@ void packingOfParallelograms(GFace* gf,  std::vector<MVertex*> &packed, std::vec
   }
 
   // put boundary vertices in a fifo queue  
-  std::queue<surfacePointWithExclusionRegion*> fifo;
+  // std::queue<surfacePointWithExclusionRegion*> fifo;
+  std::set<surfacePointWithExclusionRegion*,  compareSurfacePointWithExclusionRegionPtr> fifo;
   std::vector<surfacePointWithExclusionRegion*> vertices;
   // put the RTREE
   RTree<surfacePointWithExclusionRegion*,double,2,double> rtree;
@@ -305,7 +332,8 @@ void packingOfParallelograms(GFace* gf,  std::vector<MVertex*> &packed, std::vec
     compute4neighbors (gf, *it, false, newp, metricField);
     surfacePointWithExclusionRegion *sp = 
       new surfacePointWithExclusionRegion (*it, newp, metricField);    
-    fifo.push(sp); 
+    //    fifo.push(sp); 
+    fifo.insert(sp); 
     vertices.push_back(sp); 
     double _min[2],_max[2];
     sp->minmax(_min,_max);
@@ -319,8 +347,10 @@ void packingOfParallelograms(GFace* gf,  std::vector<MVertex*> &packed, std::vec
 
   while(!fifo.empty()){
     //surfacePointWithExclusionRegion & parent = fifo.top();
-    surfacePointWithExclusionRegion * parent = fifo.front();
-    fifo.pop();
+    //    surfacePointWithExclusionRegion * parent = fifo.front();
+    surfacePointWithExclusionRegion * parent = *fifo.begin();
+    //    fifo.pop();
+    fifo.erase(fifo.begin());
     for (int dir=0;dir<NUMDIR;dir++){
       //      printf("dir = %d\n",dir);
       int countOK = 0;
@@ -335,8 +365,9 @@ void packingOfParallelograms(GFace* gf,  std::vector<MVertex*> &packed, std::vec
 	  //	  	printf(" %g %g %g %g\n",parent._center.x(),parent._center.y(),gp.u(),gp.v());
 	  compute4neighbors (gf, v, false, newp, metricField);
 	  surfacePointWithExclusionRegion *sp = 
-	    new surfacePointWithExclusionRegion (v, newp, metricField);    
-	  fifo.push(sp); 
+	    new surfacePointWithExclusionRegion (v, newp, metricField, parent);    
+	  //	  fifo.push(sp); 
+	  fifo.insert(sp); 
 	  vertices.push_back(sp); 
 	  double _min[2],_max[2];
 	  sp->minmax(_min,_max);
diff --git a/Post/PView.cpp b/Post/PView.cpp
index a1920dab2be4b55b1a57d4ec660648cad9b77651..30da150af0f7b0b78db1a4d166db7c0548a1c6b5 100644
--- a/Post/PView.cpp
+++ b/Post/PView.cpp
@@ -121,6 +121,8 @@ PView::PView(const std::string &name, const std::string &type,
     t = PViewDataGModel::ElementData;
   else if(type == "ElementNodeData")
     t = PViewDataGModel::ElementNodeData;
+  else if(type == "Beam")
+    t = PViewDataGModel::BeamData;
   else{
     Msg::Error("Unknown type of view to create '%s'", type.c_str());
     return;
diff --git a/Post/PViewDataGModel.h b/Post/PViewDataGModel.h
index 08d21619196f409c4eba49dd8c2fd10db86cd3d1..869078e0d08457f58f426c7b56f4d80a2a23cb6a 100644
--- a/Post/PViewDataGModel.h
+++ b/Post/PViewDataGModel.h
@@ -154,7 +154,8 @@ class PViewDataGModel : public PViewData {
     NodeData = 1,
     ElementData = 2,
     ElementNodeData = 3,
-    GaussPointData = 4
+    GaussPointData = 4,
+    BeamData = 5
   };
  private:
   // the data, indexed by time step
diff --git a/Solver/CMakeLists.txt b/Solver/CMakeLists.txt
index 6cd11d435202d9ce040027f8c351a41bf81b9e09..36cfcd598098b469ca967acfc717416907c83c0f 100644
--- a/Solver/CMakeLists.txt
+++ b/Solver/CMakeLists.txt
@@ -16,6 +16,7 @@ elasticitySolver.cpp
   multiscaleLaplace.cpp
 functionSpace.cpp
   filters.cpp
+  frameSolver.cpp
   sparsityPattern.cpp
   STensor43.cpp
   STensor33.cpp
diff --git a/Solver/frameSolver.cpp b/Solver/frameSolver.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..294a9ec1085505fd54b1dbb0f6091e0e21a9a262
--- /dev/null
+++ b/Solver/frameSolver.cpp
@@ -0,0 +1,288 @@
+#include "GmshConfig.h"
+#include "GModel.h"
+#include "GVertex.h"
+#include "GEdge.h"
+#include "frameSolver.h"
+#include "linearSystemCSR.h"
+#include "linearSystemPETSc.h"
+#include "linearSystemGMM.h"
+#include "linearSystemFull.h"
+#if defined(HAVE_POST)
+#include "PView.h"
+#include "PViewData.h"
+#endif
+
+frameSolver2d::frameSolver2d (GModel *gm)
+  : pAssembler(0),_myModel(gm)
+{
+}
+
+
+void frameSolver2d::addFixations (const std::vector<int> & dirs, const std::vector<int> &modelVertices, double value)
+{
+  for (unsigned int j=0;j<modelVertices.size();j++){
+    GVertex *gv = _myModel->getVertexByTag(modelVertices[j]);
+    if (gv){
+      for (unsigned int i=0;i<dirs.size();i++){
+	_fixations.push_back(gmshFixation(gv,dirs[i],value));
+      }      
+    }
+  }
+}
+
+void frameSolver2d::addNodalForces (const std::vector<int> &modelVertices, const std::vector<double> & force)
+{
+  for (unsigned int j=0;j<modelVertices.size();j++){
+    GVertex *gv = _myModel->getVertexByTag(modelVertices[j]);
+    if (gv){
+      _nodalForces.push_back(std::make_pair(gv,force));
+    }
+  }
+}
+
+void frameSolver2d::addBeamsOrBars (const std::vector<int> &modelEdges, 
+				    double E, double I, double A, int r[2]){
+  int r_middle[2] = {1,1} , r_left[2] = {r[0],1} , r_right[2] = {0,r[1]};
+  //  printf("adding %d beams\n",modelEdges.size());
+  for (unsigned int i=0;i<modelEdges.size();i++){
+    GEdge *ge = _myModel->getEdgeByTag(modelEdges[i]);   
+    if (ge){
+      //      printf("model edge %d found\n",ge->tag());
+      for (unsigned int j=0; j < ge->lines.size(); ++j){
+	MLine *l = ge->lines[j];
+	if (j == 0 && j == ge->lines.size()-1) _beams.push_back(gmshBeam2d ( l , E , I , A , r)); 
+	else if (j == 0) _beams.push_back(gmshBeam2d ( l , E , I , A , r_left)); 
+	else if (j == ge->lines.size()-1) _beams.push_back(gmshBeam2d ( l , E , I , A , r_right)); 
+	else _beams.push_back(gmshBeam2d ( l , E , I , A , r_middle));
+      }
+    }
+  }
+}
+
+void frameSolver2d::addBeams (const std::vector<int> &modelEdges, 
+			      double E, double I, double A)
+{
+  int r[2] = {1,1};
+  addBeamsOrBars(modelEdges,E,I,A,r);
+}
+
+void frameSolver2d::addBars (const std::vector<int> &modelEdges, 
+			     double E, double I, double A)
+{
+  int r[2] = {0,0};
+  addBeamsOrBars(modelEdges,E,I,A,r);
+}
+
+
+
+// solve any time a parameter is modified
+/*
+  
+  A vertex is connected to beams. The question
+  is how many bars are rotuled 
+  
+  We define 2 dofs per node
+
+ */
+void frameSolver2d::createDofs () 
+{
+  //  printf("coucou %d fixations\n",_fixations.size());
+  for (unsigned int i = 0; i<_fixations.size(); ++i){
+    const  gmshFixation &f = _fixations[i];
+    //    printf("f._vertex(%d) = %p %d %g\n",i,f._vertex,f._direction,f._value);
+    MVertex *v = f._vertex->mesh_vertices[0];
+    Dof DOF (v->getNum(),f._direction);
+    pAssembler->fixDof(DOF, f._value);
+  }
+  
+  //  printf("coucou2\n");
+  computeRotationTags ();
+  //  printf("coucou3\n");
+  for (unsigned int i=0;i<_beams.size(); i++){
+    //    printf("beam[%d] rot %d %d\n",i,_beams[i]._rotationTags[0],_beams[i]._rotationTags[1]);
+    for (unsigned int j=0;j<2;j++){
+      MVertex *v = _beams[i]._element->getVertex(j);
+      Dof theta (v->getNum(),
+		 Dof::createTypeWithTwoInts (2,_beams[i]._rotationTags[j]));
+      pAssembler->numberDof(theta);
+      Dof U (v->getNum(),0);
+      pAssembler->numberDof(U);
+      Dof V (v->getNum(),1);
+      pAssembler->numberDof(V);
+    }
+  }
+  //  printf("%d dofs\n",pAssembler->sizeOfR());
+}
+
+void frameSolver2d::computeStiffnessMatrix (int iBeam,
+					    fullMatrix<double> &K) 
+{
+  const gmshBeam2d &b = _beams[iBeam];
+  const double BS = b._E * b._I / (b._L*b._L*b._L);
+  const double TS = b._E * b._A / b._L;
+  const MVertex *v1 = b._element->getVertex(0);
+  const MVertex *v2 = b._element->getVertex(1);
+  const double alpha = atan2 (v2->y() - v1->y(),
+			      v2->x() - v1->x()); 
+  const double C = cos(alpha);
+  const double S = sin(alpha);
+
+  printf("beam %d %g %g %g\n",iBeam,alpha,C,S);
+  
+  fullMatrix<double> R (6,6);
+  R(0,0) = R(1,1) = R (3,3) = R(4,4) = C; 
+  R(0,1) = R (3,4) = S; 
+  R(1,0) = R (4,3) = -S;
+  R(2,2) = R(5,5) = 1.0;
+
+  fullMatrix<double> k (6,6);
+
+  // tensile stiffness
+  k(0,0) = k (3,3) =  TS;
+  k(0,3) = k (3,0) = -TS;
+  // bending stiffness
+  k(1,1) = k(4,4) = 12 * BS;
+  k(2,2) = k(5,5) = 4. * BS * b._L * b._L;
+  k(1,2) = k(2,1) = k(1,5) = k(5,1) =  6 * BS * b._L;
+  k(4,2) = k(2,4) = k(4,5) = k(5,4) = -6 * BS * b._L;
+  k(4,1) = k(1,4) = -12 * BS ;
+  k(5,2) = k(2,5) = -2 * BS * b._L * b._L;
+
+  fullMatrix<double> Rt (R), temp(6,6);
+  Rt.transposeInPlace();
+  Rt.mult(k,temp);temp.mult(R,K);
+}
+
+void frameSolver2d::solve () 
+{
+#if defined(HAVE_TAUCS)
+  linearSystemCSRTaucs<double> *lsys = new linearSystemCSRTaucs<double>;
+#elif defined(HAVE_PETSC)
+  linearSystemPETSc<double> *lsys = new linearSystemPETSc<double>;
+#else
+  linearSystemGmm<double> *lsys = new linearSystemGmm<double>;
+  lsys->setNoisy(2);
+#endif
+
+  if (pAssembler)delete pAssembler;
+  pAssembler = new dofManager<double>(lsys);
+
+  // fix dofs and create free ones
+  createDofs();
+   
+  // force vector
+  std::vector<std::pair<GVertex*,std::vector<double> > >::iterator it =
+    _nodalForces.begin();
+  for (; it != _nodalForces.end(); ++it){
+    MVertex *v = it->first->mesh_vertices[0];
+    const std::vector<double> & F = it->second; 
+    Dof DOFX (v->getNum(),0);
+    Dof DOFY (v->getNum(),1);
+    pAssembler->assemble(DOFX, F[0]);
+    pAssembler->assemble(DOFY, F[1]);
+  }
+
+  // stifness matrix
+  for (unsigned int i=0;i<_beams.size(); i++){
+    fullMatrix<double> K(6,6);
+    computeStiffnessMatrix (i,K);
+    _beams[i]._stiffness = K;
+    MVertex *v0 = _beams[i]._element->getVertex(0);
+    MVertex *v1 = _beams[i]._element->getVertex(1);
+    Dof theta0 (v0->getNum(),
+		Dof::createTypeWithTwoInts (2,_beams[i]._rotationTags[0]));
+    Dof theta1 (v1->getNum(),
+		Dof::createTypeWithTwoInts (2,_beams[i]._rotationTags[1]));
+    Dof U0 (v0->getNum(),0);
+    Dof U1 (v1->getNum(),0);
+    Dof V0 (v0->getNum(),1);
+    Dof V1 (v1->getNum(),1);
+    Dof DOFS[6]  = {U0,V0,theta0,U1,V1,theta1};
+    for (int j=0;j<6;j++){
+      for (int k=0;k<6;k++){
+	pAssembler->assemble(DOFS[j],DOFS[k],K(j,k));
+      }
+    }
+  }
+  lsys->systemSolve();
+  
+  // save the solution
+  for (unsigned int i=0;i<_beams.size(); i++){
+    MVertex *v0 = _beams[i]._element->getVertex(0);
+    MVertex *v1 = _beams[i]._element->getVertex(1);
+    Dof theta0 (v0->getNum(),
+		Dof::createTypeWithTwoInts (2,_beams[i]._rotationTags[0]));
+    Dof theta1 (v1->getNum(),
+		Dof::createTypeWithTwoInts (2,_beams[i]._rotationTags[1]));
+    Dof U0 (v0->getNum(),0);
+    Dof U1 (v1->getNum(),0);
+    Dof V0 (v0->getNum(),1);
+    Dof V1 (v1->getNum(),1);
+    Dof DOFS[6]  = {U0,V0,theta0,U1,V1,theta1};
+    for (int j=0;j<6;j++){
+      pAssembler->getDofValue(DOFS[j],  _beams[i]._displacement[j]);
+    }
+  }
+  delete lsys;
+  delete pAssembler;
+}
+
+void frameSolver2d::exportFrameData(const char * DISPL, const char * M) {
+  {
+    std::map<int, std::vector<double> > data;
+    for (unsigned int i=0;i<_beams.size(); i++){
+      std::vector<double> tmp;
+      //      tmp.push_back(_beams[i]._E);
+      //      tmp.push_back(_beams[i]._I);
+      //      tmp.push_back(_beams[i]._A);
+      for (int j=0;j<6;j++){
+	tmp.push_back(_beams[i]._displacement[j]);
+      }
+      data[_beams[i]._element->getNum()] = tmp;
+    }
+    PView *pv = new PView ("displacements", "Beam", _myModel, data, 0.0, 6);  
+    pv->getData()->writeMSH(DISPL);
+    delete pv;
+  }
+  {
+    std::map<int, std::vector<double> > data;
+    for (unsigned int i=0;i<_beams.size(); i++){
+      std::vector<double> tmp;
+      fullVector<double> d (_beams[i]._displacement,6), F(6);
+      _beams[i]._stiffness.mult(d,F);
+      tmp.push_back(-F(2));
+      tmp.push_back(F(5));
+      data[_beams[i]._element->getNum()] = tmp;
+    }
+    PView *pv = new PView ("Momentum", "ElementNodeData", _myModel, data, 0.0, 1);  
+    pv->getData()->writeMSH(M);
+    delete pv;
+  }
+
+}
+
+void frameSolver2d::computeRotationTags () 
+{
+  std::multimap<MVertex*,gmshBeam2d*> v2b;
+  for (unsigned int i=0;i<_beams.size(); i++){
+    v2b.insert(std::make_pair(_beams[i]._element->getVertex(0),&_beams[i]));
+    v2b.insert(std::make_pair(_beams[i]._element->getVertex(1),&_beams[i]));
+  }
+
+  std::multimap<MVertex*,gmshBeam2d*>::iterator s_it;
+  for (std::multimap<MVertex*,gmshBeam2d*>::iterator it = v2b.begin();  
+       it != v2b.end();  it = s_it){
+    MVertex *theKey = it->first;
+    
+    std::pair<std::multimap<MVertex*,gmshBeam2d*>::iterator, 
+	      std::multimap<MVertex*,gmshBeam2d*>::iterator> 
+      keyRange = v2b.equal_range(theKey);
+    int countRotules = 0;
+    for (s_it = keyRange.first;  s_it != keyRange.second;  ++s_it){
+      gmshBeam2d *b = s_it->second;
+      if (!b->isRigid(theKey)){
+	b->setRotationTag(theKey,++countRotules);
+      }
+    }
+  }
+}
diff --git a/Solver/frameSolver.h b/Solver/frameSolver.h
new file mode 100644
index 0000000000000000000000000000000000000000..9bf9ea753bfb771fca81bc66f8449e224ffcca0c
--- /dev/null
+++ b/Solver/frameSolver.h
@@ -0,0 +1,77 @@
+// 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 _FRAME_SOLVER_H_
+#define _FRAME_SOLVER_H_
+
+class GVertex;
+
+#include <map>
+#include <string>
+#include "PView.h"
+#include "dofManager.h"
+#include "fullMatrix.h"
+#include "MLine.h"
+
+struct gmshBeam2d
+{
+  MLine *_element;
+  double _I, _A , _E, _L;
+  bool _rigidNodes [2];
+  double _forceVector[6];
+  double _displacement[6];
+  int _rotationTags [2];
+  fullMatrix<double> _stiffness;
+  gmshBeam2d (MLine *l, double E , double I, double A, int r[2]) 
+  : _element(l), _A(A), _E(E), _I(I){
+    _L = distance(_element->getVertex(0),_element->getVertex(1));
+    _rotationTags[0] = _rotationTags[1] = 0;
+    _rigidNodes[0] = r[0];_rigidNodes[1] = r[1];
+    for (int i=0;i<6;i++)_displacement[i] = 0.;
+  }  
+  inline bool isRigid(MVertex*v)const{
+    return _element->getVertex(0) == v ? _rigidNodes[0] : _rigidNodes[1];
+  }
+  inline void setRotationTag(MVertex * v, int tag){
+    _element->getVertex(0) == v ? _rotationTags[0] = tag : _rotationTags[1] = tag;
+  }
+};
+
+struct gmshFixation 
+{
+  GVertex * _vertex;
+  int _direction;
+  double _value;
+  gmshFixation (GVertex *v, int d, double val) : _vertex(v),_direction(d), _value(val) {}
+};
+
+// a solver that computes equilibriums of frames...
+class frameSolver2d
+{
+  dofManager<double> *pAssembler;  
+  std::vector<gmshBeam2d> _beams;
+  std::vector<std::pair<GVertex*,std::vector<double> > >  _nodalForces;
+  std::vector<gmshFixation >  _fixations;
+  GModel *_myModel;
+  void computeStiffnessMatrix (int iBeam, fullMatrix<double> &K);
+  void createDofs () ;
+  void computeRotationTags () ;
+  void addBeamsOrBars (const std::vector<int> &modelEdges, 
+		       double E, double I, double A, int r[2]);
+  
+  
+ public:
+  frameSolver2d (GModel* myModel);
+  void addBeams (const std::vector<int> &modelEdges, 
+		 double E, double I, double A);
+  void addBars (const std::vector<int> &modelEdges, 
+		double E, double I, double A);
+  void addNodalForces (const std::vector<int> &modelVertices, const std::vector<double> & force);
+  void addFixations (const std::vector<int> & dirs, const std::vector<int> &modelVertices, double value);
+  void exportFrameData(const char * displ, const char* M);
+  void solve () ;
+};
+
+#endif
diff --git a/benchmarks/2d/conge.geo b/benchmarks/2d/conge.geo
index 1b8384cccd3e57a9866d9babb8713e98e6b3be2e..39841f15cba0f75e96eb5196ef566bfedfac0625 100644
--- a/benchmarks/2d/conge.geo
+++ b/benchmarks/2d/conge.geo
@@ -78,5 +78,5 @@ Physical Line(25) = {12,13,14,15,16,17,18,19,20,10};
 Physical Surface(26) = {24,22};
 Physical Line(27) = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, 11};
 Physical Line(28) = {17, 16, 20, 19, 18, 15};
-//Recombine Surface {24, 22};
+Recombine Surface {24, 22};
 Mesh.RecombinationAlgorithm=1;
\ No newline at end of file
diff --git a/wrappers/gmshpy/gmshSolver.i b/wrappers/gmshpy/gmshSolver.i
index e4e815a3ccb3d4c2e64dbdadf2198b57185216c7..61e1a2da181ac8e045fccd0d7ab4dd4ab7560207 100644
--- a/wrappers/gmshpy/gmshSolver.i
+++ b/wrappers/gmshpy/gmshSolver.i
@@ -8,6 +8,7 @@
 #if defined(HAVE_SOLVER)
   #include "dofManager.h"
   #include "elasticitySolver.h"
+  #include "frameSolver.h"
   #include "linearSystem.h"
   #include "linearSystemCSR.h"
   #include "linearSystemFull.h"
@@ -20,6 +21,7 @@
 %include "dofManager.h"
 %template(dofManagerDouble) dofManager<double>;
 %include "elasticitySolver.h"
+%include "frameSolver.h"
 %include "linearSystem.h"
 %template(linearSystemDouble) linearSystem<double>;
 %template(linearSystemFullMatrixDouble) linearSystem<fullMatrix<double> >;