From 5dd35e2aef46261d6e93e340c93ceed21eee93d7 Mon Sep 17 00:00:00 2001
From: Gaetan Bricteux <gaetan.bricteux@uclouvain.be>
Date: Wed, 10 Feb 2010 10:50:20 +0000
Subject: [PATCH] SplitMesh

---
 Geo/GModel.cpp                              |   4 +-
 Geo/GModel.h                                |   3 +-
 Geo/GModelIO_Mesh.cpp                       |   6 +-
 Geo/MElementCut.cpp                         | 197 ++++++++++++++++----
 Geo/MElementCut.h                           |   3 +-
 Geo/MVertex.h                               |   1 +
 Numeric/fullMatrix.h                        |   4 +-
 Parser/Gmsh.y                               |   6 +
 contrib/DiscreteIntegration/Integration3D.h |   3 -
 9 files changed, 182 insertions(+), 45 deletions(-)

diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index ac28226d9d..0956f1ee77 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -1302,7 +1302,7 @@ void GModel::createTopologyFromFaces(std::vector<discreteFace*> &discFaces)
   }
 }
 
-GModel *GModel::buildCutGModel(gLevelset *ls)
+GModel *GModel::buildCutGModel(gLevelset *ls, bool cutElem)
 {
   std::map<int, std::vector<MElement*> > elements[10];
   std::map<int, std::map<int, std::string> > physicals[4];
@@ -1311,7 +1311,7 @@ GModel *GModel::buildCutGModel(gLevelset *ls)
   Msg::Info("Cutting mesh...");
   double t1 = Cpu();
 
-  GModel *cutGM = buildCutMesh(this, ls, elements, vertexMap, physicals);
+  GModel *cutGM = buildCutMesh(this, ls, elements, vertexMap, physicals, cutElem);
 
   for(int i = 0; i < (int)(sizeof(elements) / sizeof(elements[0])); i++)
     cutGM->_storeElementsInEntities(elements[i]);
diff --git a/Geo/GModel.h b/Geo/GModel.h
index 9d7d17a266..af292e094b 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -340,7 +340,8 @@ class GModel
   int mesh(int dimension);
 
   // build a new GModel by cutting the elements crossed by the levelset ls
-  GModel *buildCutGModel(gLevelset *ls);
+  // if cutElem is set to false, split the model without cutting the elements
+  GModel *buildCutGModel(gLevelset *ls, bool cutElem = true);
 
   // create a GModel by importing a mesh (vertexMap has a dim equal to
   // the number of vertices and all the other vectors have a dim equal
diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index 811e843869..e569fd11d1 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -318,7 +318,7 @@ int GModel::readMSH(const std::string &name)
         if(numVertices > 100000) 
           Msg::ProgressMeter(i + 1, numVertices, "Reading nodes");
       }
-      // if the vertex numbering is dense, tranfer the map into a
+      // If the vertex numbering is dense, transfer the map into a
       // vector to speed up element creation
       if((int)vertexMap.size() == numVertices && 
          ((minVertex == 1 && maxVertex == numVertices) ||
@@ -2823,7 +2823,7 @@ int GModel::readDIFF(const std::string &name)
         vertexMap[num] = new MVertex(xyz[0], xyz[1], xyz[2], 0, num);
       if(numVertices > 100000) 
         Msg::ProgressMeter(i + 1, numVertices, "Reading nodes");
-      // If the vertex numbering is dense, tranfer the map into a
+      // If the vertex numbering is dense, transfer the map into a
       // vector to speed up element creation
       if((int)vertexMap.size() == numVertices && 
          ((minVertex == 1 && maxVertex == numVertices) ||
@@ -3175,7 +3175,7 @@ GModel *GModel::createGModel(std::map<int, MVertex*> &vertexMap,
   if(minVertex == std::numeric_limits<int>::max())
     Msg::Error("Could not determine the min index of vertices");
   
-  // If the vertex numbering is dense, tranfer the map into a
+  // If the vertex numbering is dense, transfer the map into a
   // vector to speed up element creation
   if((minVertex == 1 && maxVertex == numVertices) ||
      (minVertex == 0 && maxVertex == numVertices - 1)){
diff --git a/Geo/MElementCut.cpp b/Geo/MElementCut.cpp
index f82d2ba7f4..357cce3614 100644
--- a/Geo/MElementCut.cpp
+++ b/Geo/MElementCut.cpp
@@ -384,8 +384,6 @@ void MLineBorder::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
 
 //---------------------------------------- CutMesh ----------------------------
 
-#if defined(HAVE_DINTEGRATION)
-
 static bool equalV(MVertex *v, const DI_Point *p)
 {
   return (fabs(v->x() - p->x()) < 1.e-15 &&
@@ -424,7 +422,8 @@ static int getElementaryTag(int lsTag, int elementary, std::map<int, int> &newEl
   }
   return elementary;
 }
-static void getPhysicalTag(int lsTag, const std::vector<int> &physicals, std::vector<int> &phys2, std::map<int, int> &newPhysTags)
+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++){
@@ -452,11 +451,127 @@ static int getBorderTag(int lsTag, int count, int &maxTag, std::map<int, int> &b
   return lsTag;
 }
 
-typedef std::set<MVertex*,MVertexLessThanLexicographic> newVerticesContainer ;
+static void elementSplitMesh(MElement *e, fullMatrix<double> &verticesLs,
+                             GEntity *ge, GModel *GM, int &numEle,
+                             std::map<int, MVertex*> &vertexMap,
+                             std::map<int, std::vector<MElement*> > elements[10],
+                             std::map<int, std::map<int, std::string> > physicals[4],
+                             std::map<int, int> newElemTags[4],
+                             std::map<int, int> newPhysTags[4])
+{
+  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);
+
+  double lsMean = 0.;
+  for(int k = 0; k < e->getNumVertices(); k++)
+    lsMean += verticesLs(e->getVertex(k)->getIndex(), 0);
+  int lsTag = (lsMean < 0) ? 1 : -1;
+
+  switch (eType) {
+  case MSH_TET_4 :
+  case MSH_HEX_8 :
+  case MSH_PYR_5 :
+  case MSH_PRI_6 :
+  case MSH_POLYH_ :
+    {
+      int reg = getElementaryTag(lsTag, elementary, newElemTags[3]);
+      std::vector<int> phys;
+      getPhysicalTag(lsTag, gePhysicals, phys, newPhysTags[3]);
+      if(eType == MSH_TET_4)
+        elements[4][reg].push_back(copy);
+      else if(eType == MSH_HEX_8)
+        elements[5][reg].push_back(copy);
+      else if(eType == MSH_PRI_6)
+        elements[6][reg].push_back(copy);
+      else if(eType == MSH_PYR_5)
+        elements[7][reg].push_back(copy);
+      else if(eType == MSH_POLYH_)
+        elements[9][reg].push_back(copy);
+      assignPhysicals(GM, phys, reg, 3, physicals);
+    }
+    break;
+  case MSH_TRI_3 :
+  case MSH_QUA_4 :
+  case MSH_POLYG_ :
+    {
+      int reg = getElementaryTag(lsTag, elementary, newElemTags[2]);
+      std::vector<int> phys;
+      getPhysicalTag(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, phys, reg, 2, physicals);
+    }
+    break;
+  case MSH_LIN_2 :
+    {
+      int reg = getElementaryTag(lsTag, elementary, newElemTags[1]);
+      std::vector<int> phys;
+      getPhysicalTag(lsTag, gePhysicals, phys, newPhysTags[1]);
+      elements[1][reg].push_back(copy);
+      assignPhysicals(GM, phys, reg, 1, physicals);
+    }
+    break;
+  case MSH_PNT :
+    {
+      int reg = getElementaryTag(lsTag, elementary, newElemTags[0]);
+      std::vector<int> phys;
+      getPhysicalTag(lsTag, gePhysicals, phys, newPhysTags[0]);
+      elements[0][reg].push_back(copy);
+      assignPhysicals(GM, phys, reg, 0, physicals);
+    }
+    break;
+  default :
+    Msg::Error("This type of element cannot be cut.");
+    return;
+  }
+}
+
+#if defined(HAVE_DINTEGRATION)
+
+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,
+                           GEntity *ge, GModel *GM, int &numEle,
+                           std::map<int, MVertex*> &vertexMap,
 			   newVerticesContainer &newVertices,
                            std::map<int, std::vector<MElement*> > elements[10],
                            std::map<int, std::map<int, std::string> > physicals[4],
@@ -620,10 +735,10 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
           for(int j = 0; j < 4; j++){
             int numV = getElementVertexNum(tetras[i]->pt(j), e);
 	    if (numV == -1){
-	      MVertex *newv = new MVertex(tetras[i]->x(j), tetras[i]->y(j), tetras[i]->z(j), 0);
+	      MVertex *newv = new MVertex(tetras[i]->x(j), tetras[i]->y(j), tetras[i]->z(j));
 	      std::pair<newVerticesContainer::iterator, bool> it = newVertices.insert(newv);
 	      mv[j] = *(it.first);
-	      if (!it.second) delete newv;
+	      if (!it.second) newv->deleteLast();
 	    }
 	    else {
               std::map<int, MVertex*>::iterator it = vertexMap.find(numV);
@@ -677,10 +792,10 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
         for(int j = 0; j < 3; j++){
           int numV = getElementVertexNum(triangles[i]->pt(j), e);
           if(numV == -1) {
-	    MVertex *newv = new MVertex(triangles[i]->x(j), triangles[i]->y(j), triangles[i]->z(j), 0);
+	    MVertex *newv = new MVertex(triangles[i]->x(j), triangles[i]->y(j), triangles[i]->z(j));
 	    std::pair<newVerticesContainer::iterator, bool> it = newVertices.insert(newv);
 	    mv[j] = *(it.first);
-	    if (!it.second) delete newv;
+	    if (!it.second) newv->deleteLast();
           }
           else {
             std::map<int, MVertex*>::iterator it = vertexMap.find(numV);
@@ -696,8 +811,8 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
         if(p1 || p2) tri = new MTriangleBorder(mv[0], mv[1], mv[2], p1, p2, ++numEle, ePart);
         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);
-        // suppose that the surfaces have been cut before the volumes!
+        int c = elements[2].count(lsT) + elements[3].count(lsT) + elements[8].count(lsT);
+        // the surfaces are cut before the volumes!
         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);
@@ -749,10 +864,10 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
           for(int j = 0; j < 3; j++){
             int numV = getElementVertexNum(triangles[i]->pt(j), e);
             if(numV == -1) {
-	      MVertex *newv = new MVertex(triangles[i]->x(j), triangles[i]->y(j), triangles[i]->z(j), 0);
+	      MVertex *newv = new MVertex(triangles[i]->x(j), triangles[i]->y(j), triangles[i]->z(j));
 	      std::pair<newVerticesContainer::iterator, bool> it = newVertices.insert(newv);
 	      mv[j] = *(it.first);
-	      if (!it.second) delete newv;
+	      if (!it.second) newv->deleteLast();
             }
             else {
               std::map<int, MVertex*>::iterator it = vertexMap.find(numV);
@@ -802,10 +917,10 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
         for(int j = 0; j < 2; j++){
           int numV = getElementVertexNum(lines[i]->pt(j), e);
           if(numV == -1) {
-	    MVertex *newv = new MVertex(lines[i]->x(j), lines[i]->y(j), lines[i]->z(j), 0);
+	    MVertex *newv = new MVertex(lines[i]->x(j), lines[i]->y(j), lines[i]->z(j));
 	    std::pair<newVerticesContainer::iterator, bool> it = newVertices.insert(newv);
 	    mv[j] = *(it.first);
-	    if (!it.second) delete newv;
+	    if (!it.second) newv->deleteLast();
           }
           else {
             std::map<int, MVertex*>::iterator it = vertexMap.find(numV);
@@ -822,7 +937,7 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
         else lin = new MLine(mv[0], mv[1], ++numEle, ePart);
         int lsL = lines[i]->lsTag();
         int c = elements[1].count(lsL);
-        // suppose that the lines have been cut before the surfaces!
+        // the lines are cut before the surfaces!
         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);
@@ -844,10 +959,10 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
           for(int j = 0; j < 2; j++){
             int numV = getElementVertexNum(lines[i]->pt(j), e);
             if(numV == -1) {
-	      MVertex *newv = new MVertex(lines[i]->x(j), lines[i]->y(j), lines[i]->z(j), 0);
+	      MVertex *newv = new MVertex(lines[i]->x(j), lines[i]->y(j), lines[i]->z(j));
 	      std::pair<newVerticesContainer::iterator, bool> it = newVertices.insert(newv);
 	      mv[j] = *(it.first);
-	      if (!it.second) delete newv;
+	      if (!it.second) newv->deleteLast();
             }
             else {
               std::map<int, MVertex*>::iterator it = vertexMap.find(numV);
@@ -903,19 +1018,32 @@ static void elementCutMesh(MElement *e, std::vector<const gLevelset *> &RPN,
 GModel *buildCutMesh(GModel *gm, gLevelset *ls,
                      std::map<int, std::vector<MElement*> > elements[10],
                      std::map<int, MVertex*> &vertexMap,
-                     std::map<int, std::map<int, std::string> > physicals[4])
+                     std::map<int, std::map<int, std::string> > physicals[4],
+                     bool cutElem)
 {
 #if defined(HAVE_DINTEGRATION)
-  int numVert = gm->indexMeshVertices(true);
 
   GModel *cutGM = new GModel(gm->getName() + "_cut");
   cutGM->setFileName(cutGM->getName());
 
-  newVerticesContainer newVertices;
-
   std::vector<GEntity*> gmEntities;
   gm->getEntities(gmEntities);
-  int numEle = gm->getNumMeshElements();
+
+  std::vector<const gLevelset *> primitives;
+  ls->getPrimitives(primitives);
+  int numVert = gm->indexMeshVertices(true);
+  int nbLs = (cutElem) ? primitives.size() : 1;
+  fullMatrix<double> verticesLs(numVert + 1, nbLs);
+  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);
+      if(cutElem)
+        for(unsigned int k = 0; k < primitives.size(); k++)
+          verticesLs(vi->getIndex(), k) = (*primitives[k])(vi->x(), vi->y(), vi->z());
+      else
+        verticesLs(vi->getIndex(), 0) = (*ls)(vi->x(), vi->y(), vi->z());
+    }
+  }
 
   std::map<int, int> newElemTags[4];
   std::map<int, int> newPhysTags[4];
@@ -923,21 +1051,24 @@ GModel *buildCutMesh(GModel *gm, gLevelset *ls,
     newElemTags[d][0] = gm->getMaxElementaryNumber(d);
     newPhysTags[d][0] = gm->getMaxPhysicalNumber(d);
   }
-  std::map<int, int> borderElemTags[2];
-  std::map<int, int> borderPhysTags[2];
+  int numEle = gm->getNumMeshElements();
 
-  std::vector<const gLevelset *> primitives;
-  ls->getPrimitives(primitives);
-  fullMatrix<double> verticesLs(numVert + 1, primitives.size());
-  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);
-      for(unsigned int k = 0; k < primitives.size(); k++) {
-        verticesLs(vi->getIndex(), k) = (*primitives[k])(vi->x(), vi->y(), vi->z());
+  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);
+        cutGM->getMeshPartitions().insert(e->getPartition());
       }
     }
+    return cutGM;
   }
 
+  newVerticesContainer newVertices;
+  std::map<int, int> borderElemTags[2];
+  std::map<int, int> borderPhysTags[2];
   DI_Point::Container cp;
   std::vector<DI_Line *> lines;
   std::vector<DI_Triangle *> triangles;
diff --git a/Geo/MElementCut.h b/Geo/MElementCut.h
index 7d0d2a82ea..c58dc3202a 100644
--- a/Geo/MElementCut.h
+++ b/Geo/MElementCut.h
@@ -311,6 +311,7 @@ class MLineBorder : public MLine {
 GModel *buildCutMesh(GModel *gm, gLevelset *ls,
                      std::map<int, std::vector<MElement*> > elements[10],
                      std::map<int, MVertex*> &vertexMap,
-                     std::map<int, std::map<int, std::string> > physicals[4]);
+                     std::map<int, std::map<int, std::string> > physicals[4],
+                     bool cutElem);
 
 #endif
diff --git a/Geo/MVertex.h b/Geo/MVertex.h
index 6ac10df95c..17506c4b54 100644
--- a/Geo/MVertex.h
+++ b/Geo/MVertex.h
@@ -46,6 +46,7 @@ class MVertex{
  public:
   MVertex(double x, double y, double z, GEntity *ge=0, int num=0);
   virtual ~MVertex(){}
+  inline void deleteLast() {if(_num == _globalNum) _globalNum--; delete this;}
 
   // get/reset the global node number
   static int getGlobalNumber(){ return _globalNum; }
diff --git a/Numeric/fullMatrix.h b/Numeric/fullMatrix.h
index dcf652c6ca..a159613bff 100644
--- a/Numeric/fullMatrix.h
+++ b/Numeric/fullMatrix.h
@@ -89,10 +89,10 @@ class fullVector
     printf("\n");
   }
   void binarySave (FILE *f) const{
-    fwrite (_data,sizeof(scalar),_r,f); 
+    fwrite (_data, sizeof(scalar), _r, f); 
   }
   void binaryLoad (FILE *f){
-    fread (_data,sizeof(scalar),_r,f); 
+    if(fread (_data, sizeof(scalar), _r, f) != _r) return; 
   }
 };
 
diff --git a/Parser/Gmsh.y b/Parser/Gmsh.y
index a2c0e3a977..28b904abac 100644
--- a/Parser/Gmsh.y
+++ b/Parser/Gmsh.y
@@ -2009,6 +2009,12 @@ LevelSet :
         GM->buildCutGModel(FindLevelSet(t)->ls);
         GM->setVisibility(0);
       }
+      else if(!strcmp($2, "SplitMesh")){
+        int t = (int)$4;
+        GModel *GM = GModel::current();
+        GM->buildCutGModel(FindLevelSet(t)->ls, false);
+        GM->setVisibility(0);
+      }
       else
         yymsg(0, "Wrong levelset definition");
       Free($2);
diff --git a/contrib/DiscreteIntegration/Integration3D.h b/contrib/DiscreteIntegration/Integration3D.h
index 2665373bb5..f8a8afa14d 100644
--- a/contrib/DiscreteIntegration/Integration3D.h
+++ b/contrib/DiscreteIntegration/Integration3D.h
@@ -43,11 +43,8 @@ class DI_Point
   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;}
   // assignment
   DI_Point & operator=(const DI_Point & rhs);
-  // destructor
-  //  virtual ~DI_Point () {}
   // add a levelset value (adjusted to 0 if ls<ZERO_LS_TOL) into the vector Ls
   void addLs (const double ls);
   // add a levelset value evaluated into the element e
-- 
GitLab