10 #include "GmshConfig.h"
29 #include "hxt_tetMesh.h"
30 #include "hxt_tetDelaunay.h"
33 static int getNumThreads()
42 static HXTStatus messageCallback(HXTMessage *msg)
48 static HXTStatus nodalSizesCallBack(
double *pts, uint32_t *volume,
49 size_t numPts,
void *userData)
51 std::vector<GRegion *> *allGR = (std::vector<GRegion *> *)userData;
56 HXT_INFO(
"Computing %smesh sizes...", useInterpolatedSize ?
"interpolated " :
"");
58 int nthreads = getNumThreads();
59 bool exceptions =
false;
60 #pragma omp parallel for schedule(dynamic) num_threads(nthreads)
61 for(
size_t i = 0; i < numPts; i++) {
62 if(exceptions)
continue;
63 if(volume[i] < 0 || volume[i] >= allGR->size()) {
64 Msg::Error(
"Invalid volume tag %d in mesh size calculation", volume[i]);
67 GRegion *gr = (*allGR)[volume[i]];
70 pts[4 * i + 1], pts[4 * i + 2]);
71 if(useInterpolatedSize && pts[4 * i + 3] > 0.0)
72 pts[4 * i + 3] = std::min(pts[4 * i + 3], std::min(lcGlob, lc));
74 pts[4 * i + 3] = std::min(lcGlob, lc);
83 HXT_INFO(
"Done computing %smesh sizes", useInterpolatedSize ?
"interpolated " :
"");
88 static HXTStatus getAllSurfaces(std::vector<GRegion *> ®ions, HXTMesh *m,
89 std::vector<GFace *> &allSurfaces)
91 std::set<GFace *, GEntityPtrLessThan> allSurfacesSet;
93 m->brep.numVolumes = regions.size();
94 HXT_CHECK(hxtAlignedMalloc(&m->brep.numSurfacesPerVolume,
95 m->brep.numVolumes *
sizeof(uint32_t)));
97 uint32_t to_alloc = 0;
98 for(std::size_t i = 0; i < regions.size(); i++) {
99 std::vector<GFace *>
const &
f = regions[i]->faces();
100 std::vector<GFace *>
const &f_e = regions[i]->embeddedFaces();
102 m->brep.numSurfacesPerVolume[i] =
f.size() + f_e.size();
103 to_alloc += m->brep.numSurfacesPerVolume[i];
105 allSurfacesSet.insert(
f.begin(),
f.end());
106 allSurfacesSet.insert(f_e.begin(), f_e.end());
110 for (
auto const &gf: allSurfacesSet) {
111 if (gf->quadrangles.size() != 0 || gf->polygons.size() != 0) {
112 size_t num = gf->quadrangles.size() + gf->polygons.size();
113 Msg::Error(
"Surface %d contains %zu elements which are not triangles. "
114 "The HXT 3D meshing algorithm only supports triangles.",
116 return HXT_STATUS_ERROR;
120 allSurfaces.insert(allSurfaces.end(), allSurfacesSet.begin(),
121 allSurfacesSet.end());
123 if(!m)
return HXT_STATUS_OK;
126 hxtAlignedMalloc(&m->brep.surfacesPerVolume, to_alloc *
sizeof(uint32_t)));
128 uint32_t counter = 0;
129 for(std::size_t i = 0; i < regions.size(); i++) {
130 std::vector<GFace *>
const &
f = regions[i]->faces();
131 std::vector<GFace *>
const &f_e = regions[i]->embeddedFaces();
132 for(
size_t j = 0; j <
f.size(); j++)
133 m->brep.surfacesPerVolume[counter++] =
f[j]->tag();
134 for(
size_t j = 0; j < f_e.size(); j++)
135 m->brep.surfacesPerVolume[counter++] = f_e[j]->tag();
138 return HXT_STATUS_OK;
141 static HXTStatus getAllCurves(std::vector<GRegion *> ®ions,
142 std::vector<GFace *> &surfaces, HXTMesh *m,
143 std::vector<GEdge *> &allCurves)
146 m->brep.numSurfaces = surfaces.size();
147 HXT_CHECK(hxtAlignedMalloc(&m->brep.numCurvesPerSurface,
148 m->brep.numSurfaces *
sizeof(uint32_t)));
150 uint32_t to_alloc = 0;
152 std::set<GEdge *, GEntityPtrLessThan> allCurvesSet;
154 for(std::size_t i = 0; i < surfaces.size(); i++) {
155 std::vector<GEdge *>
const &
f = surfaces[i]->edges();
156 std::vector<GEdge *>
const &f_e = surfaces[i]->embeddedEdges();
158 m->brep.numCurvesPerSurface[i] =
f.size() + f_e.size();
159 to_alloc += m->brep.numCurvesPerSurface[i];
161 allCurvesSet.insert(
f.begin(),
f.end());
162 allCurvesSet.insert(f_e.begin(), f_e.end());
164 for(std::size_t i = 0; i < regions.size(); i++) {
165 std::vector<GEdge *>
const &r_e = regions[i]->embeddedEdges();
166 allCurvesSet.insert(r_e.begin(), r_e.end());
168 allCurves.insert(allCurves.end(), allCurvesSet.begin(), allCurvesSet.end());
170 if(!m)
return HXT_STATUS_OK;
173 hxtAlignedMalloc(&m->brep.curvesPerSurface, to_alloc *
sizeof(uint32_t)));
175 uint32_t counter = 0;
176 for(std::size_t i = 0; i < surfaces.size(); i++) {
177 std::vector<GEdge *>
const &
f = surfaces[i]->edges();
178 std::vector<GEdge *>
const &f_e = surfaces[i]->embeddedEdges();
179 for(
size_t j = 0; j <
f.size(); j++)
180 m->brep.curvesPerSurface[counter++] =
f[j]->tag();
181 for(
size_t j = 0; j < f_e.size(); j++)
182 m->brep.curvesPerSurface[counter++] = f_e[j]->tag();
185 return HXT_STATUS_OK;
188 static HXTStatus Hxt2Gmsh(std::vector<GRegion *> ®ions, HXTMesh *m,
189 std::map<MVertex *, uint32_t> &v2c,
190 std::vector<MVertex *> &c2v)
194 HXT_CHECK( hxtAlignedFree(&m->tetrahedra.neigh) );
195 HXT_CHECK( hxtAlignedFree(&m->tetrahedra.flag) );
196 HXT_CHECK( hxtAlignedFree(&m->points.node) );
197 HXT_CHECK( hxtAlignedFree(&m->points.color) );
199 std::map<uint32_t, GEdge *> i2e;
200 std::map<uint32_t, GFace *> i2f;
202 std::vector<GFace *> allSurfaces;
203 std::vector<GEdge *> allCurves;
204 HXT_CHECK(getAllSurfaces(regions,
nullptr, allSurfaces));
205 HXT_CHECK(getAllCurves(regions, allSurfaces,
nullptr, allCurves));
207 for(
size_t j = 0; j < allCurves.size(); j++) {
208 i2e[allCurves[j]->tag()] = allCurves[j];
209 GEdge *ge = allCurves[j];
210 for(
size_t i = 0; i < ge->
lines.size(); i++) {
delete ge->
lines[i]; }
214 for(
size_t j = 0; j < allSurfaces.size(); j++) {
215 i2f[allSurfaces[j]->tag()] = allSurfaces[j];
216 GFace *gf = allSurfaces[j];
222 c2v.resize(m->vertices.num,
nullptr);
224 uint32_t warning = 0;
225 for(
size_t i = 0; i < m->lines.num; i++) {
226 uint32_t
c = m->lines.color[i];
227 auto ge = i2e.find(
c);
228 if(ge == i2e.end()) {
236 uint32_t i0 = m->lines.node[2 * i + 0];
237 uint32_t i1 = m->lines.node[2 * i + 1];
239 double *x = &m->vertices.coord[4 * i0];
241 c2v[i0] =
new MEdgeVertex(x[0], x[1], x[2], ge->second, 0);
245 double *x = &m->vertices.coord[4 * i1];
246 c2v[i1] =
new MEdgeVertex(x[0], x[1], x[2], ge->second, 0);
248 ge->second->
lines.push_back(
new MLine(c2v[i0], c2v[i1]));
250 HXT_CHECK( hxtAlignedFree(&m->lines.node) );
251 HXT_CHECK( hxtAlignedFree(&m->lines.color) );
253 for(
size_t i = 0; i < m->triangles.num; i++) {
254 uint32_t
c = m->triangles.color[i];
255 auto gf = i2f.find(
c);
256 if(gf == i2f.end()) {
264 uint32_t i0 = m->triangles.node[3 * i + 0];
265 uint32_t i1 = m->triangles.node[3 * i + 1];
266 uint32_t i2 = m->triangles.node[3 * i + 2];
269 double *x = &m->vertices.coord[4 * i0];
270 c2v[i0] =
new MFaceVertex(x[0], x[1], x[2], gf->second, 0, 0);
274 double *x = &m->vertices.coord[4 * i1];
275 c2v[i1] =
new MFaceVertex(x[0], x[1], x[2], gf->second, 0, 0);
279 double *x = &m->vertices.coord[4 * i2];
280 c2v[i2] =
new MFaceVertex(x[0], x[1], x[2], gf->second, 0, 0);
284 HXT_CHECK( hxtAlignedFree(&m->triangles.node) );
285 HXT_CHECK( hxtAlignedFree(&m->triangles.color) );
288 int nthreads = getNumThreads();
290 const uint32_t nR = regions.size();
291 const uint32_t nV = m->vertices.num;
293 size_t* ht_all, *ht_tot;
294 HXT_CHECK( hxtCalloc(&ht_all, nR * (nthreads + 1),
sizeof(
size_t)) );
295 uint32_t* hp_all, *hp_tot;
296 HXT_CHECK( hxtCalloc(&hp_all, nR * (nthreads + 1) * 3 + (
size_t) nV * nthreads,
298 uint32_t* vR_all = hp_all + nR * (nthreads + 1);
300 #pragma omp parallel num_threads(nthreads)
304 nthreads = omp_get_num_threads();
305 ht_tot = ht_all + nR * nthreads;
306 hp_tot = hp_all + nR * nthreads;
309 int threadID = omp_get_thread_num();
310 size_t* ht_this = ht_all + nR * threadID;
311 uint32_t* hp_this = hp_all + nR * threadID;
312 uint32_t* vR_this = vR_all + nV * threadID;
315 #pragma omp for schedule(static)
316 for(
size_t i = 0; i < m->tetrahedra.num; i++) {
317 uint32_t
c = m->tetrahedra.color[i];
318 if(
c >= nR)
continue;
321 uint32_t *nodes = &m->tetrahedra.node[4 * i];
322 for(
int j = 0; j < 4; j++) {
323 uint32_t pt = nodes[j];
329 #pragma omp for schedule(static)
330 for(uint32_t pt = 0; pt < nV; pt++) {
331 if(c2v[pt])
continue;
334 for(
int thrd = 0; thrd < nthreads; thrd++) {
335 if(vR_all[thrd * nV + pt]) {
336 color = vR_all[thrd * nV + pt];
343 exit(HXT_ERROR_MSG(HXT_STATUS_ERROR,
"no volume or color for pt %u", pt));
350 for(uint32_t c2 = 0; c2 < 2 * nR; c2++) {
351 uint32_t
c = c2 >> 1;
354 for(
int j = 0; j < nthreads + 1; j++) {
355 size_t tsumt = ht_all[j * nR +
c] + sumt;
356 ht_all[j * nR +
c] = sumt;
359 regions[
c]->tetrahedra.resize(ht_tot[
c],
nullptr);
363 for(
int j = 0; j < nthreads + 1; j++) {
364 uint32_t tsump = hp_all[j * nR +
c] + sump;
365 hp_all[j * nR +
c] = sump;
368 regions[
c]->mesh_vertices.resize(hp_tot[
c],
nullptr);
372 #pragma omp for schedule(static)
373 for(uint32_t pt = 0; pt < nV; pt++) {
374 if(c2v[pt])
continue;
376 uint32_t
c = vR_all[pt];
378 double *x = &m->
vertices.coord[4 * pt];
379 c2v[pt] =
new MVertex(x[0], x[1], x[2], gr);
384 #pragma omp for schedule(static)
385 for(
size_t i = 0; i < m->tetrahedra.num; i++) {
386 uint32_t
c = m->tetrahedra.color[i];
387 if(
c >= nR)
continue;
389 uint32_t *nodes = &m->tetrahedra.node[4 * i];
391 (c2v[nodes[0]], c2v[nodes[1]], c2v[nodes[2]], c2v[nodes[3]]);
395 HXT_CHECK( hxtFree(&ht_all) );
396 HXT_CHECK( hxtFree(&hp_all) );
401 for(
size_t i = 0; i < m->tetrahedra.num; i++) {
402 uint16_t
c = m->tetrahedra.color[i];
403 if(
c >= regions.size())
408 uint32_t *nodes = &m->tetrahedra.node[4 * i];
409 for(
int j = 0; j < 4; j++) {
411 vv[j] = c2v[nodes[j]];
415 double *x = &m->vertices.coord[4 * nodes[j]];
416 vv[j] =
new MVertex(x[0], x[1], x[2], gr);
418 c2v[nodes[j]] = vv[j];
426 return HXT_STATUS_OK;
429 HXTStatus Gmsh2Hxt(std::vector<GRegion *> ®ions, HXTMesh *m,
430 std::map<MVertex *, uint32_t> &v2c,
431 std::vector<MVertex *> &c2v)
433 std::set<MVertex *> all;
434 std::vector<GFace *> surfaces;
435 std::vector<GEdge *> curves;
436 std::vector<GVertex *> points;
437 std::map<MVertex *, double> vlc;
439 HXT_CHECK(getAllSurfaces(regions, m, surfaces));
440 HXT_CHECK(getAllCurves(regions, surfaces, m, curves));
442 uint64_t index = 0, ntri = 0, nedg = 0, npts = 0;
448 points.push_back(gv);
449 npts += gv->points.size();
450 for(
size_t i = 0; i < gv->points.size(); i++) {
451 MVertex *v = gv->points[i]->getVertex(0);
453 if(gv->prescribedMeshSizeAtVertex() !=
MAX_LC)
454 vlc[v] = gv->prescribedMeshSizeAtVertex();
459 for(
size_t j = 0; j < curves.size(); j++) {
460 GEdge *ge = curves[j];
461 nedg += ge->
lines.size();
462 for(
size_t i = 0; i < ge->
lines.size(); i++) {
463 all.insert(ge->
lines[i]->getVertex(0));
464 all.insert(ge->
lines[i]->getVertex(1));
468 for(
size_t j = 0; j < surfaces.size(); j++) {
469 GFace *gf = surfaces[j];
471 for(
size_t i = 0; i < gf->
triangles.size(); i++) {
472 all.insert(gf->
triangles[i]->getVertex(0));
473 all.insert(gf->
triangles[i]->getVertex(1));
474 all.insert(gf->
triangles[i]->getVertex(2));
478 m->vertices.num = m->vertices.size = all.size();
480 hxtAlignedMalloc(&m->vertices.coord, 4 * m->vertices.num *
sizeof(
double)));
483 c2v.resize(all.size());
485 m->vertices.coord[4 * count + 0] = v->
x();
486 m->vertices.coord[4 * count + 1] = v->
y();
487 m->vertices.coord[4 * count + 2] = v->
z();
488 m->vertices.coord[4 * count + 3] = 0;
490 ->mesh.lcFromPoints) {
491 auto it = vlc.find(v);
492 if(it != vlc.end()) m->vertices.coord[4 * count + 3] = it->second;
499 m->points.num = m->points.size = npts;
501 hxtAlignedMalloc(&m->points.node, (m->points.num) *
sizeof(uint32_t)));
503 hxtAlignedMalloc(&m->points.color, (m->points.num) *
sizeof(uint32_t)));
505 for(
size_t j = 0; j < points.size(); j++) {
507 for(
size_t i = 0; i < gv->
points.size(); i++) {
508 m->
points.node[index] = v2c[gv->
points[i]->getVertex(0)];
509 m->points.color[index] = gv->
tag();
514 m->lines.num = m->lines.size = nedg;
516 hxtAlignedMalloc(&m->lines.node, (m->lines.num) * 2 *
sizeof(uint32_t)));
518 hxtAlignedMalloc(&m->lines.color, (m->lines.num) *
sizeof(uint32_t)));
520 for(
size_t j = 0; j < curves.size(); j++) {
521 GEdge *ge = curves[j];
522 for(
size_t i = 0; i < ge->
lines.size(); i++) {
523 m->
lines.node[2 * index + 0] = v2c[ge->
lines[i]->getVertex(0)];
524 m->lines.node[2 * index + 1] = v2c[ge->
lines[i]->getVertex(1)];
525 m->lines.color[index] = ge->
tag();
530 m->triangles.num = m->triangles.size = ntri;
531 HXT_CHECK(hxtAlignedMalloc(&m->triangles.node,
532 (m->triangles.num) * 3 *
sizeof(uint32_t)));
533 HXT_CHECK(hxtAlignedMalloc(&m->triangles.color,
534 (m->triangles.num) *
sizeof(uint32_t)));
536 for(
size_t j = 0; j < surfaces.size(); j++) {
537 GFace *gf = surfaces[j];
538 for(
size_t i = 0; i < gf->
triangles.size(); i++) {
540 m->triangles.node[3 * index + 1] = v2c[gf->
triangles[i]->getVertex(1)];
541 m->triangles.node[3 * index + 2] = v2c[gf->
triangles[i]->getVertex(2)];
542 m->triangles.color[index] = gf->
tag();
546 return HXT_STATUS_OK;
549 static HXTStatus _meshGRegionHxt(std::vector<GRegion *> ®ions)
551 HXT_CHECK(hxtSetMessageCallback(messageCallback));
554 HXT_CHECK(hxtMeshCreate(&mesh));
556 std::map<MVertex *, uint32_t> v2c;
557 std::vector<MVertex *> c2v;
558 Gmsh2Hxt(regions, mesh, v2c, c2v);
560 int nthreads = getNumThreads();
562 HXTTetMeshOptions options = {
588 HXT_CHECK(hxtTetMesh(mesh, &options));
590 HXT_CHECK(Hxt2Gmsh(regions, mesh, v2c, c2v));
591 HXT_CHECK(hxtMeshDelete(&mesh));
592 return HXT_STATUS_OK;
597 HXTStatus status = _meshGRegionHxt(regions);
598 if(status == HXT_STATUS_OK)
return 0;
602 static HXTStatus _delaunayMeshIn3DHxt(std::vector<MVertex *> &verts,
603 std::vector<MTetrahedron *> &tets)
606 HXT_CHECK(hxtMeshCreate(&mesh));
608 size_t nvert = verts.size();
610 hxtAlignedMalloc(&mesh->vertices.coord, nvert * 4 *
sizeof(
double)));
611 for(
size_t i = 0; i < nvert; i++) {
612 mesh->vertices.coord[4 * i + 0] = verts[i]->x();
613 mesh->vertices.coord[4 * i + 1] = verts[i]->y();
614 mesh->vertices.coord[4 * i + 2] = verts[i]->z();
615 mesh->vertices.coord[4 * i + 3] = 0.;
617 mesh->vertices.num = nvert;
618 mesh->vertices.size = nvert;
620 int nthreads = getNumThreads();
622 HXTDelaunayOptions delOptions = {
635 HXTNodeInfo *nodeInfo;
637 hxtAlignedMalloc(&nodeInfo,
sizeof(HXTNodeInfo) * mesh->vertices.num));
638 for(uint32_t i = 0; i < mesh->vertices.num; i++) {
639 nodeInfo[i].node = i;
640 nodeInfo[i].status = HXT_STATUS_TRYAGAIN;
643 hxtDelaunaySteadyVertices(mesh, &delOptions, nodeInfo, mesh->vertices.num));
644 HXT_CHECK(hxtAlignedFree(&nodeInfo));
646 for(
size_t i = 0; i < mesh->tetrahedra.num; i++) {
647 if(mesh->tetrahedra.node[i * 4 + 3] !=
UINT32_MAX) {
648 uint32_t myColor = mesh->tetrahedra.color ? mesh->tetrahedra.color[i] : 0;
649 if(myColor != HXT_COLOR_OUT) {
650 uint32_t *n = &mesh->tetrahedra.node[4 * i];
652 new MTetrahedron(verts[n[0]], verts[n[1]], verts[n[2]], verts[n[3]]));
657 HXT_CHECK(hxtMeshDelete(&mesh));
658 return HXT_STATUS_OK;
662 std::vector<MTetrahedron *> &tets)
664 Msg::Info(
"Tetrahedrizing %d nodes...", v.size());
666 _delaunayMeshIn3DHxt(v, tets);
668 Msg::Info(
"Done tetrahedrizing %d nodes (Wall %gs, CPU %gs)", v.size(),
676 Msg::Error(
"Gmsh should be compiled with Hxt to enable this option");
681 std::vector<MTetrahedron *> &tets)
683 Msg::Error(
"Gmsh should be compiled with Hxt to enable this option");