From d5dcebc0d0b4c73db1f55ea7b51a197dcc864776 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Sun, 23 Nov 2008 09:35:45 +0000
Subject: [PATCH] fix high order mesh for boundary layers

---
 Mesh/HighOrder.cpp            | 94 ++++++++++++++++++-----------------
 Mesh/Refine.cpp               | 14 ++++++
 Mesh/meshGFaceTransfinite.cpp | 55 +++++---------------
 3 files changed, 75 insertions(+), 88 deletions(-)

diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp
index 86726c421c..4806a38d83 100644
--- a/Mesh/HighOrder.cpp
+++ b/Mesh/HighOrder.cpp
@@ -226,6 +226,10 @@ static void getEdgeVertices(GEdge *ge, MElement *ele, std::vector<MVertex*> &ve,
                             int nPts = 1, gmshHighOrderSmoother *displ2D = 0,
                             gmshHighOrderSmoother *displ3D = 0)
 {
+  if(ge->geomType() == GEntity::DiscreteCurve ||
+     ge->geomType() == GEntity::BoundaryLayerCurve)
+    linear = true;
+
   for(int i = 0; i < ele->getNumEdges(); i++){
     MEdge edge = ele->getEdge(i);
     std::pair<MVertex*, MVertex*> p(edge.getMinVertex(), edge.getMaxVertex());
@@ -237,42 +241,37 @@ static void getEdgeVertices(GEdge *ge, MElement *ele, std::vector<MVertex*> &ve,
     }
     else{
       MVertex *v0 = edge.getVertex(0), *v1 = edge.getVertex(1);            
-      double u0 = 0., u1 = 0.;
+      double u0 = 0., u1 = 0., US[100];
       bool reparamOK = true;
-      if(!linear && ge->geomType() != GEntity::DiscreteCurve &&
-         ge->geomType() != GEntity::BoundaryLayerCurve){
+      if(!linear){
         reparamOK &= reparamMeshVertexOnEdge(v0, ge, u0);
-        if (ge->periodic(0) && v1 == ge->getEndVertex()->mesh_vertices[0]){
-          Range<double> par = ge->parBounds(0);
-          u1 = par.high();
-        }         
+        if(ge->periodic(0) && v1 == ge->getEndVertex()->mesh_vertices[0])
+          u1 = ge->parBounds(0).high();
         else
           reparamOK &= reparamMeshVertexOnEdge(v1, ge, u1);
+        if(reparamOK){
+          double relax = 1.;
+          while (1){
+            if(computeEquidistantParameters(ge, u0, u1, nPts + 2, US, relax)) 
+              break;
+            relax /= 2.0;
+            if(relax < 1.e-2) 
+              break;
+          } 
+          if(relax < 1.e-2)
+            Msg::Warning("Failed to compute equidistant parameters (relax = %g)",
+                         relax);
+        }
       }
-      double US[100];
-      if(reparamOK && !linear && ge->geomType() != GEntity::DiscreteCurve){
-        double relax = 1.;
-        while (1){
-          if(computeEquidistantParameters(ge, u0, u1, nPts + 2, US, relax)) 
-            break;
-          relax /= 2.0;
-          if (relax < 1.e-2) 
-            break;
-        } 
-        if (relax < 1.e-2)
-          Msg::Warning("Failed to compute equidistant parameters (relax = %g)",
-                       relax);
-      }
-      std::vector<MVertex*> temp;      
+      std::vector<MVertex*> temp;
       for(int j = 0; j < nPts; j++){
         const double t = (double)(j + 1)/(nPts + 1);
-        double uc = (1. - t) * u0 + t * u1;
+        double uc = (1. - t) * u0 + t * u1; // can be wrong, that's ok
         MVertex *v;
-        if(!reparamOK || linear || ge->geomType() == GEntity::DiscreteCurve || 
-           uc < u0 || uc > u1){ // need to treat periodic curves properly!
+        if(linear || !reparamOK || uc < u0 || uc > u1){ 
+          // we don't have a (valid) parameter on the curve
           SPoint3 pc = edge.interpolate(t);
           v = new MVertex(pc.x(), pc.y(), pc.z(), ge);
-          v->setParameter(0, t);
         }
         else {
           GPoint pc = ge->point(US[j + 1]);
@@ -284,6 +283,7 @@ static void getEdgeVertices(GEdge *ge, MElement *ele, std::vector<MVertex*> &ve,
 	  }
         }
         temp.push_back(v);
+        // this destroys the ordering of the mesh vertices on the edge
         ge->mesh_vertices.push_back(v);
         ve.push_back(v);
       }
@@ -300,6 +300,10 @@ static void getEdgeVertices(GFace *gf, MElement *ele, std::vector<MVertex*> &ve,
                             int nPts = 1, gmshHighOrderSmoother *displ2D = 0,
                             gmshHighOrderSmoother *displ3D = 0)
 {
+  if(gf->geomType() == GEntity::DiscreteSurface ||
+     gf->geomType() == GEntity::BoundaryLayerSurface)
+    linear = true;
+
   for(int i = 0; i < ele->getNumEdges(); i++){
     MEdge edge = ele->getEdge(i);    
     std::pair<MVertex*, MVertex*> p(edge.getMinVertex(), edge.getMaxVertex());
@@ -312,27 +316,26 @@ static void getEdgeVertices(GFace *gf, MElement *ele, std::vector<MVertex*> &ve,
     else{
       MVertex *v0 = edge.getVertex(0), *v1 = edge.getVertex(1);
       SPoint2 p0, p1;
+      double US[100], VS[100];
       bool reparamOK = true;
-      if(!linear && 
-         gf->geomType() != GEntity::DiscreteSurface &&
-         gf->geomType() != GEntity::BoundaryLayerSurface){
+      if(!linear){
         reparamOK = reparamMeshEdgeOnFace(v0, v1, gf, p0, p1);
-      }
-      double US[100], VS[100];
-      if(reparamOK && !linear && gf->geomType() != GEntity::DiscreteSurface){
-        computeEquidistantParameters(gf, p0[0], p1[0], p0[1], p1[1], nPts + 2, US, VS);
+        if(reparamOK)
+          computeEquidistantParameters(gf, p0[0], p1[0], p0[1], p1[1], nPts + 2,
+                                       US, VS);
       }
       std::vector<MVertex*> temp;
       for(int j = 0; j < nPts; j++){
         const double t = (double)(j + 1) / (nPts + 1);
         MVertex *v;
-        if(!reparamOK || linear || gf->geomType() == GEntity::DiscreteSurface){
+        if(linear || !reparamOK){
+          // we don't have (valid) parameters on the surface
           SPoint3 pc = edge.interpolate(t);
           v = new MVertex(pc.x(), pc.y(), pc.z(), gf);
         }
         else{
-          GPoint pc = gf->point(US[j+1], VS[j+1]);
-	  v = new MFaceVertex(pc.x(), pc.y(), pc.z(), gf, US[j+1], VS[j+1]);
+          GPoint pc = gf->point(US[j + 1], VS[j + 1]);
+	  v = new MFaceVertex(pc.x(), pc.y(), pc.z(), gf, US[j + 1], VS[j + 1]);
 	  if (displ3D){
 	    SPoint3 pc2 = edge.interpolate(t);          
 	    displ3D->add(v, SVector3(pc2.x(), pc2.y(), pc2.z()));
@@ -390,6 +393,10 @@ static void getFaceVertices(GFace *gf, MElement *incomplete, MElement *ele,
                             bool linear, int nPts = 1, gmshHighOrderSmoother *displ2D = 0,
                             gmshHighOrderSmoother *displ3D = 0)
 {
+  if(gf->geomType() == GEntity::DiscreteSurface ||
+     gf->geomType() == GEntity::BoundaryLayerSurface)
+    linear = true;
+
   Double_Matrix points;
   int start = 0;
 
@@ -421,19 +428,16 @@ static void getFaceVertices(GFace *gf, MElement *incomplete, MElement *ele,
       std::vector<MVertex*> &vtcs = faceVertices[face];
       SPoint2 pts[20];
       bool reparamOK = true;
-      if(!linear && 
-         gf->geomType() != GEntity::DiscreteSurface &&
-         gf->geomType() != GEntity::BoundaryLayerSurface){
-	for (int k = 0; k < incomplete->getNumVertices(); k++){
+      if(!linear){
+	for(int k = 0; k < incomplete->getNumVertices(); k++)
 	  reparamOK &= reparamMeshVertexOnFace(incomplete->getVertex(k), gf, pts[k]);
-	}
       }
       if(face.getNumVertices() == 3 && nPts > 1){ // tri face
         for(int k = start; k < points.size1(); k++){
           MVertex *v;
           const double t1 = points(k, 0);
           const double t2 = points(k, 1);
-          if(linear || gf->geomType() == GEntity::DiscreteSurface){
+          if(linear){
             SPoint3 pc = face.interpolate(t1, t2);
             v = new MVertex(pc.x(), pc.y(), pc.z(), gf);
           }
@@ -463,7 +467,7 @@ static void getFaceVertices(GFace *gf, MElement *incomplete, MElement *ele,
 	    else{
 	      v = new MVertex(X, Y, Z, gf);
 	    }
-	    if (displ3D){
+	    if(displ3D){
 	      SPoint3 pc2 = face.interpolate(t1, t2);
 	      displ3D->add(v, SVector3(pc2.x(), pc2.y(), pc2.z()));
 	    }	    
@@ -481,7 +485,7 @@ static void getFaceVertices(GFace *gf, MElement *incomplete, MElement *ele,
             // parameters are between -1 and 1
             double t1 = 2. * (double)(j + 1) / (nPts + 1) - 1.;
             double t2 = 2. * (double)(k + 1) / (nPts + 1) - 1.;
-            if(!reparamOK || linear || gf->geomType() == GEntity::DiscreteSurface){
+            if(linear || !reparamOK){
               SPoint3 pc = face.interpolate(t1, t2);
               v = new MVertex(pc.x(), pc.y(), pc.z(), gf);
             }
@@ -697,7 +701,7 @@ static void setHighOrder(GFace *gf, edgeContainer &edgeVertices,
   for(unsigned int i = 0; i < gf->triangles.size(); i++){
     MTriangle *t = gf->triangles[i];
     std::vector<MVertex*> ve, vf;
-    getEdgeVertices(gf, t, ve, edgeVertices, linear, nPts,displ2D,displ3D);
+    getEdgeVertices(gf, t, ve, edgeVertices, linear, nPts, displ2D, displ3D);
     if(nPts == 1){
       triangles2.push_back
         (new MTriangle6(t->getVertex(0), t->getVertex(1), t->getVertex(2),
diff --git a/Mesh/Refine.cpp b/Mesh/Refine.cpp
index 97add1fd40..fd6f212c2a 100644
--- a/Mesh/Refine.cpp
+++ b/Mesh/Refine.cpp
@@ -12,6 +12,17 @@
 #include "GmshMessage.h"
 #include "OS.h"
 
+class MVertexLessParam{
+ public:
+  bool operator()(const MVertex *v1, const MVertex *v2) const
+  {
+    double u1 = 0., u2 = 1.;
+    v1->getParameter(0, u1);
+    v2->getParameter(0, u2);
+    return u1 < u2;
+  }
+};
+
 static void Subdivide(GEdge *ge)
 {
   std::vector<MLine*> lines2;
@@ -25,6 +36,9 @@ static void Subdivide(GEdge *ge)
   }
   ge->lines = lines2;
 
+  // 2nd order meshing destroyed the ordering of the vertices on the edge
+  std::sort(ge->mesh_vertices.begin(), ge->mesh_vertices.end(), 
+            MVertexLessParam());
   for(unsigned int i = 0; i < ge->mesh_vertices.size(); i++)
     ge->mesh_vertices[i]->setPolynomialOrder(1);
   ge->deleteVertexArrays();
diff --git a/Mesh/meshGFaceTransfinite.cpp b/Mesh/meshGFaceTransfinite.cpp
index 1bb68b296d..2a2b30c2a6 100644
--- a/Mesh/meshGFaceTransfinite.cpp
+++ b/Mesh/meshGFaceTransfinite.cpp
@@ -104,10 +104,8 @@ int MeshTransfiniteSurface(GFace *gf)
 
   // get the indices of the interpolation corners as well as the u,v
   // coordinates of all the boundary vertices
-  int iCorner = 0;
-  int N[4] = {0, 0, 0, 0};
-  std::vector<double> U;
-  std::vector<double> V;
+  int iCorner = 0, N[4] = {0, 0, 0, 0};
+  std::vector<double> U, V;
   for(unsigned int i = 0; i < m_vertices.size(); i++){
     MVertex *v = m_vertices[i];
     if(v == corners[0] || v == corners[1] || v == corners[2] || 
@@ -119,38 +117,15 @@ int MeshTransfiniteSurface(GFace *gf)
       }
     }
     SPoint2 param;
-    if(v->onWhat()->dim() == 0){
-      GVertex *gv = (GVertex*)v->onWhat();
-      param = gv->reparamOnFace(gf, 1);
-    }
-    else if(v->onWhat()->dim() == 1){
-      GEdge *ge = (GEdge*)v->onWhat();
-      double UU;
-      v->getParameter(0, UU);
-      param = ge->reparamOnFace(gf, UU, 1);
-    }
-    else{
-      double UU, VV;
-      if(v->onWhat() == gf && v->getParameter(0, UU) && v->getParameter(1, VV))
-        param = SPoint2(UU, VV);
-      else
-        param = gf->parFromPoint(SPoint3(v->x(), v->y(), v->z()));
-    }
-    U.push_back(param.x());
-    V.push_back(param.y());
+    reparamMeshVertexOnFace(v, gf, param);
+    U.push_back(param[0]);
+    V.push_back(param[1]);
   }
 
-  int N1 = N[0];
-  int N2 = N[1];
-  int N3 = N[2];
-  int N4 = N[3];
-
-  int L = N2 - N1;
-  int H = N3 - N2;
-
+  int N1 = N[0], N2 = N[1], N3 = N[2], N4 = N[3];
+  int L = N2 - N1, H = N3 - N2;
   if(corners.size () == 4){
-    int Lb = N4 - N3;
-    int Hb = m_vertices.size() - N4;
+    int Lb = N4 - N3, Hb = m_vertices.size() - N4;
     if(Lb != L || Hb != H){
       Msg::Error("Surface %d cannot be meshed using the transfinite algo", 
 		 gf->tag());
@@ -166,10 +141,8 @@ int MeshTransfiniteSurface(GFace *gf)
     }      
   }
   
-  std::vector<double> lengths_i;
-  std::vector<double> lengths_j;
-  double L_i = 0;
-  double L_j = 0;
+  std::vector<double> lengths_i, lengths_j;
+  double L_i = 0, L_j = 0;
   lengths_i.push_back(0.);
   lengths_j.push_back(0.);
   for(int i = 0; i < L; i++){
@@ -230,12 +203,8 @@ int MeshTransfiniteSurface(GFace *gf)
     }
   }
 
-  double UC1 = U[N1];
-  double UC2 = U[N2];
-  double UC3 = U[N3];
-  double VC1 = V[N1];
-  double VC2 = V[N2];
-  double VC3 = V[N3];
+  double UC1 = U[N1], UC2 = U[N2], UC3 = U[N3];
+  double VC1 = V[N1], VC2 = V[N2], VC3 = V[N3];
 
   //create points using transfinite interpolation
   if(corners.size() == 4){
-- 
GitLab