diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp index 1c5d75080094bae84e4b8c7cc7d78dce2d418fb3..2d54c47d4f4af6e5b5f2beb36576fa21de212417 100644 --- a/Geo/MElement.cpp +++ b/Geo/MElement.cpp @@ -322,9 +322,9 @@ static double _computeDeterminantAndRegularize(MElement *ele, double jac[3][3]) } case 3: { - dJ = fabs(jac[0][0] * jac[1][1] * jac[2][2] + jac[0][2] * jac[1][0] * jac[2][1] + - jac[0][1] * jac[1][2] * jac[2][0] - jac[0][2] * jac[1][1] * jac[2][0] - - jac[0][0] * jac[1][2] * jac[2][1] - jac[0][1] * jac[1][0] * jac[2][2]); + dJ = (jac[0][0] * jac[1][1] * jac[2][2] + jac[0][2] * jac[1][0] * jac[2][1] + + jac[0][1] * jac[1][2] * jac[2][0] - jac[0][2] * jac[1][1] * jac[2][0] - + jac[0][0] * jac[1][2] * jac[2][1] - jac[0][1] * jac[1][0] * jac[2][2]); break; } } diff --git a/contrib/HighOrderMeshOptimizer/OptHOM.cpp b/contrib/HighOrderMeshOptimizer/OptHOM.cpp index 84daa9e986e1a3668235ea92b7ee634a0482a1f2..2ba8c4753815fc4712bd539a81149c8aea63db9d 100644 --- a/contrib/HighOrderMeshOptimizer/OptHOM.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHOM.cpp @@ -31,9 +31,11 @@ bool OptHOM::addJacObjGrad(double &Obj, alglib::real_1d_array &gradObj) for (int iEl = 0; iEl < mesh.nEl(); iEl++) { std::vector<double> sJ(mesh.nBezEl(iEl)); // Scaled Jacobians - mesh.scaledJac(iEl,sJ); + // mesh.scaledJac(iEl,sJ); std::vector<double> gSJ(mesh.nBezEl(iEl)*mesh.nPCEl(iEl)); // Gradients of scaled Jacobians - mesh.gradScaledJac(iEl,gSJ); + // mesh.gradScaledJac(iEl,gSJ); + mesh.scaledJacAndGradients (iEl,sJ,gSJ); + for (int l = 0; l < mesh.nBezEl(iEl); l++) { Obj += compute_f(sJ[l]); const double f1 = compute_f1(sJ[l]); @@ -198,9 +200,9 @@ void OptHOM::OptimPass(alglib::real_1d_array &x, const alglib::real_1d_array &in alglib::mincgreport rep; mincgcreate(x, state); alglib::real_1d_array scale; - calcScale(scale); - mincgsetscale(state,scale); - mincgsetprecscale(state); + calcScale(scale); + mincgsetscale(state,scale); + mincgsetprecscale(state); mincgsetcond(state, EPSG, EPSF, EPSX, itMax); mincgsetxrep(state, true); alglib::mincgoptimize(state, evalObjGradFunc, printProgressFunc, this); @@ -299,8 +301,8 @@ int OptHOM::optimize(double weightFixed, double weightFree, double b_min, double OptHomMessage("Optimization done Range (%g,%g)",minJac,maxJac); - if (minJac < barrier_min && maxJac > barrier_max) return 0; - if (minJac > 0.0) return 1; + if (minJac > barrier_min && maxJac < barrier_max) return 1; + if (minJac > 0.0) return 0; return -1; } diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp index 1525a0a9510b91d04a0878182781b2cd831b6fe8..15b1283ea5236292b5e86696d06c5d1e8108994d 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp @@ -9,8 +9,26 @@ std::map<int, std::vector<double> > Mesh::_jacBez; +std::map<int, fullMatrix<double> > Mesh::_gradShapeFunctions; +std::map<int, fullMatrix<double> > Mesh::_lag2Bez; +fullMatrix<double> Mesh::computeGSF(const polynomialBasis *lagrange, const bezierBasis *bezier) +{ + // bezier points are defined in the [0,1] x [0,1] quad + fullMatrix<double> bezierPoints = bezier->points; + if (lagrange->parentType == TYPE_QUA) { + for (int i = 0; i < bezierPoints.size1(); ++i) { + bezierPoints(i, 0) = -1 + 2 * bezierPoints(i, 0); + bezierPoints(i, 1) = -1 + 2 * bezierPoints(i, 1); + } + } + + fullMatrix<double> allDPsi; + lagrange->df(bezierPoints, allDPsi); + return allDPsi; +} + std::vector<double> Mesh::computeJB(const polynomialBasis *lagrange, const bezierBasis *bezier) { @@ -109,6 +127,8 @@ Mesh::Mesh(GEntity *ge, const std::set<MElement*> &els, std::set<MVertex*> &toFi const bezierBasis *bezier = JacobianBasis::find(lagrange->type)->bezier; if (_jacBez.find(lagrange->type) == _jacBez.end()) { _jacBez[lagrange->type] = computeJB(lagrange, bezier); + _gradShapeFunctions[lagrange->type] = computeGSF(lagrange, bezier); + _lag2Bez[lagrange->type] = bezier->matrixLag2Bez; } _nBezEl[iEl] = bezier->points.size1(); _nNodEl[iEl] = lagrange->points.size1(); @@ -301,6 +321,120 @@ void Mesh::updateGEntityPositions() } +/* + A faster version that computes jacobians and their gradients + + Terms of jacobian are of the form J_{11} = dX / dU + + X = \sum \phi_j X_{j} + + d J_{11} / dX_k = d \phi_k / du + + */ + + + +void Mesh::scaledJacAndGradients(int iEl, std::vector<double> &sJ , std::vector<double> &gSJ) { + + if (_dim == 2 && !projJac){ + // printf("coucou\n"); + gradScaledJac(iEl,gSJ); + scaledJac(iEl,sJ); + return; + } + + SVector3 n ; + if (_dim == 2) + n = _normEl[iEl]; + + // std::vector<double> OLD = sJ; + // std::vector<double> OLD = gSJ; + // gradScaledJac(iEl,OLD); + // scaledJac(iEl,OLD); + + 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]; + fullMatrix<double> JDJ (nbBez,3*nbNod+1); + fullMatrix<double> BDB (nbBez,3*nbNod+1); + + double jac[3][3]; + for (int l = 0; l < nbBez; l++) { + fullMatrix<double> dPsi(gsf, l * 3, 3); + jac[0][0] = jac[0][1] = jac[0][2] = 0.; + jac[1][0] = jac[1][1] = jac[1][2] = 0.; + jac[2][0] = jac[2][1] = jac[2][2] = (_dim == 2) ? n.z() : 0.0; + const double INVJ = (_dim == 3) ? _invStraightJac[iEl] : 1.0; + for (int i = 0; i < nbNod; i++) { + int &iVi = _el2V[iEl][i]; + const double x = _xyz[iVi].x(); + const double y = _xyz[iVi].y(); + const double z = _xyz[iVi].z(); + for (int k = 0; k < 3; k++) { + const double gg = dPsi(i, k); + jac[k][0] += x * gg; + jac[k][1] += y * gg; + jac[k][2] += z * gg; + } + } + for (int i = 0; i < nbNod; i++) { + JDJ (l,i+0*nbNod) = + ( dPsi(i, 0) * jac[1][1] * jac[2][2] + jac[0][2] * dPsi(i, 1) * jac[2][1] + + jac[0][1] * jac[1][2] * dPsi(i, 2) - jac[0][2] * jac[1][1] * dPsi(i, 2) - + dPsi(i, 0) * jac[1][2] * jac[2][1] - jac[0][1] * dPsi(i, 1) * jac[2][2]) + * INVJ; + JDJ (l,i+1*nbNod) = + (jac[0][0] * dPsi(i, 1) * jac[2][2] + jac[0][2] * jac[1][0] * dPsi(i, 2) + + dPsi(i, 0) * jac[1][2] * jac[2][0] - jac[0][2] * dPsi(i, 1) * jac[2][0] - + jac[0][0] * jac[1][2] * dPsi(i, 2) - dPsi(i, 0) * jac[1][0] * jac[2][2]) + * INVJ; + JDJ (l,i+2*nbNod) = + (jac[0][0] * jac[1][1] * dPsi(i, 2) + dPsi(i, 0) * jac[1][0] * jac[2][1] + + jac[0][1] * dPsi(i, 1) * jac[2][0] - dPsi(i, 0) * jac[1][1] * jac[2][0] - + jac[0][0] * dPsi(i, 1) * jac[2][1] - jac[0][1] * jac[1][0] * dPsi(i, 2)) + * INVJ; + } + const double dJ = + jac[0][0] * jac[1][1] * jac[2][2] + jac[0][2] * jac[1][0] * jac[2][1] + + jac[0][1] * jac[1][2] * jac[2][0] - jac[0][2] * jac[1][1] * jac[2][0] - + jac[0][0] * jac[1][2] * jac[2][1] - jac[0][1] * jac[1][0] * jac[2][2]; + JDJ(l,3*nbNod) = dJ * INVJ; + } + + // (N_b x N_b) x (N_b x 3*N_n + 1) + l2b.mult(JDJ,BDB); + + // the scaled jacobian + // printf("ELEMENT %d\n",iEl); + for (int l = 0; l < nbBez; l++) { + sJ [l] = BDB (l,3*nbNod); + // printf("OLD %12.5E NEW %12.5E\n",OLD[l],sJ[l]); + } + + // gradients of the scaled jacobian + int iPC = 0; + std::vector<SPoint3> gXyzV(nbBez); + std::vector<SPoint3> gUvwV(nbBez); + 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(BDB(l,i+0*nbNod),BDB(l,i+1*nbNod),BDB(l,i+2*nbNod)); + } + _pc->gXyz2gUvw(_freeVert[iFVi],_uvw[iFVi],gXyzV,gUvwV); + for (int l = 0; l < nbBez; l++) { + gSJ[indGSJ(iEl,l,iPC)] = gUvwV[l][0]; + if (_nPCFV[iFVi] >= 2) gSJ[indGSJ(iEl,l,iPC+1)] = gUvwV[l][1]; + if (_nPCFV[iFVi] == 3) gSJ[indGSJ(iEl,l,iPC+2)] = gUvwV[l][2]; + // if (fabs(OLD[indGSJ(iEl,l,iPC+2)]-gSJ[indGSJ(iEl,l,iPC+2)]) > 1.e-6) + // printf("OLD = %12.5E new = %12.5E\n",OLD[indGSJ(iEl,l,iPC+2)],gSJ[indGSJ(iEl,l,iPC+2)]); + } + iPC += _nPCFV[iFVi]; + } + } +} + void Mesh::scaledJac(int iEl, std::vector<double> &sJ) { diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.h b/contrib/HighOrderMeshOptimizer/OptHomMesh.h index dcdfd6fc4814c7c8ad4b82057c993a2d1e665e93..25f194beac99eaed9ec48752354c5fb0fed3c4d4 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomMesh.h +++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.h @@ -32,6 +32,8 @@ public: void scaledJac(int iEl, std::vector<double> &sJ); void gradScaledJac(int iEl, std::vector<double> &gSJ); + // a faster version that computes both jacobians and their gradients + 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; } inline double distSq(int iFV); @@ -80,11 +82,14 @@ private: bool projJac; // Using "projected" Jacobians or not static std::map<int, std::vector<double> > _jacBez; + static std::map<int, fullMatrix<double> > _gradShapeFunctions; // gradients of shape functions at Bezier points + static std::map<int, fullMatrix<double> > _lag2Bez; // gradients of shape functions at Bezier points int addVert(MVertex* vert); int addFreeVert(MVertex* vert, const int iV, const int nPCV, std::set<MVertex*> &toFix); SVector3 getNormalEl(int iEl); static std::vector<double> computeJB(const polynomialBasis *lagrange, const bezierBasis *bezier); + static fullMatrix<double> computeGSF(const polynomialBasis *lagrange, const bezierBasis *bezier); static inline int indJB2DBase(int nNod, int l, int i, int j) { return (l*nNod+i)*nNod+j; } inline int indJB2D(int iEl, int l, int i, int j) { return indJB2DBase(_nNodEl[iEl],l,i,j); } static inline int indJB3DBase(int nNod, int l, int i, int j, int m) { return ((l*nNod+i)*nNod+j)*nNod+m; } diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp index 8e8ee194785bef4bfac0ddc5a93c3a2b2eb1bf4e..61fb0f0965bf2e4b89ece5425afb63a01a997ab5 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp @@ -374,7 +374,7 @@ void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p) clock_t t1 = clock(); - int samples = 100; + int samples = 30; // int method = Mesh::METHOD_RELAXBND | Mesh::METHOD_PHYSCOORD | Mesh::METHOD_PROJJAC; // int method = Mesh::METHOD_FIXBND | Mesh::METHOD_PHYSCOORD | Mesh::METHOD_PROJJAC; @@ -425,19 +425,20 @@ void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p) OptHOM temp(*itf, toOptimizeSplit[i], toFix, method); temp.recalcJacDist(); temp.getJacDist(minJac, maxJac, distMaxBND, distAvgBND); - OptHomMessage("Optimizing a blob %i/%i composed of %4d elements minJ %12.5E -- maxJ %12.5E", i, toOptimizeSplit.size(), toOptimizeSplit[i].size(), minJac, maxJac); + OptHomMessage("Optimizing a blob %i/%i composed of %4d elements minJ %12.5E -- maxJ %12.5E", i+1, toOptimizeSplit.size(), toOptimizeSplit[i].size(), minJac, maxJac); p.SUCCESS = std::min(p.SUCCESS,temp.optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX, samples, p.itMax)); + temp.mesh.updateGEntityPositions(); } } else while (1){ std::set<MVertex*> toFix; - std::set<MElement*> toOptimize; + std::set<MElement*> toOptimize; toFix = filter2D_boundaryLayer(*itf, p.nbLayers, p.BARRIER_MIN, p.BARRIER_MAX, p.DistanceFactor, badasses, toOptimize); OptHOM temp(*itf, toOptimize, toFix, method); temp.recalcJacDist(); - temp.getJacDist(minJac, maxJac, distMaxBND, distAvgBND); + temp.getJacDist(minJac, maxJac, distMaxBND, distAvgBND); // 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"; @@ -476,7 +477,21 @@ void HighOrderMeshOptimizer (GModel *gm, OptHomParameters &p) int ITER = 0; Msg::Info("Model region %4d is considered",(*itr)->tag()); p.SUCCESS = true; - while (1){ + if (p.filter == 0) { + std::set<MVertex*> toFix; + std::set<MElement*> toOptimize; + toFix = filterSimple(*itr, p.nbLayers, p.BARRIER_MIN, p.BARRIER_MAX, toOptimize); + std::vector<std::set<MElement*> > toOptimizeSplit = splitConnex(toOptimize); + for (int i = 0; i < toOptimizeSplit.size(); ++i) { + OptHOM temp(*itr, toOptimizeSplit[i], toFix, method); + temp.recalcJacDist(); + temp.getJacDist(minJac, maxJac, distMaxBND, distAvgBND); + OptHomMessage("Optimizing a blob %i/%i composed of %4d elements minJ %12.5E -- maxJ %12.5E", i+1, toOptimizeSplit.size(), toOptimizeSplit[i].size(), minJac, maxJac); + p.SUCCESS = std::min(p.SUCCESS,temp.optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN, p.BARRIER_MAX, samples, p.itMax)); + temp.mesh.updateGEntityPositions(); + } + } + else while (1){ std::set<MVertex*> toFix; std::set<MElement*> toOptimize;