xref: /petsc/src/dm/impls/plex/plexegads.c (revision efa12513287cff49a2b9648ae83199dcbfaad71a)
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 
22 /*@
23   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.
24 
25   Not collective
26 
27   Input Parameters:
28 + dm      - The DMPlex object
29 . p       - The mesh point
30 - mcoords - A coordinate point lying on the mesh point
31 
32   Output Parameter:
33 . gcoords - The closest coordinate point on the geometry model associated with 'p' to the given point
34 
35   Note: Returns the original coordinates if no geometry model is found. Right now the only supported geometry model is EGADS.
36 
37   Level: intermediate
38 
39 .seealso: DMRefine(), DMPlexCreate(), DMPlexSetRefinementUniform()
40 @*/
41 PetscErrorCode DMPlexSnapToGeomModel(DM dm, PetscInt p, const PetscScalar mcoords[], PetscScalar gcoords[])
42 {
43 #ifdef PETSC_HAVE_EGADS
44   DM             cdm;
45   DMLabel        bodyLabel, faceLabel, edgeLabel;
46   PetscContainer modelObj;
47   PetscInt       bodyID, faceID, edgeID;
48   ego           *bodies;
49   ego            model, geom, body, obj;
50   /* result has to hold derviatives, along with the value */
51   double         params[3], result[18], paramsV[16*3], resultV[16*3];
52   int            Nb, oclass, mtype, *senses;
53   Vec            coordinatesLocal;
54   PetscScalar   *coords = NULL;
55   PetscInt       Nv, v, Np = 0, pm;
56 #endif
57   PetscInt       dE, d;
58   PetscErrorCode ierr;
59 
60   PetscFunctionBegin;
61   ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr);
62 #ifdef PETSC_HAVE_EGADS
63   ierr = DMGetLabel(dm, "EGADS Body ID",   &bodyLabel);CHKERRQ(ierr);
64   ierr = DMGetLabel(dm, "EGADS Face ID",   &faceLabel);CHKERRQ(ierr);
65   ierr = DMGetLabel(dm, "EGADS Edge ID",   &edgeLabel);CHKERRQ(ierr);
66   if (!bodyLabel || !faceLabel || !edgeLabel) {
67     for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
68     PetscFunctionReturn(0);
69   }
70   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
71   ierr = DMGetCoordinatesLocal(dm, &coordinatesLocal);CHKERRQ(ierr);
72   ierr = DMLabelGetValue(bodyLabel,   p, &bodyID);CHKERRQ(ierr);
73   ierr = DMLabelGetValue(faceLabel,   p, &faceID);CHKERRQ(ierr);
74   ierr = DMLabelGetValue(edgeLabel,   p, &edgeID);CHKERRQ(ierr);
75   ierr = PetscObjectQuery((PetscObject) dm, "EGADS Model", (PetscObject *) &modelObj);CHKERRQ(ierr);
76   ierr = PetscContainerGetPointer(modelObj, (void **) &model);CHKERRQ(ierr);
77   ierr = EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses);CHKERRQ(ierr);
78   if (bodyID < 0 || bodyID >= Nb) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Body %D is not in [0, %d)", bodyID, Nb);
79   body = bodies[bodyID];
80 
81   if (edgeID >= 0)      {ierr = EG_objectBodyTopo(body, EDGE, edgeID, &obj);CHKERRQ(ierr); Np = 1;}
82   else if (faceID >= 0) {ierr = EG_objectBodyTopo(body, FACE, faceID, &obj);CHKERRQ(ierr); Np = 2;}
83   else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D is not in edge or face label for EGADS", p);
84   /* Calculate parameters (t or u,v) for vertices */
85   ierr = DMPlexVecGetClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords);CHKERRQ(ierr);
86   Nv  /= dE;
87   if (Nv == 1) {
88     ierr = DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords);CHKERRQ(ierr);
89     for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
90     PetscFunctionReturn(0);
91   }
92   if (Nv > 16) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %D coordinates associated to point %D", Nv, p);
93   for (v = 0; v < Nv; ++v) {ierr = EG_invEvaluate(obj, &coords[v*dE], &paramsV[v*3], &resultV[v*3]);CHKERRQ(ierr);}
94   ierr = DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords);CHKERRQ(ierr);
95   /* Calculate parameters (t or u,v) for new vertex at edge midpoint */
96   for (pm = 0; pm < Np; ++pm) {
97     params[pm] = 0.;
98     for (v = 0; v < Nv; ++v) {params[pm] += paramsV[v*3+pm];}
99     params[pm] /= Nv;
100   }
101   /* TODO Check
102     double range[4]; // [umin, umax, vmin, vmax]
103     int    peri;
104     ierr = EG_getRange(face, range, &peri);CHKERRQ(ierr);
105     if ((paramsNew[0] < range[0]) || (paramsNew[0] > range[1]) || (paramsNew[1] < range[2]) || (paramsNew[1] > range[3])) SETERRQ();
106   */
107   /* Put coordinates for new vertex in result[] */
108   ierr = EG_evaluate(obj, params, result);CHKERRQ(ierr);
109   for (d = 0; d < dE; ++d) gcoords[d] = result[d];
110 #else
111   for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
112 #endif
113   PetscFunctionReturn(0);
114 }
115 
116 #if defined(PETSC_HAVE_EGADS)
117 static PetscErrorCode DMPlexEGADSPrintModel(ego model)
118 {
119   ego            geom, *bodies, *objs, *nobjs, *mobjs, *lobjs;
120   int            oclass, mtype, *senses;
121   int            Nb, b;
122   PetscErrorCode ierr;
123 
124   PetscFunctionBeginUser;
125   /* test bodyTopo functions */
126   ierr = EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses);CHKERRQ(ierr);
127   ierr = PetscPrintf(PETSC_COMM_SELF, " Number of BODIES (nbodies): %d \n", Nb);CHKERRQ(ierr);
128 
129   for (b = 0; b < Nb; ++b) {
130     ego body = bodies[b];
131     int id, Nsh, Nf, Nl, l, Ne, e, Nv, v;
132 
133     /* Output Basic Model Topology */
134     ierr = EG_getBodyTopos(body, NULL, SHELL, &Nsh, &objs);CHKERRQ(ierr);
135     ierr = PetscPrintf(PETSC_COMM_SELF, "   Number of SHELLS: %d \n", Nsh);CHKERRQ(ierr);
136     EG_free(objs);
137 
138     ierr = EG_getBodyTopos(body, NULL, FACE,  &Nf, &objs);CHKERRQ(ierr);
139     ierr = PetscPrintf(PETSC_COMM_SELF, "   Number of FACES: %d \n", Nf);CHKERRQ(ierr);
140     EG_free(objs);
141 
142     ierr = EG_getBodyTopos(body, NULL, LOOP,  &Nl, &lobjs);CHKERRQ(ierr);
143     ierr = PetscPrintf(PETSC_COMM_SELF, "   Number of LOOPS: %d \n", Nl);CHKERRQ(ierr);
144 
145     ierr = EG_getBodyTopos(body, NULL, EDGE,  &Ne, &objs);CHKERRQ(ierr);
146     ierr = PetscPrintf(PETSC_COMM_SELF, "   Number of EDGES: %d \n", Ne);CHKERRQ(ierr);
147     EG_free(objs);
148 
149     ierr = EG_getBodyTopos(body, NULL, NODE,  &Nv, &objs);CHKERRQ(ierr);
150     ierr = PetscPrintf(PETSC_COMM_SELF, "   Number of NODES: %d \n", Nv);CHKERRQ(ierr);
151     EG_free(objs);
152 
153     for (l = 0; l < Nl; ++l) {
154       ego loop = lobjs[l];
155 
156       id   = EG_indexBodyTopo(body, loop);
157       ierr = PetscPrintf(PETSC_COMM_SELF, "          LOOP ID: %d\n", id);CHKERRQ(ierr);
158 
159       /* Get EDGE info which associated with the current LOOP */
160       ierr = EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses);CHKERRQ(ierr);
161 
162       for (e = 0; e < Ne; ++e) {
163         ego    edge      = objs[e];
164         double range[4]  = {0., 0., 0., 0.};
165         double point[3]  = {0., 0., 0.};
166         double params[3] = {0., 0., 0.};
167         double result[18];
168         int    peri;
169 
170         id   = EG_indexBodyTopo(body, edge);CHKERRQ(ierr);
171         ierr = PetscPrintf(PETSC_COMM_SELF, "            EDGE ID: %d (%d)\n", id, e);CHKERRQ(ierr);
172 
173         ierr = EG_getRange(edge, range, &peri);CHKERRQ(ierr);
174         ierr = PetscPrintf(PETSC_COMM_SELF, "  Range = %lf, %lf, %lf, %lf \n", range[0], range[1], range[2], range[3]);
175 
176         /* Get NODE info which associated with the current EDGE */
177         ierr = EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);CHKERRQ(ierr);
178         if (mtype == DEGENERATE) {
179           ierr = PetscPrintf(PETSC_COMM_SELF, "  EDGE %d is DEGENERATE \n", id);CHKERRQ(ierr);
180         } else {
181           params[0] = range[0];
182           ierr = EG_evaluate(edge, params, result);CHKERRQ(ierr);
183           ierr = PetscPrintf(PETSC_COMM_SELF, "   between (%lf, %lf, %lf)", result[0], result[1], result[2]);
184           params[0] = range[1];
185           ierr = EG_evaluate(edge, params, result);CHKERRQ(ierr);
186           ierr = PetscPrintf(PETSC_COMM_SELF, " and (%lf, %lf, %lf)\n", result[0], result[1], result[2]);
187         }
188 
189         for (v = 0; v < Nv; ++v) {
190           ego    vertex = nobjs[v];
191           double limits[4];
192           int    dummy;
193 
194           ierr = EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses);CHKERRQ(ierr);
195           id   = EG_indexBodyTopo(body, vertex);
196           ierr = PetscPrintf(PETSC_COMM_SELF, "              NODE ID: %d \n", id);CHKERRQ(ierr);
197           ierr = PetscPrintf(PETSC_COMM_SELF, "                 (x, y, z) = (%lf, %lf, %lf) \n", limits[0], limits[1], limits[2]);
198 
199           point[0] = point[0] + limits[0];
200           point[1] = point[1] + limits[1];
201           point[2] = point[2] + limits[2];
202         }
203       }
204     }
205     EG_free(lobjs);
206   }
207   PetscFunctionReturn(0);
208 }
209 
210 static PetscErrorCode DMPlexEGADSDestroy_Private(void *context)
211 {
212   if (context) EG_close((ego) context);
213   return 0;
214 }
215 
216 static PetscErrorCode DMPlexCreateEGADS(MPI_Comm comm, ego context, ego model, DM *newdm)
217 {
218   DMLabel        bodyLabel, faceLabel, edgeLabel;
219   PetscInt       cStart, cEnd, c;
220   /* EGADSLite variables */
221   ego            geom, *bodies, *objs, *nobjs, *mobjs, *lobjs;
222   int            oclass, mtype, nbodies, *senses;
223   int            b;
224   /* PETSc variables */
225   DM             dm;
226   PetscHMapI     edgeMap = NULL;
227   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;
228   PetscInt      *cells  = NULL, *cone = NULL;
229   PetscReal     *coords = NULL;
230   PetscMPIInt    rank;
231   PetscErrorCode ierr;
232 
233   PetscFunctionBegin;
234   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
235   if (!rank) {
236     const PetscInt debug = 0;
237 
238     /* ---------------------------------------------------------------------------------------------------
239     Generate Petsc Plex
240       Get all Nodes in model, record coordinates in a correctly formatted array
241       Cycle through bodies, cycle through loops, recorde NODE IDs in a correctly formatted array
242       We need to uniformly refine the initial geometry to guarantee a valid mesh
243     */
244 
245     /* Calculate cell and vertex sizes */
246     ierr = EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses);CHKERRQ(ierr);
247     ierr = PetscHMapICreate(&edgeMap);CHKERRQ(ierr);
248     numEdges = 0;
249     for (b = 0; b < nbodies; ++b) {
250       ego body = bodies[b];
251       int id, Nl, l, Nv, v;
252 
253       ierr = EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs);CHKERRQ(ierr);
254       for (l = 0; l < Nl; ++l) {
255         ego loop = lobjs[l];
256         int Ner  = 0, Ne, e, Nc;
257 
258         ierr = EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses);CHKERRQ(ierr);
259         for (e = 0; e < Ne; ++e) {
260           ego edge = objs[e];
261           int Nv, id;
262           PetscHashIter iter;
263           PetscBool     found;
264 
265           ierr = EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);
266           if (mtype == DEGENERATE) continue;
267           id   = EG_indexBodyTopo(body, edge);CHKERRQ(ierr);
268           ierr = PetscHMapIFind(edgeMap, id-1, &iter, &found);CHKERRQ(ierr);
269           if (!found) {ierr = PetscHMapISet(edgeMap, id-1, numEdges++);CHKERRQ(ierr);}
270           ++Ner;
271         }
272         if (Ner == 2)      {Nc = 2;}
273         else if (Ner == 3) {Nc = 4;}
274         else if (Ner == 4) {Nc = 8; ++numQuads;}
275         else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot support loop with %d edges", Ner);
276         numCells += Nc;
277         newCells += Nc-1;
278         maxCorners = PetscMax(Ner*2+1, maxCorners);
279       }
280       ierr = EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs);CHKERRQ(ierr);
281       for (v = 0; v < Nv; ++v) {
282         ego vertex = nobjs[v];
283 
284         id = EG_indexBodyTopo(body, vertex);
285         /* TODO: Instead of assuming contiguous ids, we could use a hash table */
286         numVertices = PetscMax(id, numVertices);
287       }
288       EG_free(lobjs);
289       EG_free(nobjs);
290     }
291     ierr = PetscHMapIGetSize(edgeMap, &numEdges);CHKERRQ(ierr);
292     newVertices  = numEdges + numQuads;
293     numVertices += newVertices;
294 
295     dim        = 2; /* Assume 3D Models :: Need to update to handle 2D Models in the future */
296     cdim       = 3; /* Assume 3D Models :: Need to update to handle 2D Models in the future */
297     numCorners = 3; /* Split cells into triangles */
298     ierr = PetscMalloc3(numVertices*cdim, &coords, numCells*numCorners, &cells, maxCorners, &cone);CHKERRQ(ierr);
299 
300     /* Get vertex coordinates */
301     for (b = 0; b < nbodies; ++b) {
302       ego body = bodies[b];
303       int id, Nv, v;
304 
305       ierr = EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs);CHKERRQ(ierr);
306       for (v = 0; v < Nv; ++v) {
307         ego    vertex = nobjs[v];
308         double limits[4];
309         int    dummy;
310 
311         ierr = EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses);CHKERRQ(ierr);
312         id   = EG_indexBodyTopo(body, vertex);CHKERRQ(ierr);
313         coords[(id-1)*cdim+0] = limits[0];
314         coords[(id-1)*cdim+1] = limits[1];
315         coords[(id-1)*cdim+2] = limits[2];
316       }
317       EG_free(nobjs);
318     }
319     ierr = PetscHMapIClear(edgeMap);CHKERRQ(ierr);
320     fOff     = numVertices - newVertices + numEdges;
321     numEdges = 0;
322     numQuads = 0;
323     for (b = 0; b < nbodies; ++b) {
324       ego body = bodies[b];
325       int Nl, l;
326 
327       ierr = EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs);CHKERRQ(ierr);
328       for (l = 0; l < Nl; ++l) {
329         ego loop = lobjs[l];
330         int lid, Ner = 0, Ne, e;
331 
332         lid  = EG_indexBodyTopo(body, loop);CHKERRQ(ierr);
333         ierr = EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses);CHKERRQ(ierr);
334         for (e = 0; e < Ne; ++e) {
335           ego       edge = objs[e];
336           int       eid, Nv;
337           PetscHashIter iter;
338           PetscBool     found;
339 
340           ierr = EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);
341           if (mtype == DEGENERATE) continue;
342           ++Ner;
343           eid  = EG_indexBodyTopo(body, edge);CHKERRQ(ierr);
344           ierr = PetscHMapIFind(edgeMap, eid-1, &iter, &found);CHKERRQ(ierr);
345           if (!found) {
346             PetscInt v = numVertices - newVertices + numEdges;
347             double range[4], params[3] = {0., 0., 0.}, result[18];
348             int    periodic[2];
349 
350             ierr = PetscHMapISet(edgeMap, eid-1, numEdges++);CHKERRQ(ierr);
351             ierr = EG_getRange(edge, range, periodic);CHKERRQ(ierr);
352             params[0] = 0.5*(range[0] + range[1]);
353             ierr = EG_evaluate(edge, params, result);CHKERRQ(ierr);
354             coords[v*cdim+0] = result[0];
355             coords[v*cdim+1] = result[1];
356             coords[v*cdim+2] = result[2];
357           }
358         }
359         if (Ner == 4) {
360           PetscInt v = fOff + numQuads++;
361           ego     *fobjs, face;
362           double   range[4], params[3] = {0., 0., 0.}, result[18];
363           int      Nf, fid, periodic[2];
364 
365           ierr = EG_getBodyTopos(body, loop, FACE, &Nf, &fobjs);CHKERRQ(ierr);
366           face = fobjs[0];
367           fid  = EG_indexBodyTopo(body, face);CHKERRQ(ierr);
368           if (Nf != 1) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Loop %d has %d faces, instead of 1 (%d)", lid-1, Nf, fid);
369           ierr = EG_getRange(face, range, periodic);CHKERRQ(ierr);
370           params[0] = 0.5*(range[0] + range[1]);
371           params[1] = 0.5*(range[2] + range[3]);
372           ierr = EG_evaluate(face, params, result);CHKERRQ(ierr);
373           coords[v*cdim+0] = result[0];
374           coords[v*cdim+1] = result[1];
375           coords[v*cdim+2] = result[2];
376         }
377       }
378     }
379     if (numEdges + numQuads != newVertices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of new vertices %D != %D previous count", numEdges + numQuads, newVertices);
380     CHKMEMQ;
381 
382     /* Get cell vertices by traversing loops */
383     numQuads = 0;
384     cOff     = 0;
385     for (b = 0; b < nbodies; ++b) {
386       ego body = bodies[b];
387       int id, Nl, l;
388 
389       ierr = EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs);CHKERRQ(ierr);
390       for (l = 0; l < Nl; ++l) {
391         ego loop = lobjs[l];
392         int lid, Ner = 0, Ne, e, nc = 0, c, Nt, t;
393 
394         lid  = EG_indexBodyTopo(body, loop);CHKERRQ(ierr);
395         ierr = EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses);CHKERRQ(ierr);
396 
397         for (e = 0; e < Ne; ++e) {
398           ego edge = objs[e];
399           int points[3];
400           int eid, Nv, v, tmp;
401 
402           eid  = EG_indexBodyTopo(body, edge);
403           ierr = EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);
404           if (mtype == DEGENERATE) continue;
405           else                     ++Ner;
406           if (Nv != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Edge %d has %d vertices != 2", eid, Nv);
407 
408           for (v = 0; v < Nv; ++v) {
409             ego vertex = nobjs[v];
410 
411             id = EG_indexBodyTopo(body, vertex);
412             points[v*2] = id-1;
413           }
414           {
415             PetscInt edgeNum;
416 
417             ierr = PetscHMapIGet(edgeMap, eid-1, &edgeNum);CHKERRQ(ierr);
418             points[1] = numVertices - newVertices + edgeNum;
419           }
420           /* EGADS loops are not oriented, but seem to be in order, so we must piece them together */
421           if (!nc) {
422             for (v = 0; v < Nv+1; ++v) cone[nc++] = points[v];
423           } else {
424             if (cone[nc-1] == points[0])      {cone[nc++] = points[1]; if (cone[0] != points[2]) cone[nc++] = points[2];}
425             else if (cone[nc-1] == points[2]) {cone[nc++] = points[1]; if (cone[0] != points[0]) cone[nc++] = points[0];}
426             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];}
427             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];}
428             else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %d does not match its predecessor", eid);
429           }
430         }
431         if (nc != 2*Ner)     SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of corners %D != %D", nc, 2*Ner);
432         if (Ner == 4) {cone[nc++] = numVertices - newVertices + numEdges + numQuads++;}
433         if (nc > maxCorners) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of corners %D > %D max", nc, maxCorners);
434         /* Triangulate the loop */
435         switch (Ner) {
436           case 2: /* Bi-Segment -> 2 triangles */
437             Nt = 2;
438             cells[cOff*numCorners+0] = cone[0];
439             cells[cOff*numCorners+1] = cone[1];
440             cells[cOff*numCorners+2] = cone[2];
441             ++cOff;
442             cells[cOff*numCorners+0] = cone[0];
443             cells[cOff*numCorners+1] = cone[2];
444             cells[cOff*numCorners+2] = cone[3];
445             ++cOff;
446             break;
447           case 3: /* Triangle   -> 4 triangles */
448             Nt = 4;
449             cells[cOff*numCorners+0] = cone[0];
450             cells[cOff*numCorners+1] = cone[1];
451             cells[cOff*numCorners+2] = cone[5];
452             ++cOff;
453             cells[cOff*numCorners+0] = cone[1];
454             cells[cOff*numCorners+1] = cone[2];
455             cells[cOff*numCorners+2] = cone[3];
456             ++cOff;
457             cells[cOff*numCorners+0] = cone[5];
458             cells[cOff*numCorners+1] = cone[3];
459             cells[cOff*numCorners+2] = cone[4];
460             ++cOff;
461             cells[cOff*numCorners+0] = cone[1];
462             cells[cOff*numCorners+1] = cone[3];
463             cells[cOff*numCorners+2] = cone[5];
464             ++cOff;
465             break;
466           case 4: /* Quad       -> 8 triangles */
467             Nt = 8;
468             cells[cOff*numCorners+0] = cone[0];
469             cells[cOff*numCorners+1] = cone[1];
470             cells[cOff*numCorners+2] = cone[7];
471             ++cOff;
472             cells[cOff*numCorners+0] = cone[1];
473             cells[cOff*numCorners+1] = cone[2];
474             cells[cOff*numCorners+2] = cone[3];
475             ++cOff;
476             cells[cOff*numCorners+0] = cone[3];
477             cells[cOff*numCorners+1] = cone[4];
478             cells[cOff*numCorners+2] = cone[5];
479             ++cOff;
480             cells[cOff*numCorners+0] = cone[5];
481             cells[cOff*numCorners+1] = cone[6];
482             cells[cOff*numCorners+2] = cone[7];
483             ++cOff;
484             cells[cOff*numCorners+0] = cone[8];
485             cells[cOff*numCorners+1] = cone[1];
486             cells[cOff*numCorners+2] = cone[3];
487             ++cOff;
488             cells[cOff*numCorners+0] = cone[8];
489             cells[cOff*numCorners+1] = cone[3];
490             cells[cOff*numCorners+2] = cone[5];
491             ++cOff;
492             cells[cOff*numCorners+0] = cone[8];
493             cells[cOff*numCorners+1] = cone[5];
494             cells[cOff*numCorners+2] = cone[7];
495             ++cOff;
496             cells[cOff*numCorners+0] = cone[8];
497             cells[cOff*numCorners+1] = cone[7];
498             cells[cOff*numCorners+2] = cone[1];
499             ++cOff;
500             break;
501           default: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %d has %d edges, which we do not support", lid, Ner);
502         }
503         if (debug) {
504           for (t = 0; t < Nt; ++t) {
505             ierr = PetscPrintf(PETSC_COMM_SELF, "  LOOP Corner NODEs Triangle %D (", t);CHKERRQ(ierr);
506             for (c = 0; c < numCorners; ++c) {
507               if (c > 0) {ierr = PetscPrintf(PETSC_COMM_SELF, ", ");CHKERRQ(ierr);}
508               ierr = PetscPrintf(PETSC_COMM_SELF, "%D", cells[(cOff-Nt+t)*numCorners+c]);CHKERRQ(ierr);
509             }
510             ierr = PetscPrintf(PETSC_COMM_SELF, ")\n");CHKERRQ(ierr);
511           }
512         }
513       }
514       EG_free(lobjs);
515     }
516   }
517   if (cOff != numCells) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Count of total cells %D != %D previous count", cOff, numCells);
518   ierr = DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, numCells, numVertices, numCorners, PETSC_TRUE, cells, cdim, coords, &dm);CHKERRQ(ierr);
519   ierr = PetscFree3(coords, cells, cone);CHKERRQ(ierr);
520   ierr = PetscInfo2(dm, " Total Number of Unique Cells    = %D (%D)\n", numCells, newCells);CHKERRQ(ierr);
521   ierr = PetscInfo2(dm, " Total Number of Unique Vertices = %D (%D)\n", numVertices, newVertices);CHKERRQ(ierr);
522   /* Embed EGADS model in DM */
523   {
524     PetscContainer modelObj, contextObj;
525 
526     ierr = PetscContainerCreate(PETSC_COMM_SELF, &modelObj);CHKERRQ(ierr);
527     ierr = PetscContainerSetPointer(modelObj, model);CHKERRQ(ierr);
528     ierr = PetscObjectCompose((PetscObject) dm, "EGADS Model", (PetscObject) modelObj);CHKERRQ(ierr);
529     ierr = PetscContainerDestroy(&modelObj);CHKERRQ(ierr);
530 
531     ierr = PetscContainerCreate(PETSC_COMM_SELF, &contextObj);CHKERRQ(ierr);
532     ierr = PetscContainerSetPointer(contextObj, context);CHKERRQ(ierr);
533     ierr = PetscContainerSetUserDestroy(contextObj, DMPlexEGADSDestroy_Private);CHKERRQ(ierr);
534     ierr = PetscObjectCompose((PetscObject) dm, "EGADS Context", (PetscObject) contextObj);CHKERRQ(ierr);
535     ierr = PetscContainerDestroy(&contextObj);CHKERRQ(ierr);
536   }
537   /* Label points */
538   ierr = DMCreateLabel(dm, "EGADS Body ID");CHKERRQ(ierr);
539   ierr = DMGetLabel(dm, "EGADS Body ID", &bodyLabel);CHKERRQ(ierr);
540   ierr = DMCreateLabel(dm, "EGADS Face ID");CHKERRQ(ierr);
541   ierr = DMGetLabel(dm, "EGADS Face ID", &faceLabel);CHKERRQ(ierr);
542   ierr = DMCreateLabel(dm, "EGADS Edge ID");CHKERRQ(ierr);
543   ierr = DMGetLabel(dm, "EGADS Edge ID", &edgeLabel);CHKERRQ(ierr);
544   cOff = 0;
545   for (b = 0; b < nbodies; ++b) {
546     ego body = bodies[b];
547     int id, Nl, l;
548 
549     ierr = EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs);CHKERRQ(ierr);
550     for (l = 0; l < Nl; ++l) {
551       ego  loop = lobjs[l];
552       ego *fobjs;
553       int  lid, Nf, fid, Ner = 0, Ne, e, Nt = 0, t;
554 
555       lid  = EG_indexBodyTopo(body, loop);CHKERRQ(ierr);
556       ierr = EG_getBodyTopos(body, loop, FACE, &Nf, &fobjs);CHKERRQ(ierr);
557       if (Nf > 1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %d has %d > 1 faces, which is not supported", lid, Nf);CHKERRQ(ierr);
558       fid  = EG_indexBodyTopo(body, fobjs[0]);CHKERRQ(ierr);
559       EG_free(fobjs);
560       ierr = EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses);CHKERRQ(ierr);
561       for (e = 0; e < Ne; ++e) {
562         ego             edge = objs[e];
563         int             eid, Nv, v;
564         PetscInt        points[3], support[2], numEdges, edgeNum;
565         const PetscInt *edges;
566 
567         eid  = EG_indexBodyTopo(body, edge);
568         ierr = EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);
569         if (mtype == DEGENERATE) continue;
570         else                     ++Ner;
571         for (v = 0; v < Nv; ++v) {
572           ego vertex = nobjs[v];
573 
574           id   = EG_indexBodyTopo(body, vertex);
575           ierr = DMLabelSetValue(edgeLabel, numCells + id-1, eid);CHKERRQ(ierr);
576           points[v*2] = numCells + id-1;
577         }
578         ierr = PetscHMapIGet(edgeMap, eid-1, &edgeNum);CHKERRQ(ierr);
579         points[1] = numCells + numVertices - newVertices + edgeNum;
580 
581         ierr = DMLabelSetValue(edgeLabel, points[1], eid);CHKERRQ(ierr);
582         support[0] = points[0];
583         support[1] = points[1];
584         ierr = DMPlexGetJoin(dm, 2, support, &numEdges, &edges);CHKERRQ(ierr);
585         if (numEdges != 1) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Vertices (%D, %D) should only bound 1 edge, not %D", support[0], support[1], numEdges);
586         ierr = DMLabelSetValue(edgeLabel, edges[0], eid);CHKERRQ(ierr);
587         ierr = DMPlexRestoreJoin(dm, 2, support, &numEdges, &edges);CHKERRQ(ierr);
588         support[0] = points[1];
589         support[1] = points[2];
590         ierr = DMPlexGetJoin(dm, 2, support, &numEdges, &edges);CHKERRQ(ierr);
591         if (numEdges != 1) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Vertices (%D, %D) should only bound 1 edge, not %D", support[0], support[1], numEdges);
592         ierr = DMLabelSetValue(edgeLabel, edges[0], eid);CHKERRQ(ierr);
593         ierr = DMPlexRestoreJoin(dm, 2, support, &numEdges, &edges);CHKERRQ(ierr);
594       }
595       switch (Ner) {
596         case 2: Nt = 2;break;
597         case 3: Nt = 4;break;
598         case 4: Nt = 8;break;
599         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Loop with %d edges is unsupported", Ner);
600       }
601       for (t = 0; t < Nt; ++t) {
602         ierr = DMLabelSetValue(bodyLabel, cOff+t, b);CHKERRQ(ierr);
603         ierr = DMLabelSetValue(faceLabel, cOff+t, fid);CHKERRQ(ierr);
604       }
605       cOff += Nt;
606     }
607     EG_free(lobjs);
608   }
609   ierr = PetscHMapIDestroy(&edgeMap);CHKERRQ(ierr);
610   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
611   for (c = cStart; c < cEnd; ++c) {
612     PetscInt *closure = NULL;
613     PetscInt  clSize, cl, bval, fval;
614 
615     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
616     ierr = DMLabelGetValue(bodyLabel, c, &bval);CHKERRQ(ierr);
617     ierr = DMLabelGetValue(faceLabel, c, &fval);CHKERRQ(ierr);
618     for (cl = 0; cl < clSize*2; cl += 2) {
619       ierr = DMLabelSetValue(bodyLabel, closure[cl], bval);CHKERRQ(ierr);
620       ierr = DMLabelSetValue(faceLabel, closure[cl], fval);CHKERRQ(ierr);
621     }
622     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
623   }
624   *newdm = dm;
625   PetscFunctionReturn(0);
626 }
627 #endif
628 
629 /*@C
630   DMPlexCreateEGADSFromFile - Create a DMPlex mesh from an EGADSLite file.
631 
632   Collective
633 
634   Input Parameters:
635 + comm     - The MPI communicator
636 - filename - The name of the ExodusII file
637 
638   Output Parameter:
639 . dm       - The DM object representing the mesh
640 
641   Level: beginner
642 
643 .seealso: DMPLEX, DMCreate(), DMPlexCreateEGADS()
644 @*/
645 PetscErrorCode DMPlexCreateEGADSFromFile(MPI_Comm comm, const char filename[], DM *dm)
646 {
647   PetscMPIInt    rank;
648 #if defined(PETSC_HAVE_EGADS)
649   ego            context= NULL, model = NULL;
650 #endif
651   PetscBool      printModel = PETSC_FALSE;
652   PetscErrorCode ierr;
653 
654   PetscFunctionBegin;
655   PetscValidCharPointer(filename, 2);
656   ierr = PetscOptionsGetBool(NULL, NULL, "-dm_plex_egads_print_model", &printModel, NULL);CHKERRQ(ierr);
657   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
658 #if defined(PETSC_HAVE_EGADS)
659   if (!rank) {
660 
661     ierr = EG_open(&context);CHKERRQ(ierr);
662     ierr = EG_loadModel(context, 0, filename, &model);CHKERRQ(ierr);
663     if (printModel) {ierr = DMPlexEGADSPrintModel(model);CHKERRQ(ierr);}
664 
665   }
666   ierr = DMPlexCreateEGADS(comm, context, model, dm);CHKERRQ(ierr);
667   PetscFunctionReturn(0);
668 #else
669   SETERRQ(comm, PETSC_ERR_SUP, "This method requires EGADSLite support. Reconfigure using --download-egads");
670 #endif
671 }
672