diff --git a/contrib/MeshOptimizer/MeshOptPatch.cpp b/contrib/MeshOptimizer/MeshOptPatch.cpp index 1af5b3fd32e28bf1f876231e3360a2bcad4b6e7c..c4f71eb0620b6abce8c24e29c8b36c2683e52430 100644 --- a/contrib/MeshOptimizer/MeshOptPatch.cpp +++ b/contrib/MeshOptimizer/MeshOptPatch.cpp @@ -269,7 +269,7 @@ void Patch::initScaledJac() if ((_dim == 2) && _scaledNormEl.empty()) { _scaledNormEl.resize(nEl()); // for (int iEl = 0; iEl < nEl(); iEl++) calcScaledNormalEl2D(element2entity,iEl); - for (int iEl = 0; iEl < nEl(); iEl++) calcNormalEl2D(iEl, true); + for (int iEl = 0; iEl < nEl(); iEl++) calcNormalEl2D(iEl, NS_INVNORM); } else if (_invStraightJac.empty()) { _invStraightJac.resize(nEl(),1.); @@ -293,7 +293,7 @@ void Patch::initMetricMin() // TODO: Re-introduce normal to geometry? //void Mesh::calcScaledNormalEl2D(const std::map<MElement*,GEntity*> &element2entity, int iEl) -void Patch::calcNormalEl2D(int iEl, bool scale) +void Patch::calcNormalEl2D(int iEl, NORMALSCALING scaling) { const JacobianBasis *jac = _el[iEl]->getJacobianFuncSpace(); @@ -320,11 +320,12 @@ void Patch::calcNormalEl2D(int iEl, bool scale) // } fullMatrix<double> uElNorm(1, 3); - fullMatrix<double> &elNorm = scale ? _scaledNormEl[iEl] : uElNorm; + fullMatrix<double> &elNorm = (scaling == NS_INVNORM) ? _scaledNormEl[iEl] : + ((scaling == NS_UNIT) ? uElNorm : _metricNormEl[iEl]); elNorm.resize(1, 3); const double norm = jac->getPrimNormal2D(primNodesXYZ, elNorm); - if (scale) { - double factor = 1./norm; + if (scaling != 0) { + double factor = (scaling == NS_SQRTNORM) ? 1./norm : sqrt(norm); // if (hasGeoNorm) { // const double scal = geoNorm(0)*elNorm(0,0)+geoNorm(1)*elNorm(0,1)+geoNorm(2)*elNorm(0,2); // if (scal < 0.) factor = -factor; @@ -520,7 +521,7 @@ void Patch::initNCJ() if ((_dim == 2) && _unitNormEl.empty()) { _unitNormEl.resize(nEl()); // for (int iEl = 0; iEl < nEl(); iEl++) calcScaledNormalEl2D(element2entity,iEl); - for (int iEl = 0; iEl < nEl(); iEl++) calcNormalEl2D(iEl, false); + for (int iEl = 0; iEl < nEl(); iEl++) calcNormalEl2D(iEl, NS_UNIT); } } @@ -591,3 +592,68 @@ void Patch::NCJAndGradients(int iEl, std::vector<double> &NCJ, std::vector<doubl } } } + + +void Patch::initInvCond() +{ + // Initialize _nBezEl + if (_nBezEl.empty()) { + _nBezEl.resize(nEl()); + for (int iEl=0; iEl<nEl(); iEl++) + _nBezEl[iEl] = _el[iEl]->getJacobianFuncSpace()->getNumJacNodes(); + } + + // Set normals to 2D elements (with magnitude of inverse Jacobian) or initial + // Jacobians of 3D elements + if ((_dim == 2) && _metricNormEl.empty()) { + _metricNormEl.resize(nEl()); +// for (int iEl = 0; iEl < nEl(); iEl++) calcScaledNormalEl2D(element2entity,iEl); + for (int iEl = 0; iEl < nEl(); iEl++) calcNormalEl2D(iEl, NS_SQRTNORM); + } +} + + +void Patch::invCondAndGradients(int iEl, std::vector<double> &invCond, + std::vector<double> &gInvCond) +{ + const JacobianBasis *jacBasis = _el[iEl]->getJacobianFuncSpace(); + const int &numJacNodes = _nBezEl[iEl]; + const int &numMapNodes = _nNodEl[iEl]; + fullMatrix<double> IDI(numJacNodes,3*numMapNodes+1); + + // Coordinates of nodes + fullMatrix<double> nodesXYZ(numMapNodes,3), normals(_dim,3); + for (int i = 0; i < numMapNodes; i++) { + int &iVi = _el2V[iEl][i]; + nodesXYZ(i,0) = _xyz[iVi].x(); + nodesXYZ(i,1) = _xyz[iVi].y(); + nodesXYZ(i,2) = _xyz[iVi].z(); + } + + // Calculate Jacobian and gradients, scale if 3D (already scaled by + // regularization normals in 2D) + jacBasis->getInvCondAndGradients(nodesXYZ, _metricNormEl[iEl], IDI); + + // Inverse condition number + for (int l = 0; l < numJacNodes; l++) invCond[l] = IDI(l, 3*numMapNodes); + + // Gradients of the inverse condition number + int iPC = 0; + std::vector<SPoint3> gXyzV(numJacNodes); + std::vector<SPoint3> gUvwV(numJacNodes); + for (int i = 0; i < numMapNodes; i++) { + int &iFVi = _el2FV[iEl][i]; + if (iFVi >= 0) { + for (int l = 0; l < numJacNodes; l++) + gXyzV[l] = SPoint3(IDI(l, i), IDI(l, i+numMapNodes), + IDI(l, i+2*numMapNodes)); + _coordFV[iFVi]->gXyz2gUvw(_uvw[iFVi],gXyzV,gUvwV); + for (int l = 0; l < numJacNodes; l++) { + gInvCond[indGSJ(iEl,l,iPC)] = gUvwV[l][0]; + if (_nPCFV[iFVi] >= 2) gInvCond[indGSJ(iEl,l,iPC+1)] = gUvwV[l][1]; + if (_nPCFV[iFVi] == 3) gInvCond[indGSJ(iEl,l,iPC+2)] = gUvwV[l][2]; + } + iPC += _nPCFV[iFVi]; + } + } +} diff --git a/contrib/MeshOptimizer/MeshOptPatch.h b/contrib/MeshOptimizer/MeshOptPatch.h index 9ff8e026e5df44a837691ec0f8a200cf1efdca77..4269ba833d02510802bea41b289f0f77d8f86a5b 100644 --- a/contrib/MeshOptimizer/MeshOptPatch.h +++ b/contrib/MeshOptimizer/MeshOptPatch.h @@ -98,9 +98,13 @@ public: void initNCJ(); void NCJ(int iEl, std::vector<double> &NCJ); void NCJAndGradients(int iEl, std::vector<double> &NCJ, std::vector<double> &gNCJ); + void initInvCond(); + void invCondAndGradients(int iEl, std::vector<double> &invCond, std::vector<double> &ginvCond); private: + enum NORMALSCALING { NS_UNIT, NS_INVNORM, NS_SQRTNORM }; + // Mesh entities and variables int _dim; int _nPC; // Total nb. of parametric coordinates @@ -144,11 +148,12 @@ private: std::vector<fullMatrix<double> > _scaledNormEl; // Normals to 2D elements for Jacobian regularization and scaling std::vector<double> _invStraightJac; // Initial Jacobians for 3D elements // void calcScaledNormalEl2D(const std::map<MElement*,GEntity*> &element2entity, int iEl); - void calcNormalEl2D(int iEl, bool scale); + void calcNormalEl2D(int iEl, NORMALSCALING scaling); // Mesh quality std::vector<int> _nNCJEl; // Number of NCJ values for an el. std::vector<SVector3> _unitNormEl; // Normals to 2D elements for NCJ regularization + std::vector<fullMatrix<double> > _metricNormEl; // Normals to 2D elements for inverse conditioning computation }; diff --git a/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h b/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h new file mode 100644 index 0000000000000000000000000000000000000000..ccdac14fcf1f1566c0a5f46dbca406dbdb12c807 --- /dev/null +++ b/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h @@ -0,0 +1,98 @@ +// TODO: Copyright + +#ifndef _MESHQUALITYOBJCONTRIBINVCOND_H_ +#define _MESHQUALITYOBJCONTRIBINVCOND_H_ + +#include "MeshOptPatch.h" +#include "MeshOptObjContrib.h" + + +template<class FuncType> +class ObjContribInvCond : public ObjContrib, public FuncType +{ +public: + ObjContribInvCond(double weight); + virtual ~ObjContribInvCond() {} + virtual ObjContrib *copy() const; + virtual void initialize(Patch *mesh); + virtual bool fail() { return false; } + virtual bool addContrib(double &Obj, alglib::real_1d_array &gradObj); + virtual void updateParameters() { FuncType::updateParameters(_min, _max); } + virtual bool targetReached() { return FuncType::targetReached(_min, _max); } + virtual bool stagnated() { return FuncType::stagnated(_min, _max); } + virtual void updateMinMax(); + +protected: + Patch *_mesh; + double _weight; +}; + + +template<class FuncType> +ObjContribInvCond<FuncType>::ObjContribInvCond(double weight) : + ObjContrib("InvCond", FuncType::getNamePrefix()+"InvCond"), + _mesh(0), _weight(weight) +{ +} + + +template<class FuncType> +ObjContrib *ObjContribInvCond<FuncType>::copy() const +{ + return new ObjContribInvCond<FuncType>(*this); +} + + +template<class FuncType> +void ObjContribInvCond<FuncType>::initialize(Patch *mesh) +{ + _mesh = mesh; + _mesh->initInvCond(); + updateMinMax(); + FuncType::initialize(_min, _max); +} + + +template<class FuncType> +bool ObjContribInvCond<FuncType>::addContrib(double &Obj, alglib::real_1d_array &gradObj) +{ + _min = BIGVAL; + _max = -BIGVAL; + + for (int iEl = 0; iEl < _mesh->nEl(); iEl++) { + std::vector<double> invCond(_mesh->nBezEl(iEl)); // Min. of Metric + std::vector<double> gInvCond(_mesh->nBezEl(iEl)*_mesh->nPCEl(iEl)); // Dummy gradients of metric min. + _mesh->invCondAndGradients(iEl, invCond, gInvCond); + for (int l = 0; l < _mesh->nBezEl(iEl); l++) { // Add contribution for each Bezier coeff. + Obj += _weight * FuncType::compute(invCond[l]); + const double dfact = _weight * FuncType::computeDiff(invCond[l]); + for (int iPC = 0; iPC < _mesh->nPCEl(iEl); iPC++) + gradObj[_mesh->indPCEl(iEl,iPC)] += dfact * gInvCond[_mesh->indGSJ(iEl, l, iPC)]; + _min = std::min(_min, invCond[l]); + _max = std::max(_max, invCond[l]); + } + } + + return true; +} + + +template<class FuncType> +void ObjContribInvCond<FuncType>::updateMinMax() +{ + _min = BIGVAL; + _max = -BIGVAL; + + for (int iEl = 0; iEl < _mesh->nEl(); iEl++) { + std::vector<double> invCond(_mesh->nBezEl(iEl)); // Min. of Metric + std::vector<double> dumGInvCond(_mesh->nBezEl(iEl)*_mesh->nPCEl(iEl)); // Dummy gradients of metric min. + _mesh->invCondAndGradients(iEl, invCond, dumGInvCond); + for (int l = 0; l < _mesh->nBezEl(iEl); l++) { // Add contribution for each Bezier coeff. + _min = std::min(_min, invCond[l]); + _max = std::max(_max, invCond[l]); + } + } +} + + +#endif /* _MESHQUALITYOBJCONTRIBINVCOND_H_ */ diff --git a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp index a50d9eed61b1dd925e5246a4da63679b9b8e3805..c50d513767ae7ea9c2726e4501a221036e21a95f 100644 --- a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp +++ b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp @@ -11,6 +11,7 @@ #include "MeshOptObjContrib.h" #include "MeshOptObjContribScaledNodeDispSq.h" #include "MeshQualityObjContribNCJ.h" +#include "MeshQualityObjContribInvCond.h" #include "MeshOptimizer.h" #include "MeshQualityOptimizer.h" @@ -22,15 +23,17 @@ struct QualPatchDefParameters : public MeshOptParameters::PatchDefParameters virtual double elBadness(MElement *el); virtual double maxDistance(MElement *el); private: - double NCJMin, NCJMax; +// double NCJMin, NCJMax; + double invCondMin; double distanceFactor; }; QualPatchDefParameters::QualPatchDefParameters(const MeshQualOptParameters &p) { - NCJMin = p.minTargetNCJ; - NCJMax = (p.maxTargetNCJ > 0.) ? p.maxTargetNCJ : 1.e300; +// NCJMin = p.minTargetNCJ; +// NCJMax = (p.maxTargetNCJ > 0.) ? p.maxTargetNCJ : 1.e300; + invCondMin = p.minTargetInvCond; strategy = (p.strategy == 1) ? MeshOptParameters::STRAT_ONEBYONE : MeshOptParameters::STRAT_CONNECTED; minLayers = (p.dim == 3) ? 1 : 0; @@ -47,18 +50,25 @@ QualPatchDefParameters::QualPatchDefParameters(const MeshQualOptParameters &p) double QualPatchDefParameters::elBadness(MElement *el) { - double valMin, valMax; - switch(el->getType()) { // TODO: Complete with other types? - case TYPE_TRI: { - qmTriangle::NCJRange(static_cast<MTriangle*>(el), valMin, valMax); - break; - } - case TYPE_QUA: { - qmQuadrangle::NCJRange(static_cast<MQuadrangle*>(el), valMin, valMax); - break; - } - } - double badness = std::min(valMin-NCJMin, 0.) + std::min(NCJMin-valMax, 0.); +// double valMin, valMax; +// switch(el->getType()) { // TODO: Complete with other types? +// case TYPE_TRI: { +// qmTriangle::NCJRange(static_cast<MTriangle*>(el), valMin, valMax); +// break; +// } +// case TYPE_QUA: { +// qmQuadrangle::NCJRange(static_cast<MQuadrangle*>(el), valMin, valMax); +// break; +// } +// } + const JacobianBasis *jac = el->getJacobianFuncSpace(); + fullMatrix<double> nodesXYZ(el->getNumShapeFunctions(), 3); + el->getNodesCoord(nodesXYZ); + fullVector<double> invCond(jac->getNumJacNodes()); + jac->getInvCond(nodesXYZ, invCond); + const double valMin = *std::min_element(invCond.getDataPtr(), + invCond.getDataPtr()+jac->getNumJacNodes()); + double badness = std::min(valMin-invCondMin, 0.); return badness; } @@ -82,33 +92,38 @@ void MeshQualityOptimizer(GModel *gm, MeshQualOptParameters &p) par.verbose = 4; ObjContribScaledNodeDispSq<ObjContribFuncSimple> nodeDistFunc(p.weightFixed, p.weightFree); - ObjContribNCJ<ObjContribFuncBarrierMovMin> minNCJBarFunc(1.); - minNCJBarFunc.setTarget(p.minTargetNCJ, 1.); -// minNCJBarFunc.setTarget(p.minTargetNCJ, 0.866025404); - ObjContribNCJ<ObjContribFuncBarrierFixMinMovMax> minMaxNCJBarFunc(1.); - minMaxNCJBarFunc.setTarget(p.maxTargetNCJ, 1.); +// ObjContribNCJ<ObjContribFuncBarrierMovMin> minNCJBarFunc(1.); +// minNCJBarFunc.setTarget(p.minTargetNCJ, 1.); +//// minNCJBarFunc.setTarget(p.minTargetNCJ, 0.866025404); +// ObjContribNCJ<ObjContribFuncBarrierFixMinMovMax> minMaxNCJBarFunc(1.); +// minMaxNCJBarFunc.setTarget(p.maxTargetNCJ, 1.); + ObjContribInvCond<ObjContribFuncBarrierMovMin> minInvCondBarFunc(1.); + minInvCondBarFunc.setTarget(p.minTargetInvCond, 1.); MeshOptParameters::PassParameters minJacPass; minJacPass.barrierIterMax = p.optPassMax; minJacPass.optIterMax = p.itMax; minJacPass.contrib.push_back(&nodeDistFunc); - minJacPass.contrib.push_back(&minNCJBarFunc); +// minJacPass.contrib.push_back(&minNCJBarFunc); + minJacPass.contrib.push_back(&minInvCondBarFunc); par.pass.push_back(minJacPass); - if (p.maxTargetNCJ > 0.) { - MeshOptParameters::PassParameters minMaxJacPass; - minMaxJacPass.barrierIterMax = p.optPassMax; - minMaxJacPass.optIterMax = p.itMax; - minMaxJacPass.contrib.push_back(&nodeDistFunc); - minMaxJacPass.contrib.push_back(&minMaxNCJBarFunc); - par.pass.push_back(minMaxJacPass); - } +// if (p.maxTargetNCJ > 0.) { +// MeshOptParameters::PassParameters minMaxJacPass; +// minMaxJacPass.barrierIterMax = p.optPassMax; +// minMaxJacPass.optIterMax = p.itMax; +// minMaxJacPass.contrib.push_back(&nodeDistFunc); +// minMaxJacPass.contrib.push_back(&minMaxNCJBarFunc); +// par.pass.push_back(minMaxJacPass); +// } meshOptimizer(gm, par); p.CPU = par.CPU; - p.minNCJ = minMaxNCJBarFunc.getMin(); - p.maxNCJ = minMaxNCJBarFunc.getMax(); +// p.minNCJ = minMaxNCJBarFunc.getMin(); +// p.maxNCJ = minMaxNCJBarFunc.getMax(); + p.minInvCond = minInvCondBarFunc.getMin(); + p.maxInvCond = minInvCondBarFunc.getMax(); Msg::StatusBar(true, "Done optimizing high order mesh (%g s)", p.CPU); } diff --git a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h index 287b3a418559943d25e7099178616392a1877d39..d34d1083d33b01a16617e1d57d5402a836d6c753 100644 --- a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h +++ b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h @@ -33,7 +33,8 @@ class GModel; struct MeshQualOptParameters { - double minTargetNCJ, maxTargetNCJ; +// double minTargetNCJ, maxTargetNCJ; + double minTargetInvCond; double weightFixed ; // weight of the energy for fixed nodes double weightFree ; // weight of the energy for free nodes int nbLayers ; // number of layers taken around a bad element @@ -51,11 +52,13 @@ struct MeshQualOptParameters { double adaptBlobDistFact; // Growth factor in distance factor for blob adaptation int SUCCESS ; // 0 --> success , 1 --> Not converged - double minNCJ, maxNCJ; // after optimization, range of jacobians +// double minNCJ, maxNCJ; // after optimization, range of jacobians + double minInvCond, maxInvCond; // after optimization, range of jacobians double CPU; // Time for optimization MeshQualOptParameters () - : minTargetNCJ(0.5), maxTargetNCJ(1.5), weightFixed(1000.), +// : minTargetNCJ(0.5), maxTargetNCJ(1.5), weightFixed(1000.), + : minTargetInvCond(0.5), weightFixed(1000.), weightFree (1.), nbLayers (6) , dim(3) , itMax(300), optPassMax(50), onlyVisible(true), distanceFactor(12), fixBndNodes(false), strategy(0), maxAdaptBlob(3), adaptBlobLayerFact(2.), adaptBlobDistFact(2.)