xref: /petsc/src/dm/impls/plex/plexegads.c (revision 4ffacfe27a72f4cdf51b68a3bbb6aed96040fb2f)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/hashmapi.h>
3 
4 #ifdef PETSC_HAVE_EGADS
5 #include <egads.h>
6 #endif
7 
8 /* We need to understand how to natively parse STEP files. There seems to be only one open source implementation of
9    the STEP parser contained in the OpenCASCADE package. It is enough to make a strong man weep:
10 
11      https://github.com/tpaviot/oce/tree/master/src/STEPControl
12 
13    The STEP, and inner EXPRESS, formats are ISO standards, so they are documented
14 
15      https://stackoverflow.com/questions/26774037/documentation-or-specification-for-step-and-stp-files
16      http://stepmod.sourceforge.net/express_model_spec/
17 
18    but again it seems that there has been a deliberate effort at obfuscation, probably to raise the bar for entrants.
19 */
20 
21 #ifdef PETSC_HAVE_EGADS
22 PETSC_INTERN PetscErrorCode DMPlexSnapToGeomModel_EGADS_Internal(DM, PetscInt, ego, PetscInt, PetscInt, PetscInt, const PetscScalar[], PetscScalar[]);
23 PETSC_INTERN PetscErrorCode DMPlexSnapToGeomModel_EGADSLite_Internal(DM, PetscInt, ego, PetscInt, PetscInt, PetscInt, const PetscScalar[], PetscScalar[]);
24 
25 PetscErrorCode DMPlexSnapToGeomModel_EGADS_Internal(DM dm, PetscInt p, ego model, PetscInt bodyID, PetscInt faceID, PetscInt edgeID, const PetscScalar mcoords[], PetscScalar gcoords[])
26 {
27   DM             cdm;
28   ego           *bodies;
29   ego            geom, body, obj;
30   /* result has to hold derivatives, along with the value */
31   double         params[3], result[18], paramsV[16*3], resultV[16*3], range[4];
32   int            Nb, oclass, mtype, *senses, peri;
33   Vec            coordinatesLocal;
34   PetscScalar   *coords = NULL;
35   PetscInt       Nv, v, Np = 0, pm;
36   PetscInt       dE, d;
37 
38   PetscFunctionBeginHot;
39   PetscCall(DMGetCoordinateDM(dm, &cdm));
40   PetscCall(DMGetCoordinateDim(dm, &dE));
41   PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
42   PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
43   PetscCheck(bodyID < Nb,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Body %" PetscInt_FMT " is not in [0, %d)", bodyID, Nb);
44   body = bodies[bodyID];
45 
46   if (edgeID >= 0)      {PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &obj)); Np = 1;}
47   else if (faceID >= 0) {PetscCall(EG_objectBodyTopo(body, FACE, faceID, &obj)); Np = 2;}
48   else {
49     for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
50     PetscFunctionReturn(0);
51   }
52 
53   /* Calculate parameters (t or u,v) for vertices */
54   PetscCall(DMPlexVecGetClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords));
55   Nv  /= dE;
56   if (Nv == 1) {
57     PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords));
58     for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
59     PetscFunctionReturn(0);
60   }
61   PetscCheck(Nv <= 16,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " coordinates associated to point %" PetscInt_FMT, Nv, p);
62 
63   /* Correct EGADSlite 2pi bug when calculating nearest point on Periodic Surfaces */
64   PetscCall(EG_getRange(obj, range, &peri));
65   for (v = 0; v < Nv; ++v) {
66     PetscCall(EG_invEvaluate(obj, &coords[v*dE], &paramsV[v*3], &resultV[v*3]));
67 #if 1
68     if (peri > 0) {
69       if      (paramsV[v*3+0] + 1.e-4 < range[0]) {paramsV[v*3+0] += 2. * PETSC_PI;}
70       else if (paramsV[v*3+0] - 1.e-4 > range[1]) {paramsV[v*3+0] -= 2. * PETSC_PI;}
71     }
72     if (peri > 1) {
73       if      (paramsV[v*3+1] + 1.e-4 < range[2]) {paramsV[v*3+1] += 2. * PETSC_PI;}
74       else if (paramsV[v*3+1] - 1.e-4 > range[3]) {paramsV[v*3+1] -= 2. * PETSC_PI;}
75     }
76 #endif
77   }
78   PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords));
79   /* Calculate parameters (t or u,v) for new vertex at edge midpoint */
80   for (pm = 0; pm < Np; ++pm) {
81     params[pm] = 0.;
82     for (v = 0; v < Nv; ++v) params[pm] += paramsV[v*3+pm];
83     params[pm] /= Nv;
84   }
85   PetscCheck(!(params[0] < range[0]) && !(params[0] > range[1]),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " had bad interpolation", p);
86   PetscCheck(Np <= 1 || (params[1] >= range[2] && params[1] <= range[3]),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " had bad interpolation", p);
87   /* Put coordinates for new vertex in result[] */
88   PetscCall(EG_evaluate(obj, params, result));
89   for (d = 0; d < dE; ++d) gcoords[d] = result[d];
90   PetscFunctionReturn(0);
91 }
92 #endif
93 
94 /*@
95   DMPlexSnapToGeomModel - Given a coordinate point 'mcoords' on the mesh point 'p', return the closest coordinate point 'gcoords' on the geometry model associated with that point.
96 
97   Not collective
98 
99   Input Parameters:
100 + dm      - The DMPlex object
101 . p       - The mesh point
102 . dE      - The coordinate dimension
103 - mcoords - A coordinate point lying on the mesh point
104 
105   Output Parameter:
106 . gcoords - The closest coordinate point on the geometry model associated with 'p' to the given point
107 
108   Note: Returns the original coordinates if no geometry model is found. Right now the only supported geometry model is EGADS. The coordinate dimension may be different from the coordinate dimension of the dm, for example if the transformation is extrusion.
109 
110   Level: intermediate
111 
112 .seealso: `DMRefine()`, `DMPlexCreate()`, `DMPlexSetRefinementUniform()`
113 @*/
114 PetscErrorCode DMPlexSnapToGeomModel(DM dm, PetscInt p, PetscInt dE, const PetscScalar mcoords[], PetscScalar gcoords[])
115 {
116   PetscInt d;
117 
118   PetscFunctionBeginHot;
119 #ifdef PETSC_HAVE_EGADS
120   {
121     DM_Plex       *plex = (DM_Plex *) dm->data;
122     DMLabel        bodyLabel, faceLabel, edgeLabel;
123     PetscInt       bodyID, faceID, edgeID;
124     PetscContainer modelObj;
125     ego            model;
126     PetscBool      islite = PETSC_FALSE;
127 
128     PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
129     PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
130     PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
131     if (!bodyLabel || !faceLabel || !edgeLabel || plex->ignoreModel) {
132       for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
133       PetscFunctionReturn(0);
134     }
135     PetscCall(PetscObjectQuery((PetscObject) dm, "EGADS Model", (PetscObject *) &modelObj));
136     if (!modelObj) {
137       PetscCall(PetscObjectQuery((PetscObject) dm, "EGADSLite Model", (PetscObject *) &modelObj));
138       islite = PETSC_TRUE;
139     }
140     if (!modelObj) {
141       for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
142       PetscFunctionReturn(0);
143     }
144     PetscCall(PetscContainerGetPointer(modelObj, (void **) &model));
145     PetscCall(DMLabelGetValue(bodyLabel, p, &bodyID));
146     PetscCall(DMLabelGetValue(faceLabel, p, &faceID));
147     PetscCall(DMLabelGetValue(edgeLabel, p, &edgeID));
148     /* Allows for "Connective" Plex Edges present in models with multiple non-touching Entities */
149     if (bodyID < 0) {
150       for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
151       PetscFunctionReturn(0);
152     }
153     if (islite) PetscCall(DMPlexSnapToGeomModel_EGADSLite_Internal(dm, p, model, bodyID, faceID, edgeID, mcoords, gcoords));
154     else        PetscCall(DMPlexSnapToGeomModel_EGADS_Internal(dm, p, model, bodyID, faceID, edgeID, mcoords, gcoords));
155   }
156 #else
157   for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
158 #endif
159   PetscFunctionReturn(0);
160 }
161 
162 #if defined(PETSC_HAVE_EGADS)
163 static PetscErrorCode DMPlexEGADSPrintModel_Internal(ego model)
164 {
165   ego geom, *bodies, *objs, *nobjs, *mobjs, *lobjs;
166   int oclass, mtype, *senses;
167   int Nb, b;
168 
169   PetscFunctionBeginUser;
170   /* test bodyTopo functions */
171   PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
172   PetscCall(PetscPrintf(PETSC_COMM_SELF, " Number of BODIES (nbodies): %d \n", Nb));
173 
174   for (b = 0; b < Nb; ++b) {
175     ego body = bodies[b];
176     int id, Nsh, Nf, Nl, l, Ne, e, Nv, v;
177 
178     /* Output Basic Model Topology */
179     PetscCall(EG_getBodyTopos(body, NULL, SHELL, &Nsh, &objs));
180     PetscCall(PetscPrintf(PETSC_COMM_SELF, "   Number of SHELLS: %d \n", Nsh));
181     EG_free(objs);
182 
183     PetscCall(EG_getBodyTopos(body, NULL, FACE,  &Nf, &objs));
184     PetscCall(PetscPrintf(PETSC_COMM_SELF, "   Number of FACES: %d \n", Nf));
185     EG_free(objs);
186 
187     PetscCall(EG_getBodyTopos(body, NULL, LOOP,  &Nl, &lobjs));
188     PetscCall(PetscPrintf(PETSC_COMM_SELF, "   Number of LOOPS: %d \n", Nl));
189 
190     PetscCall(EG_getBodyTopos(body, NULL, EDGE,  &Ne, &objs));
191     PetscCall(PetscPrintf(PETSC_COMM_SELF, "   Number of EDGES: %d \n", Ne));
192     EG_free(objs);
193 
194     PetscCall(EG_getBodyTopos(body, NULL, NODE,  &Nv, &objs));
195     PetscCall(PetscPrintf(PETSC_COMM_SELF, "   Number of NODES: %d \n", Nv));
196     EG_free(objs);
197 
198     for (l = 0; l < Nl; ++l) {
199       ego loop = lobjs[l];
200 
201       id   = EG_indexBodyTopo(body, loop);
202       PetscCall(PetscPrintf(PETSC_COMM_SELF, "          LOOP ID: %d\n", id));
203 
204       /* Get EDGE info which associated with the current LOOP */
205       PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
206 
207       for (e = 0; e < Ne; ++e) {
208         ego    edge      = objs[e];
209         double range[4]  = {0., 0., 0., 0.};
210         double point[3]  = {0., 0., 0.};
211         double params[3] = {0., 0., 0.};
212         double result[18];
213         int    peri;
214 
215         id   = EG_indexBodyTopo(body, edge);
216         PetscCall(PetscPrintf(PETSC_COMM_SELF, "            EDGE ID: %d (%d)\n", id, e));
217 
218         PetscCall(EG_getRange(edge, range, &peri));
219         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Range = %lf, %lf, %lf, %lf \n", range[0], range[1], range[2], range[3]));
220 
221         /* Get NODE info which associated with the current EDGE */
222         PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
223         if (mtype == DEGENERATE) {
224           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  EDGE %d is DEGENERATE \n", id));
225         } else {
226           params[0] = range[0];
227           PetscCall(EG_evaluate(edge, params, result));
228           PetscCall(PetscPrintf(PETSC_COMM_SELF, "   between (%lf, %lf, %lf)", result[0], result[1], result[2]));
229           params[0] = range[1];
230           PetscCall(EG_evaluate(edge, params, result));
231           PetscCall(PetscPrintf(PETSC_COMM_SELF, " and (%lf, %lf, %lf)\n", result[0], result[1], result[2]));
232         }
233 
234         for (v = 0; v < Nv; ++v) {
235           ego    vertex = nobjs[v];
236           double limits[4];
237           int    dummy;
238 
239           PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
240           id   = EG_indexBodyTopo(body, vertex);
241           PetscCall(PetscPrintf(PETSC_COMM_SELF, "              NODE ID: %d \n", id));
242           PetscCall(PetscPrintf(PETSC_COMM_SELF, "                 (x, y, z) = (%lf, %lf, %lf) \n", limits[0], limits[1], limits[2]));
243 
244           point[0] = point[0] + limits[0];
245           point[1] = point[1] + limits[1];
246           point[2] = point[2] + limits[2];
247         }
248       }
249     }
250     EG_free(lobjs);
251   }
252   PetscFunctionReturn(0);
253 }
254 
255 static PetscErrorCode DMPlexEGADSDestroy_Private(void *context)
256 {
257   if (context) EG_close((ego) context);
258   return 0;
259 }
260 
261 static PetscErrorCode DMPlexCreateEGADS_Internal(MPI_Comm comm, ego context, ego model, DM *newdm)
262 {
263   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
264   PetscInt       cStart, cEnd, c;
265   /* EGADSLite variables */
266   ego            geom, *bodies, *objs, *nobjs, *mobjs, *lobjs;
267   int            oclass, mtype, nbodies, *senses;
268   int            b;
269   /* PETSc variables */
270   DM             dm;
271   PetscHMapI     edgeMap = NULL;
272   PetscInt       dim = -1, cdim = -1, numCorners = 0, maxCorners = 0, numVertices = 0, newVertices = 0, numEdges = 0, numCells = 0, newCells = 0, numQuads = 0, cOff = 0, fOff = 0;
273   PetscInt      *cells  = NULL, *cone = NULL;
274   PetscReal     *coords = NULL;
275   PetscMPIInt    rank;
276 
277   PetscFunctionBegin;
278   PetscCallMPI(MPI_Comm_rank(comm, &rank));
279   if (rank == 0) {
280     const PetscInt debug = 0;
281 
282     /* ---------------------------------------------------------------------------------------------------
283     Generate Petsc Plex
284       Get all Nodes in model, record coordinates in a correctly formatted array
285       Cycle through bodies, cycle through loops, recorde NODE IDs in a correctly formatted array
286       We need to uniformly refine the initial geometry to guarantee a valid mesh
287     */
288 
289     /* Calculate cell and vertex sizes */
290     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
291     PetscCall(PetscHMapICreate(&edgeMap));
292     numEdges = 0;
293     for (b = 0; b < nbodies; ++b) {
294       ego body = bodies[b];
295       int id, Nl, l, Nv, v;
296 
297       PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
298       for (l = 0; l < Nl; ++l) {
299         ego loop = lobjs[l];
300         int Ner  = 0, Ne, e, Nc;
301 
302         PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
303         for (e = 0; e < Ne; ++e) {
304           ego edge = objs[e];
305           int Nv, id;
306           PetscHashIter iter;
307           PetscBool     found;
308 
309           PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
310           if (mtype == DEGENERATE) continue;
311           id = EG_indexBodyTopo(body, edge);
312           PetscCall(PetscHMapIFind(edgeMap, id-1, &iter, &found));
313           if (!found) PetscCall(PetscHMapISet(edgeMap, id-1, numEdges++));
314           ++Ner;
315         }
316         if (Ner == 2)      {Nc = 2;}
317         else if (Ner == 3) {Nc = 4;}
318         else if (Ner == 4) {Nc = 8; ++numQuads;}
319         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot support loop with %d edges", Ner);
320         numCells += Nc;
321         newCells += Nc-1;
322         maxCorners = PetscMax(Ner*2+1, maxCorners);
323       }
324       PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
325       for (v = 0; v < Nv; ++v) {
326         ego vertex = nobjs[v];
327 
328         id = EG_indexBodyTopo(body, vertex);
329         /* TODO: Instead of assuming contiguous ids, we could use a hash table */
330         numVertices = PetscMax(id, numVertices);
331       }
332       EG_free(lobjs);
333       EG_free(nobjs);
334     }
335     PetscCall(PetscHMapIGetSize(edgeMap, &numEdges));
336     newVertices  = numEdges + numQuads;
337     numVertices += newVertices;
338 
339     dim        = 2; /* Assume 3D Models :: Need to update to handle 2D Models in the future */
340     cdim       = 3; /* Assume 3D Models :: Need to update to handle 2D Models in the future */
341     numCorners = 3; /* Split cells into triangles */
342     PetscCall(PetscMalloc3(numVertices*cdim, &coords, numCells*numCorners, &cells, maxCorners, &cone));
343 
344     /* Get vertex coordinates */
345     for (b = 0; b < nbodies; ++b) {
346       ego body = bodies[b];
347       int id, Nv, v;
348 
349       PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
350       for (v = 0; v < Nv; ++v) {
351         ego    vertex = nobjs[v];
352         double limits[4];
353         int    dummy;
354 
355         PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
356         id   = EG_indexBodyTopo(body, vertex);
357         coords[(id-1)*cdim+0] = limits[0];
358         coords[(id-1)*cdim+1] = limits[1];
359         coords[(id-1)*cdim+2] = limits[2];
360       }
361       EG_free(nobjs);
362     }
363     PetscCall(PetscHMapIClear(edgeMap));
364     fOff     = numVertices - newVertices + numEdges;
365     numEdges = 0;
366     numQuads = 0;
367     for (b = 0; b < nbodies; ++b) {
368       ego body = bodies[b];
369       int Nl, l;
370 
371       PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
372       for (l = 0; l < Nl; ++l) {
373         ego loop = lobjs[l];
374         int lid, Ner = 0, Ne, e;
375 
376         lid  = EG_indexBodyTopo(body, loop);
377         PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
378         for (e = 0; e < Ne; ++e) {
379           ego       edge = objs[e];
380           int       eid, Nv;
381           PetscHashIter iter;
382           PetscBool     found;
383 
384           PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
385           if (mtype == DEGENERATE) continue;
386           ++Ner;
387           eid  = EG_indexBodyTopo(body, edge);
388           PetscCall(PetscHMapIFind(edgeMap, eid-1, &iter, &found));
389           if (!found) {
390             PetscInt v = numVertices - newVertices + numEdges;
391             double range[4], params[3] = {0., 0., 0.}, result[18];
392             int    periodic[2];
393 
394             PetscCall(PetscHMapISet(edgeMap, eid-1, numEdges++));
395             PetscCall(EG_getRange(edge, range, periodic));
396             params[0] = 0.5*(range[0] + range[1]);
397             PetscCall(EG_evaluate(edge, params, result));
398             coords[v*cdim+0] = result[0];
399             coords[v*cdim+1] = result[1];
400             coords[v*cdim+2] = result[2];
401           }
402         }
403         if (Ner == 4) {
404           PetscInt v = fOff + numQuads++;
405           ego     *fobjs, face;
406           double   range[4], params[3] = {0., 0., 0.}, result[18];
407           int      Nf, fid, periodic[2];
408 
409           PetscCall(EG_getBodyTopos(body, loop, FACE, &Nf, &fobjs));
410           face = fobjs[0];
411           fid  = EG_indexBodyTopo(body, face);
412           PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Loop %d has %d faces, instead of 1 (%d)", lid-1, Nf, fid);
413           PetscCall(EG_getRange(face, range, periodic));
414           params[0] = 0.5*(range[0] + range[1]);
415           params[1] = 0.5*(range[2] + range[3]);
416           PetscCall(EG_evaluate(face, params, result));
417           coords[v*cdim+0] = result[0];
418           coords[v*cdim+1] = result[1];
419           coords[v*cdim+2] = result[2];
420         }
421       }
422     }
423     PetscCheck(numEdges + numQuads == newVertices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of new vertices %" PetscInt_FMT " != %" PetscInt_FMT " previous count", numEdges + numQuads, newVertices);
424 
425     /* Get cell vertices by traversing loops */
426     numQuads = 0;
427     cOff     = 0;
428     for (b = 0; b < nbodies; ++b) {
429       ego body = bodies[b];
430       int id, Nl, l;
431 
432       PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
433       for (l = 0; l < Nl; ++l) {
434         ego loop = lobjs[l];
435         int lid, Ner = 0, Ne, e, nc = 0, c, Nt, t;
436 
437         lid  = EG_indexBodyTopo(body, loop);
438         PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
439 
440         for (e = 0; e < Ne; ++e) {
441           ego edge = objs[e];
442           int points[3];
443           int eid, Nv, v, tmp;
444 
445           eid = EG_indexBodyTopo(body, edge);
446           PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
447           if (mtype == DEGENERATE) continue;
448           else                     ++Ner;
449           PetscCheck(Nv == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Edge %d has %d vertices != 2", eid, Nv);
450 
451           for (v = 0; v < Nv; ++v) {
452             ego vertex = nobjs[v];
453 
454             id = EG_indexBodyTopo(body, vertex);
455             points[v*2] = id-1;
456           }
457           {
458             PetscInt edgeNum;
459 
460             PetscCall(PetscHMapIGet(edgeMap, eid-1, &edgeNum));
461             points[1] = numVertices - newVertices + edgeNum;
462           }
463           /* EGADS loops are not oriented, but seem to be in order, so we must piece them together */
464           if (!nc) {
465             for (v = 0; v < Nv+1; ++v) cone[nc++] = points[v];
466           } else {
467             if (cone[nc-1] == points[0])      {cone[nc++] = points[1]; if (cone[0] != points[2]) cone[nc++] = points[2];}
468             else if (cone[nc-1] == points[2]) {cone[nc++] = points[1]; if (cone[0] != points[0]) cone[nc++] = points[0];}
469             else if (cone[nc-3] == points[0]) {tmp = cone[nc-3]; cone[nc-3] = cone[nc-1]; cone[nc-1] = tmp; cone[nc++] = points[1]; if (cone[0] != points[2]) cone[nc++] = points[2];}
470             else if (cone[nc-3] == points[2]) {tmp = cone[nc-3]; cone[nc-3] = cone[nc-1]; cone[nc-1] = tmp; cone[nc++] = points[1]; if (cone[0] != points[0]) cone[nc++] = points[0];}
471             else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %d does not match its predecessor", eid);
472           }
473         }
474         PetscCheck(nc == 2*Ner,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of corners %" PetscInt_FMT " != %" PetscInt_FMT, nc, 2*Ner);
475         if (Ner == 4) {cone[nc++] = numVertices - newVertices + numEdges + numQuads++;}
476         PetscCheck(nc <= maxCorners,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of corners %" PetscInt_FMT " > %" PetscInt_FMT " max", nc, maxCorners);
477         /* Triangulate the loop */
478         switch (Ner) {
479           case 2: /* Bi-Segment -> 2 triangles */
480             Nt = 2;
481             cells[cOff*numCorners+0] = cone[0];
482             cells[cOff*numCorners+1] = cone[1];
483             cells[cOff*numCorners+2] = cone[2];
484             ++cOff;
485             cells[cOff*numCorners+0] = cone[0];
486             cells[cOff*numCorners+1] = cone[2];
487             cells[cOff*numCorners+2] = cone[3];
488             ++cOff;
489             break;
490           case 3: /* Triangle   -> 4 triangles */
491             Nt = 4;
492             cells[cOff*numCorners+0] = cone[0];
493             cells[cOff*numCorners+1] = cone[1];
494             cells[cOff*numCorners+2] = cone[5];
495             ++cOff;
496             cells[cOff*numCorners+0] = cone[1];
497             cells[cOff*numCorners+1] = cone[2];
498             cells[cOff*numCorners+2] = cone[3];
499             ++cOff;
500             cells[cOff*numCorners+0] = cone[5];
501             cells[cOff*numCorners+1] = cone[3];
502             cells[cOff*numCorners+2] = cone[4];
503             ++cOff;
504             cells[cOff*numCorners+0] = cone[1];
505             cells[cOff*numCorners+1] = cone[3];
506             cells[cOff*numCorners+2] = cone[5];
507             ++cOff;
508             break;
509           case 4: /* Quad       -> 8 triangles */
510             Nt = 8;
511             cells[cOff*numCorners+0] = cone[0];
512             cells[cOff*numCorners+1] = cone[1];
513             cells[cOff*numCorners+2] = cone[7];
514             ++cOff;
515             cells[cOff*numCorners+0] = cone[1];
516             cells[cOff*numCorners+1] = cone[2];
517             cells[cOff*numCorners+2] = cone[3];
518             ++cOff;
519             cells[cOff*numCorners+0] = cone[3];
520             cells[cOff*numCorners+1] = cone[4];
521             cells[cOff*numCorners+2] = cone[5];
522             ++cOff;
523             cells[cOff*numCorners+0] = cone[5];
524             cells[cOff*numCorners+1] = cone[6];
525             cells[cOff*numCorners+2] = cone[7];
526             ++cOff;
527             cells[cOff*numCorners+0] = cone[8];
528             cells[cOff*numCorners+1] = cone[1];
529             cells[cOff*numCorners+2] = cone[3];
530             ++cOff;
531             cells[cOff*numCorners+0] = cone[8];
532             cells[cOff*numCorners+1] = cone[3];
533             cells[cOff*numCorners+2] = cone[5];
534             ++cOff;
535             cells[cOff*numCorners+0] = cone[8];
536             cells[cOff*numCorners+1] = cone[5];
537             cells[cOff*numCorners+2] = cone[7];
538             ++cOff;
539             cells[cOff*numCorners+0] = cone[8];
540             cells[cOff*numCorners+1] = cone[7];
541             cells[cOff*numCorners+2] = cone[1];
542             ++cOff;
543             break;
544           default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %d has %d edges, which we do not support", lid, Ner);
545         }
546         if (debug) {
547           for (t = 0; t < Nt; ++t) {
548             PetscCall(PetscPrintf(PETSC_COMM_SELF, "  LOOP Corner NODEs Triangle %" PetscInt_FMT " (", t));
549             for (c = 0; c < numCorners; ++c) {
550               if (c > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
551               PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT, cells[(cOff-Nt+t)*numCorners+c]));
552             }
553             PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
554           }
555         }
556       }
557       EG_free(lobjs);
558     }
559   }
560   PetscCheck(cOff == numCells,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Count of total cells %" PetscInt_FMT " != %" PetscInt_FMT " previous count", cOff, numCells);
561   PetscCall(DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, numCells, numVertices, numCorners, PETSC_TRUE, cells, cdim, coords, &dm));
562   PetscCall(PetscFree3(coords, cells, cone));
563   PetscCall(PetscInfo(dm, " Total Number of Unique Cells    = %" PetscInt_FMT " (%" PetscInt_FMT ")\n", numCells, newCells));
564   PetscCall(PetscInfo(dm, " Total Number of Unique Vertices = %" PetscInt_FMT " (%" PetscInt_FMT ")\n", numVertices, newVertices));
565   /* Embed EGADS model in DM */
566   {
567     PetscContainer modelObj, contextObj;
568 
569     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &modelObj));
570     PetscCall(PetscContainerSetPointer(modelObj, model));
571     PetscCall(PetscObjectCompose((PetscObject) dm, "EGADS Model", (PetscObject) modelObj));
572     PetscCall(PetscContainerDestroy(&modelObj));
573 
574     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &contextObj));
575     PetscCall(PetscContainerSetPointer(contextObj, context));
576     PetscCall(PetscContainerSetUserDestroy(contextObj, DMPlexEGADSDestroy_Private));
577     PetscCall(PetscObjectCompose((PetscObject) dm, "EGADS Context", (PetscObject) contextObj));
578     PetscCall(PetscContainerDestroy(&contextObj));
579   }
580   /* Label points */
581   PetscCall(DMCreateLabel(dm, "EGADS Body ID"));
582   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
583   PetscCall(DMCreateLabel(dm, "EGADS Face ID"));
584   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
585   PetscCall(DMCreateLabel(dm, "EGADS Edge ID"));
586   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
587   PetscCall(DMCreateLabel(dm, "EGADS Vertex ID"));
588   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
589   cOff = 0;
590   for (b = 0; b < nbodies; ++b) {
591     ego body = bodies[b];
592     int id, Nl, l;
593 
594     PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
595     for (l = 0; l < Nl; ++l) {
596       ego  loop = lobjs[l];
597       ego *fobjs;
598       int  lid, Nf, fid, Ner = 0, Ne, e, Nt = 0, t;
599 
600       lid  = EG_indexBodyTopo(body, loop);
601       PetscCall(EG_getBodyTopos(body, loop, FACE, &Nf, &fobjs));
602       PetscCheck(Nf <= 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %d has %d > 1 faces, which is not supported", lid, Nf);
603       fid  = EG_indexBodyTopo(body, fobjs[0]);
604       EG_free(fobjs);
605       PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
606       for (e = 0; e < Ne; ++e) {
607         ego             edge = objs[e];
608         int             eid, Nv, v;
609         PetscInt        points[3], support[2], numEdges, edgeNum;
610         const PetscInt *edges;
611 
612         eid = EG_indexBodyTopo(body, edge);
613         PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
614         if (mtype == DEGENERATE) continue;
615         else                     ++Ner;
616         for (v = 0; v < Nv; ++v) {
617           ego vertex = nobjs[v];
618 
619           id   = EG_indexBodyTopo(body, vertex);
620           PetscCall(DMLabelSetValue(edgeLabel, numCells + id-1, eid));
621           points[v*2] = numCells + id-1;
622         }
623         PetscCall(PetscHMapIGet(edgeMap, eid-1, &edgeNum));
624         points[1] = numCells + numVertices - newVertices + edgeNum;
625 
626         PetscCall(DMLabelSetValue(edgeLabel, points[1], eid));
627         support[0] = points[0];
628         support[1] = points[1];
629         PetscCall(DMPlexGetJoin(dm, 2, support, &numEdges, &edges));
630         PetscCheck(numEdges == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Vertices (%" PetscInt_FMT ", %" PetscInt_FMT ") should only bound 1 edge, not %" PetscInt_FMT, support[0], support[1], numEdges);
631         PetscCall(DMLabelSetValue(edgeLabel, edges[0], eid));
632         PetscCall(DMPlexRestoreJoin(dm, 2, support, &numEdges, &edges));
633         support[0] = points[1];
634         support[1] = points[2];
635         PetscCall(DMPlexGetJoin(dm, 2, support, &numEdges, &edges));
636         PetscCheck(numEdges == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Vertices (%" PetscInt_FMT ", %" PetscInt_FMT ") should only bound 1 edge, not %" PetscInt_FMT, support[0], support[1], numEdges);
637         PetscCall(DMLabelSetValue(edgeLabel, edges[0], eid));
638         PetscCall(DMPlexRestoreJoin(dm, 2, support, &numEdges, &edges));
639       }
640       switch (Ner) {
641         case 2: Nt = 2;break;
642         case 3: Nt = 4;break;
643         case 4: Nt = 8;break;
644         default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Loop with %d edges is unsupported", Ner);
645       }
646       for (t = 0; t < Nt; ++t) {
647         PetscCall(DMLabelSetValue(bodyLabel, cOff+t, b));
648         PetscCall(DMLabelSetValue(faceLabel, cOff+t, fid));
649       }
650       cOff += Nt;
651     }
652     EG_free(lobjs);
653   }
654   PetscCall(PetscHMapIDestroy(&edgeMap));
655   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
656   for (c = cStart; c < cEnd; ++c) {
657     PetscInt *closure = NULL;
658     PetscInt  clSize, cl, bval, fval;
659 
660     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
661     PetscCall(DMLabelGetValue(bodyLabel, c, &bval));
662     PetscCall(DMLabelGetValue(faceLabel, c, &fval));
663     for (cl = 0; cl < clSize*2; cl += 2) {
664       PetscCall(DMLabelSetValue(bodyLabel, closure[cl], bval));
665       PetscCall(DMLabelSetValue(faceLabel, closure[cl], fval));
666     }
667     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
668   }
669   *newdm = dm;
670   PetscFunctionReturn(0);
671 }
672 
673 static PetscErrorCode DMPlexCreateEGADS(MPI_Comm comm, ego context, ego model, DM *newdm)
674 {
675   DMLabel         bodyLabel, faceLabel, edgeLabel, vertexLabel;
676   // EGADS/EGADSLite variables
677   ego             geom, *bodies, *mobjs, *fobjs, *lobjs, *eobjs, *nobjs;
678   ego             topRef, prev, next;
679   int             oclass, mtype, nbodies, *senses, *lSenses, *eSenses;
680   int             b;
681   // PETSc variables
682   DM              dm;
683   PetscHMapI      edgeMap = NULL, bodyIndexMap = NULL, bodyVertexMap = NULL, bodyEdgeMap = NULL, bodyFaceMap = NULL, bodyEdgeGlobalMap = NULL;
684   PetscInt        dim = -1, cdim = -1, numCorners = 0, numVertices = 0, numEdges = 0, numFaces = 0, numCells = 0, edgeCntr = 0;
685   PetscInt        cellCntr = 0, numPoints = 0;
686   PetscInt        *cells  = NULL;
687   const PetscInt  *cone = NULL;
688   PetscReal       *coords = NULL;
689   PetscMPIInt      rank;
690 
691   PetscFunctionBeginUser;
692   PetscCallMPI(MPI_Comm_rank(comm, &rank));
693   if (rank == 0) {
694     // ---------------------------------------------------------------------------------------------------
695     // Generate Petsc Plex
696     //  Get all Nodes in model, record coordinates in a correctly formatted array
697     //  Cycle through bodies, cycle through loops, recorde NODE IDs in a correctly formatted array
698     //  We need to uniformly refine the initial geometry to guarantee a valid mesh
699 
700   // Caluculate cell and vertex sizes
701   PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
702 
703     PetscCall(PetscHMapICreate(&edgeMap));
704   PetscCall(PetscHMapICreate(&bodyIndexMap));
705   PetscCall(PetscHMapICreate(&bodyVertexMap));
706   PetscCall(PetscHMapICreate(&bodyEdgeMap));
707   PetscCall(PetscHMapICreate(&bodyEdgeGlobalMap));
708   PetscCall(PetscHMapICreate(&bodyFaceMap));
709 
710   for (b = 0; b < nbodies; ++b) {
711       ego             body = bodies[b];
712     int             Nf, Ne, Nv;
713     PetscHashIter   BIiter, BViter, BEiter, BEGiter, BFiter, EMiter;
714     PetscBool       BIfound, BVfound, BEfound, BEGfound, BFfound, EMfound;
715 
716     PetscCall(PetscHMapIFind(bodyIndexMap, b, &BIiter, &BIfound));
717     PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
718     PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
719     PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
720     PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
721 
722     if (!BIfound)  PetscCall(PetscHMapISet(bodyIndexMap, b, numFaces + numEdges + numVertices));
723     if (!BVfound)  PetscCall(PetscHMapISet(bodyVertexMap, b, numVertices));
724     if (!BEfound)  PetscCall(PetscHMapISet(bodyEdgeMap, b, numEdges));
725     if (!BEGfound) PetscCall(PetscHMapISet(bodyEdgeGlobalMap, b, edgeCntr));
726     if (!BFfound)  PetscCall(PetscHMapISet(bodyFaceMap, b, numFaces));
727 
728     PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
729     PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
730     PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
731     EG_free(fobjs);
732     EG_free(eobjs);
733     EG_free(nobjs);
734 
735     // Remove DEGENERATE EDGES from Edge count
736     PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
737     int Netemp = 0;
738     for (int e = 0; e < Ne; ++e) {
739       ego     edge = eobjs[e];
740       int     eid;
741 
742       PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
743       eid = EG_indexBodyTopo(body, edge);
744 
745       PetscCall(PetscHMapIFind(edgeMap, edgeCntr + eid - 1, &EMiter, &EMfound));
746       if (mtype == DEGENERATE) {
747         if (!EMfound) PetscCall(PetscHMapISet(edgeMap, edgeCntr + eid - 1, -1));
748       }
749       else {
750       ++Netemp;
751         if (!EMfound) PetscCall(PetscHMapISet(edgeMap, edgeCntr + eid - 1, Netemp));
752       }
753     }
754     EG_free(eobjs);
755 
756     // Determine Number of Cells
757     PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
758     for (int f = 0; f < Nf; ++f) {
759         ego     face = fobjs[f];
760     int     edgeTemp = 0;
761 
762       PetscCall(EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
763       for (int e = 0; e < Ne; ++e) {
764         ego     edge = eobjs[e];
765 
766         PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
767         if (mtype != DEGENERATE) {++edgeTemp;}
768       }
769       numCells += (2 * edgeTemp);
770       EG_free(eobjs);
771     }
772     EG_free(fobjs);
773 
774     numFaces    += Nf;
775     numEdges    += Netemp;
776     numVertices += Nv;
777     edgeCntr    += Ne;
778   }
779 
780   // Set up basic DMPlex parameters
781   dim        = 2;    // Assumes 3D Models :: Need to handle 2D modles in the future
782   cdim       = 3;     // Assumes 3D Models :: Need to update to handle 2D modles in future
783   numCorners = 3;     // Split Faces into triangles
784     numPoints  = numVertices + numEdges + numFaces;   // total number of coordinate points
785 
786   PetscCall(PetscMalloc2(numPoints*cdim, &coords, numCells*numCorners, &cells));
787 
788   // Get Vertex Coordinates and Set up Cells
789   for (b = 0; b < nbodies; ++b) {
790     ego             body = bodies[b];
791     int             Nf, Ne, Nv;
792     PetscInt        bodyVertexIndexStart, bodyEdgeIndexStart, bodyEdgeGlobalIndexStart, bodyFaceIndexStart;
793     PetscHashIter   BViter, BEiter, BEGiter, BFiter, EMiter;
794     PetscBool       BVfound, BEfound, BEGfound, BFfound, EMfound;
795 
796     // Vertices on Current Body
797     PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
798 
799     PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
800     PetscCheck(BVfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyVertexMap", b);
801     PetscCall(PetscHMapIGet(bodyVertexMap, b, &bodyVertexIndexStart));
802 
803     for (int v = 0; v < Nv; ++v) {
804       ego    vertex = nobjs[v];
805     double limits[4];
806     int    id, dummy;
807 
808     PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
809     id = EG_indexBodyTopo(body, vertex);
810 
811     coords[(bodyVertexIndexStart + id - 1)*cdim + 0] = limits[0];
812     coords[(bodyVertexIndexStart + id - 1)*cdim + 1] = limits[1];
813     coords[(bodyVertexIndexStart + id - 1)*cdim + 2] = limits[2];
814     }
815     EG_free(nobjs);
816 
817     // Edge Midpoint Vertices on Current Body
818     PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
819 
820     PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
821     PetscCheck(BEfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyEdgeMap", b);
822     PetscCall(PetscHMapIGet(bodyEdgeMap, b, &bodyEdgeIndexStart));
823 
824     PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
825     PetscCheck(BEGfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyEdgeGlobalMap", b);
826     PetscCall(PetscHMapIGet(bodyEdgeGlobalMap, b, &bodyEdgeGlobalIndexStart));
827 
828     for (int e = 0; e < Ne; ++e) {
829       ego          edge = eobjs[e];
830     double       range[2], avgt[1], cntrPnt[9];
831     int          eid, eOffset;
832     int          periodic;
833 
834     PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
835     if (mtype == DEGENERATE) {continue;}
836 
837     eid = EG_indexBodyTopo(body, edge);
838 
839     // get relative offset from globalEdgeID Vector
840     PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
841       PetscCheck(EMfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Edge %d not found in edgeMap", bodyEdgeGlobalIndexStart + eid - 1);
842       PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
843 
844     PetscCall(EG_getRange(edge, range, &periodic));
845     avgt[0] = (range[0] + range[1]) /  2.;
846 
847     PetscCall(EG_evaluate(edge, avgt, cntrPnt));
848     coords[(numVertices + bodyEdgeIndexStart + eOffset - 1)*cdim + 0] = cntrPnt[0];
849         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1)*cdim + 1] = cntrPnt[1];
850     coords[(numVertices + bodyEdgeIndexStart + eOffset - 1)*cdim + 2] = cntrPnt[2];
851     }
852     EG_free(eobjs);
853 
854     // Face Midpoint Vertices on Current Body
855     PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
856 
857     PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
858     PetscCheck(BFfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyFaceMap", b);
859     PetscCall(PetscHMapIGet(bodyFaceMap, b, &bodyFaceIndexStart));
860 
861     for (int f = 0; f < Nf; ++f) {
862     ego       face = fobjs[f];
863     double    range[4], avgUV[2], cntrPnt[18];
864     int       peri, id;
865 
866     id = EG_indexBodyTopo(body, face);
867     PetscCall(EG_getRange(face, range, &peri));
868 
869     avgUV[0] = (range[0] + range[1]) / 2.;
870     avgUV[1] = (range[2] + range[3]) / 2.;
871     PetscCall(EG_evaluate(face, avgUV, cntrPnt));
872 
873     coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1)*cdim + 0] = cntrPnt[0];
874     coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1)*cdim + 1] = cntrPnt[1];
875     coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1)*cdim + 2] = cntrPnt[2];
876     }
877     EG_free(fobjs);
878 
879     // Define Cells :: Note - This could be incorporated in the Face Midpoint Vertices Loop but was kept separate for clarity
880     PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
881     for (int f = 0; f < Nf; ++f) {
882     ego      face = fobjs[f];
883     int      fID, midFaceID, midPntID, startID, endID, Nl;
884 
885     fID = EG_indexBodyTopo(body, face);
886     midFaceID = numVertices + numEdges + bodyFaceIndexStart + fID - 1;
887     // Must Traverse Loop to ensure we have all necessary information like the sense (+/- 1) of the edges.
888     // TODO :: Only handles single loop faces (No holes). The choices for handling multiloop faces are:
889     //            1) Use the DMPlexCreateEGADSFromFile() with the -dm_plex_egads_with_tess = 1 option.
890     //               This will use a default EGADS tessellation as an initial surface mesh.
891     //            2) Create the initial surface mesh via a 2D mesher :: Currently not availble (?future?)
892     //               May I suggest the XXXX as a starting point?
893 
894     PetscCall(EG_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lSenses));
895 
896       PetscCheck(Nl <= 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face has %d Loops. Can only handle Faces with 1 Loop. Please use --dm_plex_egads_with_tess = 1 Option", Nl);
897     for (int l = 0; l < Nl; ++l) {
898           ego      loop = lobjs[l];
899 
900           PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
901       for (int e = 0; e < Ne; ++e) {
902         ego     edge = eobjs[e];
903         int     eid, eOffset;
904 
905         PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
906       eid = EG_indexBodyTopo(body, edge);
907         if (mtype == DEGENERATE) { continue; }
908 
909         // get relative offset from globalEdgeID Vector
910         PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
911           PetscCheck(EMfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Edge %d of Body %d not found in edgeMap. Global Edge ID :: %d", eid, b, bodyEdgeGlobalIndexStart + eid - 1);
912           PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
913 
914       midPntID = numVertices + bodyEdgeIndexStart + eOffset - 1;
915 
916         PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
917 
918         if (eSenses[e] > 0) { startID = EG_indexBodyTopo(body, nobjs[0]); endID = EG_indexBodyTopo(body, nobjs[1]); }
919         else { startID = EG_indexBodyTopo(body, nobjs[1]); endID = EG_indexBodyTopo(body, nobjs[0]); }
920 
921       // Define 2 Cells per Edge with correct orientation
922       cells[cellCntr*numCorners + 0] = midFaceID;
923       cells[cellCntr*numCorners + 1] = bodyVertexIndexStart + startID - 1;
924       cells[cellCntr*numCorners + 2] = midPntID;
925 
926       cells[cellCntr*numCorners + 3] = midFaceID;
927       cells[cellCntr*numCorners + 4] = midPntID;
928       cells[cellCntr*numCorners + 5] = bodyVertexIndexStart + endID - 1;
929 
930       cellCntr = cellCntr + 2;
931       }
932     }
933     }
934     EG_free(fobjs);
935   }
936   }
937 
938   // Generate DMPlex
939   PetscCall(DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, numCells, numPoints, numCorners, PETSC_TRUE, cells, cdim, coords, &dm));
940   PetscCall(PetscFree2(coords, cells));
941   PetscCall(PetscInfo(dm, " Total Number of Unique Cells    = %" PetscInt_FMT " \n", numCells));
942   PetscCall(PetscInfo(dm, " Total Number of Unique Vertices = %" PetscInt_FMT " \n", numVertices));
943 
944   // Embed EGADS model in DM
945   {
946     PetscContainer modelObj, contextObj;
947 
948     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &modelObj));
949     PetscCall(PetscContainerSetPointer(modelObj, model));
950     PetscCall(PetscObjectCompose((PetscObject) dm, "EGADS Model", (PetscObject) modelObj));
951     PetscCall(PetscContainerDestroy(&modelObj));
952 
953     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &contextObj));
954     PetscCall(PetscContainerSetPointer(contextObj, context));
955     PetscCall(PetscContainerSetUserDestroy(contextObj, DMPlexEGADSDestroy_Private));
956     PetscCall(PetscObjectCompose((PetscObject) dm, "EGADS Context", (PetscObject) contextObj));
957     PetscCall(PetscContainerDestroy(&contextObj));
958   }
959   // Label points
960   PetscInt   nStart, nEnd;
961 
962   PetscCall(DMCreateLabel(dm, "EGADS Body ID"));
963   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
964   PetscCall(DMCreateLabel(dm, "EGADS Face ID"));
965   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
966   PetscCall(DMCreateLabel(dm, "EGADS Edge ID"));
967   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
968   PetscCall(DMCreateLabel(dm, "EGADS Vertex ID"));
969   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
970 
971   PetscCall(DMPlexGetHeightStratum(dm, 2, &nStart, &nEnd));
972 
973   cellCntr = 0;
974   for (b = 0; b < nbodies; ++b) {
975     ego             body = bodies[b];
976   int             Nv, Ne, Nf;
977   PetscInt        bodyVertexIndexStart, bodyEdgeIndexStart, bodyEdgeGlobalIndexStart, bodyFaceIndexStart;
978   PetscHashIter   BViter, BEiter, BEGiter, BFiter, EMiter;
979   PetscBool       BVfound, BEfound, BEGfound, BFfound, EMfound;
980 
981   PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
982   PetscCheck(BVfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyVertexMap", b);
983   PetscCall(PetscHMapIGet(bodyVertexMap, b, &bodyVertexIndexStart));
984 
985   PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
986   PetscCheck(BEfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyEdgeMap", b);
987   PetscCall(PetscHMapIGet(bodyEdgeMap, b, &bodyEdgeIndexStart));
988 
989     PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
990   PetscCheck(BFfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyFaceMap", b);
991   PetscCall(PetscHMapIGet(bodyFaceMap, b, &bodyFaceIndexStart));
992 
993     PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
994     PetscCheck(BEGfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyEdgeGlobalMap", b);
995     PetscCall(PetscHMapIGet(bodyEdgeGlobalMap, b, &bodyEdgeGlobalIndexStart));
996 
997   PetscCall(EG_getBodyTopos(body, NULL, FACE,  &Nf, &fobjs));
998   for (int f = 0; f < Nf; ++f) {
999     ego   face = fobjs[f];
1000       int   fID, Nl;
1001 
1002     fID  = EG_indexBodyTopo(body, face);
1003 
1004     PetscCall(EG_getBodyTopos(body, face, LOOP, &Nl, &lobjs));
1005     for (int l = 0; l < Nl; ++l) {
1006         ego  loop = lobjs[l];
1007     int  lid;
1008 
1009     lid  = EG_indexBodyTopo(body, loop);
1010       PetscCheck(Nl <= 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %d has %d > 1 faces, which is not supported", lid, Nf);
1011 
1012     PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
1013     for (int e = 0; e < Ne; ++e) {
1014       ego     edge = eobjs[e];
1015       int     eid, eOffset;
1016 
1017       // Skip DEGENERATE Edges
1018       PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1019       if (mtype == DEGENERATE) {continue;}
1020       eid = EG_indexBodyTopo(body, edge);
1021 
1022       // get relative offset from globalEdgeID Vector
1023       PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
1024       PetscCheck(EMfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Edge %d of Body %d not found in edgeMap. Global Edge ID :: %d", eid, b, bodyEdgeGlobalIndexStart + eid - 1);
1025       PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
1026 
1027       PetscCall(EG_getBodyTopos(body, edge, NODE, &Nv, &nobjs));
1028       for (int v = 0; v < Nv; ++v){
1029         ego vertex = nobjs[v];
1030         int vID;
1031 
1032         vID = EG_indexBodyTopo(body, vertex);
1033         PetscCall(DMLabelSetValue(bodyLabel, nStart + bodyVertexIndexStart + vID - 1, b));
1034         PetscCall(DMLabelSetValue(vertexLabel, nStart + bodyVertexIndexStart + vID - 1, vID));
1035       }
1036       EG_free(nobjs);
1037 
1038       PetscCall(DMLabelSetValue(bodyLabel, nStart + numVertices + bodyEdgeIndexStart + eOffset - 1, b));
1039       PetscCall(DMLabelSetValue(edgeLabel, nStart + numVertices + bodyEdgeIndexStart + eOffset - 1, eid));
1040 
1041       // Define Cell faces
1042       for (int jj = 0; jj < 2; ++jj){
1043         PetscCall(DMLabelSetValue(bodyLabel, cellCntr, b));
1044         PetscCall(DMLabelSetValue(faceLabel, cellCntr, fID));
1045         PetscCall(DMPlexGetCone(dm, cellCntr, &cone));
1046 
1047         PetscCall(DMLabelSetValue(bodyLabel, cone[0], b));
1048         PetscCall(DMLabelSetValue(faceLabel, cone[0], fID));
1049 
1050         PetscCall(DMLabelSetValue(bodyLabel, cone[1], b));
1051         PetscCall(DMLabelSetValue(edgeLabel, cone[1], eid));
1052 
1053        PetscCall(DMLabelSetValue(bodyLabel, cone[2], b));
1054        PetscCall(DMLabelSetValue(faceLabel, cone[2], fID));
1055 
1056        cellCntr = cellCntr + 1;
1057       }
1058     }
1059     }
1060     EG_free(lobjs);
1061 
1062     PetscCall(DMLabelSetValue(bodyLabel, nStart + numVertices + numEdges + bodyFaceIndexStart + fID - 1, b));
1063     PetscCall(DMLabelSetValue(faceLabel, nStart + numVertices + numEdges + bodyFaceIndexStart + fID - 1, fID));
1064   }
1065   EG_free(fobjs);
1066   }
1067 
1068   PetscCall(PetscHMapIDestroy(&edgeMap));
1069   PetscCall(PetscHMapIDestroy(&bodyIndexMap));
1070   PetscCall(PetscHMapIDestroy(&bodyVertexMap));
1071   PetscCall(PetscHMapIDestroy(&bodyEdgeMap));
1072   PetscCall(PetscHMapIDestroy(&bodyEdgeGlobalMap));
1073   PetscCall(PetscHMapIDestroy(&bodyFaceMap));
1074 
1075   *newdm = dm;
1076   PetscFunctionReturn(0);
1077 }
1078 
1079 static PetscErrorCode DMPlexCreateEGADS_Tess_Internal(MPI_Comm comm, ego context, ego model, DM *newdm)
1080 {
1081   DMLabel              bodyLabel, faceLabel, edgeLabel, vertexLabel;
1082   /* EGADSLite variables */
1083   ego                  geom, *bodies, *fobjs;
1084   int                  b, oclass, mtype, nbodies, *senses;
1085   int                  totalNumTris = 0, totalNumPoints = 0;
1086   double               boundBox[6] = {0., 0., 0., 0., 0., 0.}, tessSize;
1087   /* PETSc variables */
1088   DM                   dm;
1089   PetscHMapI           pointIndexStartMap = NULL, triIndexStartMap = NULL, pTypeLabelMap = NULL, pIndexLabelMap = NULL;
1090   PetscHMapI           pBodyIndexLabelMap = NULL, triFaceIDLabelMap = NULL, triBodyIDLabelMap = NULL;
1091   PetscInt             dim = -1, cdim = -1, numCorners = 0, counter = 0;
1092   PetscInt            *cells  = NULL;
1093   const PetscInt      *cone = NULL;
1094   PetscReal           *coords = NULL;
1095   PetscMPIInt          rank;
1096 
1097   PetscFunctionBeginUser;
1098   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1099   if (rank == 0) {
1100     // ---------------------------------------------------------------------------------------------------
1101     // Generate Petsc Plex from EGADSlite created Tessellation of geometry
1102     // ---------------------------------------------------------------------------------------------------
1103 
1104   // Caluculate cell and vertex sizes
1105   PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
1106 
1107   PetscCall(PetscHMapICreate(&pointIndexStartMap));
1108   PetscCall(PetscHMapICreate(&triIndexStartMap));
1109   PetscCall(PetscHMapICreate(&pTypeLabelMap));
1110   PetscCall(PetscHMapICreate(&pIndexLabelMap));
1111   PetscCall(PetscHMapICreate(&pBodyIndexLabelMap));
1112   PetscCall(PetscHMapICreate(&triFaceIDLabelMap));
1113   PetscCall(PetscHMapICreate(&triBodyIDLabelMap));
1114 
1115   /* Create Tessellation of Bodies */
1116   ego tessArray[nbodies];
1117 
1118   for (b = 0; b < nbodies; ++b) {
1119     ego             body = bodies[b];
1120     double          params[3] = {0.0, 0.0, 0.0};    // Parameters for Tessellation
1121     int             Nf, bodyNumPoints = 0, bodyNumTris = 0;
1122     PetscHashIter   PISiter, TISiter;
1123     PetscBool       PISfound, TISfound;
1124 
1125     /* Store Start Index for each Body's Point and Tris */
1126     PetscCall(PetscHMapIFind(pointIndexStartMap, b, &PISiter, &PISfound));
1127     PetscCall(PetscHMapIFind(triIndexStartMap, b, &TISiter, &TISfound));
1128 
1129     if (!PISfound)  PetscCall(PetscHMapISet(pointIndexStartMap, b, totalNumPoints));
1130     if (!TISfound)  PetscCall(PetscHMapISet(triIndexStartMap, b, totalNumTris));
1131 
1132     /* Calculate Tessellation parameters based on Bounding Box */
1133     /* Get Bounding Box Dimensions of the BODY */
1134     PetscCall(EG_getBoundingBox(body, boundBox));
1135     tessSize = boundBox[3] - boundBox[0];
1136     if (tessSize < boundBox[4] - boundBox[1]) tessSize = boundBox[4] - boundBox[1];
1137     if (tessSize < boundBox[5] - boundBox[2]) tessSize = boundBox[5] - boundBox[2];
1138 
1139     // TODO :: May want to give users tessellation parameter options //
1140     params[0] = 0.0250 * tessSize;
1141     params[1] = 0.0075 * tessSize;
1142     params[2] = 15.0;
1143 
1144     PetscCall(EG_makeTessBody(body, params, &tessArray[b]));
1145 
1146     PetscCall(EG_getBodyTopos(body, NULL, FACE,  &Nf, &fobjs));
1147 
1148     for (int f = 0; f < Nf; ++f) {
1149       ego             face = fobjs[f];
1150     int             len, fID, ntris;
1151     const int      *ptype, *pindex, *ptris, *ptric;
1152     const double   *pxyz, *puv;
1153 
1154     // Get Face ID //
1155     fID = EG_indexBodyTopo(body, face);
1156 
1157     // Checkout the Surface Tessellation //
1158     PetscCall(EG_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
1159 
1160     // Determine total number of triangle cells in the tessellation //
1161     bodyNumTris += (int) ntris;
1162 
1163     // Check out the point index and coordinate //
1164     for (int p = 0; p < len; ++p) {
1165         int global;
1166 
1167         PetscCall(EG_localToGlobal(tessArray[b], fID, p+1, &global));
1168 
1169       // Determine the total number of points in the tessellation //
1170         bodyNumPoints = PetscMax(bodyNumPoints, global);
1171     }
1172     }
1173     EG_free(fobjs);
1174 
1175     totalNumPoints += bodyNumPoints;
1176     totalNumTris += bodyNumTris;
1177     }
1178   //}  - Original End of (rank == 0)
1179 
1180   dim = 2;
1181   cdim = 3;
1182   numCorners = 3;
1183   //PetscInt counter = 0;
1184 
1185   /* NEED TO DEFINE MATRICES/VECTORS TO STORE GEOM REFERENCE DATA   */
1186   /* Fill in below and use to define DMLabels after DMPlex creation */
1187   PetscCall(PetscMalloc2(totalNumPoints*cdim, &coords, totalNumTris*numCorners, &cells));
1188 
1189   for (b = 0; b < nbodies; ++b) {
1190   ego             body = bodies[b];
1191   int             Nf;
1192   PetscInt        pointIndexStart;
1193   PetscHashIter   PISiter;
1194   PetscBool       PISfound;
1195 
1196   PetscCall(PetscHMapIFind(pointIndexStartMap, b, &PISiter, &PISfound));
1197   PetscCheck(PISfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in pointIndexStartMap", b);
1198   PetscCall(PetscHMapIGet(pointIndexStartMap, b, &pointIndexStart));
1199 
1200   PetscCall(EG_getBodyTopos(body, NULL, FACE,  &Nf, &fobjs));
1201 
1202   for (int f = 0; f < Nf; ++f) {
1203     /* Get Face Object */
1204     ego              face = fobjs[f];
1205     int              len, fID, ntris;
1206     const int       *ptype, *pindex, *ptris, *ptric;
1207     const double    *pxyz, *puv;
1208 
1209     /* Get Face ID */
1210     fID = EG_indexBodyTopo(body, face);
1211 
1212     /* Checkout the Surface Tessellation */
1213     PetscCall(EG_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
1214 
1215     /* Check out the point index and coordinate */
1216     for (int p = 0; p < len; ++p) {
1217     int              global;
1218     PetscHashIter    PTLiter, PILiter, PBLiter;
1219     PetscBool        PTLfound, PILfound, PBLfound;
1220 
1221     PetscCall(EG_localToGlobal(tessArray[b], fID, p+1, &global));
1222 
1223     /* Set the coordinates array for DAG */
1224     coords[((global-1+pointIndexStart)*3) + 0] = pxyz[(p*3)+0];
1225     coords[((global-1+pointIndexStart)*3) + 1] = pxyz[(p*3)+1];
1226     coords[((global-1+pointIndexStart)*3) + 2] = pxyz[(p*3)+2];
1227 
1228     /* Store Geometry Label Information for DMLabel assignment later */
1229     PetscCall(PetscHMapIFind(pTypeLabelMap, global-1+pointIndexStart, &PTLiter, &PTLfound));
1230     PetscCall(PetscHMapIFind(pIndexLabelMap, global-1+pointIndexStart, &PILiter, &PILfound));
1231     PetscCall(PetscHMapIFind(pBodyIndexLabelMap, global-1+pointIndexStart, &PBLiter, &PBLfound));
1232 
1233     if (!PTLfound) PetscCall(PetscHMapISet(pTypeLabelMap, global-1+pointIndexStart, ptype[p]));
1234     if (!PILfound) PetscCall(PetscHMapISet(pIndexLabelMap, global-1+pointIndexStart, pindex[p]));
1235     if (!PBLfound) PetscCall(PetscHMapISet(pBodyIndexLabelMap, global-1+pointIndexStart, b));
1236 
1237     if (ptype[p] < 0) PetscCall(PetscHMapISet(pIndexLabelMap, global-1+pointIndexStart, fID));
1238     }
1239 
1240     for (int t = 0; t < (int) ntris; ++t){
1241     int           global, globalA, globalB;
1242     PetscHashIter TFLiter, TBLiter;
1243     PetscBool     TFLfound, TBLfound;
1244 
1245     PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t*3) + 0], &global));
1246     cells[(counter*3) +0] = global-1+pointIndexStart;
1247 
1248     PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t*3) + 1], &globalA));
1249     cells[(counter*3) +1] = globalA-1+pointIndexStart;
1250 
1251     PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t*3) + 2], &globalB));
1252     cells[(counter*3) +2] = globalB-1+pointIndexStart;
1253 
1254     PetscCall(PetscHMapIFind(triFaceIDLabelMap, counter, &TFLiter, &TFLfound));
1255         PetscCall(PetscHMapIFind(triBodyIDLabelMap, counter, &TBLiter, &TBLfound));
1256 
1257     if (!TFLfound)  PetscCall(PetscHMapISet(triFaceIDLabelMap, counter, fID));
1258         if (!TBLfound)  PetscCall(PetscHMapISet(triBodyIDLabelMap, counter, b));
1259 
1260     counter += 1;
1261     }
1262   }
1263   EG_free(fobjs);
1264   }
1265 }
1266 
1267   //Build DMPlex
1268   PetscCall(DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, totalNumTris, totalNumPoints, numCorners, PETSC_TRUE, cells, cdim, coords, &dm));
1269   PetscCall(PetscFree2(coords, cells));
1270 
1271   // Embed EGADS model in DM
1272   {
1273     PetscContainer modelObj, contextObj;
1274 
1275     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &modelObj));
1276     PetscCall(PetscContainerSetPointer(modelObj, model));
1277     PetscCall(PetscObjectCompose((PetscObject) dm, "EGADS Model", (PetscObject) modelObj));
1278     PetscCall(PetscContainerDestroy(&modelObj));
1279 
1280     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &contextObj));
1281     PetscCall(PetscContainerSetPointer(contextObj, context));
1282     PetscCall(PetscContainerSetUserDestroy(contextObj, DMPlexEGADSDestroy_Private));
1283     PetscCall(PetscObjectCompose((PetscObject) dm, "EGADS Context", (PetscObject) contextObj));
1284     PetscCall(PetscContainerDestroy(&contextObj));
1285   }
1286 
1287   // Label Points
1288   PetscCall(DMCreateLabel(dm, "EGADS Body ID"));
1289   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
1290   PetscCall(DMCreateLabel(dm, "EGADS Face ID"));
1291   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
1292   PetscCall(DMCreateLabel(dm, "EGADS Edge ID"));
1293   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
1294   PetscCall(DMCreateLabel(dm, "EGADS Vertex ID"));
1295   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
1296 
1297    /* Get Number of DAG Nodes at each level */
1298   int   fStart, fEnd, eStart, eEnd, nStart, nEnd;
1299 
1300   PetscCall(DMPlexGetHeightStratum(dm, 0, &fStart, &fEnd));
1301   PetscCall(DMPlexGetHeightStratum(dm, 1, &eStart, &eEnd));
1302   PetscCall(DMPlexGetHeightStratum(dm, 2, &nStart, &nEnd));
1303 
1304   /* Set DMLabels for NODES */
1305   for (int n = nStart; n < nEnd; ++n) {
1306     int             pTypeVal, pIndexVal, pBodyVal;
1307     PetscHashIter   PTLiter, PILiter, PBLiter;
1308     PetscBool       PTLfound, PILfound, PBLfound;
1309 
1310     //Converted to Hash Tables
1311     PetscCall(PetscHMapIFind(pTypeLabelMap, n - nStart, &PTLiter, &PTLfound));
1312     PetscCheck(PTLfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %d not found in pTypeLabelMap", n);
1313     PetscCall(PetscHMapIGet(pTypeLabelMap, n - nStart, &pTypeVal));
1314 
1315     PetscCall(PetscHMapIFind(pIndexLabelMap, n - nStart, &PILiter, &PILfound));
1316     PetscCheck(PILfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %d not found in pIndexLabelMap", n);
1317     PetscCall(PetscHMapIGet(pIndexLabelMap, n - nStart, &pIndexVal));
1318 
1319     PetscCall(PetscHMapIFind(pBodyIndexLabelMap, n - nStart, &PBLiter, &PBLfound));
1320     PetscCheck(PBLfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %d not found in pBodyLabelMap", n);
1321     PetscCall(PetscHMapIGet(pBodyIndexLabelMap, n - nStart, &pBodyVal));
1322 
1323     PetscCall(DMLabelSetValue(bodyLabel, n, pBodyVal));
1324     if (pTypeVal == 0) PetscCall(DMLabelSetValue(vertexLabel, n, pIndexVal));
1325     if (pTypeVal >  0) PetscCall(DMLabelSetValue(edgeLabel, n, pIndexVal));
1326     if (pTypeVal <  0) PetscCall(DMLabelSetValue(faceLabel, n, pIndexVal));
1327   }
1328 
1329   /* Set DMLabels for Edges - Based on the DMLabels of the EDGE's NODES */
1330   for (int e = eStart; e < eEnd; ++e) {
1331   int    bodyID_0, vertexID_0, vertexID_1, edgeID_0, edgeID_1, faceID_0, faceID_1;
1332 
1333   PetscCall(DMPlexGetCone(dm, e, &cone));
1334   PetscCall(DMLabelGetValue(bodyLabel, cone[0], &bodyID_0));    // Do I need to check the other end?
1335   PetscCall(DMLabelGetValue(vertexLabel, cone[0], &vertexID_0));
1336   PetscCall(DMLabelGetValue(vertexLabel, cone[1], &vertexID_1));
1337   PetscCall(DMLabelGetValue(edgeLabel, cone[0], &edgeID_0));
1338   PetscCall(DMLabelGetValue(edgeLabel, cone[1], &edgeID_1));
1339   PetscCall(DMLabelGetValue(faceLabel, cone[0], &faceID_0));
1340   PetscCall(DMLabelGetValue(faceLabel, cone[1], &faceID_1));
1341 
1342   PetscCall(DMLabelSetValue(bodyLabel, e, bodyID_0));
1343 
1344   if (edgeID_0 == edgeID_1) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_0));
1345   else if (vertexID_0 > 0 && edgeID_1 > 0) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_1));
1346   else if (vertexID_1 > 0 && edgeID_0 > 0) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_0));
1347   else { /* Do Nothing */ }
1348   }
1349 
1350   /* Set DMLabels for Cells */
1351   for (int f = fStart; f < fEnd; ++f){
1352   int             edgeID_0;
1353   PetscInt        triBodyVal, triFaceVal;
1354   PetscHashIter   TFLiter, TBLiter;
1355   PetscBool       TFLfound, TBLfound;
1356 
1357     // Convert to Hash Table
1358   PetscCall(PetscHMapIFind(triFaceIDLabelMap, f - fStart, &TFLiter, &TFLfound));
1359   PetscCheck(TFLfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %d not found in triFaceIDLabelMap", f);
1360   PetscCall(PetscHMapIGet(triFaceIDLabelMap, f - fStart, &triFaceVal));
1361 
1362   PetscCall(PetscHMapIFind(triBodyIDLabelMap, f - fStart, &TBLiter, &TBLfound));
1363   PetscCheck(TBLfound,PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %d not found in triBodyIDLabelMap", f);
1364     PetscCall(PetscHMapIGet(triBodyIDLabelMap, f - fStart, &triBodyVal));
1365 
1366   PetscCall(DMLabelSetValue(bodyLabel, f, triBodyVal));
1367   PetscCall(DMLabelSetValue(faceLabel, f, triFaceVal));
1368 
1369   /* Finish Labeling previously unlabeled DMPlex Edges - Assumes Triangular Cell (3 Edges Max) */
1370   PetscCall(DMPlexGetCone(dm, f, &cone));
1371 
1372   for (int jj = 0; jj < 3; ++jj) {
1373     PetscCall(DMLabelGetValue(edgeLabel, cone[jj], &edgeID_0));
1374 
1375     if (edgeID_0 < 0) {
1376     PetscCall(DMLabelSetValue(bodyLabel, cone[jj], triBodyVal));
1377       PetscCall(DMLabelSetValue(faceLabel, cone[jj], triFaceVal));
1378     }
1379   }
1380   }
1381 
1382   *newdm = dm;
1383   PetscFunctionReturn(0);
1384 }
1385 #endif
1386 
1387 /*@
1388   DMPlexInflateToGeomModel - Snaps the vertex coordinates of a DMPlex object representing the mesh to its geometry if some vertices depart from the model. This usually happens with non-conforming refinement.
1389 
1390   Collective on dm
1391 
1392   Input Parameter:
1393 . dm - The uninflated DM object representing the mesh
1394 
1395   Output Parameter:
1396 . dm - The inflated DM object representing the mesh
1397 
1398   Level: intermediate
1399 
1400 .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateEGADS()`
1401 @*/
1402 PetscErrorCode DMPlexInflateToGeomModel(DM dm)
1403 {
1404 #if defined(PETSC_HAVE_EGADS)
1405   /* EGADS Variables */
1406   ego            model, geom, body, face, edge;
1407   ego           *bodies;
1408   int            Nb, oclass, mtype, *senses;
1409   double         result[3];
1410   /* PETSc Variables */
1411   DM             cdm;
1412   PetscContainer modelObj;
1413   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
1414   Vec            coordinates;
1415   PetscScalar   *coords;
1416   PetscInt       bodyID, faceID, edgeID, vertexID;
1417   PetscInt       cdim, d, vStart, vEnd, v;
1418 #endif
1419 
1420   PetscFunctionBegin;
1421 #if defined(PETSC_HAVE_EGADS)
1422   PetscCall(PetscObjectQuery((PetscObject) dm, "EGADS Model", (PetscObject *) &modelObj));
1423   if (!modelObj) PetscFunctionReturn(0);
1424   PetscCall(DMGetCoordinateDim(dm, &cdim));
1425   PetscCall(DMGetCoordinateDM(dm, &cdm));
1426   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1427   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
1428   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
1429   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
1430   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
1431 
1432   PetscCall(PetscContainerGetPointer(modelObj, (void **) &model));
1433   PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
1434 
1435   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1436   PetscCall(VecGetArrayWrite(coordinates, &coords));
1437   for (v = vStart; v < vEnd; ++v) {
1438     PetscScalar *vcoords;
1439 
1440     PetscCall(DMLabelGetValue(bodyLabel, v, &bodyID));
1441     PetscCall(DMLabelGetValue(faceLabel, v, &faceID));
1442     PetscCall(DMLabelGetValue(edgeLabel, v, &edgeID));
1443     PetscCall(DMLabelGetValue(vertexLabel, v, &vertexID));
1444 
1445     PetscCheck(bodyID < Nb,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Body %" PetscInt_FMT " is not in [0, %d)", bodyID, Nb);
1446     body = bodies[bodyID];
1447 
1448     PetscCall(DMPlexPointLocalRef(cdm, v, coords, (void *) &vcoords));
1449     if (edgeID > 0) {
1450       /* Snap to EDGE at nearest location */
1451       double params[1];
1452       PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &edge));
1453       PetscCall(EG_invEvaluate(edge, vcoords, params, result)); // Get (x,y,z) of nearest point on EDGE
1454       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
1455     } else if (faceID > 0) {
1456       /* Snap to FACE at nearest location */
1457       double params[2];
1458       PetscCall(EG_objectBodyTopo(body, FACE, faceID, &face));
1459       PetscCall(EG_invEvaluate(face, vcoords, params, result)); // Get (x,y,z) of nearest point on FACE
1460       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
1461     }
1462   }
1463   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
1464   /* Clear out global coordinates */
1465   PetscCall(VecDestroy(&dm->coordinates[0].x));
1466 #endif
1467   PetscFunctionReturn(0);
1468 }
1469 
1470 /*@C
1471   DMPlexCreateEGADSFromFile - Create a DMPlex mesh from an EGADS, IGES, or STEP file.
1472 
1473   Collective
1474 
1475   Input Parameters:
1476 + comm     - The MPI communicator
1477 - filename - The name of the EGADS, IGES, or STEP file
1478 
1479   Output Parameter:
1480 . dm       - The DM object representing the mesh
1481 
1482   Level: beginner
1483 
1484 .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateEGADS()`, `DMPlexCreateEGADSLiteFromFile()`
1485 @*/
1486 PetscErrorCode DMPlexCreateEGADSFromFile(MPI_Comm comm, const char filename[], DM *dm)
1487 {
1488   PetscMPIInt    rank;
1489 #if defined(PETSC_HAVE_EGADS)
1490   ego            context= NULL, model = NULL;
1491 #endif
1492   PetscBool      printModel = PETSC_FALSE, tessModel = PETSC_FALSE, newModel = PETSC_FALSE;
1493 
1494   PetscFunctionBegin;
1495   PetscValidCharPointer(filename, 2);
1496   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_egads_print_model", &printModel, NULL));
1497   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_egads_tess_model", &tessModel, NULL));
1498   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_egads_new_model", &newModel, NULL));
1499   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1500 #if defined(PETSC_HAVE_EGADS)
1501   if (rank == 0) {
1502 
1503     PetscCall(EG_open(&context));
1504     PetscCall(EG_loadModel(context, 0, filename, &model));
1505     if (printModel) PetscCall(DMPlexEGADSPrintModel_Internal(model));
1506 
1507   }
1508   if (tessModel)     PetscCall(DMPlexCreateEGADS_Tess_Internal(comm, context, model, dm));
1509   else if (newModel) PetscCall(DMPlexCreateEGADS(comm, context, model, dm));
1510   else               PetscCall(DMPlexCreateEGADS_Internal(comm, context, model, dm));
1511   PetscFunctionReturn(0);
1512 #else
1513   SETERRQ(comm, PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
1514 #endif
1515 }
1516