From ceb735850325eee8e471bd8dd5320ec1f3275ccd Mon Sep 17 00:00:00 2001 From: Amaury Johnan <amjohnen@gmail.com> Date: Fri, 28 Oct 2016 09:41:37 +0000 Subject: [PATCH] cleanup old class MetricBasis --- Numeric/MetricBasis.cpp | 2160 --------------------------------------- Numeric/MetricBasis.h | 200 ---- 2 files changed, 2360 deletions(-) delete mode 100644 Numeric/MetricBasis.cpp delete mode 100644 Numeric/MetricBasis.h diff --git a/Numeric/MetricBasis.cpp b/Numeric/MetricBasis.cpp deleted file mode 100644 index b13874765b..0000000000 --- a/Numeric/MetricBasis.cpp +++ /dev/null @@ -1,2160 +0,0 @@ -// Gmsh - Copyright (C) 1997-2016 C. Geuzaine, J.-F. Remacle -// -// See the LICENSE.txt file for license information. Please report all -// bugs and problems to the public mailing list <gmsh@onelab.info>. - -#include "MElement.h" -#include "AnalyseCurvedMesh.h" -#include "MetricBasis.h" -#include "bezierBasis.h" -#include "JacobianBasis.h" -#include "BasisFactory.h" -#include "pointsGenerators.h" -#include "MHexahedron.h" -#include "OS.h" -#include <queue> -#include <sstream> -#include <limits> -#include <iomanip> -#include <cmath> - -double MetricBasis::_tol = 1e-3; - -//TODO Renommer fonctions plus explicitement (minmaxA,...) et rendre statique certaines fonctions - -namespace { - /* - double cubicCardanoRoot(double p, double q) - { - // solve the equation t^3 + p*t + q = 0 - double A = q*q/4 + p*p*p/27; - if (A > 0) { - double sq = std::sqrt(A); - double t1 = -q/2+sq, t2 = -q/2-sq;; - - if (t1 < 0) - t1 = -std::pow(-t1, 1/3.); - else - t1 = std::pow(t1, 1/3.); - if (t2 < 0) - t2 = -std::pow(-t2, 1/3.); - else - t2 = std::pow(t2, 1/3.); - return t1 + t2; - } - else { - double module = std::sqrt(-p*p*p/27); - double ang = std::acos(-q/2/module); - return 2 * std::pow(module, 1/3.) * std::cos(ang/3); - } - } - */ - int nChoosek(int n, int k) - { - if (n < k || k < 0) { - Msg::Error("Wrong argument for combination. n %d k %d", n, k); - return 1; - } - - if (k > n/2) k = n-k; - if (k == 1) - return n; - if (k == 0) - return 1; - - int c = 1; - for (int i = 1; i <= k; i++, n--) (c *= n) /= i; - return c; - } - - double symRand(double f = 1) - { - return f * (rand()%2001 - 1000) / 1000.; - } -} - -MetricBasis::MetricBasis(int tag) : - _jacobian(NULL), _type(ElementType::ParentTypeFromTag(tag)), - _dim(ElementType::DimensionFromTag(tag)) -{ - //Msg::Fatal("Verifie si cette fonction est ok 1"); - const bool serendip = false; - const int metOrder = metricOrder(tag); - const int jacOrder = 3*metOrder/2; - - // get bezier and gradients for metric space - FuncSpaceData *metricSpace = NULL; - if (_type != TYPE_PYR) - metricSpace = new FuncSpaceData(true, tag, metOrder, &serendip); - else - metricSpace = new FuncSpaceData(true, tag, false, metOrder+2, - metOrder, &serendip); - _gradients = BasisFactory::getGradientBasis(*metricSpace); - _bezier = BasisFactory::getBezierBasis(*metricSpace); - delete metricSpace; - - // get jacobian - FuncSpaceData *jacSpace = NULL; - if (_type == TYPE_TET || _type == TYPE_HEX || _type == TYPE_PRI) { - jacSpace = new FuncSpaceData(true, tag, jacOrder, &serendip); - } - else if (_type == TYPE_PYR) { - // The square of the jacobian must be in the same space than the cube of - // the metric, so +3 - jacSpace = new FuncSpaceData(true, tag, false, jacOrder+3, - jacOrder, &serendip); - } - else if (_type == TYPE_TRI || _type == TYPE_QUA) { - // jacobian not needed - } - else - Msg::Fatal("metric not implemented for element tag %d", tag); - - if (jacSpace) { - _jacobian = BasisFactory::getJacobianBasis(*jacSpace); - delete jacSpace; - } - - _fillInequalities(metOrder); -} - -double MetricBasis::getMinR(MElement *el) -{ - /*static int a = 0; - if (++a == 1) { - double pinf = 1/.0; - double minf = -1/.0; - double mynan = .0/.0; - Msg::Info("pinf=%g minf=%g mynan=%g", pinf, minf, mynan); - Msg::Info(". == . => %d %d %d", pinf == pinf, minf == minf, mynan == mynan); - Msg::Info("./. => %g %g %g", pinf/pinf, minf/minf, mynan/mynan); - Msg::Info("1. < . => %d %d %d", 1. < pinf, 1. < minf, 1. < mynan); - Msg::Info("1. > . => %d %d %d", 1. > pinf, 1. > minf, 1. > mynan); - Msg::Info("max => %g %g %g", std::max(1., pinf), std::max(1., minf), std::max(1., mynan)); - Msg::Info("min => %g %g %g", std::min(1., pinf), std::min(1., minf), std::min(1., mynan)); - Msg::Info("inv => %g %g %g", 1./pinf, 1./minf, 1./mynan); - Msg::Info("pinf>. => %d %d %d", pinf > pinf, pinf > minf, pinf > mynan); - Msg::Info(" "); - double giant = std::numeric_limits<double>::max(); - double infinity = std::numeric_limits<double>::infinity(); - Msg::Info("giant=%g, giant*10=%g infinity=%g", giant, giant*10, infinity); - Msg::Info("a=pinf, (a - 1) / (a + 1) => %g/%g => %g", pinf - 1, pinf + 1, (pinf - 1) / (pinf + 1)); - Msg::Info("a=giant, (a - 1) / (a + 1) => %g/%g => %g", giant - 1, giant + 1, (giant - 1) / (giant + 1)); - Msg::Info("giant*10 == infinity => %d", giant*10 == std::numeric_limits<double>::infinity()); - Msg::Info("sqrt(pinf) => %g", std::sqrt(pinf)); - Msg::Info("!(mynan >= 1) => %d, (mynan < 1) => %d", !(mynan >= 1), mynan < 1); - }*/ - - MetricBasis *metric = (MetricBasis*)BasisFactory::getMetricBasis(el->getTypeForMSH()); - double m = metric->computeMinR(el); - //Msg::Info("returning %g", m); - return m; -} - -double MetricBasis::computeMinR(MElement *el) const -{ - int nSampPnts = _gradients->getNumSamplingPoints(); - int nMapping = _gradients->getNumMapNodes(); - - // Nodes - fullMatrix<double> nodes(nMapping, 3); - el->getNodesCoord(nodes); - - // Jacobian coefficients - fullVector<double> *jac = NULL; - if (_jacobian) { - fullVector<double> jacLag(_jacobian->getNumJacNodes()); - jac = new fullVector<double>(_jacobian->getNumJacNodes()); - _jacobian->getSignedIdealJacobian(nodes, jacLag); - _jacobian->lag2Bez(jacLag, *jac); - } - - // Metric coefficients - fullMatrix<double> metCoeffLag; - _fillCoeff<true>(el->getDim(), _gradients, nodes, metCoeffLag); - fullMatrix<double> *metCoeff; - metCoeff = new fullMatrix<double>(nSampPnts, metCoeffLag.size2()); - _bezier->matrixLag2Bez.mult(metCoeffLag, *metCoeff); - - /*static double inf = std::numeric_limits<double>::infinity(); - double minq = inf, maxq = -inf; - for (int k = 0; k < nSampPnts; ++k) { - minq = std::min(minq, (*metCoeff)(k, 0)); - maxq = std::max(maxq, (*metCoeff)(k, 0)); - } - double minp = 0, maxp = 0; - for (int i = 1; i < 7; ++i) { - double min = inf, max = -inf; - for (int k = 0; k < nSampPnts; ++k) { - min = std::min(min, (*metCoeff)(k, i)); - max = std::max(max, (*metCoeff)(k, i)); - } - if (min < 0 && max < 0) { - double tmp = min; - min = -max; - max = -tmp; - } - minp += min*min; - maxp += max*max; - } - minp = std::sqrt(minp); - maxp = std::sqrt(maxp); - double mina = minq/maxp; - double maxa = maxq/minp; - if (maxa-mina < _tol) { - return getMinSampledR(el, 0); - }*/ - - // Compute min(R, _tol) - double RminLag, RminBez; - //Msg::Info("element %d", el->getNum()); - _computeBoundsRmin(*metCoeff, *jac, RminLag, RminBez); - - //statsForMatlab(el, 20, NULL); - - //Msg::Info("%.10g %.10g", RminBez, RminLag); - - if (RminLag-RminBez < _tol) { - delete jac; - delete metCoeff; - return RminBez; - } - else { - //Msg::Info("Subdivision (%g vs %g)", RminLag, RminBez); - MetricData *md2 = new MetricData(metCoeff, jac, RminBez, 0, 0); - double minBez = _subdivideForRmin(md2, RminLag, _tol, el); - //Msg::Info("bez lag %.10g %.10g", minBez, RminLag); - return minBez; - } -} - -double MetricBasis::getMinSampledR(MElement *el, int order) -{ - MetricBasis *metric = (MetricBasis*)BasisFactory::getMetricBasis(el->getTypeForMSH()); - return metric->computeMinSampledR(el, order); -} - -double MetricBasis::computeMinSampledR(MElement *el, int deg) const -{ - //Msg::Fatal("Verifie si cette fonction est ok b"); - fullMatrix<double> samplingPoints; - bool serendip = false; - gmshGeneratePoints(FuncSpaceData(el, deg, &serendip), samplingPoints); - - MetricData *md; - _getMetricData(el, md); - - fullMatrix<double> R; - interpolate(el, md, samplingPoints, R); - - if (R.size1() < 1) { - delete md; - return -1; - } - - double min = R(0, 1); - for (int i = 1; i < R.size1(); ++i) - min = std::min(min, R(i, 1)); - - delete md; - return min; -} - -double MetricBasis::getMaxSampledR(MElement *el, int order) -{ - MetricBasis *metric = (MetricBasis*)BasisFactory::getMetricBasis(el->getTypeForMSH()); - return metric->computeMaxSampledR(el, order); -} - -double MetricBasis::computeMaxSampledR(MElement *el, int deg) const -{ - fullMatrix<double> samplingPoints; - bool serendip = false; - gmshGeneratePoints(FuncSpaceData(el, deg, &serendip), samplingPoints); - - MetricData *md; - _getMetricData(el, md); - - fullMatrix<double> R; - interpolate(el, md, samplingPoints, R); - - if (R.size1() < 1) { - delete md; - return -1; - } - - double max = R(0, 1); - for (int i = 1; i < R.size1(); ++i) - max = std::max(max, R(i, 1)); - - delete md; - return max; -} - -void MetricBasis::lag2Bez(const fullMatrix<double> &metCoeffLag, - fullMatrix<double> &metCoeffBez) const -{ - _bezier->matrixLag2Bez.mult(metCoeffLag, metCoeffBez); -} - -double MetricBasis::getMinSampledGlobalRatio(MElement *el, int order) -{ - MetricBasis *metric = (MetricBasis*)BasisFactory::getMetricBasis(el->getTypeForMSH()); - return metric->computeMinSampledGlobalRatio(el, order); -} - -double MetricBasis::computeMinSampledGlobalRatio(MElement *el, int deg) const -{ - Msg::Fatal("Verifie si cette fonction est ok d"); - fullMatrix<double> samplingPoints; - bool serendip = false; - gmshGeneratePoints(FuncSpaceData(el, deg, &serendip), samplingPoints); - - MetricData *md; - _getMetricData(el, md); - - fullMatrix<double> R; - interpolate(el, md, samplingPoints, R); - - double min = R(0, 2); - double max = R(0, 3); - for (int i = 1; i < R.size1(); ++i) { - min = std::min(min, R(i, 2)); - max = std::max(max, R(i, 3)); - } - - //Msg::Info("%g %g", min, max); - - delete md; - return std::sqrt(min/max); -} - -double MetricBasis::getMinRCorner(MElement *el) -{ - Msg::Fatal("Verifie si cette fonction est ok e"); - int tag = el->getTypeForMSH(); - int order = 1; - if (el->getType() == TYPE_TRI || el->getType() == TYPE_TET) order = 0; - - const GradientBasis *gradients; - const JacobianBasis *jacobian; - if (el->getType() != TYPE_PYR) { - gradients = BasisFactory::getGradientBasis(tag, order); - jacobian = BasisFactory::getJacobianBasis(tag, order); - } - else { - const bool serendip = false; - FuncSpaceData fsd(true, tag, false, 1, 0, &serendip); - gradients = BasisFactory::getGradientBasis(fsd); - jacobian = BasisFactory::getJacobianBasis(fsd); - } - - int nSampPnts = jacobian->getNumJacNodes(); - if (el->getType() == TYPE_PYR) nSampPnts = 4; - int nMapping = gradients->getNumMapNodes(); - - // Nodes - fullMatrix<double> nodes(nMapping, 3); - el->getNodesCoord(nodes); - - // Jacobian coefficients - fullVector<double> jacLag(jacobian->getNumJacNodes()); - jacobian->getSignedJacobian(nodes, jacLag); - - // Metric coefficients - fullMatrix<double> metCoeffLag; - _fillCoeff<false>(el->getDim(), gradients, nodes, metCoeffLag); - - // Compute min_corner(R) - return _computeMinlagR(jacLag, metCoeffLag, nSampPnts); -} - -void MetricBasis::_fillInequalities(int metricOrder) -{ - //Msg::Fatal("Verifie si cette fonction est ok"); - if (_type == TYPE_PYR) { - _fillInequalitiesPyr(metricOrder); - return; - } - - fullMatrix<int> exp(_bezier->_exponents.size1(), _bezier->_exponents.size2()); - for (int i = 0; i < _bezier->_exponents.size1(); ++i) { - for (int j = 0; j < _bezier->_exponents.size2(); ++j) { - exp(i, j) = static_cast<int>(_bezier->_exponents(i, j) + .5); - } - } - - int ncoeff = _gradients->getNumSamplingPoints(); - int dimSimplex = _bezier->getDimSimplex(); - int dim = _bezier->getDim(); - - int countP3 = 0, countJ2 = 0, countA = 0; - for (int i = 0; i < ncoeff; i++) { - for (int j = i; j < ncoeff; j++) { - double num = 1, den = 1; - { - int compl1 = metricOrder; - int compl2 = metricOrder; - int compltot = 2*metricOrder; - for (int k = 0; k < dimSimplex; k++) { - num *= nChoosek(compl1, exp(i, k)) - * nChoosek(compl2, exp(j, k)); - den *= nChoosek(compltot, exp(i, k) + exp(j, k)); - compl1 -= exp(i, k); - compl2 -= exp(j, k); - compltot -= exp(i, k) + exp(j, k); - } - for (int k = dimSimplex; k < dim; k++) { - num *= nChoosek(metricOrder, exp(i, k)) - * nChoosek(metricOrder, exp(j, k)); - den *= nChoosek(2*metricOrder, exp(i, k) + exp(j, k)); - } - } - - if (i != j) num *= 2; - - ++countA; - int hash = 0; - for (int l = 0; l < dim; l++) { - hash += (exp(i, l)+exp(j, l)) * pow_int(2*metricOrder+1, l); - } - _ineqA[hash].push_back(IneqData(num/den, i, j)); - - for (int k = j; k < ncoeff; ++k) { - double num = 1, den = 1; - { - int compl1 = metricOrder; - int compl2 = metricOrder; - int compl3 = metricOrder; - int compltot = 3*metricOrder; - for (int l = 0; l < dimSimplex; l++) { - num *= nChoosek(compl1, exp(i, l)) - * nChoosek(compl2, exp(j, l)) - * nChoosek(compl3, exp(k, l)); - den *= nChoosek(compltot, exp(i, l) + exp(j, l) + exp(k, l)); - compl1 -= exp(i, l); - compl2 -= exp(j, l); - compl3 -= exp(k, l); - compltot -= exp(i, l) + exp(j, l) + exp(k, l); - } - for (int l = dimSimplex; l < dim; l++) { - num *= nChoosek(metricOrder, exp(i, l)) - * nChoosek(metricOrder, exp(j, l)) - * nChoosek(metricOrder, exp(k, l)); - den *= nChoosek(3*metricOrder, exp(i, l) + exp(j, l) + exp(k, l)); - } - } - - if (i == j) { - if (j != k) num *= 3; - } - else { - if (j == k || i == k) { - num *= 3; - } - else num *= 6; - } - - ++countP3; - int hash = 0; - for (int l = 0; l < dim; l++) { - hash += (exp(i, l)+exp(j, l)+exp(k, l)) * pow_int(3*metricOrder+1, l); - } - _ineqP3[hash].push_back(IneqData(num/den, i, j, k)); - } - } - } - - if (_dim == 2) { - _lightenInequalities(countJ2, countP3, countA); - return; - } - - exp.resize(_jacobian->getBezier()->_exponents.size1(), - _jacobian->getBezier()->_exponents.size2()); - for (int i = 0; i < _jacobian->getBezier()->_exponents.size1(); ++i) { - for (int j = 0; j < _jacobian->getBezier()->_exponents.size2(); ++j) { - exp(i, j) = static_cast<int>(_jacobian->getBezier()->_exponents(i, j) + .5); - } - } - int njac = _jacobian->getNumJacNodes(); - for (int i = 0; i < njac; i++) { - for (int j = i; j < njac; j++) { - int order = metricOrder/2*3; - double num = 1, den = 1; - { - int compl1 = order; - int compl2 = order; - int compltot = 2*order; - for (int k = 0; k < dimSimplex; k++) { - num *= nChoosek(compl1, exp(i, k)) - * nChoosek(compl2, exp(j, k)); - den *= nChoosek(compltot, exp(i, k) + exp(j, k)); - compl1 -= exp(i, k); - compl2 -= exp(j, k); - compltot -= exp(i, k) + exp(j, k); - } - } - for (int k = dimSimplex; k < dim; k++) { - num *= nChoosek(order, exp(i, k)) - * nChoosek(order, exp(j, k)); - den *= nChoosek(2*order, exp(i, k) + exp(j, k)); - } - - if (i != j) num *= 2; - - ++countJ2; - int hash = 0; - for (int k = 0; k < dim; k++) { - hash += (exp(i, k)+exp(j, k)) * pow_int(2*order+1, k); - } - _ineqJ2[hash].push_back(IneqData(num/den, i, j)); - } - } - - _lightenInequalities(countJ2, countP3, countA); -} - -void MetricBasis::_fillInequalitiesPyr(int metricOrder) -{ - //Msg::Fatal("Verifie si cette fonction est ok"); - fullMatrix<int> exp(_bezier->_exponents.size1(), _bezier->_exponents.size2()); - for (int i = 0; i < _bezier->_exponents.size1(); ++i) { - for (int j = 0; j < _bezier->_exponents.size2(); ++j) { - exp(i, j) = static_cast<int>(_bezier->_exponents(i, j) + .5); - } - } - - int ncoeff = _gradients->getNumSamplingPoints(); - - int countP3 = 0, countJ2 = 0, countA = 0; - for (int i = 0; i < ncoeff; i++) { - for (int j = i; j < ncoeff; j++) { - double num, den; - num = nChoosek(metricOrder+2, exp(i, 0)) - * nChoosek(metricOrder+2, exp(i, 1)) - * nChoosek(metricOrder , exp(i, 2)) - * nChoosek(metricOrder+2, exp(j, 0)) - * nChoosek(metricOrder+2, exp(j, 1)) - * nChoosek(metricOrder , exp(j, 2)); - den = nChoosek(2*metricOrder+4, exp(i, 0) + exp(j, 0)) - * nChoosek(2*metricOrder+4, exp(i, 1) + exp(j, 1)) - * nChoosek(2*metricOrder , exp(i, 2) + exp(j, 2)); - - if (i != j) num *= 2; - - ++countA; - int hash = 0; - for (int l = 0; l < 3; l++) { - hash += (exp(i, l)+exp(j, l)) * pow_int(2*metricOrder+1, l); - } - _ineqA[hash].push_back(IneqData(num/den, i, j)); - - - for (int k = j; k < ncoeff; ++k) { - double num, den; - num = nChoosek(metricOrder+2, exp(i, 0)) - * nChoosek(metricOrder+2, exp(i, 1)) - * nChoosek(metricOrder , exp(i, 2)) - * nChoosek(metricOrder+2, exp(j, 0)) - * nChoosek(metricOrder+2, exp(j, 1)) - * nChoosek(metricOrder , exp(j, 2)) - * nChoosek(metricOrder+2, exp(k, 0)) - * nChoosek(metricOrder+2, exp(k, 1)) - * nChoosek(metricOrder , exp(k, 2)); - den = nChoosek(3*metricOrder+6, exp(i, 0) + exp(j, 0) + exp(k, 0)) - * nChoosek(3*metricOrder+6, exp(i, 1) + exp(j, 1) + exp(k, 1)) - * nChoosek(3*metricOrder , exp(i, 2) + exp(j, 2) + exp(k, 2)); - - if (i == j) { - if (j != k) num *= 3; - } - else { - if (j == k || i == k) { - num *= 3; - } - else num *= 6; - } - - ++countP3; - int hash = 0; - for (int l = 0; l < 3; l++) { - hash += (exp(i, l)+exp(j, l)+exp(k, l)) * pow_int(3*metricOrder+1, l); - } - _ineqP3[hash].push_back(IneqData(num/den, i, j, k)); - } - } - } - - exp.resize(_jacobian->getBezier()->_exponents.size1(), - _jacobian->getBezier()->_exponents.size2()); - for (int i = 0; i < _jacobian->getBezier()->_exponents.size1(); ++i) { - for (int j = 0; j < _jacobian->getBezier()->_exponents.size2(); ++j) { - exp(i, j) = static_cast<int>(_jacobian->getBezier()->_exponents(i, j) + .5); - } - } - int njac = _jacobian->getNumJacNodes(); - for (int i = 0; i < njac; i++) { - for (int j = i; j < njac; j++) { - int order = metricOrder/2*3; - - double num, den; - num = nChoosek(order+3, exp(i, 0)) - * nChoosek(order+3, exp(i, 1)) - * nChoosek(order , exp(i, 2)) - * nChoosek(order+3, exp(j, 0)) - * nChoosek(order+3, exp(j, 1)) - * nChoosek(order , exp(j, 2)); - den = nChoosek(2*order+6, exp(i, 0) + exp(j, 0)) - * nChoosek(2*order+6, exp(i, 1) + exp(j, 1)) - * nChoosek(2*order , exp(i, 2) + exp(j, 2)); - - if (i != j) num *= 2; - - ++countJ2; - int hash = 0; - for (int k = 0; k < 3; k++) { - hash += (exp(i, k)+exp(j, k)) * pow_int(2*order+1, k); - } - _ineqJ2[hash].push_back(IneqData(num/den, i, j)); - } - } - - _lightenInequalities(countJ2, countP3, countA); -} - -void MetricBasis::_lightenInequalities(int &countj, int &countp, int &counta) -{ - //Msg::Fatal("Verifie si cette fonction est ok"); - double tol = .0; - std::map<int, std::vector<IneqData> >::iterator it, itbeg[3], itend[3]; - - int cnt[3] = {0,0,0}; - itbeg[0] = _ineqJ2.begin(); - itbeg[1] = _ineqP3.begin(); - itbeg[2] = _ineqA.begin(); - itend[0] = _ineqJ2.end(); - itend[1] = _ineqP3.end(); - itend[2] = _ineqA.end(); - for (int k = 0; k < 3; ++k) { - it = itbeg[k]; - while (it != itend[k]) { - std::sort(it->second.begin(), it->second.end(), gterIneq()); - - double rmved = .0; - while (it->second.size() && rmved + it->second.back().val <= tol) { - rmved += it->second.back().val; - it->second.pop_back(); - ++cnt[k]; - } - const double factor = 1-rmved; - for (unsigned int i = 0; i < it->second.size(); ++i) { - it->second[i].val /= factor; - } - ++it; - } - } - countj -= cnt[0]; - countp -= cnt[1]; - counta -= cnt[2]; -} - -bool MetricBasis::validateBezierForMetricAndJacobian() -{ - Msg::Fatal("Verifie si cette fonction est ok f"); - Msg::Info("Testing Bezier interpolation and subdivision " - "for jacobien and metric on all element types..."); - int numError = 0; - - // Parameters - const int numElem = 10000000; //////// - - MElement **elements; - elements = new MElement*[numElem]; - - for (int tag = 1; tag <= MSH_NUM_TYPE; ++tag) { - if (tag != 9) continue; //////// - const int numPrimNode = 3; //////// - - const int order = ElementType::OrderFromTag(tag); - const int dim = ElementType::DimensionFromTag(tag); - const int primTag = ElementType::getPrimaryTag(tag); - - Msg::Info("... testing element tag %d", tag); - - // Get reference nodes - const nodalBasis *mapBasis = BasisFactory::getNodalBasis(tag); - fullMatrix<double> nodes; - mapBasis->getReferenceNodes(nodes); - - // Create 'numElem' elements more and more randomized - for (int iel = 0; iel < numElem; ++iel) { - //const double range = static_cast<double>(iel) / (numElem-1) / order; - const double rangePrim = static_cast<double>(iel/2000) / ((numElem/2000)-1) / order; //////// - const double rangeSub = static_cast<double>(iel%2000) / 1999 / order; //////// - if (!(iel%200)) Msg::Info("%g %g", rangePrim, rangeSub); - std::vector<MVertex*> vertices(nodes.size1()); - for (int i = 0; i < numPrimNode; ++i) { - vertices[i] = new MVertex(nodes(i, 0) + symRand(rangePrim), - nodes(i, 1) + symRand(rangePrim), - nodes(i, 2) + symRand(rangePrim)); - } - MElement *primEl = MElement::createElement(primTag, vertices); - - for (int i = numPrimNode; i < nodes.size1(); ++i) { - SPoint3 p; - primEl->pnt(nodes(i, 0), nodes(i, 1), nodes(i, 2), p); - vertices[i] = new MVertex(p.x() + symRand(rangeSub), - p.y() + symRand(rangeSub), - p.z() + symRand(rangeSub)); - } - MElement *el = MElement::createElement(tag, vertices); - if (!el) { - Msg::Error("MElement was unable to create element for tag %d", tag); - ++numError; - } - - elements[iel] = el; - } -#if defined(HAVE_PLUGINS) - GMSH_AnalyseCurvedMeshPlugin plugin = GMSH_AnalyseCurvedMeshPlugin(); - plugin.test(elements, numElem, dim); -#endif - } - - - //================= - return true; //987; - //================= - - /*Msg::Info("Testing Bezier interpolation and subdivision " - "for jacobien and metric on all element types..."); - int numError = 0; - - // Parameters - const int numType = 6; - const int acceptedTypes[numType] = {TYPE_TRI, TYPE_QUA, TYPE_TET, - TYPE_PYR, TYPE_PRI, TYPE_HEX}; - const int maxOrder = 3; // at least 3 (so that serendip tet are tested) - const int numElem = 5; // at least 2 (first is reference element) - const int numSubdiv = 2; // at least 1 - const int numSampPnt = 10; // at least 1 - const double toleranceTensor = 1e-11; // at most 1e-5 (metric takes values in [0,1]) - double tolerance; // computed in function of tag - - // - static const double epsilon = std::numeric_limits<double>::epsilon(); - - for (int tag = 1; tag <= MSH_NUM_TYPE; ++tag) { - if (tag > 66 && tag < 71) continue; //not conventional elements - if (tag > 75 && tag < 79) continue; //no element tag 76, 77, 78... - - // Check if accepted type - const int type = ElementType::ParentTypeFromTag(tag); - bool knownType = false; - for (int i = 0; i < numType; ++i) { - knownType = (knownType || type == acceptedTypes[i]); - } - if (!knownType) continue; - - const int order = ElementType::OrderFromTag(tag); - const int dim = ElementType::DimensionFromTag(tag); - const bool serendip = ElementType::SerendipityFromTag(tag) > 1; - - // Skip p0 elements and elements for which order > 'maxOrder' - // and skip for now serendipty pyramids (not implemented) - if (order < 1 || order > maxOrder) continue; - if (type == TYPE_PYR && serendip) continue; - - Msg::Info("... testing element tag %d", tag); - - // Compute tolerance - tolerance = epsilon * pow_int(10, order*dim); - if (type == TYPE_PYR) tolerance = std::max(tolerance, epsilon*1e9); - - // Get reference nodes - const nodalBasis *mapBasis = BasisFactory::getNodalBasis(tag); - fullMatrix<double> nodes; - mapBasis->getReferenceNodes(nodes); - - // Create 'numElem' elements more and more randomized - for (int iel = 0; iel < numElem; ++iel) { - const double range = static_cast<double>(iel) / (numElem-1) / order; - std::vector<MVertex*> vertices(nodes.size1()); - for (int i = 0; i < nodes.size1(); ++i) { - vertices[i] = new MVertex(nodes(i, 0) + symRand(range), - dim > 1 ? nodes(i, 1) + symRand(range) : 0, - dim > 2 ? nodes(i, 2) + symRand(range) : 0); - } - MElement *el = MElement::createElement(tag, vertices); - if (!el) { - Msg::Error("MElement was unable to create element for tag %d", tag); - ++numError; - } - - numError += validateBezierForMetricAndJacobian(el, numSampPnt, numSubdiv, - toleranceTensor, tolerance); - } - } - - if (numError) Msg::Error("Validation of Bezier terminated with %d errors!", numError); - else Msg::Info("Validation of Bezier terminated without errors"); - return numError;*/ -} - -int MetricBasis::validateBezierForMetricAndJacobian(MElement *el, - int numSampPnt, - int numSubdiv, - double toleranceTensor, - double tolerance) -{ - Msg::Fatal("Verifie si cette fonction est ok g"); - const int tag = el->getTypeForMSH(); - const MetricBasis *metricBasis = BasisFactory::getMetricBasis(tag); - - // compare the two metric - fullMatrix<double> metric_Bez(numSampPnt, 2); - fullVector<int> isub(numSubdiv); - fullMatrix<double> uvw(numSampPnt, 3); - metricBasis->interpolateAfterNSubdivisions(el, numSubdiv, numSampPnt, - isub, uvw, metric_Bez); - - int numBadMatch = 0; - int numBadMatchTensor = 0; - double maxBadMatch = 0; - double maxBadMatchTensor = 0; - for (int isamp = 0; isamp < numSampPnt; ++isamp) { - double dum[3]; - double &u = uvw(isamp, 0); - double &v = uvw(isamp, 1); - double &w = uvw(isamp, 2); - double metric_Lag = el->getEigenvaluesMetric(u, v, w, dum); - - double diff = std::abs(metric_Lag - metric_Bez(isamp, 0)); - double diffTensor = std::abs(metric_Lag - metric_Bez(isamp, 1)); - - if (diffTensor > toleranceTensor) { - ++numBadMatchTensor; - maxBadMatchTensor = std::max(maxBadMatchTensor, diffTensor); - } - else if (diff > tolerance) { - ++numBadMatch; - maxBadMatch = std::max(maxBadMatch, diff); - } - } - - if (numBadMatchTensor > .2*numSampPnt) { - Msg::Error("Too much errors " - "even when computing by metric tensor (max %g)", maxBadMatchTensor); - return 1; - } - else if (numBadMatch > .5*numSampPnt) { - Msg::Error("Too much errors (max %g)", maxBadMatch); - return 1; - } - return 0; -} - -void MetricBasis::interpolate(const MElement *el, - const MetricData *md, - const fullMatrix<double> &nodes, - fullMatrix<double> &R) const -{ - //Msg::Fatal("Verifie si cette fonction est ok h"); - fullMatrix<double> &metcoeffs = *md->_metcoeffs, *metric = new fullMatrix<double>; - fullVector<double> &jaccoeffs = *md->_jaccoeffs, *jac = new fullVector<double>; - - _bezier->interpolate(metcoeffs, nodes, *metric); - - R.resize(nodes.size1(), 4); - - switch (metcoeffs.size2()) { - case 1: - for (int i = 0; i < R.size1(); ++i) - R(i, 0) = R(i, 1) = 1; - break; - - case 3: - ((MetricBasis*)this)->file << "q p myR eigR" << std::endl; - ((MetricBasis*)this)->file << _bezier->getNumLagCoeff() << std::endl; - for (int i = 0; i < R.size1(); ++i) { - // Compute from q, p - double p = pow((*metric)(i, 1), 2); - p += pow((*metric)(i, 2), 2); - p = std::sqrt(p); - R(i, 0) = std::sqrt(_R2Dsafe((*metric)(i, 0), p)); - // Comppute from tensor - fullMatrix<double> metricTensor(2, 2); - metricTensor(0, 0) = (*metric)(i, 0) + (*metric)(i, 1); - metricTensor(1, 1) = (*metric)(i, 0) - (*metric)(i, 1); - metricTensor(0, 1) = metricTensor(1, 0) = (*metric)(i, 2); - fullVector<double> valReal(2), valImag(2); - fullMatrix<double> vecLeft(2, 2), vecRight(2, 2); - metricTensor.eig(valReal, valImag, vecLeft, vecRight, true); - R(i, 1) = std::sqrt(valReal(0) / valReal(1)); - R(i, 2) = valReal(0); - R(i, 3) = valReal(1); - ((MetricBasis*)this)->file << (*metric)(i, 0) << " "; - ((MetricBasis*)this)->file << p << " "; - ((MetricBasis*)this)->file << R(i, 0) << " "; - ((MetricBasis*)this)->file << R(i, 1) << std::endl; - } - break; - - case 7: - ((MetricBasis*)this)->file << "a K myR eigR" << std::endl; - ((MetricBasis*)this)->file << _bezier->getNumLagCoeff() << std::endl; - _jacobian->getBezier()->interpolate(jaccoeffs, nodes, *jac); - for (int i = 0; i < R.size1(); ++i) { - // Compute from q, p, J - double p = 0; - for (int k = 1; k < 7; ++k) p += pow((*metric)(i, k), 2); - p = std::sqrt(p); - R(i, 0) = std::sqrt(_R3Dsafe((*metric)(i, 0), p, (*jac)(i))); - // Compute from tensor - fullMatrix<double> metricTensor(3, 3); - for (int k = 0; k < 3; ++k) { - static double fact1 = std::sqrt(6.); - static double fact2 = std::sqrt(3.); - const int ki = k%2; - const int kj = std::min(k+1, 2); - metricTensor(k, k) = (*metric)(i, k+1)*fact1 + (*metric)(i, 0); - metricTensor(ki, kj) = metricTensor(kj, ki) = (*metric)(i, k+4)*fact2; - } - fullVector<double> valReal(3), valImag(3); - fullMatrix<double> vecLeft(3, 3), vecRight(3, 3); - metricTensor.eig(valReal, valImag, vecLeft, vecRight, true); - R(i, 1) = std::sqrt(valReal(0) / valReal(2)); - R(i, 2) = valReal(0); - R(i, 3) = valReal(2); - ((MetricBasis*)this)->file << (*metric)(i, 0)/p << " "; - ((MetricBasis*)this)->file << (*jac)(i)*(*jac)(i)/p/p/p << " "; - ((MetricBasis*)this)->file << R(i, 0) << " "; - ((MetricBasis*)this)->file << R(i, 1) << std::endl; - } - break; - - default: - Msg::Error("Wrong number of functions for metric: %d", - metcoeffs.size2()); - } - - delete jac; - delete metric; -} - -void MetricBasis::interpolateAfterNSubdivisions( - const MElement *el, int numSubdiv, int numPnt, - fullVector<int> &isub, - fullMatrix<double> &uvw, - fullMatrix<double> &metric) const -{ - Msg::Fatal("Verifie si cette fonction est ok i"); - // Interpolate metric after 'numSub' random subdivision at - // 'numPnt' random points. - // Return: isub, the subdomain tag of each subdivision, - // uvw, the reference points at which metric has been interpolated. - // metric, the interpolation. - - MetricData *md; - _getMetricData(el, md); - - // Keep trace of subdomain to be able to compute uvw. - // (Ensure to have the tag for the complete element): - const nodalBasis *mapBasis = BasisFactory::getNodalBasis(el->getTypeForMSH()); - fullMatrix<double> nodes; - mapBasis->getReferenceNodesForBezier(nodes); - - const int nSub = _bezier->getNumDivision(); - const int numCoeff = md->_metcoeffs->size2(); - const int numMetPnts = md->_metcoeffs->size1(); - const int numJacPnts = md->haveJac() ? md->_jaccoeffs->size() : 0; - const int numNodPnts = nodes.size1(); - - const bezierBasis *bezierMapping; - if (el->getType() != TYPE_PYR) - bezierMapping = BasisFactory::getBezierBasis(el->getTypeForMSH()); - else { - FuncSpaceData data(true, el->getTypeForMSH(), false, - el->getPolynomialOrder(), el->getPolynomialOrder()); - bezierMapping = BasisFactory::getBezierBasis(data); - } - - for (int k = 0; k < numSubdiv; ++k) { - fullMatrix<double> subcoeffs, subnodes; - fullVector<double> subjac; - _bezier->subdivideBezCoeff(*md->_metcoeffs, subcoeffs); - bezierMapping->subdivideBezCoeff(nodes, subnodes); - - if (_dim == 3) - _jacobian->getBezier()->subdivideBezCoeff(*md->_jaccoeffs, subjac); - delete md; - - isub(k) = std::rand() % nSub; - - fullMatrix<double> *coeff = new fullMatrix<double>(numMetPnts, numCoeff); - coeff->copy(subcoeffs, isub(k) * numMetPnts, numMetPnts, 0, numCoeff, 0, 0); - nodes.copy(subnodes, isub(k) * numNodPnts, numNodPnts, 0, _dim, 0, 0); - fullVector<double> *jac = NULL; - if (_dim == 3) { - jac = new fullVector<double>(numJacPnts); - jac->copy(subjac, isub(k) * numJacPnts, numJacPnts, 0); - } - - md = new MetricData(coeff, jac); - } - - // compute a random convex combination of reference nodes - fullMatrix<double> subuvw(uvw.size1(), _dim); - { - int tagPrimary = ElementType::getTag(el->getType(), 1); - const nodalBasis *primMapBasis = BasisFactory::getNodalBasis(tagPrimary); - fullMatrix<double> refNodes; - primMapBasis->getReferenceNodes(refNodes); - double *c = new double[refNodes.size1()]; - - for (int k = 0; k < uvw.size1(); ++k) { - double sum = 0; - int exp = 1 + std::rand() % 5; - for (int i = 0; i < refNodes.size1(); ++i) { - c[i] = pow_int((std::rand() % 1000) / 1000., exp); - sum += c[i]; - } - for (int i = 0; i < refNodes.size1(); ++i) { - c[i] /= sum; - subuvw(k, 0) += c[i] * refNodes(i, 0); - if (_dim > 1) subuvw(k, 1) += c[i] * refNodes(i, 1); - if (_dim > 2) subuvw(k, 2) += c[i] * refNodes(i, 2); - } - } - - delete[] c; - } - - interpolate(el, md, subuvw, metric); - bezierMapping->interpolate(nodes, subuvw, uvw, false); - delete md; -} - -void MetricBasis::statsForMatlab(MElement *el, int deg, MetricData *md) const -{ - //return; - //Msg::Fatal("Verifie si cette fonction est ok h"); - fullMatrix<double> samplingPoints; - bool serendip = false; - gmshGeneratePoints(FuncSpaceData(el, deg, &serendip), samplingPoints); - - if (!md) _getMetricData(el, md); - - static unsigned int aa = 0; - if (md->_num < 100000 && ++aa < 1000) { - std::stringstream name; - name << "metricStat_" << el->getNum() << "_"; - name << (md->_num % 10); - name << (md->_num % 100)/10; - name << (md->_num % 1000)/100; - name << (md->_num % 10000)/1000; - name << (md->_num % 100000)/10000; - name << ".txt"; - ((MetricBasis*)this)->file.open(name.str().c_str(), std::fstream::out); - - { - ((MetricBasis*)this)->file << "mina minKfast minKsharp cmin beta_m beta_M beta c_m" << std::endl; - double mina, maxa, minKs, minKf, c, beta_m, beta_M, beta, c_m; - - fullMatrix<double> *coeff = md->_metcoeffs; - fullVector<double> *jac = md->_jaccoeffs; - _minMaxA(*coeff, mina, maxa); - - if (el->getDim() == 3) { - _minKfast(*coeff, *jac, minKf); - _minKsharp(*coeff, *jac, minKs); - double minK = minKf; - _moveInsideDomain(mina, minK, true); - double p_dRda, p_dRdK; - _computePseudoDerivatives(mina, minK, p_dRda, p_dRdK); - double slope = -p_dRda/p_dRdK; - c = .5*(3*minK/mina - slope); - _computeBoundingCurve(*coeff, *jac, beta_m, c, true); - _computeBoundingCurve(*coeff, *jac, beta_M, c, false); - beta = -p_dRda/(p_dRdK*3*mina*mina); - if (beta < 0) - _computeLowerBoundC(*coeff, *jac, beta, c_m); - else - c_m = -1; - } - else { - minKs = minKf = c = beta_m = beta_M = beta = c_m = -1; - } - - ((MetricBasis*)this)->file << std::setprecision(15); - ((MetricBasis*)this)->file << mina << " " << minKf << " " << minKs << " "; - ((MetricBasis*)this)->file << c << " " << beta_m << " " << beta_M << " "; - ((MetricBasis*)this)->file << beta << " " << c_m << std::endl; - ((MetricBasis*)this)->file << std::setprecision(8); - } - } - - fullMatrix<double> R; - interpolate(el, md, samplingPoints, R); - ((MetricBasis*)this)->file.close(); - - return; - - if (R.size1() < 1) { - ((MetricBasis*)this)->file << -1 << " "; - ((MetricBasis*)this)->file.close(); - return; - } - - double min = R(0, 1); - for (int i = 1; i < R.size1(); ++i) - min = std::min(min, R(i, 1)); - - //((MetricBasis*)this)->file << min << " "; - ((MetricBasis*)this)->file.close(); - return; -} - -int MetricBasis::metricOrder(int tag) -{ - const int parentType = ElementType::ParentTypeFromTag(tag); - const int order = ElementType::OrderFromTag(tag); - - switch (parentType) { - case TYPE_PNT : return 0; - - case TYPE_LIN : return order; - - case TYPE_TRI : - case TYPE_TET : - case TYPE_PYR : return 2*order-2; - - case TYPE_QUA : - case TYPE_PRI : - case TYPE_HEX : return 2*order; - - default : - Msg::Error("Unknown element type %d, return order 0", parentType); - return 0; - } -} - -void MetricBasis::_computeBoundsRmin( - const fullMatrix<double> &coeff, const fullVector<double> &jac, - double &sqrtRminLag, double &sqrtRminBez) const -{ - sqrtRminLag = _computeMinlagR(jac, coeff, _bezier->getNumLagCoeff()); - if (sqrtRminLag <= _tol) { - sqrtRminBez = .0; - return; - } - - if (coeff.size2() == 3) { // 2d element - double mina, dummy; - _minMaxA(coeff, mina, dummy); - sqrtRminBez = std::sqrt(_R2Dsafe(mina)); - return; - } - - double minK, mina, dummy; - _minKfast(coeff, jac, minK); - _minMaxA(coeff, mina, dummy); - - _moveInsideDomain(mina, minK, true); - - double p_dRda, p_dRdK; - _computePseudoDerivatives(mina, minK, p_dRda, p_dRdK); - - if (p_dRda < 0) { - //Msg::Info("case 1 & 2"); - // cases 1 & 2 => compute a lower bounding curve K = beta * a^3 + c * a - // with c such that the curve that pass through (minK, mina) has the - // slope equal to -dRda/dRdK - double slope = -p_dRda/p_dRdK; - double c = .5*(3*minK/mina - slope); - double beta; - _computeBoundingCurve(coeff, jac, beta, c, true); - { - double beta = (minK/mina-c)/mina/mina; - if (std::abs(p_dRda + p_dRdK * (3*beta*mina*mina+c)) > 1e-12) { - Msg::Error("Derivative along curve not zero %g", p_dRda + p_dRdK * (3*beta*mina*mina+c)); - } - } - - double a_int = mina, K_int = minK; - bool onVertical = _intersectionCurveLeftCorner(beta, c, a_int, K_int); - if (onVertical) { - // then the minimum is on the curve, we prefer to return this - sqrtRminBez = std::sqrt(_R3Dsafe(mina, minK)); - //Msg::Info("onvertical"); - return; - } - /*if (a_int - mina < ???) { - sqrtRminBez = std::sqrt(_R3Dsafe(a_int, minK)); - return; - }*/ - - bool haveToCompute_a0; - if (_moveInsideDomain(a_int, K_int, true)) { - haveToCompute_a0 = true; - } - else { - double p_dRda, p_dRdK; - _computePseudoDerivatives(a_int, K_int, p_dRda, p_dRdK); - if (p_dRda + p_dRdK * (3*beta*a_int*a_int+c) < -1e-5) { - Msg::Error("Derivative along curve not positive or zero %g", p_dRda + p_dRdK * (3*beta*a_int*a_int+c)); - Msg::Info("(%g, %g) vs (%g, %g), diff (%g, %g)", mina, minK, a_int, K_int, a_int-mina, K_int-minK); - double beta2 = (minK/mina-c)/mina/mina; - Msg::Info("beta %g - %g = %g", beta, beta2, beta-beta2); - } - haveToCompute_a0 = p_dRda > 0; - } - - if (haveToCompute_a0) { - double a0 = _computeAbscissaMinR(mina, minK); - sqrtRminBez = std::sqrt(_R3Dsafe(a0, minK)); - } - else { - sqrtRminBez = std::sqrt(_R3Dsafe(a_int, K_int)); - } - return; - } - else if (p_dRdK < 0) { - //Msg::Info("case 4 & 5"); - double slope = -p_dRda/p_dRdK; - double c = .5*(3*minK/mina - slope); - double beta; - _computeBoundingCurve(coeff, jac, beta, c, false); - double a_int = mina, K_int = minK; - - if (_intersectionCurveLeftCorner(beta, c, a_int, K_int)) { - /*if (std::abs(a_int - mina) < _tol / 100 && - std::abs(K_int - minK) < _tol / 100) { - sqrtRminBez = std::sqrt(_R3Dsafe(mina, minK)); - return; - }*/ - // We compute K0 and return _R3Dsafe(mina, min(K0,K_int)) - double K0 = 2*std::cos(3*std::acos(-1/mina)-M_PI) + (mina*mina-3) * mina; - sqrtRminBez = std::sqrt(_R3Dsafe(mina, std::min(K0, K_int))); - } - else { - if (_moveInsideDomain(a_int, K_int, false)) - sqrtRminBez = std::sqrt(_R3Dsafe(a_int, K_int)); - else - sqrtRminBez = std::sqrt(_computeMinRAlongCurve(beta, c, a_int, -1)); - } - return; - } - else { - //Msg::Info("case 3"); - sqrtRminBez = std::sqrt(_R3Dsafe(mina, minK)); - return; - } -} - -void MetricBasis::_computeBoundsRmax( - const fullMatrix<double> &coeff, const fullVector<double> &jac, - double &RmaxLag) const -{ - Msg::Fatal("Verifie si cette fonction est ok k"); - RmaxLag = 0.; - - for (int i = 0; i < _bezier->getNumLagCoeff(); ++i) { - double q = coeff(i, 0); - double p = 0; - for (int k = 1; k < 7; ++k) { - p += pow_int(coeff(i, k), 2); - } - p = std::sqrt(p); - const double a = q/p; - if (a > 1e4) { - RmaxLag = std::max(RmaxLag, std::sqrt((a - std::sqrt(3.)) / (a + std::sqrt(3.)))); - } - else { - const double tmpR = _R3Dsafe(a, jac(i)/p/p*jac(i)/p); - RmaxLag = std::max(RmaxLag, std::sqrt(tmpR)); - } - } -} - -double MetricBasis::_subdivideForRmin(MetricData *md, double &RminLag, double tol, MElement *el) const -{ - //Msg::Fatal("Verifie si cette fonction est ok l"); - std::priority_queue<MetricData*, std::vector<MetricData*>, lessMinB> subdomains; - const bool for3d = md->_jaccoeffs; - const int numCoeff = md->_metcoeffs->size2(); - const int numMetPnts = md->_metcoeffs->size1(); - const int numJacPnts = for3d ? md->_jaccoeffs->size() : 0; - const int numSub = _bezier->getNumDivision(); - subdomains.push(md); - - std::vector<fullVector<double>*> trash; - - int k = 0; - while (RminLag - subdomains.top()->_RminBez > tol && subdomains.size() < 25000) { - fullMatrix<double> *subcoeffs, *coeff; - fullVector<double> *subjac, *jac = NULL; - - MetricData *current = subdomains.top(); - subcoeffs = new fullMatrix<double>(numSub*numMetPnts, numCoeff); - _bezier->subDivisor.mult(*current->_metcoeffs, *subcoeffs); - if (for3d) { - subjac = new fullVector<double>(numSub*numJacPnts); - _jacobian->getBezier()->subDivisor.mult(*current->_jaccoeffs, *subjac); - } - int depth = current->_depth; - int num = current->_num; - delete current; - subdomains.pop(); - - for (int i = 0; i < numSub; ++i) { - coeff = new fullMatrix<double>(numMetPnts, numCoeff); - coeff->copy(*subcoeffs, i * numMetPnts, numMetPnts, 0, numCoeff, 0, 0); - if (for3d) { - jac = new fullVector<double>; - jac->setAsProxy(*subjac, i * numJacPnts, numJacPnts); - } - double minLag, minBez; - _computeBoundsRmin(*coeff, *jac, minLag, minBez); - RminLag = std::min(RminLag, minLag); - int newNum = num + (i+1) * pow_int(10, depth); - if (depth > 8) newNum = 999999999; - MetricData *metData = new MetricData(coeff, jac, minBez, depth+1, newNum); - //statsForMatlab(el, 15, metData); - //if (el) statsForMatlab(el, 20, metData); - subdomains.push(metData); - } - if (for3d) trash.push_back(subjac); - delete subcoeffs; - ++k; - } - - //Msg::Info("num subdiv %d", k); - - double ans = subdomains.top()->_RminBez; - while (subdomains.size()) { - md = subdomains.top(); - subdomains.pop(); - delete md; - } - for (unsigned int i = 0; i < trash.size(); ++i) { - delete trash[i]; - } - - return ans; -} - -void MetricBasis::_getMetricData(const MElement *el, MetricData *&md) const -{ - int nSampPnts = _gradients->getNumSamplingPoints(); - int nMapping = _gradients->getNumMapNodes(); - - // Nodes - fullMatrix<double> nodes(nMapping, 3); - el->getNodesCoord(nodes); - - // Jacobian coefficients - fullVector<double> *jac = NULL; - if (_dim == 3) { - fullVector<double> jacLag(_jacobian->getNumJacNodes()); - jac = new fullVector<double>(_jacobian->getNumJacNodes()); - _jacobian->getSignedIdealJacobian(nodes, jacLag); - _jacobian->lag2Bez(jacLag, *jac); - } - - // Metric coefficients - fullMatrix<double> metCoeffLag; - _fillCoeff<true>(el->getDim(), _gradients, nodes, metCoeffLag); - fullMatrix<double> *metCoeff; - metCoeff = new fullMatrix<double>(nSampPnts, metCoeffLag.size2()); - _bezier->matrixLag2Bez.mult(metCoeffLag, *metCoeff); - - md = new MetricData(metCoeff, jac, -1, 0, 0); -} - -template<bool ideal> -void MetricBasis::_fillCoeff(int dim, const GradientBasis *gradients, - const fullMatrix<double> &nodes, fullMatrix<double> &coeff) -{ - //Msg::Fatal("Verifie si cette fonction est ok o"); - const int nSampPnts = gradients->getNumSamplingPoints(); - - switch (dim) { - case 0 : - return; - case 1 : - Msg::Fatal("Should not be here, metric for 1d not implemented"); - break; - - case 2 : - { - fullMatrix<double> dxydX(nSampPnts,3), dxydY(nSampPnts,3); - if (ideal) - gradients->getIdealGradientsFromNodes(nodes, &dxydX, &dxydY, NULL); - else - gradients->getGradientsFromNodes(nodes, &dxydX, &dxydY, NULL); - - coeff.resize(nSampPnts, 3); - for (int i = 0; i < nSampPnts; i++) { - const double &dxdX = dxydX(i,0), &dydX = dxydX(i,1); - const double &dxdY = dxydY(i,0), &dydY = dxydY(i,1); - double dzdX = 0, dzdY = 0; - if (nodes.size2() > 2) { - dzdX = dxydX(i,2); - dzdY = dxydY(i,2); - } - const double dvxdX = dxdX*dxdX + dydX*dydX + dzdX*dzdX; - const double dvxdY = dxdY*dxdY + dydY*dydY + dzdY*dzdY; - coeff(i, 0) = (dvxdX + dvxdY) / 2; - coeff(i, 1) = dvxdX - coeff(i, 0); - coeff(i, 2) = (dxdX*dxdY + dydX*dydY + dzdX*dzdY); - } - } - break; - - case 3 : - { - fullMatrix<double> dxyzdX(nSampPnts,3), dxyzdY(nSampPnts,3), dxyzdZ(nSampPnts,3); - if (ideal) - gradients->getIdealGradientsFromNodes(nodes, &dxyzdX, &dxyzdY, &dxyzdZ); - else - gradients->getGradientsFromNodes(nodes, &dxyzdX, &dxyzdY, &dxyzdZ); - - coeff.resize(nSampPnts, 7); - for (int i = 0; i < nSampPnts; i++) { - const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); - const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2); - const double &dxdZ = dxyzdZ(i,0), &dydZ = dxyzdZ(i,1), &dzdZ = dxyzdZ(i,2); - const double dvxdX = dxdX*dxdX + dydX*dydX + dzdX*dzdX; - const double dvxdY = dxdY*dxdY + dydY*dydY + dzdY*dzdY; - const double dvxdZ = dxdZ*dxdZ + dydZ*dydZ + dzdZ*dzdZ; - coeff(i, 0) = (dvxdX + dvxdY + dvxdZ) / 3; - static double fact1 = 1./std::sqrt(6.); - static double fact2 = 1./std::sqrt(3.); - coeff(i, 1) = fact1 * (dvxdX - coeff(i, 0)); - coeff(i, 2) = fact1 * (dvxdY - coeff(i, 0)); - coeff(i, 3) = fact1 * (dvxdZ - coeff(i, 0)); - coeff(i, 4) = fact2 * (dxdX*dxdY + dydX*dydY + dzdX*dzdY); - coeff(i, 5) = fact2 * (dxdZ*dxdY + dydZ*dydY + dzdZ*dzdY); - coeff(i, 6) = fact2 * (dxdX*dxdZ + dydX*dydZ + dzdX*dzdZ); - } - } - break; - } -} - -double MetricBasis::_computeMinlagR(const fullVector<double> &jac, - const fullMatrix<double> &coeff, int num) -{ - double Rmin = 1.; - - switch (coeff.size2()) { - case 7: - for (int i = 0; i < num; ++i) { - if (jac(i) <= 0.) return 0; - - const double &q = coeff(i, 0); - double p = 0; - for (int k = 1; k < 7; ++k) { - p += pow_int(coeff(i, k), 2); - } - p = std::sqrt(p); - - Rmin = std::min(Rmin, _R3Dsafe(q, p, jac(i))); - } - break; - - case 3: - for (int i = 0; i < num; ++i) { - const double &q = coeff(i, 0); - double p = pow_int(coeff(i, 1), 2) + pow_int(coeff(i, 2), 2); - p = std::sqrt(p); - - Rmin = std::min(Rmin, _R2Dsafe(q, p)); - } - break; - - default: - Msg::Error("coeff have not right number of column"); - return -1; - } - - return std::sqrt(Rmin); -} - -void MetricBasis::_minMaxA(const fullMatrix<double> &coeff, - double &mina, double &max) const -{ - // TODO calculer le max ? - double upperBound = std::numeric_limits<double>::infinity(); - double lowerBound = -upperBound; - std::map<int, std::vector<IneqData> >::const_iterator it = _ineqA.begin(); - - while (it != _ineqA.end()) { - double num = 0; - double den = 0; - for (unsigned int k = 0; k < it->second.size(); ++k) { - const int i = it->second[k].i; - const int j = it->second[k].j; - double tmp = 0; - for (int l = 1; l < coeff.size2(); ++l) { - tmp += coeff(i, l) * coeff(j, l); - } - den += it->second[k].val * tmp; - num += it->second[k].val * coeff(i, 0) * coeff(j, 0); - } - - // mina has to satisfy: mina^2 * den <= num - if (den == 0) { - if (num >= 0) {} // ok, nothing to do - else {// impossible to satisfy. - _minAfast(coeff, mina); - return; - } - } - else if (den > 0) - upperBound = std::min(upperBound, num/den); - else - lowerBound = std::max(lowerBound, num/den); - - ++it; - } - - if (lowerBound > upperBound) - _minAfast(coeff, mina); - else - mina = upperBound > 1 ? std::sqrt(upperBound) : 1; -} - -void MetricBasis::_minAfast(const fullMatrix<double> &coeff, double &mina) const -{ - double minq = coeff(0, 0); - for (int i = 1; i < coeff.size1(); ++i) - minq = std::min(minq, coeff(i, 0)); - - double maxp = 0; - for (int i = 0; i < coeff.size1(); ++i) { - double tmp = 0; - for (int j = 1; j < 7; ++j) { - tmp += pow_int(coeff(i, j), 2); - } - maxp = std::max(maxp, tmp); - } - - mina = std::max(1., minq/maxp); // accept +inf as answer -} - -void MetricBasis::_minKfast(const fullMatrix<double> &coeff, - const fullVector<double> &jac, double &minK) const -{ - fullVector<double> P(coeff.size1()); - for (int i = 0; i < coeff.size1(); ++i) { - P(i) = 0; - for (int l = 1; l < 7; ++l) { - P(i) += coeff(i, l) * coeff(i, l); - } - P(i) = std::sqrt(P(i)); - } - - double upperBound = std::numeric_limits<double>::infinity(); - double lowerBound = -upperBound; - - std::map<int, std::vector<IneqData> >::const_iterator itJ, itP; - itJ = _ineqJ2.begin(); - itP = _ineqP3.begin(); - - // _ineqJ2 and _ineqP3 have the same size - while (itJ != _ineqJ2.end()) { - //if (itJ->first != itP->first) Msg::Fatal("not same hash %d %d", itJ->first, itP->first); - double num = 0; - for (unsigned int k = 0; k < itJ->second.size(); ++k) { - const int i = itJ->second[k].i; - const int j = itJ->second[k].j; - num += itJ->second[k].val * jac(i) * jac(j); - } - - double den = 0; - for (unsigned int l = 0; l < itP->second.size(); ++l) { - const int i = itP->second[l].i; - const int j = itP->second[l].j; - const int k = itP->second[l].k; - den += itP->second[l].val * P(i) * P(j) * P(k); - } - - // minK has to satisfy: minK * den <= num - if (den == 0) { - if (num >= 0) { - ++itJ; - ++itP; - continue; - } - // otherwise, it's impossible to satisfy. - minK = 0;//TODO c'est mieux de retourner _minKfast(coeff, jac, minK); ? - return; - } - else if (den > 0) - upperBound = std::min(upperBound, num/den); - else - lowerBound = std::max(lowerBound, num/den); - - ++itJ; - ++itP; - } - - if (lowerBound > upperBound) - minK = 0;//TODO c'est mieux de retourner _minKfast(coeff, jac, minK); ? - else - minK = std::max(.0, upperBound); -} - -void MetricBasis::_minKsharp(const fullMatrix<double> &coeff, - const fullVector<double> &jac, double &minK) const -{ - fullVector<double> P(coeff.size1()); - fullMatrix<double> Q(coeff.size1(), coeff.size1()); - for (int i = 0; i < coeff.size1(); ++i) { - P(i) = 0; - for (int l = 1; l < 7; ++l) { - P(i) += coeff(i, l) * coeff(i, l); - } - P(i) = std::sqrt(P(i)); - // fill only the half - for (int j = i; j < coeff.size1(); ++j) { - Q(i, j) = 0; - for (int l = 1; l < 7; ++l) { - Q(i, j) += coeff(i, l) * coeff(j, l); - } - } - } - - double upperBound = std::numeric_limits<double>::infinity(); - double lowerBound = -upperBound; - - std::map<int, std::vector<IneqData> >::const_iterator itJ, itP; - itJ = _ineqJ2.begin(); - itP = _ineqP3.begin(); - - // _ineqJ2 and _ineqP3 have the same size - while (itJ != _ineqJ2.end()) { - double num = 0; - for (unsigned int k = 0; k < itJ->second.size(); ++k) { - const int i = itJ->second[k].i; - const int j = itJ->second[k].j; - num += itJ->second[k].val * jac(i) * jac(j); - } - - double den = 0; - for (unsigned int l = 0; l < itP->second.size(); ++l) { - const int i = itP->second[l].i; - const int j = itP->second[l].j; - const int k = itP->second[l].k; - den += itP->second[l].val * 1/3*(Q(i,j)*P(k)+Q(i,k)*P(j)+Q(j,k)*P(i)); - } - - // minK has to satisfy: minK * den <= num - if (den == 0) { - if (num >= 0) { - ++itJ; - ++itP; - continue; - } - // otherwise, it's impossible to satisfy. - minK = 0;//TODO c'est mieux de retourner _minKfast(coeff, jac, minK); ? - return; - } - else if (den > 0) - upperBound = std::min(upperBound, num/den); - else - lowerBound = std::max(lowerBound, num/den); - - ++itJ; - ++itP; - } - - if (lowerBound > upperBound) - minK = 0;//TODO c'est mieux de retourner _minKfast(coeff, jac, minK); ? - else - minK = std::max(.0, upperBound); -} - -void MetricBasis::_computeBoundingCurve(const fullMatrix<double> &coeff, - const fullVector<double> &jac, - double &beta, double c, - bool compLowBound) const -{ - // compute a lower/upper bounding curve K = beta * a^3 + c * a - // with c fixed. - - //Msg::Info("BEGINNING %g %g", std::numeric_limits<double>::min(), std::numeric_limits<double>::denorm_min()); - - fullMatrix<double> Q(coeff.size1(), coeff.size1()); // (half filled!) - for (int i = 0; i < coeff.size1(); ++i) { - for (int j = i; j < coeff.size1(); ++j) { - Q(i, j) = 0; - for (int l = 1; l < 7; ++l) - Q(i, j) += coeff(i, l) * coeff(j, l); - } - } - - double upperBound = std::numeric_limits<double>::infinity(); - double lowerBound = -upperBound; - - // values in case of a failure - if (compLowBound) beta = upperBound; - else beta = lowerBound; - - std::map<int, std::vector<IneqData> >::const_iterator itJ, itP; - itJ = _ineqJ2.begin(); - itP = _ineqP3.begin(); - - // _ineqJ2 and _ineqP3 have the same size - //int kk = 0; - while (itJ != _ineqJ2.end()) {// && kk++ < 2) {// FIXME making tests - long double J2 = 0; - for (unsigned int k = 0; k < itJ->second.size(); ++k) { - const int i = itJ->second[k].i; - const int j = itJ->second[k].j; - J2 += itJ->second[k].val * jac(i) * jac(j); - //Msg::Info("(%d, %d) = (%g | %g, %g) -> J2:%Lg", i, j, itJ->second[k].val, jac(i), jac(j), J2); - } - - long double q3 = 0, qp2 = 0; - for (unsigned int l = 0; l < itP->second.size(); ++l) { - const int i = itP->second[l].i; - const int j = itP->second[l].j; - const int k = itP->second[l].k; - q3 += itP->second[l].val * coeff(i, 0) * coeff(j, 0) * coeff(k, 0); - qp2 += itP->second[l].val * 1/3*(coeff(i, 0) * Q(j, k) + - coeff(j, 0) * Q(i, k) + - coeff(k, 0) * Q(i, j)); - //Msg::Info("%d %d %d => %Lg %Lg", i, j, k, q3, qp2); - //Msg::Info("(%d %d %d) -> q3:%Lg qp2:%Lg", i, j, k, q3, qp2); - } - - //Msg::Info("a%Lg K%Lg %Lg %Lg", std::sqrt(q3/qp2), std::sqrt(J2*J2*q3/qp2/qp2/qp2), std::sqrt(q3/qp2), std::sqrt(J2*J2*q3/qp2/qp2/qp2)); - - const long double num = J2 - ((long double)c)*qp2; - const long double den = q3; - // beta has to satisfy beta * den <= num if compLowBound = true - // or beta * den >= num if compLowBound = false - - if (den == 0) { - if (compLowBound) { - if (num >= 0) {} // ok, nothing to do - else return; - //TODO c'est mieux de retourner min(..)/max(..) ?? - } - else { - if (num <= 0) {} // ok, nothing to do - else return; - //TODO c'est mieux de retourner max(..)/min(..) ?? - } - } - else if (den > 0) { - if (compLowBound) - upperBound = std::min(upperBound, (double)(num/den)); - else - lowerBound = std::max(lowerBound, (double)(num/den)); - } - else { - if (compLowBound) - lowerBound = std::max(lowerBound, (double)(num/den)); - else - upperBound = std::min(upperBound, (double)(num/den)); - } - - //Msg::Info("in [%.15g, %.15g]", lowerBound, upperBound); - - ++itJ; - ++itP; - } - - if (lowerBound <= upperBound) { - if (compLowBound) - beta = upperBound; - else - beta = lowerBound; - } - - //Msg::Info("ENDING"); - //TODO sinon, c'est mieux de retourner m..(..)/m..(..) ?? -} - -void MetricBasis::_computeLowerBoundC(const fullMatrix<double> &coeff, - const fullVector<double> &jac, - double beta, double &c) const -{ - // compute a lower/upper bound of function C = K-beta*a^3 - - double upperBound = std::numeric_limits<double>::infinity(); - double lowerBound = -upperBound; - - // value in case of a failure - c = 0; - - fullVector<double> P(coeff.size1()); - for (int i = 0; i < coeff.size1(); ++i) { - P(i) = 0; - for (int l = 1; l < 7; ++l) { - P(i) += coeff(i, l) * coeff(i, l); - } - P(i) = std::sqrt(P(i)); - } - - std::map<int, std::vector<IneqData> >::const_iterator itJ, itP; - itJ = _ineqJ2.begin(); - itP = _ineqP3.begin(); - - // _ineqJ2 and _ineqP3 have the same size - while (itJ != _ineqJ2.end()) { - double num = 0, den = 0; - for (unsigned int l = 0; l < itP->second.size(); ++l) { - const int i = itP->second[l].i; - const int j = itP->second[l].j; - const int k = itP->second[l].k; - num -= itP->second[l].val * coeff(i, 0) * coeff(j, 0) * coeff(k, 0); - den += itP->second[l].val * P(i) * P(j) * P(k); - } - - num = num * beta; - for (unsigned int l = 0; l < itJ->second.size(); ++l) { - const int i = itJ->second[l].i; - const int j = itJ->second[l].j; - num += itJ->second[l].val * jac(i) * jac(j); - } - - // c has to satisfy c * den <= num - if (den == 0) { - if (num >= 0) { - ++itJ; - ++itP; - continue; - } - else return; - //TODO c'est mieux de retourner min(J^2-beta q^3)/max(p^3) ? - } - if (den > 0) - upperBound = std::min(upperBound, num/den); - else { - lowerBound = std::max(lowerBound, num/den); - } - - ++itJ; - ++itP; - } - - if (lowerBound <= upperBound) { - c = upperBound; - } - //TODO sinon, c'est mieux de retourner min(J^2-beta q^3)/max(p^3) ? -} - -void MetricBasis::_computePseudoDerivatives(double a, double K, - double &dRda, double &dRdK) -{ - // Return derivative without positive (but non-constant) coefficients - // Useful when only the sign of dRda and dRdK or the ratio dRda/dRdK - // are needed. - - double w = _wSafe(a, K); - if (std::abs(w) > 1) { - Msg::Error("Cannot compute pseudo derivatives of R " - "outside the domain (w = %g)", w); - return; - } - - const double phip = (std::acos(w) + M_PI) / 3; - const double C = 1 + a * std::cos(phip); - - dRdK = C / 3; - dRda = 2 * std::sqrt(1-w*w) * std::sin(phip) + (1-a*a) * C; -} - -void MetricBasis::_computeDerivatives(double a, double K, - double &dRda, double &dRdK, - double &dRdaa, double &dRdaK, double &dRdKK) -{ - const double w = _wSafe(a, K); - if (std::abs(w) > 1) { - Msg::Error("Cannot compute derivatives of R outside the domain"); - return; - } - - const double phi = (std::acos(w)) / 3; - const double phip = phi + M_PI / 3; - const double S = 1./std::sqrt(1-w*w); - const double A = (1-a*a)*S; - const double sin = std::sin(phi); - const double sinp = std::sin(phip); - const double cosp = std::cos(phip); - const double C = 1 + a*cosp; - const double D = 1./(a+2*std::cos(phi)); - static const double sq3 = std::sqrt(3); - const double coeff = sq3*D*D/18; - - dRdK = coeff*6 * (C*S); - dRda = coeff*18 * (2*sinp + A*C); - dRdKK = coeff*S*S * (a*sinp - 4*C*sin*D + 3*w*C*S); - dRdaK = coeff*S*3 * (a*A*sinp + 3*w*A*C*S + 2*cosp - 4*C*(1+A*sin)*D); - dRdaa = coeff*9 * (3*w*A*A*C*S - 4*a*C*S + a*A*A*sinp - 4*(1+A*sin)*D*(2*sinp + A*C)); -} - -bool MetricBasis::_moveInsideDomain(double &a, double &K, bool bottomleftCorner) -{ - // Note: For N-R (when moving 'a'), we compute the root of - // f(a) = .5 * (K - a^3 + 3*a) - 'w' where 'w' is -1 or 1. - - double w = _w(a, K); - if (w > 1.) { - if (bottomleftCorner) { - // make sure to compute the right root (a>1) and - // avoid slopes that are too small: - a = std::max(a, 1.1); - - const double tolerance = _tol/100; - // Note: N-R approaches the root from the right, we - while (w > 1 || w < 1-tolerance) { - double df = w - 1; - double slope = 1.5*(1-a*a); - a -= df/slope; - w = _w(a, K); - } - } - else { - K -= 2*w - 2; - } - return true; - } - else if (w < -1.) { - if (bottomleftCorner) { - K -= 2*w + 2; - } - else { - a = std::max(a, 2.); - - const double tolerance = _tol/100; - while (std::abs(w+1) > tolerance) { - double df = w + 1; - double slope = 1.5*(1-a*a); - a -= df/slope; - w = _w(a, K); - } - } - return true; - } - return false; -} - -double MetricBasis::_computeMinRAlongCurve(double beta, double c, - double mina, double maxa) -{ - // Compute the minimum of R on the curve K = beta * a^3 + c - // where beta can be zero. - // 'mina' and 'maxa' stand for the limits of the curve. There must be at - // least 1 limit. To indicate that 'mina' or 'maxa' is not a limit, it is - // set to a negative value. - - bool towardsPositivea; - double a, K, R; - if (mina < 0) { - a = maxa; - K = (beta*a*a + c)*a; - R = _R3Dsafe(a, K); - towardsPositivea = false; - } - else if (maxa < 0) { - a = mina; - K = (beta*a*a + c)*a; - R = _R3Dsafe(a, K); - towardsPositivea = true; - } - else { - // choose the more promising limit as starting point - double K1 = beta*mina*mina*mina + c; - double K2 = beta*maxa*maxa*maxa + c; - double R1 = _R3Dsafe(mina, K1); - double R2 = _R3Dsafe(maxa, K2); - if (R1 < R2) { - a = mina; - K = K1; - R = R1; - towardsPositivea = true; - } - else { - a = maxa; - K = K2; - R = R2; - towardsPositivea = false; - } - } - - double da = 1, dK, dKK; - double dRda, dRdK, dRdaa, dRdaK, dRdKK; - double dRdC, dRdCC; - - _computeDerivatives(a, K, dRda, dRdK, dRdaa, dRdaK, dRdKK); - dK = 3*beta*a*a+c; - dKK = 6*beta*a; - dRdC = dRda*da + dRdK*dK; - dRdCC = dRdaa*da*da + 2*dRdaK*da*dK + dRdKK*dK*dK + dRdK*dKK; - - if ((towardsPositivea && dRdC > 0) || (!towardsPositivea && dRdC < 0)) { - Msg::Warning("Already the minimum"); - return R; - } - - while (.25*dRdC*dRdC/dRdCC > .01*_toleranceOnR(R)) { - a = a - dRdC / dRdCC; - K = (beta*a*a + c)*a; - R = _R3Dsafe(a, K); - - _computeDerivatives(a, K, dRda, dRdK, dRdaa, dRdaK, dRdKK); - dK = 3*beta*a*a+c; - dKK = 6*beta*a; - dRdC = dRda*da + dRdK*dK; - dRdCC = dRdaa*da*da + 2*dRdaK*da*dK + dRdKK*dK*dK + dRdK*dKK; - } - - /*Msg::Warning("Checking Newton Raphson solution... (%g, %g)", a, K); - double min = 1; - for (double aa = std::max(1., .5*a); aa < 2*a; aa += .001*a) { - double KK = (beta*aa*aa + c)*aa; - double w = _wSafe(aa, KK); - if (std::abs(w) <= 1) min = std::min(min, _R3Dsafe(aa, KK)); - } - if (std::abs(min-R) < .01*_toleranceOnR(R)) - Msg::Info("... aaand, it is good!"); - else - Msg::Error("... and, it's a fail! %g vs %g (tol %g => %g)", R, min, _toleranceOnR(R), R-.01*_toleranceOnR(R));*/ - - return R; -} - -bool MetricBasis::_intersectionCurveLeftCorner(double beta, double c, - double &a, double &K) -{ - // on input, a and K are the bottom left corner - // on output, a and K are the intersection - // return true if the intersection is on the vertical - // We assume the intersection exists - // (i.e. the bounding curve is sufficiently sharp) - if (3*beta*a*a + c < 0) { - Msg::Error("The slope is negative, cannot compute the intersection"); - return false; - } - - const double minK = K; - //const double mina = a; //TODO remove (not needed) - - K = (beta*a*a + c)*a; - if (K >= minK) return true; - - // Find the root by Newton-Raphson - double dK = K-minK; - - static double precision = std::numeric_limits<double>::epsilon() * 1e3; - int n = 0; - while (std::abs(dK) > minK * precision && ++n < 100) { //TODO meilleur approx - const double slope = 3*beta*a*a + c; - a -= dK / slope; - dK = (beta*a*a + c)*a-minK; - } - K = minK; - //Msg::Info("in %d it (%g, %g) -> (%g, %g) => diff(%g, %g)", k, mina, minK, a, K, a-mina, K-minK); - return false; -} - -double MetricBasis::_computeAbscissaMinR(double aStart, double K) -{ - double dRda, dRdK, dRdaa, dRdaK, dRdKK; - _computeDerivatives(aStart, K, dRda, dRdK, dRdaa, dRdaK, dRdKK); - double a = aStart; - while (dRda > MetricBasis::_tol*1e-3) { - double da = - dRda / dRdaa; - a += da; - _computeDerivatives(a, K, dRda, dRdK, dRdaa, dRdaK, dRdKK); - } - return a; -} - -double MetricBasis::_R3Dsafe(double q, double p, double J) -{ - if (q >= p && p >= 0 && J == J && - p < std::numeric_limits<double>::infinity()) { - if (q == 0) return 0; - if (p == 0) return 1; - if (q == std::numeric_limits<double>::infinity()) { - Msg::Warning("q had infinite value in computation of 3D metric"); - return 1; - } - const double a = q/p; - const double K = J*J/p/p/p; - return _R3Dsafe(a, K); - } - else { - Msg::Error("Wrong argument for 3d metric (%g, %g, %g)", q, p, J); - return -1; - } -} - -double MetricBasis::_R3Dsafe(double a, double K) -{ - if (a >= 1 && K >= 0) { - // TODO speedup in function of _tol ? - // if (2/a < _tol) return 1.; - // if (8/K < _tol*_tol*_tol) return 1.; - - if (a == std::numeric_limits<double>::infinity()) - return 1; - - const double w = _wSafe(a, K); - if (std::abs(w) > 1-_tol/10) { - if (w > 0) return (a - 1) / (a + 2); - else return (a - 2) / (a + 1); - } - - const double phi = std::acos(w) / 3; - const double R = (a + 2*std::cos(phi + 2*M_PI/3)) / (a + 2*std::cos(phi)); - return std::max(.0, std::min(1., R)); - } - else { - Msg::Error("Wrong argument for 3d metric (%g, %g)", a, K); - return -1; - } -} - -double MetricBasis::_R2Dsafe(double q, double p) -{ - if (q >= p && p >= 0 && p < std::numeric_limits<double>::infinity()) { - if (q == 0) return 0; - if (q == std::numeric_limits<double>::infinity()) { - Msg::Warning("q had infinite value in computation of 2D metric"); - return 1; - } - return (q-p) / (q+p); - } - else { - Msg::Error("Wrong argument for 2d metric (%g, %g)", q, p); - return -1; - } -} - -double MetricBasis::_R2Dsafe(double a) -{ - if (a >= 1) { - if (a == std::numeric_limits<double>::infinity()) - return 1; - return (a - 1) / (a + 1); - } - else { - Msg::Error("Wrong argument for 2d metric (%g)", a); - return -1; - } -} - -double MetricBasis::_toleranceOnR(double R) -{ - const double sqRmax = std::max(.0, std::sqrt(R) - _tol); - return R - sqRmax*sqRmax; -} diff --git a/Numeric/MetricBasis.h b/Numeric/MetricBasis.h deleted file mode 100644 index 5d0a389f96..0000000000 --- a/Numeric/MetricBasis.h +++ /dev/null @@ -1,200 +0,0 @@ -// Gmsh - Copyright (C) 1997-2016 C. Geuzaine, J.-F. Remacle -// -// See the LICENSE.txt file for license information. Please report all -// bugs and problems to the public mailing list <gmsh@onelab.info>. - -#ifndef _METRIC_BASIS_H_ -#define _METRIC_BASIS_H_ - -#include <fstream> -#include <cmath> -#include "fullMatrix.h" -class MElement; -class bezierBasis; -class JacobianBasis; -class GradientBasis; - -class MetricBasis { - friend class MetricCoefficient; - friend class GMSH_AnalyseCurvedMeshPlugin; - -private: - const JacobianBasis *_jacobian; - const GradientBasis *_gradients; - const bezierBasis *_bezier; - static double _tol; - const int _type, _dim; - - std::fstream file; - - class IneqData { - public: - int i, j, k; - double val; - - public: - IneqData(double val, int i, int j, int k = -1) : i(i), j(j), k(k), val(val) {} - }; - - std::map<int, std::vector<IneqData> > _ineqJ2, _ineqP3, _ineqA; - - class MetricData { - public: - fullMatrix<double> *_metcoeffs; - fullVector<double> *_jaccoeffs; - double _RminBez; - int _depth, _num; - - public: - MetricData(fullMatrix<double> *m, fullVector<double> *j, - double r = -1, int d = -1, int num = -1) : - _metcoeffs(m), _jaccoeffs(j), _RminBez(r), _depth(d), _num(num) {} - ~MetricData() { - delete _metcoeffs; - delete _jaccoeffs; - } - - bool haveJac() {return _jaccoeffs != NULL;} - }; - -public: - MetricBasis(int elementTag); - - // Get & Set methods - static void setTol(double tol) {_tol = tol;} - const JacobianBasis* getJacobianForMetric() const {return _jacobian;} - const bezierBasis* getBezier() const {return _bezier;} - //int getNumMetricNodes() const {return _gradients->getNumSamplingPoints();} - - // Compute min(R) with given tolerance - static double getMinR(MElement *el); - double computeMinR(MElement*) const; - - // Sample R and return min - static double getMinSampledR(MElement *el, int order); - double computeMinSampledR(MElement*, int order) const; - - // Compute R on corners and return min - static double getMinRCorner(MElement *el); - - // TEST : sample min(r_min) and max(r_max) and return ratio of the two - static double getMinSampledGlobalRatio(MElement *el, int order); - double computeMinSampledGlobalRatio(MElement*, int order) const; - - // TEST : sample R and return max - static double getMaxSampledR(MElement *el, int order); - double computeMaxSampledR(MElement*, int order) const; - - - // - template<bool ideal> - void getMetricCoeff(const fullMatrix<double> &nodes, - fullMatrix<double> &coeff) const { - _fillCoeff<ideal>(_dim, _gradients, nodes, coeff); - } -// void lag2Bez(const fullMatrix<double> &metCoeffLag, -// fullMatrix<double> &metCoeffBez) const { -// _bezier->matrixLag2Bez.mult(metCoeffLag, metCoeffBez); -// } - void lag2Bez(const fullMatrix<double> &metCoeffLag, - fullMatrix<double> &metCoeffBez) const; - - // Metric order - static int metricOrder(int tag); - -public: - // Validation for computation of Bezier coefficients & subdivision - // of Jacobian determinant and Metric stuffs - static bool validateBezierForMetricAndJacobian(); - static int validateBezierForMetricAndJacobian(MElement *el, - int numSampPnt, - int numSubdiv, - double toleranceTensor, - double tolerance); - void statsForMatlab(MElement *el, int deg, MetricData *md) const; - void interpolate(const MElement*, const MetricData*, - const fullMatrix<double> &nodes, fullMatrix<double> &R) const; - void interpolateAfterNSubdivisions(const MElement *el, - int numSubdiv, int numPnt, - fullVector<int> &isub, - fullMatrix<double> &uvw, - fullMatrix<double> &metric) const; - -private: - void _fillInequalities(int order); - void _fillInequalitiesPyr(int order); - void _lightenInequalities(int&, int&, int&); //TODO change - - void _computeBoundsRmin(const fullMatrix<double>&, const fullVector<double>&, - double &RminLag, double &RminBez) const; - void _computeBoundsRmax(const fullMatrix<double>&, const fullVector<double>&, - double &RmaxLag) const; - void _getMetricData(const MElement*, MetricData*&) const; - - double _subdivideForRmin(MetricData*, double &RminLag, double tol, MElement *el=NULL) const; - template<bool ideal> - static void _fillCoeff(int dim, const GradientBasis*, - const fullMatrix<double> &nodes, fullMatrix<double> &coeff); - static double _computeMinlagR(const fullVector<double> &jac, - const fullMatrix<double> &coeff, int num); - - void _minMaxA(const fullMatrix<double>&, double &min, double &max) const; - void _minAfast(const fullMatrix<double>&, double &min) const; - void _minKfast(const fullMatrix<double>&, const fullVector<double>&, double &min) const; - void _minKsharp(const fullMatrix<double>&, const fullVector<double>&, double &min) const; - void _computeBoundingCurve(const fullMatrix<double>&, - const fullVector<double>&, - double &beta, double c, bool lowerBound) const; - void _computeLowerBoundC(const fullMatrix<double>&, - const fullVector<double>&, - double beta, double &c) const; - - static bool _moveInsideDomain(double &a, double &K, bool bottomleftCorner); - static void _computePseudoDerivatives(double a, double K, - double &dRda, double &dRdK); - static void _computeDerivatives(double a, double K, - double &dRda, double &dRdK, - double &dRdaa, double &dRdaK, double &dRdKK); - static double _computeMinRAlongCurve(double beta, double c, - double mina, double maxa); - static bool _intersectionCurveLeftCorner(double beta, double c, - double &mina, double &minK); - static double _computeAbscissaMinR(double aStart, double K); - - static double _R3Dsafe(double a, double K); - static double _R3Dsafe(double q, double p, double J); - static double _R2Dsafe(double a); - static double _R2Dsafe(double q, double p); - static inline double _w(double a, double K) { - return .5 * (K + (3-a*a)*a); - } - static inline double _wSafe(double a, double K) { - const double w = _w(a, K); - if (w > 1) { - if (w < 1+_tol/10) return 1; - else Msg::Error("outside the domain w(%g, %g) = %g", a, K, w); - } - else if (w < -1) { - if (w > -1-_tol/10) return -1; - else Msg::Error("outside the domain w(%g, %g) = %g", a, K, w); - } - return w; - } - - static double _toleranceOnR(double R); - -private: - class gterIneq { - public: - bool operator()(const IneqData &id1, const IneqData &id2) const { - return id1.val > id2.val; - } - }; - struct lessMinB { - bool operator()(const MetricData *md1, const MetricData *md2) const { - return md1->_RminBez > md2->_RminBez; - } - }; -}; - -#endif -- GitLab