From 66fa13429593ddcc28f1a92c8706f51812cc963f Mon Sep 17 00:00:00 2001
From: Amaury Johnan <amjohnen@gmail.com>
Date: Fri, 17 Oct 2014 14:49:07 +0000
Subject: [PATCH] add faster and more accurate function
 MetricBasis::minSampledRnew(..)

---
 Numeric/BasisFactory.h    |   3 +
 Numeric/FuncSpaceData.cpp |   9 +--
 Numeric/FuncSpaceData.h   |  10 ++--
 Numeric/JacobianBasis.cpp |  32 ++++++++++
 Numeric/JacobianBasis.h   |   1 +
 Numeric/MetricBasis.cpp   | 123 ++++++++++++++++++++++++++++----------
 Numeric/MetricBasis.h     |   1 +
 Numeric/bezierBasis.cpp   |  21 +++++--
 Numeric/bezierBasis.h     |   3 +
 9 files changed, 161 insertions(+), 42 deletions(-)

diff --git a/Numeric/BasisFactory.h b/Numeric/BasisFactory.h
index d5c509c164..b1a11a4c34 100644
--- a/Numeric/BasisFactory.h
+++ b/Numeric/BasisFactory.h
@@ -61,6 +61,9 @@ class BasisFactory
   static const GradientBasis* getGradientBasis(int tag, int order) {
     return getGradientBasis(FuncSpaceData(true, tag, order));
   }
+  static const GradientBasis* getGradientBasis(int tag) {
+    return getGradientBasis(FuncSpaceData(tag));
+  }
 
   // Bezier
   static const bezierBasis* getBezierBasis(FuncSpaceData);
diff --git a/Numeric/FuncSpaceData.cpp b/Numeric/FuncSpaceData.cpp
index 8e0dfc9382..586213617e 100644
--- a/Numeric/FuncSpaceData.cpp
+++ b/Numeric/FuncSpaceData.cpp
@@ -6,19 +6,20 @@
 #include "FuncSpaceData.h"
 #include "MElement.h"
 
-FuncSpaceData::FuncSpaceData(MElement *el, int *serendip) :
+FuncSpaceData::FuncSpaceData(const MElement *el, const bool *serendip) :
   _tag(el->getTypeForMSH()), _spaceOrder(el->getPolynomialOrder()),
   _nij(0), _nk(_spaceOrder), _pyramidalSpace(el->getType() == TYPE_PYR),
   _serendipity(serendip ? *serendip : el->getIsOnlySerendipity())
 {}
 
-FuncSpaceData::FuncSpaceData(MElement *el, int order, int *serendip) :
+FuncSpaceData::FuncSpaceData(const MElement *el, int order, const bool *serendip) :
   _tag(el->getTypeForMSH()), _spaceOrder(order),
   _nij(0), _nk(_spaceOrder), _pyramidalSpace(el->getType() == TYPE_PYR),
   _serendipity(serendip ? *serendip : el->getIsOnlySerendipity())
 {}
 
-FuncSpaceData::FuncSpaceData(MElement *el, bool pyr, int nij, int nk, int *serendip) :
+FuncSpaceData::FuncSpaceData(const MElement *el, bool pyr, int nij, int nk,
+                             const bool *serendip) :
   _tag(el->getTypeForMSH()), _spaceOrder(pyr ? nij+nk : std::max(nij, nk)),
   _nij(nij), _nk(nk), _pyramidalSpace(pyr),
   _serendipity(serendip ? *serendip : el->getIsOnlySerendipity())
@@ -27,7 +28,7 @@ FuncSpaceData::FuncSpaceData(MElement *el, bool pyr, int nij, int nk, int *seren
     Msg::Error("Creation of pyramidal space data for a non-pyramid element !");
 }
 
-FuncSpaceData::FuncSpaceData(int tag, int *serendip) :
+FuncSpaceData::FuncSpaceData(int tag, const bool *serendip) :
   _tag(tag), _spaceOrder(ElementType::OrderFromTag(tag)),
   _nij(0), _nk(_spaceOrder),
   _pyramidalSpace(ElementType::ParentTypeFromTag(tag) == TYPE_PYR),
diff --git a/Numeric/FuncSpaceData.h b/Numeric/FuncSpaceData.h
index 0ddc82b565..649a5b9413 100644
--- a/Numeric/FuncSpaceData.h
+++ b/Numeric/FuncSpaceData.h
@@ -31,12 +31,14 @@ public:
     _pyramidalSpace(false), _serendipity(false) {}
 
   // Constructors using MElement*
-  FuncSpaceData(MElement *el, int *serendip = NULL);
-  FuncSpaceData(MElement *el, int order, int *serendip = NULL);
-  FuncSpaceData(MElement *el, bool pyr, int nij, int nk, int *serendip = NULL);
+  FuncSpaceData(const MElement *el, const bool *serendip = NULL);
+  FuncSpaceData(const MElement *el, int order, const bool *serendip = NULL);
+  FuncSpaceData(const MElement *el,
+                bool pyr, int nij, int nk,
+                const bool *serendip = NULL);
 
   // Constructors using element tag
-  FuncSpaceData(int tag, int *serendip = NULL);
+  FuncSpaceData(int tag, const bool *serendip = NULL);
 
   // constructors using element tag or element type
   FuncSpaceData(bool isTag, int tagOrType, int order,
diff --git a/Numeric/JacobianBasis.cpp b/Numeric/JacobianBasis.cpp
index 2bf7bc4fe0..a874038d32 100644
--- a/Numeric/JacobianBasis.cpp
+++ b/Numeric/JacobianBasis.cpp
@@ -854,3 +854,35 @@ int JacobianBasis::jacobianOrder(int parentType, int order)
       return 0;
   }
 }
+
+FuncSpaceData JacobianBasis::jacobianMatrixSpace(int type, int order)
+{
+  if (type == TYPE_PYR) {
+    Msg::Fatal("jacobianMatrixSpace not yet implemented for pyramids");
+    return FuncSpaceData(false, type, false, 1, 0);
+  }
+  int jacOrder = -1;
+  switch (type) {
+    case TYPE_PNT :
+      jacOrder = 0;
+      break;
+
+    case TYPE_LIN :
+    case TYPE_TRI :
+    case TYPE_TET :
+      jacOrder = order - 1;
+      break;
+
+    case TYPE_QUA :
+    case TYPE_PRI :
+    case TYPE_HEX :
+      jacOrder = order;
+      break;
+
+    default :
+      Msg::Error("Unknown element type %d, return order 0", type);
+      return 0;
+  }
+
+  return FuncSpaceData(true, ElementType::getTag(type, order), jacOrder);
+}
diff --git a/Numeric/JacobianBasis.h b/Numeric/JacobianBasis.h
index 7bfbf85375..bbcca1b059 100644
--- a/Numeric/JacobianBasis.h
+++ b/Numeric/JacobianBasis.h
@@ -202,6 +202,7 @@ public:
   //
   static int jacobianOrder(int tag);
   static int jacobianOrder(int parentType, int order);
+  static FuncSpaceData jacobianMatrixSpace(int type, int order);
 
 
  private :
diff --git a/Numeric/MetricBasis.cpp b/Numeric/MetricBasis.cpp
index eb4959eec4..877e9c4c1e 100644
--- a/Numeric/MetricBasis.cpp
+++ b/Numeric/MetricBasis.cpp
@@ -153,36 +153,8 @@ double MetricBasis::minSampledR(MElement *el, int order)
 double MetricBasis::getMinSampledR(MElement *el, int deg) const
 {
   fullMatrix<double> samplingPoints;
-
-  switch (el->getType()) {
-    case TYPE_PNT :
-      samplingPoints = gmshGeneratePointsLine(0);
-      break;
-    case TYPE_LIN :
-      samplingPoints = gmshGeneratePointsLine(deg);
-      break;
-    case TYPE_TRI :
-      samplingPoints = gmshGeneratePointsTriangle(deg,false);
-      break;
-    case TYPE_QUA :
-      samplingPoints = gmshGeneratePointsQuadrangle(deg,false);
-      break;
-    case TYPE_TET :
-      samplingPoints = gmshGeneratePointsTetrahedron(deg,false);
-      break;
-    case TYPE_PRI :
-      samplingPoints = gmshGeneratePointsPrism(deg,false);
-      break;
-    case TYPE_HEX :
-      samplingPoints = gmshGeneratePointsHexahedron(deg,false);
-      break;
-    case TYPE_PYR :
-      samplingPoints = gmshGeneratePointsPyramidGeneral(true, deg+1, deg);
-      break;
-    default :
-      Msg::Error("Unknown Jacobian function space for element type %d", el->getType());
-      return -1;
-  }
+  bool serendip = false;
+  gmshGeneratePoints(FuncSpaceData(el, deg, &serendip), samplingPoints);
 
   MetricData *md;
   _getMetricData(el, md);
@@ -199,6 +171,73 @@ double MetricBasis::getMinSampledR(MElement *el, int deg) const
   return min;
 }
 
+double MetricBasis::minSampledRnew(MElement *el, int deg)
+{
+  int dim = el->getDim();
+  if (dim < 2) return 1;
+
+  fullMatrix<double> nodes(el->getNumVertices(), 3);
+  el->getNodesCoord(nodes);
+
+  // if deg is small: sample at every point
+  // otherwise: compute Bezier coefficients and interpolate
+  //const bool BezierInterp = deg > 100;
+
+  FuncSpaceData jacMatSpace;
+  /*if (BezierInterp) {
+    jacMatSpace =
+        JacobianBasis::jacobianMatrixSpace(el->getType(), el->getPolynomialOrder());
+  }
+  else {*/
+    const bool serendip = false;
+    jacMatSpace = FuncSpaceData(el, deg, &serendip);
+  //}
+
+  const GradientBasis *gb = BasisFactory::getGradientBasis(jacMatSpace);
+  fullMatrix<double> coeffJacMat(gb->getNumSamplingPoints(), 3*dim);
+  fullMatrix<double> dxyzdX(coeffJacMat, 0, 3);
+  fullMatrix<double> dxyzdY(coeffJacMat, 3, 3);
+  if (dim == 2)
+    gb->getIdealGradientsFromNodes(nodes, &dxyzdX, &dxyzdY, NULL);
+  else {
+    fullMatrix<double> dxyzdZ(coeffJacMat, 6, 3);
+    gb->getIdealGradientsFromNodes(nodes, &dxyzdX, &dxyzdY, &dxyzdZ);
+  }
+
+  /*if (BezierInterp) {
+    const bezierBasis *bb = BasisFactory::getBezierBasis(jacMatSpace);
+    fullMatrix<double> points;
+    const bool serendip = false;
+    gmshGeneratePoints(FuncSpaceData(el, deg, &serendip), points);
+
+    fullMatrix<double> bezCoeffJacMat;
+    bb->lag2Bez(coeffJacMat, bezCoeffJacMat);
+    bb->interpolate(bezCoeffJacMat, points, coeffJacMat);
+  }*/
+
+  double minR = 1;
+  for (int k = 0; k < coeffJacMat.size1(); ++k) {
+    fullMatrix<double> metric(dim, dim);
+    for (int i = 0; i < dim; ++i) {
+      for (int j = i; j < dim; ++j) {
+        for (int n = 0; n < 3; ++n)
+          metric(i, j) += coeffJacMat(k, 3*i+n) * coeffJacMat(k, 3*j+n);
+      }
+    }
+    metric(1, 0) = metric(0, 1);
+    if (dim == 3) {
+      metric(2, 0) = metric(0, 2);
+      metric(2, 1) = metric(1, 2);
+    }
+    fullVector<double> valReal(dim), valImag(dim);
+    fullMatrix<double> vecLeft(dim, dim), vecRight(dim, dim);
+    metric.eig(valReal, valImag, vecLeft, vecRight, true);
+    minR = std::min(minR, std::sqrt(valReal(0) / valReal(dim-1)));
+  }
+
+  return minR;
+}
+
 double MetricBasis::getBoundMinR(MElement *el) const
 {
   int nSampPnts = _gradients->getNumSamplingPoints();
@@ -607,6 +646,30 @@ bool MetricBasis::validateBezierForMetricAndJacobian()
       metricBasis->interpolateAfterNSubdivisions(el, numSubdiv, numSampPnt,
                                                  isub, uvw, metric_Bez);
 
+      /*{
+        static int deg = 2;
+        MetricBasis::minSampledR(el, deg);
+        MetricBasis::minSampledRnew(el, deg);
+
+        double time = Cpu();
+        double minR1;
+        for (int cn = 0; cn < 100; ++cn)
+          minR1 = MetricBasis::minSampledR(el, deg);
+        double tm1 = Cpu()-time;
+
+        time = Cpu();
+        double minR2;
+        for (int cn = 0; cn < 100; ++cn)
+          minR2 = MetricBasis::minSampledRnew(el, deg);
+        double tm2 = Cpu()-time;
+
+        if (std::abs(minR1-minR2) < 1e-14)
+          Msg::Info("ok deg %d, times %g %g speedup %g", deg, tm1, tm2, tm1/tm2);
+        else
+          Msg::Error("not ok deg %d: %g vs %g, times %g %g speedup %g", deg, minR1, minR2, tm1, tm2, tm1/tm2);
+        //++deg;
+      }*/
+
       int numBadMatch = 0;
       int numBadMatchTensor = 0;
       double maxBadMatch = 0;
diff --git a/Numeric/MetricBasis.h b/Numeric/MetricBasis.h
index 2416f8d12f..0817458ace 100644
--- a/Numeric/MetricBasis.h
+++ b/Numeric/MetricBasis.h
@@ -64,6 +64,7 @@ public:
 
   static double boundMinR(MElement *el);
   static double minSampledR(MElement *el, int order);
+  static double minSampledRnew(MElement *el, int order);
   double getBoundMinR(MElement*) const;
   double getMinSampledR(MElement*, int order) const;
 
diff --git a/Numeric/bezierBasis.cpp b/Numeric/bezierBasis.cpp
index 5eefae9b27..2a56445b35 100644
--- a/Numeric/bezierBasis.cpp
+++ b/Numeric/bezierBasis.cpp
@@ -499,7 +499,7 @@ void bezierBasis::interpolate(const fullMatrix<double> &coeffs,
                               fullMatrix<double> &result,
                               bool bezCoord) const
 {
-  if (result.size1() < uvw.size1() || result.size2() < coeffs.size2())
+  if (result.size1() != uvw.size1() || result.size2() != coeffs.size2())
     result.resize(uvw.size1(), coeffs.size2());
 
   fullMatrix<double> bezuvw = uvw;
@@ -535,11 +535,24 @@ void bezierBasis::interpolate(const fullMatrix<double> &coeffs,
   }
 }
 
+void bezierBasis::lag2Bez(const fullMatrix<double> &lag,
+                          fullMatrix<double> &bez) const
+{
+  if (lag.size1() != matrixLag2Bez.size1()) {
+    Msg::Error("matrix not the right size in lag2Bez function %d vs %d",
+        lag.size1(), matrixLag2Bez.size1());
+  }
+  if (bez.size1() != lag.size1() || bez.size2() != lag.size2()) {
+    bez.resize(lag.size1(), lag.size2());
+  }
+  matrixLag2Bez.mult(lag, bez);
+}
+
 void bezierBasis::subdivideBezCoeff(const fullMatrix<double> &coeff,
                                     fullMatrix<double> &subCoeff) const
 {
-  if (subCoeff.size1() < subDivisor.size1()
-      || subCoeff.size2() < coeff.size2()  ) {
+  if (subCoeff.size1() != subDivisor.size1()
+      || subCoeff.size2() != coeff.size2()  ) {
     subCoeff.resize(subDivisor.size1(), coeff.size2());
   }
   subDivisor.mult(coeff, subCoeff);
@@ -548,7 +561,7 @@ void bezierBasis::subdivideBezCoeff(const fullMatrix<double> &coeff,
 void bezierBasis::subdivideBezCoeff(const fullVector<double> &coeff,
                                     fullVector<double> &subCoeff) const
 {
-  if (subCoeff.size() < subDivisor.size1()) {
+  if (subCoeff.size() != subDivisor.size1()) {
     subCoeff.resize(subDivisor.size1());
   }
   subDivisor.mult(coeff, subCoeff);
diff --git a/Numeric/bezierBasis.h b/Numeric/bezierBasis.h
index f08e305a9e..b301391fd2 100644
--- a/Numeric/bezierBasis.h
+++ b/Numeric/bezierBasis.h
@@ -48,6 +48,9 @@ class bezierBasis {
   // generate Bezier points
   void generateBezierPoints(fullMatrix<double>&) const;
 
+  // transform coeff Lagrange into Bezier coeff
+  void lag2Bez(const fullMatrix<double> &lag, fullMatrix<double> &bez) const;
+
   // Subdivide Bezier coefficients
   void subdivideBezCoeff(const fullMatrix<double> &coeff,
                          fullMatrix<double> &subCoeff) const;
-- 
GitLab