diff --git a/Geo/MElementCut.cpp b/Geo/MElementCut.cpp
index 7e20a17989dd748f41b7b7d5d90f1697953fd4d1..cd129fa7975529f485926e65b20082ec38712b92 100644
--- a/Geo/MElementCut.cpp
+++ b/Geo/MElementCut.cpp
@@ -452,30 +452,43 @@ static void assignPhysicals(GModel *GM, std::vector<int> gePhysicals, int reg, i
   }
 }
 
-static int getElementaryTag(double ls, int elementary, std::map<int, int> &newtags)
+static int getElementaryTag(int lsTag, int elementary, std::map<int, int> &newElemTags)
 {
-  if(ls < 0){
-    if(newtags.count(elementary))
-      return newtags[elementary];
+  if(lsTag < 0){
+    if(newElemTags.count(elementary))
+      return newElemTags[elementary];
     else{
-      int reg = ++newtags[0];
-      newtags[elementary] = reg;
+      int reg = ++newElemTags[0];
+      newElemTags[elementary] = reg;
       return reg;
     }
   }
   return elementary;
 }
+static void getPhysicalTag(int lsTag, const std::vector<int> &physicals, std::vector<int> &phys2, std::map<int, int> &newPhysTags)
+{
+  phys2.clear();
+  for(unsigned int i = 0; i < physicals.size(); i++){
+    int phys = physicals[i];
+    if(lsTag < 0){
+      if(!newPhysTags.count(phys))
+        newPhysTags[phys] = ++newPhysTags[0];
+      phys = newPhysTags[phys];
+    }
+    phys2.push_back(phys);
+  }
+}
 
-static int getBorderTag(int lsTag, int count, int &elementaryMax, std::map<int, int> &borderTags)
+static int getBorderTag(int lsTag, int count, int &maxTag, std::map<int, int> &borderTags)
 {
   if(borderTags.count(lsTag))
     return borderTags[lsTag];
   if(count) {
-    int reg = ++elementaryMax;
-    borderTags[lsTag] = reg;
-    return reg;
+    int tag = ++maxTag;
+    borderTags[lsTag] = tag;
+    return tag;
   }
-  elementaryMax = std::max(elementaryMax, lsTag);
+  maxTag = std::max(maxTag, lsTag);
   borderTags[lsTag] = lsTag;
   return lsTag;
 }
@@ -486,8 +499,10 @@ static void elementCutMesh(MElement *e, gLevelset *ls,
                            std::vector<MVertex*> &newVertices,
                            std::map<int, std::vector<MElement*> > elements[10],
                            std::map<int, std::map<int, std::string> > physicals[4],
-                           std::map<int, int> borderTags[2],
-                           std::map<int, int> newtags[4],
+                           std::map<int, int> newElemTags[4],
+                           std::map<int, int> newPhysTags[4],
+                           std::map<int, int> borderElemTags[2],
+                           std::map<int, int> borderPhysTags[2],
                            std::vector<DI_CuttingPoint> &cp,
                            std::vector<DI_Line> &lines,
                            std::vector<DI_Triangle> &triangles,
@@ -676,9 +691,11 @@ static void elementCutMesh(MElement *e, gLevelset *ls,
         }
         if(poly[0].size()) {
           p1 = new MPolyhedron(poly[0], ++numEle, ePart, true, copy);
-          int reg = getElementaryTag(-1, elementary, newtags[3]);
+          int reg = getElementaryTag(-1, elementary, newElemTags[3]);
+          std::vector<int> phys;
+          getPhysicalTag(-1, gePhysicals, phys, newPhysTags[3]);
           elements[9][reg].push_back(p1);
-          assignPhysicals(GM, gePhysicals, reg, 3, physicals);
+          assignPhysicals(GM, phys, reg, 3, physicals);
         }
         if(poly[1].size()) {
           p2 = new MPolyhedron(poly[1], ++numEle, ePart, false, copy);
@@ -687,7 +704,9 @@ static void elementCutMesh(MElement *e, gLevelset *ls,
         }
       }
       else { // no cut
-        int reg = getElementaryTag(tetras[nbTe].lsTag(), elementary, newtags[3]);
+        int reg = getElementaryTag(tetras[nbTe].lsTag(), elementary, newElemTags[3]);
+        std::vector<int> phys;
+        getPhysicalTag(tetras[nbTe].lsTag(), gePhysicals, phys, newPhysTags[3]);
         if(eType == MSH_TET_4)
           elements[4][reg].push_back(copy);
         else if(eType == MSH_HEX_8)
@@ -698,7 +717,7 @@ static void elementCutMesh(MElement *e, gLevelset *ls,
           elements[7][reg].push_back(copy);
         else if(eType == MSH_POLYH_)
           elements[9][reg].push_back(copy);
-        assignPhysicals(GM, gePhysicals, reg, 3, physicals);
+        assignPhysicals(GM, phys, reg, 3, physicals);
       }
 
       for (unsigned int i = nbTr; i < triangles.size(); i++){
@@ -732,9 +751,11 @@ static void elementCutMesh(MElement *e, gLevelset *ls,
         int lsT = triangles[i].lsTag();
         int c = elements[2].count(lsT) + elements[3].count(lsT);
         // suppose that the surfaces have been cut before the volumes!
-        int reg = getBorderTag(lsT, c, newtags[2][0], borderTags[1]);
+        int reg = getBorderTag(lsT, c, newElemTags[2][0], borderElemTags[1]);
+        int physTag = getBorderTag(lsT, c, newPhysTags[2][0], borderPhysTags[1]);
+        std::vector<int> phys; phys.push_back(physTag);
         elements[2][reg].push_back(tri);
-        assignPhysicals(GM, gePhysicals, reg, 2, physicals);
+        assignPhysicals(GM, phys, reg, 2, physicals);
       }
     }
     break;
@@ -812,9 +833,11 @@ static void elementCutMesh(MElement *e, gLevelset *ls,
         }
         if(poly[0].size()) {
           p1 = new MPolygon(poly[0], ++numEle, ePart, true, copy);
-          int reg = getElementaryTag(-1, elementary, newtags[2]);
+          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, gePhysicals, reg, 2, physicals);
+          assignPhysicals(GM, phys, reg, 2, physicals);
         }
         if(poly[1].size()) {
           p2 = new MPolygon(poly[1], ++numEle, ePart, false, copy);
@@ -823,14 +846,16 @@ static void elementCutMesh(MElement *e, gLevelset *ls,
         }
       }
       else { // no cut
-        int reg = getElementaryTag(triangles[nbTr].lsTag(), elementary, newtags[2]);
+        int reg = getElementaryTag(triangles[nbTr].lsTag(), elementary, newElemTags[2]);
+        std::vector<int> phys;
+        getPhysicalTag(triangles[nbTr].lsTag(), gePhysicals, phys, newPhysTags[2]);
         if(eType == MSH_TRI_3)
           elements[2][reg].push_back(copy);
         else if(eType == MSH_QUA_4)
           elements[3][reg].push_back(copy);
         else if(eType == MSH_POLYG_)
           elements[8][reg].push_back(copy);
-        assignPhysicals(GM, gePhysicals, reg, 2, physicals);
+        assignPhysicals(GM, phys, reg, 2, physicals);
       }
 
       for (unsigned int i = nbL; i < lines.size(); i++){
@@ -861,11 +886,14 @@ static void elementCutMesh(MElement *e, gLevelset *ls,
         MLine *lin;
         if(p1 || p2) lin = new MLineBorder(mv[0], mv[1], p1, p2, ++numEle, ePart);
         else lin = new MLine(mv[0], mv[1], ++numEle, ePart);
-        int c = elements[1].count(lines[i].lsTag());
+        int lsL = lines[i].lsTag();
+        int c = elements[1].count(lsL);
         // suppose that the lines have been cut before the surfaces!
-        int reg = getBorderTag(lines[i].lsTag(), c, newtags[1][0], borderTags[0]);
+        int reg = getBorderTag(lsL, c, newElemTags[1][0], borderElemTags[0]);
+        int physTag = getBorderTag(lsL, c, newPhysTags[1][0], borderPhysTags[0]);
+        std::vector<int> phys; phys.push_back(physTag);
         elements[1][reg].push_back(lin);
-        assignPhysicals(GM, gePhysicals, reg, 1, physicals);
+        assignPhysicals(GM, phys, reg, 1, physicals);
       }
     }
     break;
@@ -902,15 +930,19 @@ static void elementCutMesh(MElement *e, gLevelset *ls,
             }
           }
           MLine *ml = new MLine(mv[0], mv[1], ++numEle, ePart);
-          int reg = getElementaryTag(lines[i].lsTag(), elementary, newtags[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, gePhysicals, reg, 1, physicals);
+          assignPhysicals(GM, phys, reg, 1, physicals);
         }
       }
       else { // no cut
-        int reg = getElementaryTag(lines[nbL].lsTag(), elementary, newtags[1]);
+        int reg = getElementaryTag(lines[nbL].lsTag(), elementary, newElemTags[1]);
+        std::vector<int> phys;
+        getPhysicalTag(lines[nbL].lsTag(), gePhysicals, phys, newPhysTags[1]);
         elements[1][reg].push_back(copy);
-        assignPhysicals(GM, gePhysicals, reg, 1, physicals);
+        assignPhysicals(GM, phys, reg, 1, physicals);
       }
     }
     break;
@@ -918,9 +950,11 @@ static void elementCutMesh(MElement *e, gLevelset *ls,
     {
       DI_Point P(e->getVertex(0)->x(), e->getVertex(0)->y(), e->getVertex(0)->z());
       P.computeLs(*ls);
-      int reg = getElementaryTag(P.lsTag(), elementary, newtags[0]);
+      int reg = getElementaryTag(P.lsTag(), elementary, newElemTags[0]);
+      std::vector<int> phys;
+      getPhysicalTag(P.lsTag(), gePhysicals, phys, newPhysTags[0]);
       elements[0][reg].push_back(copy);
-      assignPhysicals(GM, gePhysicals, reg, 0, physicals);
+      assignPhysicals(GM, phys, reg, 0, physicals);
     }
     break;
   default :
@@ -946,11 +980,14 @@ GModel *buildCutMesh(GModel *gm, gLevelset *ls,
   gm->getEntities(gmEntities);
   int numEle = gm->getNumMeshElements();
 
-  std::map<int, int> newtags[4];
-  for(int i = 0; i < 4; i++)
-    newtags[i][0] = gm->getMaxElementaryNumber(i);
-  std::map<int, int> borderTags[2];
-
+  std::map<int, int> newElemTags[4];
+  std::map<int, int> newPhysTags[4];
+  for(int d = 0; d < 4; d++){
+    newElemTags[d][0] = gm->getMaxElementaryNumber(d);
+    newPhysTags[d][0] = gm->getMaxPhysicalNumber(d);
+  }
+  std::map<int, int> borderElemTags[2];
+  std::map<int, int> borderPhysTags[2];
 
   std::vector<const gLevelset *> primitives;
   ls->getPrimitives(primitives);
@@ -975,7 +1012,8 @@ GModel *buildCutMesh(GModel *gm, gLevelset *ls,
       MElement *e = gmEntities[i]->getMeshElement(j);
       e->setVolumePositive();
       elementCutMesh(e, ls, verticesLs, gmEntities[i], gm, numEle, vertexMap, newVertices,
-                     elements, physicals, borderTags, newtags, cp, lines, triangles, quads, tetras, hexas);
+                     elements, physicals, newElemTags, newPhysTags, borderElemTags, borderPhysTags,
+                     cp, lines, triangles, quads, tetras, hexas);
       cutGM->getMeshPartitions().insert(e->getPartition());
     }
     cp.clear(); lines.clear(); triangles.clear(); quads.clear(); tetras.clear(); hexas.clear();
diff --git a/contrib/DiscreteIntegration/Integration3D.cpp b/contrib/DiscreteIntegration/Integration3D.cpp
index 338dca15e41458404157309a52eb6fb1b6d5b4c8..0ca3b33943cc96d75113f0ea17d9a672d918c9e2 100644
--- a/contrib/DiscreteIntegration/Integration3D.cpp
+++ b/contrib/DiscreteIntegration/Integration3D.cpp
@@ -189,18 +189,14 @@ int commonV (int &s11, int &s12, int &s21, int &s22) {
   return 0;
 }
 
-double adjustLs (double ls) {
-  return fabs(ls) < ZERO_LS_TOL ? 0. : ls;
+inline double adjustLs (double ls) {
+  return (fabs(ls) < ZERO_LS_TOL) ? 0. : ls;
 }
-bool isCrossed (double ls1, double ls2) {
+inline bool isCrossed (const DI_Point &p1, const DI_Point &p2) {
+  double ls1 = p1.ls(), ls2 = p2.ls();
   if(ls1 * ls2 >= 0.) return false;
-  if (fabs(ls1) < ZERO_LS_TOL || fabs(ls2) < ZERO_LS_TOL) return false;
   return true;
 }
-bool isCrossed (const DI_Point &p1, const DI_Point &p2) {
-  double v1 = p1.ls(), v2 = p2.ls();
-  return isCrossed (v1, v2);
-}
 
 // return the index of the point with minimum x,y and z
 int minimum(double *x, double *y, double *z, const int num) {
@@ -523,14 +519,14 @@ void DI_Point::chooseLs (const gLevelset *Lsi) {
   double ls1 = Ls[Ls.size() - 2], ls2 = Ls[Ls.size() - 1];
   double ls = Lsi->choose(ls1, ls2);
   Ls.pop_back(); Ls.pop_back();
-  Ls.push_back(ls);
+  addLs(ls);
 }
 void DI_Point::computeLs (const DI_Element *e, const std::vector<const gLevelset*> RPNi) {
   int prim = 0; Ls.clear();
   if(e->sizeLs() == 0) return;
   for(int l = 0; l < (int)RPNi.size(); l++) {
     if (RPNi[l]->isPrimitive())
-      Ls.push_back(e->evalLs(x_, y_, z_, prim++));
+      addLs(e->evalLs(x_, y_, z_, prim++));
     else
       chooseLs(RPNi[l]);
   }
@@ -548,24 +544,35 @@ void DI_IntegrationPoint::computeLs (const DI_Element *e, const std::vector<cons
   int prim = 0; std::vector<double> Ls;
   for(int l = 0; l < (int)RPN.size(); l++) {
     if(RPN[l]->isPrimitive())
-      Ls.push_back(e->evalLs(x_, y_, z_, prim++));
+      Ls.push_back(adjustLs(e->evalLs(x_, y_, z_, prim++)));
     else {
       double ls1 = Ls[Ls.size() - 2], ls2 = Ls[Ls.size() - 1];
       double ls = RPN[l]->choose(ls1, ls2);
       Ls.pop_back(); Ls.pop_back();
-      Ls.push_back(ls);
+      Ls.push_back(adjustLs(ls));
     }
   }
   setLs(Ls.back());
 }
 
 // DI_CuttingPoint methods ------------------------------------------------------------------------
+DI_CuttingPoint::DI_CuttingPoint(const DI_Point &pt) : x_(pt.x()), y_(pt.y()), z_(pt.z()),
+                                                       xl_(pt.x()), yl_(pt.y()), zl_(pt.z()) {
+  for(int i = 0; i < pt.sizeLs(); i++)
+    addLs(pt.ls(i));
+}
+void DI_CuttingPoint::addLs (const double ls) {
+  Ls.push_back(adjustLs(ls));
+}
+void DI_CuttingPoint::addLs (const DI_Element *e) {
+  addLs(e->evalLs(x_, y_, z_));
+}
 void DI_CuttingPoint::chooseLs (const gLevelset *Lsi) {
   if(Ls.size() < 2) return;
   double ls1 = Ls[Ls.size() - 2], ls2 = Ls[Ls.size() - 1];
   double ls = Lsi->choose(ls1, ls2);
   Ls.pop_back(); Ls.pop_back();
-  Ls.push_back(ls);
+  addLs(ls);
 }
 bool DI_CuttingPoint::equal (const DI_CuttingPoint &p) const {
   return (fabs(x() - p.x()) < EQUALITY_TOL && fabs(y() - p.y()) < EQUALITY_TOL && fabs(z() - p.z()) < EQUALITY_TOL);
@@ -622,6 +629,9 @@ DI_Element & DI_Element::operator= (const DI_Element &rhs){
   return *this;
 }
 void DI_Element::setPolynomialOrder (int o) {
+  if(polOrder_ == o) return;
+  for(int i = 0; i < nbMid(); i++)
+    delete mid_[i];
   polOrder_ = o;
   switch (o) {
   case 1 :
@@ -642,6 +652,7 @@ void DI_Element::setPolynomialOrder (int o) {
   }
 }
 void DI_Element::setPolynomialOrder (int o, const DI_Element *e, const std::vector<const gLevelset *> RPNi) {
+  if(polOrder_ == o) return;
   for(int i = 0; i < nbMid(); i++)
     delete mid_[i];
   polOrder_ = o;
@@ -669,10 +680,6 @@ void DI_Element::addLs (const double *ls) {
   for(int i = 0; i < nbMid(); i++)
     mid_[i]->addLs(ls[nbVert()+i]);
 }
-void DI_Element::addLs (int primTag, std::map<int, double> nodeLs[8]) {
-  for(int i = 0; i < nbVert(); i++)
-    pts_[i]->addLs(nodeLs[i][primTag]);
-}
 void DI_Element::addLs (const DI_Element *e) {
   if(e->sizeLs() < 1) return;
   for(int i = 0; i < nbVert(); i++)
@@ -698,6 +705,24 @@ void DI_Element::addLs (const DI_Element *e, const gLevelset &Ls) {
     mid_[j]->addLs(ls);
   }
 }
+void DI_Element::addLs (const DI_Element *e, const gLevelset &Ls, std::map<int, double> nodeLs[]) {
+  int primTag = Ls.getTag();
+  if(!nodeLs || !nodeLs[0].count(primTag)) {
+    addLs(e, Ls);
+    return;
+  }
+  for(int i = 0; i < nbVert(); i++)
+    pts_[i]->addLs(nodeLs[i][primTag]);
+  for(int j = 0; j < nbMid(); ++j) {
+    std::vector<int> s(nbVert()); int n;
+    e->midV(j, &s[0], n);
+    double xc = 0, yc = 0, zc = 0;
+    for(int k = 0; k < n; k++){
+      xc += e->x(s[k]); yc += e->y(s[k]); zc += e->z(s[k]); }
+    double ls = Ls(xc/n, yc/n, zc/n);
+    mid_[j]->addLs(ls);
+  }
+}
 void DI_Element::chooseLs (const gLevelset *Lsi) {
   if(sizeLs() < 2)
     printf("chooseLs with element ls size < 2 : typeEl=%d\n", type());
@@ -708,20 +733,21 @@ void DI_Element::chooseLs (const gLevelset *Lsi) {
 }
 void DI_Element::clearLs() {
   for(int i = 0; i < nbVert(); i++)
-    (pts_[i]->Ls).clear();
+    pts_[i]->clearLs();
   for(int i = 0; i < nbMid(); i++)
-    (mid_[i]->Ls).clear();
+    mid_[i]->clearLs();
 }
 bool DI_Element::addQuadEdge (int edge, DI_Point *xm,
                               const DI_Element *e, const std::vector<const gLevelset *> RPNi) {
-  /*if(edge >= nbEdg()) {printf("wrong number (%d) for quadratic edge for a ", edge); print(); return false;}
+  if(edge >= nbEdg()) {printf("wrong number (%d) for quadratic edge for a ", edge); print(); return false;}
   int s1, s2; vert(edge, s1, s2);
-  bool quad0 = isQuad();
-  if(!quad0) quad(e, RPNi);
+  int order0 = getPolynomialOrder();
+  if(order0 == 1) setPolynomialOrder(2, e, RPNi);
   double dist = distance(mid(edge), *xm);
   double sideLength = distance(pt(s1), pt(s2));
   if (dist / sideLength < 1.e-5) {
-    if(!quad0) lin(); printf("dist=%.20f, sideLength=%g, d/sL=%g => do not add quad edge\n", dist, sideLength, dist/sideLength);
+    if(order0 == 1) setPolynomialOrder(1);
+    printf("dist=%.20f, sideLength=%g, d/sL=%g => do not add quad edge\n", dist, sideLength, dist/sideLength);
     return true; // do not add the quadratic edge if xm is very close from the middle of the edge
   }
   DI_Point *p0 = mid_[edge];
@@ -729,12 +755,12 @@ bool DI_Element::addQuadEdge (int edge, DI_Point *xm,
   // check if the quadratic edge will produce a twist in the element (detJ<0)
   if(!testDetJ()){
     // reinitialize quad edges if the element was not quad at the begining
-    if(!quad0) lin();
+    if(order0 == 1) setPolynomialOrder(1);
     else mid_[edge]->move(p0->x(), p0->y(), p0->z());//mid_[edge] = p0;
     printf("detJ<0 when trying to add a quadratic edge in "); print();
     return false;
   }
-  computeIntegral();*/
+  computeIntegral();
   return true;
 }
 bool DI_Element::contain (const DI_Point &p) const {
@@ -863,9 +889,7 @@ double DI_Element::evalLs (const double u, const double v, const double w, int i
 }
 bool DI_Element::testDetJ() const {
   double detJ0 = detJ(x(0), y(0), z(0));
-  for(int i = 1; i < nbVert(); i++)
-    if(detJ0 * detJ(x(i), y(i), z(i)) < 0.) return false;
-  for(int i = nbVert(); i < nbVert() + nbMid(); i++)
+  for(int i = 1; i < nbVert() + nbMid(); i++)
     if(detJ0 * detJ(x(i), y(i), z(i)) < 0.) return false;
   return true;
 }
@@ -889,7 +913,7 @@ double DI_Element::detJ (const double u, const double v, const double w) const {
       J[2][0] += x(i) * s[i][2]; J[2][1] += y(i) * s[i][2]; J[2][2] += z(i) * s[i][2];
 //      delete [] s[i];
     }
-	delete [] s;
+    delete [] s;
     return det3(J[0][0], J[0][1], J[0][2], J[1][0], J[1][1], J[1][2], J[2][0], J[2][1], J[2][2]);
   case 2 :
     for(int i = 0; i < nbVert() + nbMid(); i++) {
@@ -909,6 +933,7 @@ double DI_Element::detJ (const double u, const double v, const double w) const {
     delete [] s;
     return sqrt(sq2(J[0][0]) + sq2(J[0][1]) + sq2(J[0][2])); // allways > 0 !!!!
   default :
+    delete [] s;
     return 1.;
   }
 }
@@ -1423,12 +1448,12 @@ void DI_Triangle::selfSplit (const DI_Element *e, const std::vector<const gLevel
                              std::vector<DI_Quad> &subQuads, std::vector<DI_Triangle> &subTriangles,
                              std::vector<DI_Line> &surfLines, std::vector<DI_CuttingPoint> &cuttingPoints) const
 {
-  bool quadT = false; // if true, use quadratic sub triangles
+  bool quadT = (e->getPolynomialOrder() == 2) ? true : false; // if true, use quadratic sub triangles
   int LStag = RPNi.back()->getTag();
 
   int nbZe = 0, ze[2];
   for(int i = 0; i < 3; i++)
-    if(fabs(pt(i).ls()) < ZERO_LS_TOL)
+    if(pt(i).isOnBorder())
       ze[nbZe++] = i;
   for(int i = 0; i < nbZe; i++)
     cuttingPoints.push_back(DI_CuttingPoint(pt(ze[i])));
@@ -1538,12 +1563,12 @@ void DI_Tetra::selfSplit (const DI_Element *e, const std::vector<const gLevelset
                        std::vector<DI_Tetra> &subTetras, std::vector<DI_Triangle> &surfTriangles,
                        std::vector<DI_CuttingPoint> &cuttingPoints, std::vector<DI_QualError> &QError) const
 {
-  bool quadT = false; // use of quadratic surf triangles and quadratic sub tetrahedra
+  bool quadT = (e->getPolynomialOrder() == 2) ? true : false; // use of quadratic surf triangles and quadratic sub tetrahedra
   int tag = RPNi.back()->getTag();
 
   int nbZe = 0, ze[3];
   for(int i = 0; i < 4; i++)
-    if(fabs(pt(i).ls()) < ZERO_LS_TOL)
+    if(pt(i).isOnBorder())
       ze[nbZe++] = i;
   for(int i = 0; i < nbZe; i++)
     cuttingPoints.push_back(DI_CuttingPoint(pt(ze[i]))); // !! we add these points several times => remove later
@@ -1972,8 +1997,7 @@ bool DI_Line::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
       const gLevelset *Lsi = RPN[l];
       RPNi.push_back(Lsi);
       if(Lsi->isPrimitive()) {
-        if(nodeLs && nodeLs[0].count(Lsi->getTag())) ll.addLs(Lsi->getTag(), nodeLs);
-        else ll.addLs(this, *Lsi);
+        ll.addLs(this, *Lsi, nodeLs);
         int nbSubLn = ll_subLines.size();
         int nbCP = ll_cp.size();
         for(int i = 0; i < nbSubLn; i++) ll_subLines[i].addLs(&ll);
@@ -1999,8 +2023,7 @@ bool DI_Line::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
       const gLevelset *Lsi = RPN[l];
       RPNi.push_back(Lsi);
       if(Lsi->isPrimitive()) {
-        if(nodeLs && nodeLs[0].count(Lsi->getTag())) ll.addLs(Lsi->getTag(), nodeLs);
-        else ll.addLs(this, *Lsi);
+        ll.addLs(this, *Lsi, nodeLs);
       }
     }
   }
@@ -2030,7 +2053,7 @@ void DI_Line::cut(const DI_Element *e, const std::vector<const gLevelset *> &RPN
   // check if the line is cut by the level set
   int on = 0, pos = 0, neg = 0, ze[2];
   for (int i = 0; i < 2; i++){
-    if(fabs(pt(i).ls()) < ZERO_LS_TOL) ze[on++] = i;
+    if(pt(i).isOnBorder()) ze[on++] = i;
     else if (pt(i).ls() > 0.) pos++;
     else neg++;
   }
@@ -2070,8 +2093,7 @@ bool DI_Triangle::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip
       const gLevelset *Lsi = RPN[l]; //printf("LS(0,0)=%g LS(1,1)=%g\n",(*Lsi)(0,0,0),(*Lsi)(1,1,0));
       RPNi.push_back(Lsi);
       if(Lsi->isPrimitive()) {
-        if(nodeLs && nodeLs[0].count(Lsi->getTag())) tt.addLs(Lsi->getTag(), nodeLs);
-        else tt.addLs(this, *Lsi);
+        tt.addLs(this, *Lsi, nodeLs);
         int nbSubQ = tt_subQuads.size(), nbSubQ1 = nbSubQ;
         int nbSubTr = tt_subTriangles.size(), nbSubTr1 = nbSubTr;
         int nbSurfLn = tt_surfLines.size(), nbSurfLn1 = nbSurfLn;
@@ -2081,7 +2103,7 @@ bool DI_Triangle::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip
         for(int i = 0; i < nbSurfLn; i++) tt_surfLines[i].addLs(&tt);
         for(int i = 0; i < nbCP; i++) tt_cp[i].addLs(&tt);
         int ze[3], cz = 0;
-        for (int i = 0; i < 3; i++) if(fabs(tt.ls(i)) < ZERO_LS_TOL) ze[cz++] = i;
+        for (int i = 0; i < 3; i++) if(tt.pt(i).isOnBorder()) ze[cz++] = i;
 
         for(int q = 0; q < nbSubQ; q++) {
           nbSubQ1 = tt_subQuads.size();
@@ -2149,36 +2171,11 @@ bool DI_Triangle::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip
       const gLevelset *Lsi = RPN[l];
       RPNi.push_back(Lsi);
       if(Lsi->isPrimitive()) {
-        if(nodeLs && nodeLs[0].count(Lsi->getTag())) tt.addLs(Lsi->getTag(), nodeLs);
-        else tt.addLs(this, *Lsi);
+        tt.addLs(this, *Lsi, nodeLs);
       }
     }
   }
 
-  //if !changeSign => no cut => clear vectors / triangles.push_back(tt)
-  /*if(tt_cp.size() == 1) {
-    tt_cp.clear();
-  }
-  if(tt_cp.size() > 1) {
-    bool changeSign = false;
-    double sign0 = tt_cp[0].ls();
-    for(int i = 1; i < (int)tt_cp.size(); i++)
-      if(sign0*tt_cp[i].ls() <= 0) {changeSign = true; break;}
-    if(!changeSign) { //print();
-      tt_subTriangles.clear();
-      tt_subQuads.clear();
-      tt_surfLines.clear();
-      tt_cp.clear();
-      DI_Point vP[3];
-      for(int i = 0; i < 3; i++) {
-        double ls = Ls(x(i), y(i), z(i));
-        vP[i] = DI_Point(tt.x(i), tt.y(i), tt.z(i), ls);
-      }
-      DI_Triangle trt(vP[0], vP[1], vP[2]); // reference triangle
-      tt_subTriangles.push_back(trt);
-    }
-  }*/
-
   for(int q = 0; q < (int)tt_subQuads.size(); q++) {
     tt_subQuads[q].computeLsTagDom(&tt, RPN);
     DI_Quad tt_subQ = tt_subQuads[q];
@@ -2220,7 +2217,7 @@ void DI_Triangle::cut (const DI_Element *e, const std::vector<const gLevelset *>
   // check if the triangle is cut by the level set
   int on = 0, pos = 0, neg = 0, ze[3];
   for (int i = 0; i < 3; i++){
-    if(fabs(pt(i).ls()) < ZERO_LS_TOL) ze[on++] = i;
+    if(pt(i).isOnBorder()) ze[on++] = i;
     else if (pt(i).ls() > 0.) pos++;
     else neg++;
   }
@@ -2264,8 +2261,7 @@ bool DI_Quad::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
       const gLevelset *Lsi = RPN[l];
       RPNi.push_back(Lsi);
       if(Lsi->isPrimitive()) {
-        if(nodeLs && nodeLs[0].count(Lsi->getTag())) qq.addLs(Lsi->getTag(), nodeLs);
-        else qq.addLs(this, *Lsi);
+        qq.addLs(this, *Lsi, nodeLs);
         int nbSubQ = qq_subQuads.size(), nbSubQ1 = nbSubQ;
         int nbSubTr = qq_subTriangles.size(), nbSubTr1 = nbSubTr;
         int nbSurfLn = qq_surfLines.size(), nbSurfLn1 = nbSurfLn;
@@ -2276,7 +2272,7 @@ bool DI_Quad::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
         for(int i = 0; i < nbCP; i++) qq_cp[i].addLs(&qq);
         int pos = 0, neg = 0, ze[2], cz = 0;
         for (int i = 0; i < 4; i++){
-          if(fabs(qq.ls(i)) < ZERO_LS_TOL) ze[cz++] = i;
+          if(qq.pt(i).isOnBorder()) ze[cz++] = i;
           else if (qq.ls(i) > 0.) pos++;
           else neg++;
         }
@@ -2347,33 +2343,11 @@ bool DI_Quad::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
       const gLevelset *Lsi = RPN[l];
       RPNi.push_back(Lsi);
       if(Lsi->isPrimitive()) {
-        if(nodeLs && nodeLs[0].count(Lsi->getTag())) qq.addLs(Lsi->getTag(), nodeLs);
-        else qq.addLs(this, *Lsi);
+        qq.addLs(this, *Lsi, nodeLs);
       }
     }
   }
 
-  /*//if !changeSign => clear vectors / quads.push_back(qq)
-  if(qq_cp.size() > 1) {
-    bool changeSign = false;
-    double sign0 = qq_cp[0].ls();
-    for(int i = 1; i < (int)qq_cp.size(); i++)
-      if(sign0 * qq_cp[i].ls() <= 0) {changeSign = true; break;}
-    if(!changeSign) {
-      qq_subTriangles.clear();
-      qq_subQuads.clear();
-      qq_surfLines.clear();
-      qq_cp.clear();
-      DI_Point vP[4];
-      for(int i = 0; i < 4; i++) {
-        double ls = Ls(x(i), y(i), z(i));
-        vP[i] = DI_Point(qq.x(i), qq.y(i), qq.z(i), ls);
-      }
-      DI_Quad qt(vP[0], vP[1], vP[2], vP[3]); // reference quad
-      qq_subQuads.push_back(qt);
-    }
-  }*/
-
   for(int q = 0; q < (int)qq_subQuads.size(); q++) {
     qq_subQuads[q].computeLsTagDom(&qq, RPN);
     DI_Quad qq_subQ = qq_subQuads[q];
@@ -2415,7 +2389,7 @@ void DI_Quad::cut (const DI_Element *e, const std::vector<const gLevelset *> &RP
   // check if the quadrangle is cut by the level set
   int on = 0, pos = 0, neg = 0, ze[4];
   for (int i = 0; i < 4; i++){
-    if(fabs(pt(i).ls()) < ZERO_LS_TOL) ze[on++] = i;
+    if(pt(i).isOnBorder()) ze[on++] = i;
     else if (pt(i).ls() > 0.) pos++;
     else neg++;
   }
@@ -2473,8 +2447,7 @@ bool DI_Tetra::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
       const gLevelset *Lsi = RPN[l];
       RPNi.push_back(Lsi);
       if(Lsi->isPrimitive()) {
-        if(nodeLs && nodeLs[0].count(Lsi->getTag())) tt.addLs(Lsi->getTag(), nodeLs);
-        else tt.addLs(this, *Lsi);
+        tt.addLs(this, *Lsi, nodeLs);
         int nbSubT = tt_subTetras.size(), nbSubT1 = nbSubT;
         int nbSurfQ = tt_surfQuads.size();
         int nbSurfTr = tt_surfTriangles.size(), nbSurfTr1 = nbSurfTr;
@@ -2484,7 +2457,7 @@ bool DI_Tetra::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
         for(int i = 0; i < nbSurfTr; i++) tt_surfTriangles[i].addLs(&tt);
         for(int i = 0; i < nbCP; i++) tt_cp[i].addLs(&tt);
         int ze[3], cz = 0;
-        for (int i = 0; i < 4; i++) if(fabs(tt.ls(i)) < ZERO_LS_TOL) ze[cz++] = i;
+        for (int i = 0; i < 4; i++) if(tt.pt(i).isOnBorder()) ze[cz++] = i;
 
         for(int t = 0; t < nbSubT; t++) {
           nbSurfTr1 = tt_surfTriangles.size();
@@ -2535,34 +2508,11 @@ bool DI_Tetra::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
       const gLevelset *Lsi = RPN[l];
       RPNi.push_back(Lsi);
       if(Lsi->isPrimitive()) {
-        if(nodeLs && nodeLs[0].count(Lsi->getTag())) tt.addLs(Lsi->getTag(), nodeLs);
-        else tt.addLs(this, *Lsi);
+        tt.addLs(this, *Lsi, nodeLs);
       }
     }
   }
 
-  /*//if !changeSign => clear vectors / tetras.push_back(tt)
-  if(tt_cp.size() > 1) {
-    bool changeSign = false;
-    double sign0 = tt_cp[0].ls();
-    for(int i = 1; i < (int)tt_cp.size(); i++)
-      if(sign0 * tt_cp[i].ls() <= 0) {changeSign = true; break;}
-    if(!changeSign) {
-      tt_subTetras.clear();
-      tt_surfQuads.clear();
-      tt_surfTriangles.clear();
-      tt_cp.clear();
-      QError.clear();
-      DI_Point vP[4];
-      for(int i = 0; i < 4; i++) {
-        double ls = Ls(x(i), y(i), z(i));
-        vP[i] = DI_Point(tt.x(i), tt.y(i), tt.z(i), ls);
-      }
-      DI_Tetra tet(vP[0], vP[1], vP[2], vP[3]); // reference tetra
-      tt_subTetras.push_back(tet);
-    }
-  }*/
-
   for(int i = 0; i < (int)QError.size(); i++)
     QError[i].print(this);
 
@@ -2609,7 +2559,7 @@ void DI_Tetra::cut (const DI_Element *e, const std::vector<const gLevelset *> &R
   // check if the tetra is cut by the level set
   int on = 0, pos = 0, neg = 0, ze[4];
   for (int i = 0; i < 4; i++){
-    if(fabs(pt(i).ls()) < ZERO_LS_TOL) ze[on++] = i;
+    if(pt(i).isOnBorder()) ze[on++] = i;
     else if (pt(i).ls() > 0.) pos++;
     else neg++;
   }
@@ -2658,8 +2608,7 @@ bool DI_Hexa::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
       const gLevelset *Lsi = RPN[l];
       RPNi.push_back(Lsi);
       if(Lsi->isPrimitive()) {
-        if(nodeLs && nodeLs[0].count(Lsi->getTag())) hh.addLs(Lsi->getTag(), nodeLs);
-        else hh.addLs(this, *Lsi);
+        hh.addLs(this, *Lsi, nodeLs);
         int nbSubH = hh_subHexas.size();
         int nbSubT = hh_subTetras.size(), nbSubT1 = nbSubT;
         int nbSurfQ = hh_surfQuads.size(), nbSurfQ1 = nbSurfQ;
@@ -2674,7 +2623,7 @@ bool DI_Hexa::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
         for(int i = 0; i < nbCP; i++) hh_cp[i].addLs(&hh);
         int pos = 0, neg = 0, ze[4], cz = 0;
         for (int i = 0; i < 8; i++){
-          if(fabs(hh.ls(i)) < ZERO_LS_TOL) ze[cz++] = i;
+          if(hh.pt(i).isOnBorder()) ze[cz++] = i;
           else if (hh.ls(i) > 0.) pos++;
           else neg++;
         }
@@ -2774,37 +2723,11 @@ bool DI_Hexa::cut (const gLevelset &Ls, std::vector<DI_IntegrationPoint> &ip,
       const gLevelset *Lsi = RPN[l];
       RPNi.push_back(Lsi);
       if(Lsi->isPrimitive()) {
-        if(nodeLs && nodeLs[0].count(Lsi->getTag())) hh.addLs(Lsi->getTag(), nodeLs);
-        else hh.addLs(this, *Lsi);
+        hh.addLs(this, *Lsi, nodeLs);
       }
     }
   }
 
-  /*//if the sign does not change and !=0 in the hexa => returns only a hexa
-  if(hh_cp.size() > 1) {
-    bool changeSign = false;
-    double sign0 = hh_cp[0].ls();
-    for(int i = 1; i < (int)hh_cp.size(); i++)
-      if(sign0*hh_cp[i].ls() <= 0)
-        {changeSign = true; break;}
-    if(!changeSign) {
-      hh_subHexas.clear();
-      hh_subTetras.clear();
-      hh_surfQuads.clear();
-      hh_surfTriangles.clear();
-      hh_frontLines.clear();
-      hh_cp.clear();
-      QError.clear();
-      DI_Point vP[8];
-      for(int i = 0; i < 8; i++) {
-        double ls = Ls(x(i), y(i), z(i));
-        vP[i] = DI_Point(hh.x(i), hh.y(i), hh.z(i), ls);
-      }
-      DI_Hexa hex(vP[0], vP[1], vP[2], vP[3], vP[4], vP[5], vP[6], vP[7]); // reference hexa
-      hh_subHexas.push_back(hex);
-    }
-  }*/
-
   for(int i = 0; i < (int)QError.size(); i++)
     QError[i].print(this);
 
@@ -2866,7 +2789,7 @@ void DI_Hexa::cut (const DI_Element *e, const std::vector<const gLevelset *> &RP
   // check if the hex is cut by the level set
   int on = 0, pos = 0, neg = 0, ze[8];
   for (int i = 0; i < 8; i++){
-    if(fabs(pt(i).ls()) < ZERO_LS_TOL) ze[on++] = i;
+    if(pt(i).isOnBorder()) ze[on++] = i;
     else if (pt(i).ls() > 0.) pos++;
     else neg++;
   }
diff --git a/contrib/DiscreteIntegration/Integration3D.h b/contrib/DiscreteIntegration/Integration3D.h
index 8cac2681b26bf35a95b2feeaf700a4d2c8084c08..791fbea19ac7d372faf911da624ce87ed4da497d 100644
--- a/contrib/DiscreteIntegration/Integration3D.h
+++ b/contrib/DiscreteIntegration/Integration3D.h
@@ -30,14 +30,14 @@ class DI_Point
 {
   // coordinates of the point
   double x_, y_, z_;
- public :
   // vector containing the levelset values of the point
   std::vector<double> Ls;
+ public :
   // constructors
   DI_Point () : x_(0), y_(0), z_(0) {}
   DI_Point (double x, double y, double z) : x_(x), y_(y), z_(z) {}
   DI_Point (double x, double y, double z, gLevelset &ls);
-  DI_Point (double x, double y, double z, const double ls) : x_(x), y_(y), z_(z) {Ls.push_back(ls);}
+  DI_Point (double x, double y, double z, const double ls) : x_(x), y_(y), z_(z) {addLs(ls);}
   DI_Point (double x, double y, double z, const DI_Element *e,
             const std::vector<const gLevelset *> RPNi) : x_(x), y_(y), z_(z) {computeLs(e, RPNi);}
   DI_Point(const DI_Point &p) : x_(p.x()), y_(p.y()), z_(p.z()) {Ls.clear(); Ls = p.Ls;}
@@ -46,9 +46,9 @@ class DI_Point
   // destructor
   ~DI_Point () {Ls.clear();}
   // add a levelset value (adjusted to 0 if ls<ZERO_LS_TOL) into the vector Ls
-  inline void addLs (const double ls);
+  void addLs (const double ls);
   // add a levelset value evaluated into the element e
-  inline void addLs (const DI_Element *e);
+  void addLs (const DI_Element *e);
   // choose the value of the levelset among the last two levelset values of Ls,
   // delete the last two values and add the chosen one
   void chooseLs (const gLevelset *Lsi);
@@ -57,7 +57,7 @@ class DI_Point
   // clear Ls and add the levelset value computed with ls
   void computeLs (const gLevelset &ls);
   // remove the last value in Ls and add ls
-  inline void changeLs (const double ls) {Ls.pop_back(); Ls.push_back(ls);}
+  inline void changeLs (const double ls) {Ls.pop_back(); addLs(ls);}
   // change the coordinates
   inline void move (double x, double y, double z) {x_ = x; y_ = y; z_ = z;}
   // return true if the coordinates of this and p are equal (with a tolerance)
@@ -70,6 +70,10 @@ class DI_Point
   inline double ls() const {return Ls.back();}
   // return the ith value of Ls
   inline double ls(int i) const {return Ls[i];}
+  // return the size of the vector of ls values
+  inline int sizeLs() const {return Ls.size();}
+  // clear the values in Ls
+  inline void clearLs() {Ls.clear();}
   // return the position of the point with respect to the domain depending on the last value in Ls
   inline bool isInsideDomain  () const {return Ls.back() < 0.;}
   inline bool isOutsideDomain () const {return Ls.back() > 0.;}
@@ -80,7 +84,7 @@ class DI_Point
     return 0;
   }
   // print the coordiantes
-  void print() const {printf("Point (%g,%g,%g)\n", x_, y_, z_);}
+  inline void print() const {printf("Point (%g,%g,%g)\n", x_, y_, z_);}
   void printls() const {
     printf("Point (%g,%g,%g) ls=(", x_, y_, z_);
     for(int i = 0; i < (int)Ls.size(); i++) printf("%g,", Ls[i]);
@@ -229,13 +233,13 @@ class DI_Element
   virtual double refIntegral() const = 0;
   // add a levelset value to each point
   void addLs (const double *ls);
-  // add the levelset value to each point from the map with each primitive value
-  void addLs (int primTag, std::map<int, double> nodeLs[8]);
   // evaluate the levelset value at each point and add it to each point
   void addLs (const DI_Element *e);
-  // add the level set at each vertex of the real element e (same type as this)
+  // compute the level set at each vertex of the real element e (same type as this)
+  // or take i from the map if exist
   // and add it to the vertices
   void addLs (const DI_Element *e, const gLevelset &Ls);
+  void addLs (const DI_Element *e, const gLevelset &Ls, std::map<int, double> nodeLs[]);
   // clear the levelset of the vertices
   void clearLs();
   // compute the levelset values at the mid edge points and add a quadratic edge,
@@ -286,7 +290,7 @@ class DI_Element
   inline double ls (int i, int j) const {
     return i < nbVert() ? pts_[i]->ls(j) : mid_[i - nbVert()]->ls(j);}
   // return the number of levelset values of the points
-  inline int sizeLs() const {return pts_[0]->Ls.size();}
+  inline int sizeLs() const {return pts_[0]->sizeLs();}
   // return the interpolating nodal shape functions evaluated at point (u,v,w)
   // in parametric coordinates (if order = -1, use the polynomial order of the element)
   virtual void getShapeFunctions (double u, double v, double w, double s[], int order = -1) const = 0;
@@ -322,12 +326,11 @@ class DI_CuttingPoint
   double xl_, yl_, zl_;
   std::vector<double> Ls;
  public:
-  DI_CuttingPoint (const DI_Point &pt)
-    : x_(pt.x()), y_(pt.y()), z_(pt.z()), xl_(pt.x()), yl_(pt.y()), zl_(pt.z()), Ls(pt.Ls) { }
+  DI_CuttingPoint (const DI_Point &pt);
   inline void addLocC (double xl, double yl, double zl) {xl_ = xl; yl_ = yl; zl_ = zl;}
   inline void move (double x, double y, double z) {x_ = x; y_ = y; z_ = z;}
-  inline void addLs (const DI_Element *e) { Ls.push_back(e->evalLs(x_, y_, z_));}
-  inline void addLs (double ls) {Ls.push_back(ls);}
+  void addLs (const double ls);
+  void addLs (const DI_Element *e);
   inline double x () const {return x_;}
   inline double y () const {return y_;}
   inline double z () const {return z_;}
@@ -337,13 +340,13 @@ class DI_CuttingPoint
   inline double ls() const {return Ls.back();}
   inline double ls(int i) const {return Ls[i];}
   // return the position of the point with respect to the domain depending on the last value in Ls
-  bool isInsideDomain  () const {return Ls.back() < 0.;}
-  bool isOutsideDomain () const {return Ls.back() > 0.;}
-  bool isOnBorder () const {return Ls.back() == 0.;}
+  inline bool isInsideDomain  () const {return Ls.back() < 0.;}
+  inline bool isOutsideDomain () const {return Ls.back() > 0.;}
+  inline bool isOnBorder () const {return Ls.back() == 0.;}
   inline int sizeLs() const {return Ls.size();}
   void chooseLs (const gLevelset *Lsi);
   bool equal (const DI_CuttingPoint &p) const;
-  void print() const {
+  inline void print() const {
     printf("CP : x=(%g,%g,%g) xl=(%g,%g,%g)\n", x_, y_, z_, xl_, yl_, zl_);
   }
   void printls() const {
diff --git a/contrib/DiscreteIntegration/recurCut.cpp b/contrib/DiscreteIntegration/recurCut.cpp
index e93eb2d90ed45869e75ebd4bad82fae3d88e9f98..a54f06376d7a3a82159fc4bcb8a38514dd134448 100644
--- a/contrib/DiscreteIntegration/recurCut.cpp
+++ b/contrib/DiscreteIntegration/recurCut.cpp
@@ -176,8 +176,7 @@ bool signChange (RecurElement *re, const DI_Element *e, const std::vector<const
     const gLevelset *Lsi = RPN[l];
     RPNi.push_back(Lsi);
     if(Lsi->isPrimitive()) {
-      if(nodeLs && nodeLs[0].count(Lsi->getTag())) elem->addLs(Lsi->getTag(), nodeLs);
-      else elem->addLs(e, *Lsi);
+      elem->addLs(e, *Lsi, nodeLs);
       for(unsigned int i = 0; i < cp.size(); i++)
         cp[i].addLs(elem);
       if (re->super) re->el->addLs(elem);