From ec0b07dbf036d67adbab21656c27ebde28e35c7f Mon Sep 17 00:00:00 2001
From: Jean-Francois Remacle <jean-francois.remacle@uclouvain.be>
Date: Wed, 20 Jan 2010 19:21:59 +0000
Subject: [PATCH] smoothing high order works with quads !!

---
 Common/LuaBindings.cpp              |  1 +
 Geo/GModel.cpp                      |  4 ++
 Geo/MElement.cpp                    | 16 +++++
 Geo/MElement.h                      |  2 +
 Geo/MQuadrangle.cpp                 | 26 ++++++++
 Geo/MQuadrangle.h                   |  2 +
 Geo/MTriangle.cpp                   |  1 +
 Geo/MVertex.cpp                     |  2 +-
 Mesh/HighOrder.cpp                  | 15 ++++-
 Mesh/highOrderSmoother.cpp          |  2 +-
 Mesh/qualityMeasures.cpp            | 92 ++++++++++++++++++++++++++++-
 Mesh/qualityMeasures.h              |  3 +
 Solver/TESTCASES/CylinderEddies.lua |  4 +-
 Solver/TESTCASES/cyl2.geo           |  8 +--
 Solver/dgAlgorithm.cpp              | 12 ++--
 Solver/dgGroupOfElements.h          |  1 +
 Solver/dgSystemOfEquations.h        |  3 +
 Solver/function.cpp                 | 38 ++++++++++++
 Solver/function.h                   | 10 ++++
 19 files changed, 225 insertions(+), 17 deletions(-)

diff --git a/Common/LuaBindings.cpp b/Common/LuaBindings.cpp
index af0d3cf8fe..1b98e8ca00 100644
--- a/Common/LuaBindings.cpp
+++ b/Common/LuaBindings.cpp
@@ -179,6 +179,7 @@ binding::binding(){
   functionLua::registerBindings(this);
   function::registerDefaultFunctions();
   MVertex::registerBindings(this);
+  MElement::registerBindings(this);
 }
 binding *binding::_instance=NULL;
 #endif
diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index 74d614020c..0bd0b84f3d 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -1401,5 +1401,9 @@ void GModel::registerBindings(binding *b)
   cm = cb->addMethod("mesh", &GModel::mesh);
   cm = cb->addMethod("load", &GModel::load);
   cm = cb->addMethod("save", &GModel::save);
+  cm = cb->addMethod("getNumMeshElements",(int (GModel::*)()) &GModel::getNumMeshElements);
+  cm = cb->addMethod("getMeshElementByTag",&GModel::getMeshElementByTag);
+  cm = cb->addMethod("getNumMeshVertices",&GModel::getNumMeshVertices);
+  cm = cb->addMethod("getMeshVertexByTag",&GModel::getMeshVertexByTag);
   cm = cb->setConstructor<GModel>();
 }
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index b29d77a43b..be20d7389b 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -801,3 +801,19 @@ MElement *MElementFactory::create(int type, std::vector<MVertex*> &v,
   default:         return 0;
   }
 }
+
+#include "Bindings.h"
+
+void MElement::registerBindings(binding *b)
+{
+  classBinding *cb = b->addClass<MElement>("MElement");
+  methodBinding *cm;
+  cm = cb->addMethod("getNum",&MElement::getNum);
+  // here we specify the cast because there are 2 MVertex::x function
+  cm = cb->addMethod("getNumVertices", &MElement::getNumVertices);
+  cm = cb->addMethod("getVertex", &MElement::getVertex);
+  cm = cb->addMethod("getType", &MElement::getType);
+  cm = cb->addMethod("getPartition", &MElement::getPartition);
+  cm = cb->addMethod("getPolynomialOrder", &MElement::getPolynomialOrder);
+  cm = cb->addMethod("getDim", &MElement::getDim);
+}
diff --git a/Geo/MElement.h b/Geo/MElement.h
index 71df81d183..fbd38e5616 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -18,6 +18,7 @@
 #include "Gauss.h"
 
 class GFace;
+class binding;
 
 // A mesh element.
 class MElement 
@@ -266,6 +267,7 @@ class MElement
   // return the number of vertices, as well as the element name if
   // 'name' != 0
   static int getInfoMSH(const int typeMSH, const char **const name=0);
+  static void registerBindings(binding *b);
 };
 
 class MElementLessThanLexicographic{
diff --git a/Geo/MQuadrangle.cpp b/Geo/MQuadrangle.cpp
index aec951b0c4..955a2507d0 100644
--- a/Geo/MQuadrangle.cpp
+++ b/Geo/MQuadrangle.cpp
@@ -7,6 +7,11 @@
 #include "GaussLegendre1D.h"
 #include "Context.h"
 #include "qualityMeasures.h"
+
+#if defined(HAVE_MESH)
+#include "qualityMeasures.h"
+#endif
+
 #define SQU(a)      ((a)*(a))
 const polynomialBasis* MQuadrangle::getFunctionSpace(int o) const
 {
@@ -38,6 +43,8 @@ int MQuadrangleN::getNumEdgesRep(){ return 4 * CTX::instance()->mesh.numSubEdges
 int MQuadrangle8::getNumEdgesRep(){ return 4 * CTX::instance()->mesh.numSubEdges; }
 int MQuadrangle9::getNumEdgesRep(){ return 4 * CTX::instance()->mesh.numSubEdges; }
 
+
+
 static void _myGetEdgeRep(MQuadrangle *q, int num, double *x, double *y, double *z,
                           SVector3 *n, int numSubEdges)
 {
@@ -159,3 +166,22 @@ void MQuadrangle::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
   *pts = getGQQPts(pOrder);
 }
 
+double MQuadrangle::distoShapeMeasure()
+{
+#if defined(HAVE_MESH)
+  //  return qmTriangleAngles(this);
+  return qmDistorsionOfMapping(this);
+#else
+  return 0.;
+#endif
+}
+
+
+double MQuadrangle::angleShapeMeasure()
+{
+#if defined(HAVE_MESH)
+  return qmQuadrangleAngles(this);
+#else
+  return 1.;
+#endif
+}
diff --git a/Geo/MQuadrangle.h b/Geo/MQuadrangle.h
index a4c274f6d0..ecfe3d254e 100644
--- a/Geo/MQuadrangle.h
+++ b/Geo/MQuadrangle.h
@@ -129,6 +129,8 @@ class MQuadrangle : public MElement {
     return true;
   }
   virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts);
+  virtual double angleShapeMeasure();
+  virtual double distoShapeMeasure();
  private:
   int edges_quad(const int edge, const int vert) const
   {
diff --git a/Geo/MTriangle.cpp b/Geo/MTriangle.cpp
index ab7171141e..8b4a4a9a40 100644
--- a/Geo/MTriangle.cpp
+++ b/Geo/MTriangle.cpp
@@ -27,6 +27,7 @@ SPoint3 MTriangle::circumcenter()
 double MTriangle::distoShapeMeasure()
 {
 #if defined(HAVE_MESH)
+  //return qmTriangleAngles(this);
   return qmDistorsionOfMapping(this);
 #else
   return 0.;
diff --git a/Geo/MVertex.cpp b/Geo/MVertex.cpp
index 0f56dfdd79..c0e19b44e5 100644
--- a/Geo/MVertex.cpp
+++ b/Geo/MVertex.cpp
@@ -407,7 +407,7 @@ void MVertex::registerBindings(binding *b)
   cm = cb->addMethod("getNum",&MVertex::getNum);
   // here we specify the cast because there are 2 MVertex::x function
   cm = cb->addMethod("x", (double (MVertex::*)() const) &MVertex::x);
-  cm = cb->addMethod("x2", (double& (MVertex::*)()) &MVertex::x);
+  // cm = cb->addMethod("x2", (double& (MVertex::*)()) &MVertex::x);
   cm = cb->addMethod("y", (double (MVertex::*)() const) &MVertex::y);
   cm = cb->addMethod("z", (double (MVertex::*)() const) &MVertex::z);
   cm = cb->setConstructor<MVertex,double,double,double>();
diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp
index b36767ecd9..5ab8d271dd 100644
--- a/Mesh/HighOrder.cpp
+++ b/Mesh/HighOrder.cpp
@@ -942,12 +942,23 @@ static void checkHighOrderTriangles(const char* cc, GModel *m,
       if (disto < 0) bad.push_back(t);
       else if (disto < 0.2) nbfair++;
     }
+    for(unsigned int i = 0; i < (*it)->quadrangles.size(); i++){
+      MQuadrangle *t = (*it)->quadrangles[i];
+      double disto_ = t->distoShapeMeasure();
+      double gamma_ = t->gammaShapeMeasure();
+      double disto = disto_;
+      minJGlob = std::min(minJGlob, disto);
+      minGGlob = std::min(minGGlob, gamma_);
+      avg += disto; count++;
+      if (disto < 0) bad.push_back(t);
+      else if (disto < 0.2) nbfair++;
+    }
   }
   if (minJGlob > 0) 
-    Msg::Info("%s : Worst Triangle Smoothness %g Gamma %g NbFair = %d", 
+    Msg::Info("%s : Worst Face Smoothness %g Gamma %g NbFair = %d", 
               cc, minJGlob, minGGlob,nbfair );
   else
-    Msg::Warning("%s : Worst Triangle Smoothness %g (%d negative jacobians) "
+    Msg::Warning("%s : Worst Face Smoothness %g (%d negative jacobians) "
                  "Worst Gamma %g Avg Smoothness %g", cc, minJGlob, bad.size(),
                  minGGlob, avg / (count ? count : 1));
 }
diff --git a/Mesh/highOrderSmoother.cpp b/Mesh/highOrderSmoother.cpp
index a885beeae7..683f3e5831 100644
--- a/Mesh/highOrderSmoother.cpp
+++ b/Mesh/highOrderSmoother.cpp
@@ -369,7 +369,7 @@ void highOrderSmoother::optimize(GFace * gf,
 
     smooth(gf, true);
     //int nbSwap = 
-        swapHighOrderTriangles(gf,edgeVertices,faceVertices,this);
+    //        swapHighOrderTriangles(gf,edgeVertices,faceVertices,this);
     // smooth(gf,true);
     // smooth(gf,true);
     // smooth(gf,true);
diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp
index 330cb4f852..bfa40d89bc 100644
--- a/Mesh/qualityMeasures.cpp
+++ b/Mesh/qualityMeasures.cpp
@@ -7,6 +7,7 @@
 #include "BDS.h"
 #include "MVertex.h"
 #include "MTriangle.h"
+#include "MQuadrangle.h"
 #include "MTetrahedron.h"
 #include "Numeric.h"
 #include "polynomialBasis.h"
@@ -177,7 +178,7 @@ double qmTet(const double &x1, const double &y1, const double &z1,
   }
 }
 
-double mesh_functional_distorsion(MTriangle *t, double u, double v)
+double mesh_functional_distorsion(MElement *t, double u, double v)
 {
   // compute uncurved element jacobian d_u x and d_v x
   double mat[3][3];  
@@ -247,6 +248,35 @@ double qmDistorsionOfMapping (MTriangle *e)
   return dmin;
 }
 
+double qmDistorsionOfMapping (MQuadrangle *e)
+{
+  //  return 1.0;
+  if (e->getPolynomialOrder() == 1) return 1.0;
+  //  if (e->getPolynomialOrder() == 2) return mesh_functional_distorsion_p2(e);
+
+  IntPt *pts;
+  int npts;
+  e->getIntegrationPoints(e->getPolynomialOrder(),&npts, &pts);
+  double dmin;
+  for (int i = 0 ; i < npts; i++){
+    const double u = pts[i].pt[0];
+    const double v = pts[i].pt[1];
+    const double di  = mesh_functional_distorsion (e, u, v);
+    dmin = (i == 0)? di : std::min(dmin, di);
+  }
+  const fullMatrix<double>& points = e->getFunctionSpace()->points;
+
+  for (int i = 0; i < e->getNumPrimaryVertices(); i++) {
+    const double u = points(i, 0);
+    const double v = points(i, 1);
+    const double di  = mesh_functional_distorsion (e, u, v);
+    dmin = std::min(dmin, di);
+  }
+  //  printf("%g\n",dmin);
+  return dmin;
+}
+
+
 static double mesh_functional_distorsion(MTetrahedron *t, double u, double v, double w)
 {
   // compute uncurved element jacobian d_u x and d_v x
@@ -351,3 +381,63 @@ double qmTriangleAngles (MTriangle *e) {
 
   return worst_quality;
 }
+
+
+double qmQuadrangleAngles (MQuadrangle *e) {
+  double a = 100;
+  double worst_quality = std::numeric_limits<double>::max();
+  double mat[3][3];
+  double mat2[3][3];
+  double den = atan(a*(M_PI/4)) + atan(a*(2*M_PI/4 - (M_PI/4)));
+
+  // This matrix is used to "rotate" the triangle to get each vertex
+  // as the "origin" of the mapping in turn 
+  double rot[3][3];
+  rot[0][0]=-1; rot[0][1]=1; rot[0][2]=0;
+  rot[1][0]=-1; rot[1][1]=0; rot[1][2]=0;
+  rot[2][0]= 0; rot[2][1]=0; rot[2][2]=1;
+  double tmp[3][3];
+  
+  const double u[9] = {-1,-1, 1, 1, 0,0,1,-1,0};
+  const double v[9] = {-1, 1, 1,-1, -1,1,0,0,0};
+
+  for (int i = 0; i < 9; i++) {
+
+    e->getJacobian(u[i], v[i], 0, mat);
+    e->getPrimaryJacobian(u[i],v[i],0,mat2);
+    //    for (int j = 0; j < i; j++) {
+    //matmat(rot,mat,tmp);
+    //      memcpy(mat, tmp, sizeof(mat)); 
+    //    }
+    //get angle
+    double v1[3] = {mat[0][0],  mat[0][1],  mat[0][2] };
+    double v2[3] = {mat[1][0],  mat[1][1],  mat[1][2] };
+    double v3[3] = {mat2[0][0],  mat2[0][1],  mat2[0][2] };
+    double v4[3] = {mat2[1][0],  mat2[1][1],  mat2[1][2] };
+    norme(v1);
+    norme(v2);
+    norme(v3);
+    norme(v4);
+    double v12[3], v34[3];
+    prodve(v1,v2,v12);
+    prodve(v3,v4,v34);
+    norme(v12); 
+    norme(v34);
+    double orientation;
+    prosca(v12,v34,&orientation);
+
+    // If the if the triangle is "flipped" it's no good
+    //    if (orientation < 0)
+    //      return -std::numeric_limits<double>::max();
+
+    double c;
+    prosca(v1,v2,&c);
+    printf("%g %g\n",c,acos(c)*180/M_PI);
+    double x = fabs(acos(c))-M_PI/2;
+    double quality = (atan(a*(x+M_PI/4)) + atan(a*(2*M_PI/4 - (x+M_PI/4))))/den;
+    worst_quality = std::min(worst_quality, quality);
+  }
+
+  return worst_quality;
+}
+
diff --git a/Mesh/qualityMeasures.h b/Mesh/qualityMeasures.h
index cacf55add0..16be388eb1 100644
--- a/Mesh/qualityMeasures.h
+++ b/Mesh/qualityMeasures.h
@@ -10,16 +10,19 @@ class BDS_Point;
 class BDS_Face;
 class MVertex;
 class MTriangle;
+class MQuadrangle;
 class MTetrahedron;
 class MElement;
 
 enum qualityMeasure4Triangle {QMTRI_RHO, QMTRI_COND};
 enum qualityMeasure4Tet{QMTET_1, QMTET_2, QMTET_3, QMTET_ONE, QMTET_COND};
 
+double qmDistorsionOfMapping (MQuadrangle *e);
 double qmDistorsionOfMapping (MTriangle *e);
 double qmDistorsionOfMapping (MTetrahedron *e);
 
 double qmTriangleAngles (MTriangle *e);
+double qmQuadrangleAngles (MQuadrangle *e);
 
 double qmTriangle(MTriangle *f, const qualityMeasure4Triangle &cr); 
 double qmTriangle(BDS_Face *f, const qualityMeasure4Triangle &cr); 
diff --git a/Solver/TESTCASES/CylinderEddies.lua b/Solver/TESTCASES/CylinderEddies.lua
index 42b5d087ce..0a7d9cf3c5 100644
--- a/Solver/TESTCASES/CylinderEddies.lua
+++ b/Solver/TESTCASES/CylinderEddies.lua
@@ -20,7 +20,7 @@ end
      Example of a lua program driving the DG code
 --]]
 
-order = 3
+order = 5
 
 FS = functionLua(4, 'free_stream', {'XYZ'}):getName()
 
@@ -62,7 +62,7 @@ CFL = 20.1;
 dt = CFL * DG:computeInvSpectralRadius();
 print('DT = ',dt)
 T = 0;
-for i=1,100000 do
+for i=1,1000000 do
     dt = CFL * DG:computeInvSpectralRadius();    
     norm = DG:RK44(dt)
     T = T + dt
diff --git a/Solver/TESTCASES/cyl2.geo b/Solver/TESTCASES/cyl2.geo
index 08735cab6f..1e8ee12b1e 100644
--- a/Solver/TESTCASES/cyl2.geo
+++ b/Solver/TESTCASES/cyl2.geo
@@ -1,11 +1,11 @@
-a = .1;
-b = 1;
+a = .4;
+b = 2;
 radius = 0.5;
 radiusBoundaryLayer = 0.7;
 Point(1) = {0, 0, 0, a};
 
-nlayers=3;
-np=5;
+nlayers=2;
+np=3;
 np2=2;
 
 
diff --git a/Solver/dgAlgorithm.cpp b/Solver/dgAlgorithm.cpp
index fd3ad00617..8035d30533 100644
--- a/Solver/dgAlgorithm.cpp
+++ b/Solver/dgAlgorithm.cpp
@@ -117,12 +117,12 @@ void dgAlgorithm::residualVolume ( //dofManager &dof, // the DOF manager (maybe
 }
 
 void dgAlgorithm::residualInterface ( //dofManager &dof, // the DOF manager (maybe useless here)
-				   const dgConservationLaw &claw,   // the conservation law
-				   dgGroupOfFaces &group, 
-				   const fullMatrix<double> &solution, // solution !! at faces nodes
-				   fullMatrix<double> &solutionLeft, 
-				   fullMatrix<double> &solutionRight, 
-				   fullMatrix<double> &residual // residual !! at faces nodes
+				     const dgConservationLaw &claw,   // the conservation law
+				     dgGroupOfFaces &group, 
+				     const fullMatrix<double> &solution, // solution !! at faces nodes
+				     fullMatrix<double> &solutionLeft, 
+				     fullMatrix<double> &solutionRight, 
+				     fullMatrix<double> &residual // residual !! at faces nodes
 				      )
 { 
   // A) global operations before entering the loop over the faces
diff --git a/Solver/dgGroupOfElements.h b/Solver/dgGroupOfElements.h
index 55f742daa4..0b9be6a2d1 100644
--- a/Solver/dgGroupOfElements.h
+++ b/Solver/dgGroupOfElements.h
@@ -82,6 +82,7 @@ public:
   inline int getDimUVW () const {return _dimUVW;}
   inline int getDimXYZ () const {return _dimXYZ;}
   inline MElement* getElement (int iElement) const {return _elements[iElement];}  
+  inline const polynomialBasis & getFunctionSpace () const {return _fs;}
   inline const fullMatrix<double> & getIntegrationPointsMatrix () const {return *_integration;}
   inline const fullMatrix<double> & getCollocationMatrix () const {return *_collocation;}
   inline const fullMatrix<double> & getFluxRedistributionMatrix (int i) const {return *_redistributionFluxes[i];}
diff --git a/Solver/dgSystemOfEquations.h b/Solver/dgSystemOfEquations.h
index e8d89dff59..fdb887dc93 100644
--- a/Solver/dgSystemOfEquations.h
+++ b/Solver/dgSystemOfEquations.h
@@ -36,6 +36,9 @@ class dgSystemOfEquations {
   dgSystemOfEquations(const dgSystemOfEquations &) {}
   double computeTimeStepMethodOfLines () const;
 public:
+  const dgConservationLaw * getLaw() const {return _claw;}
+  const GModel            * getModel() const {return _gm;}
+  std::pair<dgGroupOfElements*,int> getElementPosition (MElement *);
   void setOrder (int order); // set the polynomial order
   void setConservationLaw (dgConservationLaw *law); // set the conservationLaw
   dgSystemOfEquations(GModel *_gm);
diff --git a/Solver/function.cpp b/Solver/function.cpp
index 00a19a8b9e..998d8358d5 100644
--- a/Solver/function.cpp
+++ b/Solver/function.cpp
@@ -143,6 +143,44 @@ functionConstant::functionConstant(const fullMatrix<double> *source){
   function::add(_name,this);
 }
 
+// function that enables to interpolate a DG solution using
+// geometrical search in a mesh 
+/*
+class functionSystemOfEquations::data : public dataCacheDouble {
+  dgSystemOfEquations *_sys;
+  dataCacheDouble &xyz;
+public:
+  data(dataCacheMap &m, dgSystemOfEquations *sys) :
+    _sys(sys), 
+    xyz(cacheMap.get("Solution",this)),
+    dataCacheDouble(m.getNbEvaluationPoints(), sys->getLaw()->getNbFields())
+  {
+  }
+  void _eval() {
+    int nP =xyz().size1();
+    if(_value.size1() != nP)
+      _value = fullMatrix<double>(nP,sys->getLaw()->getNbFields());
+    _value.setAll(0.0);
+    double fs[256];
+    for (int i=0;i<_value.size1();i++){
+      const double x = xyz(i,0);
+      const double y = xyz(i,1);
+      const double z = xyz(i,2);
+      MElement *e = _sys->getModel()->getMeshElementByCoord(SPoint3(x,y,z));
+      std::pair<dgGroupOfElements*,int> location = _sys->getElementPosition(e);
+      double U[3],X[3]={xyz(i,0),xyz(i,1),xyz(i,2)};
+      e->xyz2uvw (X,U);
+      location.first->getFunctionSpace().f(U[0],U[1],U[2],fs);      
+    }
+  }
+  dataCacheDouble *newDataCache(dataCacheMap *m)
+  {
+    return new data(this,_sys);
+  }
+};
+*/
+
+
 #include "Bindings.h"
 
 void function::registerDefaultFunctions()
diff --git a/Solver/function.h b/Solver/function.h
index 51916a46d1..9a81cbfa7d 100644
--- a/Solver/function.h
+++ b/Solver/function.h
@@ -8,6 +8,7 @@
 class dataCacheMap;
 class MElement;
 class binding;
+class dgSystemOfEquations;
 
 // those classes manage complex function dependencies and keep their values in cache so that they are not recomputed when it is not necessary. To do this, we use three classes : function, dataCache and dataCacheMap. The workflow is :
 //
@@ -193,4 +194,13 @@ class functionConstant : public function {
   dataCacheDouble *newDataCache(dataCacheMap *m);
   functionConstant(const fullMatrix<double> *source);
 };
+
+class functionSystemOfEquations : public function {
+  dgSystemOfEquations *_sys;
+public:
+  class data ;
+  dataCacheDouble *newDataCache(dataCacheMap *m);
+  functionSystemOfEquations(dgSystemOfEquations *sys) : _sys(sys) {}
+};
+
 #endif
-- 
GitLab