diff --git a/Mesh/delaunay3d.cpp b/Mesh/delaunay3d.cpp index 99c7813a3a7114a7489abf33bdc4f27731cfa808..e6d4b668a420f6ce5dab751d1c9d639d68285c97 100644 --- a/Mesh/delaunay3d.cpp +++ b/Mesh/delaunay3d.cpp @@ -23,6 +23,7 @@ #include "MVertex.h" #include "MEdge.h" #include "MTetrahedron.h" +#include "qualityMeasures.h" #include "meshGRegionLocalMeshMod.h" #if defined(_HAVE_NUMA) @@ -31,6 +32,22 @@ //int Tet::in_sphere_counter = 0; +#define SQR(X) (X)*(X) + +inline double tetQuality (Vert *vx0,Vert *vx1,Vert *vx2,Vert *vx3, double *volume) +{ + return qmTetrahedron::gamma (vx0->x(),vx0->y(),vx0->z(), + vx1->x(),vx1->y(),vx1->z(), + vx2->x(),vx2->y(),vx2->z(), + vx3->x(),vx3->y(),vx3->z(),volume); +} + +double tetQuality (Tet* t, double *volume) +{ + return tetQuality(t->V[0],t->V[1],t->V[2],t->V[3], volume); +} + + struct HilbertSortB { // The code for generating table transgc from: @@ -332,9 +349,12 @@ void computeAdjacencies (Tet *t, int iFace, connContainer &faceToTet) ************************************************************************/ static int edges[6][2] = {{0,1},{0,2},{0,3},{1,2},{1,3},{2,3}}; -static int efaces[6][2] = {{0,2},{0,1},{1,2},{0,3},{2,3},{1,3}}; -static int faces[4][3] = {{0,1,2},{0,2,3},{0,1,3},{1,2,3}}; -//static int vnofaces[4] = {3,1,2,0}; +//static int efaces[6][2] = {{0,2},{0,1},{1,2},{0,3},{2,3},{1,3}}; +//static int faces[4][3] = {{0,1,2},{0,2,3},{0,1,3},{1,2,3}}; +static int efaces[6][2] = {{0,3},{0,2},{2,3},{0,1},{1,3},{1,2}}; +static int faces[4][3] = {{0,1,2},{1,3,2},{2,3,0},{1,0,3}}; +static int fnovert[4] = {1,2,3,0}; + //static int vFac[4][3] = {{0,1,2},{0,2,3},{0,1,3},{1,2,3}}; static void computeNeighboringTetsOfACavity(const std::vector<Tet*> &cavity, @@ -352,6 +372,66 @@ static void computeNeighboringTetsOfACavity(const std::vector<Tet*> &cavity, } } +void printtet (const char *c, Tet *t){ + printf("%s ",c); + + if (t->V[0]) + printf("%7d %7d %7d %7d \n", + t->V[0]->getNum(), + t->V[1]->getNum(), + t->V[2]->getNum(), + t->V[3]->getNum()); + +} + +static bool buildVertexCavity(Vert *v, std::vector<Tet*> &cavity, std::stack<Tet*> &_stack) +{ + // _stack.clear(); + + Tet *t = v->getT(); + if (!t){ + // Msg::Error("Vertex with no tet connected"); + return false; + } + // std::stack<Tet*> _stack; + _stack.push (t); + while (!_stack.empty()){ + t = _stack.top(); + _stack.pop(); + if (std::find(cavity.begin(), cavity.end(),t) == cavity.end()){ + cavity.push_back(t); + int i; + for (i=0;i<4;i++){ + if (t->V[i] == v)break; + } + if (i == 4){ + Msg::Error("Error in Vertex Cavity"); + while (!_stack.empty())_stack.pop(); + return false; + } + + if (cavity.size() > 1000){ + Msg::Error("Error in Vertex Cavity (too big)"); + while (!_stack.empty())_stack.pop(); + return false; + } + + + for (int j=0;j<4;j++){ + if (j!=fnovert[i]){ + if (t->T[j])_stack.push(t->T[j]); + else { + while (!_stack.empty())_stack.pop(); + return false; + } + } + } + } + } + return true; +} + + static bool buildEdgeCavity(Tet *t, int iLocalEdge, Vert **v1, Vert **v2, std::vector<Tet*> &cavity, @@ -363,15 +443,20 @@ static bool buildEdgeCavity(Tet *t, int iLocalEdge, *v1 = t->V[edges[iLocalEdge][0]]; *v2 = t->V[edges[iLocalEdge][1]]; - + // the 5 - i th edge contains the other 2 points of the tet Vert *lastinring = t->V[edges[5 - iLocalEdge][0]]; + ring.push_back(lastinring); cavity.push_back(t); + // printf("edge %d %d \n",(*v1)->getNum(),(*v2)->getNum()); + /// printtet ("first", t); + while (1){ Vert *ov1 = t->V[edges[5 - iLocalEdge][0]]; Vert *ov2 = t->V[edges[5 - iLocalEdge][1]]; + // printf("%p %p %p %p\n",t->V[0],t->V[1],t->V[2],t->V[3]); int K = ov1 == lastinring ? 1 : 0; lastinring = ov1 == lastinring ? ov2 : ov1; // look in the 2 faces sharing this edge the one that has vertex @@ -388,10 +473,14 @@ static bool buildEdgeCavity(Tet *t, int iLocalEdge, else { Msg::Error("Error of connexion"); return false; } t=t->T[iFace]; if (!t) return false; + // printf("xh\n"); + // printtet ("next", t); + // printf("ams\n"); if (!t->V[0]){ Msg::Error("Weird!!"); return false; } if (t == cavity[0]) break; ring.push_back(lastinring); cavity.push_back(t); + if (cavity.size() > 8)return false; iLocalEdge = -1; for (int i = 0; i < 6; i++){ Vert *a = t->V[edges[i][0]]; @@ -402,17 +491,25 @@ static bool buildEdgeCavity(Tet *t, int iLocalEdge, } } if (iLocalEdge == -1){ - Msg::Error("loc = %d", iLocalEdge); + for (int i = 0; i < 6; i++){ + Vert *a = t->V[edges[i][0]]; + Vert *b = t->V[edges[i][1]]; + printf ("%d %d vs. %d %d\n",a->getNum(),b->getNum(),(*v1)->getNum(),(*v2)->getNum()); + } + // getchar(); + Msg::Error("loc = %d size %lu", iLocalEdge, cavity.size()); return false; } } + + // printf("%d elements of the cavity\n",cavity.size()); computeNeighboringTetsOfACavity (cavity,outside); + // for (int i=0;i<outside.size();++i)printtet("outside",outside[i]); + // getchar(); return true; } -#define SQR(X) (X)*(X) - -bool edgeSwap(Tet *tet, int iLocalEdge, tetContainer &T, int myThread) +static bool edgeSwap(Tet *tet, int iLocalEdge, tetContainer &T, int myThread) { std::vector<Tet*> cavity; std::vector<Tet*> outside; @@ -422,6 +519,7 @@ bool edgeSwap(Tet *tet, int iLocalEdge, tetContainer &T, int myThread) bool closed = buildEdgeCavity(tet, iLocalEdge, &v1, &v2, cavity, outside, ring); if (!closed) return false; + // return false; SwapPattern sp; switch (ring.size()){ @@ -434,55 +532,38 @@ bool edgeSwap(Tet *tet, int iLocalEdge, tetContainer &T, int myThread) } double tetQualityRef = 1.e22; + double volumeOld = 0, volume; for (unsigned int i = 0; i < cavity.size(); i++){ - Vert *vx0 = cavity[i]->V[0]; - Vert *vx1 = cavity[i]->V[1]; - Vert *vx2 = cavity[i]->V[2]; - Vert *vx3 = cavity[i]->V[3]; - double volume = robustPredicates::orient3d((double*)vx0, (double*)vx1, (double*)vx2, (double*)vx3); - const double a = - SQR (vx0->x() - vx1->x()) + SQR (vx0->y() - vx1->y()) + SQR (vx0->z() - vx1->z()) + - SQR (vx0->x() - vx2->x()) + SQR (vx0->y() - vx2->y()) + SQR (vx0->z() - vx2->z()) + - SQR (vx0->x() - vx3->x()) + SQR (vx0->y() - vx3->y()) + SQR (vx0->z() - vx3->z()) + - SQR (vx1->x() - vx2->x()) + SQR (vx1->y() - vx2->y()) + SQR (vx1->z() - vx2->z()) + - SQR (vx1->x() - vx3->x()) + SQR (vx1->y() - vx3->y()) + SQR (vx1->z() - vx3->z()) + - SQR (vx2->x() - vx3->x()) + SQR (vx2->y() - vx3->y()) + SQR (vx2->z() - vx3->z()) ; - tetQualityRef = std::min(tetQualityRef, volume / a); + tetQualityRef = std::min(tetQualityRef, tetQuality (cavity[i], &volume)); + volumeOld += volume; } // compute qualities of all tets that appear in the patterns double tetQuality1[100], tetQuality2[100]; + double volume1[100], volume2[100]; for (int i = 0; i < sp.nbr_triangles; i++){ // FIXME VERIFY ORIENTATION OF TRIANGULAR PATTERNS int p1 = sp.triangles[i][0]; int p2 = sp.triangles[i][1]; int p3 = sp.triangles[i][2]; - const double volume1 = robustPredicates::orient3d((double*)ring[p1], (double*)ring[p2], (double*)ring[p3], (double*) v1); - const double volume2 = robustPredicates::orient3d((double*)ring[p1], (double*)ring[p2], (double*)ring[p3], (double*) v2); - const double a12 = SQR (ring[p1]->x() - ring[p2]->x())+SQR (ring[p1]->y() - ring[p2]->y())+SQR (ring[p1]->z() - ring[p2]->z()); - const double a13 = SQR (ring[p1]->x() - ring[p3]->x())+SQR (ring[p1]->y() - ring[p3]->y())+SQR (ring[p1]->z() - ring[p3]->z()); - const double a23 = SQR (ring[p2]->x() - ring[p3]->x())+SQR (ring[p2]->y() - ring[p3]->y())+SQR (ring[p2]->z() - ring[p3]->z()); - const double a123 = a12 + a13 + a23; - const double v11 = SQR (ring[p1]->x() - v1->x())+SQR (ring[p1]->y() - v1->y())+SQR (ring[p1]->z() - v1->z()); - const double v12 = SQR (ring[p2]->x() - v1->x())+SQR (ring[p2]->y() - v1->y())+SQR (ring[p2]->z() - v1->z()); - const double v13 = SQR (ring[p3]->x() - v1->x())+SQR (ring[p3]->y() - v1->y())+SQR (ring[p3]->z() - v1->z()); - const double v21 = SQR (ring[p1]->x() - v2->x())+SQR (ring[p1]->y() - v2->y())+SQR (ring[p1]->z() - v2->z()); - const double v22 = SQR (ring[p2]->x() - v2->x())+SQR (ring[p2]->y() - v2->y())+SQR (ring[p2]->z() - v2->z()); - const double v23 = SQR (ring[p3]->x() - v2->x())+SQR (ring[p3]->y() - v2->y())+SQR (ring[p3]->z() - v2->z()); - tetQuality1[i] = volume1 / (a123 + v11 + v12 + v13); - tetQuality2[i] = volume2 / (a123 + v21 + v22 + v23); + tetQuality1[i] = tetQuality (ring[p1],ring[p2],ring[p3],v1,&volume1[i]); + tetQuality2[i] = tetQuality (ring[p3],ring[p2],ring[p1],v2,&volume2[i]); } - + // look for the best triangulation, i.e. the one that maximize the // minimum element quality double minQuality[100]; + double volumes[100]; // for all triangulations for (int i = 0; i < sp.nbr_trianguls; i++){ + volumes[i] = 0; // for all triangles in a triangulation minQuality[i] = 1.e22; for (int j = 0; j < sp.nbr_triangles_2; j++){ int iT = sp.trianguls[i][j]; + // if (ring.size() == 5)printf("triangulation %d triangle %d qualities %g %g\n",i,j,tetQuality1[iT],tetQuality2[iT]); minQuality[i] = std::min(minQuality[i], std::min (tetQuality1[iT],tetQuality2[iT])); + volumes[i] += volume1[iT] + volume2[iT]; } } @@ -495,7 +576,12 @@ bool edgeSwap(Tet *tet, int iLocalEdge, tetContainer &T, int myThread) } } + if (fabs(volumes[iBest] - volumeOld) > 1.e-14*volumeOld){ + // printf("NOPE --> RING %d BEST %12.5E INITIAL %12.5E VOLS %12.5E %12.5E\n",ring.size(),best, tetQualityRef,volumes[iBest],volumeOld); + return false; + } if (best <= tetQualityRef) return false; + // printf("RING %d BEST %12.5E INITIAL %12.5E VOLS %12.5E %12.5E\n",ring.size(),best, tetQualityRef,volumes[iBest],volumeOld); unsigned int counter = 0; for (int j = 0; j < sp.nbr_triangles_2; j++){ @@ -513,8 +599,10 @@ bool edgeSwap(Tet *tet, int iLocalEdge, tetContainer &T, int myThread) if (counter < cavity.size()) nt2 = cavity[counter++]; else nt2 = T.newTet(myThread); - nt1->setVertices(pv1, pv2, pv3, v1); - nt2->setVertices(pv3, pv2, pv3, v1); + nt1->setVertices(pv1, pv2, pv3, v2); + nt2->setVertices(pv1, pv3, pv2, v1); + nt1->T[0] = nt1->T[1] = nt1->T[2] = nt1->T[3] = NULL; + nt2->T[0] = nt2->T[1] = nt2->T[2] = nt2->T[3] = NULL; outside.push_back(nt1); outside.push_back(nt2); @@ -523,18 +611,116 @@ bool edgeSwap(Tet *tet, int iLocalEdge, tetContainer &T, int myThread) for(unsigned int i = counter; i < cavity.size(); i++) cavity[i]->V[0] = NULL; connContainer ctnr; - for(unsigned int i = 0; i < outside.size(); i++) - for (int j=0;j<4;j++) + for(unsigned int i = 0; i < outside.size(); i++){ + for (int j=0;j<4;j++){ computeAdjacencies (outside[i],j,ctnr); - + } + } + return true; } -/* -static void edgeSwapPass (tetContainer &T) +static bool relocateVertex (Vert* v, std::vector<Tet*> &cavity){ + + double x=0, y=0, z=0; + double minQual = 1.0; + double volumeOld = 0, volume; + for (unsigned int i=0;i<cavity.size();i++){ + minQual = std::min(minQual, tetQuality(cavity[i], &volume)); + volumeOld += volume; + for (unsigned int j=0;j<4;j++){ + x += cavity[i]->V[j]->x(); + y += cavity[i]->V[j]->y(); + z += cavity[i]->V[j]->z(); + } + } + if (minQual > 0.3)return false; + x /= 4.*cavity.size(); + y /= 4.*cavity.size(); + z /= 4.*cavity.size(); + double oldX=v->x(), oldY=v->y(), oldZ=v->z(); + v->x()=x, v->y()=y, v->z()=z; + // double minQualNew = 1.0; + double volumeNew = 0; + for (unsigned int i=0;i<cavity.size();i++){ + if ( tetQuality(cavity[i], &volume) < minQual){ + v->x()=oldX, v->y()=oldY, v->z()=oldZ; + return false; + } + volumeNew += volume; + } + + if (fabs(volumeNew-volumeOld) < 1.e-14*volumeOld) { + return true; + } + v->x()=oldX, v->y()=oldY, v->z()=oldZ; + return false; + +} + +static bool relocateVertex (Vert* v, std::stack<Tet*> &_work, std::vector<Tet*> &cavity){ + cavity.clear(); + if (buildVertexCavity(v, cavity, _work)){ + return relocateVertex (v, cavity); + } + return false; +} + +void vertexRelocationPass (int numThreads, std::vector<Vert*> &v){ + + int N = 0; + int iter = 0; + std::stack<Tet*> _work; + std::vector<Tet*> _work2; + while (1){ + for (unsigned int i=0;i<v.size();i++){ + if (relocateVertex (v[i],_work, _work2))N++; + } + // printf("done\n"); + if (!N)break; + if (iter++ >= 0)break; + } + +} + + +void edgeSwapPass (int numThreads, tetContainer &allocator, edgeContainer &embeddedEdges) { + edgeContainer ec; + while(1){ + int N = 0; + for (int myThread=0; myThread < numThreads; myThread++) { + int NNN = allocator.size(myThread); + for (unsigned int i=0;i<NNN;i++){ + // printf("%d %d\n",NNN,i); + Tet *t = allocator(myThread,i); + if (t->V[0]){ + double vol; + if (tetQuality (t,&vol) < 0.3){ + for (int j=0;j<6;j++){ + int iLocalEdge = j; + Edge e (t->V[edges[iLocalEdge][0]], t->V[edges[iLocalEdge][1]]); + if (! embeddedEdges.find(e) && !ec.find(e)){ + ec.addNewEdge(e); + bool result = edgeSwap(t, iLocalEdge, allocator, myThread); + if (result){ + N++; + j=6; + break; + } + } + else{ + // printf("cannot swop\n"); + } + } + } + } + } + } + if (!N) break; + } } -*/ + /* Fixing a non star shaped cavity (non delaunay triangulations) @@ -908,6 +1094,7 @@ static Tet* randomTet (int thread, tetContainer &allocator) int isCavityCompatibleWithEmbeddedEdges(cavityContainer &cavity, connContainer &bndK, edgeContainer &allEmbeddedEdges){ + // return true; const unsigned int bSize = bndK.size(); std::vector<Edge> ed; diff --git a/Mesh/delaunay3d_private.h b/Mesh/delaunay3d_private.h index 45db65b4c2e7a42add9ef41f1a28f8f4e501fa42..f1b82ffa4e313c961ba99f947861738add12ab70 100644 --- a/Mesh/delaunay3d_private.h +++ b/Mesh/delaunay3d_private.h @@ -20,13 +20,17 @@ #endif typedef unsigned char CHECKTYPE; +struct Tet; struct Vert { private : double _x[3]; double _lc; unsigned int _num; + Tet *_t; public : + inline void setT(Tet*t) { _t = t;} + inline Tet* getT() const { return _t;} inline unsigned int getNum () const {return _num;} inline void setNum (unsigned int n) {_num=n;} unsigned char _thread; @@ -40,7 +44,7 @@ public : inline double &lc() {return _lc;} inline operator double *() { return _x; } Vert (double X=0, double Y=0, double Z=0, double lc=0, int num = 0) - : _num(num), _thread(0) + : _num(num),_t(NULL), _thread(0) { _x[0] = X; _x[1] = Y; _x[2] = Z; _lc = lc; } @@ -223,6 +227,7 @@ struct Tet { { _modified=true; V[0] = v0; V[1] = v1; V[2] = v2; V[3] = v3; + for (int i=0;i<4;i++)if (V[i])V[i]->setT(this); // for (int i=0;i<4;i++)_copy[i] = *V[i]; return 1; } @@ -232,6 +237,7 @@ struct Tet { double val = robustPredicates::orient3d((double*)v0, (double*)v1, (double*)v2, (double*)v3); V[0] = v0; V[1] = v1; V[2] = v2; V[3] = v3; + for (int i=0;i<4;i++)if (V[i])V[i]->setT(this); if (val > 0){ // for (int i=0;i<4;i++)_copy[i] = *V[i]; return 1; @@ -397,6 +403,7 @@ void delaunayTrgl(const unsigned int numThreads, unsigned int Npts, std::vector<Vert*> assignTo[], tetContainer &allocator, edgeContainer *embedded = 0); -bool edgeSwap(Tet *tet, int iLocalEdge, tetContainer &T, int myThread); +void edgeSwapPass (int numThreads, tetContainer &allocator, edgeContainer &embeddedEdges); +void vertexRelocationPass (int numThreads, std::vector<Vert*> &v); #endif diff --git a/Mesh/delaunay_refinement.cpp b/Mesh/delaunay_refinement.cpp index 93ed5524402eecacdc2e7cc3216be9b4f202dfed..1b0bd9b5a7999d3ede129e923c3244bb52c5f186 100644 --- a/Mesh/delaunay_refinement.cpp +++ b/Mesh/delaunay_refinement.cpp @@ -142,20 +142,10 @@ void saturateEdge(Edge &e, std::vector<Vert*> &S, std::stack<IPT> &temp) bgm = fields->get(fields->getBackgroundField()); } - if (0){ - const double length = p1.distance(p2); - const double lc_avg = (e.first->lc() + e.second->lc())*.5; - const double l_adim_approx = length / lc_avg; - if (l_adim_approx > 10.){ - SPoint3 pmid = (p1+p2)*0.5; - const double lc = GMSHSIZE(pmid, bgm, lc_avg); - S.push_back(new Vert(pmid.x(),pmid.y(),pmid.z(),lc)); - return; - } - } - // double _a = Cpu(); + // printf("%g %g \n",e.first->lc(), e.second->lc()); + const double dN = adaptiveTrapezoidalRule(p1,p2,e.first->lc(), e.second->lc(), _result, dl, temp, bgm); // _C1 += Cpu() - _a; @@ -449,15 +439,25 @@ void computeMeshSizes (GRegion *gr, std::map<MVertex*, double> &s){ updateSize ((*it)->triangles[i]->getVertex((j+1)%3), s, d); } } - } + } + // there may be steiner points + for (unsigned int i=0;i<gr->tetrahedra.size();i++){ + for (unsigned int j = 0; j < 4; j++){ + MVertex *v = gr->tetrahedra[i]->getVertex(j); + if (s.find(v) == s.end()){ + s[v] = 1.0; + } + } + } } +extern double tetQuality (Tet* t, double *volume); + void edgeBasedRefinement(const int numThreads, const int nptsatonce, GRegion *gr) { // fill up old Datastructures - edgeContainer embeddedEdges (10000); std::map<MVertex*, double> sizes; @@ -525,7 +525,6 @@ void edgeBasedRefinement(const int numThreads, } } - // do not allow to saturate boundary edges { for (unsigned int i=0;i< allocator.size(0);i++) { @@ -550,7 +549,6 @@ void edgeBasedRefinement(const int numThreads, for (unsigned int i=0;i<_vertices.size();i++){ _filter.insert( _vertices[i] ); } - int iter = 1; Msg::Info("------------------------------------- SATUR FILTR SORTH DELNY TIME TETS"); @@ -561,10 +559,10 @@ void edgeBasedRefinement(const int numThreads, double t1 = Cpu(); // C_COUNT = 0; saturateEdges (ec, allocator, numThreads, add); - // printf("%d calls %d points added",C_COUNT,add.size()); + // printf("%d points added",add.size()); double t2 = Cpu(); filterVertices (numThreads, _filter, add); - // printf(" %d points remain\n",add.size()); + // printf(" %d points remain\n",add.size()); double t3 = Cpu(); if (add.empty())break; // randomize vertices (EXTREMELY IMPORTANT FOR NOT DETERIORATING PERFORMANCE) @@ -572,6 +570,7 @@ void edgeBasedRefinement(const int numThreads, // sort them using BRIO std::vector<int> indices; SortHilbert(add, indices); + // printf("%d indices\n",indices.size()); double t4 = Cpu(); delaunayTrgl (1,1,add.size(), &add,allocator,embeddedEdges.empty() ? NULL : &embeddedEdges); double t5 = Cpu(); @@ -588,12 +587,45 @@ void edgeBasedRefinement(const int numThreads, } } - - + std::vector<Vert*> vv; + for (int myThread=0; myThread < numThreads; myThread++) + for (unsigned int i=0;i<allocator.size(myThread);i++) + for (unsigned int j=0;j<4;j++) + if (allocator(myThread,i)->V[j]) + allocator(myThread,i)->V[j]->setNum(0); + + for (int myThread=0; myThread < numThreads; myThread++) + for (unsigned int i=0;i<allocator.size(myThread);i++) + for (unsigned int j=0;j<4;j++) + if (allocator(myThread,i)->V[j] && allocator(myThread,i)->V[j]->getNum() == 0){ + allocator(myThread,i)->V[j]->setNum(1); + std::map<Vert*,MVertex*>::iterator it = _ma.find(allocator(myThread,i)->V[j]); + if (it == _ma.end())vv.push_back(allocator(myThread,i)->V[j]); + } + + double t6 = Cpu(); + Msg::Info("Optimizing"); + edgeSwapPass (numThreads, allocator, embeddedEdges); + vertexRelocationPass (numThreads,vv); + edgeSwapPass (numThreads, allocator, embeddedEdges); + vertexRelocationPass (numThreads,vv); + edgeSwapPass (numThreads, allocator, embeddedEdges); + vertexRelocationPass (numThreads,vv); + double t7 = Cpu(); + + Msg::Info("Optimization done (%g seconds)",t7-t6); + + int cat [10] = {0,0,0,0,0,0,0,0,0,0}; + double MIN = 1.0; + for (unsigned int i=0; i< allocator.size(0);i++){ Tet *tt = allocator (0,i); MVertex *mvs[4]; if (tt->V[0]){ + double vol; + double q = tetQuality (tt,&vol); + cat [(int)(q*10)] ++; + MIN = std::min(MIN,q); for (int j=0;j<4;j++){ Vert *v = tt->V[j]; std::map<Vert*,MVertex*>::iterator it = _ma.find(v); @@ -609,6 +641,11 @@ void edgeBasedRefinement(const int numThreads, } } + Msg::Info ("Min Tet Quality %22.15E",MIN); + for (int i=0;i<10;i++){ + Msg::Info ("Tet Quality [%4.3f,%4.3f] %8d",0.1*i,0.1*(i+1),cat[i]); + } + if (Msg::GetVerbosity() == 99) { std::map<Edge,double> _sizes; for (unsigned int i=0; i< allocator.size(0);i++){ @@ -638,4 +675,6 @@ void edgeBasedRefinement(const int numThreads, Msg::Info("MESH EFFICIENCY : %22.15E %6d edges among %d are out of range", exp (sum / _sizes.size()),nbBad,_sizes.size()); } + + } diff --git a/Mesh/meshGRegionBoundaryRecovery.cpp b/Mesh/meshGRegionBoundaryRecovery.cpp index 0a5ec9e1b400ac045dbd8f68cce52a8d8ed30710..469b6e638878c1db3a26e3a107e5cb14a829dc2d 100644 --- a/Mesh/meshGRegionBoundaryRecovery.cpp +++ b/Mesh/meshGRegionBoundaryRecovery.cpp @@ -107,7 +107,7 @@ bool tetgenmesh::reconstructmesh(void *p) double t_start = Cpu(); std::vector<MVertex*> _vertices; - + std::map<int,MVertex*> _extras; // Get the set of vertices from GRegion. { std::set<MVertex*, MVertexLessThanNum> all; @@ -526,6 +526,7 @@ bool tetgenmesh::reconstructmesh(void *p) clock_t t; // printf("coucou2\n"); + Msg::Info("Boundary Recovery..."); recoverboundary(t); // printf("coucou3\n"); @@ -651,7 +652,7 @@ bool tetgenmesh::reconstructmesh(void *p) } v->setIndex(pointmark(pointloop)); _gr->mesh_vertices.push_back(v); - _vertices.push_back(v); + _extras[pointmark(pointloop)] = v; } spivot(parentseg, parentsh); if (parentsh.sh != NULL) { @@ -675,7 +676,7 @@ bool tetgenmesh::reconstructmesh(void *p) } v->setIndex(pointmark(pointloop)); _gr->mesh_vertices.push_back(v); - _vertices.push_back(v); + _extras[pointmark(pointloop)] = v; } } // Record all the GFaces' tag at this segment. @@ -690,9 +691,8 @@ bool tetgenmesh::reconstructmesh(void *p) // Create an interior mesh vertex. MVertex *v = new MVertex(pointloop[0], pointloop[1], pointloop[2], _gr); v->setIndex(pointmark(pointloop)); - _gr->mesh_vertices.push_back(v); - _vertices.push_back(v); - } + _extras[pointmark(pointloop)] = v; + _gr->mesh_vertices.push_back(v); } } else if (pointtype(pointloop) == FREEFACETVERTEX) { sdecode(point2sh(pointloop), parentsh); @@ -718,29 +718,34 @@ bool tetgenmesh::reconstructmesh(void *p) } v->setIndex(pointmark(pointloop)); _gr->mesh_vertices.push_back(v); - _vertices.push_back(v); + _extras[pointmark(pointloop)] = v; } else { // Create a mesh vertex. MVertex *v = new MVertex(pointloop[0], pointloop[1], pointloop[2], _gr); v->setIndex(pointmark(pointloop)); _gr->mesh_vertices.push_back(v); - _vertices.push_back(v); + _extras[pointmark(pointloop)] = v; } } else { MVertex *v = new MVertex(pointloop[0], pointloop[1], pointloop[2], _gr); v->setIndex(pointmark(pointloop)); _gr->mesh_vertices.push_back(v); - _vertices.push_back(v); + _extras[pointmark(pointloop)] = v; } } pointloop = pointtraverse(); } - assert((int)_vertices.size() == points->items); + // assert((int)_vertices.size() == points->items); } + if (!_extras.empty())Msg::Info("We add %d steiner points...",_extras.size()); + + if (l_edges.size() > 0) { + + // There are Steiner points on segments! face segloop; // Re-create the segment mesh in the corresponding GEdges. @@ -756,7 +761,7 @@ bool tetgenmesh::reconstructmesh(void *p) } } assert(ge != NULL); - Msg::Info("Steiner points exist on GEdge %d", ge->tag()); + // Msg::Info("Steiner points exist on GEdge %d", ge->tag()); // Delete the old triangles. for(unsigned int i = 0; i < ge->lines.size(); i++) delete ge->lines[i]; @@ -770,8 +775,11 @@ bool tetgenmesh::reconstructmesh(void *p) if (shellmark(segloop) == etag) { p[0] = sorg(segloop); p[1] = sdest(segloop); - MVertex *v1 = _vertices[pointmark(p[0])]; - MVertex *v2 = _vertices[pointmark(p[1])]; + MVertex *v1 = pointmark(p[0]) >= _vertices.size() ? _extras[pointmark(p[0])] : _vertices[pointmark(p[0])]; + MVertex *v2 = pointmark(p[1]) >= _vertices.size() ? _extras[pointmark(p[1])] : _vertices[pointmark(p[1])]; + // MVertex *v2 = _vertices[pointmark(p[1])]; + // printf("%d %d %d\n",pointmark(p[0]),pointmark(p[1]),_vertices.size()); + // printf("%g %g %g %g\n",v1->x(),v1->y(),v2->x(),v2->y()); MLine *t = new MLine(v1, v2); ge->lines.push_back(t); } @@ -814,9 +822,15 @@ bool tetgenmesh::reconstructmesh(void *p) p[0] = sorg(subloop); p[1] = sdest(subloop); p[2] = sapex(subloop); - MVertex *v1 = _vertices[pointmark(p[0])]; - MVertex *v2 = _vertices[pointmark(p[1])]; - MVertex *v3 = _vertices[pointmark(p[2])]; + MVertex *v1 = pointmark(p[0]) >= _vertices.size() ? _extras[pointmark(p[0])] : _vertices[pointmark(p[0])]; + MVertex *v2 = pointmark(p[1]) >= _vertices.size() ? _extras[pointmark(p[1])] : _vertices[pointmark(p[1])]; + MVertex *v3 = pointmark(p[2]) >= _vertices.size() ? _extras[pointmark(p[2])] : _vertices[pointmark(p[2])]; + if (pointmark(p[0]) >= _vertices.size())printf("F %d %d\n",v1->getIndex(),pointmark(p[0])); + if (pointmark(p[1]) >= _vertices.size())printf("F %d %d\n",v2->getIndex(),pointmark(p[1])); + if (pointmark(p[2]) >= _vertices.size())printf("F %d %d\n",v3->getIndex(),pointmark(p[2])); + // MVertex *v1 = _vertices[pointmark(p[0])]; + // MVertex *v2 = _vertices[pointmark(p[1])]; + // MVertex *v3 = _vertices[pointmark(p[2])]; MTriangle *t = new MTriangle(v1, v2, v3); gf->triangles.push_back(t); } @@ -837,10 +851,20 @@ bool tetgenmesh::reconstructmesh(void *p) p[2] = apex(tetloop); p[3] = oppo(tetloop); - MVertex *v1 = _vertices[pointmark(p[0])]; - MVertex *v2 = _vertices[pointmark(p[1])]; - MVertex *v3 = _vertices[pointmark(p[2])]; - MVertex *v4 = _vertices[pointmark(p[3])]; + MVertex *v1 = pointmark(p[0]) >= _vertices.size() ? _extras[pointmark(p[0])] : _vertices[pointmark(p[0])]; + MVertex *v2 = pointmark(p[1]) >= _vertices.size() ? _extras[pointmark(p[1])] : _vertices[pointmark(p[1])]; + MVertex *v3 = pointmark(p[2]) >= _vertices.size() ? _extras[pointmark(p[2])] : _vertices[pointmark(p[2])]; + MVertex *v4 = pointmark(p[3]) >= _vertices.size() ? _extras[pointmark(p[3])] : _vertices[pointmark(p[3])]; + + // if (pointmark(p[0]) >= _vertices.size())printf("%d %d\n",v1->getIndex(),pointmark(p[0])); + // if (pointmark(p[1]) >= _vertices.size())printf("%d %d\n",v2->getIndex(),pointmark(p[1])); + // if (pointmark(p[2]) >= _vertices.size())printf("%d %d\n",v3->getIndex(),pointmark(p[2])); + // if (pointmark(p[3]) >= _vertices.size())printf("%d %d\n",v4->getIndex(),pointmark(p[3])); + + // MVertex *v1 = _vertices[pointmark(p[0])]; + // MVertex *v2 = _vertices[pointmark(p[1])]; + // MVertex *v3 = _vertices[pointmark(p[2])]; + // MVertex *v4 = _vertices[pointmark(p[3])]; MTetrahedron *t = new MTetrahedron(v1, v2, v3, v4); _gr->tetrahedra.push_back(t); tetloop.tet = tetrahedrontraverse(); diff --git a/Mesh/meshGRegionDelaunayInsertion.cpp b/Mesh/meshGRegionDelaunayInsertion.cpp index 5e153903773efd1ea2f504cf333d77f115ba4079..84a0a1b7dfd88bdc80bf3c82ca8904009d9cac54 100644 --- a/Mesh/meshGRegionDelaunayInsertion.cpp +++ b/Mesh/meshGRegionDelaunayInsertion.cpp @@ -193,16 +193,18 @@ struct faceXtet{ } }; -void connectTets_vector2(std::vector<MTet4*> &t, std::vector<faceXtet> &conn) +template <class ITER> +void connectTets_vector2_templ(size_t _size, ITER beg, ITER end, std::vector<faceXtet> &conn) { conn.clear(); - conn.reserve(4*t.size()); + conn.reserve(4*_size); // unsigned int k = 0; // printf("COUCOU1 %d tets\n",t.size()); - for (unsigned int i=0;i<t.size();i++){ - if (!t[i]->isDeleted()){ + for (ITER IT = beg; IT != end; ++IT){ + MTet4* t = *IT; + if (!t->isDeleted()){ for (int j = 0; j < 4; j++){ - conn.push_back(faceXtet(t[i], j)); + conn.push_back(faceXtet(t, j)); } } } @@ -253,6 +255,8 @@ void connectTets(ITER beg, ITER end, std::set<MFace, Less_Face> *allEmbeddedFace void connectTets(std::list<MTet4*> &l) { connectTets(l.begin(), l.end()); } void connectTets(std::vector<MTet4*> &l) { connectTets(l.begin(), l.end()); } +void connectTets_vector2(std::list<MTet4*> &l, std::vector<faceXtet> &conn) { connectTets_vector2_templ(l.size(), l.begin(), l.end(), conn); } +void connectTets_vector2(std::vector<MTet4*> &l, std::vector<faceXtet> &conn) { connectTets_vector2_templ(l.size(), l.begin(), l.end(), conn); } // Ensure the star-shapeness of the delaunay cavity // We use the visibility criterion : the vertex should be visible @@ -865,7 +869,7 @@ void optimizeMesh(GRegion *gr, const qmTetrahedron::Measures &qm) while (1){ // printf("coucou\n"); std::vector<MTet4*> newTets; - for (CONTAINER::iterator it = allTets.begin(); it != allTets.end(); ++it){ + /* for (CONTAINER::iterator it = allTets.begin(); it != allTets.end(); ++it){ if (!(*it)->isDeleted()){ double qq = (*it)->getQuality(); if (qq < qMin){ @@ -878,6 +882,7 @@ void optimizeMesh(GRegion *gr, const qmTetrahedron::Measures &qm) } } } + */ // printf("coucou\n"); illegals.clear(); @@ -1188,6 +1193,11 @@ void insertVerticesInRegion (GRegion *gr, int maxVert, bool _classify) } gr->tetrahedra.clear(); + { + std::vector<faceXtet> conn; + // connectTets_vector2_templ(allTets.size(), allTets.begin(), allTets.end() , conn); + } + // SLOW connectTets(allTets.begin(), allTets.end()); // classify the tets on the right region diff --git a/Mesh/meshGRegionLocalMeshMod.cpp b/Mesh/meshGRegionLocalMeshMod.cpp index 7e0073e4cafbdf566d61db2963614e1855f4bd08..dff9b341c5791e916446ad0107be2a53a546357e 100644 --- a/Mesh/meshGRegionLocalMeshMod.cpp +++ b/Mesh/meshGRegionLocalMeshMod.cpp @@ -128,10 +128,22 @@ void BuildSwapPattern3(SwapPattern *sc) sc->trianguls = trgul ; } +/* + 0 1 + +------------+ + | | + | | + | | + +------------+ + 3 2 + +*/ + + void BuildSwapPattern4(SwapPattern *sc) { static int trgl[][3] = - { {0,1,2}, {0,2,3}, {0,1,3}, {1,2,3} }; + { {0,1,2}, {2,3,0}, {1,2,3}, {3,0,1} }; static int trgul[][5] = { {0,1,-1,-1,-1}, {2,3,-1,-1,-1} }; @@ -282,6 +294,7 @@ bool edgeSwap(std::vector<MTet4 *> &newTets, // if there exist no swap that enhance the quality if (best <= tetQualityRef) return false; + // does random swaps if (best < .01) return false; // we have the best configuration, so we swap // printf("outside size = %d\n",outside.size()); diff --git a/Mesh/meshGRegionRelocateVertex.cpp b/Mesh/meshGRegionRelocateVertex.cpp index b7b7185eed13d11a8c6df6b89bd27d79ba4ea119..b4711b3f5a8bf0e36f241a9ea9b6daad17bc891d 100644 --- a/Mesh/meshGRegionRelocateVertex.cpp +++ b/Mesh/meshGRegionRelocateVertex.cpp @@ -60,6 +60,34 @@ static double objective_function (double xi, MVertex *ver, GFace *gf, } +static double objective_function (double xi, MVertex *ver, GFace *gf, + SPoint3 &p1, SPoint3 &p2, + const std::vector<MElement*> <){ + double x = ver->x(); + double y = ver->y(); + double z = ver->z(); + SPoint3 p = p1 * (1.-xi) + p2 * xi; + + double initialGuess[2]={0,0}; + + GPoint pp = gf->closestPoint(p,initialGuess); + ver->x() = pp.x(); + ver->y() = pp.y(); + ver->z() = pp.z(); + double minQual = 1.0; + for(unsigned int i = 0; i < lt.size(); i++){ + if (lt[i]->getNumVertices () == 4) + minQual = std::min((lt[i]->etaShapeMeasure()), minQual); + else + minQual = std::min(fabs(lt[i]->gammaShapeMeasure()), minQual); + } + ver->x() = x; + ver->y() = y; + ver->z() = z; + return minQual; +} + + #define sqrt5 2.236067977499789696 @@ -158,6 +186,55 @@ double Maximize_Quality_Golden_Section( MVertex *ver, GFace *gf, return a; } + +double Maximize_Quality_Golden_Section( MVertex *ver, GFace *gf, + SPoint3 &p1, SPoint3 &p2, + const std::vector<MElement*> < , + double tol, double &worst) +{ + + static const double lambda = 0.5 * (sqrt5 - 1.0); + static const double mu = 0.5 * (3.0 - sqrt5); // = 1 - lambda + double a = 0.0; + double b = 1.0; + + worst = objective_function (0.0, ver, gf, p1, p2, lt ); + + if (worst > 0.5) return 0.0; + + double x1 = b - lambda * (b - a); + double x2 = a + lambda * (b - a); + double fx1 = objective_function (x1, ver, gf, p1, p2, lt ); + double fx2 = objective_function (x2, ver, gf, p1, p2, lt ); + + if (tol < 0.0)return fx1 > fx2 ? x1 : x2; + + while ( ! Stopping_Rule( a, b , tol) ) { + // printf("GOLDEN : %g %g (%12.5E,%12.5E)\n",a,b,fa,fb); + if (fx1 < fx2) { + a = x1; + if ( Stopping_Rule( a, b , tol) ) break; + x1 = x2; + fx1 = fx2; + x2 = b - mu * (b - a); + fx2 = objective_function (x2, ver, gf, p1, p2, lt ); + } else { + b = x2; + if ( Stopping_Rule( a, b , tol) ) break; + x2 = x1; + fx2 = fx1; + x1 = a + mu * (b - a); + fx1 = objective_function (x1, ver, gf, p1, p2, lt ); + } + } + double final = objective_function (a, ver, gf, p1, p2, lt ); + if (final < worst) return 0.0; + worst = final; + // printf("finally : %g %g (%12.5E,%12.5E)\n",a,b,fa,fb); + return a; +} + + void _relocateVertexGolden(MVertex *ver, const std::vector<MElement*> <, double relax , double tol) { @@ -184,6 +261,37 @@ void _relocateVertexGolden(MVertex *ver, ver->z() = (1.-xi) * ver->z() + xi * z/N; } + +// use real space + projection at the end +static double _relocateVertex2(GFace* gf, MVertex *ver, + const std::vector<MElement*> <, + double tol) { + + SPoint3 p1(0,0,0); + int counter = 0; + for(unsigned int i = 0; i < lt.size(); i++){ + for (int j=0;j<lt[i]->getNumVertices();j++){ + MVertex* v = lt[i]->getVertex(j); + p1 += SPoint3(v->x(),v->y(),v->z()); + counter++; + } + } + p1 *= 1./(double)counter; + SPoint3 p2(ver->x(),ver->y(),ver->z()); + double worst; + double xi = Maximize_Quality_Golden_Section( ver, gf, p1, p2, lt , tol, worst); + + SPoint3 p = p1*(1-xi) + p2*xi; + double initialGuess[2]={0,0}; + GPoint pp = gf->closestPoint(p,initialGuess); + if (!pp.succeeded())return 2.0; + ver->x() = pp.x(); + ver->y() = pp.y(); + ver->z() = pp.z(); + return worst; + +} + static double _relocateVertex(GFace* gf, MVertex *ver, const std::vector<MElement*> <, double tol) { @@ -191,15 +299,19 @@ static double _relocateVertex(GFace* gf, MVertex *ver, SPoint2 p1(0,0); SPoint2 p2; - ver->getParameter(0,p2[0]); - ver->getParameter(1,p2[1]); + if (ver->getParameter(0,p2[0])){ + ver->getParameter(1,p2[1]); + } + else { + return _relocateVertex2(gf,ver,lt,tol); + } int counter=0; for(unsigned int i = 0; i < lt.size(); i++){ for (int j=0;j<lt[i]->getNumVertices();j++){ MVertex* v = lt[i]->getVertex(j); SPoint2 pp; - reparamMeshVertexOnFace(v, gf, pp); + reparamMeshVertexOnFace(v, gf, pp); counter++; if (v->onWhat()->dim() == 1) { GEdge *ge = dynamic_cast<GEdge*> (v->onWhat()); @@ -230,7 +342,7 @@ void getAllBoundaryLayerVertices (GFace *gf, std::set<MVertex*> &vs); void RelocateVertices (GFace* gf, int niter, double tol) { std::set<MVertex*> vs; getAllBoundaryLayerVertices (gf, vs); - + v2t_cont adj; buildVertexToElement(gf->triangles, adj); buildVertexToElement(gf->quadrangles, adj); diff --git a/Mesh/surfaceFiller.cpp b/Mesh/surfaceFiller.cpp index 65bc9c890752094d2480312ed83bde18809734d2..1697072a807c9f61529100ca3d10e97ef4df8647 100644 --- a/Mesh/surfaceFiller.cpp +++ b/Mesh/surfaceFiller.cpp @@ -691,11 +691,11 @@ void packingOfParallelogramsSmoothness(GFace* gf, std::vector<MVertex*> &packed // add the vertices as additional vertices in the // surface mesh - char ccc[256]; sprintf(ccc,"points%d.pos",gf->tag()); - FILE *f = Fopen(ccc,"w"); - if(f) fprintf(f, "View \"\"{\n"); + // char ccc[256]; sprintf(ccc,"points%d.pos",gf->tag()); + // FILE *f = Fopen(ccc,"w"); + // if(f) fprintf(f, "View \"\"{\n"); for (unsigned int i=0;i<vertices.size();i++){ - if(f) vertices[i]->print(f,i); + // if(f) vertices[i]->print(f,i); if(vertices[i]->_v->onWhat() == gf) { packed.push_back(vertices[i]->_v); metrics.push_back(vertices[i]->_meshMetric); @@ -704,10 +704,10 @@ void packingOfParallelogramsSmoothness(GFace* gf, std::vector<MVertex*> &packed } delete vertices[i]; } - if(f){ - fprintf(f,"};"); - fclose(f); - } + // if(f){ + // fprintf(f,"};"); + // fclose(f); + // } }