From 7f4828f351e153c5ba4192c4977026da39ea13b2 Mon Sep 17 00:00:00 2001
From: Jonathan Lambrechts <jonathan.lambrechts@uclouvain.be>
Date: Thu, 21 Oct 2010 08:45:33 +0000
Subject: [PATCH] move value of shape function at qp of faces to
 polynomialBasis

---
 Numeric/Gauss.cpp           |  12 ++
 Numeric/Gauss.h             |   1 +
 Numeric/polynomialBasis.cpp | 213 +++++++++++++++++++++++++++++++-----
 Numeric/polynomialBasis.h   |  10 +-
 4 files changed, 205 insertions(+), 31 deletions(-)

diff --git a/Numeric/Gauss.cpp b/Numeric/Gauss.cpp
index f599c16298..1f6e54b962 100644
--- a/Numeric/Gauss.cpp
+++ b/Numeric/Gauss.cpp
@@ -1,4 +1,5 @@
 #include "Gauss.h"
+#include "GmshDefines.h"
 #include "Bindings.h"
 static void pts2fullMatrix(int npts, IntPt *pts, fullMatrix<double> &pMatrix, fullMatrix<double> &wMatrix) {
   pMatrix.resize(npts,3);
@@ -52,3 +53,14 @@ void gaussIntegration::getHexahedron(int order, fullMatrix<double> &pts, fullMat
 void gaussIntegration::getPrism(int order, fullMatrix<double> &pts, fullMatrix<double> &weights) {
   pts2fullMatrix(getNGQPriPts(order),getGQPriPts(order),pts,weights);
 }
+void gaussIntegration::get(int elementType, int order, fullMatrix<double> &pts, fullMatrix<double> &weights) {
+  switch (elementType) {
+    case TYPE_TRI : pts2fullMatrix(getNGQTPts(order), getGQTPts(order), pts, weights); break;
+    case TYPE_LIN : pts2fullMatrix(getNGQLPts(order), getGQLPts(order), pts, weights); break;
+    case TYPE_QUA : pts2fullMatrix(getNGQQPts(order), getGQQPts(order), pts, weights); break;
+    case TYPE_TET : pts2fullMatrix(getNGQTetPts(order), getGQTetPts(order), pts, weights); break;
+    case TYPE_HEX : pts2fullMatrix(getNGQHPts(order), getGQHPts(order), pts, weights); break;
+    case TYPE_PRI : pts2fullMatrix(getNGQPriPts(order), getGQPriPts(order), pts, weights); break;
+    default : Msg::Error("No integration rules defined for type %i", elementType);
+  }
+}
diff --git a/Numeric/Gauss.h b/Numeric/Gauss.h
index 06ee437403..6e458f923e 100644
--- a/Numeric/Gauss.h
+++ b/Numeric/Gauss.h
@@ -41,6 +41,7 @@ IntPt *getGQHPts(int order);
 //interface
 class gaussIntegration {
   public:
+  static void get(int elementType, int order, fullMatrix<double> &pts, fullMatrix<double> &weights);
   static void getTriangle(int order, fullMatrix<double> &pts, fullMatrix<double> &weights);
   static void getLine(int order, fullMatrix<double> &pts, fullMatrix<double> &weights);
   static void getQuad(int order, fullMatrix<double> &pts, fullMatrix<double> &weights);
diff --git a/Numeric/polynomialBasis.cpp b/Numeric/polynomialBasis.cpp
index d09a3faed6..97d67876e4 100644
--- a/Numeric/polynomialBasis.cpp
+++ b/Numeric/polynomialBasis.cpp
@@ -10,6 +10,54 @@
 #include "GmshDefines.h"
 #include "GmshMessage.h"
 #include "polynomialBasis.h"
+#include "Gauss.h"
+
+static int getTriangleType (int order) {
+  switch(order) {
+    case 1 : return MSH_TRI_3;
+    case 2 : return MSH_TRI_6;
+    case 3 : return MSH_TRI_10;
+    case 4 : return MSH_TRI_15;
+    case 5 : return MSH_TRI_21;
+    case 6 : return MSH_TRI_28;
+    case 7 : return MSH_TRI_36;
+    case 8 : return MSH_TRI_45;
+    case 9 : return MSH_TRI_55;
+    case 10 : return MSH_TRI_66;
+    default : Msg::Error("triangle order %i unknown", order);
+  }
+}
+static int getQuadType (int order) {
+  switch(order) {
+    case 1 : return MSH_QUA_4;
+    case 2 : return MSH_QUA_9;
+    case 3 : return MSH_QUA_16;
+    case 4 : return MSH_QUA_25;
+    case 5 : return MSH_QUA_36;
+    case 6 : return MSH_QUA_49;
+    case 7 : return MSH_QUA_64;
+    case 8 : return MSH_QUA_81;
+    case 9 : return MSH_QUA_100;
+    case 10 : return MSH_QUA_121;
+    default : Msg::Error("quad order %i unknown", order);
+  }
+}
+static int getLineType (int order) {
+  switch(order) {
+    case 1 : return MSH_LIN_2;
+    case 2 : return MSH_LIN_3;
+    case 3 : return MSH_LIN_4;
+    case 4 : return MSH_LIN_5;
+    case 5 : return MSH_LIN_6;
+    case 6 : return MSH_LIN_7;
+    case 7 : return MSH_LIN_8;
+    case 8 : return MSH_LIN_9;
+    case 9 : return MSH_LIN_10;
+    case 10 : return MSH_LIN_11;
+    default : Msg::Error("line order %i unknown", order);
+  }
+}
+
 
 static fullMatrix<double> generate1DMonomials(int order)
 {
@@ -75,6 +123,41 @@ static fullMatrix<double> generatePascalSerendipityTriangle(int order)
   return monomials;
 }
 
+const fullMatrix<double> &polynomialBasis::getGradientAtFaceIntegrationPoints(int integrationOrder, int closureId) const{
+  std::vector<fullMatrix<double> > &dfAtFace = _dfAtFace[integrationOrder];
+  if (dfAtFace.empty()) {
+    dfAtFace.resize(closures.size());
+    int nbPsi = points.size1();
+    for (int iClosure=0; iClosure< closures.size(); iClosure++) {
+      fullMatrix<double> integrationFace, weight;
+      const polynomialBasis *fsFace = polynomialBases::find(closures[iClosure].type);
+      gaussIntegration::get(fsFace->parentType, integrationOrder, integrationFace, weight);
+      fullMatrix<double> integration(integrationFace.size1(), 3);
+      double f[256];
+      for (int i = 0; i < integrationFace.size1(); i++){
+        fsFace->f(integrationFace(i,0),integrationFace(i,1),integrationFace(i,2),f);
+        for(size_t j=0; j<closures[iClosure].size(); j++) {
+          int jNod = closures[iClosure][j];
+          for(int k = 0; k < points.size2(); k++)
+            integration(i,k) += f[j] * points(jNod,k);
+        }
+      }
+      fullMatrix<double> &v = dfAtFace[iClosure];
+      v.resize(nbPsi, integration.size1()*3);
+      double g[256][3];
+      for (size_t xi = 0; xi< integration.size1(); xi++) {
+        df(integration(xi,0 ), integration(xi,1), integration(xi,2), g);
+        for (int j = 0; j < nbPsi; j++) {
+          v(j, xi*3) = g[j][0];
+          v(j, xi*3+1) = g[j][1];
+          v(j, xi*3+2) = g[j][2];
+        }
+      }
+    }
+  }
+  return dfAtFace[closureId];
+}
+
 // generate all monomials xi^m * eta^n with n and m <= order
 static fullMatrix<double> generatePascalQuad(int order)
 {
@@ -775,12 +858,14 @@ static fullMatrix<double> generateLagrangeMonomialCoefficients
   return coefficient;
 }
 
-static void getFaceClosure(int iFace, int iSign, int iRotate, std::vector<int> &closure,
+static void getFaceClosureTet(int iFace, int iSign, int iRotate, polynomialBasis::closure &closure,
                            int order)
 {
 
   closure.clear();
   closure.resize((order + 1) * (order + 2) / 2);
+  closure.type = getTriangleType(order);
+
   switch (order){
   case 0:
     closure[0] = 0;
@@ -838,26 +923,24 @@ static void getFaceClosure(int iFace, int iSign, int iRotate, std::vector<int> &
     }
     break;
   }
-
 }
 
-static void generate3dFaceClosure(polynomialBasis::clCont &closure, int order)
+static void generateFaceClosureTet(polynomialBasis::clCont &closure, int order)
 {
 
   closure.clear();
   for (int iRotate = 0; iRotate < 3; iRotate++){
     for (int iSign = 1; iSign >= -1; iSign -= 2){
       for (int iFace = 0; iFace < 4; iFace++){
-        std::vector<int> closure_face;
-        getFaceClosure(iFace, iSign, iRotate, closure_face, order);
+        polynomialBasis::closure closure_face;
+        getFaceClosureTet(iFace, iSign, iRotate, closure_face, order);
         closure.push_back(closure_face);
       }
     }
   }
 }
-
 static void getFaceClosurePrism(int iFace, int iSign, int iRotate,
-                                std::vector<int> &closure, int order)
+                                polynomialBasis::closure &closure, int order)
 {
   if (order > 2)
     Msg::Error("FaceClosure not implemented for prisms of order %d",order);
@@ -876,6 +959,7 @@ static void getFaceClosurePrism(int iFace, int iSign, int iRotate,
   // int order2node[5][4] = {{7, 9, 6, -1}, {12, 14, 13, -1}, {6, 10, 12, 8},
   //                         {8, 13, 11, 7}, {9, 11, 14, 10}};
   int nVertex = isTriangle ? 3 : 4;
+  closure.type = isTriangle ? getTriangleType(order) : getQuadType(order);
   for (int i = 0; i < nVertex; ++i){
     int k = (nVertex + (iSign * i) + iRotate) % nVertex;  //- iSign * iRotate
     closure[i] = order1node[iFace][k];
@@ -891,14 +975,14 @@ static void getFaceClosurePrism(int iFace, int iSign, int iRotate,
   }
 }
 
-static void generate3dFaceClosurePrism(polynomialBasis::clCont &closure, int order)
+static void generateFaceClosurePrism(polynomialBasis::clCont &closure, int order)
 {
 
   closure.clear();
   for (int iRotate = 0; iRotate < 4; iRotate++){
     for (int iSign = 1; iSign >= -1; iSign -= 2){
       for (int iFace = 0; iFace < 5; iFace++){
-        std::vector<int> closure_face;
+        polynomialBasis::closure closure_face;
         getFaceClosurePrism(iFace, iSign, iRotate, closure_face, order);
         closure.push_back(closure_face);
       }
@@ -920,6 +1004,7 @@ static void generate2dEdgeClosure(polynomialBasis::clCont &closure, int order,
       closure[j].push_back( nNod + (order-1)*j + i );
       closure[nNod+j].push_back(nNod + (order-1)*(j+1) -i -1);
     }
+    closure[j].type = closure[nNod+j].type = getLineType(order);
   }
 }
 
@@ -929,6 +1014,8 @@ static void generate1dVertexClosure(polynomialBasis::clCont &closure)
   closure.resize(2);
   closure[0].push_back(0);
   closure[1].push_back(1);
+  closure[0].type = MSH_PNT;
+  closure[1].type = MSH_PNT;
 }
 
 std::map<int, polynomialBasis> polynomialBases::fs;
@@ -945,409 +1032,477 @@ const polynomialBasis *polynomialBases::find(int tag)
     F.numFaces = 1;
     F.monomials = generate1DMonomials(0);
     F.points    = generate1DPoints(0);
+    F.parentType = MSH_PNT;
     break;
   case MSH_LIN_2 :
     F.numFaces = 2;
     F.monomials = generate1DMonomials(1);
     F.points    = generate1DPoints(1);
     generate1dVertexClosure(F.closures);
+    F.parentType = TYPE_LIN;
     break;
   case MSH_LIN_3 :
     F.numFaces = 2;
     F.monomials = generate1DMonomials(2);
     F.points    = generate1DPoints(2);
     generate1dVertexClosure(F.closures);
+    F.parentType = TYPE_LIN;
     break;
   case MSH_LIN_4:
     F.numFaces = 2;
     F.monomials = generate1DMonomials(3);
     F.points    = generate1DPoints(3);
+    F.parentType = TYPE_LIN;
     generate1dVertexClosure(F.closures);
     break;
   case MSH_LIN_5:
     F.numFaces = 2;
     F.monomials = generate1DMonomials(4);
     F.points    = generate1DPoints(4);
+    F.parentType = TYPE_LIN;
     generate1dVertexClosure(F.closures);
     break;
   case MSH_LIN_6:
     F.numFaces = 2;
     F.monomials = generate1DMonomials(5);
     F.points    = generate1DPoints(5);
+    F.parentType = TYPE_LIN;
     generate1dVertexClosure(F.closures);
     break;
   case MSH_LIN_7:
     F.numFaces = 2;
     F.monomials = generate1DMonomials(6);
     F.points    = generate1DPoints(6);
+    F.parentType = TYPE_LIN;
     generate1dVertexClosure(F.closures);
     break;
   case MSH_LIN_8:
     F.numFaces = 2;
     F.monomials = generate1DMonomials(7);
     F.points    = generate1DPoints(7);
+    F.parentType = TYPE_LIN;
     generate1dVertexClosure(F.closures);
     break;
   case MSH_LIN_9:
     F.numFaces = 2;
     F.monomials = generate1DMonomials(8);
     F.points    = generate1DPoints(8);
+    F.parentType = TYPE_LIN;
     generate1dVertexClosure(F.closures);
     break;
   case MSH_LIN_10:
     F.numFaces = 2;
     F.monomials = generate1DMonomials(9);
     F.points    = generate1DPoints(9);
+    F.parentType = TYPE_LIN;
     generate1dVertexClosure(F.closures);
     break;
   case MSH_LIN_11:
     F.numFaces = 2;
     F.monomials = generate1DMonomials(10);
     F.points    = generate1DPoints(10);
+    F.parentType = TYPE_LIN;
     generate1dVertexClosure(F.closures);
     break;
   case MSH_TRI_3 :
     F.numFaces = 3;
     F.monomials = generatePascalTriangle(1);
     F.points =    gmshGeneratePointsTriangle(1, false);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 1);
     break;
   case MSH_TRI_6 :
     F.numFaces = 3;
     F.monomials = generatePascalTriangle(2);
     F.points =    gmshGeneratePointsTriangle(2, false);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 2);
     break;
   case MSH_TRI_9 :
     F.numFaces = 3;
     F.monomials = generatePascalSerendipityTriangle(3);
     F.points =    gmshGeneratePointsTriangle(3, true);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 3);
     break;
   case MSH_TRI_10 :
     F.numFaces = 3;
     F.monomials = generatePascalTriangle(3);
     F.points =    gmshGeneratePointsTriangle(3, false);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 3);
     break;
   case MSH_TRI_12 :
     F.numFaces = 3;
     F.monomials = generatePascalSerendipityTriangle(4);
     F.points =    gmshGeneratePointsTriangle(4, true);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 4);
     break;
   case MSH_TRI_15 :
     F.numFaces = 3;
     F.monomials = generatePascalTriangle(4);
     F.points =    gmshGeneratePointsTriangle(4, false);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 4);
     break;
   case MSH_TRI_15I :
     F.numFaces = 3;
     F.monomials = generatePascalSerendipityTriangle(5);
     F.points =    gmshGeneratePointsTriangle(5, true);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 5);
     break;
   case MSH_TRI_21 :
     F.numFaces = 3;
     F.monomials = generatePascalTriangle(5);
     F.points =    gmshGeneratePointsTriangle(5, false);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 5);
     break;
   case MSH_TRI_28 :
     F.numFaces = 3;
     F.monomials = generatePascalTriangle(6);
     F.points =    gmshGeneratePointsTriangle(6, false);    
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 6);
     break;
   case MSH_TRI_36 :
     F.numFaces = 3;
     F.monomials = generatePascalTriangle(7);
     F.points =    gmshGeneratePointsTriangle(7, false);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 7);
     break;
   case MSH_TRI_45 :
     F.numFaces = 3;
     F.monomials = generatePascalTriangle(8);
     F.points =    gmshGeneratePointsTriangle(8, false);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 8);
     break;
   case MSH_TRI_55 :
     F.numFaces = 3;
     F.monomials = generatePascalTriangle(9);
     F.points =    gmshGeneratePointsTriangle(9, false);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 9);
     break;
   case MSH_TRI_66 :
     F.numFaces = 3;
     F.monomials = generatePascalTriangle(10);
     F.points =    gmshGeneratePointsTriangle(10, false);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 10);
     break;
   case MSH_TRI_18 :
     F.numFaces = 3;
     F.monomials = generatePascalSerendipityTriangle(6);
     F.points =    gmshGeneratePointsTriangle(6, true);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 6);
     break;
   case MSH_TRI_21I :
     F.numFaces = 3;
     F.monomials = generatePascalSerendipityTriangle(7);
     F.points =    gmshGeneratePointsTriangle(7, true);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 7);
     break;
   case MSH_TRI_24 :
     F.numFaces = 3;
     F.monomials = generatePascalSerendipityTriangle(8);
     F.points =    gmshGeneratePointsTriangle(8, true);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 8);
     break;
   case MSH_TRI_27 :
     F.numFaces = 3;
     F.monomials = generatePascalSerendipityTriangle(9);
     F.points =    gmshGeneratePointsTriangle(9, true);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 9);
     break;
   case MSH_TRI_30 :
     F.numFaces = 3;
     F.monomials = generatePascalSerendipityTriangle(10);
     F.points =    gmshGeneratePointsTriangle(10, true);
+    F.parentType = TYPE_TRI;
     generate2dEdgeClosure(F.closures, 10);
     break;
   case MSH_TET_4 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(1);
     F.points =    gmshGeneratePointsTetrahedron(1, false);
-    generate3dFaceClosure(F.closures, 1);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 1);
     break;
   case MSH_TET_10 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(2);
     F.points =    gmshGeneratePointsTetrahedron(2, false);
-    generate3dFaceClosure(F.closures, 2);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 2);
     break;
   case MSH_TET_20 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(3);
     F.points =    gmshGeneratePointsTetrahedron(3, false);
-    generate3dFaceClosure(F.closures, 3);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 3);
     break;
   case MSH_TET_35 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(4);
     F.points =    gmshGeneratePointsTetrahedron(4, false);
-    generate3dFaceClosure(F.closures, 4);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 4);
     break;
   case MSH_TET_34 :
     F.numFaces = 4;
     F.monomials = generatePascalSerendipityTetrahedron(4);
     F.points =    gmshGeneratePointsTetrahedron(4, true);
-    generate3dFaceClosure(F.closures, 4);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 4);
     break;
   case MSH_TET_52 :
     F.numFaces = 4;
     F.monomials = generatePascalSerendipityTetrahedron(5);
     F.points =    gmshGeneratePointsTetrahedron(5, true);
-    generate3dFaceClosure(F.closures, 5);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 5);
     break;
   case MSH_TET_56 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(5);
     F.points =    gmshGeneratePointsTetrahedron(5, false);
-    generate3dFaceClosure(F.closures, 5);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 5);
     break;
   case MSH_TET_74 :
     F.numFaces = 4;
     F.monomials = generatePascalSerendipityTetrahedron(6);
     F.points =    gmshGeneratePointsTetrahedron(6, true);
-    generate3dFaceClosure(F.closures, 6);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 6);
     break;
   case MSH_TET_84 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(6);
     F.points =    gmshGeneratePointsTetrahedron(6, false);
-    generate3dFaceClosure(F.closures, 6);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 6);
     break;
   case MSH_TET_100 :
     F.numFaces = 4;
     F.monomials = generatePascalSerendipityTetrahedron(7);
     F.points =    gmshGeneratePointsTetrahedron(7, true);
-    generate3dFaceClosure(F.closures, 7);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 7);
     break;
   case MSH_TET_120 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(7);
     F.points =    gmshGeneratePointsTetrahedron(7, false);
-    generate3dFaceClosure(F.closures, 7);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 7);
     break;
   case MSH_TET_130 :
     F.numFaces = 4;
     F.monomials = generatePascalSerendipityTetrahedron(8);
     F.points =    gmshGeneratePointsTetrahedron(8, true);
-    generate3dFaceClosure(F.closures, 8);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 8);
     break;
   case MSH_TET_164 :
     F.numFaces = 4;
     F.monomials = generatePascalSerendipityTetrahedron(9);
     F.points =    gmshGeneratePointsTetrahedron(9, true);
-    generate3dFaceClosure(F.closures, 9);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 9);
     break;
   case MSH_TET_165 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(8);
     F.points =    gmshGeneratePointsTetrahedron(8, false);
-    generate3dFaceClosure(F.closures, 8);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 8);
     break;
   case MSH_TET_202 :
     F.numFaces = 4;
     F.monomials = generatePascalSerendipityTetrahedron(10);
     F.points =    gmshGeneratePointsTetrahedron(10, true);
-    generate3dFaceClosure(F.closures, 10);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 10);
     break;
   case MSH_TET_220 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(9);
     F.points =    gmshGeneratePointsTetrahedron(9, false);
-    generate3dFaceClosure(F.closures, 9);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 9);
     break;
   case MSH_TET_286 :
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(10);
     F.points =    gmshGeneratePointsTetrahedron(10, false);
-    generate3dFaceClosure(F.closures, 10);
+    F.parentType = TYPE_TET;
+    generateFaceClosureTet(F.closures, 10);
     break;
   case MSH_QUA_4 :
     F.numFaces = 4;
     F.monomials = generatePascalQuad(1);
     F.points =    gmshGeneratePointsQuad(1,false);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 1, 4);
     break;
   case MSH_QUA_9 :
     F.numFaces = 4;
     F.monomials = generatePascalQuad(2);
     F.points =    gmshGeneratePointsQuad(2,false);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 2, 4);
     break;
   case MSH_QUA_16 :
     F.numFaces = 4;
     F.monomials = generatePascalQuad(3);
     F.points =    gmshGeneratePointsQuad(3,false);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 3, 4);
     break;
   case MSH_QUA_25 :
     F.numFaces = 4;
     F.monomials = generatePascalQuad(4);
     F.points =    gmshGeneratePointsQuad(4,false);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 4, 4);
     break;
   case MSH_QUA_36 :
     F.numFaces = 4;
     F.monomials = generatePascalQuad(5);
     F.points =    gmshGeneratePointsQuad(5,false);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 5, 4);
     break;
   case MSH_QUA_49 :
     F.numFaces = 4;
     F.monomials = generatePascalQuad(6);
     F.points =    gmshGeneratePointsQuad(6,false);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 6, 4);
     break;
   case MSH_QUA_64 :
     F.numFaces = 4;
     F.monomials = generatePascalQuad(7);
     F.points =    gmshGeneratePointsQuad(7,false);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 7, 4);
     break;
   case MSH_QUA_81 :
     F.numFaces = 4;
     F.monomials = generatePascalQuad(8);
     F.points =    gmshGeneratePointsQuad(8,false);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 8, 4);
     break;
   case MSH_QUA_100 :
     F.numFaces = 4;
     F.monomials = generatePascalQuad(9);
     F.points =    gmshGeneratePointsQuad(9,false);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 9, 4);
     break;
   case MSH_QUA_121 :
     F.numFaces = 4;
     F.monomials = generatePascalQuad(10);
     F.points =    gmshGeneratePointsQuad(10,false);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 10, 4);
     break;
   case MSH_QUA_8 :
     F.numFaces = 4;
     F.monomials = generatePascalQuadSerendip(2);
     F.points =    gmshGeneratePointsQuad(2,true);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 2, 4);
     break;
   case MSH_QUA_12 :
     F.numFaces = 4;
     F.monomials = generatePascalQuadSerendip(3);
     F.points =    gmshGeneratePointsQuad(3,true);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 3, 4);
     break;
   case MSH_QUA_16I :
     F.numFaces = 4;
     F.monomials = generatePascalQuadSerendip(4);
     F.points =    gmshGeneratePointsQuad(4,true);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 4, 4);
     break;
   case MSH_QUA_20 :
     F.numFaces = 4;
     F.monomials = generatePascalQuadSerendip(5);
     F.points =    gmshGeneratePointsQuad(5,true);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 5, 4);
     break;
   case MSH_QUA_24 :
     F.numFaces = 4;
     F.monomials = generatePascalQuadSerendip(6);
     F.points =    gmshGeneratePointsQuad(6,true);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 6, 4);
     break;
   case MSH_QUA_28 :
     F.numFaces = 4;
     F.monomials = generatePascalQuadSerendip(7);
     F.points =    gmshGeneratePointsQuad(7,true);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 7, 4);
     break;
   case MSH_QUA_32 :
     F.numFaces = 4;
     F.monomials = generatePascalQuadSerendip(8);
     F.points =    gmshGeneratePointsQuad(8,true);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 8, 4);
     break;
   case MSH_QUA_36I :
     F.numFaces = 4;
     F.monomials = generatePascalQuadSerendip(9);
     F.points =    gmshGeneratePointsQuad(9,true);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 9, 4);
     break;
   case MSH_QUA_40 :
     F.numFaces = 4;
     F.monomials = generatePascalQuadSerendip(10);
     F.points =    gmshGeneratePointsQuad(10,true);
+    F.parentType = TYPE_QUA;
     generate2dEdgeClosure(F.closures, 10, 4);
     break;
   case MSH_PRI_6 :
     F.numFaces = 5;
     F.monomials = generatePascalPrism(1);
     F.points =    gmshGeneratePointsPrism(1, false);
-    generate3dFaceClosurePrism(F.closures, 1);
+    F.parentType = TYPE_PRI;
+    generateFaceClosurePrism(F.closures, 1);
     break;
   case MSH_PRI_18 :
     F.numFaces = 5;
     F.monomials = generatePascalPrism(2);
     F.points =    gmshGeneratePointsPrism(2, false);
-    generate3dFaceClosurePrism(F.closures, 2);
+    F.parentType = TYPE_PRI;
+    generateFaceClosurePrism(F.closures, 2);
     break;
   default :
     Msg::Error("Unknown function space %d: reverting to TET_4", tag);
     F.numFaces = 4;
     F.monomials = generatePascalTetrahedron(1);
+    F.parentType = TYPE_TET;
     F.points =    gmshGeneratePointsTetrahedron(1, false);
-    generate3dFaceClosure(F.closures, 1);
+    generateFaceClosureTet(F.closures, 1);
     break;
   }
   F.type = tag;
diff --git a/Numeric/polynomialBasis.h b/Numeric/polynomialBasis.h
index a3fb4edf1b..566a224ad5 100644
--- a/Numeric/polynomialBasis.h
+++ b/Numeric/polynomialBasis.h
@@ -71,10 +71,15 @@ class binding;
 // should be extended to other elements like hexes
 class polynomialBasis
 {
+  mutable std::map<int,std::vector<fullMatrix<double> > > _dfAtFace; //integrationOrder, closureId => df/dXi
  public:
   //for now the only implemented polynomial basis are nodal poly basis, we use the type of the corresponding gmsh element as type
-  int type;
-  typedef std::vector<std::vector<int> > clCont;
+  int type, parentType;
+  class closure : public std::vector<int> {
+    public: 
+    int type;
+  };
+  typedef std::vector<closure> clCont;
   clCont closures;
   fullMatrix<double> points;
   fullMatrix<double> monomials;
@@ -262,6 +267,7 @@ class polynomialBasis
       break;
     }
   }
+  const fullMatrix<double> &getGradientAtFaceIntegrationPoints(int integrationOrder, int closureId) const;
   static void registerBindings(binding *b);
 };
 
-- 
GitLab