diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h
index 999913e9991d453898b915d36269f3aea945c736..83456e0dd9657e30a1f7a393307866f8bb3e626e 100644
--- a/Common/GmshDefines.h
+++ b/Common/GmshDefines.h
@@ -121,6 +121,9 @@
 #define MSH_LIN_9  64
 #define MSH_LIN_10  65
 #define MSH_LIN_11  66
+#define MSH_LIN_B 67
+#define MSH_TRI_B 68
+#define MSH_POLYG_B 69
 
 #define MSH_NUM_TYPE 35
 
diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index 45002386829f1cbec8486eda2dcb524f7c0b2670..1c6814d8b632ea2e0508b227802ae76bce65f91e 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -366,7 +366,8 @@ int GModel::readMSH(const std::string &name)
               else if(j == numTags - 1) parent = tag;
             }
             if(!(numVertices = MElement::getInfoMSH(type))) {
-              if(type != MSH_POLYG_ && type != MSH_POLYH_) return 0;
+              if(type != MSH_POLYG_ && type != MSH_POLYH_ && type != MSH_POLYG_B)
+                return 0;
               if(fscanf(fp, "%d", &numVertices) != 1) return 0;
             }
           }
@@ -695,7 +696,7 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
   for(eiter it = firstEdge(); it != lastEdge(); ++it)
     writeElementsMSH(fp, this, (*it)->lines, saveAll, saveSinglePartition,
                      version, binary, num, (*it)->tag(), (*it)->physicals);
-  
+
   // triangles
   for(std::map<MElement*, GEntity*>::const_iterator it = parents[0].begin(); 
       it != parents[0].end(); it++)
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index 3585a71a1e34d3384ce7d4997669fcfbf421187a..0049f657813b6adc955b75a89beb20df2c0433db 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -315,7 +315,7 @@ void MElement::xyz2uvw(double xyz[3], double uvw[3])
   uvw[0] = uvw[1] = uvw[2] = 0.;
   int iter = 1, maxiter = 20;
   double error = 1., tol = 1.e-6;
-  
+
   while (error > tol && iter < maxiter){
     double jac[3][3];
     if(!getJacobian(uvw[0], uvw[1], uvw[2], jac)) break;
@@ -421,7 +421,7 @@ void MElement::writeMSH(FILE *fp, double version, bool binary, int num,
   setVolumePositive();
   int n = getNumVerticesForMSH();
   int par = (parentNum) ? 1 : 0;
-  bool poly = (type == MSH_POLYG_ || type == MSH_POLYH_);
+  bool poly = (type == MSH_POLYG_ || type == MSH_POLYH_ || type == MSH_POLYG_B);
 
   if(!binary){
     fprintf(fp, "%d %d", num ? num : _num, type);
@@ -440,7 +440,7 @@ void MElement::writeMSH(FILE *fp, double version, bool binary, int num,
       for(unsigned int i = 0; i < ghosts->size(); i++)
         fprintf(fp, " %d", -(*ghosts)[i]);
     }
-    if(version >= 2.0 && parentNum)
+    if(version >= 2.0 && par)
       fprintf(fp, " %d", parentNum);
     if(version >= 2.0 && poly)
       fprintf(fp, " %d", n);
@@ -753,8 +753,9 @@ int MElement::getInfoMSH(const int typeMSH, const char **const name)
   case MSH_LIN_7  : if(name) *name = "Line 7";          return 2 + 5;
   case MSH_LIN_8  : if(name) *name = "Line 8";          return 2 + 6;
   case MSH_LIN_9  : if(name) *name = "Line 9";          return 2 + 7;
-  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_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_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;
@@ -769,25 +770,27 @@ int MElement::getInfoMSH(const int typeMSH, const char **const name)
   case MSH_TRI_55 : if(name) *name = "Triangle 55";     return 3 + 24 + 28;
   case MSH_TRI_66 : if(name) *name = "Triangle 66";     return 3 + 27 + 36;
   case MSH_TRI_18 : if(name) *name = "Triangle 18";     return 3 + 15;
-  case MSH_TRI_21I : if(name) *name = "Triangle 21I";   return 3 + 18;
+  case MSH_TRI_21I: if(name) *name = "Triangle 21I";    return 3 + 18;
   case MSH_TRI_24 : if(name) *name = "Triangle 24";     return 3 + 21;
   case MSH_TRI_27 : if(name) *name = "Triangle 27";     return 3 + 24;
   case MSH_TRI_30 : if(name) *name = "Triangle 30";     return 3 + 27;
+  case MSH_TRI_B  : if(name) *name = "Triangle Border"; return 3;
   case MSH_QUA_4  : if(name) *name = "Quadrilateral 4"; return 4;
   case MSH_QUA_8  : if(name) *name = "Quadrilateral 8"; return 4 + 4;
   case MSH_QUA_9  : if(name) *name = "Quadrilateral 9"; return 9;
-  case MSH_QUA_16  : if(name) *name = "Quadrilateral 16"; return 16;
-  case MSH_QUA_25  : if(name) *name = "Quadrilateral 25"; return 25;
-  case MSH_QUA_36  : if(name) *name = "Quadrilateral 36"; return 36;
-  case MSH_QUA_49  : if(name) *name = "Quadrilateral 49"; return 49;
-  case MSH_QUA_64  : if(name) *name = "Quadrilateral 64"; return 64;
-  case MSH_QUA_81  : if(name) *name = "Quadrilateral 81"; return 81;
-  case MSH_QUA_100 : if(name) *name = "Quadrilateral 100"; return 100;
-  case MSH_QUA_121 : if(name) *name = "Quadrilateral 121"; return 121;
+  case MSH_QUA_16 : if(name) *name = "Quadrilateral 16"; return 16;
+  case MSH_QUA_25 : if(name) *name = "Quadrilateral 25"; return 25;
+  case MSH_QUA_36 : if(name) *name = "Quadrilateral 36"; return 36;
+  case MSH_QUA_49 : if(name) *name = "Quadrilateral 49"; return 49;
+  case MSH_QUA_64 : if(name) *name = "Quadrilateral 64"; return 64;
+  case MSH_QUA_81 : if(name) *name = "Quadrilateral 81"; return 81;
+  case MSH_QUA_100: if(name) *name = "Quadrilateral 100"; return 100;
+  case MSH_QUA_121: if(name) *name = "Quadrilateral 121"; return 121;
   case MSH_QUA_12 : if(name) *name = "Quadrilateral 12"; return 12;
-  case MSH_QUA_16I : if(name) *name = "Quadrilateral 16I"; return 16;
+  case MSH_QUA_16I: if(name) *name = "Quadrilateral 16I"; return 16;
   case MSH_QUA_20 : if(name) *name = "Quadrilateral 20"; return 20;
   case MSH_POLYG_ : if(name) *name = "Polygon";         return 0;
+  case MSH_POLYG_B: if(name) *name = "Polygon Border";  return 0;
   case MSH_TET_4  : if(name) *name = "Tetrahedron 4";   return 4;
   case MSH_TET_10 : if(name) *name = "Tetrahedron 10";  return 4 + 6;
   case MSH_TET_20 : if(name) *name = "Tetrahedron 20";  return 4 + 12 + 4;
@@ -821,6 +824,72 @@ int *MElement::getVerticesIdForMSH()
   return verts;
 }
 
+MElement *MElement::copy(int &num, std::map<int, MVertex*> &vertexMap,
+                         std::map<MElement*, MElement*> &newParents,
+                         std::map<MElement*, MElement*> &newDomains)
+{
+  if(newDomains.count(this))
+    return newDomains.find(this)->second;
+  std::vector<MVertex*> vmv;
+  int eType = getTypeForMSH();
+  MElement *eParent = getParent();
+  if(getNumChildren() == 0) {
+    for(int i = 0; i < getNumVertices(); i++) {
+      MVertex *v = getVertex(i);
+      int numV = v->getNum();
+      if(vertexMap.count(numV))
+        vmv.push_back(vertexMap[numV]);
+      else {
+        MVertex *mv = new MVertex(v->x(), v->y(), v->z(), 0, numV);
+        vmv.push_back(mv);
+        vertexMap[numV] = mv;
+      }
+    }
+  }
+  else {
+    for(int i = 0; i < getNumChildren(); i++) {
+      for(int j = 0; j < getChild(i)->getNumVertices(); j++) {
+        MVertex *v = getChild(i)->getVertex(j);
+        int numV = v->getNum();
+        if(vertexMap.count(numV))
+          vmv.push_back(vertexMap[numV]);
+        else {
+          MVertex *mv = new MVertex(v->x(), v->y(), v->z(), 0, numV);
+          vmv.push_back(mv);
+          vertexMap[numV] = mv;
+        }
+      }
+    }
+  }
+  MElementFactory factory;
+  MElement *newEl = factory.create(eType, vmv, ++num, _partition);
+  if(eParent && !getDomain(0) && !getDomain(1)) {
+    std::map<MElement*, MElement*>::iterator it = newParents.find(eParent);
+    MElement *newParent;
+    if(it == newParents.end()) {
+      newParent = eParent->copy(num, vertexMap, newParents, newDomains);
+      newParents[eParent] = newParent;
+    }
+    else
+      newParent = it->second;
+    newEl->setParent(newParent, ownsParent());
+  }
+  for(int i = 0; i < 2; i++) {
+    MElement *dom = getDomain(i);
+    if(!dom) continue;
+    std::map<MElement*, MElement*>::iterator it = newDomains.find(dom);
+    MElement *newDom;
+    if(it == newDomains.end()) {
+      newDom = dom->copy(num, vertexMap, newParents, newDomains);
+      newDomains[dom] = newDom;
+    }
+    else
+      newDom = newDomains.find(dom)->second;
+    newEl->setDomain(newDom, i);
+  }
+  return newEl;
+}
+
 MElement *MElementFactory::create(int type, std::vector<MVertex*> &v,
                                   int num, int part)
 {
@@ -836,6 +905,7 @@ MElement *MElementFactory::create(int type, std::vector<MVertex*> &v,
   case MSH_LIN_9:  return new MLineN(v, num, part);
   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_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);
@@ -849,18 +919,20 @@ MElement *MElementFactory::create(int type, std::vector<MVertex*> &v,
   case MSH_TRI_45: return new MTriangleN(v, 8, num, part);
   case MSH_TRI_55: return new MTriangleN(v, 9, num, part);
   case MSH_TRI_66: return new MTriangleN(v,10, num, part);
+  case MSH_TRI_B:  return new MTriangleBorder(v, num, part);
   case MSH_QUA_4:  return new MQuadrangle(v, num, part);
   case MSH_QUA_8:  return new MQuadrangle8(v, num, part);
   case MSH_QUA_9:  return new MQuadrangle9(v, num, part);
-  case MSH_QUA_16:  return new MQuadrangleN(v, 3, num, part);
-  case MSH_QUA_25:  return new MQuadrangleN(v, 4, num, part);
-  case MSH_QUA_36:  return new MQuadrangleN(v, 5, num, part);
-  case MSH_QUA_49:  return new MQuadrangleN(v, 6, num, part);
-  case MSH_QUA_64:  return new MQuadrangleN(v, 7, num, part);
-  case MSH_QUA_81:  return new MQuadrangleN(v, 8, num, part);
-  case MSH_QUA_100:  return new MQuadrangleN(v, 9, num, part);
-  case MSH_QUA_121:  return new MQuadrangleN(v, 10, num, part);
+  case MSH_QUA_16: return new MQuadrangleN(v, 3, num, part);
+  case MSH_QUA_25: return new MQuadrangleN(v, 4, num, part);
+  case MSH_QUA_36: return new MQuadrangleN(v, 5, num, part);
+  case MSH_QUA_49: return new MQuadrangleN(v, 6, num, part);
+  case MSH_QUA_64: return new MQuadrangleN(v, 7, num, part);
+  case MSH_QUA_81: return new MQuadrangleN(v, 8, num, part);
+  case MSH_QUA_100:return new MQuadrangleN(v, 9, num, part);
+  case MSH_QUA_121:return new MQuadrangleN(v, 10, num, part);
   case MSH_POLYG_: return new MPolygon(v, num, part);
+  case MSH_POLYG_B:return new MPolygonBorder(v, num, part);
   case MSH_TET_4:  return new MTetrahedron(v, num, part);
   case MSH_TET_10: return new MTetrahedron10(v, num, part);
   case MSH_HEX_8:  return new MHexahedron(v, num, part);
diff --git a/Geo/MElement.h b/Geo/MElement.h
index 3ae48ce099a1a8b3d306b740411e924fd658cae5..8831f18e39d573f7103f256b7c33318f10e477c9 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -150,12 +150,15 @@ class MElement
     v.resize(0);
   }
 
-  // get parent and children for hierarchial grids
+  // get and set parent and children for hierarchial grids
   virtual MElement *getParent() const { return NULL; }
   virtual void setParent(MElement *p, bool owner = false) {}
   virtual int getNumChildren() const { return 0; }
   virtual MElement *getChild(int i) const { return NULL; }
   virtual bool ownsParent() const { return false; }
+  // get and set domain for borders
+  virtual MElement *getDomain(int i) const { return NULL; }
+  virtual void setDomain (MElement *e, int i) { }
 
   //get the type of the element
   virtual int getType() const = 0;
@@ -282,6 +285,11 @@ class MElement
   virtual int getNumVerticesForMSH() { return getNumVertices(); }
   virtual int *getVerticesIdForMSH();
   static void registerBindings(binding *b);
+
+  // copy element and parent if any, vertexMap contains the new vertices
+  virtual MElement *copy(int &num, std::map<int, MVertex*> &vertexMap,
+                         std::map<MElement*, MElement*> &newParents,
+                         std::map<MElement*, MElement*> &newDomains);
 };
 
 class MElementLessThanLexicographic{
diff --git a/Geo/MElementCut.cpp b/Geo/MElementCut.cpp
index df45970ce23786ffb0ea8174c483f0d853aa6f68..388746427fbae8bfe57b40453ea96d59362fd1a2 100644
--- a/Geo/MElementCut.cpp
+++ b/Geo/MElementCut.cpp
@@ -252,6 +252,41 @@ void MTriangleBorder::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
   }
 }
 
+//----------------------------------- MPolygonBorder ------------------------------
+
+void MPolygonBorder::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
+{
+  std::vector<MVertex*> verts;
+  for(unsigned int i = 0; i < _parts.size(); i++) {
+    double uvw[3][3];
+    for(int j = 0; j < 3; j++) {
+      MVertex *v = _parts[i]->getVertex(j);
+      double xyz[3] = {v->x(), v->y(), v->z()};
+      getParent()->xyz2uvw(xyz, uvw[j]);
+    }
+    verts.push_back(new MVertex(uvw[0][0], uvw[0][1], uvw[0][2]));
+    verts.push_back(new MVertex(uvw[1][0], uvw[1][1], uvw[1][2]));
+    verts.push_back(new MVertex(uvw[2][0], uvw[2][1], uvw[2][2]));
+  }
+  MPolygon pp(verts);
+  pp.getIntegrationPoints(pOrder, npts, pts);
+  double jac[3][3];
+  for(int ip = 0; ip < (*npts); ip++){
+    const double u = pts[ip]->pt[0];
+    const double v = pts[ip]->pt[1];
+    const double w = pts[ip]->pt[2];
+    const double weight = pts[ip]->weight;
+    const double detJ = pp.getJacobian(u, v, w, jac);
+    SPoint3 p; pp.pnt(u, v, w, p);
+    (*pts[ip]).pt[0] = p.x();
+    (*pts[ip]).pt[1] = p.y();
+    (*pts[ip]).pt[2] = p.z();
+    (*pts[ip]).weight = detJ * weight;
+  }
+  for(unsigned int i = 0; i < verts.size(); i++)
+    delete verts[i];
+}
+
 //-------------------------------------- MLineBorder ------------------------------
 
 void MLineBorder::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
@@ -337,6 +372,8 @@ static int getBorderTag(int lsTag, int count, int &maxTag, std::map<int, int> &b
 static void elementSplitMesh(MElement *e, fullMatrix<double> &verticesLs,
                              GEntity *ge, GModel *GM, int &numEle,
                              std::map<int, MVertex*> &vertexMap,
+                             std::map<MElement*, MElement*> &newParents,
+                             std::map<MElement*, MElement*> &newDomains,
                              std::map<int, std::vector<MElement*> > elements[10],
                              std::map<int, std::map<int, std::string> > physicals[4],
                              std::map<int, int> newElemTags[4],
@@ -344,40 +381,9 @@ static void elementSplitMesh(MElement *e, fullMatrix<double> &verticesLs,
 {
   int elementary = ge->tag();
   int eType = e->getTypeForMSH();
-  int ePart = e->getPartition();
   std::vector<int> gePhysicals = ge->physicals;
 
-  std::vector<MVertex*> vmv;
-  if(eType != MSH_POLYG_ && eType != MSH_POLYH_) {
-    for(int i = 0; i < e->getNumVertices(); i++) {
-      MVertex *vert = e->getVertex(i);
-      int numV = vert->getNum();
-      if(vertexMap.count(numV))
-        vmv.push_back(vertexMap[numV]);
-      else {
-        MVertex *mv = new MVertex(vert->x(), vert->y(), vert->z(), 0, numV);
-        vmv.push_back(mv);
-        vertexMap[numV] = mv;
-      }
-    }
-  }
-  else {
-    for(int i = 0; i < e->getNumChildren(); i++) {
-      for(int j = 0; j < e->getChild(i)->getNumVertices(); j++) {
-        MVertex *vert = e->getChild(i)->getVertex(j);
-        int numV = vert->getNum();
-        if(vertexMap.count(numV))
-          vmv.push_back(vertexMap[numV]);
-        else {
-          MVertex *mv = new MVertex(vert->x(), vert->y(), vert->z(), 0, numV);
-          vmv.push_back(mv);
-          vertexMap[numV] = mv;
-        }
-      }
-    }
-  }
-  MElementFactory factory;
-  MElement *copy = factory.create(eType, vmv, ++numEle, ePart);
+  MElement *copy = e->copy(numEle, vertexMap, newParents, newDomains);
 
   double lsMean = 0.;
   for(int k = 0; k < e->getNumVertices(); k++)
@@ -410,6 +416,7 @@ static void elementSplitMesh(MElement *e, fullMatrix<double> &verticesLs,
   case MSH_TRI_3 :
   case MSH_QUA_4 :
   case MSH_POLYG_ :
+  case MSH_POLYG_B :
     {
       int reg = getElementaryTag(lsTag, elementary, newElemTags[2]);
       std::vector<int> phys;
@@ -418,12 +425,13 @@ static void elementSplitMesh(MElement *e, fullMatrix<double> &verticesLs,
         elements[2][reg].push_back(copy);
       else if(eType == MSH_QUA_4)
         elements[3][reg].push_back(copy);
-      else if(eType == MSH_POLYG_)
+      else if(eType == MSH_POLYG_ || eType == MSH_POLYG_B)
         elements[8][reg].push_back(copy);
       assignPhysicals(GM, phys, reg, 2, physicals);
     }
     break;
   case MSH_LIN_2 :
+  case MSH_LIN_B :
     {
       int reg = getElementaryTag(lsTag, elementary, newElemTags[1]);
       std::vector<int> phys;
@@ -442,7 +450,7 @@ static void elementSplitMesh(MElement *e, fullMatrix<double> &verticesLs,
     }
     break;
   default :
-    Msg::Error("This type of element cannot be cut.");
+    Msg::Error("This type of element cannot be split.");
     return;
   }
 }
@@ -464,14 +472,16 @@ static int getElementVertexNum(DI_Point *p, MElement *e)
   return -1;
 }
 
-
-typedef std::set<MVertex*, MVertexLessThanLexicographic> newVerticesContainer ;
+typedef std::set<MVertex*, MVertexLessThanLexicographic> newVerticesContainer;
 
 static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
                            fullMatrix<double> &verticesLs,
                            GEntity *ge, GModel *GM, int &numEle,
                            std::map<int, MVertex*> &vertexMap,
                            newVerticesContainer &newVertices,
+                           std::map<MElement*, MElement*> &newParents,
+                           std::map<MElement*, MElement*> &newDomains,
+                           std::multimap<MElement*, MElement*> borders[2],
                            std::map<int, std::vector<MElement*> > elements[10],
                            std::map<int, std::map<int, std::string> > physicals[4],
                            std::map<int, int> newElemTags[4],
@@ -488,6 +498,7 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
   int elementary = ge->tag();
   int eType = e->getTypeForMSH();
   int ePart = e->getPartition();
+  MElement *eParent = e->getParent();
   std::vector<int> gePhysicals = ge->physicals;
 
   int integOrder = 1;
@@ -500,38 +511,8 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
   unsigned int nbTe = tetras.size();
   unsigned int nbH = hexas.size();
 
-  // copy element
-  std::vector<MVertex*> vmv;
-  if(eType != MSH_POLYG_ && eType != MSH_POLYH_) {
-    for(int i = 0; i < e->getNumVertices(); i++) {
-      MVertex *vert = e->getVertex(i);
-      int numV = vert->getNum();
-      if(vertexMap.count(numV))
-        vmv.push_back(vertexMap[numV]);
-      else {
-        MVertex *mv = new MVertex(vert->x(), vert->y(), vert->z(), 0, numV);
-        vmv.push_back(mv);
-        vertexMap[numV] = mv;
-      }
-    }
-  }
-  else {
-    for(int i = 0; i < e->getNumChildren(); i++) {
-      for(int j = 0; j < e->getChild(i)->getNumVertices(); j++) {
-        MVertex *vert = e->getChild(i)->getVertex(j);
-        int numV = vert->getNum();
-        if(vertexMap.count(numV))
-          vmv.push_back(vertexMap[numV]);
-        else {
-          MVertex *mv = new MVertex(vert->x(), vert->y(), vert->z(), 0, numV);
-          vmv.push_back(mv);
-          vertexMap[numV] = mv;
-        }
-      }
-    }
-  }
-  MElementFactory factory;
-  MElement *copy = factory.create(eType, vmv, ++numEle, ePart);
+  MElement *copy = e->copy(numEle, vertexMap, newParents, newDomains);
+  MElement *parent = eParent ? copy->getParent() : copy;
 
   double **nodeLs = new double*[e->getNumPrimaryVertices()];
 
@@ -649,14 +630,15 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
               else mv[j] = it->second;
             }
           }
-          MTetrahedron *mt = new MTetrahedron(mv[0], mv[1], mv[2], mv[3], ++numEle, ePart);
+          MTetrahedron *mt = new MTetrahedron(mv[0], mv[1], mv[2], mv[3], 0, 0);
           if(tetras[i]->lsTag() < 0)
             poly[0].push_back(mt);
           else
             poly[1].push_back(mt);
         }
         if(poly[0].size()) {
-          p1 = new MPolyhedron(poly[0], ++numEle, ePart, true, copy);
+          bool own = (eParent && !e->ownsParent()) ? false : true;
+          p1 = new MPolyhedron(poly[0], ++numEle, ePart, own, parent);
           int reg = getElementaryTag(-1, elementary, newElemTags[3]);
           std::vector<int> phys;
           getPhysicalTag(-1, gePhysicals, phys, newPhysTags[3]);
@@ -664,10 +646,29 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
           assignPhysicals(GM, phys, reg, 3, physicals);
         }
         if(poly[1].size()) {
-          p2 = new MPolyhedron(poly[1], ++numEle, ePart, false, copy);
+          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);
         }
+        std::pair<std::multimap<MElement*, MElement*>::iterator,
+                  std::multimap<MElement*, MElement*>::iterator> itr = borders[1].equal_range(copy);
+        for(std::multimap<MElement*, MElement*>::iterator it = itr.first;
+            it != itr.second; it++) {
+          MElement *tb = it->second;
+          int match = 0;
+          for(int i = 0; i < p1->getNumPrimaryVertices(); i++) {
+            if(tb->getVertex(0) == p1->getVertex(i) ||
+               tb->getVertex(1) == p1->getVertex(i) ||
+               tb->getVertex(2) == p1->getVertex(i)) match++;
+            if(match == 3) break;
+          }
+          MElement *dom = (match == 3) ? p1 : p2;
+          tb->setDomain(dom, (tb->getDomain(0) == copy) ? 0 : 1);
+          borders[1].insert(std::pair<MElement*, MElement*>(dom, tb));
+        }
+        borders[1].erase(itr.first, itr.second);
+        if(eParent) {copy->setParent(NULL, false); delete copy;}
       }
       else { // no cut
         int reg = getElementaryTag(tetras[nbTe]->lsTag(), elementary, newElemTags[3]);
@@ -707,7 +708,7 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
           }
         }
         MTriangle *tri;
-        if(p1 || p2) tri = new MTriangleBorder(mv[0], mv[1], mv[2], p1, p2, ++numEle, ePart);
+        if(p1 || p2) tri = new MTriangleBorder(mv[0], mv[1], mv[2], ++numEle, ePart, p1, p2);
         else tri = new MTriangle(mv[0], mv[1], mv[2], ++numEle, ePart);
         int lsT = triangles[i]->lsTag();
         int c = elements[2].count(lsT) + elements[3].count(lsT) + elements[8].count(lsT);
@@ -717,12 +718,17 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
         std::vector<int> phys; phys.push_back(physTag);
         elements[2][reg].push_back(tri);
         assignPhysicals(GM, phys, reg, 2, physicals);
+        for(int i = 0; i < 2; i++)
+          if(tri->getDomain(i))
+            borders[1].insert(std::pair<MElement*, MElement*>(tri->getDomain(i), tri));
       }
     }
     break;
   case MSH_TRI_3 :
+  case MSH_TRI_B :
   case MSH_QUA_4 :
   case MSH_POLYG_ :
+  case MSH_POLYG_B :
     {
       if(eType == MSH_TRI_3) {
         DI_Triangle T(e->getVertex(0)->x(), e->getVertex(0)->y(), e->getVertex(0)->z(),
@@ -741,9 +747,9 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
         isCut = Q.cut(RPN, ipV, ipS, cp, integOrder,integOrder,integOrder,
                       quads, triangles, lines, 0, nodeLs);
       }
-      else if(eType == MSH_POLYG_){
+      else if(eType == MSH_POLYG_ || eType == MSH_POLYG_B){
         for(int i = 0; i < e->getNumChildren(); i++) {
-          MTriangle *t = (MTriangle*) e->getChild(i);
+          MElement *t = e->getChild(i);
           DI_Triangle Tri(t->getVertex(0)->x(), t->getVertex(0)->y(), t->getVertex(0)->z(),
                           t->getVertex(1)->x(), t->getVertex(1)->y(), t->getVertex(1)->z(),
                           t->getVertex(2)->x(), t->getVertex(2)->y(), t->getVertex(2)->z());
@@ -778,25 +784,54 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
               else mv[j] = it->second;
             }
           }
-          MTriangle *mt = new MTriangle(mv[0], mv[1], mv[2], ++numEle, ePart);
+          MTriangle *mt;
+          if(eType == MSH_TRI_B || eType == MSH_POLYG_B)
+            mt = new MTriangleBorder(mv[0], mv[1], mv[2], 0, 0,
+                                        copy->getDomain(0), copy->getDomain(1));
+          else mt = new MTriangle(mv[0], mv[1], mv[2], 0, 0);
           if(triangles[i]->lsTag() < 0)
             poly[0].push_back(mt);
           else
             poly[1].push_back(mt);
         }
         if(poly[0].size()) {
-          p1 = new MPolygon(poly[0], ++numEle, ePart, true, copy);
+          bool own = (eParent && !e->ownsParent()) ? false : true;
+          p1 = new MPolygon(poly[0], ++numEle, ePart, own, parent);
           int reg = getElementaryTag(-1, elementary, newElemTags[2]);
           std::vector<int> phys;
           getPhysicalTag(-1, gePhysicals, phys, newPhysTags[2]);
           elements[8][reg].push_back(p1);
           assignPhysicals(GM, phys, reg, 2, physicals);
+          for(int i = 0; i < 2; i++)
+            if(p1->getDomain(i))
+              borders[1].insert(std::pair<MElement*, MElement*>(p1->getDomain(i), p1));
         }
         if(poly[1].size()) {
-          p2 = new MPolygon(poly[1], ++numEle, ePart, false, copy);
+          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);
+          for(int i = 0; i < 2; i++)
+            if(p2->getDomain(i))
+              borders[1].insert(std::pair<MElement*, MElement*>(p2->getDomain(i), p2));
+        }
+        std::pair<std::multimap<MElement*, MElement*>::iterator,
+                  std::multimap<MElement*, MElement*>::iterator> itr = borders[0].equal_range(copy);
+        for(std::multimap<MElement*, MElement*>::iterator it = itr.first;
+            it != itr.second; ++it) {
+          MElement *lb = it->second;
+          int match = 0;
+          for(int i = 0; i < p1->getNumPrimaryVertices(); i++) {
+            if(lb->getVertex(0) == p1->getVertex(i) ||
+               lb->getVertex(1) == p1->getVertex(i)) match++;
+            if(match == 2) break;
+          }
+          MElement *dom = (match == 2) ? p1 : p2;
+          lb->setDomain(dom, (lb->getDomain(0) == copy) ? 0 : 1);
+          borders[0].insert(std::pair<MElement*, MElement*>(dom, lb));
         }
+        borders[0].erase(itr.first, itr.second);
+        if(eParent) {copy->setParent(NULL, false); delete copy;}
       }
       else { // no cut
         int reg = getElementaryTag(triangles[nbTr]->lsTag(), elementary, newElemTags[2]);
@@ -806,9 +841,12 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
           elements[2][reg].push_back(copy);
         else if(eType == MSH_QUA_4)
           elements[3][reg].push_back(copy);
-        else if(eType == MSH_POLYG_)
+        else if(eType == MSH_POLYG_ || eType == MSH_POLYG_B)
           elements[8][reg].push_back(copy);
         assignPhysicals(GM, phys, reg, 2, physicals);
+        for(int i = 0; i < 2; i++)
+          if(copy->getDomain(i))
+            borders[1].insert(std::pair<MElement*, MElement*>(copy->getDomain(i), copy));
       }
 
       for (unsigned int i = nbL; i < lines.size(); i++){
@@ -832,7 +870,7 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
           }
         }
         MLine *lin;
-        if(p1 || p2) lin = new MLineBorder(mv[0], mv[1], p1, p2, ++numEle, ePart);
+        if(p1 || p2) lin = new MLineBorder(mv[0], mv[1], ++numEle, ePart, p1, p2);
         else lin = new MLine(mv[0], mv[1], ++numEle, ePart);
         int lsL = lines[i]->lsTag();
         int c = elements[1].count(lsL);
@@ -842,10 +880,14 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
         std::vector<int> phys; phys.push_back(physTag);
         elements[1][reg].push_back(lin);
         assignPhysicals(GM, phys, reg, 1, physicals);
+        for(int i = 0; i < 2; i++)
+          if(lin->getDomain(i))
+            borders[0].insert(std::pair<MElement*, MElement*>(lin->getDomain(i), lin));
       }
     }
     break;
   case MSH_LIN_2 :
+  case MSH_LIN_B :
     {
       DI_Line L(e->getVertex(0)->x(), e->getVertex(0)->y(), e->getVertex(0)->z(),
                 e->getVertex(1)->x(), e->getVertex(1)->y(), e->getVertex(1)->z());
@@ -853,6 +895,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
         for (unsigned int i = nbL; i < lines.size(); i++){
           MVertex *mv[2] = {NULL, NULL};
           for(int j = 0; j < 2; j++){
@@ -872,13 +915,20 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
               else mv[j] = it->second;
             }
           }
-          MLine *ml = new MLine(mv[0], mv[1], ++numEle, ePart);
+          MLine *ml;
+          if(eType != MSH_LIN_B) ml = new MLine(mv[0], mv[1], ++numEle, ePart);
+          else ml = new MLineBorder(mv[0], mv[1], ++numEle, ePart,
+                                    copy->getDomain(0), copy->getDomain(1));
           int reg = getElementaryTag(lines[i]->lsTag(), elementary, newElemTags[1]);
           std::vector<int> phys;
           getPhysicalTag(lines[i]->lsTag(), gePhysicals, phys, newPhysTags[1]);
           elements[1][reg].push_back(ml);
           assignPhysicals(GM, phys, reg, 1, physicals);
+          for(int i = 0; i < 2; i++)
+            if(ml->getDomain(i))
+              borders[0].insert(std::pair<MElement*, MElement*>(ml->getDomain(i), ml));
         }
+        delete copy;
       }
       else { // no cut
         int reg = getElementaryTag(lines[nbL]->lsTag(), elementary, newElemTags[1]);
@@ -886,6 +936,9 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
         getPhysicalTag(lines[nbL]->lsTag(), gePhysicals, phys, newPhysTags[1]);
         elements[1][reg].push_back(copy);
         assignPhysicals(GM, phys, reg, 1, physicals);
+        for(int i = 0; i < 2; i++)
+          if(copy->getDomain(i))
+            borders[0].insert(std::pair<MElement*, MElement*>(copy->getDomain(i), copy));
       }
     }
     break;
@@ -912,7 +965,7 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
   delete [] nodeLs;
 }
 
-#endif
+#endif //HAVE_DINTEGRATION
 
 GModel *buildCutMesh(GModel *gm, gLevelset *ls,
                      std::map<int, std::vector<MElement*> > elements[10],
@@ -933,6 +986,7 @@ GModel *buildCutMesh(GModel *gm, gLevelset *ls,
   int numVert = gm->indexMeshVertices(true);
   int nbLs = (cutElem) ? primitives.size() : 1;
   fullMatrix<double> verticesLs(numVert + 1, nbLs);
+  //compute and store levelset values
   for(unsigned int i = 0; i < gmEntities.size(); i++) {
     for(unsigned int j = 0; j < gmEntities[i]->getNumMeshVertices(); j++) {
       MVertex *vi = gmEntities[i]->getMeshVertex(j);
@@ -944,21 +998,25 @@ GModel *buildCutMesh(GModel *gm, gLevelset *ls,
     }
   }
 
-  std::map<int, int> newElemTags[4];
-  std::map<int, int> newPhysTags[4];
+  std::map<int, int> newElemTags[4]; //map<oldElementary,newElementary>[dim]
+  std::map<int, int> newPhysTags[4]; //map<oldPhysical,newPhysical>[dim]
   for(int d = 0; d < 4; d++){
-    newElemTags[d][0] = gm->getMaxElementaryNumber(d);
-    newPhysTags[d][0] = gm->getMaxPhysicalNumber(d);
+    newElemTags[d][0] = gm->getMaxElementaryNumber(d); //max value at [dim][0]
+    newPhysTags[d][0] = gm->getMaxPhysicalNumber(d); //max value at [dim][0]
   }
-  int numEle = gm->getNumMeshElements();
 
+  int numEle = 0; //element number increment
+  std::map<MElement*, MElement*> newParents; //map<oldParent, newParent>
+  std::map<MElement*, MElement*> newDomains; //map<oldDomain, newDomain>
+
+  //SplitMesh
   if(!cutElem) {
     for(unsigned int i = 0; i < gmEntities.size(); i++) {
       for(unsigned int j = 0; j < gmEntities[i]->getNumMeshElements(); j++) {
         MElement *e = gmEntities[i]->getMeshElement(j);
         e->setVolumePositive();
-        elementSplitMesh(e, verticesLs, gmEntities[i], gm, numEle, vertexMap,
-                         elements, physicals, newElemTags, newPhysTags);
+        elementSplitMesh(e, verticesLs, gmEntities[i], gm, numEle, vertexMap, newParents,
+                         newDomains, elements, physicals, newElemTags, newPhysTags);
         cutGM->getMeshPartitions().insert(e->getPartition());
       }
     }
@@ -966,8 +1024,9 @@ GModel *buildCutMesh(GModel *gm, gLevelset *ls,
   }
 
   newVerticesContainer newVertices;
-  std::map<int, int> borderElemTags[2];
-  std::map<int, int> borderPhysTags[2];
+  std::map<int, int> borderElemTags[2]; //map<lsTag,elementary>[line=0,surface=1]
+  std::map<int, int> borderPhysTags[2]; //map<lstag,physical>[line=0,surface=1]
+  std::multimap<MElement*, MElement*> borders[2]; //multimap<domain,border>[polg=0,polyh=1]
   DI_Point::Container cp;
   std::vector<DI_Line *> lines;
   std::vector<DI_Triangle *> triangles;
@@ -980,9 +1039,9 @@ GModel *buildCutMesh(GModel *gm, gLevelset *ls,
     for(unsigned int j = 0; j < gmEntities[i]->getNumMeshElements(); j++) {
       MElement *e = gmEntities[i]->getMeshElement(j);
       e->setVolumePositive();
-      elementCutMesh(e, RPN, verticesLs, gmEntities[i], gm, numEle, vertexMap, newVertices,
-                     elements, physicals, newElemTags, newPhysTags, borderElemTags, borderPhysTags,
-                     cp, lines, triangles, quads, tetras, hexas);
+      elementCutMesh(e, RPN, verticesLs, gmEntities[i], gm, numEle, vertexMap, newVertices, newParents,
+                     newDomains, borders, elements, physicals, newElemTags, newPhysTags,
+                     borderElemTags, borderPhysTags, cp, lines, triangles, quads, tetras, hexas);
       cutGM->getMeshPartitions().insert(e->getPartition());
     }
     for(DI_Point::Container::iterator it = cp.begin(); it != cp.end(); it++) delete *it;
diff --git a/Geo/MElementCut.h b/Geo/MElementCut.h
index 6e5884ca12184de960b3c4b4680d716d51ba3069..174e19fa245b620b846a26e1b5da691746e7bafd 100644
--- a/Geo/MElementCut.h
+++ b/Geo/MElementCut.h
@@ -178,7 +178,7 @@ class MPolygon : public MElement {
     }
     _initVertices();
   }
-  ~MPolygon() 
+  ~MPolygon()
   {
     if(_owner)
       delete _orig;
@@ -270,21 +270,73 @@ class MPolygon : public MElement {
 
 class MTriangleBorder : public MTriangle {
  protected:
-  MPolyhedron* _domains[2];
+  MElement* _domains[2];
  public:
-  MTriangleBorder(MVertex *v0, MVertex *v1, MVertex *v2,
-                  MPolyhedron* d1, MPolyhedron* d2, int num=0, int part=0)
+  MTriangleBorder(MVertex *v0, MVertex *v1, MVertex *v2, int num = 0, int part = 0,
+                  MElement* d1 = NULL, MElement* d2 = NULL)
     : MTriangle(v0, v1, v2, num, part)
   {
     _domains[0] = d1; _domains[1] = d2;
   }
+  MTriangleBorder(std::vector<MVertex*> v, int num = 0, int part = 0,
+                  MElement* d1 = NULL, MElement* d2 = NULL)
+    : MTriangle(v, num, part)
+  {
+    _domains[0] = d1; _domains[1] = d2;
+  }
   ~MTriangleBorder() {}
-  MPolyhedron* getDomain(int i) const { return _domains[i]; }
+  virtual MElement* getDomain(int i) const { return _domains[i]; }
+  virtual void setDomain (MElement *d, int i) { _domains[i] = d; }
+  virtual MElement *getParent() const {
+    if(_domains[0]) return _domains[0]->getParent();
+    if(_domains[1]) return _domains[1]->getParent();
+    return NULL;
+  }
+  virtual int getTypeForMSH() const { return MSH_TRI_B; }
+  virtual const polynomialBasis* getFunctionSpace(int order=-1) const 
+  {
+    return getParent()->getFunctionSpace(order);
+  }
+  virtual void getShapeFunctions(double u, double v, double w, double s[], int o)
+  {
+    getParent()->getShapeFunctions(u, v, w, s, o);
+  }
+  virtual void getGradShapeFunctions(double u, double v, double w, double s[][3], int o)
+  {
+    getParent()->getGradShapeFunctions(u, v, w, s, o);
+  }
+  virtual void xyz2uvw(double xyz[3], double uvw[3])
+  {
+    getParent()->xyz2uvw(xyz,uvw);
+  }
+  virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts);
+};
+
+class MPolygonBorder : public MPolygon {
+ protected:
+  MElement* _domains[2];
+ public:
+  MPolygonBorder(std::vector<MTriangle*> v, int num = 0, int part = 0,
+                  MElement* d1 = NULL, MElement* d2 = NULL)
+    : MPolygon(v, num, part)
+  {
+    _domains[0] = d1; _domains[1] = d2;
+  }
+  MPolygonBorder(std::vector<MVertex*> v, int num = 0, int part = 0,
+                  MElement* d1 = NULL, MElement* d2 = NULL)
+    : MPolygon(v, num, part)
+  {
+    _domains[0] = d1; _domains[1] = d2;
+  }
+  ~MPolygonBorder() {}
+  virtual MElement* getDomain(int i) const { return _domains[i]; }
+  virtual void setDomain (MElement *d, int i) { _domains[i] = d; }
   virtual MElement *getParent() const {
     if(_domains[0]) return _domains[0]->getParent();
     if(_domains[1]) return _domains[1]->getParent();
     return NULL;
   }
+  virtual int getTypeForMSH() const { return MSH_POLYG_B; }
   virtual const polynomialBasis* getFunctionSpace(int order=-1) const 
   {
     return getParent()->getFunctionSpace(order);
@@ -306,21 +358,29 @@ class MTriangleBorder : public MTriangle {
 
 class MLineBorder : public MLine {
  protected:
-  MPolygon* _domains[2];
+  MElement* _domains[2];
  public:
-  MLineBorder(MVertex *v0, MVertex *v1,
-              MPolygon* d1, MPolygon* d2, int num=0, int part=0)
+  MLineBorder(MVertex *v0, MVertex *v1, int num = 0, int part = 0,
+              MElement* d1 = NULL, MElement* d2 = NULL)
     : MLine(v0, v1, num, part)
   {
     _domains[0] = d1; _domains[1] = d2;
   }
+  MLineBorder(std::vector<MVertex*> v, int num = 0, int part = 0,
+              MElement* d1 = NULL, MElement* d2 = NULL)
+    : MLine(v, num, part)
+  {
+    _domains[0] = d1; _domains[1] = d2;
+  }
   ~MLineBorder() {}
-  MPolygon* getDomain(int i) const { return _domains[i]; }
+  virtual MElement* getDomain(int i) const { return _domains[i]; }
+  virtual void setDomain (MElement *d, int i) { _domains[i] = d; }
   virtual MElement *getParent() const {
     if(_domains[0]) return _domains[0]->getParent();
     if(_domains[1]) return _domains[1]->getParent();
     return NULL;
   }
+  virtual int getTypeForMSH() const { return MSH_LIN_B; }
   virtual const polynomialBasis* getFunctionSpace(int order=-1) const 
   {
     return getParent()->getFunctionSpace(order);