diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp index defc56a3edacc85b28fc298bb74d29b2007e240f..0d0a618a6607c52f2abae9da1a663038969bed92 100644 --- a/Common/CommandLine.cpp +++ b/Common/CommandLine.cpp @@ -1,4 +1,4 @@ -// $Id: CommandLine.cpp,v 1.107 2007-11-04 21:03:16 remacle Exp $ +// $Id: CommandLine.cpp,v 1.108 2007-11-26 14:34:09 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -410,6 +410,30 @@ void Get_Options(int argc, char *argv[]) i++; opt_mesh_c1(0, GMSH_SET, 1); } + else if(!strcmp(argv[i] + 1, "statreport")) { + i++; + CTX.create_append_statreport = 1; + if(argv[i] != NULL) { + strcpy(CTX.statreport,argv[i]); + i++; + } + else { + fprintf(stderr, ERROR_STR "Missing argument\n"); + exit(1); + } + } + else if(!strcmp(argv[i] + 1, "append_statreport")) { + i++; + CTX.create_append_statreport = 2; + if(argv[i] != NULL) { + strcpy(CTX.statreport,argv[i]); + i++; + } + else { + fprintf(stderr, ERROR_STR "Missing argument\n"); + exit(1); + } + } else if(!strcmp(argv[i] + 1, "optimize_hom")) { i++; opt_mesh_smooth_internal_edges(0, GMSH_SET, 1); diff --git a/Common/Context.h b/Common/Context.h index ca3d3d55cc83a277adce3ffb400382f8f3329296..66ca89f9d25e037be04feb7366ab55831051c74b 100644 --- a/Common/Context.h +++ b/Common/Context.h @@ -46,6 +46,12 @@ public : char *error_filename, error_filename_fullpath[256]; // the name of the error file + // gmsh enables to output some mesh stats in a test suite file + // mesh algorithms are very sensitive to small parameter modifications + // and a test suite is indeed useful ;-) + char statreport[256]; + int create_append_statreport; // do nothing 0 create 1 append 2 + int session_save, options_save; // save session/option file on exit int confirm_overwrite; // confirm overwrite when file->save as char *display; // forced display host:0.0 under X11 diff --git a/Common/Options.cpp b/Common/Options.cpp index ff4aa64cf9fafa2f8d0311910b8d5b6ac1b79671..7af769f1e0c65766227d8b6fdcaabdebeae3d928 100644 --- a/Common/Options.cpp +++ b/Common/Options.cpp @@ -1,4 +1,4 @@ -// $Id: Options.cpp,v 1.367 2007-11-08 19:30:30 geuzaine Exp $ +// $Id: Options.cpp,v 1.368 2007-11-26 14:34:09 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -106,6 +106,9 @@ void Init_Options(int num) else strcpy(CTX.home_dir, ""); + // By defaults, no stat report + CTX.create_append_statreport = 0; + int len = strlen(CTX.home_dir); if(len && CTX.home_dir[len-1] != '/') strcat(CTX.home_dir, "/"); diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp index eabea2713ffc605b1c1114456f7ef0282bc9ff7c..682897fc2a0b83eae82960416ba58ea4a20ae912 100644 --- a/Geo/MElement.cpp +++ b/Geo/MElement.cpp @@ -1,4 +1,4 @@ -// $Id: MElement.cpp,v 1.45 2007-11-04 21:03:17 remacle Exp $ +// $Id: MElement.cpp,v 1.46 2007-11-26 14:34:09 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -104,29 +104,14 @@ double MTriangle::gammaShapeMeasure() double MTetrahedron::gammaShapeMeasure() { - double p0[3] = { _v[0]->x(), _v[0]->y(), _v[0]->z() }; - double p1[3] = { _v[1]->x(), _v[1]->y(), _v[1]->z() }; - double p2[3] = { _v[2]->x(), _v[2]->y(), _v[2]->z() }; - double p3[3] = { _v[3]->x(), _v[3]->y(), _v[3]->z() }; - double s1 = fabs(triangle_area(p0, p1, p2)); - double s2 = fabs(triangle_area(p0, p2, p3)); - double s3 = fabs(triangle_area(p0, p1, p3)); - double s4 = fabs(triangle_area(p1, p2, p3)); - double rhoin = 3. * fabs(getVolume()) / (s1 + s2 + s3 + s4); - return 12. * rhoin / (sqrt(6.) * maxEdge()); + double vol; + return qmTet(this,QMTET_2,&vol); } double MTetrahedron::etaShapeMeasure() { - double lij2 = 0.; - for(int i = 0; i <= 3; i++) { - for(int j = i + 1; j <= 3; j++) { - double lij = _v[i]->distance(_v[j]); - lij2 += lij * lij; - } - } - double v = fabs(getVolume()); - return 12. * pow(0.9 * v * v, 1./3.) / lij2; + double vol; + return qmTet(this,QMTET_3,&vol); } SPoint3 MElement::barycenter() diff --git a/Geo/OCCEdge.cpp b/Geo/OCCEdge.cpp index e528a2d8820a98806103994a53a273d728256e92..77779abe43ff25424b5d256e37465268498092e3 100644 --- a/Geo/OCCEdge.cpp +++ b/Geo/OCCEdge.cpp @@ -1,4 +1,4 @@ -// $Id: OCCEdge.cpp,v 1.26 2007-11-11 19:53:57 remacle Exp $ +// $Id: OCCEdge.cpp,v 1.27 2007-11-26 14:34:09 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -193,10 +193,12 @@ int OCCEdge::minimumMeshSegments() const int np; if(geomType() == Line) np= GEdge::minimumMeshSegments(); - else if(geomType() == Circle) - np= CTX.mesh.min_circ_points - 1; else np=CTX.mesh.min_curv_points - 1; + + // if the edge is closed, ensure that at least 3 points are generated + if (getBeginVertex() == getEndVertex()) np=std::max(2,np); + return np; } diff --git a/Mesh/BDS.cpp b/Mesh/BDS.cpp index df32a0832302f142684957e8c919839994bfed81..bb5ad7cf6c1f6862cecfaeeb2c94bd140e30b3c9 100644 --- a/Mesh/BDS.cpp +++ b/Mesh/BDS.cpp @@ -1,4 +1,4 @@ -// $Id: BDS.cpp,v 1.85 2007-11-11 19:53:57 remacle Exp $ +// $Id: BDS.cpp,v 1.86 2007-11-26 14:34:09 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -201,7 +201,7 @@ BDS_Edge *BDS_Mesh::recover_edge(int num1, int num2, std::set<EdgeToRecover> *e2 Msg(DEBUG," edge %d %d has to be recovered",num1,num2); int ix = 0; - int ixMax = 100; + int ixMax = 300; while(1) { std::vector<BDS_Edge *> intersected; @@ -220,9 +220,9 @@ BDS_Edge *BDS_Mesh::recover_edge(int num1, int num2, std::set<EdgeToRecover> *e2 { std::set<EdgeToRecover>::iterator itr1 = e2r->find(EdgeToRecover(e->p1->iD,e->p2->iD,0)); std::set<EdgeToRecover>::iterator itr2 = e2r->find(EdgeToRecover(num1,num2,0)); - Msg(WARNING," edge %d %d on model edge %d cannot be recovered because it intersects %d %d on model edge %d", - num1,num2,itr2->ge->tag(), - e->p1->iD,e->p2->iD,itr1->ge->tag()); + // Msg(WARNING," edge %d %d on model edge %d cannot be recovered because it intersects %d %d on model edge %d", + // num1,num2,itr2->ge->tag(), + // e->p1->iD,e->p2->iD,itr1->ge->tag()); // now throw a class that contains the diagnostic not_recovered->insert (EdgeToRecover( num1 , num2, itr2->ge)); @@ -234,13 +234,21 @@ BDS_Edge *BDS_Mesh::recover_edge(int num1, int num2, std::set<EdgeToRecover> *e2 ++it; } - if (!intersected.size() || ix > ixMax) +// if (ix > 300){ +// Msg(WARNING," edge %d %d cannot be recovered after %d iterations, trying again", +// num1,num2,ix); +// ix = 0; +// } + + if (!intersected.size() || ix > 1000) { BDS_Edge *eee = find_edge (num1, num2); if (!eee) { outputScalarField(triangles, "debugp.pos",1); outputScalarField(triangles, "debugr.pos",0); + Msg(GERROR," edge %d %d cannot be recovered at all, look at debugp.pos and debugr.pos", + num1,num2); return 0; } return eee; diff --git a/Mesh/BackgroundMesh.cpp b/Mesh/BackgroundMesh.cpp index 20d9ca97a3baf36c44f4b87d6939a40099c03b81..08a2dcb922e227b1f37cd9f9e543dc1bfb55725e 100644 --- a/Mesh/BackgroundMesh.cpp +++ b/Mesh/BackgroundMesh.cpp @@ -1,4 +1,4 @@ -// $Id: BackgroundMesh.cpp,v 1.29 2007-11-11 19:53:57 remacle Exp $ +// $Id: BackgroundMesh.cpp,v 1.30 2007-11-26 14:34:09 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -182,19 +182,22 @@ double BGM_MeshSize(GEntity *ge, double U, double V, double X, double Y, double double l3 = CTX.lc; double l4 = lc_field.empty() ? MAX_LC : lc_field(X, Y, Z); + double lc; if(l4 < MAX_LC && !CTX.mesh.constrained_bgmesh){ // use the fields unconstrained by other characteristic lengths lc = l4 * CTX.mesh.lc_factor; } else{ - if(CTX.mesh.lc_from_curvature && ge->dim() < 3) - l1 = LC_MVertex_CURV(ge, U, V); if(ge->dim() < 2) l2 = LC_MVertex_PNTS(ge, U, V); lc = std::min(std::min(std::min(l1, l2), l3), l4) * CTX.mesh.lc_factor; } - + + + if(CTX.mesh.lc_from_curvature && ge->dim() < 3) + lc = std::min (lc,LC_MVertex_CURV(ge, U, V)); + if(lc <= 0.){ Msg(GERROR, "Incorrect char. length lc = %g: using default instead", lc); return l3 * CTX.mesh.lc_factor; @@ -208,7 +211,7 @@ double BGM_MeshSize(GEntity *ge, double U, double V, double X, double Y, double // we do it also if CTX.mesh.constrained_bgmesh is true; bool Extend1dMeshIn2dSurfaces() { - if(lc_field.empty()) return true; + if(lc_field.empty() && !CTX.mesh.lc_from_curvature) return true; if(CTX.mesh.constrained_bgmesh) return true; return false; } diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp index 1ac4bb2b3b9d60e840d8c472bff278157fda4cbb..e16d722148b7a4d5f49ad30f07049fd6d2ce1f61 100644 --- a/Mesh/Generator.cpp +++ b/Mesh/Generator.cpp @@ -1,4 +1,4 @@ -// $Id: Generator.cpp,v 1.124 2007-11-04 21:03:17 remacle Exp $ +// $Id: Generator.cpp,v 1.125 2007-11-26 14:34:10 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -179,9 +179,16 @@ void Mesh1D(GModel *m) void PrintMesh2dStatistics (GModel *m) { + FILE *statreport = 0; + if (CTX.create_append_statreport == 1) + statreport = fopen (CTX.statreport,"w"); + else if (CTX.create_append_statreport == 2) + statreport = fopen (CTX.statreport,"a"); + else return; + double worst=1,best=0,avg=0; double e_long=0,e_short=1.e22,e_avg=0; - int nTotT=0,nTotE=0,nTotGoodLength=0,nTotGoodQuality=0; + int nTotT=0,nTotE=0,nTotGoodLength=0,nTotGoodQuality=0,nUnmeshed=0,numFaces=0; Msg(INFO,"2D Mesh Statistics :"); for (GModel::fiter it = m->firstFace() ; it!=m->lastFace(); ++it) { @@ -194,22 +201,25 @@ void PrintMesh2dStatistics (GModel *m) e_long = std::max((*it)->meshStatistics.longest_edge_length,e_long); e_short = std::min((*it)->meshStatistics.smallest_edge_length,e_short); - if ((*it)->meshStatistics.worst_element_shape < 0.05) - Msg(INFO,"Badly Shaped Element (rho = %12.5E) on GFace %d (%d triangles)",(*it)->meshStatistics.worst_element_shape,(*it)->tag(),(*it)->meshStatistics.nbTriangle); - if ((*it)->meshStatistics.status == GFace::FAILED) - Msg(INFO,"GMSH was unable to mesh GFace %d ",(*it)->tag()); + if ((*it)->meshStatistics.status == GFace::FAILED || (*it)->meshStatistics.status == GFace::PENDING)nUnmeshed++; nTotT += (*it)->meshStatistics.nbTriangle ; nTotE += (*it)->meshStatistics.nbEdge ; nTotGoodLength += (*it)->meshStatistics.nbGoodLength ; nTotGoodQuality+= (*it)->meshStatistics.nbGoodQuality ; + numFaces ++; } - Msg(INFO,"Element Quality (%d triangles) : avg %8.7f best %8.7f worst %8.7f greaterthan90 %d (%12.5E\\%)", - nTotT,avg/(double)nTotT,best,worst,nTotGoodQuality,(double)nTotGoodQuality/nTotT); - Msg(INFO,"Size Field Accuracy (%d edges) : %8.7f (should be as close as 1 as possible) in good brackets %d (%12.5E\%)", - nTotE,exp(e_avg/(double)nTotE),nTotGoodLength,(double)nTotGoodLength/nTotE); + if (CTX.create_append_statreport == 1){ + fprintf(statreport,"2D stats\tname\t\t#faces\t\t#fail\t\t#t\t\tQavg\t\tQbest\t\tQworst\t\t#Q>90\t\t#Q>90/#t\t#e\t\ttau\t\t#Egood\t\t#Egood/#e\tCPU\n"); + } + fprintf(statreport,"\t%16s\t%d\t\t%d\t\t",CTX.base_filename,numFaces, nUnmeshed); + fprintf(statreport,"%d\t\t%8.7f\t%8.7f\t%8.7f\t%d\t\t%8.7f\t", + nTotT,avg/(double)nTotT,best,worst,nTotGoodQuality,(double)nTotGoodQuality/nTotT); + fprintf(statreport,"%d\t\t%8.7f\t%d\t\t%8.7f\t%8.1f\n", + nTotE,exp(e_avg/(double)nTotE),nTotGoodLength,(double)nTotGoodLength/nTotE,CTX.mesh_timer[1]); + fclose (statreport); } @@ -232,15 +242,29 @@ void Mesh2D(GModel *m) // boundary layers are special: their generation (including vertices // and curve meshes) is global as it depends on a smooth normal // field generated from the surface mesh of the source surfaces - if(!Mesh2DWithBoundaryLayers(m)) - std::for_each(m->firstFace(), m->lastFace(), meshGFace()); - - PrintMesh2dStatistics(m); + if(!Mesh2DWithBoundaryLayers(m)){ + std::for_each(m->firstFace(), m->lastFace(), meshGFace()); + int nIter = 0; + while(1) + { + meshGFace mesher; + int nbPending = 0; + for (GModel::fiter it = m->firstFace() ; it!=m->lastFace(); ++it) + { + if ((*it)->meshStatistics.status == GFace::PENDING){mesher(*it);nbPending++;} + } + if (!nbPending)break; + if (nIter > 10)break; + } + } + double t2 = Cpu(); CTX.mesh_timer[1] = t2 - t1; Msg(INFO, "Mesh 2D complete (%g s)", CTX.mesh_timer[1]); Msg(STATUS1, "Mesh"); + + PrintMesh2dStatistics(m); } diff --git a/Mesh/Makefile b/Mesh/Makefile index 6ee88cba6dd77e4baf97b339cc2841c71b166bce..075f8a8a0a01a4e6e5396c705d2ddf5e624f2aac 100644 --- a/Mesh/Makefile +++ b/Mesh/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.187 2007-11-12 10:49:16 geuzaine Exp $ +# $Id: Makefile,v 1.188 2007-11-26 14:34:10 remacle Exp $ # # Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle # @@ -44,6 +44,7 @@ SRC = Generator.cpp \ meshGRegionTransfinite.cpp \ meshGRegionExtruded.cpp \ meshGRegionCarveHole.cpp \ + meshGRegionLocalMeshMod.cpp\ DivideAndConquer.cpp \ BackgroundMesh.cpp \ qualityMeasures.cpp \ diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp index e0589a529504013d42f434ba2a46476bb062d413..28a1cb1d01b3dcf7d0a2d865a4e4e0cb1be2edbd 100644 --- a/Mesh/meshGFace.cpp +++ b/Mesh/meshGFace.cpp @@ -1,4 +1,4 @@ -// $Id: meshGFace.cpp,v 1.101 2007-11-11 19:53:57 remacle Exp $ +// $Id: meshGFace.cpp,v 1.102 2007-11-26 14:34:10 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -337,7 +337,7 @@ bool edgeSwapTestDelaunay(BDS_Edge *e,GFace *gf) void OptimizeMesh(GFace *gf, BDS_Mesh &m, const int NIT) { // optimize - // if (0) + if (0) { for(int i = 0 ; i < NIT ; i++){ { @@ -602,30 +602,41 @@ void RefineMesh ( GFace *gf, BDS_Mesh &m , const int NIT) int MAXNP = m.MAXPOINTNUMBER; - if (NIT > 0) + // if (NIT > 0) { std::set<BDS_Point*,PointLessThan>::iterator itp = m.points.begin(); while (itp != m.points.end()) { - std::list<BDS_Edge*>::iterator it = (*itp)->edges.begin(); - std::list<BDS_Edge*>::iterator ite = (*itp)->edges.end(); - double L=0; - int ne = 0; - while(it!=ite){ - double l = (*it)->length(); - if ((*it)->g && (*it)->g->classif_degree == 1){ - L=ne?std::max(L,l):l; - // L=ne?std::min(L,l):l; - // L+=l; - ne++; + if (NIT > 0) + { + std::list<BDS_Edge*>::iterator it = (*itp)->edges.begin(); + std::list<BDS_Edge*>::iterator ite = (*itp)->edges.end(); + double L=0; + int ne = 0; + while(it!=ite){ + double l = (*it)->length(); + if ((*it)->g && (*it)->g->classif_degree == 1){ + L=ne?std::max(L,l):l; + // L=ne?std::min(L,l):l; + // L+=l; + ne++; + } + ++it; + } + if (!ne) L = 1.e22; + // else L/=ne; + if(!CTX.mesh.constrained_bgmesh) + (*itp)->lc() = L; + (*itp)->lcBGM() = L; } - ++it; - } - if (!ne) L = 1.e22; - // else L/=ne; - if(!CTX.mesh.constrained_bgmesh) - (*itp)->lc() = L; - (*itp)->lcBGM() = L; +// else if (CTX.mesh.lc_from_curvature) +// { +// double Crv = gf->curvature(SPoint2((*itp)->u, (*itp)->v)); +// double lc = Crv > 0 ? 2*M_PI / Crv / CTX.mesh.min_circ_points : 1.e22; +// lc *= CTX.mesh.lc_factor; +// printf("%d = %d %12.5e %12.5E %12.5E\n",gf->tag(),CTX.mesh.min_circ_points,Crv,lc,(*itp)->lcBGM()); +// (*itp)->lc() = std::min(lc,(*itp)->lc()); +// } ++itp; } } @@ -708,7 +719,7 @@ void RefineMesh ( GFace *gf, BDS_Mesh &m , const int NIT) Msg(DEBUG1," iter %3d minL %8.3f/%8.3f maxL %8.3f/%8.3f : %6d splits, %6d swaps, %6d collapses, %6d moves, accuracy %7.5f, shapes (worst %7.6f, avg %7.6f, best %7.6f) ",IT,minL,minE,maxL,maxE,nb_split,nb_swap,nb_collaps,nb_smooth, exp(mesh_quality/nE), worst,avg/nT,best); if (nb_split==0 && nb_collaps == 0)break; - if (mesh_quality < old_mesh_quality && worst > 0.1 && maxL < 1.45) break; + // if (mesh_quality < old_mesh_quality && worst > 0.1 && maxL < 1.45) break; } double t_total = t_spl + t_sw + t_col + t_sm; @@ -1185,14 +1196,6 @@ bool gmsh2DMeshGenerator ( GFace *gf , int RECUR_ITER, bool debug = true) m->cleanup(); - if (debug) - { - char name[245]; - sprintf(name,"surface%d-recovered-real.pos",gf->tag()); - outputScalarField(m->triangles, name,0); - sprintf(name,"surface%d-recovered-param.pos",gf->tag()); - outputScalarField(m->triangles, name,1); - } { @@ -1213,12 +1216,24 @@ bool gmsh2DMeshGenerator ( GFace *gf , int RECUR_ITER, bool debug = true) } } + + m->cleanup(); m->del_point(m->find_point(-1)); m->del_point(m->find_point(-2)); m->del_point(m->find_point(-3)); m->del_point(m->find_point(-4)); + + if (debug) + { + char name[245]; + sprintf(name,"surface%d-recovered-real.pos",gf->tag()); + outputScalarField(m->triangles, name,0); + sprintf(name,"surface%d-recovered-param.pos",gf->tag()); + outputScalarField(m->triangles, name,1); + } + // start mesh generation if (!AlgoDelaunay2D ( gf )) { @@ -1597,8 +1612,8 @@ bool gmsh2DMeshGeneratorPeriodic ( GFace *gf , bool debug = true) for (std::list<GEdgeLoop>::iterator it = gf->edgeLoops.begin() ; it != gf->edgeLoops.end() ; it++) { std::vector<BDS_Point* > edgeLoop_BDS; - // if(!buildConsecutiveListOfVertices ( gf, *it , edgeLoop_BDS, bbox, m, recover_map , nbPointsTotal, 1.e-7*LC2D)) - if(!buildConsecutiveListOfVertices ( gf, *it , edgeLoop_BDS, bbox, m, recover_map , nbPointsTotal, 1.e-5)) + if(!buildConsecutiveListOfVertices ( gf, *it , edgeLoop_BDS, bbox, m, recover_map , nbPointsTotal, 1.e-7*LC2D)) + if(!buildConsecutiveListOfVertices ( gf, *it , edgeLoop_BDS, bbox, m, recover_map , nbPointsTotal, 1.e-5*LC2D)) if(!buildConsecutiveListOfVertices ( gf, *it , edgeLoop_BDS, bbox, m, recover_map , nbPointsTotal, 1.e-3*LC2D)) { gf->meshStatistics.status = GFace::FAILED; @@ -1949,15 +1964,20 @@ void meshGFace::operator() (GFace *gf) computeEdgeLoops(gf, points, indices); // temp fix until we create MEdgeLoops in gmshFace - Msg(DEBUG1, "Generating the mesh"); - if(noseam (gf) || gf->getNativeType() == GEntity::GmshModel || gf->edgeLoops.empty()){ - gmsh2DMeshGenerator(gf,0, false); - } - else{ - if(!gmsh2DMeshGeneratorPeriodic(gf,false)) - Msg(GERROR, "Impossible to mesh face %d", gf->tag()); - } - + // if (gf->tag() == 2) + { + Msg(DEBUG1, "Generating the mesh"); + if(noseam (gf) || gf->getNativeType() == GEntity::GmshModel || gf->edgeLoops.empty()){ + gmsh2DMeshGenerator(gf,0, false); + } + else{ + if(!gmsh2DMeshGeneratorPeriodic(gf,false)) + Msg(GERROR, "Impossible to mesh face %d", gf->tag()); + } + } +// else +// gf->meshStatistics.status = GFace::DONE; + Msg(DEBUG1, "type %d %d triangles generated, %d internal vertices", gf->geomType(), gf->triangles.size(), gf->mesh_vertices.size()); } diff --git a/Mesh/meshGRegionDelaunayInsertion.cpp b/Mesh/meshGRegionDelaunayInsertion.cpp index de2f45f678c06d9aa2100fa13375041ae71d20c3..83e3eab036246451b7c7911176464713e735c88e 100644 --- a/Mesh/meshGRegionDelaunayInsertion.cpp +++ b/Mesh/meshGRegionDelaunayInsertion.cpp @@ -1,4 +1,4 @@ -// $Id: meshGRegionDelaunayInsertion.cpp,v 1.20 2007-11-11 19:53:57 remacle Exp $ +// $Id: meshGRegionDelaunayInsertion.cpp,v 1.21 2007-11-26 14:34:10 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -19,7 +19,9 @@ // // Please report all bugs and problems to <gmsh@geuz.org>. +#include "OS.h" #include "BackgroundMesh.h" +#include "edgeSwap.h" #include "meshGRegionDelaunayInsertion.h" #include "GModel.h" #include "GRegion.h" @@ -92,6 +94,8 @@ void connectTets ( ITER beg, ITER end) } } } +void connectTets ( std::list<MTet4*> & l) {connectTets(l.begin(),l.end());} +void connectTets ( std::vector<MTet4*> &l ) {connectTets(l.begin(),l.end());} void recurFindCavity ( std::list<faceXtet> & shell, @@ -428,6 +432,98 @@ void recur_classify ( MTet4 *t , } } +template <class CONTAINER, class DATA> +void gmshOptimizeMesh (CONTAINER &allTets, DATA &vSizes) +{ + double t1 = Cpu(); + { + double totalVolumeb = 0.0; + double worst = 1.0; + double avg = 0; + int count=0; + for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it) + { + if (!(*it)->isDeleted()){ + double vol; + double qual = qmTet((*it)->tet(),QMTET_2,&vol); + worst = std::min(qual,worst); + avg+=qual; + count++; + totalVolumeb+=vol; + } + } + Msg(INFO,"Optimization Vol = %12.5E QBAD %12.5E QAVG %12.5E",totalVolumeb,worst,avg/count); + } + + + while (1){ + std::vector<MTet4*> newTets; + + // get a bad tet and try to swap each of its edges + + for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it) + { + if (!(*it)->isDeleted()){ + double vol; + double qq = qmTet((*it)->tet(),QMTET_2,&vol); + // gmshSmoothVertex(*it,IED%4); + if (qq < .4) + for (int i=0;i<6;i++){ + gmshEdgeSwap(newTets,*it,i,QMTET_2); + if ((*it)->isDeleted())i=10; + } + } + } + + // relocate vertices +// for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it) +// { +// if (!(*it)->isDeleted()){ +// double vol; +// double qq = qmTet((*it)->tet(),QMTET_2,&vol); +// if (qq < .5) +// for (int i=0;i<4;i++){ +// gmshSmoothVertex(*it,i); +// } +// } +// } + + + // if no new tet is created, leave + if (!newTets.size())break; + + // add all the new tets in the container + for (int i=0;i<newTets.size();i++){ + if (!newTets[i]->isDeleted()){ + newTets[i]->setup(newTets[i]->tet(),vSizes); + allTets.insert(newTets[i]); + } + else{ + delete newTets[i]; + } + } + + double totalVolumeb = 0.0; + double worst = 1.0; + double avg = 0; + int count=0; + for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it) + { + if (!(*it)->isDeleted()){ + double vol; + double qual = qmTet((*it)->tet(),QMTET_2,&vol); + worst = std::min(qual,worst); + avg+=qual; + count++; + totalVolumeb+=vol; + } + } + double t2 = Cpu(); + Msg(INFO,"Optimization Vol = %12.5E QBAD %12.5E QAVG %12.5E (%8.3f sec)",totalVolumeb,worst,avg/count,t2-t1); + } +} + + void insertVerticesInRegion (GRegion *gr) { @@ -542,7 +638,7 @@ void insertVerticesInRegion (GRegion *gr) else myFactory.changeTetRadius(allTets.begin(),0.0); } - // Normally, a tet mesh contains about 5 to 6 times more tets than + // Normally, a tet mesh contains about 6 times more tets than // vertices // This allows to clean up the set of tets when lots of deleted ones // are present in the mesh @@ -562,6 +658,7 @@ void insertVerticesInRegion (GRegion *gr) Msg(INFO,"cleaning up the memory %d -> %d ",n1,allTets.size()); } } + gmshOptimizeMesh (allTets,vSizes); while (1) { diff --git a/Mesh/meshGRegionDelaunayInsertion.h b/Mesh/meshGRegionDelaunayInsertion.h index 9309625ea2c4f683b443d0ed7d5899f4b21bf249..846385298af98f44a406f0e31396091de5df3899 100644 --- a/Mesh/meshGRegionDelaunayInsertion.h +++ b/Mesh/meshGRegionDelaunayInsertion.h @@ -54,11 +54,18 @@ class MTet4 MTet4 *neigh[4]; GRegion *gr; + + public : + ~MTet4 (){} MTet4 () : deleted(false), base (0), gr(0),circum_radius(0.0) { neigh[0] = neigh[1] = neigh[2] = neigh[3] = 0; } + MTet4 (MTetrahedron * t) : deleted(false), gr(0),circum_radius(0.0),base(t) + { + neigh[0] = neigh[1] = neigh[2] = neigh[3] = 0; + } void setup ( MTetrahedron * t, std::vector<double> & sizes) { @@ -79,8 +86,6 @@ class MTet4 deleted = false; } - public : - inline GRegion * onWhat () const {return gr;} inline void setOnWhat (GRegion *g) {gr=g;} @@ -129,6 +134,7 @@ class MTet4 }; void connectTets ( std::list<MTet4*> & ); +void connectTets ( std::vector<MTet4*> & ); void insertVerticesInRegion (GRegion *gr) ; class compareTet4Ptr diff --git a/Mesh/meshGRegionLocalMeshMod.cpp b/Mesh/meshGRegionLocalMeshMod.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87a4757c84d51eaf98547ec4723877e74bc3efc5 --- /dev/null +++ b/Mesh/meshGRegionLocalMeshMod.cpp @@ -0,0 +1,418 @@ +#include "meshGRegionLocalMeshMod.h" + +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 enofaces[6][2] = {{1,3},{2,3},{0,3},{1,2},{0,1},{0,2}}; +static int facesXedges[4][3] = {{0,1,3},{1,2,5},{0,2,4},{3,4,5}}; +static int faces[4][3] = {{0,1,2},{0,2,3},{0,1,3},{1,2,3}}; + +// as input, we give a tet and an edge, as return, we get +// all tets that share this edge and all vertices that are +// forming the outer ring of the cavity +// we return true if the cavity is closed and false if it is open +bool gmshBuildEdgeCavity ( MTet4 *t, + int iLocalEdge, + MVertex **v1,MVertex **v2, + std::vector<MTet4*> &cavity, + std::vector<MTet4*> &outside, + std::vector<MVertex*> &ring ){ + cavity.clear(); + ring.clear(); + outside.clear(); + + // FILE *f = fopen ("pts.pos","w"); + // fprintf(f,"View \"\"{\n"); + + *v1 = t->tet()->getVertex(edges[iLocalEdge][0]); + *v2 = t->tet()->getVertex(edges[iLocalEdge][1]); + + // printf("trying to swap %p %p (%p,%p,%p,%p)\n",(*v1),(*v2),t->tet()->getVertex(0),t->tet()->getVertex(1),t->tet()->getVertex(2),t->tet()->getVertex(3)); + + MVertex *lastinring = t->tet()->getVertex(edges[5-iLocalEdge][0]); + + // fprintf(f,"SP(%g,%g,%g){%d};\n",(*v1)->x(),(*v1)->y(),(*v1)->z(),-1); + // fprintf(f,"SP(%g,%g,%g){%d};\n",(*v2)->x(),(*v2)->y(),(*v2)->z(),-2); + + // fprintf(f,"SP(%g,%g,%g){%d};\n",lastinring->x(),lastinring->y(),lastinring->z(),ring.size()); + + // printf("the ring starts with %p \n",lastinring); + + ring.push_back(lastinring); + cavity.push_back(t); + + while (1){ + MVertex *ov1 = t->tet()->getVertex(edges[5-iLocalEdge][0]); + MVertex *ov2 = t->tet()->getVertex(edges[5-iLocalEdge][1]); + int K = ov1 == lastinring ? 1 : 0; + lastinring = ov1 == lastinring ? ov2 : ov1; + // look in the 2 faces sharing this edge the one that has vertex + // ov2 i.e. edges[5-iLocalEdge][1] + + int iFace; +// int iFaceOK; +// for (int i=0;i<4;i++) +// { +// MVertex *f1 = t->tet()->getVertex(faces[i][0]); +// MVertex *f2 = t->tet()->getVertex(faces[i][1]); +// MVertex *f3 = t->tet()->getVertex(faces[i][2]); +// if ((f1 == *v1 && f2 == *v2 && f3 == lastinring) || +// (f1 == *v1 && f3 == *v2 && f2 == lastinring) || +// (f2 == *v1 && f1 == *v2 && f3 == lastinring) || +// (f2 == *v1 && f3 == *v2 && f1 == lastinring) || +// (f3 == *v1 && f2 == *v2 && f1 == lastinring) || +// (f3 == *v1 && f1 == *v2 && f2 == lastinring) )iFaceOK = i; +// } + + int iFace1 = efaces[iLocalEdge][0]; + int iFace2 = efaces[iLocalEdge][1]; + if (faces[iFace1][0] == edges[5-iLocalEdge][K] || + faces[iFace1][1] == edges[5-iLocalEdge][K] || + faces[iFace1][2] == edges[5-iLocalEdge][K] ) iFace = iFace1; + else if (faces[iFace2][0] == edges[5-iLocalEdge][K] || + faces[iFace2][1] == edges[5-iLocalEdge][K] || + faces[iFace2][2] == edges[5-iLocalEdge][K] ) iFace = iFace2; + else {printf("error of connexion\n");throw;} + // else iFace = iFace2; + + // printf("iFaceOK %d iFace %d\n",iFaceOK,iFace); + + if (!t->getNeigh(iFace))return false; + t=t->getNeigh(iFace); + if (t->isDeleted())throw; + // printf("next tet (%p,%p,%p,%p)\n",t->tet()->getVertex(0),t->tet()->getVertex(1),t->tet()->getVertex(2),t->tet()->getVertex(3)); + // int iNoFace1 = enofaces[iLocalEdge][0]; + // int iNoFace2 = enofaces[iLocalEdge][1]; + + if (t==*(cavity.begin())) break; + // fprintf(f,"SP(%g,%g,%g){%d};\n",lastinring->x(),lastinring->y(),lastinring->z(),ring.size()); + ring.push_back(lastinring); + // printf("the ring continues with %p \n",lastinring); + + cavity.push_back(t); + iLocalEdge = -1; + for (int i=0;i<6;i++) + { + MVertex *a = t->tet()->getVertex(edges[i][0]); + MVertex *b = t->tet()->getVertex(edges[i][1]); + if ((a == *v1 && b == *v2) || (a == *v2 && b == *v1)){ + iLocalEdge = i; + break; + } + } + if (iLocalEdge == -1){ + printf("ERROR : loc = %d\n",iLocalEdge); + throw; + } + } + // fprintf(f,"};\n"); + // fclose(f); + // getchar(); + + for (int i=0;i<cavity.size();i++){ + for (int j=0;j<4;j++){ + MTet4 * neigh = cavity[i]->getNeigh(j); + if (neigh) + { + bool found = false; + for (int k=0;k<outside.size();k++)if(outside[k]==neigh)found=true; + if(!found)outside.push_back(neigh); + } + } + } + + return true; +} + +typedef struct { + int nbr_triangles ; /* number of different triangles */ + int (*triangles)[3] ; /* triangles array */ + int nbr_trianguls ; /* number of different triangulations */ + int nbr_triangles_2 ; /* number of triangles / triangulation */ + int (*trianguls)[5] ; /* retriangulations array */ +} SwapPattern ; + + +void BuildSwapPattern3(SwapPattern *sc) +{ + static int trgl[][3] = { 0,1,2 } ; + static int trgul[][5] = { 0,-1,-1,-1,-1 } ; + + sc->nbr_triangles = 1 ; + sc->nbr_triangles_2 = 1 ; + sc->nbr_trianguls = 1 ; + sc->triangles = trgl ; + sc->trianguls = trgul ; +} + +void BuildSwapPattern4(SwapPattern *sc) +{ + static int trgl[][3] = + { 0,1,2, 0,2,3, 0,1,3, 1,2,3 } ; + static int trgul[][5] = + { 0,1,-1,-1,-1, 2,3,-1,-1,-1 } ; + + sc->nbr_triangles = 4 ; + sc->nbr_triangles_2 = 2 ; + sc->nbr_trianguls = 2 ; + sc->triangles = trgl ; + sc->trianguls = trgul ; +} + + +void BuildSwapPattern5(SwapPattern *sc) +{ + static int trgl[][3] = + { 0,1,2, 0,2,3, 0,3,4, 0,1,4, 1,3,4, 1,2,3, 2,3,4, 0,2,4, 0,1,3, 1,2,4 } ; + static int trgul[][5] = + { 0,1,2,-1,-1, 3,4,5,-1,-1, 0,6,7,-1,-1, 2,5,8,-1,-1, 3,6,9,-1,-1 } ; + + sc->nbr_triangles = 10 ; + sc->nbr_triangles_2 = 3 ; + sc->nbr_trianguls = 5 ; + sc->triangles = trgl ; + sc->trianguls = trgul ; +} + +void BuildSwapPattern6(SwapPattern *sc) +{ + static int trgl[][3] = + { 0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,2,5, 2,4,5, 2,3,4, 0,3,5, + 3,4,5, 0,2,4, 2,3,5, 1,2,3, 0,1,3, 0,1,5, 1,4,5, 1,3,4, + 0,1,4, 1,3,5, 1,2,4, 1,2,5 } ; + static int trgul[][5] = + { 0,1,2,3,-1, 0,4,5,6,-1, 0,1,7,8,-1, 0,3,6,9,-1, 0,4,8,10,-1, + 2,3,11,12,-1, 11,13,14,15,-1, 7,8,11,12,-1, 3,11,15,16,-1, + 8,11,13,17,-1, 6,13,14,18,-1, 3,6,16,18,-1, 5,6,13,19,-1, + 8,10,13,19,-1 } ; + + sc->nbr_triangles = 20 ; + sc->nbr_triangles_2 = 4 ; + sc->nbr_trianguls = 14 ; + sc->triangles = trgl ; + sc->trianguls = trgul ; +} + +void BuildSwapPattern7(SwapPattern *sc) +{ + static int trgl[][3] = + { 0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,3,6, 3,5,6, 3,4,5, 0,4,6, + 4,5,6, 0,3,5, 3,4,6, 0,2,4, 2,3,4, 0,2,6, 2,5,6, 2,4,5, 0,2,5, + 2,4,6, 2,3,5, 2,3,6, 0,1,3, 1,2,3, 0,1,4, 1,3,4, 0,1,6, 1,5,6, + 1,4,5, 0,1,5, 1,4,6, 1,3,5, 1,3,6, 1,2,4, 1,2,5, 1,2,6 }; + static int trgul[][5] = + { 0,1,2,3,4, 0,1,5,6,7, 0,1,2,8,9, 0,1,4,7,10, 0,1,5,9,11, 0,3,4,12,13, + 0,13,14,15,16, 0,8,9,12,13, 0,4,13,16,17, 0,9,13,14,18, 0,7,14,15,19, + 0,4,7,17,19, 0,6,7,14,20, 0,9,11,14,20, 2,3,4,21,22, 5,6,7,21,22, + 2,8,9,21,22, 4,7,10,21,22, 5,9,11,21,22, 3,4,22,23,24, 22,24,25,26,27, + 8,9,22,23,24, 4,22,24,27,28, 9,22,24,25,29, 7,22,25,26,30, 4,7,22,28,30, + 6,7,22,25,31, 9,11,22,25,31, 3,4,13,23,32, 13,25,26,27,32, 8,9,13,23,32, + 4,13,27,28,32, 9,13,25,29,32, 13,16,25,26,33, 4,13,16,28,33, + 13,15,16,25,34, 9,13,18,25,34, 7,19,25,26,33, 4,7,19,28,33, + 7,15,19,25,34, 6,7,20,25,34, 9,11,20,25,34 } ; + + sc->nbr_triangles = 35 ; + sc->nbr_triangles_2 = 5 ; + sc->nbr_trianguls = 42 ; + sc->triangles = trgl ; + sc->trianguls = trgul ; +} + + +void gmshEdgeSwap (std::vector<MTet4 *> &newTets, + MTet4 *tet, + int iLocalEdge, + const gmshQualityMeasure4Tet &cr){ + std::vector<MTet4*> cavity; + std::vector<MTet4*> outside; + std::vector<MVertex*> ring; + MVertex *v1,*v2; + // printf("swapping an edge\n"); + + bool closed = gmshBuildEdgeCavity ( tet,iLocalEdge,&v1,&v2,cavity,outside,ring); + + + if (!closed)return; + + double volumeRef = 0.0; + double tetQualityRef = 1; + for (int i=0;i<cavity.size();i++){ + double vol; + tetQualityRef = std::min(qmTet (cavity[i]->tet() , cr , &vol) , tetQualityRef); + // printf("%p %p -> %p %p %p %p\n",v1,v2,cavity[i]->tet()->getVertex(0),cavity[i]->tet()->getVertex(1),cavity[i]->tet()->getVertex(2),cavity[i]->tet()->getVertex(3)); + volumeRef += fabs(vol); + } + + // build swap patterns + + SwapPattern sp; + switch (ring.size()){ + case 3 : BuildSwapPattern3 (&sp); break; + case 4 : BuildSwapPattern4 (&sp); break; + case 5 : BuildSwapPattern5 (&sp); break; + case 6 : BuildSwapPattern6 (&sp); break; + case 7 : BuildSwapPattern7 (&sp); break; + default : return; + } + + // printf("the cavity contains %d tets the ring is of size %d volume %12.5E qual %12.5E\n",cavity.size(),ring.size(),volumeRef,tetQualityRef); + + // 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++){ + int p1 = sp.triangles[i][0]; + int p2 = sp.triangles[i][1]; + int p3 = sp.triangles[i][2]; + tetQuality1[i] = qmTet ( ring[p1], ring[p2], ring[p3], v1 , cr , &(volume1[i])); + tetQuality2[i] = qmTet ( ring[p1], ring[p2], ring[p3], v2 , cr , &(volume2[i])); + // printf("points %d %d %d vol %g %g qual %g %g\n",p1,p2,p3,volume1[i],volume2[i],tetQuality1[i],tetQuality2[i]); + } + + + + // look for the best triangulation, i.e. the one + // that maximize the minimum element quality + double minQuality[100]; + // for all triangulations + for (int i=0;i<sp.nbr_trianguls;i++){ + // for all triangles in a triangulation + minQuality[i] = 1; + double volume=0; + for (int j=0;j<sp.nbr_triangles_2;j++){ + int iT = sp.trianguls[i][j]; + minQuality[i] = std::min (minQuality[i],tetQuality1[iT]); + minQuality[i] = std::min (minQuality[i],tetQuality2[iT]); + volume += (volume1[iT] + volume2[iT] ); + } + // printf("config %3d qual %12.5E volume %12.5E\n",i,minQuality[i],volume); + if (fabs(volume-volumeRef) > 1.e-12 * (volume+volumeRef))minQuality[i] = 0; + } + + int iBest; + double best = 0.0; + for (int i=0;i<sp.nbr_trianguls;i++){ + if(minQuality[i] > best) + { + best = minQuality[i]; + iBest = i; + } + } + + // if there exist no swap that enhance the quality + if (best <= tetQualityRef) return; + +// printf("swap is performed\n"); + +// return; + + // we have the best configuration, so we swap + // printf("outside size = %d\n",outside.size()); + + double volumeAssert = 0; + for (int j=0;j<sp.nbr_triangles_2;j++){ + int iT = sp.trianguls[iBest][j]; + int p1 = sp.triangles[iT][0]; + int p2 = sp.triangles[iT][1]; + int p3 = sp.triangles[iT][2]; + MVertex *pv1 = ring[p1]; + MVertex *pv2 = ring[p2]; + MVertex *pv3 = ring[p3]; + MTetrahedron *tr1 = new MTetrahedron ( pv1, + pv2, + pv3, + v1); + MTetrahedron *tr2 = new MTetrahedron ( pv3, + pv2, + pv1, + v2); + volumeAssert += (fabs(tr1->getVolume()) +fabs(tr2->getVolume()) ); + + MTet4 *t41 = new MTet4 ( tr1 ); + MTet4 *t42 = new MTet4 ( tr2 ); + t41->setOnWhat(cavity[0]->onWhat()); + t42->setOnWhat(cavity[0]->onWhat()); + outside.push_back(t41); + outside.push_back(t42); + newTets.push_back(t41); + newTets.push_back(t42); + } + if (fabs(volumeRef-volumeAssert) > 1.e-10 * volumeRef) printf("volumes = %12.5E %12.5E\n",volumeRef,volumeAssert); + + for (int i=0;i<cavity.size();i++){ + cavity[i]->setDeleted(true); + } + + connectTets ( outside ); + +} + + +void gmshBuildVertexCavity_recur ( MTet4 *t, + MVertex *v, + std::vector<MTet4*> &cavity){ + for (int i=0; i<4; i++){ + MTet4 *neigh = t->getNeigh(i); + if (neigh){ + bool foundv = false; + for (int j=0;j<4;j++){if (t->tet()->getVertex(j) == v){foundv = true; break;}} + if (foundv) + { + bool found = false; + for (int j=0;j<cavity.size();j++){if (cavity[j] == neigh){found = true; break;}} + if (!found){ + cavity.push_back(neigh); + gmshBuildVertexCavity_recur ( neigh,v,cavity); + } + } + } + } +} +void gmshSmoothVertex ( MTet4 *t, + int iVertex){ + std::vector<MTet4*> cavity; + cavity.push_back(t); + gmshBuildVertexCavity_recur (t,t->tet()->getVertex(iVertex),cavity); + + // printf("cavity o size %d\n",cavity.size()); + + double xcg=0,ycg=0,zcg=0; + double vTot=0; + double worst = 1.0; + for (int i=0 ; i< cavity.size() ; i++){ + double volume; + double q = qmTet(cavity[i]->tet(),QMTET_2,&volume); + worst = std::min(worst,q); + xcg += 0.25*(cavity[i]->tet()->getVertex(0)->x()+cavity[i]->tet()->getVertex(1)->x()+cavity[i]->tet()->getVertex(2)->x()+cavity[i]->tet()->getVertex(3)->x())*volume; + ycg += 0.25*(cavity[i]->tet()->getVertex(0)->y()+cavity[i]->tet()->getVertex(1)->y()+cavity[i]->tet()->getVertex(2)->y()+cavity[i]->tet()->getVertex(3)->y())*volume; + zcg += 0.25*(cavity[i]->tet()->getVertex(0)->z()+cavity[i]->tet()->getVertex(1)->z()+cavity[i]->tet()->getVertex(2)->z()+cavity[i]->tet()->getVertex(3)->z())*volume; + vTot += volume; + + } + xcg /= (vTot); + ycg /= (vTot); + zcg /= (vTot); + double volumeAfter = 0.0; + + double x = t->tet()->getVertex(iVertex)->x(); + double y = t->tet()->getVertex(iVertex)->y(); + double z = t->tet()->getVertex(iVertex)->z(); + + t->tet()->getVertex(iVertex)->x() = xcg; + t->tet()->getVertex(iVertex)->y() = ycg; + t->tet()->getVertex(iVertex)->z() = zcg; + double worstAfter = 1.0; + for (int i=0 ; i< cavity.size() ; i++){ + double volume; + double q = qmTet(cavity[i]->tet(),QMTET_2,&volume); + volumeAfter += volume; + worstAfter =std::min(worstAfter,q); + } + + if (fabs(volumeAfter-vTot) > 1.e-10 * vTot || worstAfter < worst){ + t->tet()->getVertex(iVertex)->x() = x; + t->tet()->getVertex(iVertex)->y() = y; + t->tet()->getVertex(iVertex)->z() = z; + } +} + + diff --git a/Mesh/meshGRegionLocalMeshMod.h b/Mesh/meshGRegionLocalMeshMod.h new file mode 100644 index 0000000000000000000000000000000000000000..e0dca76adacf917988801ed9160a4f677a657ee3 --- /dev/null +++ b/Mesh/meshGRegionLocalMeshMod.h @@ -0,0 +1,39 @@ +#ifndef _MESHGREGIONLOCALMESHMOD_H_ +#define _MESHGREGIONLOCALMESHMOD_H_ + +// Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to <gmsh@geuz.org>. + +#include "meshGRegionDelaunayInsertion.h" +#include "qualityMeasures.h" + +void gmshEdgeSwap (std::vector<MTet4 *> &newTets, + MTet4 *tet, + int iLocalEdge, + const gmshQualityMeasure4Tet &cr); +void gmshFaceSwap (std::vector<MTet4 *> &newTets, + MTet4 *tet, + int iLocalFace, + const gmshQualityMeasure4Tet &cr); +void gmshSmoothVertex ( MTet4 *t, + int iLocalVertex); + +#endif + + diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp index ba640923dfd99f285f8ed166011dcce091c24407..10530237031ba4c6f540e7577c1f68fda0ae25ba 100644 --- a/Mesh/qualityMeasures.cpp +++ b/Mesh/qualityMeasures.cpp @@ -66,3 +66,77 @@ double qmTriangle ( const double &xa, const double &ya, const double &z return quality; } +double qmTet ( MTetrahedron*t, const gmshQualityMeasure4Tet &cr, double *volume) +{ + return qmTet (t->getVertex(0),t->getVertex(1),t->getVertex(2),t->getVertex(3),cr,volume); +} + +double qmTet ( const MVertex *v1, const MVertex *v2, const MVertex *v3, const MVertex *v4, const gmshQualityMeasure4Tet &cr, double *volume) +{ + return qmTet (v1->x(),v1->y(),v1->z(),v2->x(),v2->y(),v2->z(),v3->x(),v3->y(),v3->z(),v4->x(),v4->y(),v4->z(),cr,volume); +} + +double qmTet ( const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + const double &x4, const double &y4, const double &z4, + const gmshQualityMeasure4Tet &cr, double *volume ){ + double quality; + switch(cr) + { + case QMTET_3: + { + double mat[3][3]; + mat[0][0] = x2 - x1; + mat[0][1] = x3 - x1; + mat[0][2] = x4 - x1; + mat[1][0] = y2 - y1; + mat[1][1] = y3 - y1; + mat[1][2] = y4 - y1; + mat[2][0] = z2 - z1; + mat[2][1] = z3 - z1; + mat[2][2] = z4 - z1; + *volume = fabs(det3x3(mat)) / 6.; + double l = ((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1)); + l += ((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1)+(z3-z1)*(z3-z1)); + l +=((x4-x1)*(x4-x1)+(y4-y1)*(y4-y1)+(z4-z1)*(z4-z1)); + l +=((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2)+(z3-z2)*(z3-z2)); + l +=((x4-x2)*(x4-x2)+(y4-y2)*(y4-y2)+(z4-z2)*(z4-z2)); + l +=((x3-x4)*(x3-x4)+(y3-y4)*(y3-y4)+(z3-z4)*(z3-z4)); + return 12. * pow(3*fabs(*volume),2./3.)/l; + } + case QMTET_2: + { + double mat[3][3]; + mat[0][0] = x2 - x1; + mat[0][1] = x3 - x1; + mat[0][2] = x4 - x1; + mat[1][0] = y2 - y1; + mat[1][1] = y3 - y1; + mat[1][2] = y4 - y1; + mat[2][0] = z2 - z1; + mat[2][1] = z3 - z1; + mat[2][2] = z4 - z1; + *volume = fabs(det3x3(mat)) / 6.; + double p0[3] = { x1,y1,z1}; + double p1[3] = { x2,y2,z2}; + double p2[3] = { x3,y3,z3}; + double p3[3] = { x4,y4,z4}; + double s1 = fabs(triangle_area(p0, p1, p2)); + double s2 = fabs(triangle_area(p0, p2, p3)); + double s3 = fabs(triangle_area(p0, p1, p3)); + double s4 = fabs(triangle_area(p1, p2, p3)); + double rhoin = 3. * fabs(*volume) / (s1 + s2 + s3 + s4); + double l = sqrt ((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1)); + l = std::max(l,sqrt ((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1)+(z3-z1)*(z3-z1))); + l = std::max(l,sqrt ((x4-x1)*(x4-x1)+(y4-y1)*(y4-y1)+(z4-z1)*(z4-z1))); + l = std::max(l,sqrt ((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2)+(z3-z2)*(z3-z2))); + l = std::max(l,sqrt ((x4-x2)*(x4-x2)+(y4-y2)*(y4-y2)+(z4-z2)*(z4-z2))); + l = std::max(l,sqrt ((x3-x4)*(x3-x4)+(y3-y4)*(y3-y4)+(z3-z4)*(z3-z4))); + return 2. * sqrt(6.) * rhoin / l; + } + break; + default: + throw; + } +} diff --git a/Mesh/qualityMeasures.h b/Mesh/qualityMeasures.h index 02429b4fb89da054386de2dde1ab5887fa3bd27e..6b4a974e03365aeccb159aecba3267bc5785bdf4 100644 --- a/Mesh/qualityMeasures.h +++ b/Mesh/qualityMeasures.h @@ -5,7 +5,9 @@ class BDS_Point; class BDS_Face; class MVertex; class MTriangle; +class MTetrahedron; enum gmshQualityMeasure4Triangle {QMTRI_RHO}; +enum gmshQualityMeasure4Tet {QMTET_1,QMTET_2,QMTET_3}; double qmTriangle ( MTriangle *f, const gmshQualityMeasure4Triangle &cr); double qmTriangle ( BDS_Face *f, const gmshQualityMeasure4Triangle &cr); @@ -16,5 +18,12 @@ double qmTriangle ( const double &x1, const double &y1, const double &z const double &x2, const double &y2, const double &z2, const double &x3, const double &y3, const double &z3, const gmshQualityMeasure4Triangle &cr); +double qmTet ( MTetrahedron *t, const gmshQualityMeasure4Tet &cr, double *volume = 0); +double qmTet ( const MVertex *v1, const MVertex *v2, const MVertex *v3, const MVertex *v4, const gmshQualityMeasure4Tet &cr, double *volume = 0); +double qmTet ( const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + const double &x4, const double &y4, const double &z4, + const gmshQualityMeasure4Tet &cr, double *volume = 0); #endif diff --git a/Plugin/CutMap.cpp b/Plugin/CutMap.cpp index 46a9338cad29c439d437264bd8b9ffc802ed4cc3..ba8e8cffa02f3508ff9d4f87cb90db7abb9c0d73 100644 --- a/Plugin/CutMap.cpp +++ b/Plugin/CutMap.cpp @@ -1,4 +1,4 @@ -// $Id: CutMap.cpp,v 1.55 2007-09-24 08:14:29 geuzaine Exp $ +// $Id: CutMap.cpp,v 1.56 2007-11-26 14:34:10 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -25,7 +25,7 @@ extern Context_T CTX; StringXNumber CutMapOptions_Number[] = { - {GMSH_FULLRC, "A", GMSH_CutMapPlugin::callbackA, 1.}, + {GMSH_FULLRC, "A", GMSH_CutMapPlugin::callbackA, 0.}, {GMSH_FULLRC, "dTimeStep", NULL, -1.}, {GMSH_FULLRC, "dView", NULL, -1.}, {GMSH_FULLRC, "ExtractVolume", GMSH_CutMapPlugin::callbackVol, 0.}, diff --git a/Plugin/Levelset.cpp b/Plugin/Levelset.cpp index c61617fa443f886690fc2876a5a700f9cc384765..76ef9d10acae547fb3548a495b4fa6cb4743bb30 100644 --- a/Plugin/Levelset.cpp +++ b/Plugin/Levelset.cpp @@ -1,4 +1,4 @@ -// $Id: Levelset.cpp,v 1.37 2007-09-24 08:14:30 geuzaine Exp $ +// $Id: Levelset.cpp,v 1.38 2007-11-26 14:34:10 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -781,7 +781,7 @@ static bool recur_sign_change(adapt_triangle *t, double val, double v1 = plug->levelset(t->p[0]->X, t->p[0]->Y, t->p[0]->Z, t->p[0]->val); double v2 = plug->levelset(t->p[1]->X, t->p[1]->Y, t->p[1]->Z, t->p[1]->val); double v3 = plug->levelset(t->p[2]->X, t->p[2]->Y, t->p[2]->Z, t->p[2]->val); - if(v1 * v2 > 0 && v1 * v3 > 0) + if(v1 * v2 > 0 && v1 * v3 > 0 && v2 * v3 > 0) t->visible = false; else t->visible = true; diff --git a/Post/AdaptiveViews.cpp b/Post/AdaptiveViews.cpp index 1ecc325f6f8480ae0331cdd199efc0e61148986c..c78bd253ed1fe2d469f8b33e6f6cfcc03cbdb561 100644 --- a/Post/AdaptiveViews.cpp +++ b/Post/AdaptiveViews.cpp @@ -756,10 +756,10 @@ int Adaptive_Post_View::zoomElement(int ielem, itt = ELEM::all_elems.begin(); - for(; itt != itte; itt++) { - if((*itt)->visible && !(*itt)->e[0] && level != levelmax) - return 0; - } + for(; itt != itte; itt++) { + if((*itt)->visible && !(*itt)->e[0] && level != levelmax) + return 0; + } itt = ELEM::all_elems.begin(); adapt_point **p; @@ -930,8 +930,7 @@ void Adaptive_Post_View::setAdaptiveResolutionLevel_TEMPL(int level, int levelma kk++; } - for(int i = 0; i < nbelm; ++i) { - if(!done[i]) + for(int i = 0; i < nbelm; ++i) {// if(!done[i]) done[i] = zoomElement<ELEM>(i, level, levelmax, plug, *myList, counter); } }