From 624576160c0239a55a393af2c7d6428b0d565690 Mon Sep 17 00:00:00 2001
From: Thomas Toulorge <thomas.toulorge@mines-paristech.fr>
Date: Mon, 22 Sep 2014 08:45:01 +0000
Subject: [PATCH] Added "CADDist" contribution to objective function in
 high-order mesh optimizer

---
 .../OptHomObjContribCADDist.h                 |  84 +++++--------
 contrib/HighOrderMeshOptimizer/OptHomRun.cpp  |   1 +
 contrib/MeshOptimizer/MeshOptCommon.h         |   1 +
 contrib/MeshOptimizer/MeshOptPatch.cpp        | 119 +++++++++---------
 contrib/MeshOptimizer/MeshOptPatch.h          |   6 +-
 5 files changed, 93 insertions(+), 118 deletions(-)

diff --git a/contrib/HighOrderMeshOptimizer/OptHomObjContribCADDist.h b/contrib/HighOrderMeshOptimizer/OptHomObjContribCADDist.h
index d4b8d1e2aa..40aeccd354 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomObjContribCADDist.h
+++ b/contrib/HighOrderMeshOptimizer/OptHomObjContribCADDist.h
@@ -10,8 +10,9 @@ template<class FuncType>
 class ObjContribCADDist : public ObjContrib, public FuncType
 {
 public:
-  ObjContribCADDist(double weight);
+  ObjContribCADDist(double weight, double geomTol);
   virtual ~ObjContribCADDist() {}
+  virtual ObjContrib *copy() const;
   virtual void initialize(Patch *mesh);
   virtual bool fail() { return false; }
   virtual bool addContrib(double &Obj, alglib::real_1d_array &gradObj);
@@ -24,31 +25,30 @@ public:
 protected:
   Patch *_mesh;
   double _weight;
-  std::vector<int> _nBezEl;                                                             // Number of Bezier poly. and for an el.
-  inline const int &nBezEl(int iEl) { return _nBezEl[iEl]; }
-  inline int indGSJ(int iEl, int l, int iPC) { return iPC*_nBezEl[iEl]+l; }
-  void metricMinAndGradients(int iEl, std::vector<double> &sJ, std::vector<double> &gSJ);
+  double _geomTol;
 };
 
 
 template<class FuncType>
-ObjContribCADDist<FuncType>::ObjContribCADDist(double weight) :
-  ObjContrib("MetricMin", FuncType::getNamePrefix()+"MetricMin"),
-  _mesh(0), _weight(weight)
+ObjContribCADDist<FuncType>::ObjContribCADDist(double weight, double geomTol) :
+  ObjContrib("MetricMin", FuncType::getNamePrefix()+"CADDist"),
+  _mesh(0), _weight(weight), _geomTol(geomTol)
 {
 }
 
 
+template<class FuncType>
+ObjContrib *ObjContribCADDist<FuncType>::copy() const
+{
+  return new ObjContribCADDist<FuncType>(*this);
+}
+
+
 template<class FuncType>
 void ObjContribCADDist<FuncType>::initialize(Patch *mesh)
 {
   _mesh = mesh;
 
-  // Initialize _nBezEl
-  _nBezEl.resize(_mesh->nEl());
-  for (int iEl=0; iEl<_mesh->nEl(); iEl++)
-   _nBezEl[iEl] = _mesh->el(iEl)->getJacobianFuncSpace()->getNumJacNodes();
-
   updateMinMax();
   FuncType::initialize(_min, _max);
 }
@@ -60,17 +60,16 @@ bool ObjContribCADDist<FuncType>::addContrib(double &Obj, alglib::real_1d_array
   _min = BIGVAL;
   _max = -BIGVAL;
 
+  std::vector<double> gradF;
   for (int iEl = 0; iEl < _mesh->nEl(); iEl++) {
-    std::vector<double> mM(_nBezEl[iEl]);                       // Min. of Metric
-    std::vector<double> gMM(_nBezEl[iEl]*_mesh->nPCEl(iEl));    // Dummy gradients of metric min.
-    metricMinAndGradients(iEl, mM, gMM);
-    for (int l = 0; l < _nBezEl[iEl]; l++) {                    // Add contribution for each Bezier coeff.
-      Obj += _weight * FuncType::compute(mM[l]);
-      for (int iPC = 0; iPC < _mesh->nPCEl(iEl); iPC++)
-        gradObj[_mesh->indPCEl(iEl,iPC)] +=
-            _weight * FuncType::computeDiff(mM[l], gMM[indGSJ(iEl, l, iPC)]);
-      _min = std::min(_min, mM[l]);
-      _max = std::max(_max, mM[l]);
+    double f;
+    if (_mesh->bndDistAndGradients(iEl, f, gradF, _geomTol)) {
+      _min = std::min(_min, f);
+      _max = std::max(_max, f);
+      Obj += FuncType::compute(f) * _weight;
+      const double dFact = _weight * FuncType::computeDiff(f);
+      for (size_t i = 0; i < _mesh->nPCEl(iEl); ++i)
+        gradObj[_mesh->indPCEl(iEl, i)] += gradF[i] * dFact;
     }
   }
 
@@ -84,13 +83,12 @@ void ObjContribCADDist<FuncType>::updateMinMax()
   _min = BIGVAL;
   _max = -BIGVAL;
 
+  std::vector<double> dumGradF;
   for (int iEl = 0; iEl < _mesh->nEl(); iEl++) {
-    std::vector<double> mM(_nBezEl[iEl]);                         // Min. of Metric
-    std::vector<double> dumGMM(_nBezEl[iEl]*_mesh->nPCEl(iEl));   // Dummy gradients of metric min.
-    metricMinAndGradients(iEl, mM, dumGMM);
-    for (int l = 0; l < _nBezEl[iEl]; l++) {                      // Check each Bezier coeff.
-      _min = std::min(_min, mM[l]);
-      _max = std::max(_max, mM[l]);
+    double f;
+    if (_mesh->bndDistAndGradients(iEl, f, dumGradF, _geomTol)) {
+      _min = std::min(_min, f);
+      _max = std::max(_max, f);
     }
   }
 }
@@ -99,33 +97,9 @@ void ObjContribCADDist<FuncType>::updateMinMax()
 template<class FuncType>
 void ObjContribCADDist<FuncType>::updateResults(MeshOptResults &res) const
 {
-  res.minMetricMin = std::min(_min, res.minMetricMin);
-  res.maxMetricMin = std::max(_max, res.maxMetricMin);
+  res.minCADDist = std::min(_min, res.minCADDist);
+  res.maxCADDist = std::max(_max, res.maxCADDist);
 }
 
 
-//bool MeshOpt::addBndObjGrad(double factor, double &Obj, alglib::real_1d_array &gradObj)
-//{
-//  maxDistCAD = 0.0;
-//
-//  std::vector<double> gradF;
-//  double DISTANCE = 0.0;
-//  for (int iEl = 0; iEl < mesh.nEl(); iEl++) {
-//    double f;
-//    if (mesh.bndDistAndGradients(iEl, f, gradF, geomTol)) {
-//      maxDistCAD = std::max(maxDistCAD,f);
-//      DISTANCE += f;
-//      Obj += f * factor;
-//      for (size_t i = 0; i < mesh.nPCEl(iEl); ++i){
-//        gradObj[mesh.indPCEl(iEl, i)] += gradF[i] * factor;
-//  //  printf("gradf[%d] = %12.5E\n",i,gradF[i]*factor);
-//      }
-//    }
-//  }
-//  //  printf("DIST = %12.5E\n",DISTANCE);
-//  return true;
-//
-//}
-
-
 #endif /* _OPTHOMOBJCONTRIBCADDIST_H_ */
diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
index 52095e5862..cb47ed375b 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
@@ -749,6 +749,7 @@ void HighOrderMeshOptimizer(GModel *gm, OptHomParameters &p)
 #include "MeshOptObjContribScaledNodeDispSq.h"
 #include "OptHomObjContribScaledJac.h"
 #include "OptHomObjContribMetricMin.h"
+#include "OptHomObjContribCADDist.h"
 #include "MeshOptimizer.h"
 
 
diff --git a/contrib/MeshOptimizer/MeshOptCommon.h b/contrib/MeshOptimizer/MeshOptCommon.h
index 7314c0ea5b..c2e2f2f366 100644
--- a/contrib/MeshOptimizer/MeshOptCommon.h
+++ b/contrib/MeshOptimizer/MeshOptCommon.h
@@ -43,6 +43,7 @@ struct MeshOptResults {                             // Output of mesh optimizati
   double minNodeDisp, maxNodeDisp;                  // Range of node displacement
   double minScaledJac, maxScaledJac;                // Range of Scaled Jacobians
   double minMetricMin, maxMetricMin;                // Range of min. of metric
+  double minCADDist, maxCADDist;                    // Range of distance to CAD
   MeshOptResults();
 private:
   static const double BIGVAL;
diff --git a/contrib/MeshOptimizer/MeshOptPatch.cpp b/contrib/MeshOptimizer/MeshOptPatch.cpp
index d812dcf0a7..0577a25257 100644
--- a/contrib/MeshOptimizer/MeshOptPatch.cpp
+++ b/contrib/MeshOptimizer/MeshOptPatch.cpp
@@ -29,11 +29,12 @@
 
 #include "GmshMessage.h"
 #include "GRegion.h"
+#include "GFace.h"
 #include "MTriangle.h"
 #include "MQuadrangle.h"
 #include "MTetrahedron.h"
 #include "BasisFactory.h"
-//#include "OptHomIntegralBoundaryDist.h"
+#include "OptHomIntegralBoundaryDist.h"
 #include "MeshOptPatch.h"
 
 
@@ -437,61 +438,61 @@ void Patch::metricMinAndGradients(int iEl, std::vector<double> &lambda,
 }
 
 
-//bool Patch::bndDistAndGradients(int iEl, double &f, std::vector<double> &gradF, double eps)
-//{
-//  MElement *element = _el[iEl];
-//  f = 0.;
-//  // dommage ;-)
-//  if (element->getDim() != 2)
-//    return false;
-//
-//  int currentId = 0;
-//  std::vector<int> vertex2param(element->getNumVertices());
-//  for (size_t i = 0; i < element->getNumVertices(); ++i) {
-//    if (_el2FV[iEl][i] >= 0) {
-//      vertex2param[i] = currentId;
-//      currentId += _nPCFV[_el2FV[iEl][i]];
-//    }
-//    else
-//      vertex2param[i] = -1;
-//  }
-//  gradF.clear();
-//  gradF.resize(currentId, 0.);
-//
-//  const nodalBasis &elbasis = *element->getFunctionSpace();
-//  bool edgeFound = false;
-//  for (int iEdge = 0; iEdge < element->getNumEdges(); ++iEdge) {
-//    int clId = elbasis.getClosureId(iEdge, 1);
-//    const std::vector<int> &closure = elbasis.closures[clId];
-//    std::vector<MVertex *> vertices;
-//    GEdge *edge = NULL;
-//    for (size_t i = 0; i < closure.size(); ++i) {
-//      MVertex *v = element->getVertex(closure[i]);
-//      vertices.push_back(v);
-//      // only valid in 2D
-//      if ((int)i >= 2 && v->onWhat() && v->onWhat()->dim() == 1) {
-//        edge = v->onWhat()->cast2Edge();
-//      }
-//    }
-//    if (edge) {
-//      edgeFound = true;
-//      std::vector<double> localgrad;
-//      std::vector<SPoint3> nodes(closure.size());
-//      std::vector<double> params(closure.size());
-//      std::vector<bool> onedge(closure.size());
-//      for (size_t i = 0; i < closure.size(); ++i) {
-//        nodes[i] = _xyz[_el2V[iEl][closure[i]]];
-//        onedge[i] = element->getVertex(closure[i])->onWhat() == edge && _el2FV[iEl][closure[i]] >= 0;
-//        if (onedge[i]) {
-//          params[i] = _uvw[_el2FV[iEl][closure[i]]].x();
-//        }else
-//          reparamMeshVertexOnEdge(element->getVertex(closure[i]), edge, params[i]);
-//      }
-//      f += computeBndDistAndGradient(edge, params, vertices,
-//            *BasisFactory::getNodalBasis(elbasis.getClosureType(clId)), nodes, onedge, localgrad, eps);
-//      for (size_t i = 0; i < closure.size(); ++i)
-//        if (onedge[i]) gradF[vertex2param[closure[i]]] += localgrad[i];
-//    }
-//  }
-//  return edgeFound;
-//}
+bool Patch::bndDistAndGradients(int iEl, double &f, std::vector<double> &gradF, double eps)
+{
+  MElement *element = _el[iEl];
+  f = 0.;
+  // dommage ;-)
+  if (element->getDim() != 2)
+    return false;
+
+  int currentId = 0;
+  std::vector<int> vertex2param(element->getNumVertices());
+  for (size_t i = 0; i < element->getNumVertices(); ++i) {
+    if (_el2FV[iEl][i] >= 0) {
+      vertex2param[i] = currentId;
+      currentId += _nPCFV[_el2FV[iEl][i]];
+    }
+    else
+      vertex2param[i] = -1;
+  }
+  gradF.clear();
+  gradF.resize(currentId, 0.);
+
+  const nodalBasis &elbasis = *element->getFunctionSpace();
+  bool edgeFound = false;
+  for (int iEdge = 0; iEdge < element->getNumEdges(); ++iEdge) {
+    int clId = elbasis.getClosureId(iEdge, 1);
+    const std::vector<int> &closure = elbasis.closures[clId];
+    std::vector<MVertex *> vertices;
+    GEdge *edge = NULL;
+    for (size_t i = 0; i < closure.size(); ++i) {
+      MVertex *v = element->getVertex(closure[i]);
+      vertices.push_back(v);
+      // only valid in 2D
+      if ((int)i >= 2 && v->onWhat() && v->onWhat()->dim() == 1) {
+        edge = v->onWhat()->cast2Edge();
+      }
+    }
+    if (edge) {
+      edgeFound = true;
+      std::vector<double> localgrad;
+      std::vector<SPoint3> nodes(closure.size());
+      std::vector<double> params(closure.size());
+      std::vector<bool> onedge(closure.size());
+      for (size_t i = 0; i < closure.size(); ++i) {
+        nodes[i] = _xyz[_el2V[iEl][closure[i]]];
+        onedge[i] = element->getVertex(closure[i])->onWhat() == edge && _el2FV[iEl][closure[i]] >= 0;
+        if (onedge[i]) {
+          params[i] = _uvw[_el2FV[iEl][closure[i]]].x();
+        }else
+          reparamMeshVertexOnEdge(element->getVertex(closure[i]), edge, params[i]);
+      }
+      f += computeBndDistAndGradient(edge, params, vertices,
+            *BasisFactory::getNodalBasis(elbasis.getClosureType(clId)), nodes, onedge, localgrad, eps);
+      for (size_t i = 0; i < closure.size(); ++i)
+        if (onedge[i]) gradF[vertex2param[closure[i]]] += localgrad[i];
+    }
+  }
+  return edgeFound;
+}
diff --git a/contrib/MeshOptimizer/MeshOptPatch.h b/contrib/MeshOptimizer/MeshOptPatch.h
index 2207c839bb..209f173c0a 100644
--- a/contrib/MeshOptimizer/MeshOptPatch.h
+++ b/contrib/MeshOptimizer/MeshOptPatch.h
@@ -83,16 +83,14 @@ public:
   double scaledNodeDispSq(int iFV);
   void gradScaledNodeDispSq(int iFV, std::vector<double> &gDSq);
 
-  // High-order: scaled Jacobian and metric measures
+  // High-order: scaled Jacobian and metric measures, distance to CAD
   inline const int &nBezEl(int iEl) { return _nBezEl[iEl]; }
   inline int indGSJ(int iEl, int l, int iPC) { return iPC*_nBezEl[iEl]+l; }
   void initScaledJac();
   void scaledJacAndGradients(int iEl, std::vector<double> &sJ, std::vector<double> &gSJ);
   void initMetricMin();
   void metricMinAndGradients(int iEl, std::vector<double> &sJ, std::vector<double> &gSJ);
-
-  // TODO: Re-introduce distance to boundary
-//  bool bndDistAndGradients(int iEl, double &f , std::vector<double> &gradF, double eps);
+  bool bndDistAndGradients(int iEl, double &f , std::vector<double> &gradF, double eps);
 
 private:
 
-- 
GitLab