From 542bdc6f1deea0c526b25e2ac364db7a0f57a666 Mon Sep 17 00:00:00 2001
From: Amaury Johnan <amjohnen@gmail.com>
Date: Thu, 31 Jul 2014 12:35:28 +0000
Subject: [PATCH] (1) Faster JacobianBasis construction: construct bezierBasis
 only if necessary (2) Make pyramid's points and monomials ready for
 differenciation of subdivision-ready and optimization-ready basis (3)
 Correction number lagragian bezier coeff for pyramids p1

---
 Numeric/BasisFactory.h       |   9 +-
 Numeric/JacobianBasis.cpp    |  62 +++++++------
 Numeric/JacobianBasis.h      |  19 ++--
 Numeric/MetricBasis.cpp      |  16 ++--
 Numeric/bezierBasis.cpp      | 106 ++++++++++-----------
 Numeric/bezierBasis.h        |  20 ++--
 Numeric/pointsGenerators.cpp | 175 +++++++++++++++++++++++++++++++++--
 Numeric/pointsGenerators.h   |   9 +-
 Plugin/AnalyseCurvedMesh.cpp |  25 ++---
 Plugin/AnalyseCurvedMesh.h   |   3 -
 10 files changed, 305 insertions(+), 139 deletions(-)

diff --git a/Numeric/BasisFactory.h b/Numeric/BasisFactory.h
index 6c4e4e110c..82b5c3731a 100644
--- a/Numeric/BasisFactory.h
+++ b/Numeric/BasisFactory.h
@@ -9,6 +9,7 @@
 #include "MElement.h"
 #include "MPyramid.h"
 #include "nodalBasis.h"
+#include "bezierBasis.h"
 #include "JacobianBasis.h"
 #include "MetricBasis.h"
 
@@ -33,10 +34,10 @@ class BasisFactory
 
   static const GradientBasis* getGradientBasis(int tag, int order);
   static const bezierBasis* getBezierBasis(int parentTag, int order);
-  static inline const bezierBasis* getBezierBasis(int tag) {
-      return getBezierBasis(ElementType::ParentTypeFromTag(tag),
-                            ElementType::OrderFromTag(tag) );
-    }
+  static const bezierBasis* getBezierBasis(int tag) {
+    return getBezierBasis(ElementType::ParentTypeFromTag(tag),
+                          ElementType::OrderFromTag(tag) );
+  }
 
   static void clearAll();
 };
diff --git a/Numeric/JacobianBasis.cpp b/Numeric/JacobianBasis.cpp
index ba641a7ccc..0d1b868377 100644
--- a/Numeric/JacobianBasis.cpp
+++ b/Numeric/JacobianBasis.cpp
@@ -3,6 +3,8 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh@geuz.org>.
 
+#include "JacobianBasis.h"
+
 #include "GmshDefines.h"
 #include "GmshMessage.h"
 
@@ -88,15 +90,11 @@ void GradientBasis::getGradientsFromNodes(const fullMatrix<double> &nodes,
   if (dxyzdZ) gradShapeMatZ.mult(nodes, *dxyzdZ);
 }
 
-JacobianBasis::JacobianBasis(int tag, int jacOrder)
+JacobianBasis::JacobianBasis(int tag, int jacOrder) :
+    _bezier(NULL), _tag(tag), _dim(ElementType::DimensionFromTag(tag)),
+    _jacOrder(jacOrder >= 0 ? jacOrder : JacobianBasis::jacobianOrder(tag))
 {
   const int parentType = ElementType::ParentTypeFromTag(tag);
-  const int order = ElementType::OrderFromTag(tag);
-  int jacobianOrder;
-  if (jacOrder < 0)
-    jacobianOrder = JacobianBasis::jacobianOrder(parentType, order);
-  else
-    jacobianOrder = jacOrder;
   const int primJacobianOrder = JacobianBasis::jacobianOrder(parentType, 1);
 
   fullMatrix<double> lagPoints;                                  // Sampling points
@@ -106,25 +104,25 @@ JacobianBasis::JacobianBasis(int tag, int jacOrder)
       lagPoints = gmshGeneratePointsLine(0);
       break;
     case TYPE_LIN :
-      lagPoints = gmshGeneratePointsLine(jacobianOrder);
+      lagPoints = gmshGeneratePointsLine(_jacOrder);
       break;
     case TYPE_TRI :
-      lagPoints = gmshGeneratePointsTriangle(jacobianOrder,false);
+      lagPoints = gmshGeneratePointsTriangle(_jacOrder,false);
       break;
     case TYPE_QUA :
-      lagPoints = gmshGeneratePointsQuadrangle(jacobianOrder,false);
+      lagPoints = gmshGeneratePointsQuadrangle(_jacOrder,false);
       break;
     case TYPE_TET :
-      lagPoints = gmshGeneratePointsTetrahedron(jacobianOrder,false);
+      lagPoints = gmshGeneratePointsTetrahedron(_jacOrder,false);
       break;
     case TYPE_PRI :
-      lagPoints = gmshGeneratePointsPrism(jacobianOrder,false);
+      lagPoints = gmshGeneratePointsPrism(_jacOrder,false);
       break;
     case TYPE_HEX :
-      lagPoints = gmshGeneratePointsHexahedron(jacobianOrder,false);
+      lagPoints = gmshGeneratePointsHexahedron(_jacOrder,false);
       break;
     case TYPE_PYR :
-      lagPoints = generateJacPointsPyramid(jacobianOrder);
+      lagPoints = generateJacPointsPyramid(_jacOrder);
       break;
     default :
       Msg::Error("Unknown Jacobian function space for element tag %d", tag);
@@ -132,11 +130,8 @@ JacobianBasis::JacobianBasis(int tag, int jacOrder)
   }
   numJacNodes = lagPoints.size1();
 
-  // Store Bezier basis
-  bezier = BasisFactory::getBezierBasis(parentType, jacobianOrder);
-
   // Store shape function gradients of mapping at Jacobian nodes
-  _gradBasis = BasisFactory::getGradientBasis(tag, jacobianOrder);
+  _gradBasis = BasisFactory::getGradientBasis(tag, _jacOrder);
 
   // Compute matrix for lifting from primary Jacobian basis to Jacobian basis
   int primJacType = ElementType::getTag(parentType, primJacobianOrder, false);
@@ -203,6 +198,14 @@ JacobianBasis::JacobianBasis(int tag, int jacOrder)
   }
 }
 
+const bezierBasis* JacobianBasis::getBezier() const {
+  if (_bezier) return _bezier;
+  const int parentType = ElementType::ParentTypeFromTag(_tag);
+  const_cast<JacobianBasis*>(this)->_bezier =
+      BasisFactory::getBezierBasis(parentType, _jacOrder);
+  return _bezier;
+}
+
 // Computes (unit) normals to straight line element at barycenter (with norm of gradient as return value)
 double JacobianBasis::getPrimNormals1D(const fullMatrix<double> &nodesXYZ, fullMatrix<double> &result) const
 {
@@ -286,10 +289,7 @@ inline void JacobianBasis::getJacobianGeneral(int nJacNodes, const fullMatrix<do
                                               const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
                                               const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const
 {
-
-  const int dim = bezier->getDim();
-
-  switch (dim) {
+  switch (_dim) {
 
     case 0 : {
       for (int i = 0; i < nJacNodes; i++) jacobian(i) = 1.;
@@ -383,8 +383,7 @@ inline void JacobianBasis::getJacobianGeneral(int nJacNodes, const fullMatrix<do
                                               const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
                                               const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const
 {
-
-  switch (bezier->getDim()) {
+  switch (_dim) {
 
     case 0 : {
       const int numEl = nodesX.size2();
@@ -508,8 +507,7 @@ void JacobianBasis::getSignedJacAndGradientsGeneral(int nJacNodes, const fullMat
                                                     const fullMatrix<double> &normals,
                                                     fullMatrix<double> &JDJ) const
 {
-
-  switch (bezier->getDim()) {
+  switch (_dim) {
 
     case 0 : {
       for (int i = 0; i < nJacNodes; i++) {
@@ -654,9 +652,9 @@ void JacobianBasis::getMetricMinAndGradients(const fullMatrix<double> &nodesXYZ,
       gradLambdaJ(l, i + 1 * numMapNodes) = aetaxi * dPhidX + aetaeta * dPhidY;
     }
   }
-
 }
 
+// Research purpose (to be removed ?)
 void JacobianBasis::interpolate(const fullVector<double> &jacobian,
                                 const fullMatrix<double> &uvw,
                                 fullMatrix<double> &result,
@@ -671,7 +669,7 @@ void JacobianBasis::interpolate(const fullVector<double> &jacobian,
   else
     lag2Bez(jacobian, bez);
 
-  bezier->interpolate(bezM, uvw, result);
+  getBezier()->interpolate(bezM, uvw, result);
 }
 
 fullMatrix<double> JacobianBasis::generateJacMonomialsPyramid(int order)
@@ -683,6 +681,7 @@ fullMatrix<double> JacobianBasis::generateJacMonomialsPyramid(int order)
     fullMatrix<double> prox, quad = gmshGenerateMonomialsQuadrangle(2);
     prox.setAsProxy(monomials, 0, 2);
     prox.setAll(quad);
+    // monomials has been initialized to 0, so third column is ok
     return monomials;
   }
 
@@ -789,6 +788,13 @@ fullMatrix<double> JacobianBasis::generateJacPointsPyramid(int order)
   return points;
 }
 
+int JacobianBasis::jacobianOrder(int tag)
+{
+  const int parentType = ElementType::ParentTypeFromTag(tag);
+  const int order = ElementType::OrderFromTag(tag);
+  return jacobianOrder(parentType, order);
+}
+
 int JacobianBasis::jacobianOrder(int parentType, int order)
 {
   switch (parentType) {
diff --git a/Numeric/JacobianBasis.h b/Numeric/JacobianBasis.h
index 9701cec635..894b088ce3 100644
--- a/Numeric/JacobianBasis.h
+++ b/Numeric/JacobianBasis.h
@@ -33,6 +33,10 @@ class GradientBasis {
 class JacobianBasis {
  private:
   const GradientBasis *_gradBasis;
+  const bezierBasis *_bezier;
+
+  const int _tag, _dim, _jacOrder;
+
   fullMatrix<double> gradShapeMatXFast, gradShapeMatYFast, gradShapeMatZFast;
   fullVector<double> primGradShapeBarycenterX, primGradShapeBarycenterY, primGradShapeBarycenterZ;
   fullMatrix<double> matrixPrimJac2Jac;                                   // Lifts Lagrange basis of primary Jac. to Lagrange basis of Jac.
@@ -42,19 +46,16 @@ class JacobianBasis {
   int numJacNodesFast;
 
  public :
-  const bezierBasis *bezier;
-
   JacobianBasis(int tag, int jacOrder = -1);
 
   // Get methods
+  inline int getJacOrder() const { return _jacOrder; }
   inline int getNumJacNodes() const { return numJacNodes; }
   inline int getNumJacNodesFast() const { return numJacNodesFast; }
   inline int getNumMapNodes() const { return numMapNodes; }
   inline int getNumPrimJacNodes() const { return numPrimJacNodes; }
   inline int getNumPrimMapNodes() const { return numPrimMapNodes; }
-  inline int getNumDivisions() const { return bezier->getNumDivision(); }
-  inline int getNumSubNodes() const { return bezier->subDivisor.size1(); }
-  inline int getNumLagCoeff() const { return bezier->getNumLagCoeff(); }
+  const bezierBasis* getBezier() const;
 
   // Jacobian evaluation methods
   double getPrimNormals1D(const fullMatrix<double> &nodesXYZ, fullMatrix<double> &result) const;
@@ -99,23 +100,21 @@ class JacobianBasis {
   }
   //
   inline void lag2Bez(const fullVector<double> &jac, fullVector<double> &bez) const {
-    bezier->matrixLag2Bez.mult(jac,bez);
+    getBezier()->matrixLag2Bez.mult(jac,bez);
   }
   inline void lag2Bez(const fullMatrix<double> &jac, fullMatrix<double> &bez) const {
-    bezier->matrixLag2Bez.mult(jac,bez);
+    getBezier()->matrixLag2Bez.mult(jac,bez);
   }
   inline void primJac2Jac(const fullVector<double> &primJac, fullVector<double> &jac) const {
     matrixPrimJac2Jac.mult(primJac,jac);
   }
-  inline void subdivideBezierCoeff(const fullVector<double> &bez, fullVector<double> &result) const {
-    bezier->subDivisor.mult(bez,result);
-  }
   //
   void interpolate(const fullVector<double> &jacobian,
                    const fullMatrix<double> &uvw,
                    fullMatrix<double> &result, bool areBezier = false) const;
 
   //
+  static int jacobianOrder(int tag);
   static int jacobianOrder(int parentType, int order);
   static fullMatrix<double> generateJacMonomialsPyramid(int order);
   static fullMatrix<double> generateJacPointsPyramid(int order);
diff --git a/Numeric/MetricBasis.cpp b/Numeric/MetricBasis.cpp
index c94a3923ba..093a1d3d86 100644
--- a/Numeric/MetricBasis.cpp
+++ b/Numeric/MetricBasis.cpp
@@ -443,7 +443,7 @@ double MetricBasis::getBoundRmin(MElement *el, MetricData *&md, fullMatrix<doubl
 
 void MetricBasis::_fillInequalities(int metricOrder)
 {
-  int dimSimplex = _bezier->_dimSimplex;
+  int dimSimplex = _bezier->getDimSimplex();
   int dim = _bezier->getDim();
   fullMatrix<int> exp(_bezier->_exponents.size1(), _bezier->_exponents.size2());
   for (int i = 0; i < _bezier->_exponents.size1(); ++i) {
@@ -533,11 +533,11 @@ void MetricBasis::_fillInequalities(int metricOrder)
     }
   }
 
-  exp.resize(_jacobian->bezier->_exponents.size1(),
-             _jacobian->bezier->_exponents.size2());
-  for (int i = 0; i < _jacobian->bezier->_exponents.size1(); ++i) {
-    for (int j = 0; j < _jacobian->bezier->_exponents.size2(); ++j) {
-      exp(i, j) = static_cast<int>(_jacobian->bezier->_exponents(i, j) + .5);
+  exp.resize(_jacobian->getBezier()->_exponents.size1(),
+             _jacobian->getBezier()->_exponents.size2());
+  for (int i = 0; i < _jacobian->getBezier()->_exponents.size1(); ++i) {
+    for (int j = 0; j < _jacobian->getBezier()->_exponents.size2(); ++j) {
+      exp(i, j) = static_cast<int>(_jacobian->getBezier()->_exponents(i, j) + .5);
     }
   }
   int njac = _jacobian->getNumJacNodes();
@@ -1060,7 +1060,7 @@ double MetricBasis::_subdivideForRmin(
   const int numCoeff = md->_metcoeffs->size2();
   const int numMetPnts = md->_metcoeffs->size1();
   const int numJacPnts = md->_jaccoeffs->size();
-  const int numSub = _jacobian->getNumDivisions();
+  const int numSub = _bezier->getNumDivision();
   subdomains.push(md);
 
   static unsigned int aa = 200;
@@ -1082,7 +1082,7 @@ double MetricBasis::_subdivideForRmin(
     subcoeffs = new fullMatrix<double>(numSub*numMetPnts, numCoeff);
     subjac = new fullVector<double>(numSub*numJacPnts);
     _bezier->subDivisor.mult(*current->_metcoeffs, *subcoeffs);
-    _jacobian->subdivideBezierCoeff(*current->_jaccoeffs, *subjac);
+    _jacobian->getBezier()->subDivisor.mult(*current->_jaccoeffs, *subjac);
     int depth = current->_depth;
     int num = current->_num;
       //Msg::Info("d %d RminBez %g / %g", depth, current->_RminBez, RminLag);
diff --git a/Numeric/bezierBasis.cpp b/Numeric/bezierBasis.cpp
index 0fd6fdb956..edf3952873 100644
--- a/Numeric/bezierBasis.cpp
+++ b/Numeric/bezierBasis.cpp
@@ -13,6 +13,7 @@
 #include "BasisFactory.h"
 #include "Numeric.h"
 
+
 namespace {
 // Sub Control Points
 std::vector< fullMatrix<double> > generateSubPointsLine(int order)
@@ -229,8 +230,8 @@ std::vector< fullMatrix<double> > generateSubPointsPyr(int order)
     std::vector< fullMatrix<double> > subPoints(4);
     fullMatrix<double> prox;
 
-    subPoints[0] = JacobianBasis::generateJacMonomialsPyramid(0);
-    subPoints[0].scale(.5/(order+2));
+    subPoints[0] = gmshGenerateMonomialsPyramidGeneral(false, 2, 0);
+    subPoints[0].scale(.5/2);
 
     subPoints[1].copy(subPoints[0]);
     prox.setAsProxy(subPoints[1], 0, 1);
@@ -250,7 +251,7 @@ std::vector< fullMatrix<double> > generateSubPointsPyr(int order)
     std::vector< fullMatrix<double> > subPoints(8);
     fullMatrix<double> ref, prox;
 
-    subPoints[0] = JacobianBasis::generateJacMonomialsPyramid(order);
+    subPoints[0] = gmshGenerateMonomialsPyramidGeneral(false, order+2, order);
     subPoints[0].scale(.5/(order+2));
 
     subPoints[1].copy(subPoints[0]);
@@ -449,7 +450,7 @@ void bezierBasis::interpolate(const fullMatrix<double> &coeffs,
   result.resize(uvw.size1(), coeffs.size2());
   int dimSimplex;
   fullMatrix<double> bezuvw = uvw;
-  switch (type) {
+  switch (_type) {
   case TYPE_HEX:
     if (!bezCoord) {
       bezuvw.add(1);
@@ -474,7 +475,7 @@ void bezierBasis::interpolate(const fullMatrix<double> &coeffs,
 
   default:
   case TYPE_PYR:
-    Msg::Error("Bezier interpolation not implemented for type of element %d", type);
+    Msg::Error("Bezier interpolation not implemented for type of element %d", _type);
     /*bezuvw[0] = .5 * (1 + uvw[0]);
     bezuvw[1] = .5 * (1 + uvw[1]);
     bezuvw[2] = uvw[2];
@@ -489,7 +490,7 @@ void bezierBasis::interpolate(const fullMatrix<double> &coeffs,
     for (int i = 0; i < numCoeff; i++) {
       double dd = 1;
       double pointCompl = 1.;
-      int exponentCompl = order;
+      int exponentCompl = _order;
       for (int k = 0; k < dimSimplex; k++) {
         dd *= nChoosek(exponentCompl, (int) _exponents(i, k))
           * pow(bezuvw(m, k), _exponents(i, k));
@@ -498,10 +499,10 @@ void bezierBasis::interpolate(const fullMatrix<double> &coeffs,
       }
       dd *= pow_int(pointCompl, exponentCompl);
 
-      for (int k = dimSimplex; k < dim; k++) {
-        dd *= nChoosek(order, (int) _exponents(i, k))
+      for (int k = dimSimplex; k < _exponents.size2(); k++) {
+        dd *= nChoosek(_order, (int) _exponents(i, k))
             * pow_int(bezuvw(m, k), _exponents(i, k))
-            * pow_int(1. - bezuvw(m, k), order - _exponents(i, k));
+            * pow_int(1. - bezuvw(m, k), _order - _exponents(i, k));
       }
       for (int n = 0; n < coeffs.size2(); ++n)
         result(m, n) += coeffs(i, n) * dd;
@@ -511,108 +512,99 @@ void bezierBasis::interpolate(const fullMatrix<double> &coeffs,
 
 void bezierBasis::_construct(int parentType, int p)
 {
-  order = p;
-  type = parentType;
+  _order = p;
+  _type = parentType;
   std::vector< fullMatrix<double> > subPoints;
 
   if (parentType == TYPE_PYR) {
-    dim = 3;
-    numLagCoeff = 8;
-    _exponents = JacobianBasis::generateJacMonomialsPyramid(order);
+    _numLagCoeff = p == 0 ? 4 : 8;
+    _exponents = gmshGenerateMonomialsPyramidGeneral(false, 2, _order);
 
-    subPoints = generateSubPointsPyr(order);
-    numDivisions = static_cast<int>(subPoints.size());
+    subPoints = generateSubPointsPyr(_order);
+    _numDivisions = static_cast<int>(subPoints.size());
 
     fullMatrix<double> bezierPoints;
     bezierPoints.resize(_exponents.size1(), _exponents.size2());
-    const double p = order + 2;
+    const double ord = _order + 2;
     for (int i = 0; i < bezierPoints.size1(); ++i) {
-      bezierPoints(i, 2) = _exponents(i, 2) / p;
+      bezierPoints(i, 2) = _exponents(i, 2) / ord;
       const double scale = 1. - bezierPoints(i, 2);
-      bezierPoints(i, 0) = _exponents(i, 0) / p * scale;
-      bezierPoints(i, 1) = _exponents(i, 1) / p * scale;
+      bezierPoints(i, 0) = _exponents(i, 0) / ord * scale;
+      bezierPoints(i, 1) = _exponents(i, 1) / ord * scale;
     }
 
-    matrixBez2Lag = generateBez2LagMatrixPyramid(_exponents, bezierPoints, order);
+    matrixBez2Lag = generateBez2LagMatrixPyramid(_exponents, bezierPoints, _order);
     matrixBez2Lag.invert(matrixLag2Bez);
-    subDivisor = generateSubDivisorPyramid(_exponents, subPoints, matrixLag2Bez, order);
+    subDivisor = generateSubDivisorPyramid(_exponents, subPoints, matrixLag2Bez, _order);
     return;
   }
 
   switch (parentType) {
     case TYPE_PNT :
-      dim = 0;
-      numLagCoeff = 1;
+      _numLagCoeff = 1;
       _dimSimplex = 0;
       _exponents = gmshGenerateMonomialsLine(0);
       subPoints.push_back(gmshGeneratePointsLine(0));
       break;
     case TYPE_LIN : {
-      dim = 1;
-      numLagCoeff = order == 0 ? 1 : 2;
+      _numLagCoeff = _order == 0 ? 1 : 2;
       _dimSimplex = 0;
-      _exponents = gmshGenerateMonomialsLine(order);
-      subPoints = generateSubPointsLine(order);
+      _exponents = gmshGenerateMonomialsLine(_order);
+      subPoints = generateSubPointsLine(_order);
       break;
     }
     case TYPE_TRI : {
-      dim = 2;
-      numLagCoeff = order == 0 ? 1 : 3;
+      _numLagCoeff = _order == 0 ? 1 : 3;
       _dimSimplex = 2;
-      _exponents = gmshGenerateMonomialsTriangle(order);
-      subPoints = generateSubPointsTriangle(order);
+      _exponents = gmshGenerateMonomialsTriangle(_order);
+      subPoints = generateSubPointsTriangle(_order);
       break;
     }
     case TYPE_QUA : {
-      dim = 2;
-      numLagCoeff = order == 0 ? 1 : 4;
+      _numLagCoeff = _order == 0 ? 1 : 4;
       _dimSimplex = 0;
-      _exponents = gmshGenerateMonomialsQuadrangle(order);
-      subPoints = generateSubPointsQuad(order);
+      _exponents = gmshGenerateMonomialsQuadrangle(_order);
+      subPoints = generateSubPointsQuad(_order);
       break;
     }
     case TYPE_TET : {
-      dim = 3;
-      numLagCoeff = order == 0 ? 1 : 4;
+      _numLagCoeff = _order == 0 ? 1 : 4;
       _dimSimplex = 3;
-      _exponents = gmshGenerateMonomialsTetrahedron(order);
-      subPoints = generateSubPointsTetrahedron(order);
+      _exponents = gmshGenerateMonomialsTetrahedron(_order);
+      subPoints = generateSubPointsTetrahedron(_order);
       break;
     }
     case TYPE_PRI : {
-      dim = 3;
-      numLagCoeff = order == 0 ? 1 : 6;
+      _numLagCoeff = _order == 0 ? 1 : 6;
       _dimSimplex = 2;
-      _exponents = gmshGenerateMonomialsPrism(order);
-      subPoints = generateSubPointsPrism(order);
+      _exponents = gmshGenerateMonomialsPrism(_order);
+      subPoints = generateSubPointsPrism(_order);
       break;
     }
     case TYPE_HEX : {
-      dim = 3;
-      numLagCoeff = order == 0 ? 1 : 8;
+      _numLagCoeff = _order == 0 ? 1 : 8;
       _dimSimplex = 0;
-      _exponents = gmshGenerateMonomialsHexahedron(order);
-      subPoints = generateSubPointsHex(order);
+      _exponents = gmshGenerateMonomialsHexahedron(_order);
+      subPoints = generateSubPointsHex(_order);
       break;
     }
     default : {
       Msg::Error("Unknown function space of parentType %d : "
           "reverting to TET_1", parentType);
-      dim = 3;
-      order = 0;
-      numLagCoeff = 4;
+      _order = 0;
+      _numLagCoeff = 4;
       _dimSimplex = 3;
-      _exponents = gmshGenerateMonomialsTetrahedron(order);
-      subPoints = generateSubPointsTetrahedron(order);
+      _exponents = gmshGenerateMonomialsTetrahedron(_order);
+      subPoints = generateSubPointsTetrahedron(_order);
       break;
     }
   }
-  numDivisions = static_cast<int>(subPoints.size());
+  _numDivisions = static_cast<int>(subPoints.size());
 
   fullMatrix<double> bezierPoints = _exponents;
-  bezierPoints.scale(1./order);
+  bezierPoints.scale(1./_order);
 
-  matrixBez2Lag = generateBez2LagMatrix(_exponents, bezierPoints, order, _dimSimplex);
+  matrixBez2Lag = generateBez2LagMatrix(_exponents, bezierPoints, _order, _dimSimplex);
   matrixBez2Lag.invert(matrixLag2Bez);
-  subDivisor = generateSubDivisor(_exponents, subPoints, matrixLag2Bez, order, _dimSimplex);
+  subDivisor = generateSubDivisor(_exponents, subPoints, matrixLag2Bez, _order, _dimSimplex);
 }
diff --git a/Numeric/bezierBasis.h b/Numeric/bezierBasis.h
index 257e54be4a..1b0af7216d 100644
--- a/Numeric/bezierBasis.h
+++ b/Numeric/bezierBasis.h
@@ -16,11 +16,11 @@ class MElement;
 class bezierBasis {
  private :
   // the 'numLagCoeff' first exponents are related to 'Lagrangian' values
-  int numLagCoeff;
-  int dim, type, order;
-  int numDivisions;
- public:
-  int _dimSimplex;
+  int _numLagCoeff;
+  int _type, _order;
+  int _numDivisions, _dimSimplex;
+
+  friend class MetricBasis;
   fullMatrix<double> _exponents;
 
  public :
@@ -37,10 +37,12 @@ class bezierBasis {
   }
 
   // get methods
-  inline int getDim() const {return dim;}
-  inline int getOrder() const {return order;}
-  inline int getNumLagCoeff() const {return numLagCoeff;}
-  inline int getNumDivision() const {return numDivisions;}
+  inline int getDim() const {return _exponents.size2();}
+  inline int getOrder() const {return _order;}
+  inline int getDimSimplex() const {return _dimSimplex;}
+  inline int getNumLagCoeff() const {return _numLagCoeff;}
+  inline int getNumDivision() const {return _numDivisions;}
+  inline int getNumSubNodes() const {return subDivisor.size1();}
 
   // Interpolation of n functions on N points :
   // coeffs(numCoeff, n) and uvw(N, dim)
diff --git a/Numeric/pointsGenerators.cpp b/Numeric/pointsGenerators.cpp
index d8e15c91f2..f060da4ead 100644
--- a/Numeric/pointsGenerators.cpp
+++ b/Numeric/pointsGenerators.cpp
@@ -89,7 +89,7 @@ fullMatrix<double> gmshGeneratePointsPyramid(int order, bool serendip)
   if (order == 0) return points;
 
   for (int i = 0; i < points.size1(); ++i) {
-    points(i, 2) = points(i, 2) / order;
+    points(i, 2) = 1 - points(i, 2) / order;
     const double duv = -1. + points(i, 2);
     points(i, 0) = duv + points(i, 0) * 2. / order;
     points(i, 1) = duv + points(i, 1) * 2. / order;
@@ -97,6 +97,23 @@ fullMatrix<double> gmshGeneratePointsPyramid(int order, bool serendip)
   return points;
 }
 
+fullMatrix<double> gmshGeneratePointsPyramidGeneral(bool pyr, int nij, int nk, bool forSerendipPoints)
+{
+  fullMatrix<double> points =
+      gmshGenerateMonomialsPyramidGeneral(pyr, nij, nk, forSerendipPoints);
+
+  if (points.size1() == 1) return points;
+
+  for (int i = 0; i < points.size1(); ++i) {
+    int div = pyr ? nk+nij : std::max(nij, nk);
+    points(i, 2) = (nk - points(i, 2)) / div;
+    const double duv = -1. + points(i, 2);
+    points(i, 0) = duv + points(i, 0) * 2. / div;
+    points(i, 1) = duv + points(i, 1) * 2. / div;
+  }
+  return points;
+}
+
 // Monomials Generators
 
 fullMatrix<double> gmshGenerateMonomialsLine(int order, bool serendip)
@@ -668,28 +685,29 @@ fullMatrix<double> gmshGenerateMonomialsPyramid(int order, bool forSerendipPoint
   int nbMonomials = forSerendipPoints ? 5 + (order-1)*8 :
                                         (order+1)*((order+1)+1)*(2*(order+1)+1)/6;
   if (forSerendipPoints && !order) nbMonomials = 1;
+
   fullMatrix<double> monomials(nbMonomials, 3);
 
   monomials(0, 0) = 0;
   monomials(0, 1) = 0;
-  monomials(0, 2) = 0;
+  monomials(0, 2) = order;
 
   if (order > 0) {
     monomials(1, 0) = order;
     monomials(1, 1) = 0;
-    monomials(1, 2) = 0;
+    monomials(1, 2) = order;
 
     monomials(2, 0) = order;
     monomials(2, 1) = order;
-    monomials(2, 2) = 0;
+    monomials(2, 2) = order;
 
     monomials(3, 0) = 0;
     monomials(3, 1) = order;
-    monomials(3, 2) = 0;
+    monomials(3, 2) = order;
 
     monomials(4, 0) = 0;
     monomials(4, 1) = 0;
-    monomials(4, 2) = order;
+    monomials(4, 2) = 0;
 
     if (order > 1) {
       int index = 5;
@@ -751,7 +769,11 @@ fullMatrix<double> gmshGenerateMonomialsPyramid(int order, bool forSerendipPoint
 
         if (order > 2) {
           fullMatrix<double> inner = gmshGenerateMonomialsPyramid(order - 3);
-          inner.add(1);
+          fullMatrix<double> prox;
+          prox.setAsProxy(inner, 0, 2);
+          prox.add(1);
+          prox.setAsProxy(inner, 2, 1);
+          prox.add(2);
           monomials.copy(inner, 0, nbMonomials - index, 0, 3, index, 0);
         }
       }
@@ -760,3 +782,142 @@ fullMatrix<double> gmshGenerateMonomialsPyramid(int order, bool forSerendipPoint
   return monomials;
 }
 
+fullMatrix<double> gmshGenerateMonomialsPyramidGeneral(
+    bool pyr, int nij, int nk, bool forSerendipPoints)
+{
+  if (nij < 0 || nk < 0) {
+    Msg::Fatal("Wrong arguments for pyramid's monomials generation !");
+  }
+  if (!pyr && nk > 0 && nij == 0) {
+    Msg::Error("Wrong argument association for pyramid's monomials generation ! Setting nij to 1");
+    nij = 1;
+  }
+
+  // If monomials for pyramidal space, generate them in gmsh convention.
+  if (forSerendipPoints || (pyr && nij == 0))
+    return gmshGenerateMonomialsPyramid(nk, forSerendipPoints);
+
+  // Otherwise, just put corners at first places,
+  // order of others having no importance.
+
+  int nbMonomials;
+  if (pyr) {
+    nbMonomials = 0;
+    for (int k = 0; k <= nk; ++k) {
+      nbMonomials += (k+nij+1) * (k+nij+1);
+    }
+  }
+  else nbMonomials = (nij+1) * (nij+1) * (nk+1);
+
+  fullMatrix<double> monomials(nbMonomials, 3);
+
+  monomials(0, 0) = 0;
+  monomials(0, 1) = 0;
+  monomials(0, 2) = nk;
+
+  if (nk == 0 && nij == 0) return monomials;
+
+  // Here, nij > 0
+  int nijBase = pyr ? nk+nij : nij;
+
+  // Corners
+  monomials(1, 0) = nijBase;
+  monomials(1, 1) = 0;
+  monomials(1, 2) = nk;
+
+  monomials(2, 0) = nijBase;
+  monomials(2, 1) = nijBase;
+  monomials(2, 2) = nk;
+
+  monomials(3, 0) = 0;
+  monomials(3, 1) = nijBase;
+  monomials(3, 2) = nk;
+
+  if (nk > 0) {
+    monomials(4, 0) = 0;
+    monomials(4, 1) = 0;
+    monomials(4, 2) = 0;
+
+    monomials(5, 0) = nij;
+    monomials(5, 1) = 0;
+    monomials(5, 2) = 0;
+
+    monomials(6, 0) = nij;
+    monomials(6, 1) = nij;
+    monomials(6, 2) = 0;
+
+    monomials(7, 0) = 0;
+    monomials(7, 1) = nij;
+    monomials(7, 2) = 0;
+  }
+
+  int index = 8;
+
+  // Base
+  if (nijBase > 1) {
+    for (int iedge = 0; iedge < 4; ++iedge) {
+      int i0 = iedge;
+      int i1 = (iedge+1) % 4;
+
+      int u0 = (monomials(i1,0)-monomials(i0,0)) / nijBase;
+      int u1 = (monomials(i1,1)-monomials(i0,1)) / nijBase;
+
+      for (int i = 1; i < nijBase; ++i, ++index) {
+        monomials(index, 0) = monomials(i0, 0) + i * u0;
+        monomials(index, 1) = monomials(i0, 1) + i * u1;
+        monomials(index, 2) = nk;
+      }
+    }
+
+    for (int i = 1; i < nijBase; ++i) {
+      for (int j = 1; j < nijBase; ++j, ++index) {
+        monomials(index, 0) = i;
+        monomials(index, 1) = j;
+        monomials(index, 2) = nk;
+      }
+    }
+  }
+
+  // Above base
+  if (nk > 0) {
+    // Top
+    if (nij > 1) {
+      for (int iedge = 0; iedge < 4; ++iedge) {
+        int i0 = 4 + iedge;
+        int i1 = 4 + (iedge+1)%4;
+
+        int u0 = (monomials(i1,0)-monomials(i0,0)) / nijBase;
+        int u1 = (monomials(i1,1)-monomials(i0,1)) / nijBase;
+
+        for (int i = 1; i < nijBase; ++i, ++index) {
+          monomials(index, 0) = monomials(i0, 0) + i * u0;
+          monomials(index, 1) = monomials(i0, 1) + i * u1;
+          monomials(index, 2) = 0;
+        }
+      }
+
+      for (int i = 1; i < nijBase; ++i) {
+        for (int j = 1; j < nijBase; ++j, ++index) {
+          monomials(index, 0) = i;
+          monomials(index, 1) = j;
+          monomials(index, 2) = 0;
+        }
+      }
+    }
+
+    // Between bottom & top
+    for (int k = nk-1; k > 0; ++k) {
+      int currentnij = pyr ? k+nij : nij;
+      for (int i = 0; i <= currentnij; ++i) {
+        for (int j = 0; j <= currentnij; ++j, ++index) {
+          monomials(index, 0) = i;
+          monomials(index, 1) = j;
+          monomials(index, 2) = k;
+        }
+      }
+    }
+  }
+
+  return monomials;
+}
+
diff --git a/Numeric/pointsGenerators.h b/Numeric/pointsGenerators.h
index 6546e7dfd6..c3f88f39ab 100644
--- a/Numeric/pointsGenerators.h
+++ b/Numeric/pointsGenerators.h
@@ -29,6 +29,11 @@ fullMatrix<double> gmshGeneratePointsPrism(int order, bool serendip = false);
 
 fullMatrix<double> gmshGeneratePointsPyramid(int order, bool serendip = false);
 
+// If 'serendip' == true, generate points for serendipity pyramid of order 'nk',
+// else if 'pyr' == true, generate points for space {X^i Y^j Z^k | i,j <= k+'nij', k <= 'nk'},
+// else if 'pyr' == false, generate points for space {X^i Y^j Z^k | i,j <= 'nij', k <= 'nk'}
+fullMatrix<double> gmshGeneratePointsPyramidGeneral(bool pyr, int nij, int nk, bool serendip = false);
+
 
 // Monomial exponents
 
@@ -45,7 +50,9 @@ fullMatrix<double> gmshGenerateMonomialsPrism(int order, bool forSerendipPoints
 fullMatrix<double> gmshGenerateMonomialsPrismSerendipity(int order);
 
 fullMatrix<double> gmshGenerateMonomialsPyramid(int order, bool forSerendipPoints = false);
-//fullMatrix<double> gmshGenerateMonomialsPyramidSerendipity(int order); //TODO
+
+// See explanations for 'gmshGeneratePointsPyramidGeneral'
+fullMatrix<double> gmshGenerateMonomialsPyramidGeneral(bool pyr, int nij, int nk, bool forSerendipPoints = false);
 
 
 
diff --git a/Plugin/AnalyseCurvedMesh.cpp b/Plugin/AnalyseCurvedMesh.cpp
index d3ddac5164..9bf358780e 100644
--- a/Plugin/AnalyseCurvedMesh.cpp
+++ b/Plugin/AnalyseCurvedMesh.cpp
@@ -38,12 +38,12 @@ private:
   fullVector<double> _jacBez;
   double _minL, _maxL, _minB, _maxB; //Extremum of Jac at corners and of bezier values
   int _depthSub;
-  const JacobianBasis *_jfs;
+  const bezierBasis *_bfs;
 
 public:
-  BezierJacobian(fullVector<double> &, const JacobianBasis *, int depth);
+  BezierJacobian(fullVector<double>&, const bezierBasis*, int depth);
   void subDivisions(fullVector<double> &vect) const
-    {_jfs->subdivideBezierCoeff(_jacBez, vect);}
+    {_bfs->subDivisor.mult(_jacBez, vect);}
 
   bool boundsOk(double tol, double minL, double maxL) {
     return (minL <= 0 || _minB > 0) &&
@@ -294,6 +294,7 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(MElement *const*el
     Msg::Error("Jacobian function space not implemented for type of element %d", el[0]->getNum());
     return;
   }
+  const bezierBasis *bfs = jfs->getBezier();
 
   _data.reserve(_data.size() + numEl);
 
@@ -301,7 +302,7 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(MElement *const*el
   const int numMapNodes = jfs->getNumMapNodes();
   fullVector<double> jacobian(numSamplingPt);
   fullVector<double> jacBez(numSamplingPt);
-  fullVector<double> subJacBez(jfs->getNumSubNodes());
+  fullVector<double> subJacBez(bfs->getNumSubNodes());
 
   for (int k = 0; k < numEl; ++k) {
     fullMatrix<double> nodesXYZ(numMapNodes,3);
@@ -309,7 +310,7 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(MElement *const*el
     jfs->getScaledJacobian(nodesXYZ,jacobian);
     jfs->lag2Bez(jacobian, jacBez);
 
-    BezierJacobian *bj = new BezierJacobian(jacBez, jfs, 0);
+    BezierJacobian *bj = new BezierJacobian(jacBez, bfs, 0);
     std::vector<BezierJacobian*> heap;
     heap.push_back(bj);
 
@@ -330,9 +331,9 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(MElement *const*el
                      el[k]->getTypeForMSH());
       }
 
-      for (int i = 0; i < jfs->getNumDivisions(); i++) {
+      for (int i = 0; i < bfs->getNumDivision(); i++) {
         jacBez.setAsProxy(subJacBez, i * numSamplingPt, numSamplingPt);
-        BezierJacobian *newbj = new BezierJacobian(jacBez, jfs, currentDepth);
+        BezierJacobian *newbj = new BezierJacobian(jacBez, bfs, currentDepth);
         minL = std::min(minL, newbj->minL());
         maxL = std::max(maxL, newbj->maxL());
 
@@ -358,9 +359,9 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(MElement *const*el
                      el[k]->getTypeForMSH());
       }
 
-      for (int i = 0; i < jfs->getNumDivisions(); i++) {
+      for (int i = 0; i < bfs->getNumDivision(); i++) {
         jacBez.setAsProxy(subJacBez, i * numSamplingPt, numSamplingPt);
-        BezierJacobian *newbj = new BezierJacobian(jacBez, jfs, currentDepth);
+        BezierJacobian *newbj = new BezierJacobian(jacBez, bfs, currentDepth);
         minL = std::min(minL, newbj->minL());
         maxL = std::max(maxL, newbj->maxL());
 
@@ -495,15 +496,15 @@ void GMSH_AnalyseCurvedMeshPlugin::_printStatJacobian()
 }
 
 BezierJacobian::BezierJacobian(fullVector<double> &v,
-    const JacobianBasis *jfs, int depth)
+    const bezierBasis *bfs, int depth)
 {
   _jacBez = v;
   _depthSub = depth;
-  _jfs = jfs;
+  _bfs = bfs;
 
   _minL = _maxL = v(0);
   int i = 1;
-  for (; i < jfs->getNumLagCoeff(); i++) {
+  for (; i < bfs->getNumLagCoeff(); i++) {
     if (_minL > v(i)) _minL = v(i);
     if (_maxL < v(i)) _maxL = v(i);
   }
diff --git a/Plugin/AnalyseCurvedMesh.h b/Plugin/AnalyseCurvedMesh.h
index 5e9f175cfc..d3b18e445b 100644
--- a/Plugin/AnalyseCurvedMesh.h
+++ b/Plugin/AnalyseCurvedMesh.h
@@ -10,7 +10,6 @@
 #include "JacobianBasis.h"
 #include "MetricBasis.h"
 #include "MElement.h"
-#include "OS.h"
 
 #include <vector>
 
@@ -81,8 +80,6 @@ public :
   void computeMinJ(MElement *const *el, int numEl, double *minJ, bool *straight) {
     std::vector<CurvedMeshPluginData> save(_data);
     _data.clear();
-    double time = Cpu();
-    //Rmv add OS.H
     _computeMinMaxJandValidity(el, numEl);
     if (minJ) {
       for (unsigned int i = 0; i < _data.size(); ++i) {
-- 
GitLab