Newer
Older
// Gmsh - Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to <gmsh@geuz.org>.
#include "Numeric.h"
#include "Context.h"
#include "BoundaryLayers.h"

Christophe Geuzaine
committed
#if !defined(HAVE_NO_POST)
#include "PView.h"
#include "PViewData.h"

Christophe Geuzaine
committed
#endif
extern Context_T CTX;
double &gamma, double &gammaMin, double &gammaMax,
double &eta, double &etaMin, double &etaMax,
double &rho, double &rhoMin, double &rhoMax,
double &disto, double &distoMin, double &distoMax,
double quality[4][100])
for(unsigned int i = 0; i < ele.size(); i++){
double g = ele[i]->gammaShapeMeasure();
gamma += g;
gammaMin = std::min(gammaMin, g);
gammaMax = std::max(gammaMax, g);
double e = ele[i]->etaShapeMeasure();
eta += e;
etaMin = std::min(etaMin, e);
etaMax = std::max(etaMax, e);
double r = ele[i]->rhoShapeMeasure();
rho += r;
rhoMin = std::min(rhoMin, r);
rhoMax = std::max(rhoMax, r);
double d = ele[i]->distoShapeMeasure();
disto += d;
distoMin = std::min(distoMin, d);
distoMax = std::max(distoMax, d);
for(int j = 0; j < 100; j++){
if(g > j / 100. && g <= (j + 1) / 100.) quality[0][j]++;
if(e > j / 100. && e <= (j + 1) / 100.) quality[1][j]++;
if(r > j / 100. && r <= (j + 1) / 100.) quality[2][j]++;
if(d > j / 100. && d <= (j + 1) / 100.) quality[3][j]++;
void GetStatistics(double stat[50], double quality[4][100])
for(int i = 0; i < 50; i++) stat[i] = 0.;
stat[0] = m->getNumVertices();
stat[1] = m->getNumEdges();
stat[2] = m->getNumFaces();
stat[3] = m->getNumRegions();
std::map<int, std::vector<GEntity*> > physicals[4];
stat[45] = physicals[0].size() + physicals[1].size() +
physicals[2].size() + physicals[3].size();
for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); ++it)
stat[4] += (*it)->mesh_vertices.size();
for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it){
stat[5] += (*it)->mesh_vertices.size();
stat[7] += (*it)->triangles.size();
stat[8] += (*it)->quadrangles.size();
}
for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it){
stat[6] += (*it)->mesh_vertices.size();
stat[9] += (*it)->tetrahedra.size();
stat[10] += (*it)->hexahedra.size();
stat[11] += (*it)->prisms.size();
stat[12] += (*it)->pyramids.size();
}
stat[13] = CTX.mesh_timer[0];
stat[14] = CTX.mesh_timer[1];
stat[15] = CTX.mesh_timer[2];
if(quality){
for(int i = 0; i < 3; i++)
for(int j = 0; j < 100; j++)
double gamma=0., gammaMin=1., gammaMax=0.;
double eta=0., etaMin=1., etaMax=0.;
double rho=0., rhoMin=1., rhoMax=0.;
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
double disto=0., distoMin=1., distoMax=0.;
if (m->firstRegion() == m->lastRegion()){
for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it){
GetQualityMeasure((*it)->quadrangles, gamma, gammaMin, gammaMax,
eta, etaMin, etaMax, rho, rhoMin, rhoMax,
disto, distoMin,distoMax,quality);
GetQualityMeasure((*it)->triangles, gamma, gammaMin, gammaMax,
eta, etaMin, etaMax, rho, rhoMin, rhoMax,
disto, distoMin,distoMax,quality);
}
}
else{
for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it){
GetQualityMeasure((*it)->tetrahedra, gamma, gammaMin, gammaMax,
eta, etaMin, etaMax, rho, rhoMin, rhoMax,
disto, distoMin,distoMax,quality);
GetQualityMeasure((*it)->hexahedra, gamma, gammaMin, gammaMax,
eta, etaMin, etaMax, rho, rhoMin, rhoMax,
disto, distoMin,distoMax,quality);
GetQualityMeasure((*it)->prisms, gamma, gammaMin, gammaMax,
eta, etaMin, etaMax, rho, rhoMin, rhoMax,
disto, distoMin,distoMax,quality);
GetQualityMeasure((*it)->pyramids, gamma, gammaMin, gammaMax,
eta, etaMin, etaMax, rho, rhoMin, rhoMax,
disto, distoMin,distoMax,quality);
}
double N = stat[9] + stat[10] + stat[11] + stat[12];
stat[17] = N ? gamma / N : 0.;
stat[18] = gammaMin;
stat[19] = gammaMax;
stat[20] = N ? eta / N : 0.;
stat[21] = etaMin;
stat[22] = etaMax;
stat[23] = N ? rho / N : 0;
stat[24] = rhoMin;
stat[25] = rhoMax;
stat[46] = N ? disto / N : 0;
stat[47] = distoMin;
stat[48] = distoMax;

Christophe Geuzaine
committed
#if !defined(HAVE_NO_POST)
stat[26] = PView::list.size();
for(unsigned int i = 0; i < PView::list.size(); i++) {
PViewData *data = PView::list[i]->getData();
stat[27] += data->getNumPoints();
stat[28] += data->getNumLines();
stat[29] += data->getNumTriangles();
stat[30] += data->getNumQuadrangles();
stat[31] += data->getNumTetrahedra();
stat[32] += data->getNumHexahedra();
stat[33] += data->getNumPrisms();
stat[34] += data->getNumPyramids();

Christophe Geuzaine
committed
#endif
if(CTX.expert_mode || !m->getNumVertices()) return false;
// try to detect obvious mistakes in characteristic lenghts (one of
// the most common cause for erroneous bug reports on the mailing
// list)
for(GModel::viter it = m->firstVertex(); it != m->lastVertex(); ++it)

Christophe Geuzaine
committed
sumAllLc += (*it)->prescribedMeshSizeAtVertex() * CTX.mesh.lc_factor;
sumAllLc /= (double)m->getNumVertices();
if(!sumAllLc || pow(CTX.lc / sumAllLc, dim) > 1.e10)
return !Msg::GetBinaryAnswer

Christophe Geuzaine
committed
("Your choice of characteristic lengths will likely produce a very\n"
"large mesh. Do you really want to continue?\n\n"
"(To disable this warning in the future, select `Enable expert mode'\n"
"in the option dialog.)",
"Continue", "Cancel");
return false;
}
static bool CancelDelaunayHybrid(GModel *m)
{
if(CTX.expert_mode) return false;
int n = 0;
for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it)
n += (*it)->getNumMeshElements();
if(n)
return !Msg::GetBinaryAnswer
("You are trying to generate a mixed structured/unstructured grid using\n"
"the 3D Delaunay algorithm. This algorithm cannot garantee that the\n"
"final mesh will be conforming. You should probably use the Frontal\n"
"Netgen algorithm instead. Do you really want to continue?\n\n"
"(To disable this warning in the future, select `Enable expert mode'\n"
"in the option dialog.)",
"Continue", "Cancel");
}
Msg::StatusBar(1, true, "Meshing 1D...");
double t1 = Cpu();
std::for_each(m->firstEdge(), m->lastEdge(), meshGEdge());
double t2 = Cpu();
Msg::Info("Mesh 1D complete (%g s)", CTX.mesh_timer[0]);
Msg::StatusBar(1, true, "Mesh");
}
if(CTX.create_append_statreport == 1)
statreport = fopen(CTX.statreport, "w");
else if(CTX.create_append_statreport == 2)
statreport = fopen(CTX.statreport, "a");
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 nUnmeshed = 0, numFaces = 0;
Msg::Info("2D Mesh Statistics :");
for(GModel::fiter it = m->firstFace() ; it != m->lastFace(); ++it){
worst = std::min((*it)->meshStatistics.worst_element_shape, worst);
best = std::max((*it)->meshStatistics.best_element_shape, best);
avg += (*it)->meshStatistics.average_element_shape * (*it)->meshStatistics.nbTriangle;
e_avg += (*it)->meshStatistics.efficiency_index;//* (*it)->meshStatistics.nbEdge;
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.status == GFace::FAILED ||
nTotT += (*it)->meshStatistics.nbTriangle;
nTotE += (*it)->meshStatistics.nbEdge;
nTotGoodLength += (*it)->meshStatistics.nbGoodLength;
nTotGoodQuality += (*it)->meshStatistics.nbGoodQuality;
numFaces++;
}
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]);
if(!CTX.expert_mode && (CTX.mesh.algo2d == ALGO_2D_DELAUNAY ||
CTX.mesh.algo2d == ALGO_2D_FRONTAL)){
if(!Msg::GetBinaryAnswer
("The 2D Delaunay and Frontal algorithms are still experimental\n"
"and produce triangles with random orientations. Do you really\n"
"want to continue?\n\n"
"(To disable this warning in the future, select `Enable expert\n"
"mode' in the option dialog.)",
"Continue", "Cancel")) return;
Msg::StatusBar(1, true, "Meshing 2D...");
double t1 = Cpu();
// 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());
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++;
}
double t2 = Cpu();
Msg::Info("Mesh 2D complete (%g s)", CTX.mesh_timer[1]);
Msg::StatusBar(1, true, "Mesh");
}

Christophe Geuzaine
committed
std::vector<std::vector<GRegion*> > &connected)
{
// FIXME: need to split region vector into connected components here!
connected.push_back(delaunay);
}
Msg::StatusBar(1, true, "Meshing 3D...");
double t1 = Cpu();
std::for_each(m->firstRegion(), m->lastRegion(), meshGRegionExtruded());
// then subdivide if necessary (unfortunately the subdivision is a
// global operation, which can require changing the surface mesh!)
// then mesh all the non-delaunay regions
std::vector<GRegion*> delaunay;
std::for_each(m->firstRegion(), m->lastRegion(), meshGRegion(delaunay));

Christophe Geuzaine
committed
// warn if attempting to use Delaunay for mixed meshes
if(delaunay.size() && CancelDelaunayHybrid(m)) return;
// and finally mesh the delaunay regions (again, this is global; but
// we mesh each connected part separately for performance and mesh
// quality reasons)
std::vector<std::vector<GRegion*> > connected;
FindConnectedRegions(delaunay, connected);
for(unsigned int i = 0; i < connected.size(); i++)
MeshDelaunayVolume(connected[i]);
double t2 = Cpu();
Msg::Info("Mesh 3D complete (%g s)", CTX.mesh_timer[2]);
Msg::StatusBar(1, true, "Mesh");
}
void OptimizeMeshNetgen(GModel *m)
{
Msg::StatusBar(1, true, "Optimizing 3D with Netgen...");
double t1 = Cpu();
std::for_each(m->firstRegion(), m->lastRegion(), optimizeMeshGRegionNetgen());
double t2 = Cpu();
Msg::Info("Mesh 3D optimization with Netgen complete (%g s)", t2 - t1);
Msg::StatusBar(1, true, "Mesh");
Msg::StatusBar(1, true, "Optimizing 3D...");
std::for_each(m->firstRegion(), m->lastRegion(), optimizeMeshGRegionGmsh());
Msg::Info("Mesh 3D optimization complete (%g s)", t2 - t1);
Msg::StatusBar(1, true, "Mesh");
Msg::StatusBar(1, true, "Adapting the 3D Mesh...");
double t1 = Cpu();
if(CTX.threads_lock) {
Msg::Info("I'm busy! Ask me that later...");
return;
}
CTX.threads_lock = 1;
std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
double t2 = Cpu();
Msg::Info("Mesh Adaptation complete (%g s)", t2 - t1);
Msg::StatusBar(1, true, "Mesh");
Msg::Info("I'm busy! Ask me that later...");
Msg::ResetErrorCounter();
// Initialize pseudo random mesh generator with the same seed
srand(1);
std::for_each(m->firstRegion(), m->lastRegion(), deMeshGRegion());
std::for_each(m->firstFace(), m->lastFace(), deMeshGFace());
}
std::for_each(m->firstRegion(), m->lastRegion(), deMeshGRegion());
}
}
if(m->getMeshStatus() >= 2)
std::for_each(m->firstFace(), m->lastFace(), orientMeshGFace());
// Optimize quality of 3D tet mesh
if(m->getMeshStatus() == 3){
for(int i = 0; i < std::max(CTX.mesh.optimize, CTX.mesh.optimize_netgen); i++){
if(CTX.mesh.optimize > i) OptimizeMesh(m);
if(CTX.mesh.optimize_netgen > i) OptimizeMeshNetgen(m);
}
if(m->getMeshStatus() && CTX.mesh.order > 1)
SetOrderN(m, CTX.mesh.order, CTX.mesh.second_order_linear,
Msg::Info("%d vertices %d elements",
m->getNumMeshVertices(), m->getNumMeshElements());
Msg::PrintErrorCounter("Mesh generation error summary");