gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
Generator.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include <stack>
7 #include <stdexcept>
8 #include <stdlib.h>
9 
10 #include "BackgroundMesh.h"
11 #include "BoundaryLayers.h"
12 #include "Context.h"
13 #include "ExtrudeParams.h"
14 #include "Field.h"
15 #include "GModel.h"
16 #include "Generator.h"
17 #include "GmshConfig.h"
18 #include "GmshMessage.h"
19 #include "HighOrder.h"
20 #include "MHexahedron.h"
21 #include "MLine.h"
22 #include "MPoint.h"
23 #include "MPrism.h"
24 #include "MPyramid.h"
25 #include "MQuadrangle.h"
26 #include "MTetrahedron.h"
27 #include "MTriangle.h"
28 #include "Numeric.h"
29 #include "OS.h"
30 #include "Options.h"
31 #include "meshGEdge.h"
32 #include "meshGFace.h"
33 #include "meshGFaceBDS.h"
35 #include "meshGFaceOptimize.h"
36 #include "meshGRegion.h"
39 #include "meshRefine.h"
40 #include "meshRelocateVertex.h"
41 #include "sizeField.h"
42 
43 #if defined(HAVE_DOMHEX)
44 #include "pointInsertion.h"
45 #include "simple3D.h"
46 #include "yamakawa.h"
47 #endif
48 
49 #if defined(HAVE_OPTHOM)
50 #include "HighOrderMeshElasticAnalogy.h"
51 #include "HighOrderMeshFastCurving.h"
52 #include "HighOrderMeshOptimizer.h"
53 #endif
54 
55 #if defined(HAVE_WINSLOWUNTANGLER)
56 #include "meshSurfaceUntangling.h"
57 #include "meshVolumeUntangling.h"
58 #endif
59 
60 #if defined(HAVE_POST)
61 #include "PView.h"
62 #include "PViewData.h"
63 #endif
64 
66 {
67  public:
68  void operator()(GRegion *gr)
69  {
70  std::vector<GEdge *> const &e = gr->embeddedEdges();
71  std::vector<GFace *> const &f = gr->embeddedFaces();
72  if (e.empty() && f.empty())
73  return;
74  std::map<MEdge, GEdge *, MEdgeLessThan> edges;
75  std::map<MFace, GFace *, MFaceLessThan> faces;
76  auto it = e.begin();
77  auto itf = f.begin();
78  for (; it != e.end(); ++it)
79  {
80  for (std::size_t i = 0; i < (*it)->lines.size(); ++i)
81  {
82  if (distance((*it)->lines[i]->getVertex(0), (*it)->lines[i]->getVertex(1)) > 1.e-12)
83  edges.insert(
84  std::make_pair(MEdge((*it)->lines[i]->getVertex(0), (*it)->lines[i]->getVertex(1)), *it));
85  }
86  }
87  for (; itf != f.end(); ++itf)
88  {
89  for (std::size_t i = 0; i < (*itf)->triangles.size(); ++i)
90  {
91  faces.insert(
92  std::make_pair(MFace((*itf)->triangles[i]->getVertex(0), (*itf)->triangles[i]->getVertex(1),
93  (*itf)->triangles[i]->getVertex(2)),
94  *itf));
95  }
96  }
97  Msg::Info("Searching for %d embedded mesh edges and %d embedded mesh faces "
98  "in region %d",
99  edges.size(), faces.size(), gr->tag());
100  for (std::size_t k = 0; k < gr->getNumMeshElements(); k++)
101  {
102  for (int j = 0; j < gr->getMeshElement(k)->getNumEdges(); j++)
103  {
104  edges.erase(gr->getMeshElement(k)->getEdge(j));
105  }
106  for (int j = 0; j < gr->getMeshElement(k)->getNumFaces(); j++)
107  {
108  faces.erase(gr->getMeshElement(k)->getFace(j));
109  }
110  }
111  if (edges.empty() && faces.empty())
112  {
113  Msg::Info("All embedded edges and faces are present in the final mesh");
114  }
115  if (edges.size())
116  {
117  char name[256];
118  sprintf(name, "missingEdgesOnRegion%d.pos", gr->tag());
119  Msg::Warning("Region %d : %d mesh edges that should be embedded are "
120  "missing in the final mesh",
121  gr->tag(), (int)edges.size());
122  Msg::Info("Saving the missing edges in file %s", name);
123  FILE *f = fopen(name, "w");
124  fprintf(f, "View \" \" {\n");
125  for (auto it = edges.begin(); it != edges.end(); ++it)
126  {
127  MVertex *v1 = it->first.getVertex(0);
128  MVertex *v2 = it->first.getVertex(1);
129  fprintf(f, "SL(%g,%g,%g,%g,%g,%g){%d,%d};\n", v1->x(), v1->y(), v1->z(), v2->x(), v2->y(), v2->z(),
130  it->second->tag(), it->second->tag());
131  }
132  fprintf(f, "};\n");
133  fclose(f);
134  }
135  if (faces.size())
136  {
137  char name[256];
138  sprintf(name, "missingFacesOnRegion%d.pos", gr->tag());
139  Msg::Warning("Volume %d : %d mesh faces that should be embedded are "
140  "missing in the final mesh",
141  gr->tag(), (int)faces.size());
142  Msg::Info("Saving the missing faces in file %s", name);
143  FILE *f = fopen(name, "w");
144  fprintf(f, "View \" \" {\n");
145  for (auto it = faces.begin(); it != faces.end(); ++it)
146  {
147  MVertex *v1 = it->first.getVertex(0);
148  MVertex *v2 = it->first.getVertex(1);
149  MVertex *v3 = it->first.getVertex(2);
150  fprintf(f, "ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d};\n", v1->x(), v1->y(), v1->z(), v2->x(), v2->y(),
151  v2->z(), v3->x(), v3->y(), v3->z(), it->second->tag(), it->second->tag(), it->second->tag());
152  }
153  fprintf(f, "};\n");
154  fclose(f);
155  }
156  }
157 };
158 
159 template <class T>
160 static void GetQualityMeasure(std::vector<T *> &ele, double &gamma, double &gammaMin, double &gammaMax, double &minSICN,
161  double &minSICNMin, double &minSICNMax, double &minSIGE, double &minSIGEMin,
162  double &minSIGEMax, double quality[3][100])
163 {
164  for (std::size_t i = 0; i < ele.size(); i++)
165  {
166  double g = ele[i]->gammaShapeMeasure();
167  gamma += g;
168  gammaMin = std::min(gammaMin, g);
169  gammaMax = std::max(gammaMax, g);
170  double s = ele[i]->minSICNShapeMeasure();
171  minSICN += s;
172  minSICNMin = std::min(minSICNMin, s);
173  minSICNMax = std::max(minSICNMax, s);
174  double e = ele[i]->minSIGEShapeMeasure();
175  minSIGE += e;
176  minSIGEMin = std::min(minSIGEMin, e);
177  minSIGEMax = std::max(minSIGEMax, e);
178  for (int j = 0; j < 100; j++)
179  {
180  if (s > (2 * j - 100) / 100. && s <= (2 * j - 98) / 100.)
181  quality[0][j]++;
182  if (g > j / 100. && g <= (j + 1) / 100.)
183  quality[1][j]++;
184  if (e > (2 * j - 100) / 100. && e <= (2 * j - 98) / 100.)
185  quality[2][j]++;
186  }
187  }
188 }
189 
190 void GetStatistics(double stat[50], double quality[3][100], bool visibleOnly)
191 {
192  for (int i = 0; i < 50; i++)
193  stat[i] = 0.;
194 
195  GModel *m = GModel::current();
196 
197  if (!m)
198  return;
199 
200  stat[0] = m->getNumVertices();
201  stat[1] = m->getNumEdges();
202  stat[2] = m->getNumFaces();
203  stat[3] = m->getNumRegions();
204 
205  std::map<int, std::vector<GEntity *>> physicals[4];
206  m->getPhysicalGroups(physicals);
207  stat[45] = physicals[0].size() + physicals[1].size() + physicals[2].size() + physicals[3].size();
208 
209  for (auto it = m->firstVertex(); it != m->lastVertex(); ++it)
210  {
211  if (visibleOnly && !(*it)->getVisibility())
212  continue;
213  stat[4] += (*it)->mesh_vertices.size();
214  stat[5] += (*it)->points.size();
215  }
216 
217  for (auto it = m->firstEdge(); it != m->lastEdge(); ++it)
218  {
219  if (visibleOnly && !(*it)->getVisibility())
220  continue;
221  stat[4] += (*it)->mesh_vertices.size();
222  stat[6] += (*it)->lines.size();
223  }
224 
225  for (auto it = m->firstFace(); it != m->lastFace(); ++it)
226  {
227  if (visibleOnly && !(*it)->getVisibility())
228  continue;
229  stat[4] += (*it)->mesh_vertices.size();
230  stat[7] += (*it)->triangles.size();
231  stat[8] += (*it)->quadrangles.size();
232  }
233 
234  for (auto it = m->firstRegion(); it != m->lastRegion(); ++it)
235  {
236  if (visibleOnly && !(*it)->getVisibility())
237  continue;
238  stat[4] += (*it)->mesh_vertices.size();
239  stat[9] += (*it)->tetrahedra.size();
240  stat[10] += (*it)->hexahedra.size();
241  stat[11] += (*it)->prisms.size();
242  stat[12] += (*it)->pyramids.size();
243  stat[13] += (*it)->trihedra.size();
244  }
245 
246  stat[14] = CTX::instance()->meshTimer[0];
247  stat[15] = CTX::instance()->meshTimer[1];
248  stat[16] = CTX::instance()->meshTimer[2];
249 
250  if (quality)
251  {
252  for (int i = 0; i < 3; i++)
253  for (int j = 0; j < 100; j++)
254  quality[i][j] = 0.;
255  double minSICN = 0., minSICNMin = 1., minSICNMax = -1.;
256  double minSIGE = 0., minSIGEMin = 1., minSIGEMax = -1.;
257  double gamma = 0., gammaMin = 1., gammaMax = 0.;
258 
259  double N = stat[9] + stat[10] + stat[11] + stat[12] + stat[13];
260  if (N)
261  { // if we have 3D elements
262  for (auto it = m->firstRegion(); it != m->lastRegion(); ++it)
263  {
264  if (visibleOnly && !(*it)->getVisibility())
265  continue;
266  GetQualityMeasure((*it)->tetrahedra, gamma, gammaMin, gammaMax, minSICN, minSICNMin, minSICNMax,
267  minSIGE, minSIGEMin, minSIGEMax, quality);
268  GetQualityMeasure((*it)->hexahedra, gamma, gammaMin, gammaMax, minSICN, minSICNMin, minSICNMax, minSIGE,
269  minSIGEMin, minSIGEMax, quality);
270  GetQualityMeasure((*it)->prisms, gamma, gammaMin, gammaMax, minSICN, minSICNMin, minSICNMax, minSIGE,
271  minSIGEMin, minSIGEMax, quality);
272  GetQualityMeasure((*it)->pyramids, gamma, gammaMin, gammaMax, minSICN, minSICNMin, minSICNMax, minSIGE,
273  minSIGEMin, minSIGEMax, quality);
274  }
275  }
276  else
277  { // 2D elements
278  N = stat[7] + stat[8];
279  for (auto it = m->firstFace(); it != m->lastFace(); ++it)
280  {
281  if (visibleOnly && !(*it)->getVisibility())
282  continue;
283  GetQualityMeasure((*it)->quadrangles, gamma, gammaMin, gammaMax, minSICN, minSICNMin, minSICNMax,
284  minSIGE, minSIGEMin, minSIGEMax, quality);
285  GetQualityMeasure((*it)->triangles, gamma, gammaMin, gammaMax, minSICN, minSICNMin, minSICNMax, minSIGE,
286  minSIGEMin, minSIGEMax, quality);
287  }
288  }
289  if (N)
290  {
291  stat[18] = minSICN / N;
292  stat[19] = minSICNMin;
293  stat[20] = minSICNMax;
294  stat[21] = gamma / N;
295  stat[22] = gammaMin;
296  stat[23] = gammaMax;
297  stat[24] = minSIGE / N;
298  stat[25] = minSIGEMin;
299  stat[26] = minSIGEMax;
300  }
301  }
302 
303 #if defined(HAVE_POST)
304  stat[27] = PView::list.size();
305  for (std::size_t i = 0; i < PView::list.size(); i++)
306  {
307  PViewData *data = PView::list[i]->getData(true);
308  stat[28] += data->getNumPoints();
309  stat[29] += data->getNumLines();
310  stat[30] += data->getNumTriangles();
311  stat[31] += data->getNumQuadrangles();
312  stat[32] += data->getNumTetrahedra();
313  stat[33] += data->getNumHexahedra();
314  stat[34] += data->getNumPrisms();
315  stat[35] += data->getNumPyramids();
316  stat[36] += data->getNumStrings2D() + data->getNumStrings3D();
317  }
318 #endif
319 }
320 
321 static bool TooManyElements(GModel *m, int dim)
322 {
323  if (CTX::instance()->expertMode || !m->getNumVertices())
324  return false;
325 
326  // try to detect obvious mistakes in characteristic lenghts (one of the most
327  // common cause for erroneous bug reports on the mailing list)
328  double sumAllLc = 0.;
329  for (auto it = m->firstVertex(); it != m->lastVertex(); ++it)
330  sumAllLc += (*it)->prescribedMeshSizeAtVertex() * CTX::instance()->mesh.lcFactor;
331  sumAllLc /= (double)m->getNumVertices();
332  if (!sumAllLc || pow(CTX::instance()->lc / sumAllLc, dim) > 1.e10)
333  return !Msg::GetAnswer("Your choice of mesh element sizes will likely produce a very\n"
334  "large mesh. Do you really want to continue?\n\n"
335  "(To disable this warning in the future, select `Enable expert mode'\n"
336  "in the option dialog.)",
337  1, "Cancel", "Continue");
338  return false;
339 }
340 
341 static void Mesh0D(GModel *m)
342 {
343  m->getFields()->initialize();
344 
345  for (auto it = m->firstVertex(); it != m->lastVertex(); ++it)
346  {
347  GVertex *gv = *it;
348  if (gv->mesh_vertices.empty())
349  gv->mesh_vertices.push_back(new MVertex(gv->x(), gv->y(), gv->z(), gv));
350  if (gv->points.empty())
351  gv->points.push_back(new MPoint(gv->mesh_vertices.back()));
352  }
353  for (auto it = m->firstVertex(); it != m->lastVertex(); ++it)
354  {
355  GVertex *gv = *it;
356  if (gv->getMeshMaster() != gv)
357  {
358  if (gv->correspondingVertices.empty())
359  {
360  GVertex *master = dynamic_cast<GVertex *>(gv->getMeshMaster());
361  if (master)
362  gv->correspondingVertices[gv->mesh_vertices[0]] = master->mesh_vertices[0];
363  }
364  }
365  }
366 }
367 
368 static void Mesh1D(GModel *m)
369 {
370  if (CTX::instance()->abortOnError && Msg::GetErrorCount())
371  return;
372 
373  m->getFields()->initialize();
374 
375  if (TooManyElements(m, 1))
376  return;
377  Msg::StatusBar(true, "Meshing 1D...");
378  double t1 = Cpu(), w1 = TimeOfDay();
379 
380  int nthreads = CTX::instance()->numThreads;
381  if (CTX::instance()->mesh.maxNumThreads1D > 0)
382  nthreads = CTX::instance()->mesh.maxNumThreads1D;
383  if (!nthreads)
384  nthreads = Msg::GetMaxThreads();
385 
386  // boundary layers are not yet thread-safe
388  nthreads = 1;
389 
390  for (auto it = m->firstEdge(); it != m->lastEdge(); ++it)
391  {
392  // Extruded meshes are not yet fully thread-safe (not sure why!)
393  if ((*it)->meshAttributes.extrude && (*it)->meshAttributes.extrude->mesh.ExtrudeMesh)
394  nthreads = 1;
395  }
396 
397  std::vector<GEdge *> temp;
398  for (auto it = m->firstEdge(); it != m->lastEdge(); ++it)
399  {
400  (*it)->meshStatistics.status = GEdge::PENDING;
401  temp.push_back(*it);
402  }
403 
404  int nIter = 0, nTot = m->getNumEdges();
406 
407  while (1)
408  {
409  if (CTX::instance()->abortOnError && Msg::GetErrorCount())
410  {
411  Msg::Warning("Aborted 1D meshing");
412  break;
413  }
414 
415  int nPending = 0;
416  bool exceptions = false;
417 #pragma omp parallel for schedule(dynamic) num_threads(nthreads)
418  for (size_t K = 0; K < temp.size(); K++)
419  {
420  if (exceptions)
421  continue;
422  int localPending = 0;
423  GEdge *ed = temp[K];
425  {
426  try
427  { // OpenMP forbids leaving block via exception
428  ed->mesh(true);
429  }
430  catch (...)
431  {
432  exceptions = true;
433  }
434 #pragma omp atomic capture
435  {
436  ++nPending;
437  localPending = nPending;
438  }
439  }
440  if (!nIter)
441  Msg::ProgressMeter(localPending, false, "Meshing 1D...");
442  }
443  if (exceptions)
444  throw std::runtime_error(Msg::GetLastError());
445  if (!nPending)
446  break;
447  if (nIter++ > CTX::instance()->mesh.maxRetries)
448  break;
449  }
450 
452 
453  double t2 = Cpu(), w2 = TimeOfDay();
454  CTX::instance()->meshTimer[0] = w2 - w1;
455  Msg::StatusBar(true, "Done meshing 1D (Wall %gs, CPU %gs)", CTX::instance()->meshTimer[0], t2 - t1);
456 }
457 
459 {
460  FILE *statreport = nullptr;
461  if (CTX::instance()->createAppendMeshStatReport == 1)
462  statreport = Fopen(CTX::instance()->meshStatReportFileName.c_str(), "w");
463  else if (CTX::instance()->createAppendMeshStatReport == 2)
464  statreport = Fopen(CTX::instance()->meshStatReportFileName.c_str(), "a");
465  else
466  return;
467 
468  if (!statreport)
469  {
470  Msg::Error("Could not open file '%s'", CTX::instance()->meshStatReportFileName.c_str());
471  return;
472  }
473 
474  double worst = 1, best = 0, avg = 0;
475  double e_long = 0, e_short = 1.e22, e_avg = 0;
476  int nTotT = 0, nTotE = 0, nTotGoodLength = 0, nTotGoodQuality = 0;
477  int nUnmeshed = 0, numFaces = 0;
478 
479  if (CTX::instance()->createAppendMeshStatReport == 1)
480  {
481  fprintf(statreport, "2D stats\tname\t\t#faces\t\t#fail\t\t"
482  "#t\t\tQavg\t\tQbest\t\tQworst\t\t#Q>90\t\t#Q>90/#t\t"
483  "#e\t\ttau\t\t#Egood\t\t#Egood/#e\tCPU\n");
484  if (m->empty())
485  {
486  fclose(statreport);
487  return;
488  }
489  }
490 
491  for (auto it = m->firstFace(); it != m->lastFace(); ++it)
492  {
493  if ((*it)->geomType() != GEntity::DiscreteSurface)
494  {
495  worst = std::min((*it)->meshStatistics.worst_element_shape, worst);
496  best = std::max((*it)->meshStatistics.best_element_shape, best);
497  avg += (*it)->meshStatistics.average_element_shape * (*it)->meshStatistics.nbTriangle;
498  e_avg += (*it)->meshStatistics.efficiency_index;
499  e_long = std::max((*it)->meshStatistics.longest_edge_length, e_long);
500  e_short = std::min((*it)->meshStatistics.smallest_edge_length, e_short);
501  if ((*it)->meshStatistics.status == GFace::FAILED || (*it)->meshStatistics.status == GFace::PENDING)
502  nUnmeshed++;
503  nTotT += (*it)->meshStatistics.nbTriangle;
504  nTotE += (*it)->meshStatistics.nbEdge;
505  nTotGoodLength += (*it)->meshStatistics.nbGoodLength;
506  nTotGoodQuality += (*it)->meshStatistics.nbGoodQuality;
507  numFaces++;
508  }
509  }
510 
511  Msg::Info("Efficiency index for surface mesh tau=%g ", 100 * exp(e_avg / (double)nTotE));
512 
513  fprintf(statreport, "\t%16s\t%d\t\t%d\t\t", m->getName().c_str(), numFaces, nUnmeshed);
514  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,
515  nTotGoodQuality, (double)nTotGoodQuality / nTotT);
516  fprintf(statreport, "%d\t\t%8.7f\t%d\t\t%8.7f\t%8.1f\n", nTotE, exp(e_avg / (double)nTotE), nTotGoodLength,
517  (double)nTotGoodLength / nTotE, CTX::instance()->meshTimer[1]);
518  fclose(statreport);
519 }
520 
521 static void Mesh2D(GModel *m)
522 {
523  if (CTX::instance()->abortOnError && Msg::GetErrorCount())
524  return;
525 
526  m->getFields()->initialize();
527 
528  if (TooManyElements(m, 2))
529  return;
530  Msg::StatusBar(true, "Meshing 2D...");
531  double t1 = Cpu(), w1 = TimeOfDay();
532 
533  int nthreads = CTX::instance()->numThreads;
534  if (CTX::instance()->mesh.maxNumThreads2D > 0)
535  nthreads = CTX::instance()->mesh.maxNumThreads2D;
536  if (!nthreads)
537  nthreads = Msg::GetMaxThreads();
538 
539  // boundary layers are not yet thread-safe
541  nthreads = 1;
542 
543  for (auto it = m->firstFace(); it != m->lastFace(); ++it)
544  {
545  // Frontal-Delaunay for quads and co are not yet thread-safe
546  if ((*it)->getMeshingAlgo() == ALGO_2D_FRONTAL_QUAD || (*it)->getMeshingAlgo() == ALGO_2D_PACK_PRLGRMS ||
547  (*it)->getMeshingAlgo() == ALGO_2D_PACK_PRLGRMS_CSTR)
548  nthreads = 1;
549 
550  // Periodic meshing is not yet thread-safe
551  if ((*it)->getMeshMaster() != *it)
552  nthreads = 1;
553 
554  // Extruded meshes are not yet fully thread-safe (not sure why!)
555  if ((*it)->meshAttributes.extrude && (*it)->meshAttributes.extrude->mesh.ExtrudeMesh)
556  nthreads = 1;
557  }
558 
559  for (auto it = m->firstFace(); it != m->lastFace(); ++it)
560  (*it)->meshStatistics.status = GFace::PENDING;
561 
562  // boundary layers are special: their generation (including vertices and curve
563  // meshes) is global as it depends on a smooth normal field generated from the
564  // surface mesh of the source surfaces
565  if (!Mesh2DWithBoundaryLayers(m))
566  {
567  std::set<GFace *, GEntityPtrLessThan> f;
568  for (auto it = m->firstFace(); it != m->lastFace(); ++it)
569  f.insert(*it);
570 
571  int nIter = 0, nTot = m->getNumFaces();
572 
574 
575  while (1)
576  {
577  if (CTX::instance()->abortOnError && Msg::GetErrorCount())
578  {
579  Msg::Warning("Aborted 2D meshing");
580  break;
581  }
582 
583  int nPending = 0;
584  bool exceptions = false;
585  std::vector<GFace *> temp;
586  temp.insert(temp.begin(), f.begin(), f.end());
587 #pragma omp parallel for schedule(dynamic) num_threads(nthreads)
588  for (size_t K = 0; K < temp.size(); K++)
589  {
590  if (exceptions)
591  continue;
592  int localPending = 0;
593  if (temp[K]->meshStatistics.status == GFace::PENDING)
594  {
596  try
597  { // OpenMP forbids leaving block via exception
598  temp[K]->mesh(true);
599  }
600  catch (...)
601  {
602  exceptions = true;
603  }
604 #pragma omp atomic capture
605  {
606  ++nPending;
607  localPending = nPending;
608  }
609  }
610  if (!nIter)
611  Msg::ProgressMeter(localPending, false, "Meshing 2D...");
612  }
613  if (exceptions)
614  throw std::runtime_error(Msg::GetLastError());
615  if (!nPending)
616  break;
617  // iter == 2 is for meshing re-parametrized surfaces; after that, we
618  // serialize (self-intersections of 1D meshes are not thread safe)!
619  if (nIter > 2)
620  nthreads = 1;
621  if (nIter++ > CTX::instance()->mesh.maxRetries)
622  break;
623  }
624 
626  }
627 
628  if (CTX::instance()->mesh.algo2d == ALGO_2D_QUAD_QUASI_STRUCT)
629  {
631 
632  // In the quasi-structured pipeline, the quad-dominant mesh is subdivided
633  // into a full quad mesh. TODO: 1) a faster CAD projection approach (from
634  // uv) and 2) verify quality during projection
635 
636  // bool linear = false; RefineMesh(m, linear, true, false);
638 
639  OptimizeMesh(m, "QuadQuasiStructured");
640  }
641 
642  double t2 = Cpu(), w2 = TimeOfDay();
643  CTX::instance()->meshTimer[1] = w2 - w1;
644  Msg::StatusBar(true, "Done meshing 2D (Wall %gs, CPU %gs)", CTX::instance()->meshTimer[1], t2 - t1);
645 
647 }
648 
649 static void FindConnectedRegions(const std::vector<GRegion *> &del, std::vector<std::vector<GRegion *>> &connected)
650 {
651  std::vector<GRegion *> delaunay = del;
652  // test: connected.resize(1); connected[0] = delaunay; return;
653 
654  const std::size_t nbVolumes = delaunay.size();
655  if (!nbVolumes)
656  return;
657  while (delaunay.size())
658  {
659  std::set<GRegion *> oneDomain;
660  std::stack<GRegion *> _stack;
661  GRegion *r = delaunay[0];
662  _stack.push(r);
663  while (!_stack.empty())
664  {
665  r = _stack.top();
666  _stack.pop();
667  oneDomain.insert(r);
668  std::vector<GFace *> faces = r->faces();
669  for (auto it = faces.begin(); it != faces.end(); ++it)
670  {
671  GFace *gf = *it;
672  GRegion *other = (gf->getRegion(0) == r) ? gf->getRegion(1) : gf->getRegion(0);
673  if (other != nullptr && oneDomain.find(other) == oneDomain.end())
674  _stack.push(other);
675  }
676  }
677  std::vector<GRegion *> temp1, temp2;
678  for (std::size_t i = 0; i < delaunay.size(); i++)
679  {
680  r = delaunay[i];
681  if (oneDomain.find(r) == oneDomain.end())
682  temp1.push_back(r);
683  else
684  temp2.push_back(r);
685  }
686  connected.push_back(temp2);
687  delaunay = temp1;
688  }
689  Msg::Info("3D Meshing %d volume%s with %d connected component%s", nbVolumes, nbVolumes > 1 ? "s" : "",
690  connected.size(), connected.size() > 1 ? "s" : "");
691 }
692 
693 // JFR : use hex-splitting to resolve non conformity
694 // : if howto == 1 ---> split hexes
695 // : if howto == 2 ---> create transition elements
696 
697 /*
698  v3 v2
699  x--------x
700  |\ |
701  | \ |
702  | \ |
703  | \ |
704  x--------x
705  v0 v1
706  */
707 
708 void buildUniqueFaces(GRegion *gr, std::set<MFace, MFaceLessThan> &bnd)
709 {
710  for (std::size_t i = 0; i < gr->getNumMeshElements(); i++)
711  {
712  MElement *e = gr->getMeshElement(i);
713  for (int j = 0; j < e->getNumFaces(); j++)
714  {
715  MFace f = e->getFace(j);
716  auto it = bnd.find(f);
717  if (it == bnd.end())
718  bnd.insert(f);
719  else
720  bnd.erase(it);
721  }
722  }
723 }
724 
725 bool MakeMeshConformal(GModel *gm, int howto)
726 {
727  fs_cont search;
728  buildFaceSearchStructure(gm, search);
729  std::set<MFace, MFaceLessThan> bnd;
730  for (auto rit = gm->firstRegion(); rit != gm->lastRegion(); ++rit)
731  {
732  GRegion *gr = *rit;
733  buildUniqueFaces(gr, bnd);
734  }
735  // bnd2 contains non conforming faces
736 
737  std::set<MFace, MFaceLessThan> bnd2;
738  for (auto itf = bnd.begin(); itf != bnd.end(); ++itf)
739  {
740  GFace *gfound = findInFaceSearchStructure(*itf, search);
741  if (!gfound)
742  {
743  bnd2.insert(*itf);
744  }
745  }
746  bnd.clear();
747 
748  Msg::Info("%d hanging faces", bnd2.size());
749 
750  std::set<MFace, MFaceLessThan> ncf;
751  for (auto itf = bnd2.begin(); itf != bnd2.end(); ++itf)
752  {
753  const MFace &f = *itf;
754  if (f.getNumVertices() == 4)
755  { // quad face
756  auto it1 = bnd2.find(MFace(f.getVertex(0), f.getVertex(1), f.getVertex(2)));
757  auto it2 = bnd2.find(MFace(f.getVertex(2), f.getVertex(3), f.getVertex(0)));
758  if (it1 != bnd2.end() && it2 != bnd2.end())
759  {
760  ncf.insert(MFace(f.getVertex(1), f.getVertex(2), f.getVertex(3), f.getVertex(0)));
761  }
762  else
763  {
764  it1 = bnd2.find(MFace(f.getVertex(0), f.getVertex(1), f.getVertex(3)));
765  it2 = bnd2.find(MFace(f.getVertex(3), f.getVertex(1), f.getVertex(2)));
766  if (it1 != bnd2.end() && it2 != bnd2.end())
767  {
768  ncf.insert(MFace(f.getVertex(0), f.getVertex(1), f.getVertex(2), f.getVertex(3)));
769  }
770  else
771  {
772  Msg::Error("MakeMeshConformal: wrong mesh topology");
773  return false;
774  }
775  }
776  }
777  }
778  bnd2.clear();
779 
780  for (auto rit = gm->firstRegion(); rit != gm->lastRegion(); ++rit)
781  {
782  GRegion *gr = *rit;
783  std::vector<MHexahedron *> remainingHexes;
784  for (std::size_t i = 0; i < gr->hexahedra.size(); i++)
785  {
786  MHexahedron *e = gr->hexahedra[i];
787  std::vector<MFace> faces;
788  for (int j = 0; j < e->getNumFaces(); j++)
789  {
790  MFace f = e->getFace(j);
791  auto it = ncf.find(f);
792  if (it == ncf.end())
793  {
794  faces.push_back(f);
795  }
796  else
797  {
798  faces.push_back(MFace(it->getVertex(0), it->getVertex(1), it->getVertex(3)));
799  faces.push_back(MFace(it->getVertex(1), it->getVertex(2), it->getVertex(3)));
800  }
801  }
802  // Hex is only surrounded by compatible elements
803  if ((int)faces.size() == e->getNumFaces())
804  {
805  remainingHexes.push_back(e);
806  }
807  else
808  {
809  SPoint3 pp = e->barycenter();
810  MVertex *newv = new MVertex(pp.x(), pp.y(), pp.z(), gr);
811  gr->mesh_vertices.push_back(newv);
812  for (std::size_t j = 0; j < faces.size(); j++)
813  {
814  MFace &f = faces[j];
815  if (f.getNumVertices() == 4)
816  {
817  gr->pyramids.push_back(
818  new MPyramid(f.getVertex(0), f.getVertex(1), f.getVertex(2), f.getVertex(3), newv));
819  }
820  else
821  {
822  gr->tetrahedra.push_back(
823  new MTetrahedron(f.getVertex(0), f.getVertex(1), f.getVertex(2), newv));
824  }
825  }
826  }
827  }
828  gr->hexahedra = remainingHexes;
829  remainingHexes.clear();
830  std::vector<MPrism *> remainingPrisms;
831  for (std::size_t i = 0; i < gr->prisms.size(); i++)
832  {
833  MPrism *e = gr->prisms[i];
834  std::vector<MFace> faces;
835  for (int j = 0; j < e->getNumFaces(); j++)
836  {
837  MFace f = e->getFace(j);
838  auto it = ncf.find(f);
839  if (it == ncf.end())
840  {
841  faces.push_back(f);
842  }
843  else
844  {
845  faces.push_back(MFace(it->getVertex(0), it->getVertex(1), it->getVertex(3)));
846  faces.push_back(MFace(it->getVertex(1), it->getVertex(2), it->getVertex(3)));
847  }
848  }
849  // Hex is only surrounded by compatible elements
850  if ((int)faces.size() == e->getNumFaces())
851  {
852  remainingPrisms.push_back(e);
853  }
854  else
855  {
856  SPoint3 pp = e->barycenter();
857  MVertex *newv = new MVertex(pp.x(), pp.y(), pp.z(), gr);
858  gr->mesh_vertices.push_back(newv);
859  for (std::size_t j = 0; j < faces.size(); j++)
860  {
861  MFace &f = faces[j];
862  if (f.getNumVertices() == 4)
863  {
864  gr->pyramids.push_back(
865  new MPyramid(f.getVertex(0), f.getVertex(1), f.getVertex(2), f.getVertex(3), newv));
866  }
867  else
868  {
869  gr->tetrahedra.push_back(
870  new MTetrahedron(f.getVertex(0), f.getVertex(1), f.getVertex(2), newv));
871  }
872  }
873  }
874  }
875  gr->prisms = remainingPrisms;
876  }
877 
878  return true;
879 }
880 
881 #if defined(HAVE_DOMHEX)
882 static void TestConformity(GModel *gm)
883 {
884  fs_cont search;
885  buildFaceSearchStructure(gm, search);
886  int count = 0;
887  for (auto rit = gm->firstRegion(); rit != gm->lastRegion(); ++rit)
888  {
889  GRegion *gr = *rit;
890  std::set<MFace, MFaceLessThan> bnd;
891  double vol = 0.0;
892  for (std::size_t i = 0; i < gr->getNumMeshElements(); i++)
893  {
894  MElement *e = gr->getMeshElement(i);
895  vol += fabs(e->getVolume());
896  for (int j = 0; j < e->getNumFaces(); j++)
897  {
898  MFace f = e->getFace(j);
899  auto it = bnd.find(f);
900  if (it == bnd.end())
901  bnd.insert(f);
902  else
903  bnd.erase(it);
904  }
905  }
906  Msg::Info("vol(%d) = %12.5E", gr->tag(), vol);
907 
908  for (auto itf = bnd.begin(); itf != bnd.end(); ++itf)
909  {
910  GFace *gfound = findInFaceSearchStructure(*itf, search);
911  if (!gfound)
912  {
913  count++;
914  }
915  }
916  }
917  if (!count)
918  Msg::Info("Mesh Conformity: OK");
919  else
920  Msg::Error("Mesh is not conforming (%d hanging faces)!", count);
921 }
922 #endif
923 
924 static void Mesh3D(GModel *m)
925 {
926  if (CTX::instance()->abortOnError && Msg::GetErrorCount())
927  return;
928 
929  m->getFields()->initialize();
930 
931  if (TooManyElements(m, 3))
932  return;
933  Msg::StatusBar(true, "Meshing 3D...");
934  double t1 = Cpu(), w1 = TimeOfDay();
935 
936  if (m->getNumRegions())
937  {
939  Msg::ProgressMeter(0, false, "Meshing 3D...");
940  }
941 
942  // mesh the extruded volumes first
943  std::for_each(m->firstRegion(), m->lastRegion(), meshGRegionExtruded());
944 
945  // then subdivide if necessary (unfortunately the subdivision is a
946  // global operation, which can require changing the surface mesh!)
948 
949  // then mesh all the non-delaunay regions (front3D with netgen)
950  std::vector<GRegion *> delaunay;
951  std::for_each(m->firstRegion(), m->lastRegion(), meshGRegion(delaunay));
952 
953  // and finally mesh the delaunay regions (again, this is global; but
954  // we mesh each connected part separately for performance and mesh
955  // quality reasons)
956  std::vector<std::vector<GRegion *>> connected;
957  FindConnectedRegions(delaunay, connected);
958 
959  // remove quads elements for volumes that are recombined
960  for (std::size_t i = 0; i < connected.size(); i++)
961  {
962  for (std::size_t j = 0; j < connected[i].size(); j++)
963  {
964  GRegion *gr = connected[i][j];
965  if (CTX::instance()->mesh.recombine3DAll || gr->meshAttributes.recombine3D)
966  {
967  std::vector<GFace *> f = gr->faces();
968  for (auto it = f.begin(); it != f.end(); ++it)
969  quadsToTriangles(*it, 1000000);
970  }
971  }
972  }
973 
974 #if defined(HAVE_DOMHEX)
975  double time_recombination = 0., vol_element_recombination = 0.;
976  double vol_hexa_recombination = 0.;
977  int nb_elements_recombination = 0, nb_hexa_recombination = 0;
978 #endif
979 
980  for (std::size_t i = 0; i < connected.size(); i++)
981  {
982  if (CTX::instance()->abortOnError && Msg::GetErrorCount())
983  {
984  Msg::Warning("Aborted 3D meshing");
985  break;
986  }
987 
988  MeshDelaunayVolume(connected[i]);
989 
990 #if defined(HAVE_DOMHEX)
991  // additional code for experimental hex mesh - will eventually be replaced
992  // by new HXT-based code
993  for (std::size_t j = 0; j < connected[i].size(); j++)
994  {
995  GRegion *gr = connected[i][j];
996  bool treat_region_ok = false;
997  if (CTX::instance()->mesh.algo3d == ALGO_3D_RTREE)
998  {
999  if (old_algo_hexa())
1000  {
1001  Filler f;
1002  f.treat_region(gr);
1003  treat_region_ok = true;
1004  }
1005  else
1006  {
1007  Filler3D f;
1008  treat_region_ok = f.treat_region(gr);
1009  }
1010  }
1011  if (treat_region_ok && (CTX::instance()->mesh.recombine3DAll || gr->meshAttributes.recombine3D))
1012  {
1013  if (CTX::instance()->mesh.optimize)
1014  {
1015  optimizeMeshGRegion opt;
1016  opt(gr);
1017  }
1018  double a = TimeOfDay();
1019  // CTX::instance()->mesh.recombine3DLevel = 2;
1020  if (CTX::instance()->mesh.recombine3DLevel >= 0)
1021  {
1022  Recombinator rec;
1023  rec.execute(gr);
1024  }
1025  if (CTX::instance()->mesh.recombine3DLevel >= 1)
1026  {
1027  Supplementary sup;
1028  sup.execute(gr);
1029  }
1030  PostOp post;
1031  post.execute(gr, CTX::instance()->mesh.recombine3DLevel, CTX::instance()->mesh.recombine3DConformity);
1032  // CTX::instance()->mesh.recombine3DConformity);
1033  // 0: no pyramid, 1: single-step, 2: two-steps (conforming),
1034  // true: fill non-conformities with trihedra
1035  RelocateVertices(gr, CTX::instance()->mesh.nbSmoothing);
1036  // while(LaplaceSmoothing (gr)){
1037  // }
1038  nb_elements_recombination += post.get_nb_elements();
1039  nb_hexa_recombination += post.get_nb_hexahedra();
1040  vol_element_recombination += post.get_vol_elements();
1041  vol_hexa_recombination += post.get_vol_hexahedra();
1042  time_recombination += (TimeOfDay() - a);
1043  }
1044  }
1045 #endif
1046  }
1047 
1048 #if defined(HAVE_DOMHEX)
1050  {
1051  Msg::Info("Recombination timing:");
1052  Msg::Info(" - Cumulative time recombination: %g s", time_recombination);
1053  Msg::Info("Recombination cumulative statistics:");
1054  Msg::Info(" - Percentage of hexahedra (#) : %g", nb_hexa_recombination * 100. / nb_elements_recombination);
1055  Msg::Info(" - Percentage of hexahedra (Vol): %g", vol_hexa_recombination * 100. / vol_element_recombination);
1056  // MakeMeshConformal(m, 1);
1057  TestConformity(m);
1058  }
1059 #endif
1060 
1061  // ensure that all volume Jacobians are positive
1062  m->setAllVolumesPositive();
1063 
1064  if (Msg::GetVerbosity() > 98)
1065  std::for_each(m->firstRegion(), m->lastRegion(), EmbeddedCompatibilityTest());
1066 
1067  std::stringstream debugInfo;
1068  debugInfo << "No elements in volume ";
1069  bool emptyRegionFound = false;
1070  for (auto it = m->firstRegion(); it != m->lastRegion(); ++it)
1071  {
1072  GRegion *gr = *it;
1073  if (CTX::instance()->mesh.meshOnlyVisible && !gr->getVisibility())
1074  continue;
1075  if (CTX::instance()->mesh.meshOnlyEmpty && gr->getNumMeshElements())
1076  continue;
1077  if (gr->getNumMeshElements() == 0)
1078  {
1079  debugInfo << gr->tag() << " ";
1080  emptyRegionFound = true;
1081  }
1082  }
1083  if (emptyRegionFound)
1084  {
1085  debugInfo << std::endl;
1086  Msg::Error(debugInfo.str().c_str());
1087  }
1088 
1089  double t2 = Cpu(), w2 = TimeOfDay();
1090  CTX::instance()->meshTimer[2] = w2 - w1;
1091 
1092  if (m->getNumRegions())
1093  {
1094  Msg::ProgressMeter(1, false, "Meshing 3D...");
1096  }
1097 
1098  Msg::StatusBar(true, "Done meshing 3D (Wall %gs, CPU %gs)", CTX::instance()->meshTimer[2], t2 - t1);
1099 }
1100 
1101 void OptimizeMesh(GModel *m, const std::string &how, bool force, int niter)
1102 {
1103  if (CTX::instance()->abortOnError && Msg::GetErrorCount())
1104  return;
1105 
1106  if (how != "" && how != "Gmsh" && how != "Optimize" && how != "Netgen" && how != "HighOrder" &&
1107  how != "HighOrderElastic" && how != "HighOrderFastCurving" && how != "Laplace2D" && how != "Relocate2D" &&
1108  how != "Relocate3D" && how != "DiskQuadrangulation" && how != "QuadCavityRemeshing" &&
1109  how != "QuadQuasiStructured" && how != "UntangleMeshGeometry")
1110  {
1111  Msg::Error("Unknown mesh optimization method '%s'", how.c_str());
1112  return;
1113  }
1114 
1115  if (how == "" || how == "Gmsh" || how == "Optimize")
1116  Msg::StatusBar(true, "Optimizing mesh...");
1117  else
1118  Msg::StatusBar(true, "Optimizing mesh (%s)...", how.c_str());
1119  double t1 = Cpu(), w1 = TimeOfDay();
1120 
1121  if (how == "" || how == "Gmsh" || how == "Optimize")
1122  {
1123  for (auto it = m->firstRegion(); it != m->lastRegion(); it++)
1124  {
1125  optimizeMeshGRegion opt;
1126  opt(*it, force);
1127  }
1128  m->setAllVolumesPositive();
1129  }
1130  else if (how == "Netgen")
1131  {
1132  for (auto it = m->firstRegion(); it != m->lastRegion(); it++)
1133  {
1135  opt(*it, force);
1136  }
1137  m->setAllVolumesPositive();
1138  }
1139  else if (how == "HighOrder")
1140  {
1141 #if defined(HAVE_OPTHOM)
1142  OptHomParameters p;
1143  p.nbLayers = CTX::instance()->mesh.hoNLayers;
1144  p.BARRIER_MIN = CTX::instance()->mesh.hoThresholdMin;
1145  p.BARRIER_MAX = CTX::instance()->mesh.hoThresholdMax;
1146  p.itMax = CTX::instance()->mesh.hoIterMax;
1147  p.optPassMax = CTX::instance()->mesh.hoPassMax;
1148  p.fixBndNodes = CTX::instance()->mesh.hoFixBndNodes;
1149  p.dim = m->getDim();
1150  p.optPrimSurfMesh = CTX::instance()->mesh.hoPrimSurfMesh;
1151  p.optCAD = CTX::instance()->mesh.hoDistCAD;
1152  HighOrderMeshOptimizer(m, p);
1153 #else
1154  Msg::Error("High-order mesh optimization requires the OPTHOM module");
1155 #endif
1156  }
1157  else if (how == "HighOrderElastic")
1158  {
1159 #if defined(HAVE_OPTHOM)
1160  HighOrderMeshElasticAnalogy(m, false);
1161 #else
1162  Msg::Error("High-order mesh optimization requires the OPTHOM module");
1163 #endif
1164  }
1165  else if (how == "HighOrderFastCurving")
1166  {
1167 #if defined(HAVE_OPTHOM)
1168  FastCurvingParameters p;
1169  p.dim = m->getMeshDim();
1170  p.thickness = false;
1171  p.curveOuterBL = (FastCurvingParameters::OUTERBLCURVE)CTX::instance()->mesh.hoCurveOuterBL;
1172  p.maxNumLayers = CTX::instance()->mesh.hoNLayers;
1173  p.maxRho = CTX::instance()->mesh.hoMaxRho;
1174  p.maxAngle = CTX::instance()->mesh.hoMaxAngle;
1175  p.maxAngleInner = CTX::instance()->mesh.hoMaxInnerAngle;
1176  HighOrderMeshFastCurving(m, p, false);
1177 #else
1178  Msg::Error("High-order mesh optimization requires the OPTHOM module");
1179 #endif
1180  }
1181  else if (how == "Laplace2D")
1182  {
1183  for (auto it = m->firstFace(); it != m->lastFace(); ++it)
1184  {
1185  GFace *gf = *it;
1186  laplaceSmoothing(gf, niter);
1187  }
1188  }
1189  else if (how == "Relocate2D")
1190  {
1191  for (auto it = m->firstFace(); it != m->lastFace(); ++it)
1192  {
1193  GFace *gf = *it;
1194  RelocateVertices(gf, niter);
1195  }
1196  }
1197  else if (how == "Relocate3D")
1198  {
1199  for (auto it = m->firstRegion(); it != m->lastRegion(); ++it)
1200  {
1201  GRegion *gr = *it;
1202  RelocateVertices(gr, niter);
1203  }
1204  }
1205  else if (how == "DiskQuadrangulation")
1206  {
1207  for (GFace *gf : m->getFaces())
1208  {
1209  if (gf->meshStatistics.status == GFace::DONE)
1210  {
1211  gf->meshStatistics.status = GFace::PENDING;
1212  }
1213  }
1216  for (GFace *gf : m->getFaces())
1217  {
1218  if (gf->meshStatistics.status == GFace::PENDING)
1219  {
1220  gf->meshStatistics.status = GFace::DONE;
1221  }
1222  }
1223  }
1224  else if (how == "QuadCavityRemeshing")
1225  {
1226  for (GFace *gf : m->getFaces())
1227  {
1228  if (gf->meshStatistics.status == GFace::DONE)
1229  {
1230  gf->meshStatistics.status = GFace::PENDING;
1231  }
1232  }
1235  for (GFace *gf : m->getFaces())
1236  {
1237  if (gf->meshStatistics.status == GFace::PENDING)
1238  {
1239  gf->meshStatistics.status = GFace::DONE;
1240  }
1241  }
1242  }
1243  else if (how == "QuadQuasiStructured")
1244  {
1245  // The following methods only act on faces whose status is PENDING
1246  for (GFace *gf : m->getFaces())
1247  {
1248  if (gf->meshStatistics.status == GFace::DONE)
1249  {
1250  gf->meshStatistics.status = GFace::PENDING;
1251  }
1252  }
1257  for (GFace *gf : m->getFaces())
1258  {
1259  if (gf->meshStatistics.status == GFace::PENDING)
1260  {
1261  gf->meshStatistics.status = GFace::DONE;
1262  }
1263  }
1264  }
1265  else if (how == "UntangleMeshGeometry")
1266  {
1267 #if defined(HAVE_WINSLOWUNTANGLER)
1268  int nIterWinslow = 10;
1269  for (GFace *gf : m->getFaces())
1270  {
1271  if (CTX::instance()->mesh.meshOnlyVisible && !gf->getVisibility())
1272  continue;
1273  if (gf->geomType() == GFace::Plane)
1274  {
1275  double timeMax = 100.;
1276  untangleGFaceMeshConstrained(gf, nIterWinslow, timeMax);
1277  }
1278  else
1279  {
1280  Msg::Debug("- Surface %i: not planar, do not apply Winslow untangling", gf->tag());
1281  }
1282  }
1283  for (GRegion *gr : m->getRegions())
1284  {
1285  if (CTX::instance()->mesh.meshOnlyVisible && !gr->getVisibility())
1286  continue;
1287  double timeMax = 100.;
1288  untangleGRegionMeshConstrained(gr, nIterWinslow, timeMax);
1289  }
1290 #else
1291  Msg::Error("Untangle mesh geometry optimization requires the "
1292  "WinslowUntangler module");
1293 #endif
1294  }
1295 
1296  if (Msg::GetVerbosity() > 98)
1297  std::for_each(m->firstRegion(), m->lastRegion(), EmbeddedCompatibilityTest());
1298 
1299  double t2 = Cpu(), w2 = TimeOfDay();
1300  Msg::StatusBar(true, "Done optimizing mesh (Wall %gs, CPU %gs)", w2 - w1, t2 - t1);
1301 }
1302 
1304 {
1305  if (CTX::instance()->abortOnError && Msg::GetErrorCount())
1306  return;
1307 
1308  Msg::StatusBar(true, "Adapting 3D mesh...");
1309  double t1 = Cpu(), w1 = TimeOfDay();
1310 
1311  for (int i = 0; i < 10; i++)
1312  std::for_each(m->firstRegion(), m->lastRegion(), adaptMeshGRegion());
1313 
1314  double t2 = Cpu(), w2 = TimeOfDay();
1315  Msg::StatusBar(true, "Done adaptating 3D mesh (Wall %gs, CPU %gs)", w2 - w1, t2 - t1);
1316 }
1317 
1319 {
1320  if (CTX::instance()->abortOnError && Msg::GetErrorCount())
1321  return;
1322 
1323  Msg::StatusBar(true, "Recombining 2D mesh...");
1324  double t1 = Cpu(), w1 = TimeOfDay();
1325 
1326  for (auto it = m->firstFace(); it != m->lastFace(); ++it)
1327  {
1328  GFace *gf = *it;
1329  if (CTX::instance()->mesh.algoRecombine == 4)
1330  {
1332  }
1333  else
1334  {
1335  bool blossom = (CTX::instance()->mesh.algoRecombine == 1 || CTX::instance()->mesh.algoRecombine == 3);
1338  double minqual = CTX::instance()->mesh.recombineMinimumQuality;
1339  recombineIntoQuads(gf, blossom, topo, repos, minqual);
1340  }
1341  }
1342 
1343  double t2 = Cpu(), w2 = TimeOfDay();
1344  Msg::StatusBar(true, "Done recombining 2D mesh (Wall %gs, CPU %gs)", w2 - w1, t2 - t1);
1345 }
1346 
1347 static SPoint3 transform(MVertex *vsource, const std::vector<double> &tfo)
1348 {
1349  double ps[4] = {vsource->x(), vsource->y(), vsource->z(), 1.};
1350  double res[4] = {0., 0., 0., 0.};
1351  int idx = 0;
1352  for (int i = 0; i < 4; i++)
1353  for (int j = 0; j < 4; j++)
1354  res[i] += tfo[idx++] * ps[j];
1355 
1356  return SPoint3(res[0], res[1], res[2]);
1357 }
1358 
1359 static void relocateSlaveVertices(GFace *slave, std::map<MVertex *, MVertex *> &vertS2M, bool useClosestPoint)
1360 {
1361  for (auto vit = vertS2M.begin(); vit != vertS2M.end(); ++vit)
1362  {
1363  MFaceVertex *v = dynamic_cast<MFaceVertex *>(vit->first);
1364  if (v && v->onWhat() == slave)
1365  {
1366  SPoint3 p = transform(vit->second, slave->affineTransform);
1367  SPoint2 p2;
1368  if (useClosestPoint)
1369  {
1370  double guess[2];
1371  v->getParameter(0, guess[0]);
1372  v->getParameter(1, guess[1]);
1373  GPoint pp = slave->closestPoint(p, guess);
1374  p2.setPosition(pp.u(), pp.v());
1375  }
1376  else
1377  {
1378  p2 = slave->parFromPoint(p);
1379  }
1380  GPoint gp = slave->point(p2);
1381  v->setXYZ(gp.x(), gp.y(), gp.z());
1382  v->setParameter(0, gp.u());
1383  v->setParameter(1, gp.v());
1384  }
1385  }
1386 }
1387 
1388 static void relocateSlaveVertices(GEdge *slave, std::map<MVertex *, MVertex *> &vertS2M, bool useClosestPoint)
1389 {
1390  for (auto vit = vertS2M.begin(); vit != vertS2M.end(); ++vit)
1391  {
1392  MEdgeVertex *v = dynamic_cast<MEdgeVertex *>(vit->first);
1393  if (v && v->onWhat() == slave)
1394  {
1395  SPoint3 p = transform(vit->second, slave->affineTransform);
1396  double u;
1397  if (useClosestPoint)
1398  {
1399  v->getParameter(0, u);
1400  GPoint pp = slave->closestPoint(p, u);
1401  u = pp.u();
1402  }
1403  else
1404  {
1405  u = slave->parFromPoint(p);
1406  }
1407  GPoint gp = slave->point(u);
1408  v->setXYZ(gp.x(), gp.y(), gp.z());
1409  v->setParameter(0, u);
1410  }
1411  }
1412 }
1413 
1414 static void relocateSlaveVertices(std::vector<GEntity *> &entities, bool useClosestPoint)
1415 {
1416  std::multimap<GEntity *, GEntity *> master2slave;
1417  for (std::size_t i = 0; i < entities.size(); ++i)
1418  {
1419  if (entities[i]->dim() == 0)
1420  continue;
1421  GEntity *master = entities[i]->getMeshMaster();
1422  if (master != entities[i])
1423  {
1424  master2slave.insert(std::make_pair(master, entities[i]));
1425  }
1426  }
1427 
1428  for (auto it = master2slave.begin(); it != master2slave.end(); ++it)
1429  {
1430  if (it->first->dim() == 2)
1431  {
1432  GFace *master = dynamic_cast<GFace *>(it->first);
1433  GFace *slave = dynamic_cast<GFace *>(it->second);
1434  if (slave->affineTransform.size() < 16)
1435  continue;
1436  Msg::Info("Relocating nodes of slave surface %i using master %i%s", slave->tag(), master->tag(),
1437  useClosestPoint ? " (using closest point)" : "");
1438  relocateSlaveVertices(slave, slave->correspondingVertices, useClosestPoint);
1439  relocateSlaveVertices(slave, slave->correspondingHighOrderVertices, useClosestPoint);
1440  }
1441  else if (it->first->dim() == 1)
1442  {
1443  GEdge *master = dynamic_cast<GEdge *>(it->first);
1444  GEdge *slave = dynamic_cast<GEdge *>(it->second);
1445  if (slave->affineTransform.size() < 16)
1446  continue;
1447  Msg::Info("Relocating nodes of slave curve %i using master %i%s", slave->tag(), master->tag(),
1448  useClosestPoint ? " (using closest point)" : "");
1449  relocateSlaveVertices(slave, slave->correspondingVertices, useClosestPoint);
1450  relocateSlaveVertices(slave, slave->correspondingHighOrderVertices, useClosestPoint);
1451  }
1452  }
1453 }
1454 
1456 {
1457  if (CTX::instance()->abortOnError && Msg::GetErrorCount())
1458  return;
1459 
1460  for (auto it = m->firstEdge(); it != m->lastEdge(); ++it)
1461  {
1462  GEdge *tgt = *it;
1463 
1464  // non complete periodic info (e.g. through extrusion)
1465  if (tgt->vertexCounterparts.empty())
1466  continue;
1467 
1468  GEdge *src = dynamic_cast<GEdge *>(tgt->getMeshMaster());
1469 
1470  if (src != nullptr && src != tgt)
1471  {
1472  std::map<MVertex *, MVertex *> &v2v = tgt->correspondingVertices;
1473  std::map<MVertex *, MVertex *> &p2p = tgt->correspondingHighOrderVertices;
1474  p2p.clear();
1475 
1476  Msg::Info("Reconstructing periodicity for curve connection %d - %d", tgt->tag(), src->tag());
1477 
1478  std::map<MEdge, MLine *, MEdgeLessThan> srcEdges;
1479  for (std::size_t i = 0; i < src->getNumMeshElements(); i++)
1480  {
1481  MLine *srcLine = dynamic_cast<MLine *>(src->getMeshElement(i));
1482  if (!srcLine)
1483  {
1484  Msg::Error("Master element %d is not a line", src->getMeshElement(i)->getNum());
1485  return;
1486  }
1487  srcEdges[MEdge(srcLine->getVertex(0), srcLine->getVertex(1))] = srcLine;
1488  }
1489 
1490  for (std::size_t i = 0; i < tgt->getNumMeshElements(); ++i)
1491  {
1492  MLine *tgtLine = dynamic_cast<MLine *>(tgt->getMeshElement(i));
1493  MVertex *vtcs[2];
1494  if (!tgtLine)
1495  {
1496  Msg::Error("Slave element %d is not a line", tgt->getMeshElement(i)->getNum());
1497  return;
1498  }
1499  for (int iVtx = 0; iVtx < 2; iVtx++)
1500  {
1501  MVertex *vtx = tgtLine->getVertex(iVtx);
1502  auto tIter = v2v.find(vtx);
1503  if (tIter == v2v.end())
1504  {
1505  Msg::Error("Cannot find periodic counterpart of node %d"
1506  " of curve %d on curve %d",
1507  vtx->getNum(), tgt->tag(), src->tag());
1508  return;
1509  }
1510  else
1511  vtcs[iVtx] = tIter->second;
1512  }
1513 
1514  auto srcIter = srcEdges.find(MEdge(vtcs[0], vtcs[1]));
1515  if (srcIter == srcEdges.end())
1516  {
1517  Msg::Error("Can't find periodic counterpart of mesh edge %d-%d "
1518  "on curve %d, connected to mesh edge %d-%d on curve %d",
1519  tgtLine->getVertex(0)->getNum(), tgtLine->getVertex(1)->getNum(), tgt->tag(),
1520  vtcs[0]->getNum(), vtcs[1]->getNum(), src->tag());
1521  return;
1522  }
1523  else
1524  {
1525  MLine *srcLine = srcIter->second;
1526  for (std::size_t i = 2; i < tgtLine->getNumVertices(); i++)
1527  p2p[tgtLine->getVertex(i)] = srcLine->getVertex(i);
1528  }
1529  }
1530  }
1531  }
1532 
1533  if (CTX::instance()->mesh.hoPeriodic)
1534  {
1535  std::vector<GEntity *> modelEdges(m->firstEdge(), m->lastEdge());
1536  relocateSlaveVertices(modelEdges, CTX::instance()->mesh.hoPeriodic > 1);
1537  }
1538 
1539  for (auto it = m->firstFace(); it != m->lastFace(); ++it)
1540  {
1541  GFace *tgt = *it;
1542 
1543  // non complete periodic info (e.g. through extrusion)
1544  if (tgt->vertexCounterparts.empty())
1545  continue;
1546 
1547  GFace *src = dynamic_cast<GFace *>(tgt->getMeshMaster());
1548  if (src != nullptr && src != tgt)
1549  {
1550  Msg::Info("Reconstructing periodicity for surface connection %d - %d", tgt->tag(), src->tag());
1551 
1552  std::map<MVertex *, MVertex *> &v2v = tgt->correspondingVertices;
1553  std::map<MVertex *, MVertex *> &p2p = tgt->correspondingHighOrderVertices;
1554  p2p.clear();
1555 
1556  if (tgt->getNumMeshElements() && v2v.empty())
1557  {
1558  Msg::Info("No periodic vertices in surface %d (maybe due to a "
1559  "structured mesh constraint on the target surface)",
1560  tgt->tag());
1561  continue;
1562  }
1563 
1564  std::map<MFace, MElement *, MFaceLessThan> srcFaces;
1565 
1566  for (std::size_t i = 0; i < src->getNumMeshElements(); ++i)
1567  {
1568  MElement *srcElmt = src->getMeshElement(i);
1569  int nbVtcs = 0;
1570  if (dynamic_cast<MTriangle *>(srcElmt))
1571  nbVtcs = 3;
1572  if (dynamic_cast<MQuadrangle *>(srcElmt))
1573  nbVtcs = 4;
1574  std::vector<MVertex *> vtcs;
1575  vtcs.reserve(nbVtcs);
1576  for (int iVtx = 0; iVtx < nbVtcs; iVtx++)
1577  {
1578  vtcs.push_back(srcElmt->getVertex(iVtx));
1579  }
1580  srcFaces[MFace(vtcs)] = srcElmt;
1581  }
1582 
1583  for (std::size_t i = 0; i < tgt->getNumMeshElements(); ++i)
1584  {
1585  MElement *tgtElmt = tgt->getMeshElement(i);
1586  int nbVtcs = 0;
1587  if (dynamic_cast<MTriangle *>(tgtElmt))
1588  nbVtcs = 3;
1589  if (dynamic_cast<MQuadrangle *>(tgtElmt))
1590  nbVtcs = 4;
1591  std::vector<MVertex *> vtcs;
1592  for (int iVtx = 0; iVtx < nbVtcs; iVtx++)
1593  {
1594  MVertex *vtx = tgtElmt->getVertex(iVtx);
1595 
1596  auto tIter = v2v.find(vtx);
1597  if (tIter == v2v.end())
1598  {
1599  Msg::Error("Cannot find periodic counterpart of node %d "
1600  "of surface %d on surface %d",
1601  vtx->getNum(), tgt->tag(), src->tag());
1602  return;
1603  }
1604  else
1605  vtcs.push_back(tIter->second);
1606  }
1607 
1608  MFace tgtFace(vtcs);
1609  auto srcIter = srcFaces.find(tgtFace);
1610  if (srcIter == srcFaces.end())
1611  {
1612  std::ostringstream faceDef;
1613  for (int iVtx = 0; iVtx < nbVtcs; iVtx++)
1614  faceDef << vtcs[iVtx]->getNum() << " ";
1615  Msg::Error("Cannot find periodic counterpart of mesh face %s in "
1616  "surface %d on surface %d",
1617  faceDef.str().c_str(), tgt->tag(), src->tag());
1618  return;
1619  }
1620  else
1621  {
1622  MElement *srcElmt = srcIter->second;
1623  // Warning: this check is made in case the source and target surface
1624  // meshes are oriented differently (e.g. to be consistent with the
1625  // underlying orientation of the geometrical surfaces)
1626  bool revert = dot(tgtFace.normal(), srcIter->first.normal()) < 0;
1627  if (revert)
1628  srcElmt->reverse();
1629  for (std::size_t j = nbVtcs; j < srcElmt->getNumVertices(); j++)
1630  {
1631  p2p[tgtElmt->getVertex(j)] = srcElmt->getVertex(j);
1632  }
1633  if (revert)
1634  srcElmt->reverse();
1635  }
1636  }
1637  }
1638  }
1639 
1640  if (CTX::instance()->mesh.hoPeriodic)
1641  {
1642  std::vector<GEntity *> modelFaces(m->firstFace(), m->lastFace());
1643  relocateSlaveVertices(modelFaces, CTX::instance()->mesh.hoPeriodic > 1);
1644  }
1645 }
1646 
1647 //#include <google/profiler.h>
1648 
1649 void GenerateMesh(GModel *m, int ask)
1650 {
1651  // ProfilerStart("gmsh.prof");
1652  if (CTX::instance()->lock)
1653  {
1654  Msg::Info("I'm busy! Ask me that later...");
1655  return;
1656  }
1657  CTX::instance()->lock = 1;
1658 
1660 
1663 
1664  // Initialize pseudo random mesh generator with the same seed
1665  srand(CTX::instance()->mesh.randomSeed);
1666 
1667  // Change any high order elements back into first order ones (but skip
1668  // discrete entities)
1669  SetOrder1(m, false, true);
1670  FixPeriodicMesh(m);
1671 
1672  // Some meshing algorithms require a global background mesh
1673  // and a guiding field (e.g. cross field + size map)
1674  QuadqsContextUpdater *qqs = nullptr;
1675  if (CTX::instance()->mesh.algo2d == ALGO_2D_PACK_PRLGRMS ||
1677  {
1678  int old = m->getMeshStatus(false);
1679  bool doIt = (ask >= 1 && ask <= 3);
1680  bool exists = backgroundMeshAndGuidingFieldExists(m);
1681  bool overwriteGModelMesh = false; // use current mesh if available
1682  bool overwriteField = false;
1683  if (old == 1 && ask == 1 && exists)
1684  doIt = true;
1685  if (old == 1 && ask == 2 && exists)
1686  doIt = false;
1687  if (old == 2 && exists && (ask == 1 || ask == 2))
1688  {
1689  // User has a mesh and wants a new one (all options may have changed)
1690  doIt = true;
1691  overwriteField = true;
1692  overwriteGModelMesh = true;
1693  }
1694  if (old == 2 && ask == 1 && exists)
1695  doIt = true;
1696  if (old == 2 && ask == 2 && exists)
1697  doIt = true;
1698  if (doIt)
1699  {
1700  bool deleteGModelMeshAfter = true; // mesh saved in background, no longer needed
1701  BuildBackgroundMeshAndGuidingField(m, overwriteGModelMesh, deleteGModelMeshAfter, overwriteField);
1702  }
1703 
1704  if (CTX::instance()->mesh.algo2d == ALGO_2D_QUAD_QUASI_STRUCT && old == 2 && exists && (ask == 1 || ask == 2))
1705  {
1706  // transferSeamGEdgesVerticesToGFace() called by quadqs remove the 1D
1707  // meshes of the seam GEdge, so 2D initial meshing does not work without
1708  // first remeshing the seam GEdge. We delete the whole mesh by security
1709  m->deleteMesh();
1710  }
1711 
1712  if (CTX::instance()->mesh.algo2d == ALGO_2D_QUAD_QUASI_STRUCT)
1713  {
1714  // note: the creation of QuadqsContextUpdater modifies many meshing
1715  // parameters; current parameter values are saved and will be restored at
1716  // the destruction of qqs
1717  qqs = new QuadqsContextUpdater();
1718  }
1719 
1720  if (CTX::instance()->mesh.algo2d == ALGO_2D_QUAD_QUASI_STRUCT)
1721  {
1722  std::set<GFace *> faces;
1723  for (GFace *gf : m->getFaces())
1724  if (gf->edges().size() == 4)
1725  {
1726  faces.insert(gf);
1727  }
1728  double maxDiffRel = 0.34; // do not deviate more than 34% from size map
1729  MeshSetTransfiniteFacesAutomatic(faces, 2.35, true, maxDiffRel);
1730  }
1731  }
1732 
1733  // dimension of previous/existing mesh
1734  int old = m->getMeshStatus(false);
1735 
1736  // 1D mesh
1737  if (ask == 1 || (ask > 1 && old < 1))
1738  {
1739  std::for_each(m->firstRegion(), m->lastRegion(), deMeshGRegion());
1740  std::for_each(m->firstFace(), m->lastFace(), deMeshGFace());
1741  Mesh0D(m);
1742  Mesh1D(m);
1743  }
1744 
1745  // 2D mesh
1746  if (ask == 2 || (ask > 2 && old < 2))
1747  {
1748  std::for_each(m->firstRegion(), m->lastRegion(), deMeshGRegion());
1749  Mesh2D(m);
1750  // if two passes --> juste fait le ...
1751  // createSizeFieldFromExistingMesh (m, false);
1752  // Mesh2D(m);
1753  }
1754 
1755  // 3D mesh
1756  if (ask == 3)
1757  {
1758  Mesh3D(m);
1759  }
1760 
1761  // Orient the line and surface meshes so that they match the orientation of
1762  // the geometrical entities and/or the user orientation constraints
1763  if (m->getMeshStatus() >= 1)
1764  std::for_each(m->firstEdge(), m->lastEdge(), orientMeshGEdge());
1765  if (m->getMeshStatus() >= 2)
1766  std::for_each(m->firstFace(), m->lastFace(), orientMeshGFace());
1767 
1768  // Optimize quality of 3D tet mesh
1769  if (m->getMeshStatus() == 3 && CTX::instance()->mesh.algo3d != ALGO_3D_INITIAL_ONLY &&
1771  {
1772  for (int i = 0; i < std::max(CTX::instance()->mesh.optimize, CTX::instance()->mesh.optimizeNetgen); i++)
1773  {
1774  if (CTX::instance()->mesh.optimize > i)
1775  OptimizeMesh(m);
1776  if (CTX::instance()->mesh.optimizeNetgen > i)
1777  OptimizeMesh(m, "Netgen");
1778  }
1779  }
1780 
1781  // Subdivide into quads or hexas
1782  if (m->getMeshStatus() == 2 && CTX::instance()->mesh.algoSubdivide == 1)
1784  else if (m->getMeshStatus() == 3 && CTX::instance()->mesh.algoSubdivide == 2)
1785  RefineMesh(m, CTX::instance()->mesh.secondOrderLinear, false, true);
1786  else if (m->getMeshStatus() >= 2 && CTX::instance()->mesh.algoSubdivide == 3)
1788 
1789  if (m->getMeshStatus() && CTX::instance()->mesh.order > 1)
1790  {
1791  // Create high order elements
1794 
1795  // Optimize high order elements
1796  if (CTX::instance()->mesh.hoOptimize == 2 || CTX::instance()->mesh.hoOptimize == 3)
1797  OptimizeMesh(m, "HighOrderElastic");
1798 
1799  if (CTX::instance()->mesh.hoOptimize == 1 || CTX::instance()->mesh.hoOptimize == 2)
1800  OptimizeMesh(m, "HighOrder");
1801 
1802  if (CTX::instance()->mesh.hoOptimize == 4)
1803  OptimizeMesh(m, "HighOrderFastCurving");
1804  }
1805 
1806  // make sure periodic meshes are actually periodic and store periodic node
1807  // correspondences
1808  FixPeriodicMesh(m);
1809 
1810  Msg::Info("%d nodes %d elements", m->getNumMeshVertices(), m->getNumMeshElements());
1811 
1812  Msg::PrintErrorCounter("Mesh generation error summary");
1813 
1814  if (qqs != nullptr)
1815  delete qqs;
1816 
1817  CTX::instance()->lock = 0;
1818  // ProfilerStop();
1819 }
MElement::getNum
virtual std::size_t getNum() const
Definition: MElement.h:68
MPrism::getNumFaces
virtual int getNumFaces()
Definition: MPrism.h:91
Mesh2D
static void Mesh2D(GModel *m)
Definition: Generator.cpp:521
SetOrderN
void SetOrderN(GModel *m, int order, bool linear, bool incomplete, bool onlyVisible)
Definition: HighOrder.cpp:1396
MTriangle.h
GModel::clearLastMeshEntityError
void clearLastMeshEntityError()
Definition: GModel.h:584
buildUniqueFaces
void buildUniqueFaces(GRegion *gr, std::set< MFace, MFaceLessThan > &bnd)
Definition: Generator.cpp:708
TimeOfDay
double TimeOfDay()
Definition: OS.cpp:399
PViewData::getNumLines
virtual int getNumLines(int step=-1)
Definition: PViewData.h:115
meshGFaceBipartiteLabelling.h
replaceBadQuadDominantMeshes
int replaceBadQuadDominantMeshes(GModel *gm)
The initial unstructured quad-tri mesh may contain very bad configurations (e.g. valence 50+) due to ...
Definition: meshQuadQuasiStructured.cpp:3290
GEntity::affineTransform
std::vector< double > affineTransform
Definition: GEntity.h:403
GModel::firstEdge
eiter firstEdge()
Definition: GModel.h:356
Field.h
PViewData::getNumPyramids
virtual int getNumPyramids(int step=-1)
Definition: PViewData.h:122
contextMeshOptions::optimizeNetgen
int optimizeNetgen
Definition: Context.h:19
RefineMeshWithBackgroundMeshProjection
int RefineMeshWithBackgroundMeshProjection(GModel *gm)
Midpoint subdivision of the surface mesh with projections on the CAD surfaces, using the background m...
Definition: meshQuadQuasiStructured.cpp:3284
MEdge
Definition: MEdge.h:14
GEdge::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GEdge.cpp:173
dot
double dot(const SVector3 &a, const SMetric3 &m, const SVector3 &b)
Definition: STensor3.h:71
AdaptMesh
void AdaptMesh(GModel *m)
Definition: Generator.cpp:1303
GEntity::correspondingHighOrderVertices
std::map< MVertex *, MVertex * > correspondingHighOrderVertices
Definition: GEntity.h:409
Msg::GetVerbosity
static int GetVerbosity()
Definition: GmshMessage.cpp:254
GVertex::z
virtual double z() const =0
GPoint::y
double y() const
Definition: GPoint.h:22
distance
double distance(MVertex *v1, MVertex *v2)
Definition: MVertex.h:245
GModel::getNumMeshVertices
std::size_t getNumMeshVertices(int dim=-1) const
Definition: GModel.cpp:1529
GenerateMesh
void GenerateMesh(GModel *m, int ask)
Definition: Generator.cpp:1649
PViewData::getNumStrings3D
virtual int getNumStrings3D()
Definition: PViewData.h:187
MTetrahedron
Definition: MTetrahedron.h:34
MLine::getVertex
virtual MVertex * getVertex(int num)
Definition: MLine.h:45
GModel::getFaces
std::set< GFace *, GEntityPtrLessThan > getFaces() const
Definition: GModel.h:376
meshGRegionLocalMeshMod.h
GFace
Definition: GFace.h:33
contextMeshOptions::optimize
int optimize
Definition: Context.h:19
PViewData::getNumStrings2D
virtual int getNumStrings2D()
Definition: PViewData.h:186
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
SPoint2
Definition: SPoint2.h:12
contextMeshOptions::maxNumThreads1D
int maxNumThreads1D
Definition: Context.h:46
quadsToTriangles
void quadsToTriangles(GFace *gf, double minqual)
Definition: meshGFaceOptimize.cpp:1374
OS.h
GFace::getRegion
GRegion * getRegion(int const num) const
Definition: GFace.h:81
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
MVertex
Definition: MVertex.h:24
CTX::numThreads
int numThreads
Definition: Context.h:169
contextMeshOptions::hoIterMax
int hoIterMax
Definition: Context.h:38
GModel::getName
std::string getName() const
Definition: GModel.h:329
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
Msg::StatusBar
static void StatusBar(bool log, const char *fmt,...)
Definition: GmshMessage.cpp:686
MVertex::z
double z() const
Definition: MVertex.h:62
BackgroundMesh.h
GRegion::recombine3D
int recombine3D
Definition: GRegion.h:144
optimizeMeshGRegion
Definition: meshGRegion.h:36
MakeMeshConformal
bool MakeMeshConformal(GModel *gm, int howto)
Definition: Generator.cpp:725
FindConnectedRegions
static void FindConnectedRegions(const std::vector< GRegion * > &del, std::vector< std::vector< GRegion * >> &connected)
Definition: Generator.cpp:649
transform
static SPoint3 transform(MVertex *vsource, const std::vector< double > &tfo)
Definition: Generator.cpp:1347
SPoint3
Definition: SPoint3.h:14
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
findInFaceSearchStructure
GFace * findInFaceSearchStructure(MVertex *p1, MVertex *p2, MVertex *p3, const fs_cont &search)
Definition: meshGRegion.cpp:333
contextMeshOptions::recombineOptimizeTopology
int recombineOptimizeTopology
Definition: Context.h:30
MVertex::getNum
std::size_t getNum() const
Definition: MVertex.h:86
ALGO_2D_PACK_PRLGRMS
#define ALGO_2D_PACK_PRLGRMS
Definition: GmshDefines.h:245
MFace::normal
SVector3 normal() const
Definition: MFace.cpp:204
GModel::getRegions
std::set< GRegion *, GEntityPtrLessThan > getRegions() const
Definition: GModel.h:372
GFace::point
virtual GPoint point(double par1, double par2) const =0
GModel::empty
bool empty() const
Definition: GModel.cpp:311
contextMeshOptions::order
int order
Definition: Context.h:35
PViewData::getNumPoints
virtual int getNumPoints(int step=-1)
Definition: PViewData.h:114
meshGFaceOptimize.h
contextMeshOptions::recombineNodeRepositioning
int recombineNodeRepositioning
Definition: Context.h:31
PView.h
GModel::clearLastMeshVertexError
void clearLastMeshVertexError()
Definition: GModel.h:590
GRegion::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GRegion.cpp:60
meshGEdge.h
contextMeshOptions::meshOnlyVisible
int meshOnlyVisible
Definition: Context.h:36
EmbeddedCompatibilityTest::operator()
void operator()(GRegion *gr)
Definition: Generator.cpp:68
MPyramid
Definition: MPyramid.h:32
MVertex::onWhat
GEntity * onWhat() const
Definition: MVertex.h:82
MPoint.h
GModel::firstVertex
viter firstVertex()
Definition: GModel.h:357
MPrism
Definition: MPrism.h:34
MHexahedron::getFace
virtual MFace getFace(int num) const
Definition: MHexahedron.h:92
GModel::getMeshDim
int getMeshDim() const
Definition: GModel.cpp:998
GmshMessage.h
MLine.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
MEdgeVertex::getParameter
virtual bool getParameter(int i, double &par) const
Definition: MVertex.h:153
QuadqsContextUpdater
The QuadQuasiStructured meshing mode requires control over various meshing parameters which are store...
Definition: meshQuadQuasiStructured.h:27
GModel::getNumMeshElements
std::size_t getNumMeshElements(int dim=-1) const
Definition: GModel.cpp:1540
w1
const double w1
Definition: GaussQuadratureHex.cpp:18
PViewData.h
GEntity
Definition: GEntity.h:31
GPoint
Definition: GPoint.h:13
MLine::getNumVertices
virtual std::size_t getNumVertices() const
Definition: MLine.h:44
GFace::closestPoint
virtual GPoint closestPoint(const SPoint3 &queryPoint, const double initialGuess[2]) const
Definition: GFace.cpp:1323
GEntity::getMeshMaster
GEntity * getMeshMaster() const
Definition: GEntity.h:291
MElement::getNumVertices
virtual std::size_t getNumVertices() const =0
relocateSlaveVertices
static void relocateSlaveVertices(GFace *slave, std::map< MVertex *, MVertex * > &vertS2M, bool useClosestPoint)
Definition: Generator.cpp:1359
transferSeamGEdgesVerticesToGFace
int transferSeamGEdgesVerticesToGFace(GModel *gm)
Mesh vertices on seam curves (and isolated corners) are reparametrized on the associated GFace and tr...
Definition: meshQuadQuasiStructured.cpp:3306
Fopen
FILE * Fopen(const char *f, const char *mode)
Definition: OS.cpp:273
GEntity::Plane
@ Plane
Definition: GEntity.h:105
FixPeriodicMesh
void FixPeriodicMesh(GModel *m)
Definition: Generator.cpp:1455
MLine
Definition: MLine.h:21
GVertex::points
std::vector< MPoint * > points
Definition: GVertex.h:120
MFaceVertex::getParameter
virtual bool getParameter(int i, double &par) const
Definition: MVertex.h:184
GPoint::z
double z() const
Definition: GPoint.h:23
deMeshGRegion
Definition: meshGRegion.h:48
FieldManager::initialize
void initialize()
Definition: Field.cpp:3211
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
ALGO_2D_FRONTAL_QUAD
#define ALGO_2D_FRONTAL_QUAD
Definition: GmshDefines.h:244
MElement::getVertex
virtual const MVertex * getVertex(int num) const =0
GRegion::faces
virtual std::vector< GFace * > faces() const
Definition: GRegion.h:64
SPoint3::x
double x(void) const
Definition: SPoint3.h:125
GRegion::hexahedra
std::vector< MHexahedron * > hexahedra
Definition: GRegion.h:164
MElement::getEdge
virtual MEdge getEdge(int num) const =0
GModel::getPhysicalGroups
void getPhysicalGroups(std::map< int, std::vector< GEntity * > > groups[4]) const
Definition: GModel.cpp:837
GModel::lastFace
fiter lastFace()
Definition: GModel.h:359
MFace
Definition: MFace.h:20
SubdivideExtrudedMesh
int SubdivideExtrudedMesh(GModel *m)
Definition: meshGRegionExtruded.cpp:481
GPoint::u
double u() const
Definition: GPoint.h:27
contextMeshOptions::algoSubdivide
int algoSubdivide
Definition: Context.h:29
GEntity::mesh_vertices
std::vector< MVertex * > mesh_vertices
Definition: GEntity.h:56
contextMeshOptions::recombineMinimumQuality
double recombineMinimumQuality
Definition: Context.h:32
Mesh3D
static void Mesh3D(GModel *m)
Definition: Generator.cpp:924
PViewData::getNumHexahedra
virtual int getNumHexahedra(int step=-1)
Definition: PViewData.h:120
backgroundMeshAndGuidingFieldExists
bool backgroundMeshAndGuidingFieldExists(GModel *gm)
To check if a compatible background mesh and guiding field already exists.
Definition: meshQuadQuasiStructured.cpp:3259
MHexahedron.h
MEdgeVertex
Definition: MVertex.h:137
GetStatistics
void GetStatistics(double stat[50], double quality[3][100], bool visibleOnly)
Definition: Generator.cpp:190
MEdgeVertex::setParameter
virtual bool setParameter(int i, double par)
Definition: MVertex.h:159
GModel::lastVertex
viter lastVertex()
Definition: GModel.h:361
HighOrder.h
contextMeshOptions::recombine3DAll
int recombine3DAll
Definition: Context.h:33
MElement::getNumFaces
virtual int getNumFaces()=0
GVertex
Definition: GVertex.h:23
meshRefine.h
Msg::PrintErrorCounter
static void PrintErrorCounter(const char *title)
Definition: GmshMessage.cpp:859
contextMeshOptions::algo3d
int algo3d
Definition: Context.h:29
MElement::getVolume
virtual double getVolume()
Definition: MElement.cpp:567
GModel::getDim
int getDim() const
Definition: GModel.cpp:989
contextMeshOptions::hoMaxInnerAngle
double hoMaxInnerAngle
Definition: Context.h:43
Numeric.h
contextMeshOptions::maxNumThreads2D
int maxNumThreads2D
Definition: Context.h:46
GModel::getNumVertices
std::size_t getNumVertices() const
Definition: GModel.h:347
MElement::getFace
virtual MFace getFace(int num) const =0
GModel
Definition: GModel.h:44
Msg::StopProgressMeter
static void StopProgressMeter()
Definition: GmshMessage.cpp:318
Cpu
double Cpu()
Definition: OS.cpp:366
Msg::GetMaxThreads
static int GetMaxThreads()
Definition: GmshMessage.cpp:1637
PViewData::getNumQuadrangles
virtual int getNumQuadrangles(int step=-1)
Definition: PViewData.h:117
GEntity::DONE
@ DONE
Definition: GEntity.h:130
ExtrudeParams.h
MVertex::setXYZ
void setXYZ(double x, double y, double z)
Definition: MVertex.h:68
GFace::parFromPoint
virtual SPoint2 parFromPoint(const SPoint3 &, bool onSurface=true, bool convTestXYZ=false) const
Definition: GFace.cpp:1254
MElement::reverse
virtual void reverse()
Definition: MElement.h:308
MPyramid.h
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
MFaceVertex::setParameter
virtual bool setParameter(int i, double par)
Definition: MVertex.h:196
SPoint3::y
double y(void) const
Definition: SPoint3.h:127
contextMeshOptions::hoDistCAD
int hoDistCAD
Definition: Context.h:39
contextMeshOptions::recombine3DConformity
int recombine3DConformity
Definition: Context.h:33
RelocateVertices
void RelocateVertices(GFace *gf, int niter, double tol)
Definition: meshRelocateVertex.cpp:410
optimizeTopologyWithCavityRemeshing
int optimizeTopologyWithCavityRemeshing(GModel *gm)
Look for patches of quads with >=3 irregular vertices which can be remeshed with more regular quad me...
Definition: meshQuadQuasiStructured.cpp:3271
MHexahedron
Definition: MHexahedron.h:28
contextMeshOptions::hoNLayers
int hoNLayers
Definition: Context.h:38
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
GModel::getNumRegions
std::size_t getNumRegions() const
Definition: GModel.h:344
deMeshGFace
Definition: meshGFace.h:30
GModel::getFields
FieldManager * getFields()
Definition: GModel.h:325
MElement
Definition: MElement.h:30
Mesh2DWithBoundaryLayers
int Mesh2DWithBoundaryLayers(GModel *m)
Definition: BoundaryLayers.cpp:304
ALGO_3D_HXT
#define ALGO_3D_HXT
Definition: GmshDefines.h:255
GEntity::tag
int tag() const
Definition: GEntity.h:280
MFaceVertex
Definition: MVertex.h:168
GModel::getNumFaces
std::size_t getNumFaces() const
Definition: GModel.h:345
GModel::deleteMesh
void deleteMesh()
Definition: GModel.cpp:236
BuildBackgroundMeshAndGuidingField
int BuildBackgroundMeshAndGuidingField(GModel *gm, bool overwriteGModelMesh, bool deleteGModelMeshAfter, bool overwriteField, int N)
Definition: meshQuadQuasiStructured.cpp:3251
SPoint2::setPosition
void setPosition(double xx, double yy)
Definition: SPoint2.h:68
MeshDelaunayVolume
void MeshDelaunayVolume(std::vector< GRegion * > &regions)
Definition: meshGRegion.cpp:95
GRegion
Definition: GRegion.h:28
meshGRegionExtruded
Definition: meshGRegion.h:30
contextMeshOptions::hoThresholdMax
double hoThresholdMax
Definition: Context.h:40
GModel::getNumEdges
std::size_t getNumEdges() const
Definition: GModel.h:346
GRegion::prisms
std::vector< MPrism * > prisms
Definition: GRegion.h:165
PViewData
Definition: PViewData.h:29
GFace::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GFace.cpp:234
MTriangle
Definition: MTriangle.h:26
GEntity::DiscreteSurface
@ DiscreteSurface
Definition: GEntity.h:117
contextMeshOptions::secondOrderIncomplete
int secondOrderIncomplete
Definition: Context.h:35
GVertex::x
virtual double x() const =0
GRegion::pyramids
std::vector< MPyramid * > pyramids
Definition: GRegion.h:166
MHexahedron::getNumFaces
virtual int getNumFaces()
Definition: MHexahedron.h:91
PViewData::getNumTetrahedra
virtual int getNumTetrahedra(int step=-1)
Definition: PViewData.h:119
Msg::GetLastError
static std::string GetLastError()
Definition: GmshMessage.cpp:362
optimizeTopologyWithDiskQuadrangulationRemeshing
int optimizeTopologyWithDiskQuadrangulationRemeshing(GModel *gm)
Look for non-ideal vertex valences in quad mesh and find a better local remeshing by looking into all...
Definition: meshQuadQuasiStructured.cpp:3265
GModel::firstRegion
riter firstRegion()
Definition: GModel.h:354
meshGFaceQuadrangulateBipartiteLabelling
void meshGFaceQuadrangulateBipartiteLabelling(int faceTag)
Definition: meshGFaceBipartiteLabelling.cpp:358
GVertex::y
virtual double y() const =0
recombineIntoQuads
void recombineIntoQuads(GFace *gf, bool blossom, int topologicalOptiPasses, bool nodeRepositioning, double minqual)
Definition: meshGFaceOptimize.cpp:1311
MeshSetTransfiniteFacesAutomatic
bool MeshSetTransfiniteFacesAutomatic(std::set< GFace * > &candidate_faces, double cornerAngle=2.35, bool setRecombine=true, double maxDiffRel=1., bool ignoreEmbedded=false)
Automatically set transfinite constraints on curves and faces in the candidate_faces if possible....
Definition: meshGFaceTransfinite.cpp:817
ALGO_3D_RTREE
#define ALGO_3D_RTREE
Definition: GmshDefines.h:254
GModel::lastRegion
riter lastRegion()
Definition: GModel.h:358
GEdge::status
GEntity::MeshGenerationStatus status
Definition: GEdge.h:263
Msg::ResetErrorCounter
static void ResetErrorCounter()
Definition: GmshMessage.cpp:850
meshGFace.h
GEdge::meshStatistics
struct GEdge::@17 meshStatistics
GEdge::closestPoint
virtual GPoint closestPoint(const SPoint3 &queryPoint, double &param) const
Definition: GEdge.cpp:552
adaptMeshGRegion
Definition: meshGRegion.h:86
Context.h
EmbeddedCompatibilityTest
Definition: Generator.cpp:66
GRegion::embeddedEdges
std::vector< GEdge * > & embeddedEdges()
Definition: GRegion.h:80
meshGRegion
Definition: meshGRegion.h:23
MTetrahedron.h
backgroundMesh::unset
static void unset()
Definition: BackgroundMesh.cpp:60
GetQualityMeasure
static void GetQualityMeasure(std::vector< T * > &ele, double &gamma, double &gammaMin, double &gammaMax, double &minSICN, double &minSICNMin, double &minSICNMax, double &minSIGE, double &minSIGEMin, double &minSIGEMax, double quality[3][100])
Definition: Generator.cpp:160
contextMeshOptions::hoPassMax
int hoPassMax
Definition: Context.h:38
contextMeshOptions::hoFixBndNodes
int hoFixBndNodes
Definition: Context.h:39
Msg::GetAnswer
static int GetAnswer(const char *question, int defaultval, const char *zero, const char *one, const char *two=nullptr)
Definition: GmshMessage.cpp:952
contextMeshOptions::secondOrderLinear
int secondOrderLinear
Definition: Context.h:35
GRegion::embeddedFaces
std::vector< GFace * > & embeddedFaces()
Definition: GRegion.h:81
laplaceSmoothing
void laplaceSmoothing(GFace *gf, int niter, bool infinity_norm)
Definition: meshGFaceOptimize.cpp:978
MQuadrangle.h
contextMeshOptions::lcFactor
double lcFactor
Definition: Context.h:21
meshGFaceBDS.h
contextMeshOptions::algo2d
int algo2d
Definition: Context.h:29
GRegion::meshAttributes
struct GRegion::@20 meshAttributes
PViewData::getNumPrisms
virtual int getNumPrisms(int step=-1)
Definition: PViewData.h:121
GEdge::point
virtual GPoint point(double p) const =0
MPoint
Definition: MPoint.h:16
Msg::StartProgressMeter
static void StartProgressMeter(int ntotal)
Definition: GmshMessage.cpp:312
Mesh0D
static void Mesh0D(GModel *m)
Definition: Generator.cpp:341
orientMeshGFace
Definition: meshGFace.h:42
GEdge
Definition: GEdge.h:26
contextMeshOptions::hoPrimSurfMesh
int hoPrimSurfMesh
Definition: Context.h:38
MPrism.h
sizeField.h
orientMeshGEdge
Definition: meshGEdge.h:25
MElement::barycenter
virtual SPoint3 barycenter(bool primary=false) const
Definition: MElement.cpp:520
optimizeMeshGRegionNetgen
Definition: meshGRegion.h:42
FieldManager::getNumBoundaryLayerFields
int getNumBoundaryLayerFields()
Definition: Field.h:179
backgroundMesh::current
static backgroundMesh * current()
Definition: BackgroundMesh.cpp:68
buildFaceSearchStructure
bool buildFaceSearchStructure(GModel *model, fs_cont &search, bool onlyTriangles)
Definition: meshGRegion.cpp:286
GEntity::vertexCounterparts
std::map< GVertex *, GVertex * > vertexCounterparts
Definition: GEntity.h:62
SPoint3::z
double z(void) const
Definition: SPoint3.h:129
ALGO_3D_INITIAL_ONLY
#define ALGO_3D_INITIAL_ONLY
Definition: GmshDefines.h:251
meshGRegion.h
RecombineMesh
void RecombineMesh(GModel *m)
Definition: Generator.cpp:1318
Options.h
GPoint::v
double v() const
Definition: GPoint.h:28
fs_cont
std::map< MFace, GFace *, MFaceLessThan > fs_cont
Definition: meshGRegion.h:60
GModel::lastEdge
eiter lastEdge()
Definition: GModel.h:360
RefineMesh
void RefineMesh(GModel *m, bool linear, bool splitIntoQuads, bool splitIntoHexas)
Definition: meshRefine.cpp:463
GModel.h
contextMeshOptions::hoCurveOuterBL
int hoCurveOuterBL
Definition: Context.h:42
Mesh1D
static void Mesh1D(GModel *m)
Definition: Generator.cpp:368
GEdge::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GEdge.h:201
MVertex::y
double y() const
Definition: MVertex.h:61
contextMeshOptions::algoRecombine
int algoRecombine
Definition: Context.h:30
meshQuadQuasiStructured.h
contextMeshOptions::hoThresholdMin
double hoThresholdMin
Definition: Context.h:40
GFace::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GFace.cpp:181
PView::list
static std::vector< PView * > list
Definition: PView.h:112
PrintMesh2dStatistics
static void PrintMesh2dStatistics(GModel *m)
Definition: Generator.cpp:458
GEntity::FAILED
@ FAILED
Definition: GEntity.h:130
Msg::ProgressMeter
static void ProgressMeter(int n, bool log, const char *fmt,...)
Definition: GmshMessage.cpp:783
BoundaryLayers.h
OptimizeMesh
void OptimizeMesh(GModel *m, const std::string &how, bool force, int niter)
Definition: Generator.cpp:1101
Generator.h
GModel::getMeshStatus
int getMeshStatus(bool countDiscrete=true)
Definition: GModel.cpp:1474
GPoint::x
double x() const
Definition: GPoint.h:21
GEntity::getVisibility
virtual char getVisibility()
Definition: GEntity.cpp:35
GEntity::correspondingVertices
std::map< MVertex *, MVertex * > correspondingVertices
Definition: GEntity.h:406
GEntity::PENDING
@ PENDING
Definition: GEntity.h:130
GModel::setAllVolumesPositive
bool setAllVolumesPositive()
Definition: GModel.cpp:1085
CTX::lock
int lock
Definition: Context.h:252
MQuadrangle
Definition: MQuadrangle.h:26
GEdge::parFromPoint
virtual double parFromPoint(const SPoint3 &P) const
Definition: GEdge.cpp:595
MPrism::getFace
virtual MFace getFace(int num) const
Definition: MPrism.h:94
contextMeshOptions::hoMaxRho
double hoMaxRho
Definition: Context.h:43
ALGO_2D_QUAD_QUASI_STRUCT
#define ALGO_2D_QUAD_QUASI_STRUCT
Definition: GmshDefines.h:247
PViewData::getNumTriangles
virtual int getNumTriangles(int step=-1)
Definition: PViewData.h:116
GEdge::mesh
virtual void mesh(bool verbose)
Definition: GEdge.cpp:918
meshRelocateVertex.h
Msg::GetErrorCount
static int GetErrorCount()
Definition: GmshMessage.cpp:347
GRegion::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GRegion.cpp:127
GRegion::tetrahedra
std::vector< MTetrahedron * > tetrahedra
Definition: GRegion.h:163
GModel::current
static GModel * current(int index=-1)
Definition: GModel.cpp:136
CTX::meshTimer
double meshTimer[3]
Definition: Context.h:290
TooManyElements
static bool TooManyElements(GModel *m, int dim)
Definition: Generator.cpp:321
MVertex::x
double x() const
Definition: MVertex.h:60
quadMeshingOfSimpleFacesWithPatterns
int quadMeshingOfSimpleFacesWithPatterns(GModel *gm, double minimumQualityRequired)
Look for simple CAD faces (topological disk, a few corners) which can be remeshed with simple quad pa...
Definition: meshQuadQuasiStructured.cpp:3277
SetOrder1
void SetOrder1(GModel *m, bool onlyVisible, bool skipDiscrete)
Definition: HighOrder.cpp:1233
ALGO_2D_PACK_PRLGRMS_CSTR
#define ALGO_2D_PACK_PRLGRMS_CSTR
Definition: GmshDefines.h:246
faces
static int faces[4][3]
Definition: meshGRegionDelaunayInsertion.cpp:165
BarycentricRefineMesh
void BarycentricRefineMesh(GModel *m)
Definition: meshRefine.cpp:507
contextMeshOptions::hoOptimize
int hoOptimize
Definition: Context.h:38
contextMeshOptions::hoMaxAngle
double hoMaxAngle
Definition: Context.h:43