From 232b3f7a7e325507b68657baa32a9489b2bd1d58 Mon Sep 17 00:00:00 2001
From: Jonathan Lambrechts <jonathan.lambrechts@uclouvain.be>
Date: Fri, 24 Sep 2010 15:16:41 +0000
Subject: [PATCH] missing bits for tets up to order 9

---
 Common/GmshDefines.h        |   8 ++-
 Geo/MElement.cpp            |  10 ++++
 Geo/MTetrahedron.cpp        | 106 ++++++++++++++++++++++++++++++++++++
 Geo/MTetrahedron.h          |  45 ++++++---------
 Mesh/HighOrder.cpp          |  98 +++++++++++++++++++++++----------
 Numeric/polynomialBasis.cpp |  30 ++++++++++
 6 files changed, 238 insertions(+), 59 deletions(-)

diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h
index 64f8d3233c..adc4bae068 100644
--- a/Common/GmshDefines.h
+++ b/Common/GmshDefines.h
@@ -136,8 +136,12 @@
 #define MSH_HEX_64   76
 #define MSH_HEX_125  77
 #define MSH_HEX_196  78
-
-#define MSH_NUM_TYPE 75
+#define MSH_TET_74   79
+#define MSH_TET_100  80
+#define MSH_TET_130  81 
+#define MSH_TET_164  82 
+#define MSH_TET_202  83
+#define MSH_NUM_TYPE 84
 
 // Geometric entities
 #define ENT_NONE     0
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index 48ee94d70d..9e23906295 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -866,6 +866,11 @@ int MElement::getInfoMSH(const int typeMSH, const char **const name)
   case MSH_TET_35 : if(name) *name = "Tetrahedron 35";  return 4 + 18 + 12 + 1;
   case MSH_TET_52 : if(name) *name = "Tetrahedron 52";  return 4 + 24 + 24 + 0;
   case MSH_TET_56 : if(name) *name = "Tetrahedron 56";  return 4 + 24 + 24 + 4;
+  case MSH_TET_84 : if(name) *name = "Tetrahedron 84";  return (7*8*9)/6;
+  case MSH_TET_120 : if(name) *name = "Tetrahedron 120";  return (8*9*10)/6;
+  case MSH_TET_165 : if(name) *name = "Tetrahedron 165";  return (9*10*11)/6;
+  case MSH_TET_220 : if(name) *name = "Tetrahedron 220";  return (10*11*12)/6;
+  case MSH_TET_286 : if(name) *name = "Tetrahedron 286";  return (11*12*13)/6;
   case MSH_HEX_8  : if(name) *name = "Hexahedron 8";    return 8;
   case MSH_HEX_20 : if(name) *name = "Hexahedron 20";   return 8 + 12;
   case MSH_HEX_27 : if(name) *name = "Hexahedron 27";   return 8 + 12 + 6 + 1;
@@ -1024,6 +1029,11 @@ MElement *MElementFactory::create(int type, std::vector<MVertex*> &v,
   case MSH_TET_35: return new MTetrahedronN(v, 4, num, part);
   case MSH_TET_52: return new MTetrahedronN(v, 5, num, part);
   case MSH_TET_56: return new MTetrahedronN(v, 5, num, part);
+  case MSH_TET_84: return new MTetrahedronN(v, 6, num, part);
+  case MSH_TET_120: return new MTetrahedronN(v, 7, num, part);
+  case MSH_TET_165: return new MTetrahedronN(v, 8, num, part);
+  case MSH_TET_220: return new MTetrahedronN(v, 9, num, part);
+  case MSH_TET_286: return new MTetrahedronN(v, 10, num, part);
   case MSH_POLYH_: return new MPolyhedron(v, num, part, owner, parent);
   default:         return 0;
   }
diff --git a/Geo/MTetrahedron.cpp b/Geo/MTetrahedron.cpp
index 145fbd6fa2..cc44a7c6fb 100644
--- a/Geo/MTetrahedron.cpp
+++ b/Geo/MTetrahedron.cpp
@@ -130,6 +130,11 @@ const polynomialBasis* MTetrahedron::getFunctionSpace(int o) const
     case 3: return polynomialBases::find(MSH_TET_20);
     case 4: return polynomialBases::find(MSH_TET_34);
     case 5: return polynomialBases::find(MSH_TET_52);
+    case 6: return polynomialBases::find(MSH_TET_74);
+    case 7: return polynomialBases::find(MSH_TET_100);
+    case 8: return polynomialBases::find(MSH_TET_130);
+    case 9: return polynomialBases::find(MSH_TET_164);
+    case 10: return polynomialBases::find(MSH_TET_202);
     default: Msg::Error("Order %d tetrahedron function space not implemented", order);
     }
   }
@@ -356,3 +361,104 @@ void MTetrahedron::getFaceInfo(const MFace &face, int &ithFace, int &sign, int &
   }
   Msg::Error("Could not get face information for tetrahedron %d", getNum());
 }
+
+static std::vector<std::vector<int> > tetReverseIndices(20);
+
+const std::vector<int> &MTetrahedronN::_getReverseIndices (int order) {
+  if(order>=tetReverseIndices.size())
+    tetReverseIndices.resize(order+1);
+  std::vector<int> &r = tetReverseIndices[order];
+  if (r.size() != 0) return r;
+  //
+  // not the funniest code ever ... (guaranteed correct only up to order 5)
+  //
+  int nb = (order+1)*(order+2)*(order+3)/6;
+  r.resize(nb);
+  int p=0;
+  for (int layerOrder = order; layerOrder>=0; layerOrder-=4) {
+    //principal vertices
+    r[p+0] = p+0; 
+    if (layerOrder ==0) break;
+    r[p+1] = p+2; 
+    r[p+2] = p+1; 
+    r[p+3] = p+3;
+    p+=4;
+    for (int i = 0; i<layerOrder-1; i++) {
+      //E2 reversed switches with E0
+      r[p+i] = p+3*(layerOrder-1)-(i+1);
+      r[p+3*(layerOrder-1)-(i+1)] = p+i;
+      //E1 is reversed
+      r[p+(layerOrder-1)+i] = p+2*(layerOrder-1)-(i+1);
+      //E3 is preserved
+      r[p+3*(layerOrder-1)+i] = p+3*(layerOrder-1)+i;
+      //E4 switches with E5
+      r[p+4*(layerOrder-1)+i] = p+5*(layerOrder-1)+i;
+      r[p+5*(layerOrder-1)+i] = p+4*(layerOrder-1)+i;
+    }
+    p+=6*(layerOrder-1);
+    //F0(=012) switches its nodes 1 and 2
+    for (int of = layerOrder-3; of >= 0; of -= 3) {
+      r[p] = p;
+      if (of == 0) {
+        p+=1;
+        break;
+      }
+      r[p+1] = p+2;
+      r[p+2] = p+1;
+      for (int i = 0; i < of-1; i++) {
+        //switch edges 0 and 2
+        r[p+3+i] = p+3+3*(of-1)-(i+1);
+        r[p+3+3*(of-1)-(i+1)] = p+3+i;
+        //reverse edge 1
+        r[p+3+(of-1)+i] = p+3+2*(of-1)-(i+1);
+      }
+      p += 3*of;
+    }
+    //F1 (=013) reversed switches with F2 (=032)
+    int nf = (layerOrder-2)*(layerOrder-1)/2;
+    for (int of = layerOrder-3; of >= 0; of -= 3) {
+      r[p] = p+nf;
+      r[p+nf] = p;
+      if (of == 0) {
+        p += 1;
+        break;
+      }
+      r[p+1] = p+nf+2;
+      r[p+nf+2] = p+1;
+      r[p+2] = p+nf+1;
+      r[p+nf+1] = p+2;
+      for (int i = 0; i < of-1; i++) {
+        //switch edges 0 and 2
+        r[p+3+i] = p+3+3*(of-1)-(i+1)+nf;
+        r[p+3+3*(of-1)-(i+1)] = p+3+i+nf;
+        r[p+3+i+nf] = p+3+3*(of-1)-(i+1);
+        r[p+3+3*(of-1)-(i+1)+nf] = p+3+i;
+        //reverse edge 1
+        r[p+3+(of-1)+i] = p+3+2*(of-1)-(i+1)+nf;
+        r[p+3+(of-1)+i+nf] = p+3+2*(of-1)-(i+1);
+      }
+      p += 3*of;
+    }
+    p+=nf;
+
+    //F3(=312) switches its nodes 1 and 2
+    for (int of = layerOrder-3; of >= 0; of -= 3) {
+      r[p] = p;
+      if (of == 0) {
+        p += 1;
+        break;
+      }
+      r[p+1] = p+2;
+      r[p+2] = p+1;
+      for (int i = 0; i < of-1; i++) {
+        //switch edges 0 and 2
+        r[p+3+i] = p+3+3*(of-1)-(i+1);
+        r[p+3+3*(of-1)-(i+1)] = p+3+i;
+        //reverse edge 1
+        r[p+3+(of-1)+i] = p+3+2*(of-1)-(i+1);
+      }
+      p += 3*of;
+    }
+  }
+  return r;
+}
diff --git a/Geo/MTetrahedron.h b/Geo/MTetrahedron.h
index dde4c80ff1..6ae19d0f94 100644
--- a/Geo/MTetrahedron.h
+++ b/Geo/MTetrahedron.h
@@ -347,6 +347,7 @@ static int reverseTet34[34] = {0,2,1,3,  // principal vertices
                                31,33,32};// F3 is uvw plane, reverts normal
 
 class MTetrahedronN : public MTetrahedron {
+  const static std::vector<int> &_getReverseIndices(int order);
  protected:
   std::vector<MVertex *> _vs;
   const char _order;
@@ -396,6 +397,11 @@ class MTetrahedronN : public MTetrahedron {
     switch(getTypeForMSH()){
     case MSH_TET_35 : return 1;
     case MSH_TET_56 : return 4;
+    case MSH_TET_84 : return 10;
+    case MSH_TET_120 : return 20;
+    case MSH_TET_165 : return 35;
+    case MSH_TET_220 : return 56;
+    case MSH_TET_286 : return 84;
     default : return 0;
     }    
   }
@@ -407,41 +413,22 @@ class MTetrahedronN : public MTetrahedron {
     if(_order == 4 && _vs.size() + 4 == 35) return MSH_TET_35; 
     if(_order == 5 && _vs.size() + 4 == 56) return MSH_TET_56; 
     if(_order == 5 && _vs.size() + 4 == 52) return MSH_TET_52; 
+    if(_order == 6 && _vs.size() + 4 == 84) return MSH_TET_84; 
+    if(_order == 7 && _vs.size() + 4 == 120) return MSH_TET_120; 
+    if(_order == 8 && _vs.size() + 4 == 165) return MSH_TET_165; 
+    if(_order == 9 && _vs.size() + 4 == 220) return MSH_TET_220; 
+    if(_order == 10 && _vs.size() + 4 == 286) return MSH_TET_286; 
     return 0;
   }
   virtual void revert() 
   {    
     MVertex *tmp;
     tmp = _v[1]; _v[1] = _v[2]; _v[2] = tmp;    
-    switch (getTypeForMSH()) {
-    case MSH_TET_20:
-      {
-        std::vector<MVertex*> inv(16);
-        for (int i=0;i<16;i++) inv[i] = _vs[reverseTet20[i+4]-4];
-        _vs = inv;
-        break;
-      }
-    case MSH_TET_35:
-      {
-        std::vector<MVertex*> inv(31);
-        for (int i=0;i<31;i++) inv[i] = _vs[reverseTet35[i+4]-4];
-        _vs = inv;
-        break;
-      }
-    case MSH_TET_34:
-      {
-        std::vector<MVertex*> inv(30);
-        for (int i=0;i<30;i++) inv[i] = _vs[reverseTet34[i+4]-4];
-        _vs = inv;
-        break;
-      }
-    default:
-      {
-        Msg::Error("Reversion of %d order tetrahedron (type %d) not implemented\n",
-                   _order, getTypeForMSH());
-        break;
-      }
-    }
+    std::vector<MVertex*> inv(_vs.size());
+    std::vector<int> reverseIndices = _getReverseIndices(_order);
+    for (int i = 0; i<_vs.size(); i++)
+      inv[i] = _vs[reverseIndices[i+4]-4];
+    _vs = inv;
   }
   virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n);
   virtual int getNumEdgesRep();
diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp
index 1ad6aaba7c..d10ff18ba3 100644
--- a/Mesh/HighOrder.cpp
+++ b/Mesh/HighOrder.cpp
@@ -479,29 +479,29 @@ static void reorientTrianglePoints(std::vector<MVertex*> &vtcs, int orientation,
                                    bool swap)
 {
   int nbPts = vtcs.size();
-
-  if(nbPts <= 1) return;
-
-  if(nbPts > 3){
-    Msg::Error("Interior face nodes reorientation not supported for order > 4");
-    return;
-  }
-  
+  if (nbPts <= 1) return;
   std::vector<MVertex*> tmp(nbPts);
-
-  // rotation
-  // --- interior "principal vertices"
-  for (int i = 0; i < 3; i++) tmp[(i + orientation) % 3] = vtcs[i];
- 
-  // normal swap
-  if (swap) {
-    // --- interior "principal vertices"
-    vtcs[orientation]           = tmp[orientation];
-    vtcs[(orientation + 1) % 3] = tmp[(orientation + 2) % 3];
-    vtcs[(orientation + 2) % 3] = tmp[(orientation + 1) % 3];
+  int interiorOrder = (int)((sqrt(1+8*nbPts)-3)/2);
+  int pos = 0;
+  for (int o = interiorOrder; o>0; o-=3) {
+    if (swap) {
+      tmp[pos] = vtcs[pos];
+      tmp[pos+1] = vtcs[pos+2];
+      tmp[pos+2] = vtcs[pos+1];
+      for (int i = 0; i < 3*(o-1); i++)
+        tmp[pos+3+i] = vtcs[pos+3*o-i-1];
+    } else {
+      for (int i=0; i< 3*o; i++)
+        tmp[pos+i] = vtcs[pos+i];
+    }
+    for (int i = 0; i < 3; i++) {
+      int ri = (i+orientation)%3;
+      vtcs[pos+ri] = tmp[pos+i];
+      for (int j = 0; j < o-1; j++)
+        vtcs[pos+3+(o-1)*ri+j] = tmp[pos+3+(o-1)*i+j];
+    }
+    pos += 3*o;
   }
-  // no swap
-  else vtcs = tmp;
 } 
 
 // KH: check face orientation wrt element ... 
@@ -512,8 +512,11 @@ static void getFaceVertices(GRegion *gr, MElement *ele, std::vector<MVertex*> &v
 {
   fullMatrix<double> points;
   int start = 0;
-  
   switch (nPts){
+  case 0 :
+  case 1 :
+    // do nothing (e.g. for 2nd order tri faces or for quad faces)
+    break;
   case 2 :
     points = polynomialBases::find(MSH_TRI_10)->points;
     start = 9;
@@ -526,8 +529,28 @@ static void getFaceVertices(GRegion *gr, MElement *ele, std::vector<MVertex*> &v
     points = polynomialBases::find(MSH_TRI_21)->points;
     start = 15;
     break;
+  case 5 :
+    points = polynomialBases::find(MSH_TRI_28)->points;
+    start = 18;
+    break;
+  case 6 :
+    points = polynomialBases::find(MSH_TRI_36)->points;
+    start = 21;
+    break;
+  case 7 :
+    points = polynomialBases::find(MSH_TRI_45)->points;
+    start = 24;
+    break;
+  case 8 :
+    points = polynomialBases::find(MSH_TRI_55)->points;
+    start = 27;
+    break;
+  case 9 :
+    points = polynomialBases::find(MSH_TRI_66)->points;
+    start = 30;
+    break;
   default :  
-    // do nothing (e.g. for 2nd order tri faces or for quad faces)
+    Msg::Error("getFaceVertices not implemented for order %i\n",nPts +1);
     break;
   }
   
@@ -607,18 +630,36 @@ static void getRegionVertices(GRegion *gr, MElement *incomplete, MElement *ele,
   int start = 0;
 
   switch (nPts){
+    case 0:
+    case 1:
+    case 2:
+    // done: return!
+    return;
   case 3 :
     points = polynomialBases::find(MSH_TET_35)->points;
-    start = 34;
     break;
   case 4 :
     points = polynomialBases::find(MSH_TET_56)->points;
-    start = 52;
+    break;
+  case 5 :
+    points = polynomialBases::find(MSH_TET_84)->points;
+    break;
+  case 6 :
+    points = polynomialBases::find(MSH_TET_120)->points;
+    break;
+  case 7 :
+    points = polynomialBases::find(MSH_TET_165)->points;
+    break;
+  case 8 :
+    points = polynomialBases::find(MSH_TET_220)->points;
+    break;
+  case 9 :
+    points = polynomialBases::find(MSH_TET_286)->points;
     break;
   default :  
-    // done: return!
-    return;
+    Msg::Error("getRegionVertices not implemented for order %i\n", nPts+1);
   }
+  start = ((nPts+2)*(nPts+3)*(nPts+4)-(nPts-2)*(nPts-1)*(nPts))/6;
 
   for(int k = start; k < points.size1(); k++){
     MVertex *v;
@@ -782,8 +823,9 @@ static void setHighOrder(GRegion *gr, edgeContainer &edgeVertices,
       ve.insert(ve.end(), vr.begin(), vr.end());
       MTetrahedron* n = new MTetrahedronN(t->getVertex(0), t->getVertex(1), 
                                           t->getVertex(2), t->getVertex(3), ve, nPts + 1);
-      if (!mappingIsInvertible(n))
+      if (!mappingIsInvertible(n)){
         Msg::Warning("Found invalid curved volume element (# %d in list)", i);
+      }
       tetrahedra2.push_back(n);
     }
     delete t;
diff --git a/Numeric/polynomialBasis.cpp b/Numeric/polynomialBasis.cpp
index 85fbc1adb9..629060dedd 100644
--- a/Numeric/polynomialBasis.cpp
+++ b/Numeric/polynomialBasis.cpp
@@ -1159,24 +1159,54 @@ const polynomialBasis *polynomialBases::find(int tag)
     F.points =    gmshGeneratePointsTetrahedron(5, false);
     generate3dFaceClosure(F.closures, 5);
     break;
+  case MSH_TET_74 :
+    F.numFaces = 4;
+    F.monomials = generatePascalSerendipityTetrahedron(6);
+    F.points =    gmshGeneratePointsTetrahedron(6, true);
+    generate3dFaceClosure(F.closures, 6);
+    break;
   case MSH_TET_84 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(6);
     F.points =    gmshGeneratePointsTetrahedron(6, false);
     generate3dFaceClosure(F.closures, 6);
     break;
+  case MSH_TET_100 :
+    F.numFaces = 4;
+    F.monomials = generatePascalSerendipityTetrahedron(7);
+    F.points =    gmshGeneratePointsTetrahedron(7, true);
+    generate3dFaceClosure(F.closures, 7);
+    break;
   case MSH_TET_120 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(7);
     F.points =    gmshGeneratePointsTetrahedron(7, false);
     generate3dFaceClosure(F.closures, 7);
     break;
+  case MSH_TET_130 :
+    F.numFaces = 4;
+    F.monomials = generatePascalSerendipityTetrahedron(8);
+    F.points =    gmshGeneratePointsTetrahedron(8, true);
+    generate3dFaceClosure(F.closures, 8);
+    break;
+  case MSH_TET_164 :
+    F.numFaces = 4;
+    F.monomials = generatePascalSerendipityTetrahedron(9);
+    F.points =    gmshGeneratePointsTetrahedron(9, true);
+    generate3dFaceClosure(F.closures, 9);
+    break;
   case MSH_TET_165 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(8);
     F.points =    gmshGeneratePointsTetrahedron(8, false);
     generate3dFaceClosure(F.closures, 8);
     break;
+  case MSH_TET_202 :
+    F.numFaces = 4;
+    F.monomials = generatePascalSerendipityTetrahedron(10);
+    F.points =    gmshGeneratePointsTetrahedron(10, true);
+    generate3dFaceClosure(F.closures, 10);
+    break;
   case MSH_TET_220 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(9);
-- 
GitLab