xref: /petsc/src/dm/impls/plex/generators/ctetgen/ctetgenerate.c (revision 21e3ffae2f3b73c0bd738cf6d0a809700fc04bb0)
1 #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2 
3 #ifdef PETSC_HAVE_EGADS
4   #include <egads.h>
5 #endif
6 
7 #include <ctetgen.h>
8 
9 /* This is to fix the tetrahedron orientation from TetGen */
10 static PetscErrorCode DMPlexInvertCells_CTetgen(PetscInt numCells, PetscInt numCorners, PetscInt cells[])
11 {
12   PetscInt bound = numCells * numCorners, coff;
13 
14   PetscFunctionBegin;
15 #define SWAP(a, b) \
16   do { \
17     PetscInt tmp = (a); \
18     (a)          = (b); \
19     (b)          = tmp; \
20   } while (0)
21   for (coff = 0; coff < bound; coff += numCorners) SWAP(cells[coff], cells[coff + 1]);
22 #undef SWAP
23   PetscFunctionReturn(PETSC_SUCCESS);
24 }
25 
26 PETSC_EXTERN PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
27 {
28   MPI_Comm               comm;
29   const PetscInt         dim = 3;
30   PLC                   *in, *out;
31   DMUniversalLabel       universal;
32   PetscInt               vStart, vEnd, v, eStart, eEnd, e, fStart, fEnd, f, defVal, verbose = 0;
33   DMPlexInterpolatedFlag isInterpolated;
34   PetscMPIInt            rank;
35 
36   PetscFunctionBegin;
37   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)boundary)->prefix, "-ctetgen_verbose", &verbose, NULL));
38   PetscCall(PetscObjectGetComm((PetscObject)boundary, &comm));
39   PetscCallMPI(MPI_Comm_rank(comm, &rank));
40   PetscCall(DMPlexIsInterpolatedCollective(boundary, &isInterpolated));
41   PetscCall(DMUniversalLabelCreate(boundary, &universal));
42   PetscCall(DMLabelGetDefaultValue(universal->label, &defVal));
43 
44   PetscCall(PLCCreate(&in));
45   PetscCall(PLCCreate(&out));
46 
47   PetscCall(DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd));
48   in->numberofpoints = vEnd - vStart;
49   if (in->numberofpoints > 0) {
50     PetscSection       coordSection;
51     Vec                coordinates;
52     const PetscScalar *array;
53 
54     PetscCall(PetscMalloc1(in->numberofpoints * dim, &in->pointlist));
55     PetscCall(PetscCalloc1(in->numberofpoints, &in->pointmarkerlist));
56     PetscCall(DMGetCoordinatesLocal(boundary, &coordinates));
57     PetscCall(DMGetCoordinateSection(boundary, &coordSection));
58     PetscCall(VecGetArrayRead(coordinates, &array));
59     for (v = vStart; v < vEnd; ++v) {
60       const PetscInt idx = v - vStart;
61       PetscInt       off, d, m;
62 
63       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
64       for (d = 0; d < dim; ++d) in->pointlist[idx * dim + d] = PetscRealPart(array[off + d]);
65       PetscCall(DMLabelGetValue(universal->label, v, &m));
66       if (m != defVal) in->pointmarkerlist[idx] = (int)m;
67     }
68     PetscCall(VecRestoreArrayRead(coordinates, &array));
69   }
70 
71   PetscCall(DMPlexGetHeightStratum(boundary, 1, &eStart, &eEnd));
72   in->numberofedges = eEnd - eStart;
73   if (isInterpolated == DMPLEX_INTERPOLATED_FULL && in->numberofedges > 0) {
74     PetscCall(PetscMalloc1(in->numberofedges * 2, &in->edgelist));
75     PetscCall(PetscMalloc1(in->numberofedges, &in->edgemarkerlist));
76     for (e = eStart; e < eEnd; ++e) {
77       const PetscInt  idx = e - eStart;
78       const PetscInt *cone;
79       PetscInt        coneSize, val;
80 
81       PetscCall(DMPlexGetConeSize(boundary, e, &coneSize));
82       PetscCall(DMPlexGetCone(boundary, e, &cone));
83       in->edgelist[idx * 2]     = cone[0] - vStart;
84       in->edgelist[idx * 2 + 1] = cone[1] - vStart;
85 
86       PetscCall(DMLabelGetValue(universal->label, e, &val));
87       if (val != defVal) in->edgemarkerlist[idx] = (int)val;
88     }
89   }
90 
91   PetscCall(DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd));
92   in->numberoffacets = fEnd - fStart;
93   if (in->numberoffacets > 0) {
94     PetscCall(PetscMalloc1(in->numberoffacets, &in->facetlist));
95     PetscCall(PetscMalloc1(in->numberoffacets, &in->facetmarkerlist));
96     for (f = fStart; f < fEnd; ++f) {
97       const PetscInt idx    = f - fStart;
98       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m = -1;
99       polygon       *poly;
100 
101       in->facetlist[idx].numberofpolygons = 1;
102       PetscCall(PetscMalloc1(in->facetlist[idx].numberofpolygons, &in->facetlist[idx].polygonlist));
103       in->facetlist[idx].numberofholes = 0;
104       in->facetlist[idx].holelist      = NULL;
105 
106       PetscCall(DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points));
107       for (p = 0; p < numPoints * 2; p += 2) {
108         const PetscInt point = points[p];
109         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
110       }
111 
112       poly                   = in->facetlist[idx].polygonlist;
113       poly->numberofvertices = numVertices;
114       PetscCall(PetscMalloc1(poly->numberofvertices, &poly->vertexlist));
115       for (v = 0; v < numVertices; ++v) {
116         const PetscInt vIdx = points[v] - vStart;
117         poly->vertexlist[v] = vIdx;
118       }
119       PetscCall(DMLabelGetValue(universal->label, f, &m));
120       if (m != defVal) in->facetmarkerlist[idx] = (int)m;
121       PetscCall(DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points));
122     }
123   }
124   if (rank == 0) {
125     TetGenOpts t;
126 
127     PetscCall(TetGenOptsInitialize(&t));
128     t.in        = boundary; /* Should go away */
129     t.plc       = 1;
130     t.quality   = 1;
131     t.edgesout  = 1;
132     t.zeroindex = 1;
133     t.quiet     = 1;
134     t.verbose   = verbose;
135 #if 0
136   #ifdef PETSC_HAVE_EGADS
137     /* Need to add in more TetGen code */
138     t.nobisect  = 1; /* Add Y to preserve Surface Mesh for EGADS */
139   #endif
140 #endif
141 
142     PetscCall(TetGenCheckOpts(&t));
143     PetscCall(TetGenTetrahedralize(&t, in, out));
144   }
145   {
146     const PetscInt numCorners  = 4;
147     const PetscInt numCells    = out->numberoftetrahedra;
148     const PetscInt numVertices = out->numberofpoints;
149     PetscReal     *meshCoords  = NULL;
150     PetscInt      *cells       = NULL;
151 
152     if (sizeof(PetscReal) == sizeof(out->pointlist[0])) {
153       meshCoords = (PetscReal *)out->pointlist;
154     } else {
155       PetscInt i;
156 
157       PetscCall(PetscMalloc1(dim * numVertices, &meshCoords));
158       for (i = 0; i < dim * numVertices; ++i) meshCoords[i] = (PetscReal)out->pointlist[i];
159     }
160     if (sizeof(PetscInt) == sizeof(out->tetrahedronlist[0])) {
161       cells = (PetscInt *)out->tetrahedronlist;
162     } else {
163       PetscInt i;
164 
165       PetscCall(PetscMalloc1(numCells * numCorners, &cells));
166       for (i = 0; i < numCells * numCorners; i++) cells[i] = (PetscInt)out->tetrahedronlist[i];
167     }
168 
169     PetscCall(DMPlexInvertCells_CTetgen(numCells, numCorners, cells));
170     PetscCall(DMPlexCreateFromCellListPetsc(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm));
171     if (sizeof(PetscReal) != sizeof(out->pointlist[0])) PetscCall(PetscFree(meshCoords));
172     if (sizeof(PetscInt) != sizeof(out->tetrahedronlist[0])) PetscCall(PetscFree(cells));
173 
174     /* Set labels */
175     PetscCall(DMUniversalLabelCreateLabels(universal, PETSC_TRUE, *dm));
176     for (v = 0; v < numVertices; ++v) {
177       if (out->pointmarkerlist[v]) PetscCall(DMUniversalLabelSetLabelValue(universal, *dm, PETSC_TRUE, v + numCells, out->pointmarkerlist[v]));
178     }
179     if (interpolate) {
180       PetscInt e;
181 
182       for (e = 0; e < out->numberofedges; e++) {
183         if (out->edgemarkerlist[e]) {
184           const PetscInt  vertices[2] = {out->edgelist[e * 2 + 0] + numCells, out->edgelist[e * 2 + 1] + numCells};
185           const PetscInt *edges;
186           PetscInt        numEdges;
187 
188           PetscCall(DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges));
189           PetscCheck(numEdges == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %" PetscInt_FMT, numEdges);
190           PetscCall(DMUniversalLabelSetLabelValue(universal, *dm, PETSC_TRUE, edges[0], out->edgemarkerlist[e]));
191           PetscCall(DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges));
192         }
193       }
194       for (f = 0; f < out->numberoftrifaces; f++) {
195         if (out->trifacemarkerlist[f]) {
196           const PetscInt  vertices[3] = {out->trifacelist[f * 3 + 0] + numCells, out->trifacelist[f * 3 + 1] + numCells, out->trifacelist[f * 3 + 2] + numCells};
197           const PetscInt *faces;
198           PetscInt        numFaces;
199 
200           PetscCall(DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces));
201           PetscCheck(numFaces == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %" PetscInt_FMT, numFaces);
202           PetscCall(DMUniversalLabelSetLabelValue(universal, *dm, PETSC_TRUE, faces[0], out->trifacemarkerlist[f]));
203           PetscCall(DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces));
204         }
205       }
206     }
207 
208 #ifdef PETSC_HAVE_EGADS
209     {
210       DMLabel        bodyLabel;
211       PetscContainer modelObj;
212       PetscInt       cStart, cEnd, c, eStart, eEnd, fStart, fEnd;
213       ego           *bodies;
214       ego            model, geom;
215       int            Nb, oclass, mtype, *senses;
216 
217       /* Get Attached EGADS Model from Original DMPlex */
218       PetscCall(PetscObjectQuery((PetscObject)boundary, "EGADS Model", (PetscObject *)&modelObj));
219       if (modelObj) {
220         PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
221         PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
222         /* Transfer EGADS Model to Volumetric Mesh */
223         PetscCall(PetscObjectCompose((PetscObject)*dm, "EGADS Model", (PetscObject)modelObj));
224 
225         /* Set Cell Labels */
226         PetscCall(DMGetLabel(*dm, "EGADS Body ID", &bodyLabel));
227         PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd));
228         PetscCall(DMPlexGetHeightStratum(*dm, 1, &fStart, &fEnd));
229         PetscCall(DMPlexGetDepthStratum(*dm, 1, &eStart, &eEnd));
230 
231         for (c = cStart; c < cEnd; ++c) {
232           PetscReal centroid[3] = {0., 0., 0.};
233           PetscInt  b;
234 
235           /* Determine what body the cell's centroid is located in */
236           if (!interpolate) {
237             PetscSection coordSection;
238             Vec          coordinates;
239             PetscScalar *coords = NULL;
240             PetscInt     coordSize, s, d;
241 
242             PetscCall(DMGetCoordinatesLocal(*dm, &coordinates));
243             PetscCall(DMGetCoordinateSection(*dm, &coordSection));
244             PetscCall(DMPlexVecGetClosure(*dm, coordSection, coordinates, c, &coordSize, &coords));
245             for (s = 0; s < coordSize; ++s)
246               for (d = 0; d < dim; ++d) centroid[d] += coords[s * dim + d];
247             PetscCall(DMPlexVecRestoreClosure(*dm, coordSection, coordinates, c, &coordSize, &coords));
248           } else PetscCall(DMPlexComputeCellGeometryFVM(*dm, c, NULL, centroid, NULL));
249           for (b = 0; b < Nb; ++b) {
250             if (EG_inTopology(bodies[b], centroid) == EGADS_SUCCESS) break;
251           }
252           if (b < Nb) {
253             PetscInt  cval    = b, eVal, fVal;
254             PetscInt *closure = NULL, Ncl, cl;
255 
256             PetscCall(DMLabelSetValue(bodyLabel, c, cval));
257             PetscCall(DMPlexGetTransitiveClosure(*dm, c, PETSC_TRUE, &Ncl, &closure));
258             for (cl = 0; cl < Ncl; ++cl) {
259               const PetscInt p = closure[cl * 2];
260 
261               if (p >= eStart && p < eEnd) {
262                 PetscCall(DMLabelGetValue(bodyLabel, p, &eVal));
263                 if (eVal < 0) PetscCall(DMLabelSetValue(bodyLabel, p, cval));
264               }
265               if (p >= fStart && p < fEnd) {
266                 PetscCall(DMLabelGetValue(bodyLabel, p, &fVal));
267                 if (fVal < 0) PetscCall(DMLabelSetValue(bodyLabel, p, cval));
268               }
269             }
270             PetscCall(DMPlexRestoreTransitiveClosure(*dm, c, PETSC_TRUE, &Ncl, &closure));
271           }
272         }
273       }
274     }
275 #endif
276     PetscCall(DMPlexSetRefinementUniform(*dm, PETSC_FALSE));
277   }
278 
279   PetscCall(DMUniversalLabelDestroy(&universal));
280   PetscCall(PLCDestroy(&in));
281   PetscCall(PLCDestroy(&out));
282   PetscFunctionReturn(PETSC_SUCCESS);
283 }
284 
285 PETSC_EXTERN PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
286 {
287   MPI_Comm               comm;
288   const PetscInt         dim = 3;
289   PLC                   *in, *out;
290   DMUniversalLabel       universal;
291   PetscInt               vStart, vEnd, v, eStart, eEnd, e, fStart, fEnd, f, cStart, cEnd, c, defVal, verbose = 0;
292   DMPlexInterpolatedFlag isInterpolated;
293   PetscMPIInt            rank;
294 
295   PetscFunctionBegin;
296   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-ctetgen_verbose", &verbose, NULL));
297   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
298   PetscCallMPI(MPI_Comm_rank(comm, &rank));
299   PetscCall(DMPlexIsInterpolatedCollective(dm, &isInterpolated));
300   PetscCall(DMUniversalLabelCreate(dm, &universal));
301   PetscCall(DMLabelGetDefaultValue(universal->label, &defVal));
302 
303   PetscCall(PLCCreate(&in));
304   PetscCall(PLCCreate(&out));
305 
306   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
307   in->numberofpoints = vEnd - vStart;
308   if (in->numberofpoints > 0) {
309     PetscSection coordSection;
310     Vec          coordinates;
311     PetscScalar *array;
312 
313     PetscCall(PetscMalloc1(in->numberofpoints * dim, &in->pointlist));
314     PetscCall(PetscCalloc1(in->numberofpoints, &in->pointmarkerlist));
315     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
316     PetscCall(DMGetCoordinateSection(dm, &coordSection));
317     PetscCall(VecGetArray(coordinates, &array));
318     for (v = vStart; v < vEnd; ++v) {
319       const PetscInt idx = v - vStart;
320       PetscInt       off, d, m;
321 
322       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
323       for (d = 0; d < dim; ++d) in->pointlist[idx * dim + d] = PetscRealPart(array[off + d]);
324       PetscCall(DMLabelGetValue(universal->label, v, &m));
325       if (m != defVal) in->pointmarkerlist[idx] = (int)m;
326     }
327     PetscCall(VecRestoreArray(coordinates, &array));
328   }
329 
330   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
331   in->numberofedges = eEnd - eStart;
332   if (isInterpolated == DMPLEX_INTERPOLATED_FULL && in->numberofedges > 0) {
333     PetscCall(PetscMalloc1(in->numberofedges * 2, &in->edgelist));
334     PetscCall(PetscMalloc1(in->numberofedges, &in->edgemarkerlist));
335     for (e = eStart; e < eEnd; ++e) {
336       const PetscInt  idx = e - eStart;
337       const PetscInt *cone;
338       PetscInt        coneSize, val;
339 
340       PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
341       PetscCall(DMPlexGetCone(dm, e, &cone));
342       in->edgelist[idx * 2]     = cone[0] - vStart;
343       in->edgelist[idx * 2 + 1] = cone[1] - vStart;
344 
345       PetscCall(DMLabelGetValue(universal->label, e, &val));
346       if (val != defVal) in->edgemarkerlist[idx] = (int)val;
347     }
348   }
349 
350   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
351   in->numberoftrifaces = 0;
352   for (f = fStart; f < fEnd; ++f) {
353     PetscInt supportSize;
354 
355     PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
356     if (supportSize == 1) ++in->numberoftrifaces;
357   }
358   if (isInterpolated == DMPLEX_INTERPOLATED_FULL && in->numberoftrifaces > 0) {
359     PetscInt tf = 0;
360 
361     PetscCall(PetscMalloc1(in->numberoftrifaces * 3, &in->trifacelist));
362     PetscCall(PetscMalloc1(in->numberoftrifaces, &in->trifacemarkerlist));
363     for (f = fStart; f < fEnd; ++f) {
364       PetscInt *points = NULL;
365       PetscInt  supportSize, numPoints, p, Nv = 0, val;
366 
367       PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
368       if (supportSize != 1) continue;
369       PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &numPoints, &points));
370       for (p = 0; p < numPoints * 2; p += 2) {
371         const PetscInt point = points[p];
372         if ((point >= vStart) && (point < vEnd)) in->trifacelist[tf * 3 + Nv++] = point - vStart;
373       }
374       PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &numPoints, &points));
375       PetscCheck(Nv == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " has %" PetscInt_FMT " vertices, not 3", f, Nv);
376       PetscCall(DMLabelGetValue(universal->label, f, &val));
377       if (val != defVal) in->trifacemarkerlist[tf] = (int)val;
378       ++tf;
379     }
380   }
381 
382   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
383   in->numberofcorners       = 4;
384   in->numberoftetrahedra    = cEnd - cStart;
385   in->tetrahedronvolumelist = maxVolumes;
386   if (in->numberoftetrahedra > 0) {
387     PetscCall(PetscMalloc1(in->numberoftetrahedra * in->numberofcorners, &in->tetrahedronlist));
388     for (c = cStart; c < cEnd; ++c) {
389       const PetscInt idx     = c - cStart;
390       PetscInt      *closure = NULL;
391       PetscInt       closureSize;
392 
393       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
394       PetscCheck((closureSize == 5) || (closureSize == 15), comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %" PetscInt_FMT " vertices in closure", closureSize);
395       for (v = 0; v < 4; ++v) in->tetrahedronlist[idx * in->numberofcorners + v] = closure[(v + closureSize - 4) * 2] - vStart;
396       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
397     }
398   }
399 
400   if (rank == 0) {
401     TetGenOpts t;
402 
403     PetscCall(TetGenOptsInitialize(&t));
404 
405     t.in        = dm; /* Should go away */
406     t.refine    = 1;
407     t.varvolume = 1;
408     t.quality   = 1;
409     t.edgesout  = 1;
410     t.zeroindex = 1;
411     t.quiet     = 1;
412     t.verbose   = verbose; /* Change this */
413 
414     PetscCall(TetGenCheckOpts(&t));
415     PetscCall(TetGenTetrahedralize(&t, in, out));
416   }
417 
418   in->tetrahedronvolumelist = NULL;
419   {
420     const PetscInt numCorners  = 4;
421     const PetscInt numCells    = out->numberoftetrahedra;
422     const PetscInt numVertices = out->numberofpoints;
423     PetscReal     *meshCoords  = NULL;
424     PetscInt      *cells       = NULL;
425     PetscBool      interpolate = isInterpolated == DMPLEX_INTERPOLATED_FULL ? PETSC_TRUE : PETSC_FALSE;
426 
427     if (sizeof(PetscReal) == sizeof(out->pointlist[0])) {
428       meshCoords = (PetscReal *)out->pointlist;
429     } else {
430       PetscInt i;
431 
432       PetscCall(PetscMalloc1(dim * numVertices, &meshCoords));
433       for (i = 0; i < dim * numVertices; ++i) meshCoords[i] = (PetscReal)out->pointlist[i];
434     }
435     if (sizeof(PetscInt) == sizeof(out->tetrahedronlist[0])) {
436       cells = (PetscInt *)out->tetrahedronlist;
437     } else {
438       PetscInt i;
439 
440       PetscCall(PetscMalloc1(numCells * numCorners, &cells));
441       for (i = 0; i < numCells * numCorners; ++i) cells[i] = (PetscInt)out->tetrahedronlist[i];
442     }
443 
444     PetscCall(DMPlexInvertCells_CTetgen(numCells, numCorners, cells));
445     PetscCall(DMPlexCreateFromCellListPetsc(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined));
446     if (sizeof(PetscReal) != sizeof(out->pointlist[0])) PetscCall(PetscFree(meshCoords));
447     if (sizeof(PetscInt) != sizeof(out->tetrahedronlist[0])) PetscCall(PetscFree(cells));
448 
449     /* Set labels */
450     PetscCall(DMUniversalLabelCreateLabels(universal, PETSC_TRUE, *dmRefined));
451     for (v = 0; v < numVertices; ++v) {
452       if (out->pointmarkerlist[v]) PetscCall(DMUniversalLabelSetLabelValue(universal, *dmRefined, PETSC_TRUE, v + numCells, out->pointmarkerlist[v]));
453     }
454     if (interpolate) {
455       PetscInt e, f;
456 
457       for (e = 0; e < out->numberofedges; e++) {
458         if (out->edgemarkerlist[e]) {
459           const PetscInt  vertices[2] = {out->edgelist[e * 2 + 0] + numCells, out->edgelist[e * 2 + 1] + numCells};
460           const PetscInt *edges;
461           PetscInt        numEdges;
462 
463           PetscCall(DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges));
464           PetscCheck(numEdges == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %" PetscInt_FMT, numEdges);
465           PetscCall(DMUniversalLabelSetLabelValue(universal, *dmRefined, PETSC_TRUE, edges[0], out->edgemarkerlist[e]));
466           PetscCall(DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges));
467         }
468       }
469       for (f = 0; f < out->numberoftrifaces; f++) {
470         if (out->trifacemarkerlist[f]) {
471           const PetscInt  vertices[3] = {out->trifacelist[f * 3 + 0] + numCells, out->trifacelist[f * 3 + 1] + numCells, out->trifacelist[f * 3 + 2] + numCells};
472           const PetscInt *faces;
473           PetscInt        numFaces;
474 
475           PetscCall(DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces));
476           PetscCheck(numFaces == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %" PetscInt_FMT, numFaces);
477           PetscCall(DMUniversalLabelSetLabelValue(universal, *dmRefined, PETSC_TRUE, faces[0], out->trifacemarkerlist[f]));
478           PetscCall(DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces));
479         }
480       }
481     }
482 
483 #ifdef PETSC_HAVE_EGADS
484     {
485       DMLabel        bodyLabel;
486       PetscContainer modelObj;
487       PetscInt       cStart, cEnd, c, eStart, eEnd, fStart, fEnd;
488       ego           *bodies;
489       ego            model, geom;
490       int            Nb, oclass, mtype, *senses;
491 
492       /* Get Attached EGADS Model from Original DMPlex */
493       PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
494       if (modelObj) {
495         PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
496         PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
497         /* Transfer EGADS Model to Volumetric Mesh */
498         PetscCall(PetscObjectCompose((PetscObject)*dmRefined, "EGADS Model", (PetscObject)modelObj));
499 
500         /* Set Cell Labels */
501         PetscCall(DMGetLabel(*dmRefined, "EGADS Body ID", &bodyLabel));
502         PetscCall(DMPlexGetHeightStratum(*dmRefined, 0, &cStart, &cEnd));
503         PetscCall(DMPlexGetHeightStratum(*dmRefined, 1, &fStart, &fEnd));
504         PetscCall(DMPlexGetDepthStratum(*dmRefined, 1, &eStart, &eEnd));
505 
506         for (c = cStart; c < cEnd; ++c) {
507           PetscReal centroid[3] = {0., 0., 0.};
508           PetscInt  b;
509 
510           /* Determine what body the cell's centroid is located in */
511           if (!interpolate) {
512             PetscSection coordSection;
513             Vec          coordinates;
514             PetscScalar *coords = NULL;
515             PetscInt     coordSize, s, d;
516 
517             PetscCall(DMGetCoordinatesLocal(*dmRefined, &coordinates));
518             PetscCall(DMGetCoordinateSection(*dmRefined, &coordSection));
519             PetscCall(DMPlexVecGetClosure(*dmRefined, coordSection, coordinates, c, &coordSize, &coords));
520             for (s = 0; s < coordSize; ++s)
521               for (d = 0; d < dim; ++d) centroid[d] += coords[s * dim + d];
522             PetscCall(DMPlexVecRestoreClosure(*dmRefined, coordSection, coordinates, c, &coordSize, &coords));
523           } else PetscCall(DMPlexComputeCellGeometryFVM(*dmRefined, c, NULL, centroid, NULL));
524           for (b = 0; b < Nb; ++b) {
525             if (EG_inTopology(bodies[b], centroid) == EGADS_SUCCESS) break;
526           }
527           if (b < Nb) {
528             PetscInt  cval    = b, eVal, fVal;
529             PetscInt *closure = NULL, Ncl, cl;
530 
531             PetscCall(DMLabelSetValue(bodyLabel, c, cval));
532             PetscCall(DMPlexGetTransitiveClosure(*dmRefined, c, PETSC_TRUE, &Ncl, &closure));
533             for (cl = 0; cl < Ncl; cl += 2) {
534               const PetscInt p = closure[cl];
535 
536               if (p >= eStart && p < eEnd) {
537                 PetscCall(DMLabelGetValue(bodyLabel, p, &eVal));
538                 if (eVal < 0) PetscCall(DMLabelSetValue(bodyLabel, p, cval));
539               }
540               if (p >= fStart && p < fEnd) {
541                 PetscCall(DMLabelGetValue(bodyLabel, p, &fVal));
542                 if (fVal < 0) PetscCall(DMLabelSetValue(bodyLabel, p, cval));
543               }
544             }
545             PetscCall(DMPlexRestoreTransitiveClosure(*dmRefined, c, PETSC_TRUE, &Ncl, &closure));
546           }
547         }
548       }
549     }
550 #endif
551     PetscCall(DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE));
552   }
553   PetscCall(DMUniversalLabelDestroy(&universal));
554   PetscCall(PLCDestroy(&in));
555   PetscCall(PLCDestroy(&out));
556   PetscFunctionReturn(PETSC_SUCCESS);
557 }
558