diff --git a/contrib/HighOrderMeshOptimizer/OptHOM.cpp b/contrib/HighOrderMeshOptimizer/OptHOM.cpp index 3d5fc413fd3fec4f94bf857d6a37f2d7a7017a45..a9a0954ccae4aacbde25428a856a07236075d834 100644 --- a/contrib/HighOrderMeshOptimizer/OptHOM.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHOM.cpp @@ -20,6 +20,7 @@ OptHOM::OptHOM(GEntity *ge, const std::set<MElement*> &els, std::set<MVertex*> & toFix, int method) : mesh(ge, els, toFix, method) { + _optimizeMetricMin = false; }; @@ -50,6 +51,29 @@ bool OptHOM::addJacObjGrad(double &Obj, alglib::real_1d_array &gradObj) } +bool OptHOM::addMetricMinObjGrad(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 + std::vector<double> gSJ(mesh.nBezEl(iEl)*mesh.nPCEl(iEl)); // Gradients of scaled Jacobians + mesh.metricMinAndGradients (iEl,sJ,gSJ); + + for (int l = 0; l < mesh.nBezEl(iEl); l++) { + Obj += compute_f(sJ[l]); + 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]); + } + } + return true; +} + // Contribution of the vertex distance to the objective function value and gradients (2D version) @@ -89,9 +113,12 @@ void OptHOM::evalObjGrad(const alglib::real_1d_array &x, double &Obj, alglib::re addJacObjGrad(Obj, gradObj); addDistObjGrad(lambda, lambda2, Obj, gradObj); + if(_optimizeMetricMin) + addMetricMinObjGrad(Obj, gradObj); + if ((minJac > barrier_min) && (maxJac < barrier_max)) { - printf("INFO: reached Jacobian requirements, setting null gradient\n"); + printf("INFO: reached %s (%g %g) requirements, setting null gradient\n", _optimizeMetricMin ? "svd" : "jacobian", minJac, maxJac); Obj = 0.; for (int i = 0; i < gradObj.length(); i++) gradObj[i] = 0.; } @@ -130,12 +157,13 @@ void OptHOM::recalcJacDist() std::vector<double> sJ(mesh.nBezEl(iEl)); // Scaled Jacobians std::vector<double> dumGSJ(mesh.nBezEl(iEl)*mesh.nPCEl(iEl)); // (Dummy) gradients of scaled Jacobians mesh.scaledJacAndGradients (iEl,sJ,dumGSJ); + if(_optimizeMetricMin) + mesh.metricMinAndGradients (iEl,sJ,dumGSJ); for (int l = 0; l < mesh.nBezEl(iEl); l++) { minJac = std::min(minJac, sJ[l]); maxJac = std::max(maxJac, sJ[l]); } } - } @@ -236,7 +264,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) +int OptHOM::optimize(double weightFixed, double weightFree, double b_min, double b_max, bool optimizeMetricMin, int pInt, int itMax) { barrier_min = b_min; @@ -245,6 +273,7 @@ int OptHOM::optimize(double weightFixed, double weightFree, double b_min, double // powM = 4; // powP = 3; + _optimizeMetricMin = optimizeMetricMin; // Set weights & length scale for non-dimensionalization lambda = weightFixed; lambda2 = weightFree; diff --git a/contrib/HighOrderMeshOptimizer/OptHOM.h b/contrib/HighOrderMeshOptimizer/OptHOM.h index a0865c7ef244c697d8baf313f34e997a0ecb258d..431c7413eb837cfe501d35f9f613a67bf7bef498 100644 --- a/contrib/HighOrderMeshOptimizer/OptHOM.h +++ b/contrib/HighOrderMeshOptimizer/OptHOM.h @@ -25,7 +25,7 @@ public: // 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 + int optimize(double lambda, double lambda2, double barrier_min, double barrier_max, bool optimizeMetricMin, int pInt, int itMax); // optimize one list of elements void recalcJacDist(); inline void getJacDist(double &minJ, double &maxJ, double &maxD, double &avgD); void updateMesh(const alglib::real_1d_array &x); @@ -39,6 +39,7 @@ private: // double lambda, lambda2, powM, powP, invLengthScaleSq; double lambda, lambda2, jacBar, invLengthScaleSq; int iter, progressInterv; // Current iteration, interval of iterations for reporting + bool _optimizeMetricMin; double initObj, initMaxDist, initAvgDist; // Values for reporting double minJac, maxJac, maxDist, avgDist; // Values for reporting @@ -46,6 +47,7 @@ private: inline double compute_f(double v); inline double compute_f1(double v); bool addJacObjGrad(double &Obj, alglib::real_1d_array &gradObj); + bool addMetricMinObjGrad(double &Obj, alglib::real_1d_array &gradObj); bool addDistObjGrad(double Fact, double Fact2, double &Obj, alglib::real_1d_array &gradObj); void calcScale(alglib::real_1d_array &scale); void OptimPass(alglib::real_1d_array &x, const alglib::real_1d_array &initGradObj, int itMax); diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp index 23c635348d9d9542958af57c10aa9c9f737757ec..20f7035bc0555ea2e53bdb976e5a9a07c286bb6c 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp @@ -269,6 +269,85 @@ void Mesh::updateGEntityPositions() } +void Mesh::metricMinAndGradients(int iEl, std::vector<double> &lambda , std::vector<double> &gradLambda) +{ + fullMatrix<double> &gsf = _gradShapeFunctions[_el[iEl]->getTypeForMSH()]; + //const fullMatrix<double> &l2b = _lag2Bez[_el[iEl]->getTypeForMSH()]; + const int nbBez = _nBezEl[iEl]; + const int nbNod = _nNodEl[iEl]; + fullVector<double> lambdaJ(nbBez), lambdaB(nbBez); + fullMatrix<double> gradLambdaJ(nbBez, 2 * nbNod); + fullMatrix<double> gradLambdaB(nbBez, 2 * nbNod); + + // jacobian of the straight elements (only triangles for now) + SPoint3 *IXYZ[3] = {&_ixyz[_el2V[iEl][0]], &_ixyz[_el2V[iEl][1]], &_ixyz[_el2V[iEl][2]]}; + double jaci[2][2] = { + {IXYZ[1]->x() - IXYZ[0]->x(), IXYZ[2]->x() - IXYZ[0]->x()}, + {IXYZ[1]->y() - IXYZ[0]->y(), IXYZ[2]->y() - IXYZ[0]->y()} + }; + double invJaci[2][2]; + inv2x2(jaci, invJaci); + + for (int l = 0; l < nbBez; l++) { + fullMatrix<double> dPsi(gsf, l * 3, 3); + double jac[2][2] = {{0., 0.}, {0., 0.}}; + for (int i = 0; i < nbNod; i++) { + int &iVi = _el2V[iEl][i]; + const double dpsidx = dPsi(i, 0) * invJaci[0][0] + dPsi(i, 1) * invJaci[1][0]; + const double dpsidy = dPsi(i, 0) * invJaci[0][1] + dPsi(i, 1) * invJaci[1][1]; + jac[0][0] += _xyz[iVi].x() * dpsidx; + jac[0][1] += _xyz[iVi].x() * dpsidy; + jac[1][0] += _xyz[iVi].y() * dpsidx; + jac[1][1] += _xyz[iVi].y() * dpsidy; + } + const double dxdx = jac[0][0] * jac[0][0] + jac[0][1] * jac[0][1]; + const double dydy = jac[1][0] * jac[1][0] + jac[1][1] * jac[1][1]; + const double dxdy = jac[0][0] * jac[1][0] + jac[0][1] * jac[1][1]; + const double sqr = sqrt((dxdx - dydy) * (dxdx - dydy) + 4 * dxdy * dxdy); + const double osqr = sqr > 1e-8 ? 1/sqr : 0; + lambdaJ(l) = 0.5 * (dxdx + dydy - sqr); + const double axx = (1 - (dxdx - dydy) * osqr) * jac[0][0] - 2 * dxdy * osqr * jac[1][0]; + const double axy = (1 - (dxdx - dydy) * osqr) * jac[0][1] - 2 * dxdy * osqr * jac[1][1]; + const double ayx = -2 * dxdy * osqr * jac[0][0] + (1 - (dydy - dxdx) * osqr) * jac[1][0]; + const double ayy = -2 * dxdy * osqr * jac[0][1] + (1 - (dydy - dxdx) * osqr) * jac[1][1]; + const double axixi = axx * invJaci[0][0] + axy * invJaci[0][1]; + const double aetaeta = ayx * invJaci[1][0] + ayy * invJaci[1][1]; + const double aetaxi = ayx * invJaci[0][0] + ayy * invJaci[0][1]; + const double axieta = axx * invJaci[1][0] + axy * invJaci[1][1]; + for (int i = 0; i < nbNod; i++) { + gradLambdaJ(l, i + 0 * nbNod) = axixi * dPsi(i, 0) + axieta * dPsi(i, 1); + gradLambdaJ(l, i + 1 * nbNod) = aetaxi * dPsi(i, 0) + aetaeta * dPsi(i, 1); + } + } + + //l2b.mult(lambdaJ, lambdaB); + //l2b.mult(gradLambdaJ, gradLambdaB); + lambdaB = lambdaJ; + gradLambdaB = gradLambdaJ; + + int iPC = 0; + std::vector<SPoint3> gXyzV(nbBez); + std::vector<SPoint3> gUvwV(nbBez); + for (int l = 0; l < nbBez; l++) { + lambda[l] = lambdaB(l); + } + for (int i = 0; i < nbNod; i++) { + int &iFVi = _el2FV[iEl][i]; + if (iFVi >= 0) { + for (int l = 0; l < nbBez; l++) { + gXyzV [l] = SPoint3(gradLambdaB(l,i+0*nbNod),gradLambdaB(l,i+1*nbNod),/*BDB(l,i+2*nbNod)*/ 0.); + } + _pc->gXyz2gUvw(_freeVert[iFVi],_uvw[iFVi],gXyzV,gUvwV); + for (int l = 0; l < nbBez; l++) { + gradLambda[indGSJ(iEl,l,iPC)] = gUvwV[l][0]; + if (_nPCFV[iFVi] >= 2) gradLambda[indGSJ(iEl,l,iPC+1)] = gUvwV[l][1]; + if (_nPCFV[iFVi] == 3) gradLambda[indGSJ(iEl,l,iPC+2)] = gUvwV[l][2]; + } + iPC += _nPCFV[iFVi]; + } + } +} + /* A faster version that computes jacobians and their gradients diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.h b/contrib/HighOrderMeshOptimizer/OptHomMesh.h index bac927e1a3139010324bfe48c3296cd07359f980..61c89a72ca24d57379c0b3082dbc5362ebed01b0 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomMesh.h +++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.h @@ -30,6 +30,7 @@ public: inline const int &indPCEl(int iEl, int iPC) { return _indPCEl[iEl][iPC]; } inline const int &nBezEl(int iEl) { return _nBezEl[iEl]; } + void metricMinAndGradients(int iEl, std::vector<double> &sJ, std::vector<double> &gSJ); void scaledJacAndGradients(int iEl, std::vector<double> &sJ, std::vector<double> &gSJ); inline int indGSJ(int iEl, int l, int iPC) { return iPC*_nBezEl[iEl]+l; } diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp index cff74b8f5fa422e27eda6ac7cb881b4c4e54c43e..d6ac67769efda27e1d60f2e3940ee56689843865 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp @@ -457,7 +457,11 @@ void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p) OptHomMessage("Optimizing a blob %i/%i composed of %4d elements", i+1, toOptimize.size(), toOptimize[i].first.size()); fflush(stdout); OptHOM temp(&entity, toOptimize[i].first, toOptimize[i].second, method); - int success = temp.optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX, samples, p.itMax); + int success = temp.optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX, false, samples, p.itMax); + if (success >= 0 && p.BARRIER_MIN_METRIC > 0) { + OptHomMessage("jacobian optimization succeed, starting svd optimization"); + success = temp.optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN_METRIC, p.BARRIER_MAX, true, samples, p.itMax); + } temp.mesh.updateGEntityPositions(); if (success <= 0) { std::ostringstream ossI2; @@ -508,7 +512,7 @@ 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 = std::min(p.SUCCESS,temp.optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX, samples, p.itMax)); + p.SUCCESS = std::min(p.SUCCESS,temp.optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX, false, samples, p.itMax)); // temp.recalcJacDist(); // temp.getJacDist(minJac, maxJac, distMaxBND, distAvgBND); @@ -556,7 +560,7 @@ void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p) ossI << "initial_" << (*itr)->tag() << "ITER_" << ITER << ".msh"; 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); + p.SUCCESS = temp.optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX, false, samples, p.itMax); temp.recalcJacDist(); temp.getJacDist(minJac, maxJac, distMaxBND, distAvgBND); temp.mesh.updateGEntityPositions(); diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.h b/contrib/HighOrderMeshOptimizer/OptHomRun.h index 5b6cebb9460ca1438c8d79559503dae4e7b14426..66fa29a22e3378158726f199383b005cbe6739d3 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomRun.h +++ b/contrib/HighOrderMeshOptimizer/OptHomRun.h @@ -5,6 +5,7 @@ class GModel; struct OptHomParameters { // INPUT ------> + double BARRIER_MIN_METRIC ; // minimum scaled jcaobian double BARRIER_MIN ; // minimum scaled jcaobian double BARRIER_MAX ; // maximum scaled jcaobian double weightFixed ; // weight of the energy for fixed nodes @@ -28,7 +29,7 @@ struct OptHomParameters { OptHomParameters () // default values - : BARRIER_MIN (0.1), BARRIER_MAX (2.0) , weightFixed (1.e6), weightFree (1.e2), + : BARRIER_MIN (0.1), BARRIER_MAX (2.0) , BARRIER_MIN_METRIC (-1.), weightFixed (1.e6), weightFree (1.e2), nbLayers (6) , dim(3) , itMax(10000), onlyVisible(true), DistanceFactor(12), method(1), filter(1) { }