diff --git a/Fltk/highOrderToolsWindow.cpp b/Fltk/highOrderToolsWindow.cpp index 6b6a5bcd98a721b030446fd05b5a64d6f0d1cc81..4181ea08b5465fc9fe53d3e5ba24309eb3c31116 100644 --- a/Fltk/highOrderToolsWindow.cpp +++ b/Fltk/highOrderToolsWindow.cpp @@ -65,10 +65,7 @@ static void highordertools_runp_cb(Fl_Widget *w, void *data) int order = (int)o->value[0]->value(); bool linear = !(bool)o->butt[2]->value(); bool incomplete = (bool)o->butt[0]->value(); - bool elastic = (bool)o->butt[3]->value(); - double threshold = o->value[1]->value(); bool onlyVisible = (bool)o->butt[1]->value(); - int nLayers = (int) o->value[2]->value(); if (order == 1) SetOrder1(GModel::current()); @@ -89,85 +86,31 @@ static void highordertools_runp_cb(Fl_Widget *w, void *data) static void chooseopti_cb(Fl_Widget *w, void *data){ highOrderToolsWindow *o = FlGui::instance()->highordertools; - bool elastic = (bool)o->butt[3]->value(); + int elastic = o->choice[2]->value(); - if (elastic){ - o->butt[4]->value(0); + if (elastic == 1){ o->choice[0]->deactivate(); + o->choice[1]->deactivate(); for (int i=3;i<=6;i++) o->value[i]->deactivate(); - o->push[1]->deactivate(); + // o->push[1]->deactivate(); } else { - o->butt[3]->value(0); o->push[0]->activate(); o->choice[0]->activate(); + o->choice[1]->activate(); for (int i=3;i<=6;i++) o->value[i]->activate(); - o->push[1]->activate(); + // o->push[1]->activate(); } } - -static void chooseopti2_cb(Fl_Widget *w, void *data){ - highOrderToolsWindow *o = FlGui::instance()->highordertools; - bool elastic = !(bool)o->butt[4]->value(); - - if (elastic){ - o->butt[4]->value(0); - o->choice[0]->deactivate(); - for (int i=3;i<=6;i++) - o->value[i]->deactivate(); - o->push[1]->deactivate(); - } - else { - o->butt[3]->value(0); - o->push[0]->activate(); - o->choice[0]->activate(); - for (int i=3;i<=6;i++) - o->value[i]->activate(); - o->push[1]->activate(); - } - -} - -static void getMeshInfo (GModel *gm, - int &meshOrder, - bool &complete, - bool &CAD){ - meshOrder = -1; - CAD = true; - for (GModel::riter itr = gm->firstRegion(); itr != gm->lastRegion(); ++itr) { - if ((*itr)->getNumMeshElements()){ - meshOrder = (*itr)->getMeshElement(0)->getPolynomialOrder(); - complete = (meshOrder <= 2) ? 1 : (*itr)->getMeshElement(0)->getNumVolumeVertices(); - break; - } - } - for (GModel::fiter itf = gm->firstFace(); itf != gm->lastFace(); ++itf) { - printf("%d\n",(*itf)->getNumMeshElements()); - if ((*itf)->getNumMeshElements()){ - if (meshOrder == -1) { - meshOrder = (*itf)->getMeshElement(0)->getPolynomialOrder(); - complete = (meshOrder <= 2) ? 1 : (*itf)->getMeshElement(0)->getNumFaceVertices(); - if ((*itf)->geomType() == GEntity::DiscreteSurface)CAD = false; - printf("%d %d %d\n",meshOrder,complete, CAD); - break; - } - } - } -} - - static void highordertools_runelas_cb(Fl_Widget *w, void *data) { highOrderToolsWindow *o = FlGui::instance()->highordertools; - int order = (int)o->value[0]->value(); - bool linear = !(bool)o->butt[2]->value(); - bool incomplete = (bool)o->butt[0]->value(); - bool elastic = (bool)o->butt[3]->value(); + bool elastic = o->choice[2]->value() == 1; double threshold_min = o->value[1]->value(); bool onlyVisible = (bool)o->butt[1]->value(); int nbLayers = (int) o->value[2]->value(); @@ -180,7 +123,7 @@ static void highordertools_runelas_cb(Fl_Widget *w, void *data) p.BARRIER_MIN = threshold_min; p.BARRIER_MAX = threshold_max; p.onlyVisible = onlyVisible; - p.dim = GModel::current()->getNumRegions() ? 3 : 2; + p.dim = GModel::current()->getDim();//o->meshOrder; p.itMax = (int) o->value[3]->value(); p.weightFixed = o->value[5]->value(); p.weightFree = o->value[6]->value(); @@ -197,6 +140,7 @@ static void highordertools_runelas_cb(Fl_Widget *w, void *data) } + highOrderToolsWindow::highOrderToolsWindow(int deltaFontSize) { FL_NORMAL_SIZE -= deltaFontSize; @@ -342,22 +286,21 @@ highOrderToolsWindow::highOrderToolsWindow(int deltaFontSize) } { - y += BH; - butt[3] = new Fl_Check_Button - (x,y, IW, BH, "Relocate mesh vertices through Elastic Analogy"); - butt[3]->type(FL_TOGGLE_BUTTON); - butt[3]->value(0); - butt[3]->callback(chooseopti_cb); + static Fl_Menu_Item menu_method[] = { + {"Optimization", 0, 0, 0}, + {"ElasticAnalogy", 0, 0, 0}, + {0} + }; + + y += BH; + choice[2] = new Fl_Choice + (x,y, IW, BH, "Algorithm"); + choice[2]->align(FL_ALIGN_RIGHT); + choice[2]->menu(menu_method); + choice[2]->callback(chooseopti_cb); } { - y += BH; - butt[4] = new Fl_Check_Button - (x,y, IW, BH, "Use Optimization for relocating mesh vertices"); - butt[4]->type(FL_TOGGLE_BUTTON); - butt[4]->value(1); - butt[4]->callback(chooseopti2_cb); - static Fl_Menu_Item menu_objf[] = { {"CAD + FIXBND", 0, 0, 0}, {"CAD + FREEBND", 0, 0, 0}, @@ -422,9 +365,14 @@ highOrderToolsWindow::highOrderToolsWindow(int deltaFontSize) } - - // g->end(); - // Fl_Group::current()->resizable(g); + y += 1.5*BH; + messages = new Fl_Browser + (x,y, width-2*x, height - y - 2*WB); + messages->box(FL_THIN_DOWN_BOX); + messages->textfont(FL_COURIER); + messages->textsize(FL_NORMAL_SIZE - 1); + messages->type(FL_MULTI_BROWSER); + // messages->callback(message_browser_cb, this); } // win->resizable(o); @@ -435,7 +383,7 @@ highOrderToolsWindow::highOrderToolsWindow(int deltaFontSize) void highOrderToolsWindow::show(bool redrawOnly) { - getMeshInfo (GModel::current(),meshOrder,complete, CAD); + getMeshInfoForHighOrder (GModel::current(),meshOrder,complete, CAD); if(win->shown() && redrawOnly) win->redraw(); @@ -443,7 +391,10 @@ void highOrderToolsWindow::show(bool redrawOnly) value[0]->value(meshOrder); butt[0]->value(!complete); if (CAD)output[0]->value("AVAILABLE"); - else output[0]->value("NOT AVAILABLE"); + else { + output[0]->value("NOT AVAILABLE"); + choice[0]->value(2); + } win->show(); } } diff --git a/Fltk/highOrderToolsWindow.h b/Fltk/highOrderToolsWindow.h index 43862d8daa1c4ff2769d8f59ff4648c8de5ca54c..6e7124d5fe5701488849db32553a9d03c9fe0ead 100644 --- a/Fltk/highOrderToolsWindow.h +++ b/Fltk/highOrderToolsWindow.h @@ -12,7 +12,7 @@ #include <FL/Fl_Multi_Browser.H> #include <FL/Fl_Button.H> #include <FL/Fl_Check_Button.H> -#include <FL/Fl_Input.H> +#include <FL/Fl_Value_Input.H> #include <FL/Fl_Output.H> #include "GmshConfig.h" @@ -26,6 +26,7 @@ class highOrderToolsWindow{ Fl_Choice *choice[20]; Fl_Button *push[20]; Fl_Output *output[20]; + Fl_Browser *messages; public: highOrderToolsWindow(int deltaFontSize=0); void show(bool redrawOnly); diff --git a/Fltk/menuWindow.cpp b/Fltk/menuWindow.cpp index bd6cd213fee29ab3abf03beb4d35e998e9904009..7a8e317a28b87557c35342df0a93ea56e396e518 100644 --- a/Fltk/menuWindow.cpp +++ b/Fltk/menuWindow.cpp @@ -1820,7 +1820,8 @@ static void mesh_inspect_cb(Fl_Widget *w, void *data) Msg::Direct(" Rho: %g", ele->rhoShapeMeasure()); Msg::Direct(" Gamma: %g", ele->gammaShapeMeasure()); Msg::Direct(" Eta: %g", ele->etaShapeMeasure()); - Msg::Direct(" Disto: %g", ele->distoShapeMeasure()); + double jmin,jmax;ele->scaledJacRange(jmin,jmax); + Msg::Direct(" Scaled Jacobian Range : %g %g",jmin,jmax ); CTX::instance()->mesh.changed = ENT_ALL; drawContext::global()->draw(); FlGui::instance()->showMessages(); diff --git a/Fltk/statisticsWindow.cpp b/Fltk/statisticsWindow.cpp index 78167989a72703e3f11e2bea41aa2b2ce32bddd3..4efe5f4bc219dee81aeb89792325cc53641a6aef 100644 --- a/Fltk/statisticsWindow.cpp +++ b/Fltk/statisticsWindow.cpp @@ -77,8 +77,10 @@ static void statistics_histogram_cb(Fl_Widget *w, void *data) d[e->getNum()].push_back(e->etaShapeMeasure()); else if(name == "Rho3D") d[e->getNum()].push_back(e->rhoShapeMeasure()); - else - d[e->getNum()].push_back(e->distoShapeMeasure()); + else{ + double jmin,jmax; e->scaledJacRange(jmin,jmax); + d[e->getNum()].push_back(std::min(jmin,1./jmax)); + } } } @@ -137,7 +139,7 @@ statisticsWindow::statisticsWindow(int deltaFontSize) value[num] = new Fl_Output(2 * WB, 2 * WB + 15 * BH, IW, BH, "Rho"); value[num]->tooltip("~ min_edge_length / max_edge_length"); num++; value[num] = new Fl_Output(2 * WB, 2 * WB + 16 * BH, IW, BH, "Disto"); - value[num]->tooltip("~ min (J0/J, J/J0)"); num++; + value[num]->tooltip("~ min (J_min/J_0, J_0/J_max)"); num++; for(int i = 0; i < 4; i++){ int ww = 3 * FL_NORMAL_SIZE; diff --git a/Geo/MElement.h b/Geo/MElement.h index 65c48e5a36fa01fb9fa5718b841994193bc2a557..5d048996537be150eb00753162d7334b6eda4f79 100644 --- a/Geo/MElement.h +++ b/Geo/MElement.h @@ -181,6 +181,7 @@ class MElement virtual double etaShapeMeasure(){ return 0.; } virtual double distoShapeMeasure(){ return 1.0; } virtual double angleShapeMeasure() { return 1.0; } + virtual void scaledJacRange(double &jmin, double &jmax); // get the radius of the inscribed circle/sphere if it exists, // otherwise get the minimum radius of all the circles/spheres diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp index f89e9a4622cc1204938d9d619c6a0159d046d0fd..9906814b6de41b495cc15181364f97530805404e 100644 --- a/Mesh/Generator.cpp +++ b/Mesh/Generator.cpp @@ -171,6 +171,7 @@ static void GetQualityMeasure(std::vector<T*> &ele, double &eta, double &etaMin, double &etaMax, double &rho, double &rhoMin, double &rhoMax, double &disto, double &distoMin, double &distoMax, + double &scaledJacMin, double &scaledJacMax, double quality[4][100]) { for(unsigned int i = 0; i < ele.size(); i++){ @@ -186,10 +187,14 @@ static void GetQualityMeasure(std::vector<T*> &ele, rho += r; rhoMin = std::min(rhoMin, r); rhoMax = std::max(rhoMax, r); - double d = ele[i]->distoShapeMeasure(); + double jmin,jmax; ele[i]->scaledJacRange(jmin,jmax); + double d = std::min(jmin,1./jmax); disto += d; distoMin = std::min(distoMin, d); distoMax = std::max(distoMax, d); + scaledJacMin = std::min(scaledJacMin, jmin); + scaledJacMax = std::max(scaledJacMax, jmax); + for(int j = 0; j < 100; j++){ if(g > j / 100. && g <= (j + 1) / 100.) quality[0][j]++; if(e > j / 100. && e <= (j + 1) / 100.) quality[1][j]++; @@ -246,15 +251,16 @@ void GetStatistics(double stat[50], double quality[4][100]) double eta=0., etaMin=1., etaMax=0.; double rho=0., rhoMin=1., rhoMax=0.; double disto=0., distoMin=1., distoMax=0.; + double jmin = 1.e22, jmax = -1.e22; double N = 0.0; if (m->firstRegion() == m->lastRegion()){ for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it){ GetQualityMeasure((*it)->quadrangles, gamma, gammaMin, gammaMax, eta, etaMin, etaMax, rho, rhoMin, rhoMax, - disto, distoMin, distoMax, quality); + disto, distoMin, distoMax, jmin,jmax, quality); GetQualityMeasure((*it)->triangles, gamma, gammaMin, gammaMax, eta, etaMin, etaMax, rho, rhoMin, rhoMax, - disto, distoMin, distoMax, quality); + disto, distoMin, distoMax, jmin,jmax, quality); } N = stat[7] + stat[8]; } @@ -262,16 +268,16 @@ void GetStatistics(double stat[50], double quality[4][100]) for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it){ GetQualityMeasure((*it)->tetrahedra, gamma, gammaMin, gammaMax, eta, etaMin, etaMax, rho, rhoMin, rhoMax, - disto, distoMin, distoMax, quality); + disto, distoMin, distoMax, jmin,jmax, quality); GetQualityMeasure((*it)->hexahedra, gamma, gammaMin, gammaMax, eta, etaMin, etaMax, rho, rhoMin, rhoMax, - disto, distoMin, distoMax, quality); + disto, distoMin, distoMax, jmin,jmax, quality); GetQualityMeasure((*it)->prisms, gamma, gammaMin, gammaMax, eta, etaMin, etaMax, rho, rhoMin, rhoMax, - disto, distoMin, distoMax,quality); + disto, distoMin, distoMax,jmin,jmax, quality); GetQualityMeasure((*it)->pyramids, gamma, gammaMin, gammaMax, eta, etaMin, etaMax, rho, rhoMin, rhoMax, - disto, distoMin, distoMax, quality); + disto, distoMin, distoMax, jmin,jmax, quality); } N = stat[9] + stat[10] + stat[11] + stat[12]; } @@ -284,6 +290,9 @@ void GetStatistics(double stat[50], double quality[4][100]) stat[23] = rho / N ; stat[24] = rhoMin; stat[25] = rhoMax; + + stat[45] = jmin; + stat[46] = jmax; stat[46] = disto / N ; stat[47] = distoMin; stat[48] = distoMax; diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp index 43b1f16f2dd34140a3f718cecd1752e6de866ef2..cb2d12993e12a1a261762f9026913e5637857a41 100644 --- a/Mesh/HighOrder.cpp +++ b/Mesh/HighOrder.cpp @@ -1234,8 +1234,40 @@ void printJacobians(GModel *m, const char *nm) fclose(f); } +void getMeshInfoForHighOrder (GModel *gm, + int &meshOrder, + bool &complete, + bool &CAD){ + meshOrder = -1; + CAD = true; + for (GModel::riter itr = gm->firstRegion(); itr != gm->lastRegion(); ++itr) { + if ((*itr)->getNumMeshElements()){ + meshOrder = (*itr)->getMeshElement(0)->getPolynomialOrder(); + complete = (meshOrder <= 2) ? 1 : (*itr)->getMeshElement(0)->getNumVolumeVertices(); + break; + } + } + for (GModel::fiter itf = gm->firstFace(); itf != gm->lastFace(); ++itf) { + if ((*itf)->getNumMeshElements()){ + if (meshOrder == -1) { + meshOrder = (*itf)->getMeshElement(0)->getPolynomialOrder(); + complete = (meshOrder <= 2) ? 1 : (*itf)->getMeshElement(0)->getNumFaceVertices(); + if ((*itf)->geomType() == GEntity::DiscreteSurface)CAD = false; + break; + } + } + } +} + + + + void ElasticAnalogy ( GModel *m, double threshold, bool onlyVisible) { + bool CAD, complete; + int meshOrder; + + getMeshInfoForHighOrder (m,meshOrder, complete, CAD); highOrderTools hot(m); // now we smooth mesh the internal vertices of the faces // we do that model face by model face @@ -1248,7 +1280,8 @@ void ElasticAnalogy ( GModel *m, double threshold, bool onlyVisible) { std::vector<MElement*> v; v.insert(v.begin(), (*it)->triangles.begin(), (*it)->triangles.end()); v.insert(v.end(), (*it)->quadrangles.begin(), (*it)->quadrangles.end()); - hot.applySmoothingTo(v, (*it)); + if (CAD)hot.applySmoothingTo(v, (*it)); + else hot.applySmoothingTo(v, 1.e32, false); } } // hot.ensureMinimumDistorsion(0.1); @@ -1432,13 +1465,13 @@ void SetHighOrderInComplete (GModel *m, bool onlyVisible){ for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it) { if (onlyVisible && !(*it)->getVisibility())continue; std::vector<MTriangle*> newT; - std::vector<MQuadrangle*> newQ; + for (int i=0;i<(*it)->triangles.size();i++){ MTriangle *t = (*it)->triangles[i]; std::vector<MVertex*> vt; int order = t->getPolynomialOrder(); for (int j=3;j<t->getNumVertices()-t->getNumFaceVertices();j++)vt.push_back(t->getVertex(j)); - for (int j=t->getNumVertices()-t->getNumFaceVertices();j<t->getNumVertices();j++)toDelete.insert(t->getVertex(j)); + for (int j=t->getNumVertices()-t->getNumFaceVertices();j < t->getNumVertices();j++)toDelete.insert(t->getVertex(j)); newT.push_back(new MTriangleN(t->getVertex(0), t->getVertex(1), t->getVertex(2), vt, order)); @@ -1446,6 +1479,7 @@ void SetHighOrderInComplete (GModel *m, bool onlyVisible){ } (*it)->triangles = newT; + std::vector<MQuadrangle*> newQ; for (int i=0;i<(*it)->quadrangles.size();i++){ MQuadrangle *t = (*it)->quadrangles[i]; std::vector<MVertex*> vt; @@ -1456,13 +1490,18 @@ void SetHighOrderInComplete (GModel *m, bool onlyVisible){ delete t; } (*it)->quadrangles = newQ; + std::vector<MVertex*> newV; + int numd = 0; for (int i=0;i<(*it)->mesh_vertices.size();++i){ if (toDelete.find((*it)->mesh_vertices[i]) == toDelete.end()) newV.push_back((*it)->mesh_vertices[i]); - else + else{ delete (*it)->mesh_vertices[i]; + numd++; + } } + printf("%d vertices deleted\n"); (*it)->mesh_vertices = newV; } diff --git a/Mesh/HighOrder.h b/Mesh/HighOrder.h index 49be09e410236f4d40eab5a08c280b340f05d402..cd19ea3e2d131cac7c05e6caf2be5f52deb2d7a9 100644 --- a/Mesh/HighOrder.h +++ b/Mesh/HighOrder.h @@ -36,5 +36,5 @@ struct distanceFromMeshToGeometry_t { }; void computeDistanceFromMeshToGeometry (GModel *m, distanceFromMeshToGeometry_t &dist); - +void getMeshInfoForHighOrder (GModel *gm, int &meshOrder, bool &complete, bool &CAD); #endif diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp index 31ee8bfcd4e1a6fc8985cce2b9e25274dc711211..d55777041c54bc925383b3a922dae157c3310da0 100644 --- a/Mesh/qualityMeasures.cpp +++ b/Mesh/qualityMeasures.cpp @@ -307,15 +307,11 @@ double mesh_functional_distorsion_p2_exact(MTriangle *t) double mesh_functional_distorsion_pN(MElement *t) { - // printf("element disto -->\n"); const bezierBasis *jac = t->getJacobianFuncSpace()->bezier; fullVector<double>Ji(jac->points.size1()); - // printf("%d points for bez \n",jac->points.size1()); for (int i=0;i<jac->points.size1();i++){ double u = jac->points(i,0); double v = jac->points(i,1); - - // JF : bezier points are defined in the [0,1] x [0,1] quad if (t->getType() == TYPE_QUA){ u = -1 + 2*u; v = -1 + 2*v; @@ -326,23 +322,31 @@ double mesh_functional_distorsion_pN(MElement *t) fullVector<double> Bi( jac->matrixLag2Bez.size1() ); jac->matrixLag2Bez.mult(Ji,Bi); + return *std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size()); +} - // for (int i=0;i<jac->points.size1();i++){ - // printf("J(%d) = %12.5E B(%d) = %12.5E\n",i,Ji(i),i,Bi(i)); - // } - /* - if (t->getType() == TYPE_QUA){ - jac->matrixLag2Bez.print("lag2bez"); +void MElement::scaledJacRange(double &jmin, double &jmax) +{ + jmin = jmax = 1.0; + if (getPolynomialOrder() == 1) return; + const bezierBasis *jac = getJacobianFuncSpace()->bezier; + fullVector<double>Ji(jac->points.size1()); + for (int i=0;i<jac->points.size1();i++){ + double u = jac->points(i,0); + double v = jac->points(i,1); + if (getType() == TYPE_QUA){ + u = -1 + 2*u; + v = -1 + 2*v; + } - jac->points.print("lagrangianNodesBezierQ"); - t->getFunctionSpace(t->getPolynomialOrder())->points.print("lagrangianNodesQ"); - t->getFunctionSpace(t->getPolynomialOrder())->monomials.print("MonomialsQ"); - t->getFunctionSpace(t->getPolynomialOrder())->coefficients.print("shapeFunctionCoeffQ"); + Ji(i) = mesh_functional_distorsion(this,u,v); } - */ - - return *std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size()); + + fullVector<double> Bi( jac->matrixLag2Bez.size1() ); + jac->matrixLag2Bez.mult(Ji,Bi); + jmin = *std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size()); + jmax = *std::max_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size()); } diff --git a/contrib/HighOrderMeshOptimizer/OptHOM.cpp b/contrib/HighOrderMeshOptimizer/OptHOM.cpp index 7c677ea5d1c38a2e409850e1b43888e5eb7ac5bf..1ea6bb6851288475d13d638d2ce02afdbd814630 100644 --- a/contrib/HighOrderMeshOptimizer/OptHOM.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHOM.cpp @@ -2,6 +2,7 @@ #include <algorithm> #include "OptHomMesh.h" #include "OptHOM.h" +#include "OptHOMRun.h" #include "GmshMessage.h" #include "GmshConfig.h" @@ -14,7 +15,6 @@ #include "optimization.h" - // Constructor OptHOM::OptHOM(GEntity *ge, std::set<MVertex*> & toFix, int method) : mesh(ge, toFix, method) @@ -25,9 +25,6 @@ OptHOM::OptHOM(GEntity *ge, std::set<MVertex*> & toFix, int method) : bool OptHOM::addJacObjGrad(double &Obj, alglib::real_1d_array &gradObj) { - minJac = 1.e300; - maxJac = -1.e300; - for (int iEl = 0; iEl < mesh.nEl(); iEl++) { std::vector<double> sJ(mesh.nBezEl(iEl)); // Scaled Jacobians mesh.scaledJac(iEl,sJ); @@ -38,8 +35,6 @@ bool OptHOM::addJacObjGrad(double &Obj, alglib::real_1d_array &gradObj) const double f1 = compute_f1(sJ[l]); for (int iPC = 0; iPC < mesh.nPCEl(iEl); iPC++) gradObj[mesh.indPCEl(iEl,iPC)] += f1*gSJ[mesh.indGSJ(iEl,l,iPC)]; - minJac = std::min(minJac,sJ[l]); - maxJac = std::max(maxJac,sJ[l]); } } @@ -53,22 +48,13 @@ bool OptHOM::addJacObjGrad(double &Obj, alglib::real_1d_array &gradObj) bool OptHOM::addDistObjGrad(double Fact, double Fact2, double &Obj, alglib::real_1d_array &gradObj) { - maxDist = 0; - avgDist = 0; - int nbBnd = 0; - for (int iFV = 0; iFV < mesh.nFV(); iFV++) { const double Factor = invLengthScaleSq*(mesh.forced(iFV) ? Fact : Fact2); - const double dSq = mesh.distSq(iFV), dist = sqrt(dSq); - Obj += Factor * dSq; + Obj += Factor * mesh.distSq(iFV); std::vector<double> gDSq(mesh.nPCFV(iFV)); mesh.gradDistSq(iFV,gDSq); for (int iPC = 0; iPC < mesh.nPCFV(iFV); iPC++) gradObj[mesh.indPCFV(iFV,iPC)] += Factor*gDSq[iPC]; - maxDist = std::max(maxDist, dist); - avgDist += dist; - nbBnd++; } - if (nbBnd != 0) avgDist /= nbBnd; return true; @@ -87,42 +73,49 @@ void OptHOM::evalObjGrad(const alglib::real_1d_array &x, double &Obj, alglib::re addJacObjGrad(Obj, gradObj); addDistObjGrad(lambda, lambda2, Obj, gradObj); - if ((minJac > barrier_min) && (maxJac < barrier_max)) { - printf("INFO: reached Jacobian requirements, setting null gradient\n"); - Obj = 0.; - for (int i = 0; i < gradObj.length(); i++) gradObj[i] = 0.; - } - + // if ((minJac > barrier_min) && (maxJac < barrier_max)) { + // printf("INFO: reached Jacobian requirements, setting null gradient\n"); + // Obj = 0.; + // for (int i = 0; i < gradObj.length(); i++) gradObj[i] = 0.; + // } } void evalObjGradFunc(const alglib::real_1d_array &x, double &Obj, alglib::real_1d_array &gradObj, void *HOInst) { - (static_cast<OptHOM*>(HOInst))->evalObjGrad(x, Obj, gradObj); + OptHOM &HO = *static_cast<OptHOM*> (HOInst); + HO.evalObjGrad(x, Obj, gradObj); + double distMaxBnd, distAvgBnd, minJac, maxJac; + HO.getDistances(distMaxBnd, distAvgBnd, minJac, maxJac); + if (minJac > HO.barrier_min && maxJac < HO.barrier_max) { + for (int i = 0; i < gradObj.length(); ++i) { + gradObj[i] = 0; + } + } } -void OptHOM::recalcJacDist() - { +void OptHOM::getDistances(double &distMaxBND, double &distAvgBND, double &minJac, double &maxJac) +{ - maxDist = 0; - avgDist = 0; + distMaxBND = 0; + distAvgBND = 0; int nbBnd = 0; for (int iFV = 0; iFV < mesh.nFV(); iFV++) { if (mesh.forced(iFV)) { double dSq = mesh.distSq(iFV); - maxDist = std::max(maxDist, sqrt(dSq)); - avgDist += sqrt(dSq); + distMaxBND = std::max(distMaxBND, sqrt(dSq)); + distAvgBND += sqrt(dSq); nbBnd++; } } - if (nbBnd != 0) avgDist /= nbBnd; + if (nbBnd != 0) distAvgBND /= nbBnd; - minJac = 1.e300; - maxJac = -1.e300; + minJac = 1000; + maxJac = -1000; for (int iEl = 0; iEl < mesh.nEl(); iEl++) { std::vector<double> sJ(mesh.nBezEl(iEl)); // Scaled Jacobians mesh.scaledJac(iEl,sJ); @@ -142,8 +135,11 @@ void OptHOM::printProgress(const alglib::real_1d_array &x, double Obj) iter++; if (iter % progressInterv == 0) { - printf("--> Iteration %3d --- OBJ %12.5E (relative decrease = %12.5E) -- minJ = %12.5E maxJ = %12.5E Max D = %12.5E Avg D = %12.5E\n", iter, Obj, Obj/initObj, minJac, maxJac, maxDist, avgDist); - Msg::Debug("--> Iteration %3d --- OBJ %12.5E (relative decrease = %12.5E) -- minJ = %12.5E maxJ = %12.5E Max D = %12.5E Avg D = %12.5E", iter, Obj, Obj/initObj, minJac, maxJac, maxDist, avgDist); + double maxD, avgD, minJ, maxJ; + getDistances(maxD, avgD, minJ, maxJ); + + printf("--> Iteration %3d --- OBJ %12.5E (relative decrease = %12.5E) -- minJ = %12.5E maxJ = %12.5E Max D = %12.5E Avg D = %12.5E\n", iter, Obj, Obj/initObj, minJ, maxJ, maxD, avgD); + Msg::Debug("--> Iteration %3d --- OBJ %12.5E (relative decrease = %12.5E) -- minJ = %12.5E maxJ = %12.5E Max D = %12.5E Avg D = %12.5E", iter, Obj, Obj/initObj, minJ, maxJ, maxD, avgD); } } @@ -157,83 +153,53 @@ void printProgressFunc(const alglib::real_1d_array &x, double Obj, void *HOInst) -void OptHOM::calcScale(alglib::real_1d_array &scale) -{ - - scale.setlength(mesh.nPC()); - - // Calculate scale - for (int iFV = 0; iFV < mesh.nFV(); iFV++) { - std::vector<double> scaleFV(mesh.nPCFV(iFV),1.); - mesh.pcScale(iFV,scaleFV); - for (int iPC = 0; iPC < mesh.nPCFV(iFV); iPC++) scale[mesh.indPCFV(iFV,iPC)] = scaleFV[iPC]; - } - - // Normalize scale vector (otherwise ALGLIB routines may fail) - double scaleNormSq = 0.; - for (int i = 0; i < mesh.nPC(); i++) scaleNormSq += scale[i]*scale[i]; - const double scaleNorm = sqrt(scaleNormSq); - for (int i = 0; i < mesh.nPC(); i++) scale[i] /= scaleNorm; - -} - - - void OptHOM::OptimPass(alglib::real_1d_array &x, const alglib::real_1d_array &initGradObj, int itMax) { - static const double EPSG = 0.; - static const double EPSF = 0.; + static const double EPSF = 1.e-8; +// static const double EPSF = 0.; static const double EPSX = 0.; - static int OPTMETHOD = 1; +// const double EPSX = x.length()*1.e-4/sqrt(invLengthScaleSq); +// std::cout << "DEBUG: EPSX = " << EPSX << ", EPSX/x.length() = " << EPSX/x.length() << std::endl; + +// double iGONorm = 0; +// for (int i=0; i<initGradObj.length(); i++) iGONorm += initGradObj[i]*initGradObj[i]; +// const double EPSG = 1.e-2*sqrt(iGONorm); Msg::Debug("--- Optimization pass with jacBar = %12.5E",jacBar); - iter = 0; +// alglib::minlbfgsstate state; +// alglib::minlbfgsreport rep; + alglib::mincgstate state; + alglib::mincgreport rep; - int iterationscount = 0, nfev = 0, terminationtype = -1; - if (OPTMETHOD == 1) { - alglib::mincgstate state; - alglib::mincgreport rep; - mincgcreate(x, state); - alglib::real_1d_array scale; - calcScale(scale); - mincgsetscale(state,scale); - mincgsetprecscale(state); - mincgsetcond(state, EPSG, EPSF, EPSX, itMax); - mincgsetxrep(state, true); - alglib::mincgoptimize(state, evalObjGradFunc, printProgressFunc, this); - mincgresults(state, x, rep); - iterationscount = rep.iterationscount; - nfev = rep.nfev; - terminationtype = rep.terminationtype; - } - else { - alglib::minlbfgsstate state; - alglib::minlbfgsreport rep; - minlbfgscreate(3, x, state); - alglib::real_1d_array scale; - calcScale(scale); - minlbfgssetscale(state,scale); - minlbfgssetprecscale(state); - minlbfgssetcond(state, EPSG, EPSF, EPSX, itMax); - minlbfgssetxrep(state, true); - alglib::minlbfgsoptimize(state, evalObjGradFunc, printProgressFunc, this); - minlbfgsresults(state, x, rep); - iterationscount = rep.iterationscount; - nfev = rep.nfev; - terminationtype = rep.terminationtype; - } +// minlbfgscreate(3, x, state); +// minlbfgssetcond(state, EPSG, EPSF, EPSX, itMax); +// minlbfgssetxrep(state, true); + mincgcreate(x, state); + mincgsetcond(state, EPSG, EPSF, EPSX, itMax); + mincgsetxrep(state, true); - std::cout << "Optimization finalized after " << iterationscount << " iterations (" << nfev << " functions evaluations)"; - switch(int(terminationtype)) { - case 1: std::cout << ", because relative function improvement is no more than EpsF"; break; - case 2: std::cout << ", because relative step is no more than EpsX"; break; - case 4: std::cout << ", because gradient norm is no more than EpsG"; break; - case 5: std::cout << ", because the maximum number of steps was taken"; break; - default: std::cout << " with code " << int(terminationtype); break; - } - std::cout << "." << std::endl; + iter = 0; + +// alglib::minlbfgsoptimize(state, evalObjGradFunc, printProgressFunc, this); + alglib::mincgoptimize(state, evalObjGradFunc, printProgressFunc, this); + +// minlbfgsresults(state, x, rep); + mincgresults(state, x, rep); + + // std::cout << "Optimization finalized after " << rep.iterationscount << " iterations (" << rep.nfev << " functions evaluations)"; + // switch(int(rep.terminationtype)) { +// case -2: std::cout << ", because rounding errors prevented further improvement"; break; +// case -1: std::cout << ", because incorrect parameters were specified"; break; +// case 1: std::cout << ", because relative function improvement is no more than EpsF"; break; +// case 2: std::cout << ", because relative step is no more than EpsX"; break; +// case 4: std::cout << ", because gradient norm is no more than EpsG"; break; +// case 5: std::cout << ", because the maximum number of steps was taken"; break; +// case 7: std::cout << ", because stopping conditions are too stringent, further improvement is impossible"; break; +// default: std::cout << " with code " << int(rep.terminationtype); break; +// } +// std::cout << "." << std::endl; } @@ -241,6 +207,7 @@ void OptHOM::OptimPass(alglib::real_1d_array &x, const alglib::real_1d_array &in int OptHOM::optimize(double weightFixed, double weightFree, double b_min, double b_max, int pInt, int itMax) { + double minJ,maxJ; barrier_min = b_min; barrier_max = b_max; progressInterv = pInt; @@ -254,6 +221,8 @@ int OptHOM::optimize(double weightFixed, double weightFree, double b_min, double mesh.distSqToStraight(dSq); const double maxDSq = *max_element(dSq.begin(),dSq.end()); invLengthScaleSq = 1./maxDSq; // Length scale for non-dimensional distance + // printf("DISTANCE TO STRAIGHT = %12.5E\n",maxDSq); + // Set initial guess alglib::real_1d_array x; @@ -261,32 +230,34 @@ int OptHOM::optimize(double weightFixed, double weightFree, double b_min, double mesh.getUvw(x.getcontent()); // Calculate initial performance - recalcJacDist(); - initMaxDist = maxDist; - initAvgDist = avgDist; + // double minJ, maxJ; + double initMaxD, initAvgD; + getDistances(initMaxD, initAvgD, minJ, maxJ); - const double jacBarStart = (minJac > 0.) ? 0.9*minJac : 1.1*minJac; + const double jacBarStart = (minJ > 0.) ? 0.9*minJ : 1.1*minJ; jacBar = jacBarStart; setBarrierTerm(jacBarStart); + // std::cout << "DEBUG: jacBarStart = " << jacBarStart << std::endl; // Calculate initial objective function value and gradient initObj = 0.; alglib::real_1d_array gradObj; gradObj.setlength(mesh.nPC()); + // printf("mesh.npc = %d\n",mesh.nPC()); for (int i = 0; i < mesh.nPC(); i++) gradObj[i] = 0.; evalObjGrad(x, initObj, gradObj); - std::cout << "Start optimizing " << mesh.nEl() << " elements (" << mesh.nVert() << " vertices, " - << mesh.nFV() << " free vertices, " << mesh.nPC() << " variables) with min. barrier = " << barrier_min - << " and max. barrier = " << barrier_max << std::endl; + // std::cout << "Start optimizing with barrier = " << barrier_min << std::endl; int ITER = 0; - while (minJac < barrier_min) { + while (minJ < barrier_min || maxJ > barrier_max ) { OptimPass(x, gradObj, itMax); - jacBar = (minJac > 0.) ? 0.9*minJac : 1.1*minJac; + double dumMaxD, dumAvgD; + getDistances(dumMaxD, dumAvgD, minJ, maxJ); + jacBar = (minJ > 0.) ? 0.9*minJ : 1.1*minJ; setBarrierTerm(jacBar); - if (ITER ++ > 10) break; + if (ITER ++ > 15) break; } // for (int i = 0; i<3; i++) { @@ -294,12 +265,14 @@ int OptHOM::optimize(double weightFixed, double weightFree, double b_min, double // OptimPass(x, gradObj, itMax); // } - double finalObj = 0.; + double finalObj = 0., finalMaxD, finalAvgD; evalObjGrad(x, finalObj, gradObj); - Msg::Info("Optimization finished : Avg distance to bnd = %12.5E MinJac %12.5E MaxJac %12.5E",avgDist,minJac,maxJac); - - return (minJac > barrier_min && maxJac < barrier_max ); + getDistances(finalMaxD, finalAvgD, minJ, maxJ); + OptHomMessage("Optimization done Range (%g,%g)",minJ,maxJ); + if (minJ < barrier_min && maxJ > barrier_max) return 0; + if (minJ > 0.0) return 1; + return -1; } diff --git a/contrib/HighOrderMeshOptimizer/OptHOM.h b/contrib/HighOrderMeshOptimizer/OptHOM.h index f2b18530e2ff576fb92cc7e2ac9055b41790e98a..093411aabb1624fe9c6e63454cc56b3cda36d10a 100644 --- a/contrib/HighOrderMeshOptimizer/OptHOM.h +++ b/contrib/HighOrderMeshOptimizer/OptHOM.h @@ -19,12 +19,17 @@ class OptHOM public: + Mesh mesh; OptHOM(GEntity *gf, std::set<MVertex*> & toFix, int method); + // returns 1 if the mesh has been optimized with success i.e. all jacobians are in the range + // returns 0 if the mesh is valid (all jacobians positive, JMIN > 0) but JMIN < barrier_min || JMAX > barrier_max + // returns -1 if the mesh is invalid : some jacobians cannot be made positive int optimize(double lambda, double lambda2, double barrier_min, double barrier_max, int pInt, int itMax); // optimize one list of elements - void recalcJacDist(); - inline void getJacDist(double &minJ, double &maxJ, double &maxD, double &avgD); + void getDistances(double &distMaxBND, double &distAvgBND, double &minJac, double &maxJac); + // void recalcJacDist(); + // inline void getJacDist(double &minJ, double &maxJ, double &maxD, double &avgD); void updateMesh(const alglib::real_1d_array &x); void evalObjGrad(const alglib::real_1d_array &x, double &Obj, alglib::real_1d_array &gradObj); void printProgress(const alglib::real_1d_array &x, double Obj); @@ -81,10 +86,10 @@ inline double OptHOM::compute_f1(double v) -void OptHOM::getJacDist(double &minJ, double &maxJ, double &maxD, double &avgD) -{ - minJ = minJac; maxJ = maxJac; maxD = maxDist; avgD = avgDist; -} +//void OptHOM::getJacDist(double &minJ, double &maxJ, double &maxD, double &avgD) +//{ +// minJ = minJac; maxJ = maxJac; maxD = maxDist; avgD = avgDist; +//} diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp index 46fffaaebe1fad33207c5afec52edadbfbe5d1a2..abb960a711888c76be0f4d16d9b24755124ec245 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp @@ -16,6 +16,33 @@ #include "OptHOM.h" #include <stack> +#ifdef HAVE_FLTK +#include "highOrderToolsWindow.h" +#include "FLGui.h" +#endif + +void OptHomMessage (const char *s, ...) { + char str[1024]; + va_list args; + va_start(args, s); + vsnprintf(str, sizeof(str), s, args); + va_end(args); +#ifdef HAVE_FLTK + if(FlGui::available()){ + FlGui::instance()->check(); + FlGui::instance()->highordertools->messages->add(str, 0); + if(FlGui::instance()->highordertools->win->shown() && + FlGui::instance()->highordertools->messages->h() >= 10){ + FlGui::instance()->highordertools->messages->bottomline(FlGui::instance()->highordertools->messages->size()); + FlGui::instance()->highordertools->messages->show(); + } + } +#else + fprintf(stdout,"%s\n",str); +#endif +} + + // get all elements that are neighbors double distMaxStraight (MElement *el){ @@ -170,21 +197,39 @@ static MElement * compare_worst (MElement *a, MElement *b){ return b; } -template <class T> -MElement* getTheWorstElement (const std::vector<T*> &a) { - T *worst = 0; - double q = 1.e22; - for (int i=0;i<a.size();i++){ - T *t = a[i]; - double Q = t->distoShapeMeasure(); - if (Q < q) { - worst = t;q = Q; +template <class ITERATOR> +MElement* getTheWorstElementDown (const ITERATOR &beg, const ITERATOR &end, double &q) { + MElement *worst = 0; + q = 1.e22; + ITERATOR it = beg; + for (;it != end;++it){ + MElement *t = *it; + double jmin,jmax; + t->scaledJacRange(jmin,jmax); + if (jmin < q) { + worst = t;q = jmin; } } - // printf("worst = %12.5E\n",q); return worst; } +template <class ITERATOR> +MElement* getTheWorstElementUp (const ITERATOR &beg, const ITERATOR &end, double &q) { + MElement *worst = 0; + q = -1.e22; + ITERATOR it = beg; + for (;it != end;++it){ + MElement *t = *it; + double jmin,jmax; + t->scaledJacRange(jmin,jmax); + if (jmax > q) { + worst = t;q = jmax; + } + } + return worst; +} + + std::set<MVertex*> filter3D(GRegion *gr, int nbLayers, double _qual) { std::set<MVertex*> touched; @@ -196,7 +241,7 @@ std::set<MVertex*> filter3D(GRegion *gr, int nbLayers, double _qual) ts.insert(t); for(int j=0;j<t->getNumVertices();j++)touched.insert(t->getVertex(j)); } - if (ts.size() == 1)break; + // if (ts.size() == 1)break; } printf("FILTER3D : %d bad tets found among %6d\n",ts.size(),gr->tetrahedra.size()); @@ -242,9 +287,18 @@ std::set<MVertex*> filter2D_boundaryLayer(GFace *gf, int nbLayers, double _qual_min, double _qual_max, - double F ) { - MElement *worst = compare_worst (getTheWorstElement(gf->triangles), - getTheWorstElement(gf->quadrangles)); + double F , + std::set<MElement*> & badasses) { + + double jmin, jmax; + MElement *worstDown = getTheWorstElementDown(badasses.begin(),badasses.end(),jmin); + MElement *worstUp = getTheWorstElementUp(badasses.begin(),badasses.end(),jmax); + MElement *worst; + if (jmin < _qual_min)worst = worstDown; + else worst = worstUp; + + // MElement *worst = compare_worst (getTheWorstElement(gf->triangles), + // getTheWorstElement(gf->quadrangles)); std::vector<MElement*> vworst; vworst.push_back(worst); std::vector<MElement*> all; @@ -284,9 +338,10 @@ std::set<MVertex*> filter3D_boundaryLayer(GRegion *gr, double _qual_min, double _qual_max, double F ) { - MElement *worst = compare_worst (getTheWorstElement(gr->tetrahedra), - getTheWorstElement(gr->prisms)); - worst = compare_worst (worst,getTheWorstElement(gr->hexahedra)); + double jmin,jmax; + MElement *worst = compare_worst (getTheWorstElementDown(gr->tetrahedra.begin(),gr->tetrahedra.end(),jmin), + getTheWorstElementDown(gr->prisms.begin(),gr->prisms.end(),jmin)); + worst = compare_worst (worst,getTheWorstElementDown(gr->hexahedra.begin(),gr->hexahedra.end(),jmin)); std::vector<MElement*> vworst; vworst.push_back(worst); std::vector<MElement*> all; @@ -327,27 +382,32 @@ std::set<MVertex*> filter3D_boundaryLayer(GRegion *gr, std::set<MVertex*> filter2D(GFace *gf, int nbLayers, double _qual_min, - double _qual_max, - double F = 1.e22) + double _qual_max) { std::set<MVertex*> touched; std::set<MVertex*> not_touched; std::set<MElement*> elements; + std::set<MTriangle*> tt; + std::set<MQuadrangle*> qq; for (int i = 0; i < gf->triangles.size(); i++) { MTriangle *t = gf->triangles[i]; - double Q = t->distoShapeMeasure(); - if (Q < _qual_min || Q > _qual_max) { + double jmin,jmax; + t->scaledJacRange(jmin,jmax); + if (jmin < _qual_min || jmax > _qual_max) { elements.insert(t); + tt.insert(t); for (int j = 0; j < t->getNumVertices(); j++) touched.insert(t->getVertex(j)); } } for (int i = 0; i < gf->quadrangles.size(); i++) { MQuadrangle *q = gf->quadrangles[i]; - double Q = q->distoShapeMeasure(); - if (Q < _qual_min || Q > _qual_max) { + double jmin,jmax; + q->scaledJacRange(jmin,jmax); + if (jmin < _qual_min || jmax > _qual_max) { elements.insert(q); + qq.insert(q); for (int j = 0; j < q->getNumVertices(); j++) touched.insert(q->getVertex(j)); } @@ -360,14 +420,16 @@ std::set<MVertex*> filter2D(GFace *gf, for (int j = 0; j < el->getNumVertices(); ++j) { if (touched.find(el->getVertex(j)) != touched.end()) { elements.insert(el); + if (el->getType() == TYPE_TRI)tt.insert((MTriangle*)el); + if (el->getType() == TYPE_QUA)qq.insert((MQuadrangle*)el); break; } } } for (std::set<MElement *>::iterator it = elements.begin(); it != elements.end(); ++it) { - MElement &el = **it; - for (int j = 0; j < el.getNumVertices(); ++j) { - touched.insert(el.getVertex(j)); + MElement *el = *it; + for (int j = 0; j < el->getNumVertices(); ++j) { + touched.insert(el->getVertex(j)); } } } @@ -379,6 +441,10 @@ std::set<MVertex*> filter2D(GFace *gf, } } } + gf->triangles.clear(); + gf->triangles.insert(gf->triangles.begin(),tt.begin(),tt.end()); + gf->quadrangles.clear(); + gf->quadrangles.insert(gf->quadrangles.begin(),qq.begin(),qq.end()); return not_touched; } @@ -427,7 +493,7 @@ void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p) clock_t t1 = clock(); - int samples = 20; + int samples = 100; // int method = Mesh::METHOD_RELAXBND | Mesh::METHOD_PHYSCOORD | Mesh::METHOD_PROJJAC; // int method = Mesh::METHOD_FIXBND | Mesh::METHOD_PHYSCOORD | Mesh::METHOD_PROJJAC; @@ -449,47 +515,68 @@ void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p) SVector3 BND(gm->bounds().max(), gm->bounds().min()); double SIZE = BND.norm(); - Msg::Info("High order mesh optimizer starts"); - + OptHomMessage("High order mesh optimizer starts"); + double distMaxBND, distAvgBND, minJac, maxJac; if (p.dim == 2) { + clock_t tf1 = clock();; for (GModel::fiter itf = gm->firstFace(); itf != gm->lastFace(); ++itf) { if (p.onlyVisible && !(*itf)->getVisibility())continue; int ITER = 0; - Msg::Info("Model face %4d is considered",(*itf)->tag()); - p.SUCCESS = true; + OptHomMessage("Optimizing Model face %4d...",(*itf)->tag()); + p.SUCCESS = 1; + std::set<MElement*> badasses; + if (p.filter == 1){ + for (int i=0;i<(*itf)->getNumMeshElements();i++){ + double jmin,jmax; + (*itf)->getMeshElement(i)->scaledJacRange(jmin,jmax); + if (jmin < p.BARRIER_MIN || jmax > p.BARRIER_MAX)badasses.insert((*itf)->getMeshElement(i)); + } + // printf("START WITH %d bad asses\n",badasses.size()); + if (badasses.size() == 0)continue; + } while (1){ std::vector<MTriangle*> tris = (*itf)->triangles; std::vector<MQuadrangle*> quas = (*itf)->quadrangles; std::set<MVertex*> toFix; - if (p.filter == 1) toFix = filter2D_boundaryLayer(*itf, p.nbLayers, p.BARRIER_MIN, p.BARRIER_MAX, p.DistanceFactor); - else toFix = filter2D(*itf, p.nbLayers, p.BARRIER_MIN, p.BARRIER_MAX, p.DistanceFactor); - + if (p.filter == 1) toFix = filter2D_boundaryLayer(*itf, p.nbLayers, p.BARRIER_MIN, p.BARRIER_MAX, p.DistanceFactor, badasses); + else toFix = filter2D(*itf, p.nbLayers, p.BARRIER_MIN, p.BARRIER_MAX); OptHOM *temp = new OptHOM(*itf, toFix, method); - double distMaxBND, distAvgBND, minJac, maxJac; - temp->recalcJacDist(); - temp->getJacDist(minJac, maxJac, distMaxBND, distAvgBND); - if (minJac < 1.e2)Msg::Info("Optimizing a blob of %4d elements minJ %12.5E -- maxJ %12.5E",(*itf)->getNumMeshElements(), minJac, maxJac); - (*itf)->triangles = tris; - (*itf)->quadrangles = quas; + // temp->recalcJacDist(); + + temp->getDistances(distMaxBND, distAvgBND,minJac, maxJac); + // if (minJac < 1.e2)OptHomMessage("Optimizing a blob of %4d elements minJ %12.5E -- maxJ %12.5E",(*itf)->getNumMeshElements(), minJac, maxJac); std::ostringstream ossI; ossI << "initial_" << (*itf)->tag() << "ITER_" << ITER << ".msh"; temp->mesh.writeMSH(ossI.str().c_str()); + (*itf)->triangles = tris; + (*itf)->quadrangles = quas; if (minJac > p.BARRIER_MIN && maxJac < p.BARRIER_MAX) break; - p.SUCCESS = temp->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX, samples, p.itMax); - temp->getJacDist(p.minJac, p.maxJac, distMaxBND, distAvgBND); + p.SUCCESS = std::min(p.SUCCESS,temp->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX, samples, p.itMax)); + + temp->getDistances(distMaxBND, distAvgBND,minJac, maxJac); + // temp->getJacDist(p.minJac, p.maxJac, distMaxBND, distAvgBND); temp->mesh.updateGEntityPositions(); - if (!p.SUCCESS) break; + if (p.SUCCESS == -1) break; ITER ++; + if (p.filter == 1 && ITER > badasses.size() * 2)break; // std::ostringstream ossF; // ossF << "final_" << (*itf)->tag() << ".msh"; // temp->mesh.writeMSH(ossF.str().c_str()); } - Msg::Info("Model face %4d is done (%d subdomains were computed) SUCCESS %1d",(*itf)->tag(),ITER,p.SUCCESS); - Msg::Info("----------------------------------------------------------------"); + double DTF = (double)(clock()-tf1) / CLOCKS_PER_SEC; + if (p.SUCCESS == 1){ + OptHomMessage("Optimization succeeded (CPU %g sec)",DTF); + } + else if (p.SUCCESS == 0) + OptHomMessage("Warning : Model face %4d has all jacobians positive but not all in the range CPU %g",(*itf)->tag(),DTF); + else if (p.SUCCESS == -1) + OptHomMessage("Error : Model face %4d has still negative jacobians",(*itf)->tag()); + + Msg::Info("---------------------------------------------------------------------------------------------------------------"); } exportMeshToDassault (gm,gm->getName() + "_opti.das", 2); } @@ -509,8 +596,9 @@ void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p) // if ((*itr)->tetrahedra.size() > 0) { OptHOM *temp = new OptHOM(*itr, toFix, method); double distMaxBND, distAvgBND, minJac, maxJac; - temp->recalcJacDist(); - temp->getJacDist(minJac, maxJac, distMaxBND, distAvgBND); + temp->getDistances(distMaxBND, distAvgBND,minJac, maxJac); + // temp->recalcJacDist(); + // temp->getJacDist(minJac, maxJac, distMaxBND, distAvgBND); if (minJac < 1.e2)Msg::Info("Optimizing a blob of %4d elements minJ %12.5E -- maxJ %12.5E",(*itr)->getNumMeshElements(), minJac, maxJac); (*itr)->tetrahedra = tets; std::ostringstream ossI; @@ -518,7 +606,8 @@ void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p) temp->mesh.writeMSH(ossI.str().c_str()); if (minJac > p.BARRIER_MIN && maxJac < p.BARRIER_MAX) break; p.SUCCESS = temp->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX, samples, p.itMax); - temp->getJacDist(p.minJac, p.maxJac, distMaxBND, distAvgBND); + temp->getDistances(distMaxBND, distAvgBND,minJac, maxJac); + // temp->getJacDist(p.minJac, p.maxJac, distMaxBND, distAvgBND); temp->mesh.updateGEntityPositions(); if (!p.SUCCESS) break; // } @@ -530,5 +619,5 @@ void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p) } } clock_t t2 = clock(); - p.CPU = (double)(t2-t2)/CLOCKS_PER_SEC; + p.CPU = (double)(t2-t1)/CLOCKS_PER_SEC; } diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.h b/contrib/HighOrderMeshOptimizer/OptHomRun.h index feac05b006f3b45f0ecac6ad5d0595748b926c85..5b6cebb9460ca1438c8d79559503dae4e7b14426 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomRun.h +++ b/contrib/HighOrderMeshOptimizer/OptHomRun.h @@ -22,6 +22,9 @@ struct OptHomParameters { int SUCCESS ; // 0 --> success , 1 --> Not converged double minJac, maxJac; // after optimization, range of jacobians double CPU; // Time for optimization + + // is called by the optimizer at every stage of the + // virtual void progressCallback (int percetageDone) const {} OptHomParameters () // default values @@ -32,6 +35,7 @@ struct OptHomParameters { }; void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p); +void OptHomMessage (const char *s, ...); #endif