Date: 2022-03-31T04:47:32+00:00

Actual source code: plexegads.c

      1: #include <petsc/private/dmpleximpl.h>
      2: #include <petsc/private/hashmapi.h>

      4: #ifdef PETSC_HAVE_EGADS
      5: #include <egads.h>
      6: #endif

      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:

     11:      https://github.com/tpaviot/oce/tree/master/src/STEPControl

     13:    The STEP, and inner EXPRESS, formats are ISO standards, so they are documented

     15:      https://stackoverflow.com/questions/26774037/documentation-or-specification-for-step-and-stp-files
     16:      http://stepmod.sourceforge.net/express_model_spec/

     18:    but again it seems that there has been a deliberate effort at obfuscation, probably to raise the bar for entrants.
     19: */

     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[]);

     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;

     39:   DMGetCoordinateDM(dm, &cdm);
     40:   DMGetCoordinateDim(dm, &dE);
     41:   DMGetCoordinatesLocal(dm, &coordinatesLocal);
     42:   EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses);
     44:   body = bodies[bodyID];

     46:   if (edgeID >= 0)      {EG_objectBodyTopo(body, EDGE, edgeID, &obj); Np = 1;}
     47:   else if (faceID >= 0) {EG_objectBodyTopo(body, FACE, faceID, &obj); Np = 2;}
     48:   else {
     49:     for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
     50:     return 0;
     51:   }

     53:   /* Calculate parameters (t or u,v) for vertices */
     54:   DMPlexVecGetClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords);
     55:   Nv  /= dE;
     56:   if (Nv == 1) {
     57:     DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords);
     58:     for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
     59:     return 0;
     60:   }

     63:   /* Correct EGADSlite 2pi bug when calculating nearest point on Periodic Surfaces */
     64:   EG_getRange(obj, range, &peri);
     65:   for (v = 0; v < Nv; ++v) {
     66:     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:   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:   }
     87:   /* Put coordinates for new vertex in result[] */
     88:   EG_evaluate(obj, params, result);
     89:   for (d = 0; d < dE; ++d) gcoords[d] = result[d];
     90:   return 0;
     91: }
     92: #endif

     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.

     97:   Not collective

     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

    105:   Output Parameter:
    106: . gcoords - The closest coordinate point on the geometry model associated with 'p' to the given point

    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.

    110:   Level: intermediate

    112: .seealso: DMRefine(), DMPlexCreate(), DMPlexSetRefinementUniform()
    113: @*/
    114: PetscErrorCode DMPlexSnapToGeomModel(DM dm, PetscInt p, PetscInt dE, const PetscScalar mcoords[], PetscScalar gcoords[])
    115: {
    116:   PetscInt d;

    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;

    128:     DMGetLabel(dm, "EGADS Body ID", &bodyLabel);
    129:     DMGetLabel(dm, "EGADS Face ID", &faceLabel);
    130:     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:       return 0;
    134:     }
    135:     PetscObjectQuery((PetscObject) dm, "EGADS Model", (PetscObject *) &modelObj);
    136:     if (!modelObj) {
    137:       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:       return 0;
    143:     }
    144:     PetscContainerGetPointer(modelObj, (void **) &model);
    145:     DMLabelGetValue(bodyLabel, p, &bodyID);
    146:     DMLabelGetValue(faceLabel, p, &faceID);
    147:     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:       return 0;
    152:     }
    153:     if (islite) DMPlexSnapToGeomModel_EGADSLite_Internal(dm, p, model, bodyID, faceID, edgeID, mcoords, gcoords);
    154:     else        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:   return 0;
    160: }

    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;

    170:   /* test bodyTopo functions */
    171:   EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses);
    172:   PetscPrintf(PETSC_COMM_SELF, " Number of BODIES (nbodies): %d \n", Nb);

    174:   for (b = 0; b < Nb; ++b) {
    175:     ego body = bodies[b];
    176:     int id, Nsh, Nf, Nl, l, Ne, e, Nv, v;

    178:     /* Output Basic Model Topology */
    179:     EG_getBodyTopos(body, NULL, SHELL, &Nsh, &objs);
    180:     PetscPrintf(PETSC_COMM_SELF, "   Number of SHELLS: %d \n", Nsh);
    181:     EG_free(objs);

    183:     EG_getBodyTopos(body, NULL, FACE,  &Nf, &objs);
    184:     PetscPrintf(PETSC_COMM_SELF, "   Number of FACES: %d \n", Nf);
    185:     EG_free(objs);

    187:     EG_getBodyTopos(body, NULL, LOOP,  &Nl, &lobjs);
    188:     PetscPrintf(PETSC_COMM_SELF, "   Number of LOOPS: %d \n", Nl);

    190:     EG_getBodyTopos(body, NULL, EDGE,  &Ne, &objs);
    191:     PetscPrintf(PETSC_COMM_SELF, "   Number of EDGES: %d \n", Ne);
    192:     EG_free(objs);

    194:     EG_getBodyTopos(body, NULL, NODE,  &Nv, &objs);
    195:     PetscPrintf(PETSC_COMM_SELF, "   Number of NODES: %d \n", Nv);
    196:     EG_free(objs);

    198:     for (l = 0; l < Nl; ++l) {
    199:       ego loop = lobjs[l];

    201:       id   = EG_indexBodyTopo(body, loop);
    202:       PetscPrintf(PETSC_COMM_SELF, "          LOOP ID: %d\n", id);

    204:       /* Get EDGE info which associated with the current LOOP */
    205:       EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses);

    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;

    215:         id   = EG_indexBodyTopo(body, edge);
    216:         PetscPrintf(PETSC_COMM_SELF, "            EDGE ID: %d (%d)\n", id, e);

    218:         EG_getRange(edge, range, &peri);
    219:         PetscPrintf(PETSC_COMM_SELF, "  Range = %lf, %lf, %lf, %lf \n", range[0], range[1], range[2], range[3]);

    221:         /* Get NODE info which associated with the current EDGE */
    222:         EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);
    223:         if (mtype == DEGENERATE) {
    224:           PetscPrintf(PETSC_COMM_SELF, "  EDGE %d is DEGENERATE \n", id);
    225:         } else {
    226:           params[0] = range[0];
    227:           EG_evaluate(edge, params, result);
    228:           PetscPrintf(PETSC_COMM_SELF, "   between (%lf, %lf, %lf)", result[0], result[1], result[2]);
    229:           params[0] = range[1];
    230:           EG_evaluate(edge, params, result);
    231:           PetscPrintf(PETSC_COMM_SELF, " and (%lf, %lf, %lf)\n", result[0], result[1], result[2]);
    232:         }

    234:         for (v = 0; v < Nv; ++v) {
    235:           ego    vertex = nobjs[v];
    236:           double limits[4];
    237:           int    dummy;

    239:           EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses);
    240:           id   = EG_indexBodyTopo(body, vertex);
    241:           PetscPrintf(PETSC_COMM_SELF, "              NODE ID: %d \n", id);
    242:           PetscPrintf(PETSC_COMM_SELF, "                 (x, y, z) = (%lf, %lf, %lf) \n", limits[0], limits[1], limits[2]);

    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:   return 0;
    253: }

    255: static PetscErrorCode DMPlexEGADSDestroy_Private(void *context)
    256: {
    257:   if (context) EG_close((ego) context);
    258:   return 0;
    259: }

    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;

    277:   MPI_Comm_rank(comm, &rank);
    278:   if (rank == 0) {
    279:     const PetscInt debug = 0;

    281:     /* ---------------------------------------------------------------------------------------------------
    282:     Generate Petsc Plex
    283:       Get all Nodes in model, record coordinates in a correctly formatted array
    284:       Cycle through bodies, cycle through loops, recorde NODE IDs in a correctly formatted array
    285:       We need to uniformly refine the initial geometry to guarantee a valid mesh
    286:     */

    288:     /* Calculate cell and vertex sizes */
    289:     EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses);
    290:     PetscHMapICreate(&edgeMap);
    291:     numEdges = 0;
    292:     for (b = 0; b < nbodies; ++b) {
    293:       ego body = bodies[b];
    294:       int id, Nl, l, Nv, v;

    296:       EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs);
    297:       for (l = 0; l < Nl; ++l) {
    298:         ego loop = lobjs[l];
    299:         int Ner  = 0, Ne, e, Nc;

    301:         EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses);
    302:         for (e = 0; e < Ne; ++e) {
    303:           ego edge = objs[e];
    304:           int Nv, id;
    305:           PetscHashIter iter;
    306:           PetscBool     found;

    308:           EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);
    309:           if (mtype == DEGENERATE) continue;
    310:           id = EG_indexBodyTopo(body, edge);
    311:           PetscHMapIFind(edgeMap, id-1, &iter, &found);
    312:           if (!found) PetscHMapISet(edgeMap, id-1, numEdges++);
    313:           ++Ner;
    314:         }
    315:         if (Ner == 2)      {Nc = 2;}
    316:         else if (Ner == 3) {Nc = 4;}
    317:         else if (Ner == 4) {Nc = 8; ++numQuads;}
    318:         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot support loop with %d edges", Ner);
    319:         numCells += Nc;
    320:         newCells += Nc-1;
    321:         maxCorners = PetscMax(Ner*2+1, maxCorners);
    322:       }
    323:       EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs);
    324:       for (v = 0; v < Nv; ++v) {
    325:         ego vertex = nobjs[v];

    327:         id = EG_indexBodyTopo(body, vertex);
    328:         /* TODO: Instead of assuming contiguous ids, we could use a hash table */
    329:         numVertices = PetscMax(id, numVertices);
    330:       }
    331:       EG_free(lobjs);
    332:       EG_free(nobjs);
    333:     }
    334:     PetscHMapIGetSize(edgeMap, &numEdges);
    335:     newVertices  = numEdges + numQuads;
    336:     numVertices += newVertices;

    338:     dim        = 2; /* Assume 3D Models :: Need to update to handle 2D Models in the future */
    339:     cdim       = 3; /* Assume 3D Models :: Need to update to handle 2D Models in the future */
    340:     numCorners = 3; /* Split cells into triangles */
    341:     PetscMalloc3(numVertices*cdim, &coords, numCells*numCorners, &cells, maxCorners, &cone);

    343:     /* Get vertex coordinates */
    344:     for (b = 0; b < nbodies; ++b) {
    345:       ego body = bodies[b];
    346:       int id, Nv, v;

    348:       EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs);
    349:       for (v = 0; v < Nv; ++v) {
    350:         ego    vertex = nobjs[v];
    351:         double limits[4];
    352:         int    dummy;

    354:         EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses);
    355:         id   = EG_indexBodyTopo(body, vertex);
    356:         coords[(id-1)*cdim+0] = limits[0];
    357:         coords[(id-1)*cdim+1] = limits[1];
    358:         coords[(id-1)*cdim+2] = limits[2];
    359:       }
    360:       EG_free(nobjs);
    361:     }
    362:     PetscHMapIClear(edgeMap);
    363:     fOff     = numVertices - newVertices + numEdges;
    364:     numEdges = 0;
    365:     numQuads = 0;
    366:     for (b = 0; b < nbodies; ++b) {
    367:       ego body = bodies[b];
    368:       int Nl, l;

    370:       EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs);
    371:       for (l = 0; l < Nl; ++l) {
    372:         ego loop = lobjs[l];
    373:         int lid, Ner = 0, Ne, e;

    375:         lid  = EG_indexBodyTopo(body, loop);
    376:         EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses);
    377:         for (e = 0; e < Ne; ++e) {
    378:           ego       edge = objs[e];
    379:           int       eid, Nv;
    380:           PetscHashIter iter;
    381:           PetscBool     found;

    383:           EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);
    384:           if (mtype == DEGENERATE) continue;
    385:           ++Ner;
    386:           eid  = EG_indexBodyTopo(body, edge);
    387:           PetscHMapIFind(edgeMap, eid-1, &iter, &found);
    388:           if (!found) {
    389:             PetscInt v = numVertices - newVertices + numEdges;
    390:             double range[4], params[3] = {0., 0., 0.}, result[18];
    391:             int    periodic[2];

    393:             PetscHMapISet(edgeMap, eid-1, numEdges++);
    394:             EG_getRange(edge, range, periodic);
    395:             params[0] = 0.5*(range[0] + range[1]);
    396:             EG_evaluate(edge, params, result);
    397:             coords[v*cdim+0] = result[0];
    398:             coords[v*cdim+1] = result[1];
    399:             coords[v*cdim+2] = result[2];
    400:           }
    401:         }
    402:         if (Ner == 4) {
    403:           PetscInt v = fOff + numQuads++;
    404:           ego     *fobjs, face;
    405:           double   range[4], params[3] = {0., 0., 0.}, result[18];
    406:           int      Nf, fid, periodic[2];

    408:           EG_getBodyTopos(body, loop, FACE, &Nf, &fobjs);
    409:           face = fobjs[0];
    410:           fid  = EG_indexBodyTopo(body, face);
    412:           EG_getRange(face, range, periodic);
    413:           params[0] = 0.5*(range[0] + range[1]);
    414:           params[1] = 0.5*(range[2] + range[3]);
    415:           EG_evaluate(face, params, result);
    416:           coords[v*cdim+0] = result[0];
    417:           coords[v*cdim+1] = result[1];
    418:           coords[v*cdim+2] = result[2];
    419:         }
    420:       }
    421:     }

    424:     /* Get cell vertices by traversing loops */
    425:     numQuads = 0;
    426:     cOff     = 0;
    427:     for (b = 0; b < nbodies; ++b) {
    428:       ego body = bodies[b];
    429:       int id, Nl, l;

    431:       EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs);
    432:       for (l = 0; l < Nl; ++l) {
    433:         ego loop = lobjs[l];
    434:         int lid, Ner = 0, Ne, e, nc = 0, c, Nt, t;

    436:         lid  = EG_indexBodyTopo(body, loop);
    437:         EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses);

    439:         for (e = 0; e < Ne; ++e) {
    440:           ego edge = objs[e];
    441:           int points[3];
    442:           int eid, Nv, v, tmp;

    444:           eid = EG_indexBodyTopo(body, edge);
    445:           EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);
    446:           if (mtype == DEGENERATE) continue;
    447:           else                     ++Ner;

    450:           for (v = 0; v < Nv; ++v) {
    451:             ego vertex = nobjs[v];

    453:             id = EG_indexBodyTopo(body, vertex);
    454:             points[v*2] = id-1;
    455:           }
    456:           {
    457:             PetscInt edgeNum;

    459:             PetscHMapIGet(edgeMap, eid-1, &edgeNum);
    460:             points[1] = numVertices - newVertices + edgeNum;
    461:           }
    462:           /* EGADS loops are not oriented, but seem to be in order, so we must piece them together */
    463:           if (!nc) {
    464:             for (v = 0; v < Nv+1; ++v) cone[nc++] = points[v];
    465:           } else {
    466:             if (cone[nc-1] == points[0])      {cone[nc++] = points[1]; if (cone[0] != points[2]) cone[nc++] = points[2];}
    467:             else if (cone[nc-1] == points[2]) {cone[nc++] = points[1]; if (cone[0] != points[0]) cone[nc++] = points[0];}
    468:             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];}
    469:             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];}
    470:             else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %d does not match its predecessor", eid);
    471:           }
    472:         }
    474:         if (Ner == 4) {cone[nc++] = numVertices - newVertices + numEdges + numQuads++;}
    476:         /* Triangulate the loop */
    477:         switch (Ner) {
    478:           case 2: /* Bi-Segment -> 2 triangles */
    479:             Nt = 2;
    480:             cells[cOff*numCorners+0] = cone[0];
    481:             cells[cOff*numCorners+1] = cone[1];
    482:             cells[cOff*numCorners+2] = cone[2];
    483:             ++cOff;
    484:             cells[cOff*numCorners+0] = cone[0];
    485:             cells[cOff*numCorners+1] = cone[2];
    486:             cells[cOff*numCorners+2] = cone[3];
    487:             ++cOff;
    488:             break;
    489:           case 3: /* Triangle   -> 4 triangles */
    490:             Nt = 4;
    491:             cells[cOff*numCorners+0] = cone[0];
    492:             cells[cOff*numCorners+1] = cone[1];
    493:             cells[cOff*numCorners+2] = cone[5];
    494:             ++cOff;
    495:             cells[cOff*numCorners+0] = cone[1];
    496:             cells[cOff*numCorners+1] = cone[2];
    497:             cells[cOff*numCorners+2] = cone[3];
    498:             ++cOff;
    499:             cells[cOff*numCorners+0] = cone[5];
    500:             cells[cOff*numCorners+1] = cone[3];
    501:             cells[cOff*numCorners+2] = cone[4];
    502:             ++cOff;
    503:             cells[cOff*numCorners+0] = cone[1];
    504:             cells[cOff*numCorners+1] = cone[3];
    505:             cells[cOff*numCorners+2] = cone[5];
    506:             ++cOff;
    507:             break;
    508:           case 4: /* Quad       -> 8 triangles */
    509:             Nt = 8;
    510:             cells[cOff*numCorners+0] = cone[0];
    511:             cells[cOff*numCorners+1] = cone[1];
    512:             cells[cOff*numCorners+2] = cone[7];
    513:             ++cOff;
    514:             cells[cOff*numCorners+0] = cone[1];
    515:             cells[cOff*numCorners+1] = cone[2];
    516:             cells[cOff*numCorners+2] = cone[3];
    517:             ++cOff;
    518:             cells[cOff*numCorners+0] = cone[3];
    519:             cells[cOff*numCorners+1] = cone[4];
    520:             cells[cOff*numCorners+2] = cone[5];
    521:             ++cOff;
    522:             cells[cOff*numCorners+0] = cone[5];
    523:             cells[cOff*numCorners+1] = cone[6];
    524:             cells[cOff*numCorners+2] = cone[7];
    525:             ++cOff;
    526:             cells[cOff*numCorners+0] = cone[8];
    527:             cells[cOff*numCorners+1] = cone[1];
    528:             cells[cOff*numCorners+2] = cone[3];
    529:             ++cOff;
    530:             cells[cOff*numCorners+0] = cone[8];
    531:             cells[cOff*numCorners+1] = cone[3];
    532:             cells[cOff*numCorners+2] = cone[5];
    533:             ++cOff;
    534:             cells[cOff*numCorners+0] = cone[8];
    535:             cells[cOff*numCorners+1] = cone[5];
    536:             cells[cOff*numCorners+2] = cone[7];
    537:             ++cOff;
    538:             cells[cOff*numCorners+0] = cone[8];
    539:             cells[cOff*numCorners+1] = cone[7];
    540:             cells[cOff*numCorners+2] = cone[1];
    541:             ++cOff;
    542:             break;
    543:           default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %d has %d edges, which we do not support", lid, Ner);
    544:         }
    545:         if (debug) {
    546:           for (t = 0; t < Nt; ++t) {
    547:             PetscPrintf(PETSC_COMM_SELF, "  LOOP Corner NODEs Triangle %D (", t);
    548:             for (c = 0; c < numCorners; ++c) {
    549:               if (c > 0) PetscPrintf(PETSC_COMM_SELF, ", ");
    550:               PetscPrintf(PETSC_COMM_SELF, "%D", cells[(cOff-Nt+t)*numCorners+c]);
    551:             }
    552:             PetscPrintf(PETSC_COMM_SELF, ")\n");
    553:           }
    554:         }
    555:       }
    556:       EG_free(lobjs);
    557:     }
    558:   }
    560:   DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, numCells, numVertices, numCorners, PETSC_TRUE, cells, cdim, coords, &dm);
    561:   PetscFree3(coords, cells, cone);
    562:   PetscInfo(dm, " Total Number of Unique Cells    = %D (%D)\n", numCells, newCells);
    563:   PetscInfo(dm, " Total Number of Unique Vertices = %D (%D)\n", numVertices, newVertices);
    564:   /* Embed EGADS model in DM */
    565:   {
    566:     PetscContainer modelObj, contextObj;

    568:     PetscContainerCreate(PETSC_COMM_SELF, &modelObj);
    569:     PetscContainerSetPointer(modelObj, model);
    570:     PetscObjectCompose((PetscObject) dm, "EGADS Model", (PetscObject) modelObj);
    571:     PetscContainerDestroy(&modelObj);

    573:     PetscContainerCreate(PETSC_COMM_SELF, &contextObj);
    574:     PetscContainerSetPointer(contextObj, context);
    575:     PetscContainerSetUserDestroy(contextObj, DMPlexEGADSDestroy_Private);
    576:     PetscObjectCompose((PetscObject) dm, "EGADS Context", (PetscObject) contextObj);
    577:     PetscContainerDestroy(&contextObj);
    578:   }
    579:   /* Label points */
    580:   DMCreateLabel(dm, "EGADS Body ID");
    581:   DMGetLabel(dm, "EGADS Body ID", &bodyLabel);
    582:   DMCreateLabel(dm, "EGADS Face ID");
    583:   DMGetLabel(dm, "EGADS Face ID", &faceLabel);
    584:   DMCreateLabel(dm, "EGADS Edge ID");
    585:   DMGetLabel(dm, "EGADS Edge ID", &edgeLabel);
    586:   DMCreateLabel(dm, "EGADS Vertex ID");
    587:   DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel);
    588:   cOff = 0;
    589:   for (b = 0; b < nbodies; ++b) {
    590:     ego body = bodies[b];
    591:     int id, Nl, l;

    593:     EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs);
    594:     for (l = 0; l < Nl; ++l) {
    595:       ego  loop = lobjs[l];
    596:       ego *fobjs;
    597:       int  lid, Nf, fid, Ner = 0, Ne, e, Nt = 0, t;

    599:       lid  = EG_indexBodyTopo(body, loop);
    600:       EG_getBodyTopos(body, loop, FACE, &Nf, &fobjs);
    602:       fid  = EG_indexBodyTopo(body, fobjs[0]);
    603:       EG_free(fobjs);
    604:       EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses);
    605:       for (e = 0; e < Ne; ++e) {
    606:         ego             edge = objs[e];
    607:         int             eid, Nv, v;
    608:         PetscInt        points[3], support[2], numEdges, edgeNum;
    609:         const PetscInt *edges;

    611:         eid = EG_indexBodyTopo(body, edge);
    612:         EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);
    613:         if (mtype == DEGENERATE) continue;
    614:         else                     ++Ner;
    615:         for (v = 0; v < Nv; ++v) {
    616:           ego vertex = nobjs[v];

    618:           id   = EG_indexBodyTopo(body, vertex);
    619:           DMLabelSetValue(edgeLabel, numCells + id-1, eid);
    620:           points[v*2] = numCells + id-1;
    621:         }
    622:         PetscHMapIGet(edgeMap, eid-1, &edgeNum);
    623:         points[1] = numCells + numVertices - newVertices + edgeNum;

    625:         DMLabelSetValue(edgeLabel, points[1], eid);
    626:         support[0] = points[0];
    627:         support[1] = points[1];
    628:         DMPlexGetJoin(dm, 2, support, &numEdges, &edges);
    630:         DMLabelSetValue(edgeLabel, edges[0], eid);
    631:         DMPlexRestoreJoin(dm, 2, support, &numEdges, &edges);
    632:         support[0] = points[1];
    633:         support[1] = points[2];
    634:         DMPlexGetJoin(dm, 2, support, &numEdges, &edges);
    636:         DMLabelSetValue(edgeLabel, edges[0], eid);
    637:         DMPlexRestoreJoin(dm, 2, support, &numEdges, &edges);
    638:       }
    639:       switch (Ner) {
    640:         case 2: Nt = 2;break;
    641:         case 3: Nt = 4;break;
    642:         case 4: Nt = 8;break;
    643:         default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Loop with %d edges is unsupported", Ner);
    644:       }
    645:       for (t = 0; t < Nt; ++t) {
    646:         DMLabelSetValue(bodyLabel, cOff+t, b);
    647:         DMLabelSetValue(faceLabel, cOff+t, fid);
    648:       }
    649:       cOff += Nt;
    650:     }
    651:     EG_free(lobjs);
    652:   }
    653:   PetscHMapIDestroy(&edgeMap);
    654:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    655:   for (c = cStart; c < cEnd; ++c) {
    656:     PetscInt *closure = NULL;
    657:     PetscInt  clSize, cl, bval, fval;

    659:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
    660:     DMLabelGetValue(bodyLabel, c, &bval);
    661:     DMLabelGetValue(faceLabel, c, &fval);
    662:     for (cl = 0; cl < clSize*2; cl += 2) {
    663:       DMLabelSetValue(bodyLabel, closure[cl], bval);
    664:       DMLabelSetValue(faceLabel, closure[cl], fval);
    665:     }
    666:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
    667:   }
    668:   *newdm = dm;
    669:   return 0;
    670: }

    672: static PetscErrorCode DMPlexCreateEGADS(MPI_Comm comm, ego context, ego model, DM *newdm)
    673: {
    674:   DMLabel         bodyLabel, faceLabel, edgeLabel, vertexLabel;
    675:   // EGADS/EGADSLite variables
    676:   ego             geom, *bodies, *mobjs, *fobjs, *lobjs, *eobjs, *nobjs;
    677:   ego             topRef, prev, next;
    678:   int             oclass, mtype, nbodies, *senses, *lSenses, *eSenses;
    679:   int             b;
    680:   // PETSc variables
    681:   DM              dm;
    682:   PetscHMapI      edgeMap = NULL, bodyIndexMap = NULL, bodyVertexMap = NULL, bodyEdgeMap = NULL, bodyFaceMap = NULL, bodyEdgeGlobalMap = NULL;
    683:   PetscInt        dim = -1, cdim = -1, numCorners = 0, numVertices = 0, numEdges = 0, numFaces = 0, numCells = 0, edgeCntr = 0;
    684:   PetscInt        cellCntr = 0, numPoints = 0;
    685:   PetscInt        *cells  = NULL;
    686:   const PetscInt  *cone = NULL;
    687:   PetscReal       *coords = NULL;
    688:   PetscMPIInt      rank;

    691:   MPI_Comm_rank(comm, &rank);
    692:   if (!rank) {
    693:     // ---------------------------------------------------------------------------------------------------
    694:     // Generate Petsc Plex
    695:     //  Get all Nodes in model, record coordinates in a correctly formatted array
    696:     //  Cycle through bodies, cycle through loops, recorde NODE IDs in a correctly formatted array
    697:     //  We need to uniformly refine the initial geometry to guarantee a valid mesh

    699:   // Caluculate cell and vertex sizes
    700:   EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses);

    702:     PetscHMapICreate(&edgeMap);
    703:   PetscHMapICreate(&bodyIndexMap);
    704:   PetscHMapICreate(&bodyVertexMap);
    705:   PetscHMapICreate(&bodyEdgeMap);
    706:   PetscHMapICreate(&bodyEdgeGlobalMap);
    707:   PetscHMapICreate(&bodyFaceMap);

    709:   for (b = 0; b < nbodies; ++b) {
    710:       ego             body = bodies[b];
    711:     int             Nf, Ne, Nv;
    712:     PetscHashIter   BIiter, BViter, BEiter, BEGiter, BFiter, EMiter;
    713:     PetscBool       BIfound, BVfound, BEfound, BEGfound, BFfound, EMfound;

    715:     PetscHMapIFind(bodyIndexMap, b, &BIiter, &BIfound);
    716:     PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound);
    717:     PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound);
    718:     PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound);
    719:     PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound);

    721:     if (!BIfound)  PetscHMapISet(bodyIndexMap, b, numFaces + numEdges + numVertices);
    722:     if (!BVfound)  PetscHMapISet(bodyVertexMap, b, numVertices);
    723:     if (!BEfound)  PetscHMapISet(bodyEdgeMap, b, numEdges);
    724:     if (!BEGfound) PetscHMapISet(bodyEdgeGlobalMap, b, edgeCntr);
    725:     if (!BFfound)  PetscHMapISet(bodyFaceMap, b, numFaces);

    727:     EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs);
    728:     EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs);
    729:     EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs);
    730:     EG_free(fobjs);
    731:     EG_free(eobjs);
    732:     EG_free(nobjs);

    734:     // Remove DEGENERATE EDGES from Edge count
    735:     EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs);
    736:     int Netemp = 0;
    737:     for (int e = 0; e < Ne; ++e) {
    738:       ego     edge = eobjs[e];
    739:       int     eid;

    741:       EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next);
    742:       eid = EG_indexBodyTopo(body, edge);

    744:       PetscHMapIFind(edgeMap, edgeCntr + eid - 1, &EMiter, &EMfound);
    745:       if (mtype == DEGENERATE) {
    746:         if (!EMfound) PetscHMapISet(edgeMap, edgeCntr + eid - 1, -1);
    747:       }
    748:       else {
    749:       ++Netemp;
    750:         if (!EMfound) PetscHMapISet(edgeMap, edgeCntr + eid - 1, Netemp);
    751:       }
    752:     }
    753:     EG_free(eobjs);

    755:     // Determine Number of Cells
    756:     EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs);
    757:     for (int f = 0; f < Nf; ++f) {
    758:         ego     face = fobjs[f];
    759:     int     edgeTemp = 0;

    761:       EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs);
    762:       for (int e = 0; e < Ne; ++e) {
    763:         ego     edge = eobjs[e];

    765:         EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next);
    766:         if (mtype != DEGENERATE) {++edgeTemp;}
    767:       }
    768:       numCells += (2 * edgeTemp);
    769:       EG_free(eobjs);
    770:     }
    771:     EG_free(fobjs);

    773:     numFaces    += Nf;
    774:     numEdges    += Netemp;
    775:     numVertices += Nv;
    776:     edgeCntr    += Ne;
    777:   }

    779:   // Set up basic DMPlex parameters
    780:   dim        = 2;    // Assumes 3D Models :: Need to handle 2D modles in the future
    781:   cdim       = 3;     // Assumes 3D Models :: Need to update to handle 2D modles in future
    782:   numCorners = 3;     // Split Faces into triangles
    783:     numPoints  = numVertices + numEdges + numFaces;   // total number of coordinate points

    785:   PetscMalloc2(numPoints*cdim, &coords, numCells*numCorners, &cells);

    787:   // Get Vertex Coordinates and Set up Cells
    788:   for (b = 0; b < nbodies; ++b) {
    789:     ego             body = bodies[b];
    790:     int             Nf, Ne, Nv;
    791:     PetscInt        bodyVertexIndexStart, bodyEdgeIndexStart, bodyEdgeGlobalIndexStart, bodyFaceIndexStart;
    792:     PetscHashIter   BViter, BEiter, BEGiter, BFiter, EMiter;
    793:     PetscBool       BVfound, BEfound, BEGfound, BFfound, EMfound;

    795:     // Vertices on Current Body
    796:     EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs);

    798:     PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound);
    800:     PetscHMapIGet(bodyVertexMap, b, &bodyVertexIndexStart);

    802:     for (int v = 0; v < Nv; ++v) {
    803:       ego    vertex = nobjs[v];
    804:     double limits[4];
    805:     int    id, dummy;

    807:     EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses);
    808:     id = EG_indexBodyTopo(body, vertex);

    810:     coords[(bodyVertexIndexStart + id - 1)*cdim + 0] = limits[0];
    811:     coords[(bodyVertexIndexStart + id - 1)*cdim + 1] = limits[1];
    812:     coords[(bodyVertexIndexStart + id - 1)*cdim + 2] = limits[2];
    813:     }
    814:     EG_free(nobjs);

    816:     // Edge Midpoint Vertices on Current Body
    817:     EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs);

    819:     PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound);
    821:     PetscHMapIGet(bodyEdgeMap, b, &bodyEdgeIndexStart);

    823:     PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound);
    825:     PetscHMapIGet(bodyEdgeGlobalMap, b, &bodyEdgeGlobalIndexStart);

    827:     for (int e = 0; e < Ne; ++e) {
    828:       ego          edge = eobjs[e];
    829:     double       range[2], avgt[1], cntrPnt[9];
    830:     int          eid, eOffset;
    831:     int          periodic;

    833:     EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next);
    834:     if (mtype == DEGENERATE) {continue;}

    836:     eid = EG_indexBodyTopo(body, edge);

    838:     // get relative offset from globalEdgeID Vector
    839:     PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound);
    841:       PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset);

    843:     EG_getRange(edge, range, &periodic);
    844:     avgt[0] = (range[0] + range[1]) /  2.;

    846:     EG_evaluate(edge, avgt, cntrPnt);
    847:     coords[(numVertices + bodyEdgeIndexStart + eOffset - 1)*cdim + 0] = cntrPnt[0];
    848:         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1)*cdim + 1] = cntrPnt[1];
    849:     coords[(numVertices + bodyEdgeIndexStart + eOffset - 1)*cdim + 2] = cntrPnt[2];
    850:     }
    851:     EG_free(eobjs);

    853:     // Face Midpoint Vertices on Current Body
    854:     EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs);

    856:     PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound);
    858:     PetscHMapIGet(bodyFaceMap, b, &bodyFaceIndexStart);

    860:     for (int f = 0; f < Nf; ++f) {
    861:     ego       face = fobjs[f];
    862:     double    range[4], avgUV[2], cntrPnt[18];
    863:     int       peri, id;

    865:     id = EG_indexBodyTopo(body, face);
    866:     EG_getRange(face, range, &peri);

    868:     avgUV[0] = (range[0] + range[1]) / 2.;
    869:     avgUV[1] = (range[2] + range[3]) / 2.;
    870:     EG_evaluate(face, avgUV, cntrPnt);

    872:     coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1)*cdim + 0] = cntrPnt[0];
    873:     coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1)*cdim + 1] = cntrPnt[1];
    874:     coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1)*cdim + 2] = cntrPnt[2];
    875:     }
    876:     EG_free(fobjs);

    878:     // Define Cells :: Note - This could be incorporated in the Face Midpoint Vertices Loop but was kept separate for clarity
    879:     EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs);
    880:     for (int f = 0; f < Nf; ++f) {
    881:     ego      face = fobjs[f];
    882:     int      fID, midFaceID, midPntID, startID, endID, Nl;

    884:     fID = EG_indexBodyTopo(body, face);
    885:     midFaceID = numVertices + numEdges + bodyFaceIndexStart + fID - 1;
    886:     // Must Traverse Loop to ensure we have all necessary information like the sense (+/- 1) of the edges.
    887:     // TODO :: Only handles single loop faces (No holes). The choices for handling multiloop faces are:
    888:     //            1) Use the DMPlexCreateEGADSFromFile() with the -dm_plex_egads_with_tess = 1 option.
    889:     //               This will use a default EGADS tessellation as an initial surface mesh.
    890:     //            2) Create the initial surface mesh via a 2D mesher :: Currently not availble (?future?)
    891:     //               May I suggest the XXXX as a starting point?

    893:     EG_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lSenses);

    896:     for (int l = 0; l < Nl; ++l) {
    897:           ego      loop = lobjs[l];

    899:           EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses);
    900:       for (int e = 0; e < Ne; ++e) {
    901:         ego     edge = eobjs[e];
    902:         int     eid, eOffset;

    904:         EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next);
    905:       eid = EG_indexBodyTopo(body, edge);
    906:         if (mtype == DEGENERATE) { continue; }

    908:         // get relative offset from globalEdgeID Vector
    909:         PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound);
    911:           PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset);

    913:       midPntID = numVertices + bodyEdgeIndexStart + eOffset - 1;

    915:         EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses);

    917:         if (eSenses[e] > 0) { startID = EG_indexBodyTopo(body, nobjs[0]); endID = EG_indexBodyTopo(body, nobjs[1]); }
    918:         else { startID = EG_indexBodyTopo(body, nobjs[1]); endID = EG_indexBodyTopo(body, nobjs[0]); }

    920:       // Define 2 Cells per Edge with correct orientation
    921:       cells[cellCntr*numCorners + 0] = midFaceID;
    922:       cells[cellCntr*numCorners + 1] = bodyVertexIndexStart + startID - 1;
    923:       cells[cellCntr*numCorners + 2] = midPntID;

    925:       cells[cellCntr*numCorners + 3] = midFaceID;
    926:       cells[cellCntr*numCorners + 4] = midPntID;
    927:       cells[cellCntr*numCorners + 5] = bodyVertexIndexStart + endID - 1;

    929:       cellCntr = cellCntr + 2;
    930:       }
    931:     }
    932:     }
    933:     EG_free(fobjs);
    934:   }
    935:   }

    937:   // Generate DMPlex
    938:   DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, numCells, numPoints, numCorners, PETSC_TRUE, cells, cdim, coords, &dm);
    939:   PetscFree2(coords, cells);
    940:   PetscInfo(dm, " Total Number of Unique Cells    = %D \n", numCells);
    941:   PetscInfo(dm, " Total Number of Unique Vertices = %D \n", numVertices);

    943:   // Embed EGADS model in DM
    944:   {
    945:     PetscContainer modelObj, contextObj;

    947:     PetscContainerCreate(PETSC_COMM_SELF, &modelObj);
    948:     PetscContainerSetPointer(modelObj, model);
    949:     PetscObjectCompose((PetscObject) dm, "EGADS Model", (PetscObject) modelObj);
    950:     PetscContainerDestroy(&modelObj);

    952:     PetscContainerCreate(PETSC_COMM_SELF, &contextObj);
    953:     PetscContainerSetPointer(contextObj, context);
    954:     PetscContainerSetUserDestroy(contextObj, DMPlexEGADSDestroy_Private);
    955:     PetscObjectCompose((PetscObject) dm, "EGADS Context", (PetscObject) contextObj);
    956:     PetscContainerDestroy(&contextObj);
    957:   }
    958:   // Label points
    959:   PetscInt   nStart, nEnd;

    961:   DMCreateLabel(dm, "EGADS Body ID");
    962:   DMGetLabel(dm, "EGADS Body ID", &bodyLabel);
    963:   DMCreateLabel(dm, "EGADS Face ID");
    964:   DMGetLabel(dm, "EGADS Face ID", &faceLabel);
    965:   DMCreateLabel(dm, "EGADS Edge ID");
    966:   DMGetLabel(dm, "EGADS Edge ID", &edgeLabel);
    967:   DMCreateLabel(dm, "EGADS Vertex ID");
    968:   DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel);

    970:   DMPlexGetHeightStratum(dm, 2, &nStart, &nEnd);

    972:   cellCntr = 0;
    973:   for (b = 0; b < nbodies; ++b) {
    974:     ego             body = bodies[b];
    975:   int             Nv, Ne, Nf;
    976:   PetscInt        bodyVertexIndexStart, bodyEdgeIndexStart, bodyEdgeGlobalIndexStart, bodyFaceIndexStart;
    977:   PetscHashIter   BViter, BEiter, BEGiter, BFiter, EMiter;
    978:   PetscBool       BVfound, BEfound, BEGfound, BFfound, EMfound;

    980:   PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound);
    982:   PetscHMapIGet(bodyVertexMap, b, &bodyVertexIndexStart);

    984:   PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound);
    986:   PetscHMapIGet(bodyEdgeMap, b, &bodyEdgeIndexStart);

    988:     PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound);
    990:   PetscHMapIGet(bodyFaceMap, b, &bodyFaceIndexStart);

    992:     PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound);
    994:     PetscHMapIGet(bodyEdgeGlobalMap, b, &bodyEdgeGlobalIndexStart);

    996:   EG_getBodyTopos(body, NULL, FACE,  &Nf, &fobjs);
    997:   for (int f = 0; f < Nf; ++f) {
    998:     ego   face = fobjs[f];
    999:       int   fID, Nl;

    1001:     fID  = EG_indexBodyTopo(body, face);

    1003:     EG_getBodyTopos(body, face, LOOP, &Nl, &lobjs);
    1004:     for (int l = 0; l < Nl; ++l) {
    1005:         ego  loop = lobjs[l];
    1006:     int  lid;

    1008:     lid  = EG_indexBodyTopo(body, loop);

    1011:     EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses);
    1012:     for (int e = 0; e < Ne; ++e) {
    1013:       ego     edge = eobjs[e];
    1014:       int     eid, eOffset;

    1016:       // Skip DEGENERATE Edges
    1017:       EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next);
    1018:       if (mtype == DEGENERATE) {continue;}
    1019:       eid = EG_indexBodyTopo(body, edge);

    1021:       // get relative offset from globalEdgeID Vector
    1022:       PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound);
    1024:       PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset);

    1026:       EG_getBodyTopos(body, edge, NODE, &Nv, &nobjs);
    1027:       for (int v = 0; v < Nv; ++v){
    1028:         ego vertex = nobjs[v];
    1029:         int vID;

    1031:         vID = EG_indexBodyTopo(body, vertex);
    1032:         DMLabelSetValue(bodyLabel, nStart + bodyVertexIndexStart + vID - 1, b);
    1033:         DMLabelSetValue(vertexLabel, nStart + bodyVertexIndexStart + vID - 1, vID);
    1034:       }
    1035:       EG_free(nobjs);

    1037:       DMLabelSetValue(bodyLabel, nStart + numVertices + bodyEdgeIndexStart + eOffset - 1, b);
    1038:       DMLabelSetValue(edgeLabel, nStart + numVertices + bodyEdgeIndexStart + eOffset - 1, eid);

    1040:       // Define Cell faces
    1041:       for (int jj = 0; jj < 2; ++jj){
    1042:         DMLabelSetValue(bodyLabel, cellCntr, b);
    1043:         DMLabelSetValue(faceLabel, cellCntr, fID);
    1044:         DMPlexGetCone(dm, cellCntr, &cone);

    1046:         DMLabelSetValue(bodyLabel, cone[0], b);
    1047:         DMLabelSetValue(faceLabel, cone[0], fID);

    1049:         DMLabelSetValue(bodyLabel, cone[1], b);
    1050:         DMLabelSetValue(edgeLabel, cone[1], eid);

    1052:        DMLabelSetValue(bodyLabel, cone[2], b);
    1053:        DMLabelSetValue(faceLabel, cone[2], fID);

    1055:        cellCntr = cellCntr + 1;
    1056:       }
    1057:     }
    1058:     }
    1059:     EG_free(lobjs);

    1061:     DMLabelSetValue(bodyLabel, nStart + numVertices + numEdges + bodyFaceIndexStart + fID - 1, b);
    1062:     DMLabelSetValue(faceLabel, nStart + numVertices + numEdges + bodyFaceIndexStart + fID - 1, fID);
    1063:   }
    1064:   EG_free(fobjs);
    1065:   }

    1067:   PetscHMapIDestroy(&edgeMap);
    1068:   PetscHMapIDestroy(&bodyIndexMap);
    1069:   PetscHMapIDestroy(&bodyVertexMap);
    1070:   PetscHMapIDestroy(&bodyEdgeMap);
    1071:   PetscHMapIDestroy(&bodyEdgeGlobalMap);
    1072:   PetscHMapIDestroy(&bodyFaceMap);

    1074:   *newdm = dm;
    1075:   return 0;
    1076: }

    1078: static PetscErrorCode DMPlexCreateEGADS_Tess_Internal(MPI_Comm comm, ego context, ego model, DM *newdm)
    1079: {
    1080:   DMLabel              bodyLabel, faceLabel, edgeLabel, vertexLabel;
    1081:   /* EGADSLite variables */
    1082:   ego                  geom, *bodies, *fobjs;
    1083:   int                  b, oclass, mtype, nbodies, *senses;
    1084:   int                  totalNumTris = 0, totalNumPoints = 0;
    1085:   double               boundBox[6] = {0., 0., 0., 0., 0., 0.}, tessSize;
    1086:   /* PETSc variables */
    1087:   DM                   dm;
    1088:   PetscHMapI           pointIndexStartMap = NULL, triIndexStartMap = NULL, pTypeLabelMap = NULL, pIndexLabelMap = NULL;
    1089:   PetscHMapI           pBodyIndexLabelMap = NULL, triFaceIDLabelMap = NULL, triBodyIDLabelMap = NULL;
    1090:   PetscInt             dim = -1, cdim = -1, numCorners = 0, counter = 0;
    1091:   PetscInt            *cells  = NULL;
    1092:   const PetscInt      *cone = NULL;
    1093:   PetscReal           *coords = NULL;
    1094:   PetscMPIInt          rank;

    1097:   MPI_Comm_rank(comm, &rank);
    1098:   if (!rank) {
    1099:     // ---------------------------------------------------------------------------------------------------
    1100:     // Generate Petsc Plex from EGADSlite created Tessellation of geometry
    1101:     // ---------------------------------------------------------------------------------------------------

    1103:   // Caluculate cell and vertex sizes
    1104:   EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses);

    1106:   PetscHMapICreate(&pointIndexStartMap);
    1107:   PetscHMapICreate(&triIndexStartMap);
    1108:   PetscHMapICreate(&pTypeLabelMap);
    1109:   PetscHMapICreate(&pIndexLabelMap);
    1110:   PetscHMapICreate(&pBodyIndexLabelMap);
    1111:   PetscHMapICreate(&triFaceIDLabelMap);
    1112:   PetscHMapICreate(&triBodyIDLabelMap);

    1114:   /* Create Tessellation of Bodies */
    1115:   ego tessArray[nbodies];

    1117:   for (b = 0; b < nbodies; ++b) {
    1118:     ego             body = bodies[b];
    1119:     double          params[3] = {0.0, 0.0, 0.0};    // Parameters for Tessellation
    1120:     int             Nf, bodyNumPoints = 0, bodyNumTris = 0;
    1121:     PetscHashIter   PISiter, TISiter;
    1122:     PetscBool       PISfound, TISfound;

    1124:     /* Store Start Index for each Body's Point and Tris */
    1125:     PetscHMapIFind(pointIndexStartMap, b, &PISiter, &PISfound);
    1126:     PetscHMapIFind(triIndexStartMap, b, &TISiter, &TISfound);

    1128:     if (!PISfound)  PetscHMapISet(pointIndexStartMap, b, totalNumPoints);
    1129:     if (!TISfound)  PetscHMapISet(triIndexStartMap, b, totalNumTris);

    1131:     /* Calculate Tessellation parameters based on Bounding Box */
    1132:     /* Get Bounding Box Dimensions of the BODY */
    1133:     EG_getBoundingBox(body, boundBox);
    1134:     tessSize = boundBox[3] - boundBox[0];
    1135:     if (tessSize < boundBox[4] - boundBox[1]) tessSize = boundBox[4] - boundBox[1];
    1136:     if (tessSize < boundBox[5] - boundBox[2]) tessSize = boundBox[5] - boundBox[2];

    1138:     // TODO :: May want to give users tessellation parameter options //
    1139:     params[0] = 0.0250 * tessSize;
    1140:     params[1] = 0.0075 * tessSize;
    1141:     params[2] = 15.0;

    1143:     EG_makeTessBody(body, params, &tessArray[b]);

    1145:     EG_getBodyTopos(body, NULL, FACE,  &Nf, &fobjs);

    1147:     for (int f = 0; f < Nf; ++f) {
    1148:       ego             face = fobjs[f];
    1149:     int             len, fID, ntris;
    1150:     const int      *ptype, *pindex, *ptris, *ptric;
    1151:     const double   *pxyz, *puv;

    1153:     // Get Face ID //
    1154:     fID = EG_indexBodyTopo(body, face);

    1156:     // Checkout the Surface Tessellation //
    1157:     EG_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric);

    1159:     // Determine total number of triangle cells in the tessellation //
    1160:     bodyNumTris += (int) ntris;

    1162:     // Check out the point index and coordinate //
    1163:     for (int p = 0; p < len; ++p) {
    1164:         int global;

    1166:         EG_localToGlobal(tessArray[b], fID, p+1, &global);

    1168:       // Determine the total number of points in the tessellation //
    1169:         bodyNumPoints = PetscMax(bodyNumPoints, global);
    1170:     }
    1171:     }
    1172:     EG_free(fobjs);

    1174:     totalNumPoints += bodyNumPoints;
    1175:     totalNumTris += bodyNumTris;
    1176:     }
    1177:   //}  - Original End of (!rank)

    1179:   dim = 2;
    1180:   cdim = 3;
    1181:   numCorners = 3;
    1182:   //PetscInt counter = 0;

    1184:   /* NEED TO DEFINE MATRICES/VECTORS TO STORE GEOM REFERENCE DATA   */
    1185:   /* Fill in below and use to define DMLabels after DMPlex creation */
    1186:   PetscMalloc2(totalNumPoints*cdim, &coords, totalNumTris*numCorners, &cells);

    1188:   for (b = 0; b < nbodies; ++b) {
    1189:   ego             body = bodies[b];
    1190:   int             Nf;
    1191:   PetscInt        pointIndexStart;
    1192:   PetscHashIter   PISiter;
    1193:   PetscBool       PISfound;

    1195:   PetscHMapIFind(pointIndexStartMap, b, &PISiter, &PISfound);
    1197:   PetscHMapIGet(pointIndexStartMap, b, &pointIndexStart);

    1199:   EG_getBodyTopos(body, NULL, FACE,  &Nf, &fobjs);

    1201:   for (int f = 0; f < Nf; ++f) {
    1202:     /* Get Face Object */
    1203:     ego              face = fobjs[f];
    1204:     int              len, fID, ntris;
    1205:     const int       *ptype, *pindex, *ptris, *ptric;
    1206:     const double    *pxyz, *puv;

    1208:     /* Get Face ID */
    1209:     fID = EG_indexBodyTopo(body, face);

    1211:     /* Checkout the Surface Tessellation */
    1212:     EG_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric);

    1214:     /* Check out the point index and coordinate */
    1215:     for (int p = 0; p < len; ++p) {
    1216:     int              global;
    1217:     PetscHashIter    PTLiter, PILiter, PBLiter;
    1218:     PetscBool        PTLfound, PILfound, PBLfound;

    1220:     EG_localToGlobal(tessArray[b], fID, p+1, &global);

    1222:     /* Set the coordinates array for DAG */
    1223:     coords[((global-1+pointIndexStart)*3) + 0] = pxyz[(p*3)+0];
    1224:     coords[((global-1+pointIndexStart)*3) + 1] = pxyz[(p*3)+1];
    1225:     coords[((global-1+pointIndexStart)*3) + 2] = pxyz[(p*3)+2];

    1227:     /* Store Geometry Label Information for DMLabel assignment later */
    1228:     PetscHMapIFind(pTypeLabelMap, global-1+pointIndexStart, &PTLiter, &PTLfound);
    1229:     PetscHMapIFind(pIndexLabelMap, global-1+pointIndexStart, &PILiter, &PILfound);
    1230:     PetscHMapIFind(pBodyIndexLabelMap, global-1+pointIndexStart, &PBLiter, &PBLfound);

    1232:     if (!PTLfound) PetscHMapISet(pTypeLabelMap, global-1+pointIndexStart, ptype[p]);
    1233:     if (!PILfound) PetscHMapISet(pIndexLabelMap, global-1+pointIndexStart, pindex[p]);
    1234:     if (!PBLfound) PetscHMapISet(pBodyIndexLabelMap, global-1+pointIndexStart, b);

    1236:     if (ptype[p] < 0) PetscHMapISet(pIndexLabelMap, global-1+pointIndexStart, fID);
    1237:     }

    1239:     for (int t = 0; t < (int) ntris; ++t){
    1240:     int           global, globalA, globalB;
    1241:     PetscHashIter TFLiter, TBLiter;
    1242:     PetscBool     TFLfound, TBLfound;

    1244:     EG_localToGlobal(tessArray[b], fID, ptris[(t*3) + 0], &global);
    1245:     cells[(counter*3) +0] = global-1+pointIndexStart;

    1247:     EG_localToGlobal(tessArray[b], fID, ptris[(t*3) + 1], &globalA);
    1248:     cells[(counter*3) +1] = globalA-1+pointIndexStart;

    1250:     EG_localToGlobal(tessArray[b], fID, ptris[(t*3) + 2], &globalB);
    1251:     cells[(counter*3) +2] = globalB-1+pointIndexStart;

    1253:     PetscHMapIFind(triFaceIDLabelMap, counter, &TFLiter, &TFLfound);
    1254:         PetscHMapIFind(triBodyIDLabelMap, counter, &TBLiter, &TBLfound);

    1256:     if (!TFLfound)  PetscHMapISet(triFaceIDLabelMap, counter, fID);
    1257:         if (!TBLfound)  PetscHMapISet(triBodyIDLabelMap, counter, b);

    1259:     counter += 1;
    1260:     }
    1261:   }
    1262:   EG_free(fobjs);
    1263:   }
    1264: }

    1266:   //Build DMPlex
    1267:   DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, totalNumTris, totalNumPoints, numCorners, PETSC_TRUE, cells, cdim, coords, &dm);
    1268:   PetscFree2(coords, cells);

    1270:   // Embed EGADS model in DM
    1271:   {
    1272:     PetscContainer modelObj, contextObj;

    1274:     PetscContainerCreate(PETSC_COMM_SELF, &modelObj);
    1275:     PetscContainerSetPointer(modelObj, model);
    1276:     PetscObjectCompose((PetscObject) dm, "EGADS Model", (PetscObject) modelObj);
    1277:     PetscContainerDestroy(&modelObj);

    1279:     PetscContainerCreate(PETSC_COMM_SELF, &contextObj);
    1280:     PetscContainerSetPointer(contextObj, context);
    1281:     PetscContainerSetUserDestroy(contextObj, DMPlexEGADSDestroy_Private);
    1282:     PetscObjectCompose((PetscObject) dm, "EGADS Context", (PetscObject) contextObj);
    1283:     PetscContainerDestroy(&contextObj);
    1284:   }

    1286:   // Label Points
    1287:   DMCreateLabel(dm, "EGADS Body ID");
    1288:   DMGetLabel(dm, "EGADS Body ID", &bodyLabel);
    1289:   DMCreateLabel(dm, "EGADS Face ID");
    1290:   DMGetLabel(dm, "EGADS Face ID", &faceLabel);
    1291:   DMCreateLabel(dm, "EGADS Edge ID");
    1292:   DMGetLabel(dm, "EGADS Edge ID", &edgeLabel);
    1293:   DMCreateLabel(dm, "EGADS Vertex ID");
    1294:   DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel);

    1296:    /* Get Number of DAG Nodes at each level */
    1297:   int   fStart, fEnd, eStart, eEnd, nStart, nEnd;

    1299:   DMPlexGetHeightStratum(dm, 0, &fStart, &fEnd);
    1300:   DMPlexGetHeightStratum(dm, 1, &eStart, &eEnd);
    1301:   DMPlexGetHeightStratum(dm, 2, &nStart, &nEnd);

    1303:   /* Set DMLabels for NODES */
    1304:   for (int n = nStart; n < nEnd; ++n) {
    1305:     int             pTypeVal, pIndexVal, pBodyVal;
    1306:     PetscHashIter   PTLiter, PILiter, PBLiter;
    1307:     PetscBool       PTLfound, PILfound, PBLfound;

    1309:     //Converted to Hash Tables
    1310:     PetscHMapIFind(pTypeLabelMap, n - nStart, &PTLiter, &PTLfound);
    1312:     PetscHMapIGet(pTypeLabelMap, n - nStart, &pTypeVal);

    1314:     PetscHMapIFind(pIndexLabelMap, n - nStart, &PILiter, &PILfound);
    1316:     PetscHMapIGet(pIndexLabelMap, n - nStart, &pIndexVal);

    1318:     PetscHMapIFind(pBodyIndexLabelMap, n - nStart, &PBLiter, &PBLfound);
    1320:     PetscHMapIGet(pBodyIndexLabelMap, n - nStart, &pBodyVal);

    1322:     DMLabelSetValue(bodyLabel, n, pBodyVal);
    1323:     if (pTypeVal == 0) DMLabelSetValue(vertexLabel, n, pIndexVal);
    1324:     if (pTypeVal >  0) DMLabelSetValue(edgeLabel, n, pIndexVal);
    1325:     if (pTypeVal <  0) DMLabelSetValue(faceLabel, n, pIndexVal);
    1326:   }

    1328:   /* Set DMLabels for Edges - Based on the DMLabels of the EDGE's NODES */
    1329:   for (int e = eStart; e < eEnd; ++e) {
    1330:   int    bodyID_0, vertexID_0, vertexID_1, edgeID_0, edgeID_1, faceID_0, faceID_1;

    1332:   DMPlexGetCone(dm, e, &cone);
    1333:   DMLabelGetValue(bodyLabel, cone[0], &bodyID_0);    // Do I need to check the other end?
    1334:   DMLabelGetValue(vertexLabel, cone[0], &vertexID_0);
    1335:   DMLabelGetValue(vertexLabel, cone[1], &vertexID_1);
    1336:   DMLabelGetValue(edgeLabel, cone[0], &edgeID_0);
    1337:   DMLabelGetValue(edgeLabel, cone[1], &edgeID_1);
    1338:   DMLabelGetValue(faceLabel, cone[0], &faceID_0);
    1339:   DMLabelGetValue(faceLabel, cone[1], &faceID_1);

    1341:   DMLabelSetValue(bodyLabel, e, bodyID_0);

    1343:   if (edgeID_0 == edgeID_1) DMLabelSetValue(edgeLabel, e, edgeID_0);
    1344:   else if (vertexID_0 > 0 && edgeID_1 > 0) DMLabelSetValue(edgeLabel, e, edgeID_1);
    1345:   else if (vertexID_1 > 0 && edgeID_0 > 0) DMLabelSetValue(edgeLabel, e, edgeID_0);
    1346:   else { /* Do Nothing */ }
    1347:   }

    1349:   /* Set DMLabels for Cells */
    1350:   for (int f = fStart; f < fEnd; ++f){
    1351:   int             edgeID_0;
    1352:   PetscInt        triBodyVal, triFaceVal;
    1353:   PetscHashIter   TFLiter, TBLiter;
    1354:   PetscBool       TFLfound, TBLfound;

    1356:     // Convert to Hash Table
    1357:   PetscHMapIFind(triFaceIDLabelMap, f - fStart, &TFLiter, &TFLfound);
    1359:   PetscHMapIGet(triFaceIDLabelMap, f - fStart, &triFaceVal);

    1361:   PetscHMapIFind(triBodyIDLabelMap, f - fStart, &TBLiter, &TBLfound);
    1363:     PetscHMapIGet(triBodyIDLabelMap, f - fStart, &triBodyVal);

    1365:   DMLabelSetValue(bodyLabel, f, triBodyVal);
    1366:   DMLabelSetValue(faceLabel, f, triFaceVal);

    1368:   /* Finish Labeling previously unlabeled DMPlex Edges - Assumes Triangular Cell (3 Edges Max) */
    1369:   DMPlexGetCone(dm, f, &cone);

    1371:   for (int jj = 0; jj < 3; ++jj) {
    1372:     DMLabelGetValue(edgeLabel, cone[jj], &edgeID_0);

    1374:     if (edgeID_0 < 0) {
    1375:     DMLabelSetValue(bodyLabel, cone[jj], triBodyVal);
    1376:       DMLabelSetValue(faceLabel, cone[jj], triFaceVal);
    1377:     }
    1378:   }
    1379:   }

    1381:   *newdm = dm;
    1382:   return 0;
    1383: }
    1384: #endif

    1386: /*@
    1387:   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:   Collective on dm

    1391:   Input Parameter:
    1392: . dm - The uninflated DM object representing the mesh

    1394:   Output Parameter:
    1395: . dm - The inflated DM object representing the mesh

    1397:   Level: intermediate

    1399: .seealso: DMPLEX, DMCreate(), DMPlexCreateEGADS()
    1400: @*/
    1401: PetscErrorCode DMPlexInflateToGeomModel(DM dm)
    1402: {
    1403: #if defined(PETSC_HAVE_EGADS)
    1404:   /* EGADS Variables */
    1405:   ego            model, geom, body, face, edge;
    1406:   ego           *bodies;
    1407:   int            Nb, oclass, mtype, *senses;
    1408:   double         result[3];
    1409:   /* PETSc Variables */
    1410:   DM             cdm;
    1411:   PetscContainer modelObj;
    1412:   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
    1413:   Vec            coordinates;
    1414:   PetscScalar   *coords;
    1415:   PetscInt       bodyID, faceID, edgeID, vertexID;
    1416:   PetscInt       cdim, d, vStart, vEnd, v;
    1417: #endif

    1419: #if defined(PETSC_HAVE_EGADS)
    1420:   PetscObjectQuery((PetscObject) dm, "EGADS Model", (PetscObject *) &modelObj);
    1421:   if (!modelObj) return 0;
    1422:   DMGetCoordinateDim(dm, &cdim);
    1423:   DMGetCoordinateDM(dm, &cdm);
    1424:   DMGetCoordinatesLocal(dm, &coordinates);
    1425:   DMGetLabel(dm, "EGADS Body ID", &bodyLabel);
    1426:   DMGetLabel(dm, "EGADS Face ID", &faceLabel);
    1427:   DMGetLabel(dm, "EGADS Edge ID", &edgeLabel);
    1428:   DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel);

    1430:   PetscContainerGetPointer(modelObj, (void **) &model);
    1431:   EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses);

    1433:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    1434:   VecGetArrayWrite(coordinates, &coords);
    1435:   for (v = vStart; v < vEnd; ++v) {
    1436:     PetscScalar *vcoords;

    1438:     DMLabelGetValue(bodyLabel, v, &bodyID);
    1439:     DMLabelGetValue(faceLabel, v, &faceID);
    1440:     DMLabelGetValue(edgeLabel, v, &edgeID);
    1441:     DMLabelGetValue(vertexLabel, v, &vertexID);

    1444:     body = bodies[bodyID];

    1446:     DMPlexPointLocalRef(cdm, v, coords, (void *) &vcoords);
    1447:     if (edgeID > 0) {
    1448:       /* Snap to EDGE at nearest location */
    1449:       double params[1];
    1450:       EG_objectBodyTopo(body, EDGE, edgeID, &edge);
    1451:       EG_invEvaluate(edge, vcoords, params, result); // Get (x,y,z) of nearest point on EDGE
    1452:       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
    1453:     } else if (faceID > 0) {
    1454:       /* Snap to FACE at nearest location */
    1455:       double params[2];
    1456:       EG_objectBodyTopo(body, FACE, faceID, &face);
    1457:       EG_invEvaluate(face, vcoords, params, result); // Get (x,y,z) of nearest point on FACE
    1458:       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
    1459:     }
    1460:   }
    1461:   VecRestoreArrayWrite(coordinates, &coords);
    1462:   /* Clear out global coordinates */
    1463:   VecDestroy(&dm->coordinates);
    1464: #endif
    1465:   return 0;
    1466: }

    1468: /*@C
    1469:   DMPlexCreateEGADSFromFile - Create a DMPlex mesh from an EGADS, IGES, or STEP file.

    1471:   Collective

    1473:   Input Parameters:
    1474: + comm     - The MPI communicator
    1475: - filename - The name of the EGADS, IGES, or STEP file

    1477:   Output Parameter:
    1478: . dm       - The DM object representing the mesh

    1480:   Level: beginner

    1482: .seealso: DMPLEX, DMCreate(), DMPlexCreateEGADS(), DMPlexCreateEGADSLiteFromFile()
    1483: @*/
    1484: PetscErrorCode DMPlexCreateEGADSFromFile(MPI_Comm comm, const char filename[], DM *dm)
    1485: {
    1486:   PetscMPIInt    rank;
    1487: #if defined(PETSC_HAVE_EGADS)
    1488:   ego            context= NULL, model = NULL;
    1489: #endif
    1490:   PetscBool      printModel = PETSC_FALSE, tessModel = PETSC_FALSE, newModel = PETSC_FALSE;

    1493:   PetscOptionsGetBool(NULL, NULL, "-dm_plex_egads_print_model", &printModel, NULL);
    1494:   PetscOptionsGetBool(NULL, NULL, "-dm_plex_egads_tess_model", &tessModel, NULL);
    1495:   PetscOptionsGetBool(NULL, NULL, "-dm_plex_egads_new_model", &newModel, NULL);
    1496:   MPI_Comm_rank(comm, &rank);
    1497: #if defined(PETSC_HAVE_EGADS)
    1498:   if (rank == 0) {

    1500:     EG_open(&context);
    1501:     EG_loadModel(context, 0, filename, &model);
    1502:     if (printModel) DMPlexEGADSPrintModel_Internal(model);

    1504:   }
    1505:   if (tessModel)     DMPlexCreateEGADS_Tess_Internal(comm, context, model, dm);
    1506:   else if (newModel) DMPlexCreateEGADS(comm, context, model, dm);
    1507:   else               DMPlexCreateEGADS_Internal(comm, context, model, dm);
    1508:   return 0;
    1509: #else
    1510:   SETERRQ(comm, PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
    1511: #endif
    1512: }