From 8ed03598b4b54d9b6bb20629c1f0c2b3dd4f0dab Mon Sep 17 00:00:00 2001 From: Amaury Johnan <amjohnen@gmail.com> Date: Wed, 22 Jun 2016 09:06:51 +0000 Subject: [PATCH] (1) improved stats for analyseCurvedMesh plugin. (2) add function that sample quality measures for testing --- Mesh/qualityMeasuresJacobian.cpp | 123 ++++++++++++++++++++++++++ Mesh/qualityMeasuresJacobian.h | 5 ++ Plugin/AnalyseCurvedMesh.cpp | 143 ++++++++++++++++++++----------- 3 files changed, 223 insertions(+), 48 deletions(-) diff --git a/Mesh/qualityMeasuresJacobian.cpp b/Mesh/qualityMeasuresJacobian.cpp index d9c8f500c7..48ed8d53fb 100644 --- a/Mesh/qualityMeasuresJacobian.cpp +++ b/Mesh/qualityMeasuresJacobian.cpp @@ -391,6 +391,129 @@ double minIsotropyMeasure(MElement *el, // return min; //} +double minSampledIsotropyMeasure(MElement *el, int deg, bool writeInFile)//fordebug +{ + fullMatrix<double> nodesXYZ(el->getNumVertices(), 3); + el->getNodesCoord(nodesXYZ); + + const JacobianBasis *jacBasis; + const GradientBasis *gradBasis; + + const int type = el->getType(); +// const int order = el->getPolynomialOrder(); +// const int jacOrder = order * el->getDim(); + const bool serendipFalse = false; + + FuncSpaceData jacMatSpace, jacDetSpace; + + switch(type) { + case TYPE_TRI: + case TYPE_TET: + case TYPE_QUA: + case TYPE_HEX: + case TYPE_PRI: + jacMatSpace = FuncSpaceData(el, deg, &serendipFalse); + jacDetSpace = FuncSpaceData(el, deg, &serendipFalse); + break; + case TYPE_PYR: +// jacMatSpace = FuncSpaceData(el, false, order, order-1, &serendipFalse); +// jacDetSpace = FuncSpaceData(el, false, jacOrder, jacOrder-3, &serendipFalse); + break; + default: + Msg::Error("Isotropy not implemented for type of element %d", el->getType()); + return -1; + } + gradBasis = BasisFactory::getGradientBasis(jacMatSpace); + jacBasis = BasisFactory::getJacobianBasis(jacDetSpace); + + fullVector<double> coeffDetLag(jacBasis->getNumJacNodes()); + jacBasis->getSignedIdealJacobian(nodesXYZ, coeffDetLag); + + fullMatrix<double> coeffMatLag(gradBasis->getNumSamplingPoints(), 9); + gradBasis->getAllIdealGradientsFromNodes(nodesXYZ, coeffMatLag); + + double min = std::numeric_limits<double>::infinity(); + for (int i = 0; i < coeffDetLag.size(); ++i) { + double frobNorm = 0; + if (el->getDim() == 2) { + for (int k = 0; k < 6; ++k) + frobNorm += coeffMatLag(i, k) * coeffMatLag(i, k); + min = std::min(min, 2*coeffDetLag(i)/frobNorm); + } + else if (el->getDim() == 3) { + for (int k = 0; k < 9; ++k) + frobNorm += coeffMatLag(i, k) * coeffMatLag(i, k); + min = std::min(min, 3*std::pow(coeffDetLag(i), 2/3.)/frobNorm); + } + } + + return min; +} + +double minSampledScaledJacobian(MElement *el, int deg, bool writeInFile)//fordebug +{ + fullMatrix<double> nodesXYZ(el->getNumVertices(), 3); + el->getNodesCoord(nodesXYZ); + + const JacobianBasis *jacBasis; + const GradientBasis *gradBasis; + + const int type = el->getType(); +// const int order = el->getPolynomialOrder(); +// const int jacOrder = order * el->getDim(); + const bool serendipFalse = false; + + FuncSpaceData jacMatSpace, jacDetSpace; + + switch(type) { + case TYPE_TRI: + case TYPE_TET: + case TYPE_QUA: + case TYPE_HEX: + case TYPE_PRI: + jacMatSpace = FuncSpaceData(el, deg, &serendipFalse); + jacDetSpace = FuncSpaceData(el, deg, &serendipFalse); + break; + case TYPE_PYR: +// jacMatSpace = FuncSpaceData(el, false, order, order-1, &serendipFalse); +// jacDetSpace = FuncSpaceData(el, false, jacOrder, jacOrder-3, &serendipFalse); + break; + default: + Msg::Error("Isotropy not implemented for type of element %d", el->getType()); + return -1; + } + gradBasis = BasisFactory::getGradientBasis(jacMatSpace); + jacBasis = BasisFactory::getJacobianBasis(jacDetSpace); + + fullVector<double> coeffDetLag(jacBasis->getNumJacNodes()); + jacBasis->getSignedIdealJacobian(nodesXYZ, coeffDetLag); + + fullMatrix<double> coeffMatLag(gradBasis->getNumSamplingPoints(), 9); + gradBasis->getAllIdealGradientsFromNodes(nodesXYZ, coeffMatLag); + + double min = std::numeric_limits<double>::infinity(); + for (int i = 0; i < coeffDetLag.size(); ++i) { + if (el->getDim() == 2) { + double v[2] = {0, 0}; + for (int k = 0; k < 2; ++k) { + for (int l = k*3; l < k*3+3; ++l) + v[k] += coeffMatLag(i, l) * coeffMatLag(i, l); + } + min = std::min(min, coeffDetLag(i)/v[0]/v[1]); + } + else if (el->getDim() == 3) { + double v[3] = {0, 0, 0}; + for (int k = 0; k < 3; ++k) { + for (int l = k*3; l < k*3+3; ++l) + v[k] += coeffMatLag(i, l) * coeffMatLag(i, l); + } + min = std::min(min, coeffDetLag(i)/std::sqrt(v[0]*v[1]*v[2])); + } + } + + return min; +} + // Virtual class _CoeffData bool _lessMinB::operator()(_CoeffData *cd1, _CoeffData *cd2) const { diff --git a/Mesh/qualityMeasuresJacobian.h b/Mesh/qualityMeasuresJacobian.h index 5c4921c60a..dbf4eae0bf 100644 --- a/Mesh/qualityMeasuresJacobian.h +++ b/Mesh/qualityMeasuresJacobian.h @@ -28,6 +28,10 @@ double minIsotropyMeasure(MElement *el, bool reversedOk = false); //double minSampledAnisotropyMeasure(MElement *el, int order,//fordebug // bool writeInFile = false); +double minSampledIsotropyMeasure(MElement *el, int order,//fordebug + bool writeInFile = false); +double minSampledScaledJacobian(MElement *el, int order,//fordebug + bool writeInFile = false); class _CoeffData { @@ -45,6 +49,7 @@ public: inline double maxL() const {return _maxL;} inline double minB() const {return _minB;} inline double maxB() const {return _maxB;} + inline int depth() const {return _depth;} virtual bool boundsOk(double minL, double maxL) const = 0; virtual void getSubCoeff(std::vector<_CoeffData*>&) const = 0; diff --git a/Plugin/AnalyseCurvedMesh.cpp b/Plugin/AnalyseCurvedMesh.cpp index f4aa42dc40..49771e7dd4 100644 --- a/Plugin/AnalyseCurvedMesh.cpp +++ b/Plugin/AnalyseCurvedMesh.cpp @@ -27,7 +27,7 @@ StringXNumber CurvedMeshOptions_Number[] = { {GMSH_FULLRC, "Jacobian determinant", NULL, 1}, {GMSH_FULLRC, "Scaled Jacobian", NULL, 0}, {GMSH_FULLRC, "Isotropy", NULL, 1}, - {GMSH_FULLRC, "Hidding threshold", NULL, 10}, + {GMSH_FULLRC, "Hidding threshold", NULL, 9}, {GMSH_FULLRC, "Draw PView", NULL, 0}, {GMSH_FULLRC, "Recompute", NULL, 0}, {GMSH_FULLRC, "Dimension of elements", NULL, -1} @@ -133,21 +133,24 @@ PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v) double time = Cpu(); Msg::StatusBar(true, "Computing Jacobian for %dD elements...", dim); _computeMinMaxJandValidity(dim); - Msg::StatusBar(true, "Done in %g seconds", Cpu()-time); + Msg::StatusBar(true, "Done computing Jacobian for %dD elements (%g s)", + dim, Cpu()-time); printStatJ = true; } if (computeScaledJac && !_computedS[dim-1]) { double time = Cpu(); Msg::StatusBar(true, "Computing scaled Jacobian for %dD elements...", dim); _computeMinScaledJac(dim); - Msg::StatusBar(true, "Done in %g seconds", Cpu()-time); + Msg::StatusBar(true, "Done computing scaled Jacobian for %dD elements (%g s)", + dim, Cpu()-time); printStatS = true; } if (computeIsotropy && !_computedI[dim-1]) { double time = Cpu(); Msg::StatusBar(true, "Computing isotropy for %dD elements...", dim); _computeMinIsotropy(dim); - Msg::StatusBar(true, "Done in %g seconds", Cpu()-time); + Msg::StatusBar(true, "Done computing isotropy for %dD elements (%g s)", + dim, Cpu()-time); printStatI = true; } } @@ -222,47 +225,79 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(int dim) { if (_computedJ[dim-1]) return; + std::set<GEntity*, GEntityLessThan> entities; switch (dim) { - case 3 : - for (GModel::riter it = _m->firstRegion(); it != _m->lastRegion(); it++) { - GRegion *r = *it; - unsigned int numType[6] = {0, 0, 0, 0, 0, 0}; - r->getNumMeshElements(numType); - - for(int type = 0; type < 5; type++) { - MElement *const *el = r->getStartElementType(type); - _computeMinMaxJandValidity(el, numType[type]); - } - } + case 3: + for (GModel::riter it = _m->firstRegion(); it != _m->lastRegion(); it++) + entities.insert(*it); break; - - case 2 : - for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++) { - GFace *f = *it; - unsigned int numType[3] = {0, 0, 0}; - f->getNumMeshElements(numType); - - for (int type = 0; type < 3; type++) { - MElement *const *el = f->getStartElementType(type); - _computeMinMaxJandValidity(el, numType[type]); - } - } + case 2: + for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++) + entities.insert(*it); break; - - case 1 : - for (GModel::eiter it = _m->firstEdge(); it != _m->lastEdge(); it++) { - GEdge *e = *it; - unsigned int numElement = e->getNumMeshElements(); - MElement *const *el = e->getStartElementType(0); - _computeMinMaxJandValidity(el, numElement); - } + case 1: + for (GModel::eiter it = _m->firstEdge(); it != _m->lastEdge(); it++) + entities.insert(*it); break; - - default : + default: Msg::Fatal("This should not happen."); return; } + std::set<GEntity*, GEntityLessThan>::iterator it; + for (it = entities.begin(); it != entities.end(); ++it) { + GEntity *entity = *it; + unsigned num = entity->getNumMeshElements(); + switch (dim) { + case 3: + Msg::StatusBar(true, "Volume %d: checking the Jacobian of %d elements", + entity->tag(), num); + break; + case 2: + Msg::StatusBar(true, "Surface %d: checking the Jacobian of %d elements", + entity->tag(), num); + break; + case 1: + Msg::StatusBar(true, "Line %d: checking the Jacobian of %d elements", + entity->tag(), num); + break; + default: break; + } + + double initial, time = initial = Cpu(); + unsigned int percentage = 0, nextCheck = 0; + + for (unsigned i = 0; i < num; ++i) { + MElement *el = entity->getMeshElement(i); + double min, max; + jacobianBasedQuality::minMaxJacobianDeterminant(el, min, max); + _data.push_back(data_elementMinMax(el, min, max)); + if (min < 0 && max < 0) { + Msg::Warning("Element %d is completely inverted", el->getNum()); + } + + if (i >= nextCheck) { + nextCheck += _data.size() / 100; + double curTime = Cpu(); + unsigned int curPercentage = i*100/_data.size(); + if ((curTime - time > 10. && curPercentage > percentage + 4) || + (curTime - time > 15. && curPercentage < 5)) { + percentage = curPercentage; + time = curTime; + const double remaining = (time-initial) / (i+1) * (_data.size() - i-1); + if (remaining < 60*2) + Msg::StatusBar(true, "%d%% (remaining time ~%g seconds)", + percentage, remaining); + else if (remaining < 60*60*2) + Msg::StatusBar(true, "%d%% (remaining time ~%g minutes)", + percentage, remaining/60); + else + Msg::StatusBar(true, "%d%% (remaining time ~%g hours)", + percentage, remaining/3600); + } + } + } + } _computedJ[dim-1] = true; } @@ -294,6 +329,12 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinScaledJac(int dim) else { _data[i].setMinS(jacobianBasedQuality::minScaledJacobian(el, true)); } +// Msg::Info("Scaled Jac"); +// Msg::Info("=========="); +// for (int k = 1; k < 30; ++k) { +// Msg::Info("%.10g", jacobianBasedQuality::minSampledScaledJacobian(el, k)); +// } +// Msg::Info(" "); if (i >= nextCheck) { nextCheck += _data.size() / 100; double curTime = Cpu(); @@ -335,6 +376,12 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinIsotropy(int dim) else { _data[i].setMinI(jacobianBasedQuality::minIsotropyMeasure(el, true)); } +// Msg::Info("Isotropy"); +// Msg::Info("========"); +// for (int k = 1; k < 30; ++k) { +// Msg::Info("%.10g", jacobianBasedQuality::minSampledIsotropyMeasure(el, k)); +// } +// Msg::Info(" "); if (i >= nextCheck) { nextCheck += _data.size() / 100; double curTime = Cpu(); @@ -362,7 +409,7 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinIsotropy(int dim) int GMSH_AnalyseCurvedMeshPlugin::_hideWithThreshold(int askedDim, int whichMeasure) { - // only hide for wuality measures + // only hide for quality measures if (_threshold > 1 || whichMeasure == 0) return 0; int nHidden = 0; @@ -429,12 +476,12 @@ void GMSH_AnalyseCurvedMeshPlugin::_printStatJacobian() avgratJ /= count; avgratJc /= countc; - Msg::Info("Jacobian determinant: in [%.3g, %.3g] (avg=%.3g)", - infminJ, supminJ, avgminJ); - Msg::Info("Ratio minJ/maxJ : in [%.3g, %.3g] (avg=%.3g)", - infratJ, supratJ, avgratJ); - if (countc < count) - Msg::Info(" (avg=%.3g" + Msg::Info("Min Jac. det. (minJ): %.3g, %.3g, %.3g (= min, avg, max)", + infminJ, avgminJ, supminJ); + Msg::Info("Ratio minJ/maxJ : %.3f, %.3f, %.3f (= worst, avg, best)", + infratJ, avgratJ, supratJ); + if (countc && countc < count) + Msg::Info(" (avg=%3.3g" " on the %d non-constant elements)", avgratJc, countc); } @@ -455,8 +502,8 @@ void GMSH_AnalyseCurvedMeshPlugin::_printStatScaledJac() } avgminS /= _data.size(); - Msg::Info("Scaled Jacobian : in [%.3g, %.3g] (avg=%.3g)", - infminS, supminS, avgminS); + Msg::Info("Scaled Jacobian : %.3f, %.3f, %.3f (= worst, avg, best)", + infminS, avgminS, supminS); } void GMSH_AnalyseCurvedMeshPlugin::_printStatIsotropy() @@ -475,8 +522,8 @@ void GMSH_AnalyseCurvedMeshPlugin::_printStatIsotropy() } avgminI /= _data.size(); - Msg::Info("Isotropy : in [%.3g, %.3g] (avg=%.3g)", - infminI, supminI, avgminI); + Msg::Info("Isotropy : %.3f, %.3f, %.3f (= worst, avg, best)", + infminI, avgminI, supminI); } // For testing -- GitLab