From 577221ee8f42ce19c13ed1355366924f0cd73c57 Mon Sep 17 00:00:00 2001
From: Thomas Toulorge <thomas.toulorge@mines-paristech.fr>
Date: Mon, 28 Oct 2013 23:09:31 +0000
Subject: [PATCH] Added maxDistToStraight to MElement. High order mesh
 optimization: fixed bug with length scale, worked on one-by-one strategy.

---
 Fltk/highOrderToolsWindow.cpp                 |   4 +-
 Geo/MElement.cpp                              |  23 ++
 Geo/MElement.h                                |   3 +
 contrib/HighOrderMeshOptimizer/OptHOM.cpp     |   2 +-
 contrib/HighOrderMeshOptimizer/OptHomMesh.cpp |  27 +--
 contrib/HighOrderMeshOptimizer/OptHomRun.cpp  | 225 ++++++++----------
 contrib/HighOrderMeshOptimizer/OptHomRun.h    |   4 +-
 7 files changed, 131 insertions(+), 157 deletions(-)

diff --git a/Fltk/highOrderToolsWindow.cpp b/Fltk/highOrderToolsWindow.cpp
index d9410ed48e..93683f2427 100644
--- a/Fltk/highOrderToolsWindow.cpp
+++ b/Fltk/highOrderToolsWindow.cpp
@@ -343,11 +343,11 @@ highOrderToolsWindow::highOrderToolsWindow(int deltaFontSize)
   value[5] = new Fl_Value_Input
     (x, y, IW/2, BH);
   value[5]->align(FL_ALIGN_RIGHT);
-  value[5]->value(1.e+5);
+  value[5]->value(1000.);
   value[6] = new Fl_Value_Input
     (x+IW/2,y, IW/2, BH, "W fixed / W free");
   value[6]->align(FL_ALIGN_RIGHT);
-  value[6]->value(1.e+2);
+  value[6]->value(1.);
 
   y += BH;
   value[3] = new Fl_Value_Input
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index 6799ec9e7e..7a4acf9cb8 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -112,6 +112,29 @@ double MElement::rhoShapeMeasure()
     return 0.;
 }
 
+double MElement::maxDistToStraight()
+{
+  const nodalBasis *lagBasis = getFunctionSpace();
+  const fullMatrix<double> &uvw = lagBasis->points;
+  const int &nV = uvw.size1();
+  const int &dim = uvw.size2();
+  const nodalBasis *lagBasis1 = getFunctionSpace(1);
+  const int &nV1 = lagBasis1->points.size1();
+  SPoint3 xyz1[nV1];
+  for (int iV = 0; iV < nV1; ++iV) xyz1[iV] = getVertex(iV)->point();
+  double maxdx = 0.;
+  for (int iV = nV1; iV < nV; ++iV) {
+    double f[256];
+    lagBasis1->f(uvw(iV, 0), (dim > 1) ? uvw(iV, 1) : 0., (dim > 2) ? uvw(iV, 2) : 0., f);
+    SPoint3 xyzS(0.,0.,0.);
+    for (int iSF = 0; iSF < nV1; ++iSF) xyzS += xyz1[iSF]*f[iSF];
+    SVector3 vec(xyzS,getVertex(iV)->point());
+    double dx = vec.norm();
+    if (dx > maxdx) maxdx = dx;
+  }
+  return maxdx;
+}
+
 void MElement::scaledJacRange(double &jmin, double &jmax, GEntity *ge)
 {
   jmin = jmax = 1.0;
diff --git a/Geo/MElement.h b/Geo/MElement.h
index 67c280f409..12e362dc63 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -175,6 +175,9 @@ class MElement
   virtual double maxEdge();
   virtual double minEdge();
 
+  // Max. distance between curved and straight element among all high-order nodes
+  double maxDistToStraight();
+
   // get the quality measures
   virtual double rhoShapeMeasure();
   virtual double gammaShapeMeasure(){ return 0.; }
diff --git a/contrib/HighOrderMeshOptimizer/OptHOM.cpp b/contrib/HighOrderMeshOptimizer/OptHOM.cpp
index c7fb2a88a3..6ecfb3bf9c 100644
--- a/contrib/HighOrderMeshOptimizer/OptHOM.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHOM.cpp
@@ -316,7 +316,7 @@ int OptHOM::optimize(double weightFixed, double weightFree, double b_min,
   // Set weights & length scale for non-dimensionalization
   lambda = weightFixed;
   lambda2 = weightFree;
-  std::vector<double> dSq(mesh.nVert());
+  std::vector<double> dSq(mesh.nEl());
   mesh.distSqToStraight(dSq);
   const double maxDSq = *max_element(dSq.begin(),dSq.end());
   if (maxDSq < 1.e-10) {                                        // Length scale for non-dim. distance
diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
index e24731670d..e8cdf9de65 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
@@ -207,31 +207,10 @@ void Mesh::updateMesh(const double *it)
 
 }
 
-void Mesh::distSqToStraight(std::vector<double> &dSq)
-{
-  std::vector<SPoint3> sxyz(nVert());
+void Mesh::distSqToStraight(std::vector<double> &dSq) {
   for (int iEl = 0; iEl < nEl(); iEl++) {
-    MElement *el = _el[iEl];
-    const polynomialBasis *lagrange = (polynomialBasis*)el->getFunctionSpace();
-    const polynomialBasis *lagrange1 = (polynomialBasis*)el->getFunctionSpace(1);
-    int nV = lagrange->points.size1();
-    int nV1 = lagrange1->points.size1();
-    for (int i = 0; i < nV1; ++i) {
-      sxyz[_el2V[iEl][i]] = _vert[_el2V[iEl][i]]->point();
-    }
-    int dim = lagrange->points.size2();
-    for (int i = nV1; i < nV; ++i) {
-      double f[256];
-      lagrange1->f(lagrange->points(i, 0), dim > 1 ? lagrange->points(i, 1) : 0.,
-                   dim > 2 ? lagrange->points(i, 2) : 0., f);
-      for (int j = 0; j < nV1; ++j)
-        sxyz[_el2V[iEl][i]] += sxyz[_el2V[iEl][j]] * f[j];
-    }
-  }
-
-  for (int iV = 0; iV < nVert(); iV++) {
-    SPoint3 d = _xyz[iV]-sxyz[iV];
-    dSq[iV] = d[0]*d[0]+d[1]*d[1]+d[2]*d[2];
+    const double d = _el[iEl]->maxDistToStraight();
+    dSq[iEl] = d*d;
   }
 }
 
diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
index 7a013dec96..b5f5d615ec 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
@@ -47,37 +47,6 @@
 
 #if defined(HAVE_BFGS)
 
-double distMaxStraight(MElement *el)
-{
-  const polynomialBasis *lagrange = (polynomialBasis*)el->getFunctionSpace();
-  const polynomialBasis *lagrange1 = (polynomialBasis*)el->getFunctionSpace(1);
-  int nV = lagrange->points.size1();
-  int nV1 = lagrange1->points.size1();
-  SPoint3 sxyz[256];
-  for (int i = 0; i < nV1; ++i) {
-    sxyz[i] = el->getVertex(i)->point();
-  }
-  for (int i = nV1; i < nV; ++i) {
-    double f[256];
-    double u = 0., v = 0., w = 0.;
-    if(lagrange->points.size2() > 0) u = lagrange->points(i, 0);
-    if(lagrange->points.size2() > 1) v = lagrange->points(i, 1);
-    if(lagrange->points.size2() > 2) w = lagrange->points(i, 2);
-    lagrange1->f(u, v, w, f);
-    for (int j = 0; j < nV1; ++j)
-      sxyz[i] += sxyz[j] * f[j];
-  }
-
-  double maxdx = 0.0;
-  for (int iV = nV1; iV < nV; iV++) {
-    SVector3 d = el->getVertex(iV)->point()-sxyz[iV];
-    double dx = d.norm();
-    if (dx > maxdx) maxdx = dx;
-  }
-
-  return maxdx;
-}
-
 void exportMeshToDassault(GModel *gm, const std::string &fn, int dim)
 {
   FILE *f = fopen(fn.c_str(),"w");
@@ -167,7 +136,7 @@ static std::set<MElement*> getSurroundingBlob
 {
 
   const SPoint3 p = el->barycenter();
-  const double dist = distMaxStraight(el);
+  const double dist = el->maxDistToStraight();
   const double limDist = ((optPrimSurfMesh && (dist < 1.e-10)) ?
                           el->getOuterRadius() : dist) * distFactor;
 
@@ -395,7 +364,7 @@ static std::set<MElement*> getSurroundingBlob3D
    const std::map<MVertex*, std::vector<MElement*> > &vertex2elements,
    const double distFactor)
 {
-  const double limDist = distMaxStraight(el) * distFactor;
+  const double limDist = el->maxDistToStraight() * distFactor;
 
   std::set<MElement*> blob;
   std::list<MElement*> currentLayer, lastLayer;
@@ -499,111 +468,111 @@ static void optimizeOneByOne
 
     for (int iterBlob=0; iterBlob<p.maxAdaptBlob; iterBlob++) {
 
-      OptHOM *opt;
+//      OptHOM *opt;
+//
+//      // First step: small blob with unsafe optimization (only 1st-order
+//      // bnd. vertices fixed)
+//      std::set<MElement*> toOptimizePrim = getSurroundingBlob
+//        (worstEl, nbLayers, vertex2elements, distanceFactor, 0, p.optPrimSurfMesh);
+//      std::set<MVertex*> toFix1 = getPrimBndVertices(toOptimizePrim, vertex2elements);
+//      std::set<MElement*> toOptimize1;
+//      std::set_difference(toOptimizePrim.begin(),toOptimizePrim.end(),
+//                          badElts.begin(),badElts.end(), // Do not optimize badElts
+//                          std::inserter(toOptimize1, toOptimize1.end()));
+//      Msg::Info("Optimizing primary blob %i (max. %i remaining) composed of"
+//                " %4d elements", iBadEl, badElts.size(), toOptimize1.size());
+//      fflush(stdout);
+//      opt = new OptHOM(element2entity, toOptimize1, toFix1, p.fixBndNodes);
+//      //std::ostringstream ossI1;
+//      //ossI1 << "initial_primary_" << iter << ".msh";
+//      //opt->mesh.writeMSH(ossI1.str().c_str());
+//      success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX,
+//                              false, samples, p.itMax, p.optPassMax);
+//
+//      // Second step: add external layer, check it and optimize it safely (all
+//      // bnd. vertices fixed) if new broken element
+//      if (success > 0) {
+//        opt->mesh.updateGEntityPositions();
+//        std::set<MElement*> layer = addBlobLayer(toOptimizePrim, vertex2elements);
+//        if (detectNewBrokenElement(layer, badElts, p)) {
+//          delete opt;
+//          std::set<MVertex*> toFix2 = getAllBndVertices(toOptimizePrim, vertex2elements);
+//          std::set<MElement*> toOptimize2;
+//          std::set_difference(toOptimizePrim.begin(),toOptimizePrim.end(),
+//                              badElts.begin(),badElts.end(),
+//                              std::inserter(toOptimize2, toOptimize2.end()));
+//          Msg::Info("Optimizing corrective blob %i (max. %i remaining) "
+//                    "composed of %4d elements", iBadEl, badElts.size(),
+//                    toOptimize2.size());
+//          fflush(stdout);
+//          opt = new OptHOM(element2entity, toOptimize2, toFix2, p.fixBndNodes);
+//          //std::ostringstream ossI1;
+//          //ossI1 << "initial_corrective_" << iter << ".msh";
+//          //opt->mesh.writeMSH(ossI1.str().c_str());
+//          success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN,
+//                                  p.BARRIER_MAX, false, samples, p.itMax, p.optPassMax);
+//          if (success >= 0 && p.BARRIER_MIN_METRIC > 0) {
+//            Msg::Info("Jacobian optimization succeed, starting svd optimization");
+//            success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN_METRIC,
+//                                    p.BARRIER_MAX, true, samples, p.itMax, p.optPassMax);
+//          }
+//        }
+//        else {
+//          Msg::Info("Primary blob %i did not break new elements, "
+//                    "no correction needed", iBadEl);
+//          fflush(stdout);
+//        }
+//      }
 
-      // First step: small blob with unsafe optimization (only 1st-order
-      // bnd. vertices fixed)
       std::set<MElement*> toOptimizePrim = getSurroundingBlob
-        (worstEl, nbLayers, vertex2elements, distanceFactor, 0, p.optPrimSurfMesh);
-      std::set<MVertex*> toFix1 = getPrimBndVertices(toOptimizePrim, vertex2elements);
-      std::set<MElement*> toOptimize1;
+        (worstEl, nbLayers, vertex2elements, distanceFactor, 1, p.optPrimSurfMesh);
+//    std::set<MElement*> layer = addBlobLayer(toOptimizePrim, vertex2elements);
+      std::set<MVertex*> toFix = getAllBndVertices(toOptimizePrim, vertex2elements);
+      std::set<MElement*> toOptimize;
       std::set_difference(toOptimizePrim.begin(),toOptimizePrim.end(),
-                          badElts.begin(),badElts.end(), // Do not optimize badElts
-                          std::inserter(toOptimize1, toOptimize1.end()));
-      Msg::Info("Optimizing primary blob %i (max. %i remaining) composed of"
-                " %4d elements", iBadEl, badElts.size(), toOptimize1.size());
+                          badElts.begin(),badElts.end(),
+                          std::inserter(toOptimize, toOptimize.end()));
+      Msg::Info("Optimizing blob %i (max. %i remaining) "
+                "composed of %4d elements", iBadEl, badElts.size(),
+                toOptimize.size());
       fflush(stdout);
-      opt = new OptHOM(element2entity, toOptimize1, toFix1, p.fixBndNodes);
+      OptHOM *opt = new OptHOM(element2entity, toOptimize, toFix, p.fixBndNodes);
       //std::ostringstream ossI1;
-      //ossI1 << "initial_primary_" << iter << ".msh";
+      //ossI1 << "initial_corrective_" << iter << ".msh";
       //opt->mesh.writeMSH(ossI1.str().c_str());
-      success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX,
-                              false, samples, p.itMax, p.optPassMax);
+      success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN,
+                              p.BARRIER_MAX, false, samples, p.itMax, p.optPassMax);
+      if (success >= 0 && p.BARRIER_MIN_METRIC > 0) {
+        Msg::Info("Jacobian optimization succeed, starting svd optimization");
+        success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN_METRIC,
+                                p.BARRIER_MAX, true, samples, p.itMax, p.optPassMax);
+      }
 
-      // Second step: add external layer, check it and optimize it safely (all
-      // bnd. vertices fixed) if new broken element
-      if (success > 0) {
+      // Measure min and max Jac., update mesh
+      if ((success > 0) || (iterBlob == p.maxAdaptBlob-1)) {
+        double minJac, maxJac, distMaxBND, distAvgBND;
+        opt->recalcJacDist();
+        opt->getJacDist(minJac, maxJac, distMaxBND, distAvgBND);
+        p.minJac = std::min(p.minJac,minJac);
+        p.maxJac = std::max(p.maxJac,maxJac);
         opt->mesh.updateGEntityPositions();
-        std::set<MElement*> layer = addBlobLayer(toOptimizePrim, vertex2elements);
-        if (detectNewBrokenElement(layer, badElts, p)) {
-          delete opt;
-          std::set<MVertex*> toFix2 = getAllBndVertices(toOptimizePrim, vertex2elements);
-          std::set<MElement*> toOptimize2;
-          std::set_difference(toOptimizePrim.begin(),toOptimizePrim.end(),
-                              badElts.begin(),badElts.end(),
-                              std::inserter(toOptimize2, toOptimize2.end()));
-          Msg::Info("Optimizing corrective blob %i (max. %i remaining) "
-                    "composed of %4d elements", iBadEl, badElts.size(),
-                    toOptimize2.size());
-          fflush(stdout);
-          opt = new OptHOM(element2entity, toOptimize2, toFix2, p.fixBndNodes);
-          //std::ostringstream ossI1;
-          //ossI1 << "initial_corrective_" << iter << ".msh";
-          //opt->mesh.writeMSH(ossI1.str().c_str());
-          success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN,
-                                  p.BARRIER_MAX, false, samples, p.itMax, p.optPassMax);
-          if (success >= 0 && p.BARRIER_MIN_METRIC > 0) {
-            Msg::Info("Jacobian optimization succeed, starting svd optimization");
-            success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN_METRIC,
-                                    p.BARRIER_MAX, true, samples, p.itMax, p.optPassMax);
-          }
-        }
-        else {
-          Msg::Info("Primary blob %i did not break new elements, "
-                    "no correction needed", iBadEl);
-          fflush(stdout);
-        }
       }
 
-//      std::set<MElement*> toOptimizePrim = getSurroundingBlob
-//        (worstEl, nbLayers, vertex2elements, distanceFactor, 1, p.optPrimSurfMesh);
-////    std::set<MElement*> layer = addBlobLayer(toOptimizePrim, vertex2elements);
-//      std::set<MVertex*> toFix = getAllBndVertices(toOptimizePrim, vertex2elements);
-//      std::set<MElement*> toOptimize;
-//      std::set_difference(toOptimizePrim.begin(),toOptimizePrim.end(),
-//                          badElts.begin(),badElts.end(),
-//                          std::inserter(toOptimize, toOptimize.end()));
-//      Msg::Info("Optimizing blob %i (max. %i remaining) "
-//                "composed of %4d elements", iBadEl, badElts.size(),
-//                toOptimize.size());
-//      fflush(stdout);
-//      OptHOM *opt = new OptHOM(element2entity, toOptimize, toFix, p.fixBndNodes);
-//      //std::ostringstream ossI1;
-//      //ossI1 << "initial_corrective_" << iter << ".msh";
-//      //opt->mesh.writeMSH(ossI1.str().c_str());
-//      success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN,
-//                              p.BARRIER_MAX, false, samples, p.itMax, p.optPassMax);
-//      if (success >= 0 && p.BARRIER_MIN_METRIC > 0) {
-//        Msg::Info("Jacobian optimization succeed, starting svd optimization");
-//        success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN_METRIC,
-//                                p.BARRIER_MAX, true, samples, p.itMax, p.optPassMax);
-//      }
-//
-//      // Measure min and max Jac., update mesh
-//      if ((success > 0) || (iterBlob == p.maxAdaptBlob-1)) {
-//        double minJac, maxJac, distMaxBND, distAvgBND;
-//        opt->recalcJacDist();
-//        opt->getJacDist(minJac, maxJac, distMaxBND, distAvgBND);
-//        p.minJac = std::min(p.minJac,minJac);
-//        p.maxJac = std::max(p.maxJac,maxJac);
-//        opt->mesh.updateGEntityPositions();
-//      }
-//
-//      //std::ostringstream ossI2;
-//      //ossI2 << "final_ITER_" << iter << ".msh";
-//      //temp.mesh.writeMSH(ossI2.str().c_str());
-//      if (success <= 0) {
-//        distanceFactor *= p.adaptBlobDistFact;
-//        nbLayers *= p.adaptBlobLayerFact;
-//        Msg::Info("Blob %i failed (adapt #%i), adapting with increased size",
-//                  iBadEl, iterBlob);
-////        if (iterBlob == p.maxAdaptBlob-1) {
-//          std::ostringstream ossI2;
-//          ossI2 << "final_" << iBadEl << ".msh";
-//          opt->mesh.writeMSH(ossI2.str().c_str());
-////        }
-//      }
-//      else break;
+      //std::ostringstream ossI2;
+      //ossI2 << "final_ITER_" << iter << ".msh";
+      //temp.mesh.writeMSH(ossI2.str().c_str());
+      if (success <= 0) {
+        distanceFactor *= p.adaptBlobDistFact;
+        nbLayers *= p.adaptBlobLayerFact;
+        Msg::Info("Blob %i failed (adapt #%i), adapting with increased size",
+                  iBadEl, iterBlob);
+//        if (iterBlob == p.maxAdaptBlob-1) {
+          std::ostringstream ossI2;
+          ossI2 << "final_" << iBadEl << ".msh";
+          opt->mesh.writeMSH(ossI2.str().c_str());
+//        }
+      }
+      else break;
 
     }
 
diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.h b/contrib/HighOrderMeshOptimizer/OptHomRun.h
index f82751da05..e934f01ad3 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomRun.h
+++ b/contrib/HighOrderMeshOptimizer/OptHomRun.h
@@ -61,8 +61,8 @@ struct OptHomParameters {
   double CPU; // Time for optimization
 
   OptHomParameters ()
-    : BARRIER_MIN_METRIC(-1.), BARRIER_MIN(0.1), BARRIER_MAX(2.0), weightFixed(1.e6),
-      weightFree (1.e2), nbLayers (6) , dim(3) , itMax(300), onlyVisible(true),
+    : BARRIER_MIN_METRIC(-1.), BARRIER_MIN(0.1), BARRIER_MAX(2.0), weightFixed(1000.),
+      weightFree (1.), nbLayers (6) , dim(3) , itMax(300), onlyVisible(true),
       distanceFactor(12), fixBndNodes(false), strategy(0), maxAdaptBlob(3),
       adaptBlobLayerFact(2.), adaptBlobDistFact(2.), optPrimSurfMesh(false)
   {
-- 
GitLab