diff --git a/CMakeLists.txt b/CMakeLists.txt index bc64947300f71bbb2cd343b88bb29c05cd16729b..2e81dd63dd0af83d932bf65f26e4189bbfa1e4e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,7 +149,7 @@ set(GMSH_API contrib/HighOrderMeshOptimizer/OptHomRun.h contrib/HighOrderMeshOptimizer/ParamCoord.h contrib/HighOrderMeshOptimizer/OptHomFastCurving.h contrib/HighOrderMeshOptimizer/SuperEl.h contrib/HighOrderMeshOptimizer/OptHomIntegralBoundaryDist.h - contrib/HighOrderMeshOptimizer/OptHomCADDist.h + contrib/HighOrderMeshOptimizer/CADDistances.h contrib/HighOrderMeshOptimizer/OptHomObjContribScaledJac.h contrib/HighOrderMeshOptimizer/OptHomObjContribMetricMin.h contrib/HighOrderMeshOptimizer/OptHomObjContribCADDist.h diff --git a/contrib/HighOrderMeshOptimizer/CADDistances.cpp b/contrib/HighOrderMeshOptimizer/CADDistances.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf4b1066057456375e698c73e579e34c3e193697 --- /dev/null +++ b/contrib/HighOrderMeshOptimizer/CADDistances.cpp @@ -0,0 +1,588 @@ +// TODO: Header + +#include "SPoint3.h" +#include "SVector3.h" +#include "nodalBasis.h" +#include "GEdge.h" +#include "GFace.h" +#include "MElement.h" +#include "MLine.h" +#include "MTriangle.h" +#include "BasisFactory.h" +#include "GModel.h" +#if defined(HAVE_ANN) +#include "ANN/ANN.h" +#endif +#include "CADDistances.h" + + +namespace { + + +// ---------------------------------- Discretization of curves ---------------------------------- + + +class parametricLine +{ + void recurDiscretize(const double &t1, const double &t2, const SPoint3 &p1, + const SPoint3 &p2, std::vector<SPoint3> &dpts, + std::vector<double> &ts, double Prec, int minDepth, + int maxDepth, int depth) const; +public: + virtual ~parametricLine() {} + virtual SPoint3 operator()(double xi) const = 0; + virtual SVector3 derivative(double xi) const = 0; + virtual SVector3 secondDerivative(double xi) const = 0; + SVector3 curvature(double xi) const; + void discretize(std::vector<SPoint3> &dpts,std::vector<double> &ts, + double Prec, int minDepth, int maxDepth, + double t0 = 0., double t1 = 1.) const; +}; + + +class parametricLineNodalBasis : public parametricLine +{ + const nodalBasis &_basis; + const std::vector<SPoint3> &_xyz; + +public: + parametricLineNodalBasis(const nodalBasis &basis, const std::vector<SPoint3> &xyz); + virtual SPoint3 operator()(double xi) const; + virtual SVector3 derivative(double xi) const; + virtual SVector3 secondDerivative(double xi) const; +}; + + +class parametricLineGEdge : public parametricLine +{ + const GEdge *_edge; + double _t0, _t1; + +public: + parametricLineGEdge(const GEdge *edge, double t0, double t1); + virtual SPoint3 operator()(double xi) const; + virtual SVector3 derivative(double xi) const; + virtual SVector3 secondDerivative(double xi) const; +}; + + +void parametricLine::recurDiscretize(const double &t1, const double &t2, const SPoint3 &p1, + const SPoint3 &p2, std::vector<SPoint3> &dpts, + std::vector<double> &ts, double Prec, int minDepth, + int maxDepth, int depth) const +{ + double t = 0.5 * (t2 + t1); + SPoint3 p = (*this)(t); + SVector3 dx(p, (p1+p2)*0.5); + if (((depth >= minDepth) && (dx.norm() < Prec)) || (depth >= maxDepth)) { + dpts.push_back(p); + ts.push_back(t); + dpts.push_back(p2); + ts.push_back(t2); + } + else { + recurDiscretize(t1, t, p1, p, dpts, ts, Prec, minDepth, maxDepth, depth+1); + recurDiscretize(t, t2, p, p2, dpts, ts, Prec, minDepth, maxDepth, depth+1); + } +} + + +void parametricLine::discretize(std::vector<SPoint3> &dpts, + std::vector<double> &ts, + double Prec, int minDepth, int maxDepth, double t0, double t1) const +{ + dpts.push_back((*this)(t0)); + ts.push_back(t0); + recurDiscretize(t0, t1, dpts[0], (*this)(t1), dpts, ts, Prec, minDepth, maxDepth, 0); +} + + +SVector3 parametricLine::curvature(double xi) const +{ + SVector3 xp = derivative(xi); + SVector3 xpp = secondDerivative(xi); + const double nxp = xp.norm(), onxp = 1./nxp; + SVector3 c = (onxp*onxp*onxp)*(xpp*nxp-xp*dot(xp,xpp)*onxp); + return c; +} + + +parametricLineNodalBasis::parametricLineNodalBasis(const nodalBasis &basis, + const std::vector<SPoint3> &xyz): + _basis(basis), _xyz(xyz) +{ +} + + +SPoint3 parametricLineNodalBasis::operator()(double xi) const +{ + double psi[_xyz.size()]; + SPoint3 p(0., 0., 0.); + _basis.f(-1 + 2 * xi, 0., 0., psi); + for (size_t j = 0; j < _xyz.size(); ++j) { + p[0] += psi[j] * _xyz[j].x(); + p[1] += psi[j] * _xyz[j].y(); + p[2] += psi[j] * _xyz[j].z(); + } + return p; +} + + +SVector3 parametricLineNodalBasis::derivative(double xi) const +{ + double dpsi[_xyz.size()][3]; + SVector3 p(0., 0., 0.); + _basis.df(-1 + 2 * xi, 0., 0., dpsi); + for (size_t j = 0; j < _xyz.size(); ++j) { + p[0] += dpsi[j][0] * _xyz[j].x(); + p[1] += dpsi[j][0] * _xyz[j].y(); + p[2] += dpsi[j][0] * _xyz[j].z(); + } + return p; +} + + +SVector3 parametricLineNodalBasis::secondDerivative(double xi) const +{ + double ddpsi[_xyz.size()][3][3]; + SVector3 p(0, 0, 0); + _basis.ddf(-1 + 2 * xi, 0, 0, ddpsi); + for (size_t j = 0; j < _xyz.size(); ++j) { + p[0] += ddpsi[j][0][0] * _xyz[j].x(); + p[1] += ddpsi[j][0][0] * _xyz[j].y(); + p[2] += ddpsi[j][0][0] * _xyz[j].z(); + } + return p; +} + + +parametricLineGEdge::parametricLineGEdge(const GEdge *edge, double t0, double t1): + _edge(edge), _t0(t0), _t1(t1) +{ +} + + +SPoint3 parametricLineGEdge::operator()(double xi) const +{ + GPoint gp = _edge->point(_t0 + (_t1 - _t0) * xi); + return SPoint3 (gp.x(), gp.y(), gp.z()); +} + + +SVector3 parametricLineGEdge::derivative(double xi) const +{ + return _edge->firstDer(_t0 + (_t1 - _t0) * xi); +} + + +SVector3 parametricLineGEdge::secondDerivative(double xi) const +{ + return _edge->secondDer(_t0 + (_t1 - _t0) * xi); +} + + +void oversample(std::vector<SPoint3> &s, double tol) +{ + std::vector<SPoint3> t; + for (unsigned int i=1;i<s.size();i++){ + SPoint3 p0 = s[i-1]; + SPoint3 p1 = s[i]; + double d = p0.distance(p1); + int N = (int) (d / tol); + t.push_back(p0); + for (int j=1;j<N;j++){ + const double xi = (double) j/ N; + t.push_back(p0 + (p1-p0)*xi); + } + } + t.push_back(s[s.size()-1]); + s = t; +} + + +// ---------------------------------- Discrete Fréchet distance ---------------------------------- + + +double recurMinMax(int i, int j, fullMatrix<double> &CA, + const std::vector<SPoint3> &P, const std::vector<SPoint3> &Q) +{ + double CAij; + if (CA(i,j) > -1.) { + CAij = CA(i,j); + } + else if (i==0 && j==0) { + CA(i,j) = P[0].distance(Q[0]); // update the CA permanent + CAij = CA(i,j); // set the current relevant value + } + else if (i>0 && j==0) { + CA(i,j) = std::max(recurMinMax(i-1, 0, CA, P, Q), P[i].distance(Q[1])); + CAij = CA(i,j); + } + else if (i==0 && j>0) { + CA(i,j) = std::max(recurMinMax(0, j-1, CA, P, Q), P[0].distance(Q[j])); + CAij = CA(i,j); + } + else if (i>0 && j>0) { + double temp = std::min(std::min(recurMinMax(i-1, j, CA, P, Q), + recurMinMax(i-1, j-1, CA, P, Q)), recurMinMax(i, j-1, CA, P, Q)); + CA(i,j) = std::max(temp, P[i].distance(Q[j])); + CAij = CA(i,j); + } + else { + CA(i,j) = 1.e22; + CAij = CA(i,j); + } + return CAij; +} + + +double discreteFrechetDistanceBrute(const std::vector<SPoint3> &P, + const std::vector<SPoint3> &Q) +{ + const int sP = P.size(); + const int sQ = Q.size(); + fullMatrix<double> CA(sP, sQ); + CA.setAll(-1.); + double cm = recurMinMax(sP-1, sQ-1, CA, P, Q); + return cm; +} + + +// ---------------------------------- Discrete Hausdorff distance ---------------------------------- + + +double oneSidedMaxDist(const std::vector<SPoint3> &dpts1, const std::vector<SPoint3> &dpts2, + int &iMaxDist, int &jMaxDist) +{ + double maxDist = 0.; + for (unsigned int i=0; i<dpts1.size(); i++) { + double dist = 1.e22; + int jDist = 0; + for (unsigned int j=0; j<dpts2.size(); j++) { + double h = dpts1[i].distance(dpts2[j]); + if (h < dist){ + dist = h; + jDist = j; + } + } + if (dist > maxDist) { + maxDist = dist; + jMaxDist = jDist; + iMaxDist = i; + } + } + return maxDist; +} + + +#if defined(HAVE_ANN) +double oneSidedMaxDistFast(const std::vector<SPoint3> &dptsA, const ANNpointArray &ptsB, + ANNkd_tree *treeB, double tol) +{ + ANNidx idx[1]; + ANNdist distSq[1]; + ANNdist maxDistSq = 0.; + for (unsigned int i=0; i<dptsA.size(); i++) { + ANNcoord xyz[3] = {dptsA[i].x(), dptsA[i].y(), dptsA[i].z()}; + treeB->annkSearch(xyz, 1, idx, distSq); + if (distSq[0] > maxDistSq) maxDistSq = distSq[0]; + } + return sqrt(maxDistSq); +} +#endif + + +double discreteHausdorffDistanceBrute(const std::vector<SPoint3> &dpts1, + const std::vector<SPoint3> &dpts2) +{ + int i1, j1, i2, j2; + double d1 = oneSidedMaxDist(dpts1, dpts2, i1, j1); + double d2 = oneSidedMaxDist(dpts2, dpts1, i2, j2); + return (d1 > d2) ? d1 : d2; +} + + +double discreteHausdorffDistanceFast(const std::vector<SPoint3> &dpts1, + const std::vector<SPoint3> &dpts2, double tol) +{ +#if defined(HAVE_ANN) + ANNpointArray pts1 = annAllocPts(dpts1.size(), 3); + for (unsigned int k=0; k<dpts1.size(); k++) { + pts1[k][0] = dpts1[k].x(); + pts1[k][1] = dpts1[k].y(); + pts1[k][2] = dpts1[k].z(); + } + ANNkd_tree *tree1 = new ANNkd_tree(pts1, dpts1.size(), 3); + + ANNpointArray pts2 = annAllocPts(dpts2.size(), 3); + for (unsigned int k=0; k<dpts2.size(); k++) { + pts2[k][0] = dpts2[k].x(); + pts2[k][1] = dpts2[k].y(); + pts2[k][2] = dpts2[k].z(); + } + ANNkd_tree *tree2 = new ANNkd_tree(pts2, dpts2.size(), 3); + + double d1 = oneSidedMaxDistFast(dpts1, pts2, tree2, tol); + double d2 = oneSidedMaxDistFast(dpts2, pts1, tree1, tol); + + delete tree1, tree2; + annDeallocPts(pts1); + annDeallocPts(pts2); + + return (d1 > d2) ? d1 : d2; +#else + Msg::Fatal("Gmsh should be compiled using ANN"); +#endif +} + + +template<int distDef> +double discreteDistance(MLine *l, GEdge *ed, double tol, int meshDiscr, int geomDiscr) +{ + if (ed->geomType() == GEntity::Line) return 0.; + + std::vector<SPoint3> dpts1, dpts2; + std::vector<double> ts1, ts2; + + if (geomDiscr == CADDIST_DECASTELJAU) + ed->discretize(tol, dpts1, ts1); + else { + double t0, t1; + reparamMeshVertexOnEdge(l->getVertex(0), ed, t0); + reparamMeshVertexOnEdge(l->getVertex(1), ed, t1); + parametricLineGEdge l1(ed, t0, t1); + l1.discretize(dpts1, ts1, tol, 5, 45); + } + oversample(dpts1, tol); + + if (meshDiscr == CADDIST_DECASTELJAU) + l->discretize(tol, dpts2, ts2); + else { + const nodalBasis &basis = *(l->getFunctionSpace()); + std::vector<SPoint3> xyz; + const int nV = l->getNumVertices(); + for (int i=0; i<nV; ++i) xyz.push_back(l->getVertex(i)->point()); + parametricLineNodalBasis l2(basis, xyz); + int minDepth = std::ceil(std::log(nV)/std::log(2)); + l2.discretize(dpts2, ts2, tol, minDepth, 10*minDepth); + } + oversample(dpts2, tol); +// std::cout << "DBGTT: " << dpts1.size() << " points on model, " << dpts2.size() << " points on mesh\n"; + + switch (distDef) { + case 1: return discreteHausdorffDistanceBrute(dpts1, dpts2); + case 2: return discreteHausdorffDistanceFast(dpts1, dpts2, tol); + case 3: return discreteFrechetDistanceBrute(dpts1, dpts2); + } + return -1.; +} + + +} + + +double discreteHausdorffDistanceBruteEdge(MLine *l, GEdge *ed, double tol, + int meshDiscr, int geomDiscr) +{ + return discreteDistance<1>(l, ed, tol, meshDiscr, geomDiscr); +} + + +double discreteHausdorffDistanceFastEdge(MLine *l, GEdge *ed, double tol, + int meshDiscr, int geomDiscr) +{ + return discreteDistance<2>(l, ed, tol, meshDiscr, geomDiscr); +} + + +double discreteFrechetDistanceEdge(MLine *l, GEdge *ed, double tol, + int meshDiscr, int geomDiscr) +{ + return discreteDistance<3>(l, ed, tol, meshDiscr, geomDiscr); +} + + +// ---------------------------------- Taylor-based distance ---------------------------------- + + +double taylorDistanceSq1D(const GradientBasis *gb, const fullMatrix<double> &nodesXYZ, + const std::vector<SVector3> &tanCAD) +{ + const int nV = nodesXYZ.size1(); + fullMatrix<double> dxyzdX(nV, 3); + gb->getGradientsFromNodes(nodesXYZ, &dxyzdX, 0, 0); +// const double dx = nodesXYZ(1, 0) - nodesXYZ(0, 0), dy = nodesXYZ(1, 1) - nodesXYZ(0, 1), +// dz = nodesXYZ(1, 2) - nodesXYZ(0, 2), h = 0.5*sqrt(dx*dx+dy*dy+dz*dz)/double(nV-1); + double distSq = 0.; + for (int i=0; i<nV; i++) { + SVector3 tanMesh(dxyzdX(i, 0), dxyzdX(i, 1), dxyzdX(i, 2)); + const double h = 0.25*tanMesh.normalize(); // Half of "local edge length" + SVector3 diff = (dot(tanCAD[i], tanMesh) > 0) ? + tanCAD[i] - tanMesh : tanCAD[i] + tanMesh; + distSq += h*h*diff.normSq(); + } + return distSq; +} + + +double taylorDistanceSq2D(const GradientBasis *gb, const fullMatrix<double> &nodesXYZ, + const std::vector<SVector3> &normCAD) +{ + const int nV = nodesXYZ.size1(); + fullMatrix<double> dxyzdX(nV, 3),dxyzdY(nV, 3); + gb->getGradientsFromNodes(nodesXYZ, &dxyzdX, &dxyzdY, 0); + double distSq = 0.; + for (int i=0; i<nV; i++) { + const double nz = dxyzdX(i, 0) * dxyzdY(i, 1) - dxyzdX(i, 1) * dxyzdY(i, 0); + const double ny = -dxyzdX(i, 0) * dxyzdY(i, 2) + dxyzdX(i, 2) * dxyzdY(i, 0); + const double nx = dxyzdX(i, 1) * dxyzdY(i, 2) - dxyzdX(i, 2) * dxyzdY(i, 1); + SVector3 normMesh(nx, ny, nz); + const double h = 0.25*sqrt(normMesh.normalize()); // Half of sqrt of "local area", to be adjusted w.r.t. el. type? + SVector3 diff = (dot(normCAD[i], normMesh) > 0) ? + normCAD[i] - normMesh : normCAD[i] + normMesh; + distSq += h*h*diff.normSq(); + } + return distSq; +} + + +double taylorDistanceEdge(MLine *l, GEdge *ge) +{ + const int nV = l->getNumVertices(); + const GradientBasis *gb = BasisFactory::getGradientBasis(FuncSpaceData(l)); + + // Coordinates of vertices + fullMatrix<double> nodesXYZ(nV, 3); + l->getNodesCoord(nodesXYZ); + + // Tangent to CAD at vertices + std::vector<SVector3> tanCAD(nV); + for (int i=0; i<nV; i++) { + double tCAD; + reparamMeshVertexOnEdge(l->getVertex(i), ge, tCAD); + tanCAD[i] = ge->firstDer(tCAD); + tanCAD[i].normalize(); + } + + // Compute distance + return sqrt(taylorDistanceSq1D(gb, nodesXYZ, tanCAD)); +} + + +double taylorDistanceFace(MElement *el, GFace *gf) +{ + const int nV = el->getNumVertices(); + const GradientBasis *gb = BasisFactory::getGradientBasis(FuncSpaceData(el)); + + // Coordinates of vertices + fullMatrix<double> nodesXYZ(nV, 3); + el->getNodesCoord(nodesXYZ); + + // Normal to CAD at vertices + std::vector<SVector3> normCAD(nV); + for (int i=0; i<nV; i++) { + SPoint2 pCAD; + reparamMeshVertexOnFace(el->getVertex(i), gf, pCAD); + normCAD[i] = gf->normal(pCAD); + normCAD[i].normalize(); + } + + // Compute distance + return sqrt(taylorDistanceSq2D(gb, nodesXYZ, normCAD)); +} + + +// ---------------------------------- General functions ---------------------------------- + + +void distanceFromElementsToGeometry(GModel *gm, int dim, std::map<MElement*,double> &distances) +{ + std::map<MEdge,double,Less_Edge> dist2Edge; + for (GModel::eiter it = gm->firstEdge(); it != gm->lastEdge(); ++it) { + if ((*it)->geomType() == GEntity::Line) continue; + for (unsigned int i = 0; i < (*it)->lines.size(); i++) { + double d = taylorDistanceEdge((*it)->lines[i], *it); + MEdge e = (*it)->lines[i]->getEdge(0); + dist2Edge[e] = d; + } + } + + std::map<MFace,double,Less_Face> dist2Face; + for(GModel::fiter it = gm->firstFace(); it != gm->lastFace(); ++it){ + if ((*it)->geomType() == GEntity::Plane)continue; + for (unsigned int i = 0; i < (*it)->triangles.size(); i++){ + double d = taylorDistanceFace((*it)->triangles[i], *it); + MFace f = (*it)->triangles[i]->getFace(0); + dist2Face[f] = d; + } + } + + std::vector<GEntity*> entities; + gm->getEntities(entities); + for (int iEnt = 0; iEnt < entities.size(); ++iEnt) { + GEntity* &entity = entities[iEnt]; + if (entity->dim() != dim) continue; + for (int iEl = 0; iEl < entity->getNumMeshElements(); iEl++) { // Detect bad elements + MElement *element = entity->getMeshElement(iEl); + double d = 0.; + for (int iEdge = 0; iEdge < element->getNumEdges(); ++iEdge) { + MEdge e = element->getEdge(iEdge); + std::map<MEdge,double,Less_Edge>::iterator it = dist2Edge.find(e); + if (it != dist2Edge.end()) d += it->second; + } + for (int iFace = 0; iFace < element->getNumFaces(); ++iFace) { + MFace f = element->getFace(iFace); + std::map<MFace,double,Less_Face>::iterator it = dist2Face.find(f); + if (it != dist2Face.end()) d += it->second; + } + distances[element] = d; + } + } +} + + +double distanceToGeometry(GModel *gm, int distType, double tol, int meshDiscr, int geomDiscr) +{ + double maxDist = 0.; + + for (GModel::eiter it = gm->firstEdge(); it != gm->lastEdge(); ++it) { + if ((*it)->geomType() == GEntity::Line) continue; + for (unsigned int i = 0; i < (*it)->lines.size(); i++) { + double dist; + switch (distType) { + case CADDIST_TAYLOR: + dist = taylorDistanceEdge((*it)->lines[i], *it); + break; + case CADDIST_FRECHET: + dist = discreteFrechetDistanceEdge((*it)->lines[i], *it, + tol, meshDiscr, geomDiscr); + break; + case CADDIST_HAUSFAST: + dist = discreteHausdorffDistanceFastEdge((*it)->lines[i], *it, + tol, meshDiscr, geomDiscr); + break; + case CADDIST_HAUSBRUTE: + dist = discreteHausdorffDistanceBruteEdge((*it)->lines[i], *it, + tol, meshDiscr, geomDiscr); + break; + default: + Msg::Error("Wrong CAD distance type in distanceToGeometry"); + break; + } + maxDist = std::max(dist, maxDist); + } + } +// printf("DISTANCE TO GEOMETRY : 1D PART %22.15E\n",Obj); + + if (distType == CADDIST_TAYLOR) { + for(GModel::fiter it = gm->firstFace(); it != gm->lastFace(); ++it) { + if ((*it)->geomType() == GEntity::Plane) continue; + for (unsigned int i = 0; i < (*it)->triangles.size(); i++) { + maxDist = std::max(taylorDistanceFace((*it)->triangles[i], *it), maxDist); + } + } + } +// printf("DISTANCE TO GEOMETRY : 1D AND 2D PART %22.15E\n",Obj); + + return maxDist; +} diff --git a/contrib/HighOrderMeshOptimizer/CADDistances.h b/contrib/HighOrderMeshOptimizer/CADDistances.h new file mode 100644 index 0000000000000000000000000000000000000000..fb35f138b9a0f689f59e80938c753fe08ec3c620 --- /dev/null +++ b/contrib/HighOrderMeshOptimizer/CADDistances.h @@ -0,0 +1,43 @@ +// TODO: Header + +#ifndef _CADDISTANCES_H_ +#define _CADDISTANCES_H_ + +#include "fullMatrix.h" +#include <vector> +#include <map> + + +class GradientBasis; +class MLine; +class MElement; +class GEdge; +class GFace; +class SVector3; +class GModel; + + +enum { CADDIST_GEN, CADDIST_DECASTELJAU }; +enum { CADDIST_TAYLOR, CADDIST_FRECHET, CADDIST_HAUSFAST, CADDIST_HAUSBRUTE }; + + +double discreteFrechetDistanceEdge(MLine *l, GEdge *ed, double tol, + int meshDiscr = CADDIST_GEN, int geomDiscr = CADDIST_GEN); +double discreteHausdorffDistanceBruteEdge(MLine *l, GEdge *ed, double tol, + int meshDiscr = CADDIST_GEN, int geomDiscr = CADDIST_GEN); +double discreteHausdorffDistanceFastEdge(MLine *l, GEdge *ed, double tol, + int meshDiscr = CADDIST_GEN, int geomDiscr = CADDIST_GEN); +double taylorDistanceSq1D(const GradientBasis *gb, const fullMatrix<double> &nodesXYZ, + const std::vector<SVector3> &tanCAD); +double taylorDistanceSq2D(const GradientBasis *gb, const fullMatrix<double> &nodesXYZ, + const std::vector<SVector3> &normCAD); +double taylorDistanceEdge(MLine *l, GEdge *ge); +double taylorDistanceFace(MElement *el, GFace *gf); + +void distanceFromElementsToGeometry(GModel *gm, int dim, std::map<MElement*, double> &distances); +double distanceToGeometry(GModel *gm, int distType = CADDIST_TAYLOR, double tol = 1e-3, + int meshDiscr = CADDIST_DECASTELJAU, + int geomDiscr = CADDIST_DECASTELJAU); + + +#endif /* _CADDISTANCES_H_ */ diff --git a/contrib/HighOrderMeshOptimizer/CMakeLists.txt b/contrib/HighOrderMeshOptimizer/CMakeLists.txt index 29223ca3cd54a09fcdeafb1d3fa363c22560a162..768ccb4b4050497ec186b764e97d0a6d9925f3f8 100644 --- a/contrib/HighOrderMeshOptimizer/CMakeLists.txt +++ b/contrib/HighOrderMeshOptimizer/CMakeLists.txt @@ -13,6 +13,7 @@ set(SRC SuperEl.cpp OptHomElastic.cpp OptHomFastCurving.cpp + CADDistances.cpp ) file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.hpp) diff --git a/contrib/HighOrderMeshOptimizer/OptHomCADDist.cpp b/contrib/HighOrderMeshOptimizer/OptHomCADDist.cpp index 5e3d16b0076d037f17173129a13f6c44cd3d9b16..9cd6685fcfd2e1f8e33625d1066f128b3fd487e6 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomCADDist.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHomCADDist.cpp @@ -175,72 +175,72 @@ double MFaceGFaceDistance(MElement *el, GFace *gf) } -void distanceFromElementsToGeometry(GModel *gm, int dim, std::map<MElement*,double> &distances){ - - std::map<MEdge,double,Less_Edge> dist2Edge; - for (GModel::eiter it = gm->firstEdge(); it != gm->lastEdge(); ++it){ - if ((*it)->geomType() == GEntity::Line)continue; - for (unsigned int i=0;i<(*it)->lines.size(); i++){ - double d = MLineGEdgeDistance ( (*it)->lines[i] , *it ); - MEdge e = (*it)->lines[i]->getEdge(0); - dist2Edge[e] = d; - } - } - - // printf("DISTANCE TO GEOMETRY : 1D PART %22.15E\n",Obj); - - std::map<MFace,double,Less_Face> dist2Face; - for(GModel::fiter it = gm->firstFace(); it != gm->lastFace(); ++it){ - if ((*it)->geomType() == GEntity::Plane)continue; - for (unsigned int i=0;i<(*it)->triangles.size(); i++){ - double d = MFaceGFaceDistance ( (*it)->triangles[i] , *it ); - MFace f = (*it)->triangles[i]->getFace(0); - dist2Face[f] = d; - } - } - - std::vector<GEntity*> entities; - gm->getEntities(entities); - for (int iEnt = 0; iEnt < entities.size(); ++iEnt) { - GEntity* &entity = entities[iEnt]; - if (entity->dim() != dim) continue; - for (int iEl = 0; iEl < entity->getNumMeshElements();iEl++) { // Detect bad elements - MElement *element = entity->getMeshElement(iEl); - double d = 0.0; - for (int iEdge = 0; iEdge < element->getNumEdges(); ++iEdge) { - MEdge e = element->getEdge(iEdge); - std::map<MEdge,double,Less_Edge>::iterator it = dist2Edge.find(e); - if(it != dist2Edge.end())d+=it->second; - } - for (int iFace = 0; iFace < element->getNumFaces(); ++iFace) { - MFace f = element->getFace(iFace); - std::map<MFace,double,Less_Face>::iterator it = dist2Face.find(f); - if(it != dist2Face.end())d+=it->second; - } - distances[element] = d; - } - } -} - - -double distanceToGeometry(GModel *gm) -{ - double Obj = 0.0; - - for (GModel::eiter it = gm->firstEdge(); it != gm->lastEdge(); ++it) { - if ((*it)->geomType() == GEntity::Line) continue; - for (unsigned int i=0;i<(*it)->lines.size(); i++) - Obj = std::max(MLineGEdgeDistance((*it)->lines[i], *it), Obj); - } - printf("DISTANCE TO GEOMETRY : 1D PART %22.15E\n",Obj); - - for(GModel::fiter it = gm->firstFace(); it != gm->lastFace(); ++it) { - if ((*it)->geomType() == GEntity::Plane) continue; - for (unsigned int i=0;i<(*it)->triangles.size(); i++) { - Obj = std::max(Obj,MFaceGFaceDistance( (*it)->triangles[i] , *it )); - } - } - printf("DISTANCE TO GEOMETRY : 1D AND 2D PART %22.15E\n",Obj); - - return Obj; -} +//void distanceFromElementsToGeometry(GModel *gm, int dim, std::map<MElement*,double> &distances){ +// +// std::map<MEdge,double,Less_Edge> dist2Edge; +// for (GModel::eiter it = gm->firstEdge(); it != gm->lastEdge(); ++it){ +// if ((*it)->geomType() == GEntity::Line)continue; +// for (unsigned int i=0;i<(*it)->lines.size(); i++){ +// double d = MLineGEdgeDistance ( (*it)->lines[i] , *it ); +// MEdge e = (*it)->lines[i]->getEdge(0); +// dist2Edge[e] = d; +// } +// } +// +// // printf("DISTANCE TO GEOMETRY : 1D PART %22.15E\n",Obj); +// +// std::map<MFace,double,Less_Face> dist2Face; +// for(GModel::fiter it = gm->firstFace(); it != gm->lastFace(); ++it){ +// if ((*it)->geomType() == GEntity::Plane)continue; +// for (unsigned int i=0;i<(*it)->triangles.size(); i++){ +// double d = MFaceGFaceDistance ( (*it)->triangles[i] , *it ); +// MFace f = (*it)->triangles[i]->getFace(0); +// dist2Face[f] = d; +// } +// } +// +// std::vector<GEntity*> entities; +// gm->getEntities(entities); +// for (int iEnt = 0; iEnt < entities.size(); ++iEnt) { +// GEntity* &entity = entities[iEnt]; +// if (entity->dim() != dim) continue; +// for (int iEl = 0; iEl < entity->getNumMeshElements();iEl++) { // Detect bad elements +// MElement *element = entity->getMeshElement(iEl); +// double d = 0.0; +// for (int iEdge = 0; iEdge < element->getNumEdges(); ++iEdge) { +// MEdge e = element->getEdge(iEdge); +// std::map<MEdge,double,Less_Edge>::iterator it = dist2Edge.find(e); +// if(it != dist2Edge.end())d+=it->second; +// } +// for (int iFace = 0; iFace < element->getNumFaces(); ++iFace) { +// MFace f = element->getFace(iFace); +// std::map<MFace,double,Less_Face>::iterator it = dist2Face.find(f); +// if(it != dist2Face.end())d+=it->second; +// } +// distances[element] = d; +// } +// } +//} +// +// +//double distanceToGeometry(GModel *gm) +//{ +// double Obj = 0.0; +// +// for (GModel::eiter it = gm->firstEdge(); it != gm->lastEdge(); ++it) { +// if ((*it)->geomType() == GEntity::Line) continue; +// for (unsigned int i=0;i<(*it)->lines.size(); i++) +// Obj = std::max(MLineGEdgeDistance((*it)->lines[i], *it), Obj); +// } +// printf("DISTANCE TO GEOMETRY : 1D PART %22.15E\n",Obj); +// +// for(GModel::fiter it = gm->firstFace(); it != gm->lastFace(); ++it) { +// if ((*it)->geomType() == GEntity::Plane) continue; +// for (unsigned int i=0;i<(*it)->triangles.size(); i++) { +// Obj = std::max(Obj,MFaceGFaceDistance( (*it)->triangles[i] , *it )); +// } +// } +// printf("DISTANCE TO GEOMETRY : 1D AND 2D PART %22.15E\n",Obj); +// +// return Obj; +//} diff --git a/contrib/HighOrderMeshOptimizer/OptHomCADDist.h b/contrib/HighOrderMeshOptimizer/OptHomCADDist.h index d91deb6f96d689f90426c076090aa2e2fe962092..2354ffa365437d08ab48d2bed718ddf0a798ef13 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomCADDist.h +++ b/contrib/HighOrderMeshOptimizer/OptHomCADDist.h @@ -24,8 +24,8 @@ double distToCAD2D(const GradientBasis *gb, const fullMatrix<double> &nodesXYZ, double MLineGEdgeDistance (MLine *l, GEdge *ge); double MFaceGFaceDistance(MElement *el, GFace *gf); -void distanceFromElementsToGeometry(GModel *gm, int dim, std::map<MElement*, double> &distances); -double distanceToGeometry(GModel *gm); +//void distanceFromElementsToGeometry(GModel *gm, int dim, std::map<MElement*, double> &distances); +//double distanceToGeometry(GModel *gm); #endif /* OPTHOMCADDIST_H_ */ diff --git a/contrib/HighOrderMeshOptimizer/OptHomObjContribCADDist.h b/contrib/HighOrderMeshOptimizer/OptHomObjContribCADDist.h index 7c31c4178e78af8372780b2da3bc1c67167d8fe0..fa4aed8d80368f28c5f60eccaa5b8fcf4f9f0d97 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomObjContribCADDist.h +++ b/contrib/HighOrderMeshOptimizer/OptHomObjContribCADDist.h @@ -7,11 +7,11 @@ template<class FuncType> -class ObjContribCADDist : public ObjContrib, public FuncType +class ObjContribCADDistSq : public ObjContrib, public FuncType { public: - ObjContribCADDist(double weight, double refDist); - virtual ~ObjContribCADDist() {} + ObjContribCADDistSq(double weight, double refDist); + virtual ~ObjContribCADDistSq() {} virtual ObjContrib *copy() const; virtual void initialize(Patch *mesh); virtual bool fail() { return false; } @@ -29,7 +29,7 @@ protected: template<class FuncType> -ObjContribCADDist<FuncType>::ObjContribCADDist(double weight, double refDist) : +ObjContribCADDistSq<FuncType>::ObjContribCADDistSq(double weight, double refDist) : ObjContrib("CADDist", FuncType::getNamePrefix()+"CADDist"), _mesh(0), _weight(weight), _refDist(refDist) { @@ -37,24 +37,24 @@ ObjContribCADDist<FuncType>::ObjContribCADDist(double weight, double refDist) : template<class FuncType> -ObjContrib *ObjContribCADDist<FuncType>::copy() const +ObjContrib *ObjContribCADDistSq<FuncType>::copy() const { - return new ObjContribCADDist<FuncType>(*this); + return new ObjContribCADDistSq<FuncType>(*this); } template<class FuncType> -void ObjContribCADDist<FuncType>::initialize(Patch *mesh) +void ObjContribCADDistSq<FuncType>::initialize(Patch *mesh) { _mesh = mesh; - _mesh->initScaledCADDist(_refDist); + _mesh->initScaledCADDistSq(_refDist); updateMinMax(); FuncType::initialize(_min, _max); } template<class FuncType> -bool ObjContribCADDist<FuncType>::addContrib(double &Obj, alglib::real_1d_array &gradObj) +bool ObjContribCADDistSq<FuncType>::addContrib(double &Obj, alglib::real_1d_array &gradObj) { _min = BIGVAL; _max = -BIGVAL; @@ -65,7 +65,7 @@ bool ObjContribCADDist<FuncType>::addContrib(double &Obj, alglib::real_1d_array const int nVEl = _mesh->nNodBndEl(iBndEl); double f; std::vector<double> gradF(nVEl*bndDim); - _mesh->scaledCADDistAndGradients(iBndEl, f, gradF); + _mesh->scaledCADDistSqAndGradients(iBndEl, f, gradF); _min = std::min(_min, f); _max = std::max(_max, f); Obj += FuncType::compute(f) * _weight; @@ -87,7 +87,7 @@ bool ObjContribCADDist<FuncType>::addContrib(double &Obj, alglib::real_1d_array template<class FuncType> -void ObjContribCADDist<FuncType>::updateMinMax() +void ObjContribCADDistSq<FuncType>::updateMinMax() { _min = BIGVAL; _max = -BIGVAL; @@ -98,7 +98,7 @@ void ObjContribCADDist<FuncType>::updateMinMax() const int nVEl = _mesh->nNodBndEl(iBndEl); double f; std::vector<double> dumGradF(nVEl*bndDim); - _mesh->scaledCADDistAndGradients(iBndEl, f, dumGradF); + _mesh->scaledCADDistSqAndGradients(iBndEl, f, dumGradF); _min = std::min(_min, f); _max = std::max(_max, f); } diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp index 0cd51f319212a06a09d96bc917c769f3ad2b992c..9f6feb58ec450bc0a016ebc5e1af748f668fc035 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp @@ -42,6 +42,7 @@ #include "MHexahedron.h" #include "MPrism.h" #include "MLine.h" +#include "CADDistances.h" #include "OS.h" #include <stack> @@ -586,10 +587,10 @@ static void optimizeOneByOne #include "OptHomIntegralBoundaryDist.h" -double ComputeDistanceToGeometry (GModel* gm) -{ - return distanceToGeometry(gm); -} +//double ComputeDistanceToGeometry (GModel* gm) +//{ +// return distanceToGeometry(gm); +//} double ComputeDistanceToGeometry (GEntity *ge , int distanceDefinition, double tolerance) @@ -691,7 +692,7 @@ void HighOrderMeshOptimizer(GModel *gm, OptHomParameters &p) #include "GEntity.h" //#include "MElement.h" //#include "OptHomRun.h" -#include "OptHomCADDist.h" +#include "CADDistances.h" #include "MeshOptCommon.h" #include "MeshOptObjContribFunc.h" #include "MeshOptObjContrib.h" @@ -756,11 +757,13 @@ double HOPatchDefParameters::bndElBadness(MElement *el, GEntity* gEnt) const if (optCAD) { if (el->getType() == TYPE_LIN) { // 2D if (gEnt->geomType() != GEntity::Line) // Straight geometric line -> no distance - return MLineGEdgeDistance(static_cast<MLine*>(el), gEnt->cast2Edge()); + return optCADDistMax - + taylorDistanceEdge(static_cast<MLine*>(el), gEnt->cast2Edge()); } else { // 3D if (gEnt->geomType() != GEntity::Plane) // Straight geometric plance -> no distance - return MFaceGFaceDistance(el, gEnt->cast2Face()); + return optCADDistMax - + taylorDistanceFace(el, gEnt->cast2Face()); } } return 1.; @@ -803,15 +806,19 @@ void HighOrderMeshOptimizerNew(GModel *gm, OptHomParameters &p) minJacBarFunc.setTarget(p.BARRIER_MIN, 1.); ObjContribScaledJac<ObjContribFuncBarrierFixMinMovMax> minMaxJacBarFunc(1.); minMaxJacBarFunc.setTarget(p.BARRIER_MAX, 1.); - ObjContribCADDist<ObjContribFuncSimpleTargetMax> CADDistFunc(p.optCADWeight, p.optCADDistMax); - CADDistFunc.setTarget(1.); + ObjContribCADDistSq<ObjContribFuncSimpleTargetMax> CADDistFunc(p.optCADWeight, p.optCADDistMax); + CADDistFunc.setTarget(0.); +// ObjContribCADDistSq<ObjContribFuncBarrierMovMax> CADDistFunc(p.optCADWeight, p.optCADDistMax); +// CADDistFunc.setTarget(1., 0.); + ObjContribScaledJac<ObjContribFuncBarrierFixMin> minJacFixBarFunc(1.); + minJacFixBarFunc.setTarget(p.BARRIER_MIN, 1.); MeshOptPass minJacPass; minJacPass.maxParamUpdates = p.optPassMax; minJacPass.maxOptIter = p.itMax; minJacPass.contrib.push_back(&nodeDistFunc); minJacPass.contrib.push_back(&minJacBarFunc); - if (p.optCAD) minJacPass.contrib.push_back(&CADDistFunc); +// if (p.optCAD) minJacPass.contrib.push_back(&CADDistFunc); par.pass.push_back(minJacPass); if (p.BARRIER_MAX > 0.) { @@ -820,10 +827,20 @@ void HighOrderMeshOptimizerNew(GModel *gm, OptHomParameters &p) minMaxJacPass.maxOptIter = p.itMax; minMaxJacPass.contrib.push_back(&nodeDistFunc); minMaxJacPass.contrib.push_back(&minMaxJacBarFunc); - if (p.optCAD) minMaxJacPass.contrib.push_back(&CADDistFunc); +// if (p.optCAD) minMaxJacPass.contrib.push_back(&CADDistFunc); par.pass.push_back(minMaxJacPass); } + if (p.optCAD) { + MeshOptPass maxCADDistPass; + maxCADDistPass.maxParamUpdates = p.optPassMax; + maxCADDistPass.maxOptIter = p.itMax; + maxCADDistPass.contrib.push_back(&nodeDistFunc); + maxCADDistPass.contrib.push_back(&minJacFixBarFunc); + maxCADDistPass.contrib.push_back(&CADDistFunc); + par.pass.push_back(maxCADDistPass); + } + meshOptimizer(gm, par); p.CPU = par.CPU; diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.h b/contrib/HighOrderMeshOptimizer/OptHomRun.h index 56befba458bd5793e29dba930aa6df0bf8ddb661..df3e4601612f30cffa27f3c67e0658a2555c45cd 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomRun.h +++ b/contrib/HighOrderMeshOptimizer/OptHomRun.h @@ -77,6 +77,6 @@ void HighOrderMeshOptimizer(GModel *gm, OptHomParameters &p); void HighOrderMeshOptimizerNew(GModel *gm, OptHomParameters &p); // distanceDefinition 1) Hausdorff 2) Area/Length 3) Frechet (not done) double ComputeDistanceToGeometry (GEntity *ge , int distanceDefinition,double tolerance) ; -double ComputeDistanceToGeometry (GModel*gm); +//double ComputeDistanceToGeometry (GModel*gm); #endif diff --git a/contrib/MeshOptimizer/MeshOptObjContribFunc.cpp b/contrib/MeshOptimizer/MeshOptObjContribFunc.cpp index cd5757325c612de14504b348183341504b061d07..ca67b9630f997e0a5e540025a48a0d37f730e847 100644 --- a/contrib/MeshOptimizer/MeshOptObjContribFunc.cpp +++ b/contrib/MeshOptimizer/MeshOptObjContribFunc.cpp @@ -86,6 +86,13 @@ bool ObjContribFuncBarrierMovMax::stagnated(double vMin, double vMax) } +void ObjContribFuncBarrierFixMin::initialize(double vMin, double vMax) +{ + const double margin = (vMin == 0.) ? _defaultMargin : MARGINCOEFF*fabs(vMin); + _barrier = vMin - margin; +} + + void ObjContribFuncBarrierFixMinMovMax::initialize(double vMin, double vMax) { ObjContribFuncBarrierMovMax::initialize(vMin, vMax); diff --git a/contrib/MeshOptimizer/MeshOptObjContribFunc.h b/contrib/MeshOptimizer/MeshOptObjContribFunc.h index ec12b3fde04ff8bf572bb51e208c19364f541c0f..3f31118654f94347c290ef7e2a766c868e4cd4da 100644 --- a/contrib/MeshOptimizer/MeshOptObjContribFunc.h +++ b/contrib/MeshOptimizer/MeshOptObjContribFunc.h @@ -13,7 +13,7 @@ protected: void initialize(double vMin, double vMax) {} void updateParameters(double vMin, double vMax) {} bool targetReached(double vMin, double vMax) { return true; } - bool stagnated(double vMin, double vMax) { return false; }; + bool stagnated(double vMin, double vMax) { return false; } double compute(double v) { return v; } double computeDiff(double v) { return 1.; } }; @@ -79,6 +79,19 @@ protected: }; +class ObjContribFuncBarrierFixMin : public ObjContribFuncBarrier +{ +protected: + std::string getNamePrefix() { return "BarrierFixMin"; } + void initialize(double vMin, double vMax); + void updateParameters(double vMin, double vMax) {} + bool targetReached(double vMin, double vMax) { return (vMin >= _barrier); } + bool stagnated(double vMin, double vMax) { return false; } + inline double compute(double v); + inline double computeDiff(double v); +}; + + class ObjContribFuncBarrierFixMinMovMax : public ObjContribFuncBarrierMovMax { protected: @@ -134,6 +147,20 @@ inline double ObjContribFuncBarrierMovMax::computeDiff(double v) } +inline double ObjContribFuncBarrierFixMin::compute(double v) +{ + if (v > _barrier) return logBarrier(v, _barrier, _opt); + else return 1e300; +} + + +inline double ObjContribFuncBarrierFixMin::computeDiff(double v) +{ + if (v > _barrier) return diffLogBarrier(v, _barrier, _opt); + else return -1e300; +} + + inline double ObjContribFuncBarrierFixMinMovMax::compute(double v) { double obj; diff --git a/contrib/MeshOptimizer/MeshOptPatch.cpp b/contrib/MeshOptimizer/MeshOptPatch.cpp index 0f657ddf023bcc13e72badf983a200173d1d9d4e..32a8dfb09fb2195b477b3f38c1c1eb7e479cebd7 100644 --- a/contrib/MeshOptimizer/MeshOptPatch.cpp +++ b/contrib/MeshOptimizer/MeshOptPatch.cpp @@ -36,7 +36,8 @@ #include "BasisFactory.h" #include "CondNumBasis.h" #include "OptHomIntegralBoundaryDist.h" -#include "OptHomCADDist.h" +//#include "OptHomCADDist.h" +#include "CADDistances.h" #include "qualityMeasures.h" #include "MeshOptPatch.h" @@ -344,9 +345,9 @@ void Patch::initMetricMin() } -void Patch::initScaledCADDist(double refCADDist) +void Patch::initScaledCADDistSq(double refCADDist) { - _invRefCADDist = 1./refCADDist; + _invRefCADDistSq = 1./(refCADDist*refCADDist); } @@ -565,8 +566,8 @@ bool Patch::bndDistAndGradients(int iEl, double &f, std::vector<double> &gradF, } -void Patch::scaledCADDistAndGradients(int iBndEl, double &scaledDist, - std::vector<double> &gradScaledDist) +void Patch::scaledCADDistSqAndGradients(int iBndEl, double &scaledDist, + std::vector<double> &gradScaledDist) { const std::vector<int> &iV = _bndEl2V[iBndEl], &iFV = _bndEl2FV[iBndEl]; const int nV = iV.size(); @@ -604,8 +605,7 @@ void Patch::scaledCADDistAndGradients(int iBndEl, double &scaledDist, tanCAD[i] = ge->firstDer(tCAD); // Compute tangent at vertex tanCAD[i].normalize(); // Normalize tangent } - const double edLength = _xyz[iV[0]].distance(_xyz[iV[1]]); // Get edge length - scaledDist = _invRefCADDist * distToCAD1D(gb, nodesXYZ, tanCAD, edLength); + scaledDist = _invRefCADDistSq * taylorDistanceSq1D(gb, nodesXYZ, tanCAD); for (int i=0; i<nV; i++) { const int &iFVi = iFV[i]; if (iFVi < 0) continue; // Skip if not free vertex @@ -616,7 +616,8 @@ void Patch::scaledCADDistAndGradients(int iBndEl, double &scaledDist, nodesXYZ(i, 0) = gp.x(); nodesXYZ(i, 1) = gp.y(); nodesXYZ(i, 2) = gp.z(); tanCAD[i] = ge->firstDer(tCAD); // New tangent to CAD at perturbed node tanCAD[i].normalize(); // Normalize new tangent - double sDistDiff = _invRefCADDist * distToCAD1D(gb, nodesXYZ, tanCAD, edLength); // Compute distance with perturbed node + const double sDistDiff = _invRefCADDistSq * + taylorDistanceSq1D(gb, nodesXYZ, tanCAD); // Compute distance with perturbed node gradScaledDist[i] = (sDistDiff-scaledDist) / eps; // Compute gradient nodesXYZ(i, 0) = xS; nodesXYZ(i, 1) = yS; nodesXYZ(i, 2) = zS; // Restore coord. of perturbed node tanCAD[i] = tanCADS; // Restore tan. to CAD at perturbed node @@ -639,7 +640,7 @@ void Patch::scaledCADDistAndGradients(int iBndEl, double &scaledDist, normCAD[i] = gf->normal(pCAD); // Compute normal at vertex normCAD[i].normalize(); // Normalize normal } - scaledDist = _invRefCADDist * distToCAD2D(gb, nodesXYZ, normCAD); + scaledDist = _invRefCADDistSq * taylorDistanceSq2D(gb, nodesXYZ, normCAD); for (int i=0; i<nV; i++) { const int &iFVi = iFV[i]; if (iFVi < 0) continue; // Skip if not free vertex @@ -650,14 +651,16 @@ void Patch::scaledCADDistAndGradients(int iBndEl, double &scaledDist, nodesXYZ(i, 0) = gp0.x(); nodesXYZ(i, 1) = gp0.y(); nodesXYZ(i, 2) = gp0.z(); normCAD[i] = gf->normal(pCAD0); // New normal to CAD at perturbed node in 1st dir. normCAD[i].normalize(); // Normalize new normal - double sDistDiff0 = _invRefCADDist * distToCAD2D(gb, nodesXYZ, normCAD); // Compute distance with perturbed node in 1st dir. + const double sDistDiff0 = _invRefCADDistSq * + taylorDistanceSq2D(gb, nodesXYZ, normCAD); // Compute distance with perturbed node in 1st dir. gradScaledDist[2*i] = (sDistDiff0-scaledDist) / eps0; // Compute gradient in 1st dir. const SPoint2 pCAD1 = SPoint2(_uvw[iFVi].x(), _uvw[iFVi].y()+eps1); // New param. coord. of perturbed node in 2nd dir. GPoint gp1 = gf->point(pCAD1); // New coord. of perturbed node in 2nd dir. nodesXYZ(i, 0) = gp1.x(); nodesXYZ(i, 1) = gp1.y(); nodesXYZ(i, 2) = gp1.z(); normCAD[i] = gf->normal(pCAD1); // New normal to CAD at perturbed node in 2nd dir. normCAD[i].normalize(); // Normalize new normal - double sDistDiff1 = _invRefCADDist * distToCAD2D(gb, nodesXYZ, normCAD); // Compute distance with perturbed node in 2nd dir. + double sDistDiff1 = _invRefCADDistSq * + taylorDistanceSq2D(gb, nodesXYZ, normCAD); // Compute distance with perturbed node in 2nd dir. gradScaledDist[2*i+1] = (sDistDiff1-scaledDist) / eps0; // Compute gradient in 2nd dir. nodesXYZ(i, 0) = xS; nodesXYZ(i, 1) = yS; nodesXYZ(i, 2) = zS; // Restore coord. of perturbed node normCAD[i] = tanCADS; // Restore tan. to CAD at perturbed node diff --git a/contrib/MeshOptimizer/MeshOptPatch.h b/contrib/MeshOptimizer/MeshOptPatch.h index e0d7fb1bc98647a8be321705d12d204a2565ab99..baa3b0b7b2dc4f780a487e80e8db2825c499d1bf 100644 --- a/contrib/MeshOptimizer/MeshOptPatch.h +++ b/contrib/MeshOptimizer/MeshOptPatch.h @@ -95,9 +95,9 @@ public: void initMetricMin(); void metricMinAndGradients(int iEl, std::vector<double> &sJ, std::vector<double> &gSJ); bool bndDistAndGradients(int iEl, double &f, std::vector<double> &gradF, double eps); - void initScaledCADDist(double refCADDist); - void scaledCADDistAndGradients(int iBndEl, double &scaledDist, - std::vector<double> &gradScaledDist); + void initScaledCADDistSq(double refCADDist); + void scaledCADDistSqAndGradients(int iBndEl, double &scaledDist, + std::vector<double> &gradScaledDist); // Mesh quality inline const int &nIJacEl(int iEl) { return _nIJacEl[iEl]; } @@ -158,7 +158,7 @@ private: std::vector<MElement*> _bndEl; // Boundary elements std::vector<std::vector<int> > _bndEl2V, _bndEl2FV; // Vertices & corresponding free vertices on the boundary elements std::vector<GEntity*> _bndEl2Ent; // Geometric entities corresponding to the boundary elements - double _invRefCADDist; + double _invRefCADDistSq; void calcNormalEl2D(int iEl, NormalScaling scaling, fullMatrix<double> &elNorm, bool ideal); diff --git a/wrappers/gmshpy/gmshMesh.i b/wrappers/gmshpy/gmshMesh.i index 361cfed3e9c4ef1aa06fb98b0df7cb4bda1579fb..92ae6e7c0aa88b78e633ae513c27bb35d2f6f953 100644 --- a/wrappers/gmshpy/gmshMesh.i +++ b/wrappers/gmshpy/gmshMesh.i @@ -19,6 +19,7 @@ #include "OptHomElastic.h" #include "OptHomFastCurving.h" #include "MeshQualityOptimizer.h" + #include "CADDistances.h" #endif #if defined(HAVE_METIS) || defined(HAVE_CHACO) #include "meshPartition.h" @@ -59,6 +60,7 @@ namespace std { %include "OptHomElastic.h" %include "OptHomFastCurving.h" %include "MeshQualityOptimizer.h" +%include "CADDistances.h" #endif #if defined(HAVE_METIS) || defined(HAVE_CHACO) %include "meshPartition.h"