diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h
index 92b5f3d4b68d4fdc531879ab24b4df0acc063f29..b9d91aa18cd1d1a92936c7fb6215700c63eb931a 100644
--- a/Common/GmshDefines.h
+++ b/Common/GmshDefines.h
@@ -124,8 +124,9 @@
 #define MSH_LIN_B 67
 #define MSH_TRI_B 68
 #define MSH_POLYG_B 69
+#define MSH_LIN_C 70
 
-#define MSH_NUM_TYPE 35
+#define MSH_NUM_TYPE 70
 
 // Geometric entities
 #define ENT_NONE     0
diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index 2023e9272e3b2375054b1ca7d416add7e86150e1..ec453a6abb4e2f859b2c031d24a3c2096e0d3783 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -621,16 +621,20 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
   // get the number of elements we need to save
   int numElements = getNumElementsMSH(this, saveAll, saveSinglePartition);
 
-  // get parent elements for polygons and polyhedra
-  std::map<MElement*, GEntity*> parents[2];
+  // get parent elements for lines, polygons and polyhedra
+  std::map<MElement*, GEntity*> parents[3];
+  for(eiter it = firstEdge(); it != lastEdge(); ++it)
+    for(unsigned int i = 0; i < (*it)->lines.size(); i++)
+      if((*it)->lines[i]->ownsParent())
+        parents[0][(*it)->lines[i]->getParent()] = (*it);
   for(fiter it = firstFace(); it != lastFace(); ++it)
     for(unsigned int i = 0; i < (*it)->polygons.size(); i++)
       if((*it)->polygons[i]->ownsParent())
-        parents[0][(*it)->polygons[i]->getParent()] = (*it);
+        parents[1][(*it)->polygons[i]->getParent()] = (*it);
   for(riter it = firstRegion(); it != lastRegion(); ++it)
     for(unsigned int i = 0; i < (*it)->polyhedra.size(); i++)
       if((*it)->polyhedra[i]->ownsParent())
-        parents[1][(*it)->polyhedra[i]->getParent()] = (*it);
+        parents[2][(*it)->polyhedra[i]->getParent()] = (*it);
 
   if(version >= 2.0){
     fprintf(fp, "$MeshFormat\n");
@@ -692,13 +696,21 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
                      version, binary, num, (*it)->tag(), (*it)->physicals);
 
   // lines
+  for(std::map<MElement*, GEntity*>::const_iterator it = parents[0].begin(); 
+      it != parents[0].end(); it++)
+    if(it->first->getType() == TYPE_LIN) {
+      writeElementMSH(fp, this, it->first, saveAll, version, binary, num,
+                      it->second->tag(), it->second->physicals, 0);
+      parentsNum[it->first] = num;
+    }
   for(eiter it = firstEdge(); it != lastEdge(); ++it)
     writeElementsMSH(fp, this, (*it)->lines, saveAll, saveSinglePartition,
-                     version, binary, num, (*it)->tag(), (*it)->physicals);
+                     version, binary, num, (*it)->tag(), (*it)->physicals,
+                     &parentsNum);
 
   // triangles
-  for(std::map<MElement*, GEntity*>::const_iterator it = parents[0].begin(); 
-      it != parents[0].end(); it++)
+  for(std::map<MElement*, GEntity*>::const_iterator it = parents[1].begin(); 
+      it != parents[1].end(); it++)
     if(it->first->getType() == TYPE_TRI) {
       writeElementMSH(fp, this, it->first, saveAll, version, binary, num,
                       it->second->tag(), it->second->physicals, 0);
@@ -709,8 +721,8 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
                      version, binary, num, (*it)->tag(), (*it)->physicals);
 
   // quads
-  for(std::map<MElement*, GEntity*>::const_iterator it = parents[0].begin(); 
-      it != parents[0].end(); it++)
+  for(std::map<MElement*, GEntity*>::const_iterator it = parents[1].begin(); 
+      it != parents[1].end(); it++)
     if(it->first->getType() == TYPE_QUA) {
       writeElementMSH(fp, this, it->first, saveAll, version, binary, num,
                       it->second->tag(), it->second->physicals, 0);
@@ -721,8 +733,8 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
                      version, binary, num, (*it)->tag(), (*it)->physicals);
 
   // polygons
-  for(std::map<MElement*, GEntity*>::const_iterator it = parents[0].begin();
-      it != parents[0].end(); it++)
+  for(std::map<MElement*, GEntity*>::const_iterator it = parents[1].begin();
+      it != parents[1].end(); it++)
     if(it->first->getType() == TYPE_POLYG) {
       writeElementMSH(fp, this, it->first, saveAll, version, binary, num,
                       it->second->tag(), it->second->physicals, 0);
@@ -734,8 +746,8 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
                      &parentsNum);
 
   // tets
-  for(std::map<MElement*, GEntity*>::const_iterator it = parents[1].begin();
-      it != parents[1].end(); it++)
+  for(std::map<MElement*, GEntity*>::const_iterator it = parents[2].begin();
+      it != parents[2].end(); it++)
     if(it->first->getType() == TYPE_TET) {
       writeElementMSH(fp, this, it->first, saveAll, version, binary, num,
                       it->second->tag(), it->second->physicals, 0);
@@ -746,8 +758,8 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
                      version, binary, num, (*it)->tag(), (*it)->physicals);
 
   // hexas
-  for(std::map<MElement*, GEntity*>::const_iterator it = parents[1].begin();
-      it != parents[1].end(); it++)
+  for(std::map<MElement*, GEntity*>::const_iterator it = parents[2].begin();
+      it != parents[2].end(); it++)
     if(it->first->getType() == TYPE_HEX) {
       writeElementMSH(fp, this, it->first, saveAll, version, binary, num,
                       it->second->tag(), it->second->physicals, 0);
@@ -758,8 +770,8 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
                      version, binary, num, (*it)->tag(), (*it)->physicals);
 
   // prisms
-  for(std::map<MElement*, GEntity*>::const_iterator it = parents[1].begin();
-      it != parents[1].end(); it++)
+  for(std::map<MElement*, GEntity*>::const_iterator it = parents[2].begin();
+      it != parents[2].end(); it++)
     if(it->first->getType() == TYPE_PRI) {
       writeElementMSH(fp, this, it->first, saveAll, version, binary, num,
                       it->second->tag(), it->second->physicals, 0);
@@ -770,8 +782,8 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
                      version, binary, num, (*it)->tag(), (*it)->physicals);
   
   // pyramids
-  for(std::map<MElement*, GEntity*>::const_iterator it = parents[1].begin();
-      it != parents[1].end(); it++)
+  for(std::map<MElement*, GEntity*>::const_iterator it = parents[2].begin();
+      it != parents[2].end(); it++)
     if(it->first->getType() == TYPE_PYR) {
       writeElementMSH(fp, this, it->first, saveAll, version, binary, num,
                       it->second->tag(), it->second->physicals, 0);
@@ -782,8 +794,8 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
                      version, binary, num, (*it)->tag(), (*it)->physicals);
 
   // polyhedra
-  for(std::map<MElement*, GEntity*>::const_iterator it = parents[1].begin();
-      it != parents[1].end(); it++)
+  for(std::map<MElement*, GEntity*>::const_iterator it = parents[2].begin();
+      it != parents[2].end(); it++)
     if(it->first->getType() == TYPE_POLYH) {
       writeElementMSH(fp, this, it->first, saveAll, version, binary, num,
                       it->second->tag(), it->second->physicals, 0);
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index 8d055784ee716ec86d862cd884d44c2bbc88e8bc..e1d8f5d555034c1908b018edf5440dd1848976bb 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -776,6 +776,7 @@ int MElement::getInfoMSH(const int typeMSH, const char **const name)
   case MSH_LIN_10 : if(name) *name = "Line 10";         return 2 + 8;
   case MSH_LIN_11 : if(name) *name = "Line 11";         return 2 + 9;
   case MSH_LIN_B  : if(name) *name = "Line Border";     return 2;
+  case MSH_LIN_C  : if(name) *name = "Line Child";      return 2;
   case MSH_TRI_3  : if(name) *name = "Triangle 3";      return 3;
   case MSH_TRI_6  : if(name) *name = "Triangle 6";      return 3 + 3;
   case MSH_TRI_9  : if(name) *name = "Triangle 9";      return 3 + 6;
@@ -926,6 +927,7 @@ MElement *MElementFactory::create(int type, std::vector<MVertex*> &v,
   case MSH_LIN_10: return new MLineN(v, num, part);
   case MSH_LIN_11: return new MLineN(v, num, part);
   case MSH_LIN_B:  return new MLineBorder(v, num, part);
+  case MSH_LIN_C:  return new MLineChild(v, num, part);
   case MSH_TRI_3:  return new MTriangle(v, num, part);
   case MSH_TRI_6:  return new MTriangle6(v, num, part);
   case MSH_TRI_9:  return new MTriangleN(v, 3, num, part);
diff --git a/Geo/MElementCut.cpp b/Geo/MElementCut.cpp
index 388746427fbae8bfe57b40453ea96d59362fd1a2..d87e34eaaff2682abf29cb905c5e7323dafc6233 100644
--- a/Geo/MElementCut.cpp
+++ b/Geo/MElementCut.cpp
@@ -86,11 +86,22 @@ void MPolyhedron::_init()
 
 bool MPolyhedron::isInside(double u, double v, double w)
 {
-  double ksi[3] = {u, v, w};
+  double uvw[3] = {u, v, w};
   for(unsigned int i = 0; i < _parts.size(); i++) {
-    double uvw[3];
-    _parts[i]->xyz2uvw(ksi,uvw);
-    if(_parts[i]->isInside(uvw[0],uvw[1],uvw[2]))
+    double verts[4][3];
+    for(int j = 0; j < 4; j++) {
+      MVertex *vij = _parts[i]->getVertex(j);
+      double v_xyz[3] = {vij->x(), vij->y(), vij->z()};
+      _orig->xyz2uvw(v_xyz, verts[j]);
+    }
+    MVertex v0(verts[0][0], verts[0][1], verts[0][2]);
+    MVertex v1(verts[1][0], verts[1][1], verts[1][2]);
+    MVertex v2(verts[2][0], verts[2][1], verts[2][2]);
+    MVertex v3(verts[3][0], verts[3][1], verts[3][2]);
+    MTetrahedron t(&v0, &v1, &v2, &v3);
+    double ksi[3];
+    t.xyz2uvw(uvw, ksi);
+    if(t.isInside(ksi[0], ksi[1], ksi[2]))
       return true;
   }
   return false;
@@ -176,11 +187,21 @@ void MPolygon::_initVertices()
 }
 bool MPolygon::isInside(double u, double v, double w)
 {
-   double ksi[3] = {u, v, w};
+  double uvw[3] = {u, v, w};
   for(unsigned int i = 0; i < _parts.size(); i++) {
-    double uvw[3];
-    _parts[i]->xyz2uvw(ksi,uvw);
-    if(_parts[i]->isInside(uvw[0],uvw[1],uvw[2]))
+    double v_uvw[3][3];
+    for(int j = 0; j < 3; j++) {
+      MVertex *vij = _parts[i]->getVertex(j);
+      double v_xyz[3] = {vij->x(), vij->y(), vij->z()};
+      _orig->xyz2uvw(v_xyz, v_uvw[j]);
+    }
+    MVertex v0(v_uvw[0][0], v_uvw[0][1], v_uvw[0][2]);
+    MVertex v1(v_uvw[1][0], v_uvw[1][1], v_uvw[1][2]);
+    MVertex v2(v_uvw[2][0], v_uvw[2][1], v_uvw[2][2]);
+    MTriangle t(&v0, &v1, &v2);
+    double ksi[3];
+    t.xyz2uvw(uvw, ksi);
+    if(t.isInside(ksi[0], ksi[1], ksi[2]))
       return true;
   }
   return false;
@@ -223,6 +244,61 @@ void MPolygon::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
   *pts = _intpt;
 }
 
+//----------------------------------- MLineChild ------------------------------
+
+bool MLineChild::isInside(double u, double v, double w)
+{
+  double uvw[3] = {u, v, w};
+  double v_uvw[2][3];
+  for(int i = 0; i < 2; i++) {
+    MVertex *vi = getVertex(i);
+    double v_xyz[3] = {vi->x(), vi->y(), vi->z()};
+    _orig->xyz2uvw(v_xyz, v_uvw[i]);
+  }
+  MVertex v0(v_uvw[0][0], v_uvw[0][1], v_uvw[0][2]);
+  MVertex v1(v_uvw[1][0], v_uvw[1][1], v_uvw[1][2]);
+  MLine l(&v0, &v1);
+  double ksi[3];
+  l.xyz2uvw(uvw, ksi);
+  if(l.isInside(ksi[0], ksi[1], ksi[2]))
+    return true;
+  return false;
+}
+
+void MLineChild::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
+{
+  *npts = 0;
+  double jac[3][3];
+  if(_intpt) delete [] _intpt;
+  _intpt = new IntPt[getNGQLPts(pOrder)];
+  int nptsi;
+  IntPt *ptsi;
+  double v_uvw[2][3];
+  for(int i = 0; i < 2; i++) {
+    MVertex *vi = getVertex(i);
+    double v_xyz[3] = {vi->x(), vi->y(), vi->z()};
+    _orig->xyz2uvw(v_xyz, v_uvw[i]);
+  }
+  MVertex v0(v_uvw[0][0], v_uvw[0][1], v_uvw[0][2]);
+  MVertex v1(v_uvw[1][0], v_uvw[1][1], v_uvw[1][2]);
+  MLine l(&v0, &v1);
+  l.getIntegrationPoints(pOrder, &nptsi, &ptsi);
+  for(int ip = 0; ip < nptsi; ip++){
+    const double u = ptsi[ip].pt[0];
+    const double v = ptsi[ip].pt[1];
+    const double w = ptsi[ip].pt[2];
+    const double weight = ptsi[ip].weight;
+    const double detJ = l.getJacobian(u, v, w, jac);
+    SPoint3 p; l.pnt(u, v, w, p);
+    _intpt[*npts + ip].pt[0] = p.x();
+    _intpt[*npts + ip].pt[1] = p.y();
+    _intpt[*npts + ip].pt[2] = p.z();
+    _intpt[*npts + ip].weight = detJ * weight;
+  }
+  *npts = nptsi;
+  *pts = _intpt;
+}
+
 //----------------------------------- MTriangleBorder ------------------------------
 
 void MTriangleBorder::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
@@ -636,9 +712,10 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
           else
             poly[1].push_back(mt);
         }
+        bool own = (eParent && !e->ownsParent()) ? false : true;
         if(poly[0].size()) {
-          bool own = (eParent && !e->ownsParent()) ? false : true;
           p1 = new MPolyhedron(poly[0], ++numEle, ePart, own, parent);
+          own = false;
           int reg = getElementaryTag(-1, elementary, newElemTags[3]);
           std::vector<int> phys;
           getPhysicalTag(-1, gePhysicals, phys, newPhysTags[3]);
@@ -646,7 +723,6 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
           assignPhysicals(GM, phys, reg, 3, physicals);
         }
         if(poly[1].size()) {
-          bool own = poly[0].size() ? false : (eParent && !e->ownsParent()) ? false : true;
           p2 = new MPolyhedron(poly[1], ++numEle, ePart, own, parent);
           elements[9][elementary].push_back(p2);
           assignPhysicals(GM, gePhysicals, elementary, 3, physicals);
@@ -794,9 +870,10 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
           else
             poly[1].push_back(mt);
         }
+        bool own = (eParent && !e->ownsParent()) ? false : true;
         if(poly[0].size()) {
-          bool own = (eParent && !e->ownsParent()) ? false : true;
           p1 = new MPolygon(poly[0], ++numEle, ePart, own, parent);
+          own = false;
           int reg = getElementaryTag(-1, elementary, newElemTags[2]);
           std::vector<int> phys;
           getPhysicalTag(-1, gePhysicals, phys, newPhysTags[2]);
@@ -807,7 +884,6 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
               borders[1].insert(std::pair<MElement*, MElement*>(p1->getDomain(i), p1));
         }
         if(poly[1].size()) {
-          bool own = poly[0].size() ? false : (eParent && !e->ownsParent()) ? false : true;
           p2 = new MPolygon(poly[1], ++numEle, ePart, own, parent);
           elements[8][elementary].push_back(p2);
           assignPhysicals(GM, gePhysicals, elementary, 2, physicals);
@@ -895,7 +971,7 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
       isCut = L.cut(RPN, ipV, cp, integOrder, lines, 0, nodeLs);
 
       if(isCut) {
-        if(eType == MSH_LIN_2) numEle--; // delete copy
+        bool own = (eParent && !e->ownsParent()) ? false : true;
         for (unsigned int i = nbL; i < lines.size(); i++){
           MVertex *mv[2] = {NULL, NULL};
           for(int j = 0; j < 2; j++){
@@ -916,9 +992,10 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
             }
           }
           MLine *ml;
-          if(eType != MSH_LIN_B) ml = new MLine(mv[0], mv[1], ++numEle, ePart);
+          if(eType != MSH_LIN_B) ml = new MLineChild(mv[0], mv[1], ++numEle, ePart, own, parent);
           else ml = new MLineBorder(mv[0], mv[1], ++numEle, ePart,
                                     copy->getDomain(0), copy->getDomain(1));
+          own = false;
           int reg = getElementaryTag(lines[i]->lsTag(), elementary, newElemTags[1]);
           std::vector<int> phys;
           getPhysicalTag(lines[i]->lsTag(), gePhysicals, phys, newPhysTags[1]);
@@ -928,7 +1005,7 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
             if(ml->getDomain(i))
               borders[0].insert(std::pair<MElement*, MElement*>(ml->getDomain(i), ml));
         }
-        delete copy;
+        if(eParent) {copy->setParent(NULL, false); delete copy;}
       }
       else { // no cut
         int reg = getElementaryTag(lines[nbL]->lsTag(), elementary, newElemTags[1]);
diff --git a/Geo/MElementCut.h b/Geo/MElementCut.h
index 65f7a9d47e12e9db113caf362cd76109315c5dc3..6af8126073f432b25c90c1007bf02a71400a86a1 100644
--- a/Geo/MElementCut.h
+++ b/Geo/MElementCut.h
@@ -126,6 +126,8 @@ class MPolyhedron : public MElement {
   {
     _orig->getGradShapeFunctions(u, v, w, s, o);
   }
+  // the parametric coordinates of the polyhedron are
+  // the coordinates in the local parent element.
   virtual void xyz2uvw(double xyz[3], double uvw[3])
   {
     _orig->xyz2uvw(xyz,uvw);
@@ -245,6 +247,8 @@ class MPolygon : public MElement {
   {
     _orig->getGradShapeFunctions(u, v, w, s, o);
   }
+  // the parametric coordinates of the polygon are
+  // the coordinates in the local parent element.
   virtual void xyz2uvw(double xyz[3], double uvw[3])
   {
     _orig->xyz2uvw(xyz,uvw);
@@ -268,6 +272,51 @@ class MPolygon : public MElement {
   }
 };
 
+class MLineChild : public MLine {
+ protected:
+  bool _owner;
+  MElement* _orig;
+  IntPt *_intpt;
+ public:
+  MLineChild(MVertex *v0, MVertex *v1, int num = 0, int part = 0,
+             bool owner = false, MElement* orig = NULL)
+    : MLine(v0, v1, num, part), _owner(owner), _orig(orig) {}
+  MLineChild(std::vector<MVertex*> v, int num = 0, int part = 0,
+           bool owner = false, MElement* orig = NULL)
+    : MLine(v, num, part), _owner(owner), _orig(orig) {}
+  ~MLineChild()
+  {
+    if(_owner)
+      delete _orig;
+  }
+  virtual int getTypeForMSH() const { return MSH_LIN_C; }
+  virtual const polynomialBasis* getFunctionSpace(int order=-1) const
+  {
+    return _orig->getFunctionSpace(order);
+  }
+  virtual void getShapeFunctions(double u, double v, double w, double s[], int o)
+  {
+    _orig->getShapeFunctions(u, v, w, s, o);
+  }
+  virtual void getGradShapeFunctions(double u, double v, double w, double s[][3], int o)
+  {
+    _orig->getGradShapeFunctions(u, v, w, s, o);
+  }
+  // the parametric coordinates of the LineChildren are
+  // the coordinates in the local parent element.
+  virtual void xyz2uvw(double xyz[3], double uvw[3])
+  {
+    _orig->xyz2uvw(xyz,uvw);
+  }
+  virtual bool isInside(double u, double v, double w);
+  virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts);
+  virtual MElement *getParent() const { return _orig; }
+  virtual void setParent(MElement *p, bool owner = false) { _orig = p; _owner = owner; }
+  virtual bool ownsParent() const { return _owner; }
+};
+
+// -------------------- Border classes
+
 class MTriangleBorder : public MTriangle {
  protected:
   MElement* _domains[2];
@@ -401,6 +450,16 @@ class MLineBorder : public MLine {
   virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts);
 };
 
+// Build a new GModel with elements on each side of the levelset ls.
+// New physical and elementary entities are created.
+// The physical and elementary numbers of the elements with ls < 0 are  
+// the physical and elementary number of the elements cut.
+// The physical and elementary numbers of the elements with ls > 0 are
+// the maximum physical and elementary numbers existing in their dimension + 1.
+// The physical and elementary numbers of the elements on the border (ls=0) are
+// the levelset tag, unless an entity of the same dimension has already this number,
+// knowing that the elements are cut in ascending dimension order (points, lines,
+// surfaces and then volumes).
 GModel *buildCutMesh(GModel *gm, gLevelset *ls,
                      std::map<int, std::vector<MElement*> > elements[10],
                      std::map<int, MVertex*> &vertexMap,