From 975652a97a01f5b6b00479953bab5c3b25fd5e25 Mon Sep 17 00:00:00 2001
From: Jean-Francois Remacle <jean-francois.remacle@uclouvain.be>
Date: Fri, 16 Sep 2016 09:32:19 +0000
Subject: [PATCH] improvement of hybrid meshes

---
 Geo/discreteDiskFace.cpp            |  4 +--
 Geo/discreteDiskFace.h              | 16 ++++------
 Geo/discreteFace.cpp                | 13 +++++---
 Mesh/CMakeLists.txt                 |  1 +
 Mesh/Generator.cpp                  |  2 +-
 Mesh/Generator.h                    |  4 +++
 Mesh/meshGFaceDelaunayInsertion.cpp | 13 +++++---
 Mesh/meshGRegion.cpp                | 49 ++++++++++++++++++++++++++---
 Mesh/meshGRegionRelocateVertex.cpp  | 33 +++++++++++--------
 Mesh/meshGRegionRelocateVertex.h    |  7 +++--
 Solver/dofManager.h                 |  2 +-
 11 files changed, 100 insertions(+), 44 deletions(-)

diff --git a/Geo/discreteDiskFace.cpp b/Geo/discreteDiskFace.cpp
index b52d22a38c..5bb7361e62 100644
--- a/Geo/discreteDiskFace.cpp
+++ b/Geo/discreteDiskFace.cpp
@@ -1122,8 +1122,8 @@ static double computeDistanceLinePoint (MVertex *v1, MVertex *v2, MVertex *v){
 
 }
 */
-static double computeDistance (MVertex *v1, double d1, MVertex *v2, double d2, MVertex *v)
-{
+inline double computeDistance (MVertex *v1, double d1, MVertex *v2, double d2, MVertex *v){
+  
   //       o------------a
   //
   //
diff --git a/Geo/discreteDiskFace.h b/Geo/discreteDiskFace.h
index 1719fe3d39..cad358b209 100644
--- a/Geo/discreteDiskFace.h
+++ b/Geo/discreteDiskFace.h
@@ -84,6 +84,7 @@ class triangulation {
   {
     double L = bord.rbegin()->first;
     if (L == 0.0)return 1.e22;
+    if (maxD < 0) maxD = geodesicDistance();
     //    printf("%12.5E %12.5E\n",L,maxD);
     return maxD / L;
   }
@@ -136,7 +137,7 @@ class triangulation {
     std::map<MVertex*,std::vector<MVertex*> > firstNode2Edge;
     for (std::set<MEdge>::iterator ie = borderEdg.begin(); ie != borderEdg.end() ; ++ie) {
       MEdge ed = *ie;
-      std::vector<int> nT = ed2tri[ed];
+      const std::vector<int> &nT = ed2tri[ed];
       MElement* t = tri[nT[0]];
 
       std::vector<MVertex*> vecver;
@@ -163,7 +164,7 @@ class triangulation {
       std::map<MVertex*,std::vector<MVertex*> >::iterator in = firstNode2Edge.begin();
       MVertex* previous = in->first;
       while(in != firstNode2Edge.end()) { // it didn't find it
-	std::vector<MVertex*> myV = in->second;
+	const std::vector<MVertex*> &myV = in->second;
 	for(unsigned int i=0; i<myV.size(); i++){
 	  loop.push_back(previous);
 	  MVertex* current = myV[i];
@@ -189,7 +190,7 @@ class triangulation {
     assignVert();
     assignEd2tri();
     assignBord();
-    maxD = geodesicDistance();
+    maxD = -1.e22;
   }
 
   void print (char *name, int elementary) const {
@@ -203,8 +204,8 @@ class triangulation {
   }
   
   triangulation() : gf(0) {}
-  triangulation(int id, std::vector<MElement*> input, GFace* gface)
-    : idNum(id), tri(input), gf(gface) { assign(); }
+  triangulation(int id, const  std::vector<MElement*> &input, GFace* gface)
+    : idNum(id), tri(input), gf(gface){ assign(); }
 };
 
 // triangles in the physical space xyz, with their parametric coordinates
@@ -247,12 +248,7 @@ class discreteDiskFace : public GFace {
   void printAtlasMesh () ;
   void printParamMesh () ;
   
-
-
   std::vector<MElement*> discrete_triangles;
-
-
-
  protected:
   // a copy of the mesh that should not be destroyed
   triangulation* initialTriangulation;
diff --git a/Geo/discreteFace.cpp b/Geo/discreteFace.cpp
index ea1c672c1e..09a792deff 100644
--- a/Geo/discreteFace.cpp
+++ b/Geo/discreteFace.cpp
@@ -111,16 +111,16 @@ void discreteFace::secondDer(const SPoint2 &param,
 
 void discreteFace::createGeometry()
 {
-
   checkAndFixOrientation();
   
 #if defined(HAVE_SOLVER) && defined(HAVE_ANN)
   int order = 1;
   int nPart = 2;
   double eta = 5/(2.*3.14);
-
   if (!_atlas.empty())return;
 
+  double dtSplit = 0.0;
+  
   int id=1;
   std::stack<triangulation*>  toSplit;
   std::vector<triangulation*> toParam;
@@ -134,7 +134,11 @@ void discreteFace::createGeometry()
       std::vector<triangulation*> part;
       triangulation* tosplit = toSplit.top();
       toSplit.pop();
+
+      clock_t ts0 = clock();
       split(tosplit,part,nPart);
+      clock_t ts1 = clock();
+      dtSplit += (double)(ts1-ts0)/CLOCKS_PER_SEC;
       delete tosplit;
 
       for(unsigned int i=0; i<part.size(); i++){
@@ -165,7 +169,6 @@ void discreteFace::createGeometry()
   }
 
   for(unsigned int i=0; i<toParam.size(); i++){    
-    std::vector<MElement*> mytri = toParam[i]->tri;
     discreteDiskFace *df = new discreteDiskFace (this,toParam[i], order,(_CAD.empty() ? NULL : &_CAD));
     df->printAtlasMesh();
     df->replaceEdges(toParam[i]->my_GEdges);
@@ -228,7 +231,7 @@ void discreteFace::mesh(bool verbose)
     _atlas[i]->mesh(verbose);/*
     const char *name = "atlas%d";
     char filename[256];
-    sprintf(filename,name,i);
+    sprintf(filename,name,i);t0
     _atlas[i]->printPhysicalMesh(filename);*/
   }
   
@@ -461,7 +464,7 @@ void discreteFace::split(triangulation* trian,std::vector<triangulation*> &parti
       for(int j=0; j<3; j++){// adjacency from edges
 	MEdge ed = current->getEdge(j);
 	if(trian->ed2tri[ed].size()>1){
-	  std::vector<int> oldnums = trian->ed2tri[ed];
+	  const std::vector<int> &oldnums = trian->ed2tri[ed];
 	  int on = trian->tri[oldnums[0]] == current ? oldnums[1] : oldnums[0];
 	  if(check_todo.find(trian->tri[on])==check_todo.end() && el2part[trian->tri[on]]==p){
 	    my_todo.push(trian->tri[on]);
diff --git a/Mesh/CMakeLists.txt b/Mesh/CMakeLists.txt
index 7cf93c40fc..d870c95fbc 100644
--- a/Mesh/CMakeLists.txt
+++ b/Mesh/CMakeLists.txt
@@ -17,6 +17,7 @@ set(SRC
       meshGFaceLloyd.cpp meshGFaceOptimize.cpp 
      meshGFaceQuadrilateralize.cpp 
     meshGRegion.cpp 
+    meshDiscreteRegion.cpp 
       meshGRegionDelaunayInsertion.cpp meshGRegionTransfinite.cpp 
       meshGRegionExtruded.cpp  meshGRegionCarveHole.cpp 
       meshGRegionLocalMeshMod.cpp meshGRegionMMG3D.cpp
diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp
index b81bf497ce..4f14d5c3d2 100644
--- a/Mesh/Generator.cpp
+++ b/Mesh/Generator.cpp
@@ -802,7 +802,7 @@ static void Mesh3D(GModel *m)
 	//			     CTX::instance()->mesh.recombine3DConformity);
         // 0: no pyramid, 1: single-step, 2: two-steps (conforming),
         // true: fill non-conformities with trihedra
-	RelocateVertices(gr);
+	RelocateVertices(gr, CTX::instance()->mesh.nbSmoothing);
         // while(LaplaceSmoothing (gr)){
         // }
 	nb_elements_recombination += post.get_nb_elements();
diff --git a/Mesh/Generator.h b/Mesh/Generator.h
index 52ec48a371..6d59607831 100644
--- a/Mesh/Generator.h
+++ b/Mesh/Generator.h
@@ -7,6 +7,8 @@
 #define _GENERATOR_H_
 
 class GModel;
+class GRegion;
+#include "fullMatrix.h"
 
 void GetStatistics(double stat[50], double quality[4][100]=0);
 void AdaptMesh(GModel *m);
@@ -17,5 +19,7 @@ void SmoothMesh(GModel *m);
 void RefineMesh(GModel *m, bool linear, bool splitIntoQuads=false,
                 bool splitIntoHexas=false);
 void RecombineMesh(GModel *m);
+GRegion * createTetrahedralMesh ( GModel *gm, fullMatrix<double> & pts, fullMatrix<int> &triangles ) ;
+  //GRegion * createTetrahedralMesh ( GModel *gm, unsigned int nbPts , double *pts, unsigned int nbTriangles, int *triangles );
 
 #endif
diff --git a/Mesh/meshGFaceDelaunayInsertion.cpp b/Mesh/meshGFaceDelaunayInsertion.cpp
index 259c4281b9..1e8b2e85fb 100644
--- a/Mesh/meshGFaceDelaunayInsertion.cpp
+++ b/Mesh/meshGFaceDelaunayInsertion.cpp
@@ -1281,7 +1281,7 @@ double optimalPointFrontal (GFace *gf,
    and the edge length
 */
 
-void optimalPointFrontalB (GFace *gf,
+bool optimalPointFrontalB (GFace *gf,
 			   MTri3* worst,
 			   int active_edge,
 			   bidimMeshData & data,
@@ -1320,8 +1320,9 @@ void optimalPointFrontalB (GFace *gf,
       if (gp.succeeded()){
 	newPoint[0] = gp.u();
 	newPoint[1] = gp.v();
-	return ;
+	return true;
       }
+      return false;
     }
   }
 #endif
@@ -1333,7 +1334,7 @@ void optimalPointFrontalB (GFace *gf,
       if (gp.succeeded()){
 	newPoint[0] = gp.u();
 	newPoint[1] = gp.v();
-	return ;
+	return true;
       }
     }
   }
@@ -1348,8 +1349,10 @@ void optimalPointFrontalB (GFace *gf,
   }
   else {
     Msg::Debug("--- Non optimal point found -----------");
+    return false;
     //    Msg::Info("--- Non optimal point found -----------");
   }
+  return true;
 }
 
 void bowyerWatsonFrontal(GFace *gf,
@@ -1406,8 +1409,8 @@ void bowyerWatsonFrontal(GFace *gf,
                    gf->mesh_vertices.size(), worst->getRadius());
       double newPoint[2], metric[3];
       //optimalPointFrontal (gf,worst,active_edge,Us,Vs,vSizes,vSizesBGM,newPoint,metric);
-      optimalPointFrontalB (gf,worst,active_edge,DATA,newPoint,metric);
-      insertAPoint(gf, AllTris.end(), newPoint, metric, DATA, AllTris, &ActiveTris, worst);
+      if (optimalPointFrontalB (gf,worst,active_edge,DATA,newPoint,metric))
+	insertAPoint(gf, AllTris.end(), newPoint, metric, DATA, AllTris, &ActiveTris, worst);
     }
 
     /*   if(ITER % 1== 0){
diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp
index 0eb02f7594..d04b788cfa 100644
--- a/Mesh/meshGRegion.cpp
+++ b/Mesh/meshGRegion.cpp
@@ -57,6 +57,41 @@ class splitQuadRecovery {
   {
     _data.insert(std::make_pair(ge, std::make_pair(v,f)));
   }
+  void relocateVertices(GRegion *region, int niter) {
+    if(empty()) return ;
+    v2t_cont adj;
+    buildVertexToElement(region->tetrahedra, adj);
+    buildVertexToElement(region->pyramids, adj);
+    buildVertexToElement(region->prisms, adj);
+    buildVertexToElement(region->hexahedra, adj);
+
+    double minQual     = 1;
+    double minQualOpti = 1;
+    
+    std::list<GFace*> faces = region->faces();
+    
+    for (int iter=0; iter < niter+2;iter++){
+      for (std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); ++it){
+	for (std::multimap<GEntity*, std::pair<MVertex*,MFace> >::iterator it2 =
+	       _data.lower_bound(*it); it2 != _data.upper_bound(*it) ; ++it2){
+	  const MFace &f = it2->second.second;
+	  MVertex *v = it2->second.first;
+	  MPyramid p (f.getVertex(0), f.getVertex(1), f.getVertex(2), f.getVertex(3), v);
+	  minQual = std::min(minQual, fabs(p.minSICNShapeMeasure()));
+	  std::vector<MElement*> e = adj[v];
+	  e.push_back(&p);	
+	  v->setEntity (region);
+	  double relax = std::min((double)(iter+1)/niter, 1.0);
+	  //	  printf("%g (%d) --> ",e.size(),p.minSICNShapeMeasure());
+	  _relocateVertexGolden( v, e, relax);
+	  minQualOpti = std::min(minQualOpti, fabs(p.minSICNShapeMeasure()));
+	  //	  printf("%g \n",p.minSICNShapeMeasure());
+	  v->setEntity (*it);
+	}
+      }	
+    }
+    printf("relocation improves %g --> %g\n", minQual, minQualOpti);
+  }
   int buildPyramids(GModel *gm)
   {
     if(empty()) return 0;
@@ -226,9 +261,9 @@ void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numb
 
   //// TEST
   {
-    std::vector<MVertex*>ALL;
-    std::vector<MTetrahedron*> MESH;
-    ALL.insert(ALL.begin(),allBoundingVertices.begin(),allBoundingVertices.end());
+    //    std::vector<MVertex*>ALL;
+    //    std::vector<MTetrahedron*> MESH;
+    //    ALL.insert(ALL.begin(),allBoundingVertices.begin(),allBoundingVertices.end());
     //    delaunayMeshIn3D (ALL,MESH);
     //    exit(1);
   }
@@ -561,6 +596,7 @@ void MeshDelaunayVolumeTetgen(std::vector<GRegion*> &regions)
       return;
     }
     TransferTetgenMesh(gr, in, out, numberedV);
+    sqr.relocateVertices(gr,3);
   }
 
 
@@ -575,6 +611,7 @@ void MeshDelaunayVolumeTetgen(std::vector<GRegion*> &regions)
   // restore the initial set of faces
   gr->set(faces);
 
+  
   // now do insertion of points
   if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_DEL)
     bowyerWatsonFrontalLayers(gr, false);
@@ -590,10 +627,12 @@ void MeshDelaunayVolumeTetgen(std::vector<GRegion*> &regions)
       insertVerticesInRegion(gr,2000000000,true);
     }
   }
-
+  // crete an initial mesh 
+  printf("coucou1\n");
   if (sqr.buildPyramids (gr->model())){
-    RelocateVertices (regions);
+    RelocateVertices (regions, 3);
   }
+  printf("coucou2\n");
 }
 
 #else
diff --git a/Mesh/meshGRegionRelocateVertex.cpp b/Mesh/meshGRegionRelocateVertex.cpp
index 3a4ac88484..cabedbfd06 100644
--- a/Mesh/meshGRegionRelocateVertex.cpp
+++ b/Mesh/meshGRegionRelocateVertex.cpp
@@ -25,7 +25,8 @@ static double objective_function (double xi, MVertex *ver,
     if (lt[i]->getNumVertices () == 4)
       minQual = std::min((lt[i]->minSICNShapeMeasure()), minQual);
     else
-      minQual = std::min(fabs(lt[i]->minSICNShapeMeasure()), minQual);
+      //  minQual = std::min((lt[i]->specialQuality()), minQual);
+      minQual = std::min(fabs(lt[i]->minSICNShapeMeasure())*.2, minQual);
 //    minQual = std::min(lt[i]->minAnisotropyMeasure(), minQual);
   }
   ver->x() = x;
@@ -70,7 +71,7 @@ static int Stopping_Rule(double x0, double x1, double tol)
 
 double Maximize_Quality_Golden_Section( MVertex *ver, 
                                         double xTarget, double yTarget, double zTarget,
-                                        const std::vector<MElement*> &lt , double tol)
+                                        const std::vector<MElement*> &lt , double tol, double &q)
 {
   
   static const double lambda = 0.5 * (sqrt5 - 1.0);
@@ -104,6 +105,7 @@ double Maximize_Quality_Golden_Section( MVertex *ver,
     }
   }
   //  printf("finally : %g %g (%12.5E,%12.5E)\n",a,b,fa,fb);
+  q = std::min(fx1,fx2);
   return a;
 }
 
@@ -155,8 +157,8 @@ double Maximize_Quality_Golden_Section( MVertex *ver, GFace *gf,
   return a;
 }
 
-static void _relocateVertex(MVertex *ver,
-                            const std::vector<MElement*> &lt, double tol)
+void _relocateVertexGolden(MVertex *ver,
+			   const std::vector<MElement*> &lt, double relax , double tol)
 {
   if(ver->onWhat()->dim() != 3) return;
   double x = 0, y=0, z=0;
@@ -174,14 +176,16 @@ static void _relocateVertex(MVertex *ver,
     N += lt[i]->getNumVertices();
   }
 
-  double xi = Maximize_Quality_Golden_Section( ver, x/N, y/N, z/N, lt , tol);
+  double q;
+  double xi = relax * Maximize_Quality_Golden_Section( ver, x/N, y/N, z/N, lt , tol, q);
   ver->x() = (1.-xi) * ver->x() + xi * x/N;
   ver->y() = (1.-xi) * ver->y() + xi * y/N;
   ver->z() = (1.-xi) * ver->z() + xi * z/N;
 }
 
 static double _relocateVertex(GFace* gf, MVertex *ver,
-                              const std::vector<MElement*> &lt, double tol) {
+		       const std::vector<MElement*> &lt,
+		       double tol) {
   if(ver->onWhat()->dim() != 2) return 2.0;
   
   SPoint2 p1(0,0);
@@ -239,22 +243,25 @@ void RelocateVertices (GFace* gf, int niter, double tol) {
 }
 
 
-void RelocateVertices (GRegion* region, double tol) {
+void RelocateVertices (GRegion* region, int niter, double tol) {
   v2t_cont adj;
   buildVertexToElement(region->tetrahedra, adj);
   buildVertexToElement(region->pyramids, adj);
   buildVertexToElement(region->prisms, adj);
   buildVertexToElement(region->hexahedra, adj);
-  v2t_cont::iterator it = adj.begin();
-  while (it != adj.end()){
-    _relocateVertex( it->first, it->second, tol);
-    ++it;
+  for (int i=0;i<niter+2;i++){
+    v2t_cont::iterator it = adj.begin();
+    double relax = std::min((double)(i+1)/niter, 1.0);
+    while (it != adj.end()){
+      _relocateVertexGolden( it->first, it->second, relax, tol);
+      ++it;
+    }
   }
 }
 
-void RelocateVertices (std::vector<GRegion*> &regions, double tol) {
+void RelocateVertices (std::vector<GRegion*> &regions, int niter, double tol) {
   for(unsigned int k = 0; k < regions.size(); k++){
-    RelocateVertices (regions[k], tol);
+    RelocateVertices (regions[k], niter, tol);
   }
 }
 
diff --git a/Mesh/meshGRegionRelocateVertex.h b/Mesh/meshGRegionRelocateVertex.h
index 56c8ac45f7..f267ef73d8 100644
--- a/Mesh/meshGRegionRelocateVertex.h
+++ b/Mesh/meshGRegionRelocateVertex.h
@@ -3,7 +3,10 @@
 #include <vector>
 class GRegion;
 class GFace;
-void RelocateVertices (GRegion* region, double tol = 1.e-2);
-void RelocateVertices (std::vector<GRegion*> &regions, double tol = 1.e-2);
+class MElement;
+void RelocateVertices (GRegion* region, int niter, double tol = 1.e-2);
+void RelocateVertices (std::vector<GRegion*> &regions, int niter, double tol = 1.e-2);
 void RelocateVertices (GFace*, int niter, double tol = 1.e-3);
+void _relocateVertexGolden(MVertex *ver, const std::vector<MElement*> &lt,  double relax, double tol= 1.e-2);
+
 #endif
diff --git a/Solver/dofManager.h b/Solver/dofManager.h
index 1205cc3e59..6a10ab223f 100644
--- a/Solver/dofManager.h
+++ b/Solver/dofManager.h
@@ -357,7 +357,7 @@ class dofManager : public dofManagerBase{
       insertInSparsityPatternLinConst(R, C);
     }
   }
-
+  
   virtual inline void sparsityDof(const std::vector<Dof> &keys){
     for (unsigned int itR=0; itR< keys.size(); itR++){
       for (unsigned int itC=0; itC<keys.size(); itC++){
-- 
GitLab