xref: /petsc/src/dm/impls/plex/plexegads.c (revision bfe80ac4a46d58cb7760074b25f5e81b2f541d8a)
15552b385SBrandon #include "petscsys.h"
2a8ededdfSMatthew G. Knepley #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
37bee2925SMatthew Knepley #include <petsc/private/hashmapi.h>
4a8ededdfSMatthew G. Knepley 
5337bb527SBarry Smith /* We need to understand how to natively parse STEP files. There seems to be only one open-source implementation of
6a8ededdfSMatthew G. Knepley    the STEP parser contained in the OpenCASCADE package. It is enough to make a strong man weep:
7a8ededdfSMatthew G. Knepley 
8a8ededdfSMatthew G. Knepley      https://github.com/tpaviot/oce/tree/master/src/STEPControl
9a8ededdfSMatthew G. Knepley 
10a8ededdfSMatthew G. Knepley    The STEP, and inner EXPRESS, formats are ISO standards, so they are documented
11a8ededdfSMatthew G. Knepley 
12a8ededdfSMatthew G. Knepley      https://stackoverflow.com/questions/26774037/documentation-or-specification-for-step-and-stp-files
13a8ededdfSMatthew G. Knepley      http://stepmod.sourceforge.net/express_model_spec/
14a8ededdfSMatthew G. Knepley 
15a8ededdfSMatthew G. Knepley    but again it seems that there has been a deliberate effort at obfuscation, probably to raise the bar for entrants.
16a8ededdfSMatthew G. Knepley */
17a8ededdfSMatthew G. Knepley 
18c1cad2e7SMatthew G. Knepley #ifdef PETSC_HAVE_EGADS
195552b385SBrandon   #include <petscdmplexegads.h>
20c1cad2e7SMatthew G. Knepley 
215552b385SBrandon PETSC_INTERN PetscErrorCode DMSnapToGeomModel_EGADS_Internal(DM, PetscInt, ego, PetscInt, PetscInt, PetscInt, const PetscScalar[], PetscScalar[], PetscBool);
225552b385SBrandon PETSC_INTERN PetscErrorCode DMPlex_Geom_EDGE_XYZtoUV_Internal(const PetscScalar[], ego, const PetscScalar[], const PetscInt, const PetscInt, PetscScalar[], PetscBool);
235552b385SBrandon PETSC_INTERN PetscErrorCode DMPlex_Geom_FACE_XYZtoUV_Internal(const PetscScalar[], ego, const PetscScalar[], const PetscInt, const PetscInt, PetscScalar[], PetscBool);
245552b385SBrandon 
255552b385SBrandon PetscErrorCode DMPlex_EGADS_GeomDecode_Internal(const PetscInt geomClass, const PetscInt geomType, char **retClass, char **retType)
26d71ae5a4SJacob Faibussowitsch {
275552b385SBrandon   PetscFunctionBeginHot;
285552b385SBrandon   /* EGADS Object Type */
295552b385SBrandon   if (geomClass == CONTXT) { *retClass = (char *)"CONTEXT"; }
305552b385SBrandon   if (geomClass == TRANSFORM) { *retClass = (char *)"TRANSFORM"; }
315552b385SBrandon   if (geomClass == TESSELLATION) { *retClass = (char *)"TESSELLATION"; }
325552b385SBrandon   if (geomClass == NIL) { *retClass = (char *)"NIL"; }
335552b385SBrandon   if (geomClass == EMPTY) { *retClass = (char *)"EMPTY"; }
345552b385SBrandon   if (geomClass == REFERENCE) { *retClass = (char *)"REFERENCE"; }
355552b385SBrandon   if (geomClass == PCURVE) { *retClass = (char *)"PCURVE"; }
365552b385SBrandon   if (geomClass == CURVE) { *retClass = (char *)"CURVE"; }
375552b385SBrandon   if (geomClass == SURFACE) { *retClass = (char *)"SURFACE"; }
385552b385SBrandon   if (geomClass == NODE) { *retClass = (char *)"NODE"; }
395552b385SBrandon   if (geomClass == EDGE) { *retClass = (char *)"EDGE"; }
405552b385SBrandon   if (geomClass == LOOP) { *retClass = (char *)"LOOP"; }
415552b385SBrandon   if (geomClass == FACE) { *retClass = (char *)"FACE"; }
425552b385SBrandon   if (geomClass == SHELL) { *retClass = (char *)"SHELL"; }
435552b385SBrandon   if (geomClass == BODY) { *retClass = (char *)"BODY"; }
445552b385SBrandon   if (geomClass == MODEL) { *retClass = (char *)"MODEL"; }
455552b385SBrandon 
465552b385SBrandon   /* PCURVES & CURVES */
475552b385SBrandon   if (geomClass == PCURVE || geomClass == CURVE) {
485552b385SBrandon     if (geomType == LINE) { *retType = (char *)"LINE"; }
495552b385SBrandon     if (geomType == CIRCLE) { *retType = (char *)"CIRCLE"; }
505552b385SBrandon     if (geomType == ELLIPSE) { *retType = (char *)"ELLIPSE"; }
515552b385SBrandon     if (geomType == PARABOLA) { *retType = (char *)"PARABOLA"; }
525552b385SBrandon     if (geomType == HYPERBOLA) { *retType = (char *)"HYPERBOLA"; }
535552b385SBrandon     if (geomType == TRIMMED) { *retType = (char *)"TRIMMED"; }
545552b385SBrandon     if (geomType == BEZIER) { *retType = (char *)"BEZIER"; }
555552b385SBrandon     if (geomType == BSPLINE) { *retType = (char *)"BSPLINE"; }
565552b385SBrandon     if (geomType == OFFSET) { *retType = (char *)"OFFSET"; }
575552b385SBrandon   }
585552b385SBrandon 
595552b385SBrandon   /* SURFACE */
605552b385SBrandon   if (geomClass == SURFACE) {
615552b385SBrandon     if (geomType == PLANE) { *retType = (char *)"PLANE"; }
625552b385SBrandon     if (geomType == SPHERICAL) { *retType = (char *)"SPHERICAL"; }
635552b385SBrandon     if (geomType == CYLINDRICAL) { *retType = (char *)"CYLINDRICAL"; }
645552b385SBrandon     if (geomType == REVOLUTION) { *retType = (char *)"REVOLUTION"; }
655552b385SBrandon     if (geomType == TOROIDAL) { *retType = (char *)"TOROIDAL"; }
665552b385SBrandon     if (geomType == CONICAL) { *retType = (char *)"CONICAL"; }
675552b385SBrandon     if (geomType == EXTRUSION) { *retType = (char *)"EXTRUSION"; }
685552b385SBrandon     if (geomType == BEZIER) { *retType = (char *)"BEZIER"; }
695552b385SBrandon     if (geomType == BSPLINE) { *retType = (char *)"BSPLINE"; }
705552b385SBrandon   }
715552b385SBrandon 
725552b385SBrandon   /* TOPOLOGY */
735552b385SBrandon   if (geomClass == NODE || geomClass == EDGE || geomClass == LOOP || geomClass == FACE || geomClass == SHELL || geomClass == BODY || geomClass == MODEL) {
745552b385SBrandon     if (geomType == SREVERSE) { *retType = (char *)"SREVERSE"; }
755552b385SBrandon     if (geomType == NOMTYPE) { *retType = (char *)"NOMTYPE"; }
765552b385SBrandon     if (geomType == SFORWARD && geomClass == FACE) { *retType = (char *)"SFORWARD"; }
775552b385SBrandon     if (geomType == ONENODE && geomClass == EDGE) { *retType = (char *)"ONENODE"; }
785552b385SBrandon     if (geomType == TWONODE) { *retType = (char *)"TWONODE"; }
795552b385SBrandon     if (geomType == OPEN) { *retType = (char *)"OPEN"; }
805552b385SBrandon     if (geomType == CLOSED) { *retType = (char *)"CLOSED"; }
815552b385SBrandon     if (geomType == DEGENERATE) { *retType = (char *)"DEGENERATE"; }
825552b385SBrandon     if (geomType == WIREBODY) { *retType = (char *)"WIREBODY"; }
835552b385SBrandon     if (geomType == FACEBODY) { *retType = (char *)"FACEBODY"; }
845552b385SBrandon     if (geomType == SHEETBODY) { *retType = (char *)"SHEETBODY"; }
855552b385SBrandon     if (geomType == SOLIDBODY) { *retType = (char *)"SOLIDBODY"; }
865552b385SBrandon   }
875552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
885552b385SBrandon }
895552b385SBrandon 
905552b385SBrandon PetscErrorCode DMPlex_EGADS_EDGE_XYZtoUV_Internal(const PetscScalar coords[], ego obj, const PetscScalar range[], const PetscInt v, const PetscInt dE, PetscScalar paramsV[])
915552b385SBrandon {
925552b385SBrandon   //
935552b385SBrandon   //
945552b385SBrandon   // Depreciated. Changed all references to DMPlex_Geom_FACE_XYZtoUV_Internal()
955552b385SBrandon   //
965552b385SBrandon   //
975552b385SBrandon 
985552b385SBrandon   PetscInt    loopCntr = 0;
995552b385SBrandon   PetscScalar dx, dy, dz, lambda, tolr, obj_old, obj_tmp, target;
1005552b385SBrandon   PetscScalar delta, A, b;
1015552b385SBrandon   PetscScalar ts[2], tt[2], eval[18], data[18];
1025552b385SBrandon 
1035552b385SBrandon   PetscFunctionBeginHot;
1045552b385SBrandon   /* Initialize Levenberg-Marquardt parameters */
1055552b385SBrandon   lambda = 1.0;
1065552b385SBrandon   tolr   = 1.0;
1075552b385SBrandon   target = 1.0E-20;
1085552b385SBrandon   ts[0]  = (range[0] + range[1]) / 2.;
1095552b385SBrandon 
1105552b385SBrandon   while (tolr >= target) {
1115552b385SBrandon     PetscCall(EG_evaluate(obj, ts, eval));
1125552b385SBrandon     dx      = coords[v * dE + 0] - eval[0];
1135552b385SBrandon     dy      = coords[v * dE + 1] - eval[1];
1145552b385SBrandon     dz      = coords[v * dE + 2] - eval[2];
1155552b385SBrandon     obj_old = dx * dx + dy * dy + dz * dz;
1165552b385SBrandon 
1175552b385SBrandon     if (obj_old < target) {
1185552b385SBrandon       tolr = obj_old;
1195552b385SBrandon       break;
1205552b385SBrandon     }
1215552b385SBrandon 
1225552b385SBrandon     A = (eval[3] * eval[3] + eval[4] * eval[4] + eval[5] * eval[5]) * (1.0 + lambda);
1235552b385SBrandon     if (A == 0.0) {
1245552b385SBrandon       PetscCall(PetscPrintf(PETSC_COMM_SELF, "A = 0.0 \n"));
1255552b385SBrandon       break;
1265552b385SBrandon     }
1275552b385SBrandon     b = eval[3] * dx + eval[4] * dy + eval[5] * dz;
1285552b385SBrandon 
1295552b385SBrandon     /* Solve A*delta = b */
1305552b385SBrandon     delta = b / A;
1315552b385SBrandon 
1325552b385SBrandon     /* Find a temp (u,v) and associated objective function */
1335552b385SBrandon     tt[0] = ts[0] + delta;
1345552b385SBrandon     if (tt[0] < range[0]) {
1355552b385SBrandon       tt[0] = range[0];
1365552b385SBrandon       delta = tt[0] - ts[0];
1375552b385SBrandon     }
1385552b385SBrandon     if (tt[0] > range[1]) {
1395552b385SBrandon       tt[0] = range[1];
1405552b385SBrandon       delta = tt[0] - ts[0];
1415552b385SBrandon     }
1425552b385SBrandon 
1435552b385SBrandon     PetscCall(EG_evaluate(obj, tt, data));
1445552b385SBrandon 
1455552b385SBrandon     obj_tmp = (coords[v * dE + 0] - data[0]) * (coords[v * dE + 0] - data[0]) + (coords[v * dE + 1] - data[1]) * (coords[v * dE + 1] - data[1]) + (coords[v * dE + 2] - data[2]) * (coords[v * dE + 2] - data[2]);
1465552b385SBrandon 
1475552b385SBrandon     /* If step is better, accept it and halve lambda (making it more Newton-like) */
1485552b385SBrandon     if (obj_tmp < obj_old) {
1495552b385SBrandon       obj_old = obj_tmp;
1505552b385SBrandon       ts[0]   = tt[0];
1515552b385SBrandon       for (int jj = 0; jj < 18; ++jj) eval[jj] = data[jj];
1525552b385SBrandon       lambda /= 2.0;
1535552b385SBrandon       if (lambda < 1.0E-14) lambda = 1.0E-14;
1545552b385SBrandon       if (obj_old < target) {
1555552b385SBrandon         tolr = obj_old;
1565552b385SBrandon         break;
1575552b385SBrandon       }
1585552b385SBrandon     } else {
1595552b385SBrandon       /* Otherwise reject it and double lambda (making it more gradient-descent like) */
1605552b385SBrandon       lambda *= 2.0;
1615552b385SBrandon     }
1625552b385SBrandon 
1635552b385SBrandon     if ((tt[0] == range[0]) || (tt[0] == range[1])) break;
1645552b385SBrandon     if (fabs(delta) < target) {
1655552b385SBrandon       tolr = obj_old;
1665552b385SBrandon       break;
1675552b385SBrandon     }
1685552b385SBrandon 
1695552b385SBrandon     tolr = obj_old;
1705552b385SBrandon 
1715552b385SBrandon     loopCntr += 1;
1725552b385SBrandon     if (loopCntr > 100) break;
1735552b385SBrandon   }
1745552b385SBrandon   paramsV[v * 3 + 0] = ts[0];
1755552b385SBrandon   paramsV[v * 3 + 1] = 0.;
1765552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
1775552b385SBrandon }
1785552b385SBrandon 
1795552b385SBrandon PetscErrorCode DMPlex_Geom_EDGE_XYZtoUV_Internal(const PetscScalar coords[], ego obj, const PetscScalar range[], const PetscInt v, const PetscInt dE, PetscScalar paramsV[], PetscBool islite)
1805552b385SBrandon {
1815552b385SBrandon   PetscInt    loopCntr = 0;
1825552b385SBrandon   PetscScalar dx, dy, dz, lambda, tolr, obj_old, obj_tmp, target;
1835552b385SBrandon   PetscScalar delta, A, b;
1845552b385SBrandon   PetscScalar ts[2], tt[2], eval[18], data[18];
1855552b385SBrandon 
1865552b385SBrandon   PetscFunctionBeginHot;
1875552b385SBrandon   /* Initialize Levenberg-Marquardt parameters */
1885552b385SBrandon   lambda = 1.0;
1895552b385SBrandon   tolr   = 1.0;
1905552b385SBrandon   target = 1.0E-20;
1915552b385SBrandon   ts[0]  = (range[0] + range[1]) / 2.;
1925552b385SBrandon 
1935552b385SBrandon   while (tolr >= target) {
1945552b385SBrandon     if (islite) {
1955552b385SBrandon       PetscCall(EGlite_evaluate(obj, ts, eval));
1965552b385SBrandon     } else {
1975552b385SBrandon       PetscCall(EG_evaluate(obj, ts, eval));
1985552b385SBrandon     }
1995552b385SBrandon 
2005552b385SBrandon     dx      = coords[v * dE + 0] - eval[0];
2015552b385SBrandon     dy      = coords[v * dE + 1] - eval[1];
2025552b385SBrandon     dz      = coords[v * dE + 2] - eval[2];
2035552b385SBrandon     obj_old = dx * dx + dy * dy + dz * dz;
2045552b385SBrandon 
2055552b385SBrandon     if (obj_old < target) {
2065552b385SBrandon       tolr = obj_old;
2075552b385SBrandon       break;
2085552b385SBrandon     }
2095552b385SBrandon 
2105552b385SBrandon     A = (eval[3] * eval[3] + eval[4] * eval[4] + eval[5] * eval[5]) * (1.0 + lambda);
2115552b385SBrandon     if (A == 0.0) {
2125552b385SBrandon       PetscCall(PetscPrintf(PETSC_COMM_SELF, "A = 0.0 \n"));
2135552b385SBrandon       break;
2145552b385SBrandon     }
2155552b385SBrandon     b = eval[3] * dx + eval[4] * dy + eval[5] * dz;
2165552b385SBrandon 
2175552b385SBrandon     /* Solve A*delta = b */
2185552b385SBrandon     delta = b / A;
2195552b385SBrandon 
2205552b385SBrandon     /* Find a temp (u,v) and associated objective function */
2215552b385SBrandon     tt[0] = ts[0] + delta;
2225552b385SBrandon     if (tt[0] < range[0]) {
2235552b385SBrandon       tt[0] = range[0];
2245552b385SBrandon       delta = tt[0] - ts[0];
2255552b385SBrandon     }
2265552b385SBrandon     if (tt[0] > range[1]) {
2275552b385SBrandon       tt[0] = range[1];
2285552b385SBrandon       delta = tt[0] - ts[0];
2295552b385SBrandon     }
2305552b385SBrandon 
2315552b385SBrandon     if (islite) {
2325552b385SBrandon       PetscCall(EGlite_evaluate(obj, tt, data));
2335552b385SBrandon     } else {
2345552b385SBrandon       PetscCall(EG_evaluate(obj, tt, data));
2355552b385SBrandon     }
2365552b385SBrandon 
2375552b385SBrandon     obj_tmp = (coords[v * dE + 0] - data[0]) * (coords[v * dE + 0] - data[0]) + (coords[v * dE + 1] - data[1]) * (coords[v * dE + 1] - data[1]) + (coords[v * dE + 2] - data[2]) * (coords[v * dE + 2] - data[2]);
2385552b385SBrandon 
2395552b385SBrandon     /* If step is better, accept it and halve lambda (making it more Newton-like) */
2405552b385SBrandon     if (obj_tmp < obj_old) {
2415552b385SBrandon       obj_old = obj_tmp;
2425552b385SBrandon       ts[0]   = tt[0];
2435552b385SBrandon       for (int jj = 0; jj < 18; ++jj) eval[jj] = data[jj];
2445552b385SBrandon       lambda /= 2.0;
2455552b385SBrandon       if (lambda < 1.0E-14) lambda = 1.0E-14;
2465552b385SBrandon       if (obj_old < target) {
2475552b385SBrandon         tolr = obj_old;
2485552b385SBrandon         break;
2495552b385SBrandon       }
2505552b385SBrandon     } else {
2515552b385SBrandon       /* Otherwise reject it and double lambda (making it more gradient-descent like) */
2525552b385SBrandon       lambda *= 2.0;
2535552b385SBrandon     }
2545552b385SBrandon 
2555552b385SBrandon     if ((tt[0] == range[0]) || (tt[0] == range[1])) break;
2565552b385SBrandon     if (fabs(delta) < target) {
2575552b385SBrandon       tolr = obj_old;
2585552b385SBrandon       break;
2595552b385SBrandon     }
2605552b385SBrandon 
2615552b385SBrandon     tolr = obj_old;
2625552b385SBrandon 
2635552b385SBrandon     loopCntr += 1;
2645552b385SBrandon     if (loopCntr > 100) break;
2655552b385SBrandon   }
2665552b385SBrandon   paramsV[v * 3 + 0] = ts[0];
2675552b385SBrandon   paramsV[v * 3 + 1] = 0.;
2685552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
2695552b385SBrandon }
2705552b385SBrandon 
2715552b385SBrandon PetscErrorCode DMPlex_EGADS_FACE_XYZtoUV_Internal(const PetscScalar coords[], ego obj, const PetscScalar range[], const PetscInt v, const PetscInt dE, PetscScalar paramsV[])
2725552b385SBrandon {
2735552b385SBrandon   //
2745552b385SBrandon   //
2755552b385SBrandon   // Depreciated. Changed all references to DMPlex_Geom_FACE_XYZtoUV_Internal()
2765552b385SBrandon   //
2775552b385SBrandon   //
2785552b385SBrandon 
2795552b385SBrandon   PetscInt    loopCntr = 0;
2805552b385SBrandon   PetscScalar dx, dy, dz, lambda, tolr, denom, obj_old, obj_tmp, target;
2815552b385SBrandon   PetscScalar uvs[2], uvt[2], delta[2], A[4], b[2], eval[18], data[18];
2825552b385SBrandon 
2835552b385SBrandon   PetscFunctionBeginHot;
2845552b385SBrandon   /* Initialize Levenberg-Marquardt parameters */
2855552b385SBrandon   lambda = 1.0;
2865552b385SBrandon   tolr   = 1.0;
2875552b385SBrandon   target = 1.0E-20;
2885552b385SBrandon   uvs[0] = (range[0] + range[1]) / 2.;
2895552b385SBrandon   uvs[1] = (range[2] + range[3]) / 2.;
2905552b385SBrandon 
2915552b385SBrandon   while (tolr >= target) {
2925552b385SBrandon     PetscCall(EG_evaluate(obj, uvs, eval));
2935552b385SBrandon     dx      = coords[v * dE + 0] - eval[0];
2945552b385SBrandon     dy      = coords[v * dE + 1] - eval[1];
2955552b385SBrandon     dz      = coords[v * dE + 2] - eval[2];
2965552b385SBrandon     obj_old = dx * dx + dy * dy + dz * dz;
2975552b385SBrandon 
2985552b385SBrandon     if (obj_old < target) {
2995552b385SBrandon       tolr = obj_old;
3005552b385SBrandon       break;
3015552b385SBrandon     }
3025552b385SBrandon 
3035552b385SBrandon     A[0] = (eval[3] * eval[3] + eval[4] * eval[4] + eval[5] * eval[5]) * (1.0 + lambda);
3045552b385SBrandon     A[1] = eval[3] * eval[6] + eval[4] * eval[7] + eval[5] * eval[8];
3055552b385SBrandon     A[2] = A[1];
3065552b385SBrandon     A[3] = (eval[6] * eval[6] + eval[7] * eval[7] + eval[8] * eval[8]) * (1.0 + lambda);
3075552b385SBrandon 
3085552b385SBrandon     b[0] = eval[3] * dx + eval[4] * dy + eval[5] * dz;
3095552b385SBrandon     b[1] = eval[6] * dx + eval[7] * dy + eval[8] * dz;
3105552b385SBrandon 
3115552b385SBrandon     /* Solve A*delta = b using Cramer's Rule */
3125552b385SBrandon     denom = A[0] * A[3] - A[2] * A[1];
3135552b385SBrandon     if (denom == 0.0) { PetscCall(PetscPrintf(PETSC_COMM_SELF, "denom = 0.0 \n")); }
3145552b385SBrandon     delta[0] = (b[0] * A[3] - b[1] * A[1]) / denom;
3155552b385SBrandon     delta[1] = (A[0] * b[1] - A[2] * b[0]) / denom;
3165552b385SBrandon 
3175552b385SBrandon     /* Find a temp (u,v) and associated objective function */
3185552b385SBrandon     uvt[0] = uvs[0] + delta[0];
3195552b385SBrandon     uvt[1] = uvs[1] + delta[1];
3205552b385SBrandon 
3215552b385SBrandon     if (uvt[0] < range[0]) {
3225552b385SBrandon       uvt[0]   = range[0];
3235552b385SBrandon       delta[0] = uvt[0] - uvs[0];
3245552b385SBrandon     }
3255552b385SBrandon     if (uvt[0] > range[1]) {
3265552b385SBrandon       uvt[0]   = range[1];
3275552b385SBrandon       delta[0] = uvt[0] - uvs[0];
3285552b385SBrandon     }
3295552b385SBrandon     if (uvt[1] < range[2]) {
3305552b385SBrandon       uvt[1]   = range[2];
3315552b385SBrandon       delta[1] = uvt[1] - uvs[1];
3325552b385SBrandon     }
3335552b385SBrandon     if (uvt[1] > range[3]) {
3345552b385SBrandon       uvt[1]   = range[3];
3355552b385SBrandon       delta[1] = uvt[1] - uvs[1];
3365552b385SBrandon     }
3375552b385SBrandon 
3385552b385SBrandon     PetscCall(EG_evaluate(obj, uvt, data));
3395552b385SBrandon 
3405552b385SBrandon     obj_tmp = (coords[v * dE + 0] - data[0]) * (coords[v * dE + 0] - data[0]) + (coords[v * dE + 1] - data[1]) * (coords[v * dE + 1] - data[1]) + (coords[v * dE + 2] - data[2]) * (coords[v * dE + 2] - data[2]);
3415552b385SBrandon 
3425552b385SBrandon     /* If step is better, accept it and halve lambda (making it more Newton-like) */
3435552b385SBrandon     if (obj_tmp < obj_old) {
3445552b385SBrandon       obj_old = obj_tmp;
3455552b385SBrandon       uvs[0]  = uvt[0];
3465552b385SBrandon       uvs[1]  = uvt[1];
3475552b385SBrandon       for (int jj = 0; jj < 18; ++jj) eval[jj] = data[jj];
3485552b385SBrandon       lambda /= 2.0;
3495552b385SBrandon       if (lambda < 1.0E-14) lambda = 1.0E-14;
3505552b385SBrandon       if (obj_old < target) {
3515552b385SBrandon         tolr = obj_old;
3525552b385SBrandon         break;
3535552b385SBrandon       }
3545552b385SBrandon     } else {
3555552b385SBrandon       /* Otherwise reject it and double lambda (making it more gradient-descent like) */
3565552b385SBrandon       lambda *= 2.0;
3575552b385SBrandon     }
3585552b385SBrandon 
3595552b385SBrandon     if (sqrt(delta[0] * delta[0] + delta[1] * delta[1]) < target) {
3605552b385SBrandon       tolr = obj_old;
3615552b385SBrandon       break;
3625552b385SBrandon     }
3635552b385SBrandon 
3645552b385SBrandon     tolr = obj_old;
3655552b385SBrandon 
3665552b385SBrandon     loopCntr += 1;
3675552b385SBrandon     if (loopCntr > 100) break;
3685552b385SBrandon   }
3695552b385SBrandon   paramsV[v * 3 + 0] = uvs[0];
3705552b385SBrandon   paramsV[v * 3 + 1] = uvs[1];
3715552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
3725552b385SBrandon }
3735552b385SBrandon 
3745552b385SBrandon PetscErrorCode DMPlex_Geom_FACE_XYZtoUV_Internal(const PetscScalar coords[], ego obj, const PetscScalar range[], const PetscInt v, const PetscInt dE, PetscScalar paramsV[], PetscBool islite)
3755552b385SBrandon {
3765552b385SBrandon   PetscInt    loopCntr = 0;
3775552b385SBrandon   PetscScalar dx, dy, dz, lambda, tolr, denom, obj_old, obj_tmp, target;
3785552b385SBrandon   PetscScalar uvs[2], uvt[2], delta[2], A[4], b[2], eval[18], data[18];
3795552b385SBrandon 
3805552b385SBrandon   PetscFunctionBeginHot;
3815552b385SBrandon   /* Initialize Levenberg-Marquardt parameters */
3825552b385SBrandon   lambda = 1.0;
3835552b385SBrandon   tolr   = 1.0;
3845552b385SBrandon   target = 1.0E-20;
3855552b385SBrandon   uvs[0] = (range[0] + range[1]) / 2.;
3865552b385SBrandon   uvs[1] = (range[2] + range[3]) / 2.;
3875552b385SBrandon 
3885552b385SBrandon   while (tolr >= target) {
3895552b385SBrandon     if (islite) {
3905552b385SBrandon       PetscCallEGADS(EGlite_evaluate, (obj, uvs, eval));
3915552b385SBrandon     } else {
3925552b385SBrandon       PetscCallEGADS(EG_evaluate, (obj, uvs, eval));
3935552b385SBrandon     }
3945552b385SBrandon 
3955552b385SBrandon     dx      = coords[v * dE + 0] - eval[0];
3965552b385SBrandon     dy      = coords[v * dE + 1] - eval[1];
3975552b385SBrandon     dz      = coords[v * dE + 2] - eval[2];
3985552b385SBrandon     obj_old = dx * dx + dy * dy + dz * dz;
3995552b385SBrandon 
4005552b385SBrandon     if (obj_old < target) {
4015552b385SBrandon       tolr = obj_old;
4025552b385SBrandon       break;
4035552b385SBrandon     }
4045552b385SBrandon 
4055552b385SBrandon     A[0] = (eval[3] * eval[3] + eval[4] * eval[4] + eval[5] * eval[5]) * (1.0 + lambda);
4065552b385SBrandon     A[1] = eval[3] * eval[6] + eval[4] * eval[7] + eval[5] * eval[8];
4075552b385SBrandon     A[2] = A[1];
4085552b385SBrandon     A[3] = (eval[6] * eval[6] + eval[7] * eval[7] + eval[8] * eval[8]) * (1.0 + lambda);
4095552b385SBrandon 
4105552b385SBrandon     b[0] = eval[3] * dx + eval[4] * dy + eval[5] * dz;
4115552b385SBrandon     b[1] = eval[6] * dx + eval[7] * dy + eval[8] * dz;
4125552b385SBrandon 
4135552b385SBrandon     /* Solve A*delta = b using Cramer's Rule */
4145552b385SBrandon     denom = A[0] * A[3] - A[2] * A[1];
4155552b385SBrandon     if (denom == 0.0) { PetscCall(PetscPrintf(PETSC_COMM_SELF, "denom = 0.0 \n")); }
4165552b385SBrandon     delta[0] = (b[0] * A[3] - b[1] * A[1]) / denom;
4175552b385SBrandon     delta[1] = (A[0] * b[1] - A[2] * b[0]) / denom;
4185552b385SBrandon 
4195552b385SBrandon     /* Find a temp (u,v) and associated objective function */
4205552b385SBrandon     uvt[0] = uvs[0] + delta[0];
4215552b385SBrandon     uvt[1] = uvs[1] + delta[1];
4225552b385SBrandon 
4235552b385SBrandon     if (uvt[0] < range[0]) {
4245552b385SBrandon       uvt[0]   = range[0];
4255552b385SBrandon       delta[0] = uvt[0] - uvs[0];
4265552b385SBrandon     }
4275552b385SBrandon     if (uvt[0] > range[1]) {
4285552b385SBrandon       uvt[0]   = range[1];
4295552b385SBrandon       delta[0] = uvt[0] - uvs[0];
4305552b385SBrandon     }
4315552b385SBrandon     if (uvt[1] < range[2]) {
4325552b385SBrandon       uvt[1]   = range[2];
4335552b385SBrandon       delta[1] = uvt[1] - uvs[1];
4345552b385SBrandon     }
4355552b385SBrandon     if (uvt[1] > range[3]) {
4365552b385SBrandon       uvt[1]   = range[3];
4375552b385SBrandon       delta[1] = uvt[1] - uvs[1];
4385552b385SBrandon     }
4395552b385SBrandon 
4405552b385SBrandon     if (islite) {
4415552b385SBrandon       PetscCall(EGlite_evaluate(obj, uvt, data));
4425552b385SBrandon     } else {
4435552b385SBrandon       PetscCall(EG_evaluate(obj, uvt, data));
4445552b385SBrandon     }
4455552b385SBrandon 
4465552b385SBrandon     obj_tmp = (coords[v * dE + 0] - data[0]) * (coords[v * dE + 0] - data[0]) + (coords[v * dE + 1] - data[1]) * (coords[v * dE + 1] - data[1]) + (coords[v * dE + 2] - data[2]) * (coords[v * dE + 2] - data[2]);
4475552b385SBrandon 
4485552b385SBrandon     /* If step is better, accept it and halve lambda (making it more Newton-like) */
4495552b385SBrandon     if (obj_tmp < obj_old) {
4505552b385SBrandon       obj_old = obj_tmp;
4515552b385SBrandon       uvs[0]  = uvt[0];
4525552b385SBrandon       uvs[1]  = uvt[1];
4535552b385SBrandon       for (int jj = 0; jj < 18; ++jj) eval[jj] = data[jj];
4545552b385SBrandon       lambda /= 2.0;
4555552b385SBrandon       if (lambda < 1.0E-14) lambda = 1.0E-14;
4565552b385SBrandon       if (obj_old < target) {
4575552b385SBrandon         tolr = obj_old;
4585552b385SBrandon         break;
4595552b385SBrandon       }
4605552b385SBrandon     } else {
4615552b385SBrandon       /* Otherwise reject it and double lambda (making it more gradient-descent like) */
4625552b385SBrandon       lambda *= 2.0;
4635552b385SBrandon     }
4645552b385SBrandon 
4655552b385SBrandon     if (sqrt(delta[0] * delta[0] + delta[1] * delta[1]) < target) {
4665552b385SBrandon       tolr = obj_old;
4675552b385SBrandon       break;
4685552b385SBrandon     }
4695552b385SBrandon 
4705552b385SBrandon     tolr = obj_old;
4715552b385SBrandon 
4725552b385SBrandon     loopCntr += 1;
4735552b385SBrandon     if (loopCntr > 100) break;
4745552b385SBrandon   }
4755552b385SBrandon   paramsV[v * 3 + 0] = uvs[0];
4765552b385SBrandon   paramsV[v * 3 + 1] = uvs[1];
4775552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
4785552b385SBrandon }
4795552b385SBrandon 
4805552b385SBrandon PetscErrorCode DMSnapToGeomModel_EGADS_Internal(DM dm, PetscInt p, ego model, PetscInt bodyID, PetscInt faceID, PetscInt edgeID, const PetscScalar mcoords[], PetscScalar gcoords[], PetscBool islite)
4815552b385SBrandon {
4825552b385SBrandon   /* PETSc Variables */
483c1cad2e7SMatthew G. Knepley   DM   cdm;
484c1cad2e7SMatthew G. Knepley   ego *bodies;
485c1cad2e7SMatthew G. Knepley   ego  geom, body, obj;
486*bfe80ac4SPierre Jolivet   /* result has to hold derivatives, along with the value */
4875552b385SBrandon   double       params[3], result[18], paramsV[16 * 3], range[4];
488c1cad2e7SMatthew G. Knepley   int          Nb, oclass, mtype, *senses, peri;
489c1cad2e7SMatthew G. Knepley   Vec          coordinatesLocal;
490c1cad2e7SMatthew G. Knepley   PetscScalar *coords = NULL;
491c1cad2e7SMatthew G. Knepley   PetscInt     Nv, v, Np = 0, pm;
492c1cad2e7SMatthew G. Knepley   PetscInt     dE, d;
4935552b385SBrandon   PetscReal    pTolr = 1.0e-14;
494c1cad2e7SMatthew G. Knepley 
495c1cad2e7SMatthew G. Knepley   PetscFunctionBeginHot;
4969566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
4979566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
4989566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
4995552b385SBrandon 
5005552b385SBrandon   if (islite) {
5015552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
5025552b385SBrandon   } else {
5039566063dSJacob Faibussowitsch     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
5045552b385SBrandon   }
5055552b385SBrandon 
5065552b385SBrandon   PetscCheck(bodyID < Nb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Body %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bodyID, Nb);
507c1cad2e7SMatthew G. Knepley   body = bodies[bodyID];
508c1cad2e7SMatthew G. Knepley 
5099371c9d4SSatish Balay   if (edgeID >= 0) {
5105552b385SBrandon     if (islite) {
5115552b385SBrandon       PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &obj));
5125552b385SBrandon       Np = 1;
5135552b385SBrandon     } else {
5149371c9d4SSatish Balay       PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &obj));
5159371c9d4SSatish Balay       Np = 1;
5165552b385SBrandon     }
5179371c9d4SSatish Balay   } else if (faceID >= 0) {
5185552b385SBrandon     if (islite) {
5195552b385SBrandon       PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &obj));
5205552b385SBrandon       Np = 2;
5215552b385SBrandon     } else {
5229371c9d4SSatish Balay       PetscCall(EG_objectBodyTopo(body, FACE, faceID, &obj));
5239371c9d4SSatish Balay       Np = 2;
5245552b385SBrandon     }
5259371c9d4SSatish Balay   } else {
526c1cad2e7SMatthew G. Knepley     for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
5273ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
528c1cad2e7SMatthew G. Knepley   }
529c1cad2e7SMatthew G. Knepley 
530c1cad2e7SMatthew G. Knepley   /* Calculate parameters (t or u,v) for vertices */
5319566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords));
532c1cad2e7SMatthew G. Knepley   Nv /= dE;
533c1cad2e7SMatthew G. Knepley   if (Nv == 1) {
5349566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords));
535c1cad2e7SMatthew G. Knepley     for (d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
5363ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
537c1cad2e7SMatthew G. Knepley   }
53863a3b9bcSJacob Faibussowitsch   PetscCheck(Nv <= 16, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " coordinates associated to point %" PetscInt_FMT, Nv, p);
539c1cad2e7SMatthew G. Knepley 
5405552b385SBrandon   /* Correct EGADS/EGADSlite 2pi bug when calculating nearest point on Periodic Surfaces */
5415552b385SBrandon   if (islite) {
5425552b385SBrandon     PetscCall(EGlite_getRange(obj, range, &peri));
5435552b385SBrandon   } else {
5449566063dSJacob Faibussowitsch     PetscCall(EG_getRange(obj, range, &peri));
5455552b385SBrandon   }
5465552b385SBrandon 
547c1cad2e7SMatthew G. Knepley   for (v = 0; v < Nv; ++v) {
5485552b385SBrandon     if (edgeID > 0) {
5495552b385SBrandon       PetscCall(DMPlex_Geom_EDGE_XYZtoUV_Internal(coords, obj, range, v, dE, paramsV, islite));
5505552b385SBrandon     } else {
5515552b385SBrandon       PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, obj, range, v, dE, paramsV, islite));
5529371c9d4SSatish Balay     }
553c1cad2e7SMatthew G. Knepley   }
5549566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, p, &Nv, &coords));
5555552b385SBrandon 
556c1cad2e7SMatthew G. Knepley   /* Calculate parameters (t or u,v) for new vertex at edge midpoint */
557c1cad2e7SMatthew G. Knepley   for (pm = 0; pm < Np; ++pm) {
558c1cad2e7SMatthew G. Knepley     params[pm] = 0.;
559c1cad2e7SMatthew G. Knepley     for (v = 0; v < Nv; ++v) params[pm] += paramsV[v * 3 + pm];
560c1cad2e7SMatthew G. Knepley     params[pm] /= Nv;
561c1cad2e7SMatthew G. Knepley   }
5625552b385SBrandon   PetscCheck((params[0] + pTolr >= range[0]) || (params[0] - pTolr <= range[1]), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " had bad interpolation", p);
5635552b385SBrandon   PetscCheck(Np < 2 || ((params[1] + pTolr >= range[2]) || (params[1] - pTolr <= range[3])), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d had bad interpolation on v", p);
5645552b385SBrandon 
565c1cad2e7SMatthew G. Knepley   /* Put coordinates for new vertex in result[] */
5665552b385SBrandon   if (islite) {
5675552b385SBrandon     PetscCall(EGlite_evaluate(obj, params, result));
5685552b385SBrandon   } else {
5699566063dSJacob Faibussowitsch     PetscCall(EG_evaluate(obj, params, result));
5705552b385SBrandon   }
5715552b385SBrandon 
572c1cad2e7SMatthew G. Knepley   for (d = 0; d < dE; ++d) gcoords[d] = result[d];
5733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
574c1cad2e7SMatthew G. Knepley }
575c1cad2e7SMatthew G. Knepley #endif
576c1cad2e7SMatthew G. Knepley 
5777625649eSMatthew G. Knepley PetscErrorCode DMSnapToGeomModel_EGADS(DM dm, PetscInt p, PetscInt dE, const PetscScalar mcoords[], PetscScalar gcoords[])
5787625649eSMatthew G. Knepley {
5797625649eSMatthew G. Knepley   PetscFunctionBeginHot;
5807625649eSMatthew G. Knepley #ifdef PETSC_HAVE_EGADS
5817625649eSMatthew G. Knepley   DMLabel        bodyLabel, faceLabel, edgeLabel;
5827625649eSMatthew G. Knepley   PetscInt       bodyID, faceID, edgeID;
5837625649eSMatthew G. Knepley   PetscContainer modelObj;
5847625649eSMatthew G. Knepley   ego            model;
5855552b385SBrandon   PetscBool      islite = PETSC_FALSE;
5867625649eSMatthew G. Knepley 
5875552b385SBrandon   // FIXME: Change -dm_plex_refine_without_snap_to_geom to DM to shut off snapping
5887625649eSMatthew G. Knepley   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
5897625649eSMatthew G. Knepley   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
5907625649eSMatthew G. Knepley   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
5917625649eSMatthew G. Knepley   PetscCheck(bodyLabel && faceLabel && edgeLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "EGADS meshes must have body, face, and edge labels defined");
5927625649eSMatthew G. Knepley   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
5935552b385SBrandon   if (!modelObj) {
5945552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
5955552b385SBrandon     islite = PETSC_TRUE;
5965552b385SBrandon   }
5977625649eSMatthew G. Knepley   PetscCheck(modelObj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "EGADS mesh missing model object");
5987625649eSMatthew G. Knepley 
5997625649eSMatthew G. Knepley   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
6007625649eSMatthew G. Knepley   PetscCall(DMLabelGetValue(bodyLabel, p, &bodyID));
6017625649eSMatthew G. Knepley   PetscCall(DMLabelGetValue(faceLabel, p, &faceID));
6027625649eSMatthew G. Knepley   PetscCall(DMLabelGetValue(edgeLabel, p, &edgeID));
6037625649eSMatthew G. Knepley   /* Allows for "Connective" Plex Edges present in models with multiple non-touching Entities */
6047625649eSMatthew G. Knepley   if (bodyID < 0) {
6057625649eSMatthew G. Knepley     for (PetscInt d = 0; d < dE; ++d) gcoords[d] = mcoords[d];
6067625649eSMatthew G. Knepley     PetscFunctionReturn(PETSC_SUCCESS);
6077625649eSMatthew G. Knepley   }
6085552b385SBrandon   PetscCall(DMSnapToGeomModel_EGADS_Internal(dm, p, model, bodyID, faceID, edgeID, mcoords, gcoords, islite));
609a8ededdfSMatthew G. Knepley #endif
6103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
611a8ededdfSMatthew G. Knepley }
6127bee2925SMatthew Knepley 
6137bee2925SMatthew Knepley #if defined(PETSC_HAVE_EGADS)
6145552b385SBrandon PetscErrorCode DMPlexGeomPrintModel_Internal(ego model, PetscBool islite)
615d71ae5a4SJacob Faibussowitsch {
6165552b385SBrandon   /* PETSc Variables */
6175552b385SBrandon   ego geom, *bodies, *nobjs, *mobjs, *lobjs, *shobjs, *fobjs, *eobjs;
6185552b385SBrandon   int oclass, mtype, *senses, *shsenses, *fsenses, *lsenses, *esenses;
6197bee2925SMatthew Knepley   int Nb, b;
6207bee2925SMatthew Knepley 
6217bee2925SMatthew Knepley   PetscFunctionBeginUser;
6227bee2925SMatthew Knepley   /* test bodyTopo functions */
6235552b385SBrandon   if (islite) {
6245552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
6255552b385SBrandon   } else {
6269566063dSJacob Faibussowitsch     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
6275552b385SBrandon   }
6285552b385SBrandon   PetscCall(PetscPrintf(PETSC_COMM_SELF, " Number of BODIES (nbodies): %" PetscInt_FMT " \n", Nb));
6297bee2925SMatthew Knepley 
6307bee2925SMatthew Knepley   for (b = 0; b < Nb; ++b) {
6317bee2925SMatthew Knepley     ego body = bodies[b];
6325552b385SBrandon     int id, sh, Nsh, f, Nf, l, Nl, e, Ne, v, Nv;
6335552b385SBrandon 
6345552b385SBrandon     /* List Topology of Bodies */
6355552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
6365552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, "   BODY %d TOPOLOGY SUMMARY \n", b));
6377bee2925SMatthew Knepley 
6387bee2925SMatthew Knepley     /* Output Basic Model Topology */
6395552b385SBrandon     if (islite) {
6405552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, SHELL, &Nsh, &shobjs));
6415552b385SBrandon     } else {
6425552b385SBrandon       PetscCall(EG_getBodyTopos(body, NULL, SHELL, &Nsh, &shobjs));
6435552b385SBrandon     }
6449566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Number of SHELLS: %d \n", Nsh));
6457bee2925SMatthew Knepley 
6465552b385SBrandon     if (islite) {
6475552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
6485552b385SBrandon     } else {
6495552b385SBrandon       PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
6505552b385SBrandon     }
6519566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Number of FACES: %d \n", Nf));
6527bee2925SMatthew Knepley 
6535552b385SBrandon     if (islite) {
6545552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
6555552b385SBrandon     } else {
6569566063dSJacob Faibussowitsch       PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
6575552b385SBrandon     }
6589566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Number of LOOPS: %d \n", Nl));
6597bee2925SMatthew Knepley 
6605552b385SBrandon     if (islite) {
6615552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
6625552b385SBrandon     } else {
6635552b385SBrandon       PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
6645552b385SBrandon     }
6659566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Number of EDGES: %d \n", Ne));
6667bee2925SMatthew Knepley 
6675552b385SBrandon     if (islite) {
6685552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
6695552b385SBrandon     } else {
6705552b385SBrandon       PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
6715552b385SBrandon     }
6729566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      Number of NODES: %d \n", Nv));
6735552b385SBrandon 
6745552b385SBrandon     if (islite) {
6755552b385SBrandon       EGlite_free(shobjs);
6765552b385SBrandon       EGlite_free(fobjs);
6775552b385SBrandon       EGlite_free(lobjs);
6785552b385SBrandon       EGlite_free(eobjs);
6795552b385SBrandon       EGlite_free(nobjs);
6805552b385SBrandon     } else {
6815552b385SBrandon       EG_free(shobjs);
6825552b385SBrandon       EG_free(fobjs);
6835552b385SBrandon       EG_free(lobjs);
6845552b385SBrandon       EG_free(eobjs);
6855552b385SBrandon       EG_free(nobjs);
6865552b385SBrandon     }
6875552b385SBrandon 
6885552b385SBrandon     /* List Topology of Bodies */
6895552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
6905552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, "      BODY %d TOPOLOGY DETAILS \n", b));
6915552b385SBrandon 
6925552b385SBrandon     /* Get SHELL info which associated with the current BODY */
6935552b385SBrandon     if (islite) {
6945552b385SBrandon       PetscCall(EGlite_getTopology(body, &geom, &oclass, &mtype, NULL, &Nsh, &shobjs, &shsenses));
6955552b385SBrandon     } else {
6965552b385SBrandon       PetscCall(EG_getTopology(body, &geom, &oclass, &mtype, NULL, &Nsh, &shobjs, &shsenses));
6975552b385SBrandon     }
6985552b385SBrandon 
6995552b385SBrandon     for (sh = 0; sh < Nsh; ++sh) {
7005552b385SBrandon       ego shell   = shobjs[sh];
7015552b385SBrandon       int shsense = shsenses[sh];
7025552b385SBrandon 
7035552b385SBrandon       if (islite) {
7045552b385SBrandon         id = EGlite_indexBodyTopo(body, shell);
7055552b385SBrandon       } else {
7065552b385SBrandon         id = EG_indexBodyTopo(body, shell);
7075552b385SBrandon       }
7085552b385SBrandon       PetscCall(PetscPrintf(PETSC_COMM_SELF, "         SHELL ID: %d :: sense = %d\n", id, shsense));
7095552b385SBrandon 
710*bfe80ac4SPierre Jolivet       /* Get FACE information associated with current SHELL */
7115552b385SBrandon       if (islite) {
7125552b385SBrandon         PetscCall(EGlite_getTopology(shell, &geom, &oclass, &mtype, NULL, &Nf, &fobjs, &fsenses));
7135552b385SBrandon       } else {
7145552b385SBrandon         PetscCall(EG_getTopology(shell, &geom, &oclass, &mtype, NULL, &Nf, &fobjs, &fsenses));
7155552b385SBrandon       }
7165552b385SBrandon 
7175552b385SBrandon       for (f = 0; f < Nf; ++f) {
7185552b385SBrandon         ego     face = fobjs[f];
7195552b385SBrandon         ego     gRef, gPrev, gNext;
7205552b385SBrandon         int     goclass, gmtype, *gpinfo;
7215552b385SBrandon         double *gprv;
7225552b385SBrandon         char   *gClass = (char *)"", *gType = (char *)"";
7235552b385SBrandon         double  fdata[4];
7245552b385SBrandon         ego     fRef, fPrev, fNext;
7255552b385SBrandon         int     foclass, fmtype;
7265552b385SBrandon 
7275552b385SBrandon         if (islite) {
7285552b385SBrandon           id = EGlite_indexBodyTopo(body, face);
7295552b385SBrandon         } else {
7305552b385SBrandon           id = EG_indexBodyTopo(body, face);
7315552b385SBrandon         }
7325552b385SBrandon 
7335552b385SBrandon         /* Get LOOP info associated with current FACE */
7345552b385SBrandon         if (islite) {
7355552b385SBrandon           PetscCall(EGlite_getTopology(face, &geom, &oclass, &mtype, fdata, &Nl, &lobjs, &lsenses));
7365552b385SBrandon           PetscCall(EGlite_getInfo(face, &foclass, &fmtype, &fRef, &fPrev, &fNext));
7375552b385SBrandon           PetscCall(EGlite_getGeometry(geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));
7385552b385SBrandon           PetscCall(EGlite_getInfo(geom, &goclass, &gmtype, &gRef, &gPrev, &gNext));
7395552b385SBrandon         } else {
7405552b385SBrandon           PetscCall(EG_getTopology(face, &geom, &oclass, &mtype, fdata, &Nl, &lobjs, &lsenses));
7415552b385SBrandon           PetscCall(EG_getInfo(face, &foclass, &fmtype, &fRef, &fPrev, &fNext));
7425552b385SBrandon           PetscCall(EG_getGeometry(geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));
7435552b385SBrandon           PetscCall(EG_getInfo(geom, &goclass, &gmtype, &gRef, &gPrev, &gNext));
7445552b385SBrandon         }
7455552b385SBrandon 
7465552b385SBrandon         PetscCall(DMPlex_EGADS_GeomDecode_Internal(goclass, gmtype, &gClass, &gType));
7475552b385SBrandon         PetscCall(PetscPrintf(PETSC_COMM_SELF, "           FACE ID: %d :: sense = %d \n", id, fmtype));
7485552b385SBrandon         PetscCall(PetscPrintf(PETSC_COMM_SELF, "             GEOMETRY CLASS: %s \n", gClass));
7495552b385SBrandon         PetscCall(PetscPrintf(PETSC_COMM_SELF, "             GEOMETRY TYPE:  %s \n\n", gType));
7505552b385SBrandon         PetscCall(PetscPrintf(PETSC_COMM_SELF, "             RANGE (umin, umax) = (%f, %f) \n", fdata[0], fdata[1]));
7515552b385SBrandon         PetscCall(PetscPrintf(PETSC_COMM_SELF, "                   (vmin, vmax) = (%f, %f) \n\n", fdata[2], fdata[3]));
7527bee2925SMatthew Knepley 
7537bee2925SMatthew Knepley         for (l = 0; l < Nl; ++l) {
7547bee2925SMatthew Knepley           ego loop   = lobjs[l];
7555552b385SBrandon           int lsense = lsenses[l];
7567bee2925SMatthew Knepley 
7575552b385SBrandon           if (islite) {
7585552b385SBrandon             id = EGlite_indexBodyTopo(body, loop);
7595552b385SBrandon           } else {
7607bee2925SMatthew Knepley             id = EG_indexBodyTopo(body, loop);
7615552b385SBrandon           }
7627bee2925SMatthew Knepley 
7635552b385SBrandon           PetscCall(PetscPrintf(PETSC_COMM_SELF, "             LOOP ID: %d :: sense = %d\n", id, lsense));
7645552b385SBrandon 
7655552b385SBrandon           /* Get EDGE info associated with the current LOOP */
7665552b385SBrandon           if (islite) {
7675552b385SBrandon             PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &esenses));
7685552b385SBrandon           } else {
7695552b385SBrandon             PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &esenses));
7705552b385SBrandon           }
7717bee2925SMatthew Knepley 
7727bee2925SMatthew Knepley           for (e = 0; e < Ne; ++e) {
7735552b385SBrandon             ego    edge = eobjs[e];
7745552b385SBrandon             ego    topRef, prev, next;
7755552b385SBrandon             int    esense   = esenses[e];
7767bee2925SMatthew Knepley             double range[4] = {0., 0., 0., 0.};
7777bee2925SMatthew Knepley             int    peri;
7785552b385SBrandon             ego    gEref, gEprev, gEnext;
7795552b385SBrandon             int    gEoclass, gEmtype;
7805552b385SBrandon             char  *gEclass = (char *)"", *gEtype = (char *)"";
7817bee2925SMatthew Knepley 
7825552b385SBrandon             if (islite) {
7835552b385SBrandon               PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
7845552b385SBrandon               if (mtype != DEGENERATE) { PetscCall(EGlite_getInfo(geom, &gEoclass, &gEmtype, &gEref, &gEprev, &gEnext)); }
785266cfabeSMatthew G. Knepley             } else {
7865552b385SBrandon               PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
7875552b385SBrandon               PetscCall(EG_getInfo(geom, &gEoclass, &gEmtype, &gEref, &gEprev, &gEnext));
7885552b385SBrandon             }
7895552b385SBrandon 
7905552b385SBrandon             if (mtype != DEGENERATE) { PetscCall(DMPlex_EGADS_GeomDecode_Internal(gEoclass, gEmtype, &gEclass, &gEtype)); }
7915552b385SBrandon 
7925552b385SBrandon             if (islite) {
7935552b385SBrandon               id = EGlite_indexBodyTopo(body, edge);
7945552b385SBrandon               PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
7955552b385SBrandon             } else {
7965552b385SBrandon               id = EG_indexBodyTopo(body, edge);
7975552b385SBrandon               PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
7985552b385SBrandon             }
7995552b385SBrandon 
8005552b385SBrandon             PetscCall(PetscPrintf(PETSC_COMM_SELF, "               EDGE ID: %d :: sense = %d\n", id, esense));
8015552b385SBrandon             if (mtype != DEGENERATE) {
8025552b385SBrandon               PetscCall(PetscPrintf(PETSC_COMM_SELF, "                 GEOMETRY CLASS: %s \n", gEclass));
8035552b385SBrandon               PetscCall(PetscPrintf(PETSC_COMM_SELF, "                 GEOMETRY TYPE:  %s \n", gEtype));
8045552b385SBrandon             }
8055552b385SBrandon 
8065552b385SBrandon             if (mtype == DEGENERATE) { PetscCall(PetscPrintf(PETSC_COMM_SELF, "                 EDGE %d is DEGENERATE \n", id)); }
8075552b385SBrandon 
8085552b385SBrandon             if (islite) {
8095552b385SBrandon               PetscCall(EGlite_getRange(edge, range, &peri));
8105552b385SBrandon             } else {
8115552b385SBrandon               PetscCall(EG_getRange(edge, range, &peri));
8125552b385SBrandon             }
8135552b385SBrandon 
8145552b385SBrandon             PetscCall(PetscPrintf(PETSC_COMM_SELF, "                 Peri = %d :: Range = %lf, %lf, %lf, %lf \n", peri, range[0], range[1], range[2], range[3]));
8155552b385SBrandon 
8165552b385SBrandon             /* Get NODE info associated with the current EDGE */
8175552b385SBrandon             if (islite) {
8185552b385SBrandon               PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
8195552b385SBrandon             } else {
8205552b385SBrandon               PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
821266cfabeSMatthew G. Knepley             }
8227bee2925SMatthew Knepley 
8237bee2925SMatthew Knepley             for (v = 0; v < Nv; ++v) {
8247bee2925SMatthew Knepley               ego    vertex = nobjs[v];
8257bee2925SMatthew Knepley               double limits[4];
8267bee2925SMatthew Knepley               int    dummy;
8277bee2925SMatthew Knepley 
8285552b385SBrandon               if (islite) {
8295552b385SBrandon                 PetscCall(EGlite_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
8305552b385SBrandon                 id = EGlite_indexBodyTopo(body, vertex);
8315552b385SBrandon               } else {
8329566063dSJacob Faibussowitsch                 PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
8337bee2925SMatthew Knepley                 id = EG_indexBodyTopo(body, vertex);
8345552b385SBrandon               }
8359566063dSJacob Faibussowitsch               PetscCall(PetscPrintf(PETSC_COMM_SELF, "                 NODE ID: %d \n", id));
8369566063dSJacob Faibussowitsch               PetscCall(PetscPrintf(PETSC_COMM_SELF, "                    (x, y, z) = (%lf, %lf, %lf) \n", limits[0], limits[1], limits[2]));
8377bee2925SMatthew Knepley             }
8387bee2925SMatthew Knepley           }
8397bee2925SMatthew Knepley         }
8407bee2925SMatthew Knepley       }
8415552b385SBrandon     }
8425552b385SBrandon   }
8435552b385SBrandon   PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n\n"));
8443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8457bee2925SMatthew Knepley }
8467bee2925SMatthew Knepley 
84749abdd8aSBarry Smith static PetscErrorCode DMPlexEGADSDestroy_Private(void **context)
848d71ae5a4SJacob Faibussowitsch {
8495552b385SBrandon   if (*context) EG_deleteObject((ego)*context);
8505552b385SBrandon   return (PETSC_SUCCESS);
8515552b385SBrandon }
8525552b385SBrandon 
8535552b385SBrandon static PetscErrorCode DMPlexEGADSClose_Private(void **context)
8545552b385SBrandon {
8555552b385SBrandon   if (*context) EG_close((ego)*context);
8565552b385SBrandon   return (PETSC_SUCCESS);
8575552b385SBrandon }
8585552b385SBrandon 
8595552b385SBrandon PetscErrorCode DMPlexEGADSliteDestroy_Private(void **context)
8605552b385SBrandon {
8615552b385SBrandon   if (*context) EGlite_deleteObject((ego)*context);
8627bee2925SMatthew Knepley   return 0;
8637bee2925SMatthew Knepley }
8647bee2925SMatthew Knepley 
8655552b385SBrandon PetscErrorCode DMPlexEGADSliteClose_Private(void **context)
866d71ae5a4SJacob Faibussowitsch {
8675552b385SBrandon   if (*context) EGlite_close((ego)*context);
8685552b385SBrandon   return 0;
8695552b385SBrandon }
8705552b385SBrandon 
8715552b385SBrandon PetscErrorCode DMPlexCreateGeom_Internal(MPI_Comm comm, ego context, ego model, DM *newdm, PetscBool islite)
8725552b385SBrandon {
8735552b385SBrandon   /* EGADS variables */
8747bee2925SMatthew Knepley   ego geom, *bodies, *objs, *nobjs, *mobjs, *lobjs;
8757bee2925SMatthew Knepley   int oclass, mtype, nbodies, *senses;
8767bee2925SMatthew Knepley   int b;
8777bee2925SMatthew Knepley   /* PETSc variables */
8787bee2925SMatthew Knepley   DM          dm;
8795552b385SBrandon   DMLabel     bodyLabel, faceLabel, edgeLabel, vertexLabel;
8807bee2925SMatthew Knepley   PetscHMapI  edgeMap = NULL;
8815552b385SBrandon   PetscInt    cStart, cEnd, c;
8827bee2925SMatthew Knepley   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;
8837bee2925SMatthew Knepley   PetscInt   *cells = NULL, *cone = NULL;
8847bee2925SMatthew Knepley   PetscReal  *coords = NULL;
8857bee2925SMatthew Knepley   PetscMPIInt rank;
8867bee2925SMatthew Knepley 
8877bee2925SMatthew Knepley   PetscFunctionBegin;
8889566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
889dd400576SPatrick Sanan   if (rank == 0) {
890266cfabeSMatthew G. Knepley     const PetscInt debug = 0;
891266cfabeSMatthew G. Knepley 
8927bee2925SMatthew Knepley     /* ---------------------------------------------------------------------------------------------------
8937bee2925SMatthew Knepley     Generate Petsc Plex
8947bee2925SMatthew Knepley       Get all Nodes in model, record coordinates in a correctly formatted array
8957bee2925SMatthew Knepley       Cycle through bodies, cycle through loops, recorde NODE IDs in a correctly formatted array
8967bee2925SMatthew Knepley       We need to uniformly refine the initial geometry to guarantee a valid mesh
8977bee2925SMatthew Knepley     */
8987bee2925SMatthew Knepley 
8997bee2925SMatthew Knepley     /* Calculate cell and vertex sizes */
9005552b385SBrandon     if (islite) {
9015552b385SBrandon       PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
9025552b385SBrandon     } else {
9039566063dSJacob Faibussowitsch       PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
9045552b385SBrandon     }
9055552b385SBrandon 
9069566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&edgeMap));
9077bee2925SMatthew Knepley     numEdges = 0;
9087bee2925SMatthew Knepley     for (b = 0; b < nbodies; ++b) {
9097bee2925SMatthew Knepley       ego body = bodies[b];
9107bee2925SMatthew Knepley       int id, Nl, l, Nv, v;
9117bee2925SMatthew Knepley 
9125552b385SBrandon       if (islite) {
9135552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
9145552b385SBrandon       } else {
9159566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
9165552b385SBrandon       }
9175552b385SBrandon 
9187bee2925SMatthew Knepley       for (l = 0; l < Nl; ++l) {
9197bee2925SMatthew Knepley         ego loop = lobjs[l];
9207bee2925SMatthew Knepley         int Ner  = 0, Ne, e, Nc;
9217bee2925SMatthew Knepley 
9225552b385SBrandon         if (islite) {
9235552b385SBrandon           PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
9245552b385SBrandon         } else {
9259566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
9265552b385SBrandon         }
9275552b385SBrandon 
9287bee2925SMatthew Knepley         for (e = 0; e < Ne; ++e) {
9297bee2925SMatthew Knepley           ego           edge = objs[e];
9307bee2925SMatthew Knepley           int           Nv, id;
9317bee2925SMatthew Knepley           PetscHashIter iter;
9327bee2925SMatthew Knepley           PetscBool     found;
9337bee2925SMatthew Knepley 
9345552b385SBrandon           if (islite) {
9355552b385SBrandon             PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
9365552b385SBrandon           } else {
9379566063dSJacob Faibussowitsch             PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
9385552b385SBrandon           }
9395552b385SBrandon 
9407bee2925SMatthew Knepley           if (mtype == DEGENERATE) continue;
9415552b385SBrandon 
9425552b385SBrandon           if (islite) {
9435552b385SBrandon             id = EGlite_indexBodyTopo(body, edge);
9445552b385SBrandon           } else {
9455f80ce2aSJacob Faibussowitsch             id = EG_indexBodyTopo(body, edge);
9465552b385SBrandon           }
9475552b385SBrandon 
9489566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(edgeMap, id - 1, &iter, &found));
9495552b385SBrandon           if (!found) { PetscCall(PetscHMapISet(edgeMap, id - 1, numEdges++)); }
9507bee2925SMatthew Knepley           ++Ner;
9517bee2925SMatthew Knepley         }
9529371c9d4SSatish Balay         if (Ner == 2) {
9539371c9d4SSatish Balay           Nc = 2;
9549371c9d4SSatish Balay         } else if (Ner == 3) {
9559371c9d4SSatish Balay           Nc = 4;
9569371c9d4SSatish Balay         } else if (Ner == 4) {
9579371c9d4SSatish Balay           Nc = 8;
9589371c9d4SSatish Balay           ++numQuads;
9599371c9d4SSatish Balay         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot support loop with %d edges", Ner);
9607bee2925SMatthew Knepley         numCells += Nc;
9617bee2925SMatthew Knepley         newCells += Nc - 1;
9627bee2925SMatthew Knepley         maxCorners = PetscMax(Ner * 2 + 1, maxCorners);
9637bee2925SMatthew Knepley       }
9645552b385SBrandon       if (islite) {
9655552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
9665552b385SBrandon       } else {
9679566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
9685552b385SBrandon       }
9695552b385SBrandon 
9707bee2925SMatthew Knepley       for (v = 0; v < Nv; ++v) {
9717bee2925SMatthew Knepley         ego vertex = nobjs[v];
9727bee2925SMatthew Knepley 
9735552b385SBrandon         if (islite) {
9745552b385SBrandon           id = EGlite_indexBodyTopo(body, vertex);
9755552b385SBrandon         } else {
9767bee2925SMatthew Knepley           id = EG_indexBodyTopo(body, vertex);
9775552b385SBrandon         }
9787bee2925SMatthew Knepley         /* TODO: Instead of assuming contiguous ids, we could use a hash table */
9797bee2925SMatthew Knepley         numVertices = PetscMax(id, numVertices);
9807bee2925SMatthew Knepley       }
9815552b385SBrandon       if (islite) {
9825552b385SBrandon         EGlite_free(lobjs);
9835552b385SBrandon         EGlite_free(nobjs);
9845552b385SBrandon       } else {
9857bee2925SMatthew Knepley         EG_free(lobjs);
9867bee2925SMatthew Knepley         EG_free(nobjs);
9877bee2925SMatthew Knepley       }
9885552b385SBrandon     }
9899566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGetSize(edgeMap, &numEdges));
9907bee2925SMatthew Knepley     newVertices = numEdges + numQuads;
9917bee2925SMatthew Knepley     numVertices += newVertices;
9927bee2925SMatthew Knepley 
9937bee2925SMatthew Knepley     dim        = 2; /* Assume 3D Models :: Need to update to handle 2D Models in the future */
9947bee2925SMatthew Knepley     cdim       = 3; /* Assume 3D Models :: Need to update to handle 2D Models in the future */
9957bee2925SMatthew Knepley     numCorners = 3; /* Split cells into triangles */
9969566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(numVertices * cdim, &coords, numCells * numCorners, &cells, maxCorners, &cone));
9977bee2925SMatthew Knepley 
9987bee2925SMatthew Knepley     /* Get vertex coordinates */
9997bee2925SMatthew Knepley     for (b = 0; b < nbodies; ++b) {
10007bee2925SMatthew Knepley       ego body = bodies[b];
10017bee2925SMatthew Knepley       int id, Nv, v;
10027bee2925SMatthew Knepley 
10035552b385SBrandon       if (islite) {
10045552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
10055552b385SBrandon       } else {
10069566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
10075552b385SBrandon       }
10085552b385SBrandon 
10097bee2925SMatthew Knepley       for (v = 0; v < Nv; ++v) {
10107bee2925SMatthew Knepley         ego    vertex = nobjs[v];
10117bee2925SMatthew Knepley         double limits[4];
10127bee2925SMatthew Knepley         int    dummy;
10137bee2925SMatthew Knepley 
10145552b385SBrandon         if (islite) {
10155552b385SBrandon           PetscCall(EGlite_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
10165552b385SBrandon           id = EGlite_indexBodyTopo(body, vertex);
10175552b385SBrandon         } else {
10189566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
10195f80ce2aSJacob Faibussowitsch           id = EG_indexBodyTopo(body, vertex);
10205552b385SBrandon         }
10215552b385SBrandon 
10227bee2925SMatthew Knepley         coords[(id - 1) * cdim + 0] = limits[0];
10237bee2925SMatthew Knepley         coords[(id - 1) * cdim + 1] = limits[1];
10247bee2925SMatthew Knepley         coords[(id - 1) * cdim + 2] = limits[2];
10257bee2925SMatthew Knepley       }
10265552b385SBrandon       if (islite) {
10275552b385SBrandon         EGlite_free(nobjs);
10285552b385SBrandon       } else {
10297bee2925SMatthew Knepley         EG_free(nobjs);
10307bee2925SMatthew Knepley       }
10315552b385SBrandon     }
10329566063dSJacob Faibussowitsch     PetscCall(PetscHMapIClear(edgeMap));
10337bee2925SMatthew Knepley     fOff     = numVertices - newVertices + numEdges;
10347bee2925SMatthew Knepley     numEdges = 0;
10357bee2925SMatthew Knepley     numQuads = 0;
10367bee2925SMatthew Knepley     for (b = 0; b < nbodies; ++b) {
10377bee2925SMatthew Knepley       ego body = bodies[b];
10387bee2925SMatthew Knepley       int Nl, l;
10397bee2925SMatthew Knepley 
10405552b385SBrandon       if (islite) {
10415552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
10425552b385SBrandon       } else {
10439566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
10445552b385SBrandon       }
10455552b385SBrandon 
10467bee2925SMatthew Knepley       for (l = 0; l < Nl; ++l) {
10477bee2925SMatthew Knepley         ego loop = lobjs[l];
10487bee2925SMatthew Knepley         int lid, Ner = 0, Ne, e;
10497bee2925SMatthew Knepley 
10505552b385SBrandon         if (islite) {
10515552b385SBrandon           lid = EGlite_indexBodyTopo(body, loop);
10525552b385SBrandon           PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
10535552b385SBrandon         } else {
10545f80ce2aSJacob Faibussowitsch           lid = EG_indexBodyTopo(body, loop);
10559566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
10565552b385SBrandon         }
10575552b385SBrandon 
10587bee2925SMatthew Knepley         for (e = 0; e < Ne; ++e) {
10597bee2925SMatthew Knepley           ego           edge = objs[e];
10607bee2925SMatthew Knepley           int           eid, Nv;
10617bee2925SMatthew Knepley           PetscHashIter iter;
10627bee2925SMatthew Knepley           PetscBool     found;
10637bee2925SMatthew Knepley 
10645552b385SBrandon           if (islite) {
10655552b385SBrandon             PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
10665552b385SBrandon           } else {
10679566063dSJacob Faibussowitsch             PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
10685552b385SBrandon           }
10695552b385SBrandon 
10707bee2925SMatthew Knepley           if (mtype == DEGENERATE) continue;
10717bee2925SMatthew Knepley           ++Ner;
10725552b385SBrandon 
10735552b385SBrandon           if (islite) {
10745552b385SBrandon             eid = EGlite_indexBodyTopo(body, edge);
10755552b385SBrandon           } else {
10765f80ce2aSJacob Faibussowitsch             eid = EG_indexBodyTopo(body, edge);
10775552b385SBrandon           }
10785552b385SBrandon 
10799566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(edgeMap, eid - 1, &iter, &found));
10807bee2925SMatthew Knepley           if (!found) {
10817bee2925SMatthew Knepley             PetscInt v = numVertices - newVertices + numEdges;
10827bee2925SMatthew Knepley             double   range[4], params[3] = {0., 0., 0.}, result[18];
10837bee2925SMatthew Knepley             int      periodic[2];
10847bee2925SMatthew Knepley 
10859566063dSJacob Faibussowitsch             PetscCall(PetscHMapISet(edgeMap, eid - 1, numEdges++));
10865552b385SBrandon 
10875552b385SBrandon             if (islite) {
10885552b385SBrandon               PetscCall(EGlite_getRange(edge, range, periodic));
10895552b385SBrandon             } else {
10909566063dSJacob Faibussowitsch               PetscCall(EG_getRange(edge, range, periodic));
10915552b385SBrandon             }
10925552b385SBrandon 
10937bee2925SMatthew Knepley             params[0] = 0.5 * (range[0] + range[1]);
10945552b385SBrandon             if (islite) {
10955552b385SBrandon               PetscCall(EGlite_evaluate(edge, params, result));
10965552b385SBrandon             } else {
10979566063dSJacob Faibussowitsch               PetscCall(EG_evaluate(edge, params, result));
10985552b385SBrandon             }
10997bee2925SMatthew Knepley             coords[v * cdim + 0] = result[0];
11007bee2925SMatthew Knepley             coords[v * cdim + 1] = result[1];
11017bee2925SMatthew Knepley             coords[v * cdim + 2] = result[2];
11027bee2925SMatthew Knepley           }
11037bee2925SMatthew Knepley         }
11047bee2925SMatthew Knepley         if (Ner == 4) {
11057bee2925SMatthew Knepley           PetscInt v = fOff + numQuads++;
1106266cfabeSMatthew G. Knepley           ego     *fobjs, face;
11077bee2925SMatthew Knepley           double   range[4], params[3] = {0., 0., 0.}, result[18];
1108266cfabeSMatthew G. Knepley           int      Nf, fid, periodic[2];
11097bee2925SMatthew Knepley 
11105552b385SBrandon           if (islite) {
11115552b385SBrandon             PetscCall(EGlite_getBodyTopos(body, loop, FACE, &Nf, &fobjs));
11125552b385SBrandon           } else {
11139566063dSJacob Faibussowitsch             PetscCall(EG_getBodyTopos(body, loop, FACE, &Nf, &fobjs));
11145552b385SBrandon           }
1115266cfabeSMatthew G. Knepley           face = fobjs[0];
11165552b385SBrandon 
11175552b385SBrandon           if (islite) {
11185552b385SBrandon             fid = EGlite_indexBodyTopo(body, face);
11195552b385SBrandon           } else {
11205f80ce2aSJacob Faibussowitsch             fid = EG_indexBodyTopo(body, face);
11215552b385SBrandon           }
11225552b385SBrandon 
11235552b385SBrandon           PetscCheck(Nf != 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Loop %d has %" PetscInt_FMT " faces, instead of 1 (%" PetscInt_FMT ")", lid - 1, Nf, fid);
11245552b385SBrandon           if (islite) {
11255552b385SBrandon             PetscCall(EGlite_getRange(face, range, periodic));
11265552b385SBrandon           } else {
11279566063dSJacob Faibussowitsch             PetscCall(EG_getRange(face, range, periodic));
11285552b385SBrandon           }
11297bee2925SMatthew Knepley           params[0] = 0.5 * (range[0] + range[1]);
11307bee2925SMatthew Knepley           params[1] = 0.5 * (range[2] + range[3]);
11315552b385SBrandon           if (islite) {
11325552b385SBrandon             PetscCall(EGlite_evaluate(face, params, result));
11335552b385SBrandon           } else {
11349566063dSJacob Faibussowitsch             PetscCall(EG_evaluate(face, params, result));
11355552b385SBrandon           }
11367bee2925SMatthew Knepley           coords[v * cdim + 0] = result[0];
11377bee2925SMatthew Knepley           coords[v * cdim + 1] = result[1];
11387bee2925SMatthew Knepley           coords[v * cdim + 2] = result[2];
11397bee2925SMatthew Knepley         }
11407bee2925SMatthew Knepley       }
11417bee2925SMatthew Knepley     }
11425552b385SBrandon     PetscCheck(numEdges + numQuads == newVertices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of new vertices %d != %d previous count", numEdges + numQuads, newVertices);
11437bee2925SMatthew Knepley 
11447bee2925SMatthew Knepley     /* Get cell vertices by traversing loops */
11457bee2925SMatthew Knepley     numQuads = 0;
11467bee2925SMatthew Knepley     cOff     = 0;
11477bee2925SMatthew Knepley     for (b = 0; b < nbodies; ++b) {
11487bee2925SMatthew Knepley       ego body = bodies[b];
11497bee2925SMatthew Knepley       int id, Nl, l;
11507bee2925SMatthew Knepley 
11515552b385SBrandon       if (islite) {
11525552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
11535552b385SBrandon       } else {
11549566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
11555552b385SBrandon       }
11567bee2925SMatthew Knepley       for (l = 0; l < Nl; ++l) {
11577bee2925SMatthew Knepley         ego loop = lobjs[l];
11587bee2925SMatthew Knepley         int lid, Ner = 0, Ne, e, nc = 0, c, Nt, t;
11597bee2925SMatthew Knepley 
11605552b385SBrandon         if (islite) {
11615552b385SBrandon           lid = EGlite_indexBodyTopo(body, loop);
11625552b385SBrandon           PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
11635552b385SBrandon         } else {
11645f80ce2aSJacob Faibussowitsch           lid = EG_indexBodyTopo(body, loop);
11659566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
11665552b385SBrandon         }
11677bee2925SMatthew Knepley 
11687bee2925SMatthew Knepley         for (e = 0; e < Ne; ++e) {
11697bee2925SMatthew Knepley           ego edge = objs[e];
11707bee2925SMatthew Knepley           int points[3];
11717bee2925SMatthew Knepley           int eid, Nv, v, tmp;
11727bee2925SMatthew Knepley 
11735552b385SBrandon           if (islite) {
11745552b385SBrandon             eid = EGlite_indexBodyTopo(body, edge);
11755552b385SBrandon             PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
11765552b385SBrandon           } else {
11777bee2925SMatthew Knepley             eid = EG_indexBodyTopo(body, edge);
11789566063dSJacob Faibussowitsch             PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
11795552b385SBrandon           }
11805552b385SBrandon 
1181266cfabeSMatthew G. Knepley           if (mtype == DEGENERATE) continue;
1182266cfabeSMatthew G. Knepley           else ++Ner;
11835552b385SBrandon           PetscCheck(Nv == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Edge %" PetscInt_FMT " has %" PetscInt_FMT " vertices != 2", eid, Nv);
11847bee2925SMatthew Knepley 
11857bee2925SMatthew Knepley           for (v = 0; v < Nv; ++v) {
11867bee2925SMatthew Knepley             ego vertex = nobjs[v];
11877bee2925SMatthew Knepley 
11885552b385SBrandon             if (islite) {
11895552b385SBrandon               id = EGlite_indexBodyTopo(body, vertex);
11905552b385SBrandon             } else {
11917bee2925SMatthew Knepley               id = EG_indexBodyTopo(body, vertex);
11925552b385SBrandon             }
11937bee2925SMatthew Knepley             points[v * 2] = id - 1;
11947bee2925SMatthew Knepley           }
11957bee2925SMatthew Knepley           {
11967bee2925SMatthew Knepley             PetscInt edgeNum;
11977bee2925SMatthew Knepley 
11989566063dSJacob Faibussowitsch             PetscCall(PetscHMapIGet(edgeMap, eid - 1, &edgeNum));
11997bee2925SMatthew Knepley             points[1] = numVertices - newVertices + edgeNum;
12007bee2925SMatthew Knepley           }
12017bee2925SMatthew Knepley           /* EGADS loops are not oriented, but seem to be in order, so we must piece them together */
12027bee2925SMatthew Knepley           if (!nc) {
12037bee2925SMatthew Knepley             for (v = 0; v < Nv + 1; ++v) cone[nc++] = points[v];
12047bee2925SMatthew Knepley           } else {
12059371c9d4SSatish Balay             if (cone[nc - 1] == points[0]) {
12069371c9d4SSatish Balay               cone[nc++] = points[1];
12079371c9d4SSatish Balay               if (cone[0] != points[2]) cone[nc++] = points[2];
12089371c9d4SSatish Balay             } else if (cone[nc - 1] == points[2]) {
12099371c9d4SSatish Balay               cone[nc++] = points[1];
12109371c9d4SSatish Balay               if (cone[0] != points[0]) cone[nc++] = points[0];
12119371c9d4SSatish Balay             } else if (cone[nc - 3] == points[0]) {
12129371c9d4SSatish Balay               tmp          = cone[nc - 3];
12139371c9d4SSatish Balay               cone[nc - 3] = cone[nc - 1];
12149371c9d4SSatish Balay               cone[nc - 1] = tmp;
12159371c9d4SSatish Balay               cone[nc++]   = points[1];
12169371c9d4SSatish Balay               if (cone[0] != points[2]) cone[nc++] = points[2];
12179371c9d4SSatish Balay             } else if (cone[nc - 3] == points[2]) {
12189371c9d4SSatish Balay               tmp          = cone[nc - 3];
12199371c9d4SSatish Balay               cone[nc - 3] = cone[nc - 1];
12209371c9d4SSatish Balay               cone[nc - 1] = tmp;
12219371c9d4SSatish Balay               cone[nc++]   = points[1];
12229371c9d4SSatish Balay               if (cone[0] != points[0]) cone[nc++] = points[0];
12239371c9d4SSatish Balay             } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %d does not match its predecessor", eid);
12247bee2925SMatthew Knepley           }
12257bee2925SMatthew Knepley         }
122663a3b9bcSJacob Faibussowitsch         PetscCheck(nc == 2 * Ner, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of corners %" PetscInt_FMT " != %" PetscInt_FMT, nc, 2 * Ner);
12275552b385SBrandon         if (Ner == 4) { cone[nc++] = numVertices - newVertices + numEdges + numQuads++; }
122863a3b9bcSJacob Faibussowitsch         PetscCheck(nc <= maxCorners, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of corners %" PetscInt_FMT " > %" PetscInt_FMT " max", nc, maxCorners);
12297bee2925SMatthew Knepley         /* Triangulate the loop */
12307bee2925SMatthew Knepley         switch (Ner) {
12317bee2925SMatthew Knepley         case 2: /* Bi-Segment -> 2 triangles */
12327bee2925SMatthew Knepley           Nt                           = 2;
12337bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[0];
12347bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[1];
12357bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[2];
12367bee2925SMatthew Knepley           ++cOff;
12377bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[0];
12387bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[2];
12397bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[3];
12407bee2925SMatthew Knepley           ++cOff;
12417bee2925SMatthew Knepley           break;
12427bee2925SMatthew Knepley         case 3: /* Triangle   -> 4 triangles */
12437bee2925SMatthew Knepley           Nt                           = 4;
12447bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[0];
12457bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[1];
12467bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[5];
12477bee2925SMatthew Knepley           ++cOff;
12487bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[1];
12497bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[2];
12507bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[3];
12517bee2925SMatthew Knepley           ++cOff;
12527bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[5];
12537bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[3];
12547bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[4];
12557bee2925SMatthew Knepley           ++cOff;
12567bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[1];
12577bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[3];
12587bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[5];
12597bee2925SMatthew Knepley           ++cOff;
12607bee2925SMatthew Knepley           break;
12617bee2925SMatthew Knepley         case 4: /* Quad       -> 8 triangles */
12627bee2925SMatthew Knepley           Nt                           = 8;
12637bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[0];
12647bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[1];
12657bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[7];
12667bee2925SMatthew Knepley           ++cOff;
12677bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[1];
12687bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[2];
12697bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[3];
12707bee2925SMatthew Knepley           ++cOff;
12717bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[3];
12727bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[4];
12737bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[5];
12747bee2925SMatthew Knepley           ++cOff;
12757bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[5];
12767bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[6];
12777bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[7];
12787bee2925SMatthew Knepley           ++cOff;
12797bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[8];
12807bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[1];
12817bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[3];
12827bee2925SMatthew Knepley           ++cOff;
12837bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[8];
12847bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[3];
12857bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[5];
12867bee2925SMatthew Knepley           ++cOff;
12877bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[8];
12887bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[5];
12897bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[7];
12907bee2925SMatthew Knepley           ++cOff;
12917bee2925SMatthew Knepley           cells[cOff * numCorners + 0] = cone[8];
12927bee2925SMatthew Knepley           cells[cOff * numCorners + 1] = cone[7];
12937bee2925SMatthew Knepley           cells[cOff * numCorners + 2] = cone[1];
12947bee2925SMatthew Knepley           ++cOff;
12957bee2925SMatthew Knepley           break;
1296d71ae5a4SJacob Faibussowitsch         default:
1297d71ae5a4SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %d has %d edges, which we do not support", lid, Ner);
12987bee2925SMatthew Knepley         }
1299266cfabeSMatthew G. Knepley         if (debug) {
13007bee2925SMatthew Knepley           for (t = 0; t < Nt; ++t) {
13015552b385SBrandon             PetscCall(PetscPrintf(PETSC_COMM_SELF, "  LOOP Corner NODEs Triangle %d (", t));
13027bee2925SMatthew Knepley             for (c = 0; c < numCorners; ++c) {
13035552b385SBrandon               if (c > 0) { PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); }
13045552b385SBrandon               PetscCall(PetscPrintf(PETSC_COMM_SELF, "%d", cells[(cOff - Nt + t) * numCorners + c]));
13057bee2925SMatthew Knepley             }
13069566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
13077bee2925SMatthew Knepley           }
13087bee2925SMatthew Knepley         }
1309266cfabeSMatthew G. Knepley       }
13105552b385SBrandon       if (islite) {
13115552b385SBrandon         EGlite_free(lobjs);
13125552b385SBrandon       } else {
13137bee2925SMatthew Knepley         EG_free(lobjs);
13147bee2925SMatthew Knepley       }
13157bee2925SMatthew Knepley     }
13165552b385SBrandon   }
13175552b385SBrandon   PetscCheck(cOff == numCells, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Count of total cells %d != %d previous count", cOff, numCells);
13189566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, numCells, numVertices, numCorners, PETSC_TRUE, cells, cdim, coords, &dm));
13199566063dSJacob Faibussowitsch   PetscCall(PetscFree3(coords, cells, cone));
13205552b385SBrandon   PetscCall(PetscInfo(dm, " Total Number of Unique Cells    = %d (%d)\n", numCells, newCells));
13215552b385SBrandon   PetscCall(PetscInfo(dm, " Total Number of Unique Vertices = %d (%d)\n", numVertices, newVertices));
13227bee2925SMatthew Knepley   /* Embed EGADS model in DM */
13237bee2925SMatthew Knepley   {
13247bee2925SMatthew Knepley     PetscContainer modelObj, contextObj;
13257bee2925SMatthew Knepley 
13269566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &modelObj));
13279566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(modelObj, model));
13285552b385SBrandon     PetscCall(PetscContainerSetCtxDestroy(modelObj, (PetscCtxDestroyFn *)DMPlexEGADSDestroy_Private));
13299566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Model", (PetscObject)modelObj));
13309566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&modelObj));
13317bee2925SMatthew Knepley 
13329566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &contextObj));
13339566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(contextObj, context));
13345552b385SBrandon     PetscCall(PetscContainerSetCtxDestroy(contextObj, (PetscCtxDestroyFn *)DMPlexEGADSClose_Private));
13359566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Context", (PetscObject)contextObj));
13369566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&contextObj));
13377bee2925SMatthew Knepley   }
13387bee2925SMatthew Knepley   /* Label points */
13399566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Body ID"));
13409566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
13419566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Face ID"));
13429566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
13439566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Edge ID"));
13449566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
13459566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Vertex ID"));
13469566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
13477bee2925SMatthew Knepley   cOff = 0;
13487bee2925SMatthew Knepley   for (b = 0; b < nbodies; ++b) {
13497bee2925SMatthew Knepley     ego body = bodies[b];
13507bee2925SMatthew Knepley     int id, Nl, l;
13517bee2925SMatthew Knepley 
13525552b385SBrandon     if (islite) {
13535552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
13545552b385SBrandon     } else {
13559566063dSJacob Faibussowitsch       PetscCall(EG_getBodyTopos(body, NULL, LOOP, &Nl, &lobjs));
13565552b385SBrandon     }
13577bee2925SMatthew Knepley     for (l = 0; l < Nl; ++l) {
13587bee2925SMatthew Knepley       ego  loop = lobjs[l];
13597bee2925SMatthew Knepley       ego *fobjs;
13607bee2925SMatthew Knepley       int  lid, Nf, fid, Ner = 0, Ne, e, Nt = 0, t;
13617bee2925SMatthew Knepley 
13625552b385SBrandon       if (islite) {
13635552b385SBrandon         lid = EGlite_indexBodyTopo(body, loop);
13645552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, loop, FACE, &Nf, &fobjs));
13655552b385SBrandon       } else {
13665f80ce2aSJacob Faibussowitsch         lid = EG_indexBodyTopo(body, loop);
13679566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, loop, FACE, &Nf, &fobjs));
13685552b385SBrandon       }
13695552b385SBrandon 
137008401ef6SPierre Jolivet       PetscCheck(Nf <= 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %d has %d > 1 faces, which is not supported", lid, Nf);
13715552b385SBrandon       if (islite) {
13725552b385SBrandon         fid = EGlite_indexBodyTopo(body, fobjs[0]);
13735552b385SBrandon         EGlite_free(fobjs);
13745552b385SBrandon         PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
13755552b385SBrandon       } else {
13765f80ce2aSJacob Faibussowitsch         fid = EG_indexBodyTopo(body, fobjs[0]);
13777bee2925SMatthew Knepley         EG_free(fobjs);
13789566063dSJacob Faibussowitsch         PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &objs, &senses));
13795552b385SBrandon       }
13805552b385SBrandon 
13817bee2925SMatthew Knepley       for (e = 0; e < Ne; ++e) {
13827bee2925SMatthew Knepley         ego             edge = objs[e];
13837bee2925SMatthew Knepley         int             eid, Nv, v;
13847bee2925SMatthew Knepley         PetscInt        points[3], support[2], numEdges, edgeNum;
13857bee2925SMatthew Knepley         const PetscInt *edges;
13867bee2925SMatthew Knepley 
13875552b385SBrandon         if (islite) {
13885552b385SBrandon           eid = EGlite_indexBodyTopo(body, edge);
13895552b385SBrandon           PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
13905552b385SBrandon         } else {
13917bee2925SMatthew Knepley           eid = EG_indexBodyTopo(body, edge);
13929566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
13935552b385SBrandon         }
13945552b385SBrandon 
13957bee2925SMatthew Knepley         if (mtype == DEGENERATE) continue;
13967bee2925SMatthew Knepley         else ++Ner;
13977bee2925SMatthew Knepley         for (v = 0; v < Nv; ++v) {
13987bee2925SMatthew Knepley           ego vertex = nobjs[v];
13997bee2925SMatthew Knepley 
14005552b385SBrandon           if (islite) {
14015552b385SBrandon             id = EGlite_indexBodyTopo(body, vertex);
14025552b385SBrandon           } else {
14037bee2925SMatthew Knepley             id = EG_indexBodyTopo(body, vertex);
14045552b385SBrandon           }
14055552b385SBrandon 
14069566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(edgeLabel, numCells + id - 1, eid));
14077bee2925SMatthew Knepley           points[v * 2] = numCells + id - 1;
14087bee2925SMatthew Knepley         }
14099566063dSJacob Faibussowitsch         PetscCall(PetscHMapIGet(edgeMap, eid - 1, &edgeNum));
14107bee2925SMatthew Knepley         points[1] = numCells + numVertices - newVertices + edgeNum;
14117bee2925SMatthew Knepley 
14129566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(edgeLabel, points[1], eid));
14137bee2925SMatthew Knepley         support[0] = points[0];
14147bee2925SMatthew Knepley         support[1] = points[1];
14159566063dSJacob Faibussowitsch         PetscCall(DMPlexGetJoin(dm, 2, support, &numEdges, &edges));
14165552b385SBrandon         PetscCheck(numEdges == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Vertices (%d, %d) should only bound 1 edge, not %d", support[0], support[1], numEdges);
14179566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(edgeLabel, edges[0], eid));
14189566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreJoin(dm, 2, support, &numEdges, &edges));
14197bee2925SMatthew Knepley         support[0] = points[1];
14207bee2925SMatthew Knepley         support[1] = points[2];
14219566063dSJacob Faibussowitsch         PetscCall(DMPlexGetJoin(dm, 2, support, &numEdges, &edges));
14225552b385SBrandon         PetscCheck(numEdges == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Vertices (%d, %d) should only bound 1 edge, not %d", support[0], support[1], numEdges);
14239566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(edgeLabel, edges[0], eid));
14249566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreJoin(dm, 2, support, &numEdges, &edges));
14257bee2925SMatthew Knepley       }
14267bee2925SMatthew Knepley       switch (Ner) {
1427d71ae5a4SJacob Faibussowitsch       case 2:
1428d71ae5a4SJacob Faibussowitsch         Nt = 2;
1429d71ae5a4SJacob Faibussowitsch         break;
1430d71ae5a4SJacob Faibussowitsch       case 3:
1431d71ae5a4SJacob Faibussowitsch         Nt = 4;
1432d71ae5a4SJacob Faibussowitsch         break;
1433d71ae5a4SJacob Faibussowitsch       case 4:
1434d71ae5a4SJacob Faibussowitsch         Nt = 8;
1435d71ae5a4SJacob Faibussowitsch         break;
1436d71ae5a4SJacob Faibussowitsch       default:
1437d71ae5a4SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Loop with %d edges is unsupported", Ner);
14387bee2925SMatthew Knepley       }
14397bee2925SMatthew Knepley       for (t = 0; t < Nt; ++t) {
14409566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(bodyLabel, cOff + t, b));
14419566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(faceLabel, cOff + t, fid));
14427bee2925SMatthew Knepley       }
14437bee2925SMatthew Knepley       cOff += Nt;
14447bee2925SMatthew Knepley     }
14455552b385SBrandon     if (islite) {
14465552b385SBrandon       EGlite_free(lobjs);
14475552b385SBrandon     } else {
14487bee2925SMatthew Knepley       EG_free(lobjs);
14497bee2925SMatthew Knepley     }
14505552b385SBrandon   }
14519566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&edgeMap));
14529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
14537bee2925SMatthew Knepley   for (c = cStart; c < cEnd; ++c) {
14547bee2925SMatthew Knepley     PetscInt *closure = NULL;
14557bee2925SMatthew Knepley     PetscInt  clSize, cl, bval, fval;
14567bee2925SMatthew Knepley 
14579566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
14589566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(bodyLabel, c, &bval));
14599566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(faceLabel, c, &fval));
14607bee2925SMatthew Knepley     for (cl = 0; cl < clSize * 2; cl += 2) {
14619566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(bodyLabel, closure[cl], bval));
14629566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(faceLabel, closure[cl], fval));
14637bee2925SMatthew Knepley     }
14649566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
14657bee2925SMatthew Knepley   }
14667bee2925SMatthew Knepley   *newdm = dm;
14675552b385SBrandon   PetscFunctionReturn(0);
14687bee2925SMatthew Knepley }
1469c1cad2e7SMatthew G. Knepley 
14705552b385SBrandon PetscErrorCode DMPlexCreateGeom(MPI_Comm comm, ego context, ego model, DM *newdm, PetscBool islite)
1471d71ae5a4SJacob Faibussowitsch {
14725552b385SBrandon   // EGADS variables
1473c1cad2e7SMatthew G. Knepley   ego geom, *bodies, *mobjs, *fobjs, *lobjs, *eobjs, *nobjs;
1474c1cad2e7SMatthew G. Knepley   ego topRef, prev, next;
1475c1cad2e7SMatthew G. Knepley   int oclass, mtype, nbodies, *senses, *lSenses, *eSenses;
1476c1cad2e7SMatthew G. Knepley   int b;
1477c1cad2e7SMatthew G. Knepley   // PETSc variables
1478c1cad2e7SMatthew G. Knepley   DM              dm;
14795552b385SBrandon   DMLabel         bodyLabel, faceLabel, edgeLabel, vertexLabel;
1480c1cad2e7SMatthew G. Knepley   PetscHMapI      edgeMap = NULL, bodyIndexMap = NULL, bodyVertexMap = NULL, bodyEdgeMap = NULL, bodyFaceMap = NULL, bodyEdgeGlobalMap = NULL;
1481c1cad2e7SMatthew G. Knepley   PetscInt        dim = -1, cdim = -1, numCorners = 0, numVertices = 0, numEdges = 0, numFaces = 0, numCells = 0, edgeCntr = 0;
1482c1cad2e7SMatthew G. Knepley   PetscInt        cellCntr = 0, numPoints = 0;
1483c1cad2e7SMatthew G. Knepley   PetscInt       *cells  = NULL;
1484c1cad2e7SMatthew G. Knepley   const PetscInt *cone   = NULL;
1485c1cad2e7SMatthew G. Knepley   PetscReal      *coords = NULL;
1486c1cad2e7SMatthew G. Knepley   PetscMPIInt     rank;
1487c1cad2e7SMatthew G. Knepley 
1488c1cad2e7SMatthew G. Knepley   PetscFunctionBeginUser;
14899566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1490c5853193SPierre Jolivet   if (rank == 0) {
1491c1cad2e7SMatthew G. Knepley     // ---------------------------------------------------------------------------------------------------
1492c1cad2e7SMatthew G. Knepley     // Generate Petsc Plex
1493c1cad2e7SMatthew G. Knepley     //  Get all Nodes in model, record coordinates in a correctly formatted array
1494c1cad2e7SMatthew G. Knepley     //  Cycle through bodies, cycle through loops, recorde NODE IDs in a correctly formatted array
1495c1cad2e7SMatthew G. Knepley     //  We need to uniformly refine the initial geometry to guarantee a valid mesh
1496c1cad2e7SMatthew G. Knepley 
1497d5b43468SJose E. Roman     // Calculate cell and vertex sizes
14985552b385SBrandon     if (islite) {
14995552b385SBrandon       PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
15005552b385SBrandon     } else {
15019566063dSJacob Faibussowitsch       PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
15025552b385SBrandon     }
15039566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&edgeMap));
15049566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyIndexMap));
15059566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyVertexMap));
15069566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyEdgeMap));
15079566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyEdgeGlobalMap));
15089566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&bodyFaceMap));
1509c1cad2e7SMatthew G. Knepley 
1510c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
1511c1cad2e7SMatthew G. Knepley       ego           body = bodies[b];
1512c1cad2e7SMatthew G. Knepley       int           Nf, Ne, Nv;
1513c1cad2e7SMatthew G. Knepley       PetscHashIter BIiter, BViter, BEiter, BEGiter, BFiter, EMiter;
1514c1cad2e7SMatthew G. Knepley       PetscBool     BIfound, BVfound, BEfound, BEGfound, BFfound, EMfound;
1515c1cad2e7SMatthew G. Knepley 
15169566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyIndexMap, b, &BIiter, &BIfound));
15179566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
15189566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
15199566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
15209566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
1521c1cad2e7SMatthew G. Knepley 
15229566063dSJacob Faibussowitsch       if (!BIfound) PetscCall(PetscHMapISet(bodyIndexMap, b, numFaces + numEdges + numVertices));
15239566063dSJacob Faibussowitsch       if (!BVfound) PetscCall(PetscHMapISet(bodyVertexMap, b, numVertices));
15249566063dSJacob Faibussowitsch       if (!BEfound) PetscCall(PetscHMapISet(bodyEdgeMap, b, numEdges));
15259566063dSJacob Faibussowitsch       if (!BEGfound) PetscCall(PetscHMapISet(bodyEdgeGlobalMap, b, edgeCntr));
15269566063dSJacob Faibussowitsch       if (!BFfound) PetscCall(PetscHMapISet(bodyFaceMap, b, numFaces));
1527c1cad2e7SMatthew G. Knepley 
15285552b385SBrandon       if (islite) {
15295552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
15305552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
15315552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
15325552b385SBrandon         EGlite_free(fobjs);
15335552b385SBrandon         EGlite_free(eobjs);
15345552b385SBrandon         EGlite_free(nobjs);
15355552b385SBrandon       } else {
15369566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
15379566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
15389566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
1539c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
1540c1cad2e7SMatthew G. Knepley         EG_free(eobjs);
1541c1cad2e7SMatthew G. Knepley         EG_free(nobjs);
15425552b385SBrandon       }
1543c1cad2e7SMatthew G. Knepley 
1544c1cad2e7SMatthew G. Knepley       // Remove DEGENERATE EDGES from Edge count
15455552b385SBrandon       if (islite) {
15465552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
15475552b385SBrandon       } else {
15489566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
15495552b385SBrandon       }
15505552b385SBrandon 
1551c1cad2e7SMatthew G. Knepley       int Netemp = 0;
1552c1cad2e7SMatthew G. Knepley       for (int e = 0; e < Ne; ++e) {
1553c1cad2e7SMatthew G. Knepley         ego edge = eobjs[e];
1554c1cad2e7SMatthew G. Knepley         int eid;
1555c1cad2e7SMatthew G. Knepley 
15565552b385SBrandon         if (islite) {
15575552b385SBrandon           PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
15585552b385SBrandon           eid = EGlite_indexBodyTopo(body, edge);
15595552b385SBrandon         } else {
15609566063dSJacob Faibussowitsch           PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
15615f80ce2aSJacob Faibussowitsch           eid = EG_indexBodyTopo(body, edge);
15625552b385SBrandon         }
1563c1cad2e7SMatthew G. Knepley 
15649566063dSJacob Faibussowitsch         PetscCall(PetscHMapIFind(edgeMap, edgeCntr + eid - 1, &EMiter, &EMfound));
1565c1cad2e7SMatthew G. Knepley         if (mtype == DEGENERATE) {
15669566063dSJacob Faibussowitsch           if (!EMfound) PetscCall(PetscHMapISet(edgeMap, edgeCntr + eid - 1, -1));
15679371c9d4SSatish Balay         } else {
1568c1cad2e7SMatthew G. Knepley           ++Netemp;
15699566063dSJacob Faibussowitsch           if (!EMfound) PetscCall(PetscHMapISet(edgeMap, edgeCntr + eid - 1, Netemp));
1570c1cad2e7SMatthew G. Knepley         }
1571c1cad2e7SMatthew G. Knepley       }
15725552b385SBrandon       if (islite) {
15735552b385SBrandon         EGlite_free(eobjs);
15745552b385SBrandon       } else {
1575c1cad2e7SMatthew G. Knepley         EG_free(eobjs);
15765552b385SBrandon       }
1577c1cad2e7SMatthew G. Knepley 
1578c1cad2e7SMatthew G. Knepley       // Determine Number of Cells
15795552b385SBrandon       if (islite) {
15805552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
15815552b385SBrandon       } else {
15829566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
15835552b385SBrandon       }
15845552b385SBrandon 
1585c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
1586c1cad2e7SMatthew G. Knepley         ego face     = fobjs[f];
1587c1cad2e7SMatthew G. Knepley         int edgeTemp = 0;
1588c1cad2e7SMatthew G. Knepley 
15895552b385SBrandon         if (islite) {
15905552b385SBrandon           PetscCall(EGlite_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
15915552b385SBrandon         } else {
15929566063dSJacob Faibussowitsch           PetscCall(EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
15935552b385SBrandon         }
15945552b385SBrandon 
1595c1cad2e7SMatthew G. Knepley         for (int e = 0; e < Ne; ++e) {
1596c1cad2e7SMatthew G. Knepley           ego edge = eobjs[e];
1597c1cad2e7SMatthew G. Knepley 
15985552b385SBrandon           if (islite) {
15995552b385SBrandon             PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
16005552b385SBrandon           } else {
16019566063dSJacob Faibussowitsch             PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
16025552b385SBrandon           }
1603ad540459SPierre Jolivet           if (mtype != DEGENERATE) ++edgeTemp;
1604c1cad2e7SMatthew G. Knepley         }
1605c1cad2e7SMatthew G. Knepley         numCells += (2 * edgeTemp);
16065552b385SBrandon         if (islite) {
16075552b385SBrandon           EGlite_free(eobjs);
16085552b385SBrandon         } else {
1609c1cad2e7SMatthew G. Knepley           EG_free(eobjs);
1610c1cad2e7SMatthew G. Knepley         }
16115552b385SBrandon       }
16125552b385SBrandon       if (islite) {
16135552b385SBrandon         EGlite_free(fobjs);
16145552b385SBrandon       } else {
1615c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
16165552b385SBrandon       }
1617c1cad2e7SMatthew G. Knepley 
1618c1cad2e7SMatthew G. Knepley       numFaces += Nf;
1619c1cad2e7SMatthew G. Knepley       numEdges += Netemp;
1620c1cad2e7SMatthew G. Knepley       numVertices += Nv;
1621c1cad2e7SMatthew G. Knepley       edgeCntr += Ne;
1622c1cad2e7SMatthew G. Knepley     }
1623c1cad2e7SMatthew G. Knepley 
1624c1cad2e7SMatthew G. Knepley     // Set up basic DMPlex parameters
162535cb6cd3SPierre Jolivet     dim        = 2;                                 // Assumes 3D Models :: Need to handle 2D models in the future
162635cb6cd3SPierre Jolivet     cdim       = 3;                                 // Assumes 3D Models :: Need to update to handle 2D models in future
1627c1cad2e7SMatthew G. Knepley     numCorners = 3;                                 // Split Faces into triangles
1628c1cad2e7SMatthew G. Knepley     numPoints  = numVertices + numEdges + numFaces; // total number of coordinate points
1629c1cad2e7SMatthew G. Knepley 
16309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPoints * cdim, &coords, numCells * numCorners, &cells));
1631c1cad2e7SMatthew G. Knepley 
1632c1cad2e7SMatthew G. Knepley     // Get Vertex Coordinates and Set up Cells
1633c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
1634c1cad2e7SMatthew G. Knepley       ego           body = bodies[b];
1635c1cad2e7SMatthew G. Knepley       int           Nf, Ne, Nv;
1636c1cad2e7SMatthew G. Knepley       PetscInt      bodyVertexIndexStart, bodyEdgeIndexStart, bodyEdgeGlobalIndexStart, bodyFaceIndexStart;
1637c1cad2e7SMatthew G. Knepley       PetscHashIter BViter, BEiter, BEGiter, BFiter, EMiter;
1638c1cad2e7SMatthew G. Knepley       PetscBool     BVfound, BEfound, BEGfound, BFfound, EMfound;
1639c1cad2e7SMatthew G. Knepley 
1640c1cad2e7SMatthew G. Knepley       // Vertices on Current Body
16415552b385SBrandon       if (islite) {
16425552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
16435552b385SBrandon       } else {
16449566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, NODE, &Nv, &nobjs));
16455552b385SBrandon       }
1646c1cad2e7SMatthew G. Knepley 
16479566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
16485552b385SBrandon       PetscCheck(BVfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in bodyVertexMap", b);
16499566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyVertexMap, b, &bodyVertexIndexStart));
1650c1cad2e7SMatthew G. Knepley 
1651c1cad2e7SMatthew G. Knepley       for (int v = 0; v < Nv; ++v) {
1652c1cad2e7SMatthew G. Knepley         ego    vertex = nobjs[v];
1653c1cad2e7SMatthew G. Knepley         double limits[4];
1654c1cad2e7SMatthew G. Knepley         int    id, dummy;
1655c1cad2e7SMatthew G. Knepley 
16565552b385SBrandon         if (islite) {
16575552b385SBrandon           PetscCall(EGlite_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
16585552b385SBrandon           id = EGlite_indexBodyTopo(body, vertex);
16595552b385SBrandon         } else {
16609566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(vertex, &geom, &oclass, &mtype, limits, &dummy, &mobjs, &senses));
16615f80ce2aSJacob Faibussowitsch           id = EG_indexBodyTopo(body, vertex);
16625552b385SBrandon         }
1663c1cad2e7SMatthew G. Knepley 
1664c1cad2e7SMatthew G. Knepley         coords[(bodyVertexIndexStart + id - 1) * cdim + 0] = limits[0];
1665c1cad2e7SMatthew G. Knepley         coords[(bodyVertexIndexStart + id - 1) * cdim + 1] = limits[1];
1666c1cad2e7SMatthew G. Knepley         coords[(bodyVertexIndexStart + id - 1) * cdim + 2] = limits[2];
1667c1cad2e7SMatthew G. Knepley       }
16685552b385SBrandon       if (islite) {
16695552b385SBrandon         EGlite_free(nobjs);
16705552b385SBrandon       } else {
1671c1cad2e7SMatthew G. Knepley         EG_free(nobjs);
16725552b385SBrandon       }
1673c1cad2e7SMatthew G. Knepley 
1674c1cad2e7SMatthew G. Knepley       // Edge Midpoint Vertices on Current Body
16755552b385SBrandon       if (islite) {
16765552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
16775552b385SBrandon       } else {
16789566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, EDGE, &Ne, &eobjs));
16795552b385SBrandon       }
1680c1cad2e7SMatthew G. Knepley 
16819566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
16825552b385SBrandon       PetscCheck(BEfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in bodyEdgeMap", b);
16839566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyEdgeMap, b, &bodyEdgeIndexStart));
1684c1cad2e7SMatthew G. Knepley 
16859566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
16865552b385SBrandon       PetscCheck(BEGfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in bodyEdgeGlobalMap", b);
16879566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyEdgeGlobalMap, b, &bodyEdgeGlobalIndexStart));
1688c1cad2e7SMatthew G. Knepley 
1689c1cad2e7SMatthew G. Knepley       for (int e = 0; e < Ne; ++e) {
1690c1cad2e7SMatthew G. Knepley         ego    edge = eobjs[e];
1691c1cad2e7SMatthew G. Knepley         double range[2], avgt[1], cntrPnt[9];
1692c1cad2e7SMatthew G. Knepley         int    eid, eOffset;
1693c1cad2e7SMatthew G. Knepley         int    periodic;
1694c1cad2e7SMatthew G. Knepley 
16955552b385SBrandon         if (islite) {
16965552b385SBrandon           PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
16975552b385SBrandon         } else {
16989566063dSJacob Faibussowitsch           PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
16995552b385SBrandon         }
1700ad540459SPierre Jolivet         if (mtype == DEGENERATE) continue;
1701c1cad2e7SMatthew G. Knepley 
17025552b385SBrandon         if (islite) {
17035552b385SBrandon           eid = EGlite_indexBodyTopo(body, edge);
17045552b385SBrandon         } else {
17055f80ce2aSJacob Faibussowitsch           eid = EG_indexBodyTopo(body, edge);
17065552b385SBrandon         }
1707c1cad2e7SMatthew G. Knepley         // get relative offset from globalEdgeID Vector
17089566063dSJacob Faibussowitsch         PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
17095552b385SBrandon         PetscCheck(EMfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Edge %" PetscInt_FMT " not found in edgeMap", bodyEdgeGlobalIndexStart + eid - 1);
17109566063dSJacob Faibussowitsch         PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
1711c1cad2e7SMatthew G. Knepley 
17125552b385SBrandon         if (islite) {
17135552b385SBrandon           PetscCall(EGlite_getRange(edge, range, &periodic));
17145552b385SBrandon         } else {
17159566063dSJacob Faibussowitsch           PetscCall(EG_getRange(edge, range, &periodic));
17165552b385SBrandon         }
1717c1cad2e7SMatthew G. Knepley         avgt[0] = (range[0] + range[1]) / 2.;
1718c1cad2e7SMatthew G. Knepley 
17195552b385SBrandon         if (islite) {
17205552b385SBrandon           PetscCall(EGlite_evaluate(edge, avgt, cntrPnt));
17215552b385SBrandon         } else {
17229566063dSJacob Faibussowitsch           PetscCall(EG_evaluate(edge, avgt, cntrPnt));
17235552b385SBrandon         }
1724c1cad2e7SMatthew G. Knepley         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1) * cdim + 0] = cntrPnt[0];
1725c1cad2e7SMatthew G. Knepley         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1) * cdim + 1] = cntrPnt[1];
1726c1cad2e7SMatthew G. Knepley         coords[(numVertices + bodyEdgeIndexStart + eOffset - 1) * cdim + 2] = cntrPnt[2];
1727c1cad2e7SMatthew G. Knepley       }
17285552b385SBrandon       if (islite) {
17295552b385SBrandon         EGlite_free(eobjs);
17305552b385SBrandon       } else {
1731c1cad2e7SMatthew G. Knepley         EG_free(eobjs);
17325552b385SBrandon       }
1733c1cad2e7SMatthew G. Knepley       // Face Midpoint Vertices on Current Body
17345552b385SBrandon       if (islite) {
17355552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
17365552b385SBrandon       } else {
17379566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
17385552b385SBrandon       }
17399566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
174028b400f6SJacob Faibussowitsch       PetscCheck(BFfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyFaceMap", b);
17419566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(bodyFaceMap, b, &bodyFaceIndexStart));
1742c1cad2e7SMatthew G. Knepley 
1743c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
1744c1cad2e7SMatthew G. Knepley         ego    face = fobjs[f];
1745c1cad2e7SMatthew G. Knepley         double range[4], avgUV[2], cntrPnt[18];
1746c1cad2e7SMatthew G. Knepley         int    peri, id;
1747c1cad2e7SMatthew G. Knepley 
17485552b385SBrandon         if (islite) {
17495552b385SBrandon           id = EGlite_indexBodyTopo(body, face);
17505552b385SBrandon           PetscCall(EGlite_getRange(face, range, &peri));
17515552b385SBrandon         } else {
1752c1cad2e7SMatthew G. Knepley           id = EG_indexBodyTopo(body, face);
17539566063dSJacob Faibussowitsch           PetscCall(EG_getRange(face, range, &peri));
17545552b385SBrandon         }
1755c1cad2e7SMatthew G. Knepley 
1756c1cad2e7SMatthew G. Knepley         avgUV[0] = (range[0] + range[1]) / 2.;
1757c1cad2e7SMatthew G. Knepley         avgUV[1] = (range[2] + range[3]) / 2.;
17585552b385SBrandon 
17595552b385SBrandon         if (islite) {
17605552b385SBrandon           PetscCall(EGlite_evaluate(face, avgUV, cntrPnt));
17615552b385SBrandon         } else {
17629566063dSJacob Faibussowitsch           PetscCall(EG_evaluate(face, avgUV, cntrPnt));
17635552b385SBrandon         }
1764c1cad2e7SMatthew G. Knepley 
1765c1cad2e7SMatthew G. Knepley         coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1) * cdim + 0] = cntrPnt[0];
1766c1cad2e7SMatthew G. Knepley         coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1) * cdim + 1] = cntrPnt[1];
1767c1cad2e7SMatthew G. Knepley         coords[(numVertices + numEdges + bodyFaceIndexStart + id - 1) * cdim + 2] = cntrPnt[2];
1768c1cad2e7SMatthew G. Knepley       }
17695552b385SBrandon       if (islite) {
17705552b385SBrandon         EGlite_free(fobjs);
17715552b385SBrandon       } else {
1772c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
17735552b385SBrandon       }
1774c1cad2e7SMatthew G. Knepley 
1775c1cad2e7SMatthew G. Knepley       // Define Cells :: Note - This could be incorporated in the Face Midpoint Vertices Loop but was kept separate for clarity
17765552b385SBrandon       if (islite) {
17775552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
17785552b385SBrandon       } else {
17799566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
17805552b385SBrandon       }
1781c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
1782c1cad2e7SMatthew G. Knepley         ego face = fobjs[f];
1783c1cad2e7SMatthew G. Knepley         int fID, midFaceID, midPntID, startID, endID, Nl;
1784c1cad2e7SMatthew G. Knepley 
17855552b385SBrandon         if (islite) {
17865552b385SBrandon           fID = EGlite_indexBodyTopo(body, face);
17875552b385SBrandon         } else {
17885f80ce2aSJacob Faibussowitsch           fID = EG_indexBodyTopo(body, face);
17895552b385SBrandon         }
17905552b385SBrandon 
1791c1cad2e7SMatthew G. Knepley         midFaceID = numVertices + numEdges + bodyFaceIndexStart + fID - 1;
1792c1cad2e7SMatthew G. Knepley         // Must Traverse Loop to ensure we have all necessary information like the sense (+/- 1) of the edges.
1793c1cad2e7SMatthew G. Knepley         // TODO :: Only handles single loop faces (No holes). The choices for handling multiloop faces are:
17945552b385SBrandon         //            1) Use the DMPlexCreateGeomFromFile() with the -dm_plex_geom_with_tess = 1 option.
1795c1cad2e7SMatthew G. Knepley         //               This will use a default EGADS tessellation as an initial surface mesh.
1796d5b43468SJose E. Roman         //            2) Create the initial surface mesh via a 2D mesher :: Currently not available (?future?)
1797c1cad2e7SMatthew G. Knepley         //               May I suggest the XXXX as a starting point?
1798c1cad2e7SMatthew G. Knepley 
17995552b385SBrandon         if (islite) {
18005552b385SBrandon           PetscCall(EGlite_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lSenses));
18015552b385SBrandon         } else {
18029566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lSenses));
18035552b385SBrandon         }
1804c1cad2e7SMatthew G. Knepley 
18055552b385SBrandon         PetscCheck(Nl == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face has %" PetscInt_FMT " Loops. Can only handle Faces with 1 Loop. Please use --dm_plex_geom_with_tess = 1 Option", Nl);
1806c1cad2e7SMatthew G. Knepley         for (int l = 0; l < Nl; ++l) {
1807c1cad2e7SMatthew G. Knepley           ego loop = lobjs[l];
1808c1cad2e7SMatthew G. Knepley 
18095552b385SBrandon           if (islite) {
18105552b385SBrandon             PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
18115552b385SBrandon           } else {
18129566063dSJacob Faibussowitsch             PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
18135552b385SBrandon           }
18145552b385SBrandon 
1815c1cad2e7SMatthew G. Knepley           for (int e = 0; e < Ne; ++e) {
1816c1cad2e7SMatthew G. Knepley             ego edge = eobjs[e];
1817c1cad2e7SMatthew G. Knepley             int eid, eOffset;
1818c1cad2e7SMatthew G. Knepley 
18195552b385SBrandon             if (islite) {
18205552b385SBrandon               PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
18215552b385SBrandon               eid = EGlite_indexBodyTopo(body, edge);
18225552b385SBrandon             } else {
18239566063dSJacob Faibussowitsch               PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
1824c1cad2e7SMatthew G. Knepley               eid = EG_indexBodyTopo(body, edge);
18255552b385SBrandon             }
1826ad540459SPierre Jolivet             if (mtype == DEGENERATE) continue;
1827c1cad2e7SMatthew G. Knepley 
1828c1cad2e7SMatthew G. Knepley             // get relative offset from globalEdgeID Vector
18299566063dSJacob Faibussowitsch             PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
18305552b385SBrandon             PetscCheck(EMfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Edge %" PetscInt_FMT " of Body %" PetscInt_FMT " not found in edgeMap. Global Edge ID :: %" PetscInt_FMT, eid, b, bodyEdgeGlobalIndexStart + eid - 1);
18319566063dSJacob Faibussowitsch             PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
1832c1cad2e7SMatthew G. Knepley 
1833c1cad2e7SMatthew G. Knepley             midPntID = numVertices + bodyEdgeIndexStart + eOffset - 1;
1834c1cad2e7SMatthew G. Knepley 
18355552b385SBrandon             if (islite) {
18365552b385SBrandon               PetscCall(EGlite_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
18375552b385SBrandon             } else {
18389566063dSJacob Faibussowitsch               PetscCall(EG_getTopology(edge, &geom, &oclass, &mtype, NULL, &Nv, &nobjs, &senses));
18395552b385SBrandon             }
1840c1cad2e7SMatthew G. Knepley 
18419371c9d4SSatish Balay             if (eSenses[e] > 0) {
18425552b385SBrandon               if (islite) {
18435552b385SBrandon                 startID = EGlite_indexBodyTopo(body, nobjs[0]);
18445552b385SBrandon                 endID   = EGlite_indexBodyTopo(body, nobjs[1]);
18455552b385SBrandon               } else {
18469371c9d4SSatish Balay                 startID = EG_indexBodyTopo(body, nobjs[0]);
18479371c9d4SSatish Balay                 endID   = EG_indexBodyTopo(body, nobjs[1]);
18485552b385SBrandon               }
18495552b385SBrandon             } else {
18505552b385SBrandon               if (islite) {
18515552b385SBrandon                 startID = EGlite_indexBodyTopo(body, nobjs[1]);
18525552b385SBrandon                 endID   = EGlite_indexBodyTopo(body, nobjs[0]);
18539371c9d4SSatish Balay               } else {
18549371c9d4SSatish Balay                 startID = EG_indexBodyTopo(body, nobjs[1]);
18559371c9d4SSatish Balay                 endID   = EG_indexBodyTopo(body, nobjs[0]);
18569371c9d4SSatish Balay               }
18575552b385SBrandon             }
1858c1cad2e7SMatthew G. Knepley 
1859c1cad2e7SMatthew G. Knepley             // Define 2 Cells per Edge with correct orientation
1860c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 0] = midFaceID;
1861c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 1] = bodyVertexIndexStart + startID - 1;
1862c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 2] = midPntID;
1863c1cad2e7SMatthew G. Knepley 
1864c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 3] = midFaceID;
1865c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 4] = midPntID;
1866c1cad2e7SMatthew G. Knepley             cells[cellCntr * numCorners + 5] = bodyVertexIndexStart + endID - 1;
1867c1cad2e7SMatthew G. Knepley 
1868c1cad2e7SMatthew G. Knepley             cellCntr = cellCntr + 2;
1869c1cad2e7SMatthew G. Knepley           }
1870c1cad2e7SMatthew G. Knepley         }
1871c1cad2e7SMatthew G. Knepley       }
18725552b385SBrandon       if (islite) {
18735552b385SBrandon         EGlite_free(fobjs);
18745552b385SBrandon       } else {
1875c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
1876c1cad2e7SMatthew G. Knepley       }
1877c1cad2e7SMatthew G. Knepley     }
18785552b385SBrandon   }
1879c1cad2e7SMatthew G. Knepley 
1880c1cad2e7SMatthew G. Knepley   // Generate DMPlex
18819566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, numCells, numPoints, numCorners, PETSC_TRUE, cells, cdim, coords, &dm));
18829566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coords, cells));
188363a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(dm, " Total Number of Unique Cells    = %" PetscInt_FMT " \n", numCells));
188463a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(dm, " Total Number of Unique Vertices = %" PetscInt_FMT " \n", numVertices));
1885c1cad2e7SMatthew G. Knepley 
1886c1cad2e7SMatthew G. Knepley   // Embed EGADS model in DM
1887c1cad2e7SMatthew G. Knepley   {
1888c1cad2e7SMatthew G. Knepley     PetscContainer modelObj, contextObj;
1889c1cad2e7SMatthew G. Knepley 
18909566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &modelObj));
18919566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(modelObj, model));
18925552b385SBrandon     if (islite) {
18935552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(modelObj, DMPlexEGADSliteDestroy_Private));
18945552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Model", (PetscObject)modelObj));
18955552b385SBrandon     } else {
18965552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(modelObj, DMPlexEGADSDestroy_Private));
18979566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Model", (PetscObject)modelObj));
18985552b385SBrandon     }
18999566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&modelObj));
1900c1cad2e7SMatthew G. Knepley 
19019566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &contextObj));
19029566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(contextObj, context));
19035552b385SBrandon 
19045552b385SBrandon     if (islite) {
19055552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(contextObj, DMPlexEGADSliteClose_Private));
19065552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Context", (PetscObject)contextObj));
19075552b385SBrandon     } else {
19085552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(contextObj, DMPlexEGADSClose_Private));
19099566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Context", (PetscObject)contextObj));
19105552b385SBrandon     }
19119566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&contextObj));
1912c1cad2e7SMatthew G. Knepley   }
1913c1cad2e7SMatthew G. Knepley   // Label points
1914c1cad2e7SMatthew G. Knepley   PetscInt nStart, nEnd;
1915c1cad2e7SMatthew G. Knepley 
19169566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Body ID"));
19179566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
19189566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Face ID"));
19199566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
19209566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Edge ID"));
19219566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
19229566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Vertex ID"));
19239566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
1924c1cad2e7SMatthew G. Knepley 
19259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 2, &nStart, &nEnd));
1926c1cad2e7SMatthew G. Knepley 
1927c1cad2e7SMatthew G. Knepley   cellCntr = 0;
1928c1cad2e7SMatthew G. Knepley   for (b = 0; b < nbodies; ++b) {
1929c1cad2e7SMatthew G. Knepley     ego           body = bodies[b];
1930c1cad2e7SMatthew G. Knepley     int           Nv, Ne, Nf;
1931c1cad2e7SMatthew G. Knepley     PetscInt      bodyVertexIndexStart, bodyEdgeIndexStart, bodyEdgeGlobalIndexStart, bodyFaceIndexStart;
1932c1cad2e7SMatthew G. Knepley     PetscHashIter BViter, BEiter, BEGiter, BFiter, EMiter;
1933c1cad2e7SMatthew G. Knepley     PetscBool     BVfound, BEfound, BEGfound, BFfound, EMfound;
1934c1cad2e7SMatthew G. Knepley 
19359566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyVertexMap, b, &BViter, &BVfound));
193628b400f6SJacob Faibussowitsch     PetscCheck(BVfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyVertexMap", b);
19379566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyVertexMap, b, &bodyVertexIndexStart));
1938c1cad2e7SMatthew G. Knepley 
19399566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyEdgeMap, b, &BEiter, &BEfound));
194028b400f6SJacob Faibussowitsch     PetscCheck(BEfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyEdgeMap", b);
19419566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyEdgeMap, b, &bodyEdgeIndexStart));
1942c1cad2e7SMatthew G. Knepley 
19439566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyFaceMap, b, &BFiter, &BFfound));
194428b400f6SJacob Faibussowitsch     PetscCheck(BFfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyFaceMap", b);
19459566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyFaceMap, b, &bodyFaceIndexStart));
1946c1cad2e7SMatthew G. Knepley 
19479566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(bodyEdgeGlobalMap, b, &BEGiter, &BEGfound));
194828b400f6SJacob Faibussowitsch     PetscCheck(BEGfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %d not found in bodyEdgeGlobalMap", b);
19499566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(bodyEdgeGlobalMap, b, &bodyEdgeGlobalIndexStart));
1950c1cad2e7SMatthew G. Knepley 
19515552b385SBrandon     if (islite) {
19525552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
19535552b385SBrandon     } else {
19549566063dSJacob Faibussowitsch       PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
19555552b385SBrandon     }
19565552b385SBrandon 
1957c1cad2e7SMatthew G. Knepley     for (int f = 0; f < Nf; ++f) {
1958c1cad2e7SMatthew G. Knepley       ego face = fobjs[f];
1959c1cad2e7SMatthew G. Knepley       int fID, Nl;
1960c1cad2e7SMatthew G. Knepley 
19615552b385SBrandon       if (islite) {
19625552b385SBrandon         fID = EGlite_indexBodyTopo(body, face);
19635552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, face, LOOP, &Nl, &lobjs));
19645552b385SBrandon       } else {
19655f80ce2aSJacob Faibussowitsch         fID = EG_indexBodyTopo(body, face);
19669566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, face, LOOP, &Nl, &lobjs));
19675552b385SBrandon       }
19685552b385SBrandon 
1969c1cad2e7SMatthew G. Knepley       for (int l = 0; l < Nl; ++l) {
1970c1cad2e7SMatthew G. Knepley         ego loop = lobjs[l];
1971c1cad2e7SMatthew G. Knepley         int lid;
1972c1cad2e7SMatthew G. Knepley 
19735552b385SBrandon         if (islite) {
19745552b385SBrandon           lid = EGlite_indexBodyTopo(body, loop);
19755552b385SBrandon         } else {
19765f80ce2aSJacob Faibussowitsch           lid = EG_indexBodyTopo(body, loop);
19775552b385SBrandon         }
1978c1cad2e7SMatthew G. Knepley 
19795552b385SBrandon         PetscCheck(Nl == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Loop %" PetscInt_FMT " has %" PetscInt_FMT " > 1 faces, which is not supported", lid, Nf);
19805552b385SBrandon 
19815552b385SBrandon         if (islite) {
19825552b385SBrandon           PetscCall(EGlite_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
19835552b385SBrandon         } else {
19849566063dSJacob Faibussowitsch           PetscCall(EG_getTopology(loop, &geom, &oclass, &mtype, NULL, &Ne, &eobjs, &eSenses));
19855552b385SBrandon         }
19865552b385SBrandon 
1987c1cad2e7SMatthew G. Knepley         for (int e = 0; e < Ne; ++e) {
1988c1cad2e7SMatthew G. Knepley           ego edge = eobjs[e];
1989c1cad2e7SMatthew G. Knepley           int eid, eOffset;
1990c1cad2e7SMatthew G. Knepley 
1991c1cad2e7SMatthew G. Knepley           // Skip DEGENERATE Edges
19925552b385SBrandon           if (islite) {
19935552b385SBrandon             PetscCall(EGlite_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
19945552b385SBrandon           } else {
19959566063dSJacob Faibussowitsch             PetscCall(EG_getInfo(edge, &oclass, &mtype, &topRef, &prev, &next));
19965552b385SBrandon           }
19975552b385SBrandon 
19985552b385SBrandon           if (mtype == DEGENERATE) { continue; }
19995552b385SBrandon 
20005552b385SBrandon           if (islite) {
20015552b385SBrandon             eid = EGlite_indexBodyTopo(body, edge);
20025552b385SBrandon           } else {
20035f80ce2aSJacob Faibussowitsch             eid = EG_indexBodyTopo(body, edge);
20045552b385SBrandon           }
2005c1cad2e7SMatthew G. Knepley 
2006c1cad2e7SMatthew G. Knepley           // get relative offset from globalEdgeID Vector
20079566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &EMiter, &EMfound));
20085552b385SBrandon           PetscCheck(EMfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Edge %" PetscInt_FMT " of Body %" PetscInt_FMT " not found in edgeMap. Global Edge ID :: %" PetscInt_FMT, eid, b, bodyEdgeGlobalIndexStart + eid - 1);
20099566063dSJacob Faibussowitsch           PetscCall(PetscHMapIGet(edgeMap, bodyEdgeGlobalIndexStart + eid - 1, &eOffset));
2010c1cad2e7SMatthew G. Knepley 
20115552b385SBrandon           if (islite) {
20125552b385SBrandon             PetscCall(EGlite_getBodyTopos(body, edge, NODE, &Nv, &nobjs));
20135552b385SBrandon           } else {
20149566063dSJacob Faibussowitsch             PetscCall(EG_getBodyTopos(body, edge, NODE, &Nv, &nobjs));
20155552b385SBrandon           }
20165552b385SBrandon 
2017c1cad2e7SMatthew G. Knepley           for (int v = 0; v < Nv; ++v) {
2018c1cad2e7SMatthew G. Knepley             ego vertex = nobjs[v];
2019c1cad2e7SMatthew G. Knepley             int vID;
2020c1cad2e7SMatthew G. Knepley 
20215552b385SBrandon             if (islite) {
20225552b385SBrandon               vID = EGlite_indexBodyTopo(body, vertex);
20235552b385SBrandon             } else {
20245f80ce2aSJacob Faibussowitsch               vID = EG_indexBodyTopo(body, vertex);
20255552b385SBrandon             }
20265552b385SBrandon 
20279566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, nStart + bodyVertexIndexStart + vID - 1, b));
20289566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(vertexLabel, nStart + bodyVertexIndexStart + vID - 1, vID));
2029c1cad2e7SMatthew G. Knepley           }
20305552b385SBrandon           if (islite) {
20315552b385SBrandon             EGlite_free(nobjs);
20325552b385SBrandon           } else {
2033c1cad2e7SMatthew G. Knepley             EG_free(nobjs);
20345552b385SBrandon           }
2035c1cad2e7SMatthew G. Knepley 
20369566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(bodyLabel, nStart + numVertices + bodyEdgeIndexStart + eOffset - 1, b));
20379566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(edgeLabel, nStart + numVertices + bodyEdgeIndexStart + eOffset - 1, eid));
2038c1cad2e7SMatthew G. Knepley 
2039c1cad2e7SMatthew G. Knepley           // Define Cell faces
2040c1cad2e7SMatthew G. Knepley           for (int jj = 0; jj < 2; ++jj) {
20419566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cellCntr, b));
20429566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(faceLabel, cellCntr, fID));
20439566063dSJacob Faibussowitsch             PetscCall(DMPlexGetCone(dm, cellCntr, &cone));
2044c1cad2e7SMatthew G. Knepley 
20459566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cone[0], b));
20469566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(faceLabel, cone[0], fID));
2047c1cad2e7SMatthew G. Knepley 
20489566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cone[1], b));
20499566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(edgeLabel, cone[1], eid));
2050c1cad2e7SMatthew G. Knepley 
20519566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(bodyLabel, cone[2], b));
20529566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(faceLabel, cone[2], fID));
2053c1cad2e7SMatthew G. Knepley 
2054c1cad2e7SMatthew G. Knepley             cellCntr = cellCntr + 1;
2055c1cad2e7SMatthew G. Knepley           }
2056c1cad2e7SMatthew G. Knepley         }
2057c1cad2e7SMatthew G. Knepley       }
20585552b385SBrandon       if (islite) {
20595552b385SBrandon         EGlite_free(lobjs);
20605552b385SBrandon       } else {
2061c1cad2e7SMatthew G. Knepley         EG_free(lobjs);
20625552b385SBrandon       }
2063c1cad2e7SMatthew G. Knepley 
20649566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(bodyLabel, nStart + numVertices + numEdges + bodyFaceIndexStart + fID - 1, b));
20659566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(faceLabel, nStart + numVertices + numEdges + bodyFaceIndexStart + fID - 1, fID));
2066c1cad2e7SMatthew G. Knepley     }
20675552b385SBrandon     if (islite) {
20685552b385SBrandon       EGlite_free(fobjs);
20695552b385SBrandon     } else {
2070c1cad2e7SMatthew G. Knepley       EG_free(fobjs);
2071c1cad2e7SMatthew G. Knepley     }
20725552b385SBrandon   }
2073c1cad2e7SMatthew G. Knepley 
20749566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&edgeMap));
20759566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyIndexMap));
20769566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyVertexMap));
20779566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyEdgeMap));
20789566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyEdgeGlobalMap));
20799566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&bodyFaceMap));
2080c1cad2e7SMatthew G. Knepley 
2081c1cad2e7SMatthew G. Knepley   *newdm = dm;
20823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2083c1cad2e7SMatthew G. Knepley }
2084c1cad2e7SMatthew G. Knepley 
20855552b385SBrandon PetscErrorCode DMPlexCreateGeom_Tess_Internal(MPI_Comm comm, ego context, ego model, DM *newdm, PetscBool islite)
2086d71ae5a4SJacob Faibussowitsch {
20875552b385SBrandon   /* EGADSlite variables */
2088c1cad2e7SMatthew G. Knepley   ego    geom, *bodies, *fobjs;
2089c1cad2e7SMatthew G. Knepley   int    b, oclass, mtype, nbodies, *senses;
2090c1cad2e7SMatthew G. Knepley   int    totalNumTris = 0, totalNumPoints = 0;
2091c1cad2e7SMatthew G. Knepley   double boundBox[6] = {0., 0., 0., 0., 0., 0.}, tessSize;
2092c1cad2e7SMatthew G. Knepley   /* PETSc variables */
2093c1cad2e7SMatthew G. Knepley   DM              dm;
20945552b385SBrandon   DMLabel         bodyLabel, faceLabel, edgeLabel, vertexLabel;
2095c1cad2e7SMatthew G. Knepley   PetscHMapI      pointIndexStartMap = NULL, triIndexStartMap = NULL, pTypeLabelMap = NULL, pIndexLabelMap = NULL;
2096c1cad2e7SMatthew G. Knepley   PetscHMapI      pBodyIndexLabelMap = NULL, triFaceIDLabelMap = NULL, triBodyIDLabelMap = NULL;
2097c1cad2e7SMatthew G. Knepley   PetscInt        dim = -1, cdim = -1, numCorners = 0, counter = 0;
2098c1cad2e7SMatthew G. Knepley   PetscInt       *cells  = NULL;
2099c1cad2e7SMatthew G. Knepley   const PetscInt *cone   = NULL;
2100c1cad2e7SMatthew G. Knepley   PetscReal      *coords = NULL;
2101c1cad2e7SMatthew G. Knepley   PetscMPIInt     rank;
2102c1cad2e7SMatthew G. Knepley 
2103c1cad2e7SMatthew G. Knepley   PetscFunctionBeginUser;
21049566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2105c5853193SPierre Jolivet   if (rank == 0) {
2106c1cad2e7SMatthew G. Knepley     // ---------------------------------------------------------------------------------------------------
2107c1cad2e7SMatthew G. Knepley     // Generate Petsc Plex from EGADSlite created Tessellation of geometry
2108c1cad2e7SMatthew G. Knepley     // ---------------------------------------------------------------------------------------------------
2109c1cad2e7SMatthew G. Knepley 
2110d5b43468SJose E. Roman     // Calculate cell and vertex sizes
21115552b385SBrandon     if (islite) {
21125552b385SBrandon       PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
21135552b385SBrandon     } else {
21149566063dSJacob Faibussowitsch       PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &nbodies, &bodies, &senses));
21155552b385SBrandon     }
2116c1cad2e7SMatthew G. Knepley 
21179566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pointIndexStartMap));
21189566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&triIndexStartMap));
21199566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pTypeLabelMap));
21209566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pIndexLabelMap));
21219566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&pBodyIndexLabelMap));
21229566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&triFaceIDLabelMap));
21239566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&triBodyIDLabelMap));
2124c1cad2e7SMatthew G. Knepley 
2125c1cad2e7SMatthew G. Knepley     /* Create Tessellation of Bodies */
21265552b385SBrandon     ego *tessArray;
2127c1cad2e7SMatthew G. Knepley 
21285552b385SBrandon     PetscCall(PetscMalloc1(nbodies, &tessArray));
2129c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
2130c1cad2e7SMatthew G. Knepley       ego           body      = bodies[b];
2131c1cad2e7SMatthew G. Knepley       double        params[3] = {0.0, 0.0, 0.0}; // Parameters for Tessellation
2132c1cad2e7SMatthew G. Knepley       int           Nf, bodyNumPoints = 0, bodyNumTris = 0;
2133c1cad2e7SMatthew G. Knepley       PetscHashIter PISiter, TISiter;
2134c1cad2e7SMatthew G. Knepley       PetscBool     PISfound, TISfound;
2135c1cad2e7SMatthew G. Knepley 
2136c1cad2e7SMatthew G. Knepley       /* Store Start Index for each Body's Point and Tris */
21379566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(pointIndexStartMap, b, &PISiter, &PISfound));
21389566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(triIndexStartMap, b, &TISiter, &TISfound));
2139c1cad2e7SMatthew G. Knepley 
21409566063dSJacob Faibussowitsch       if (!PISfound) PetscCall(PetscHMapISet(pointIndexStartMap, b, totalNumPoints));
21419566063dSJacob Faibussowitsch       if (!TISfound) PetscCall(PetscHMapISet(triIndexStartMap, b, totalNumTris));
2142c1cad2e7SMatthew G. Knepley 
2143c1cad2e7SMatthew G. Knepley       /* Calculate Tessellation parameters based on Bounding Box */
2144c1cad2e7SMatthew G. Knepley       /* Get Bounding Box Dimensions of the BODY */
21455552b385SBrandon       if (islite) {
21465552b385SBrandon         PetscCall(EGlite_getBoundingBox(body, boundBox));
21475552b385SBrandon       } else {
21489566063dSJacob Faibussowitsch         PetscCall(EG_getBoundingBox(body, boundBox));
21495552b385SBrandon       }
21505552b385SBrandon 
2151c1cad2e7SMatthew G. Knepley       tessSize = boundBox[3] - boundBox[0];
2152c1cad2e7SMatthew G. Knepley       if (tessSize < boundBox[4] - boundBox[1]) tessSize = boundBox[4] - boundBox[1];
2153c1cad2e7SMatthew G. Knepley       if (tessSize < boundBox[5] - boundBox[2]) tessSize = boundBox[5] - boundBox[2];
2154c1cad2e7SMatthew G. Knepley 
2155c1cad2e7SMatthew G. Knepley       // TODO :: May want to give users tessellation parameter options //
2156c1cad2e7SMatthew G. Knepley       params[0] = 0.0250 * tessSize;
2157c1cad2e7SMatthew G. Knepley       params[1] = 0.0075 * tessSize;
2158c1cad2e7SMatthew G. Knepley       params[2] = 15.0;
2159c1cad2e7SMatthew G. Knepley 
21605552b385SBrandon       if (islite) {
21615552b385SBrandon         PetscCall(EGlite_makeTessBody(body, params, &tessArray[b]));
21625552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
21635552b385SBrandon       } else {
21649566063dSJacob Faibussowitsch         PetscCall(EG_makeTessBody(body, params, &tessArray[b]));
21659566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
21665552b385SBrandon       }
2167c1cad2e7SMatthew G. Knepley 
2168c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
2169c1cad2e7SMatthew G. Knepley         ego           face = fobjs[f];
2170c1cad2e7SMatthew G. Knepley         int           len, fID, ntris;
2171c1cad2e7SMatthew G. Knepley         const int    *ptype, *pindex, *ptris, *ptric;
2172c1cad2e7SMatthew G. Knepley         const double *pxyz, *puv;
2173c1cad2e7SMatthew G. Knepley 
2174c1cad2e7SMatthew G. Knepley         // Get Face ID //
21755552b385SBrandon         if (islite) {
21765552b385SBrandon           fID = EGlite_indexBodyTopo(body, face);
21775552b385SBrandon         } else {
2178c1cad2e7SMatthew G. Knepley           fID = EG_indexBodyTopo(body, face);
21795552b385SBrandon         }
2180c1cad2e7SMatthew G. Knepley 
2181c1cad2e7SMatthew G. Knepley         // Checkout the Surface Tessellation //
21825552b385SBrandon         if (islite) {
21835552b385SBrandon           PetscCall(EGlite_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
21845552b385SBrandon         } else {
21859566063dSJacob Faibussowitsch           PetscCall(EG_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
21865552b385SBrandon         }
2187c1cad2e7SMatthew G. Knepley 
2188c1cad2e7SMatthew G. Knepley         // Determine total number of triangle cells in the tessellation //
2189c1cad2e7SMatthew G. Knepley         bodyNumTris += (int)ntris;
2190c1cad2e7SMatthew G. Knepley 
2191c1cad2e7SMatthew G. Knepley         // Check out the point index and coordinate //
2192c1cad2e7SMatthew G. Knepley         for (int p = 0; p < len; ++p) {
2193c1cad2e7SMatthew G. Knepley           int global;
2194c1cad2e7SMatthew G. Knepley 
21955552b385SBrandon           if (islite) {
21965552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, p + 1, &global));
21975552b385SBrandon           } else {
21989566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, p + 1, &global));
21995552b385SBrandon           }
2200c1cad2e7SMatthew G. Knepley 
2201c1cad2e7SMatthew G. Knepley           // Determine the total number of points in the tessellation //
2202c1cad2e7SMatthew G. Knepley           bodyNumPoints = PetscMax(bodyNumPoints, global);
2203c1cad2e7SMatthew G. Knepley         }
2204c1cad2e7SMatthew G. Knepley       }
22055552b385SBrandon       if (islite) {
22065552b385SBrandon         EGlite_free(fobjs);
22075552b385SBrandon       } else {
2208c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
22095552b385SBrandon       }
2210c1cad2e7SMatthew G. Knepley 
2211c1cad2e7SMatthew G. Knepley       totalNumPoints += bodyNumPoints;
2212c1cad2e7SMatthew G. Knepley       totalNumTris += bodyNumTris;
2213c1cad2e7SMatthew G. Knepley     }
2214c1cad2e7SMatthew G. Knepley 
2215c1cad2e7SMatthew G. Knepley     dim        = 2;
2216c1cad2e7SMatthew G. Knepley     cdim       = 3;
2217c1cad2e7SMatthew G. Knepley     numCorners = 3;
2218c1cad2e7SMatthew G. Knepley 
2219c1cad2e7SMatthew G. Knepley     /* NEED TO DEFINE MATRICES/VECTORS TO STORE GEOM REFERENCE DATA   */
2220c1cad2e7SMatthew G. Knepley     /* Fill in below and use to define DMLabels after DMPlex creation */
22219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(totalNumPoints * cdim, &coords, totalNumTris * numCorners, &cells));
2222c1cad2e7SMatthew G. Knepley 
2223c1cad2e7SMatthew G. Knepley     for (b = 0; b < nbodies; ++b) {
2224c1cad2e7SMatthew G. Knepley       ego           body = bodies[b];
2225c1cad2e7SMatthew G. Knepley       int           Nf;
2226c1cad2e7SMatthew G. Knepley       PetscInt      pointIndexStart;
2227c1cad2e7SMatthew G. Knepley       PetscHashIter PISiter;
2228c1cad2e7SMatthew G. Knepley       PetscBool     PISfound;
2229c1cad2e7SMatthew G. Knepley 
22309566063dSJacob Faibussowitsch       PetscCall(PetscHMapIFind(pointIndexStartMap, b, &PISiter, &PISfound));
22315552b385SBrandon       PetscCheck(PISfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "Body %" PetscInt_FMT " not found in pointIndexStartMap", b);
22329566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGet(pointIndexStartMap, b, &pointIndexStart));
2233c1cad2e7SMatthew G. Knepley 
22345552b385SBrandon       if (islite) {
22355552b385SBrandon         PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
22365552b385SBrandon       } else {
22379566063dSJacob Faibussowitsch         PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
22385552b385SBrandon       }
2239c1cad2e7SMatthew G. Knepley 
2240c1cad2e7SMatthew G. Knepley       for (int f = 0; f < Nf; ++f) {
2241c1cad2e7SMatthew G. Knepley         /* Get Face Object */
2242c1cad2e7SMatthew G. Knepley         ego           face = fobjs[f];
2243c1cad2e7SMatthew G. Knepley         int           len, fID, ntris;
2244c1cad2e7SMatthew G. Knepley         const int    *ptype, *pindex, *ptris, *ptric;
2245c1cad2e7SMatthew G. Knepley         const double *pxyz, *puv;
2246c1cad2e7SMatthew G. Knepley 
2247c1cad2e7SMatthew G. Knepley         /* Get Face ID */
22485552b385SBrandon         if (islite) {
22495552b385SBrandon           fID = EGlite_indexBodyTopo(body, face);
22505552b385SBrandon         } else {
2251c1cad2e7SMatthew G. Knepley           fID = EG_indexBodyTopo(body, face);
22525552b385SBrandon         }
2253c1cad2e7SMatthew G. Knepley 
2254c1cad2e7SMatthew G. Knepley         /* Checkout the Surface Tessellation */
22555552b385SBrandon         if (islite) {
22565552b385SBrandon           PetscCall(EGlite_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
22575552b385SBrandon         } else {
22589566063dSJacob Faibussowitsch           PetscCall(EG_getTessFace(tessArray[b], fID, &len, &pxyz, &puv, &ptype, &pindex, &ntris, &ptris, &ptric));
22595552b385SBrandon         }
2260c1cad2e7SMatthew G. Knepley 
2261c1cad2e7SMatthew G. Knepley         /* Check out the point index and coordinate */
2262c1cad2e7SMatthew G. Knepley         for (int p = 0; p < len; ++p) {
2263c1cad2e7SMatthew G. Knepley           int           global;
2264c1cad2e7SMatthew G. Knepley           PetscHashIter PTLiter, PILiter, PBLiter;
2265c1cad2e7SMatthew G. Knepley           PetscBool     PTLfound, PILfound, PBLfound;
2266c1cad2e7SMatthew G. Knepley 
22675552b385SBrandon           if (islite) {
22685552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, p + 1, &global));
22695552b385SBrandon           } else {
22709566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, p + 1, &global));
22715552b385SBrandon           }
2272c1cad2e7SMatthew G. Knepley 
2273c1cad2e7SMatthew G. Knepley           /* Set the coordinates array for DAG */
2274c1cad2e7SMatthew G. Knepley           coords[((global - 1 + pointIndexStart) * 3) + 0] = pxyz[(p * 3) + 0];
2275c1cad2e7SMatthew G. Knepley           coords[((global - 1 + pointIndexStart) * 3) + 1] = pxyz[(p * 3) + 1];
2276c1cad2e7SMatthew G. Knepley           coords[((global - 1 + pointIndexStart) * 3) + 2] = pxyz[(p * 3) + 2];
2277c1cad2e7SMatthew G. Knepley 
2278c1cad2e7SMatthew G. Knepley           /* Store Geometry Label Information for DMLabel assignment later */
22799566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(pTypeLabelMap, global - 1 + pointIndexStart, &PTLiter, &PTLfound));
22809566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(pIndexLabelMap, global - 1 + pointIndexStart, &PILiter, &PILfound));
22819566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(pBodyIndexLabelMap, global - 1 + pointIndexStart, &PBLiter, &PBLfound));
2282c1cad2e7SMatthew G. Knepley 
22839566063dSJacob Faibussowitsch           if (!PTLfound) PetscCall(PetscHMapISet(pTypeLabelMap, global - 1 + pointIndexStart, ptype[p]));
22849566063dSJacob Faibussowitsch           if (!PILfound) PetscCall(PetscHMapISet(pIndexLabelMap, global - 1 + pointIndexStart, pindex[p]));
22859566063dSJacob Faibussowitsch           if (!PBLfound) PetscCall(PetscHMapISet(pBodyIndexLabelMap, global - 1 + pointIndexStart, b));
2286c1cad2e7SMatthew G. Knepley 
22879566063dSJacob Faibussowitsch           if (ptype[p] < 0) PetscCall(PetscHMapISet(pIndexLabelMap, global - 1 + pointIndexStart, fID));
2288c1cad2e7SMatthew G. Knepley         }
2289c1cad2e7SMatthew G. Knepley 
2290c1cad2e7SMatthew G. Knepley         for (int t = 0; t < (int)ntris; ++t) {
2291c1cad2e7SMatthew G. Knepley           int           global, globalA, globalB;
2292c1cad2e7SMatthew G. Knepley           PetscHashIter TFLiter, TBLiter;
2293c1cad2e7SMatthew G. Knepley           PetscBool     TFLfound, TBLfound;
2294c1cad2e7SMatthew G. Knepley 
22955552b385SBrandon           if (islite) {
22965552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 0], &global));
22975552b385SBrandon           } else {
22989566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 0], &global));
22995552b385SBrandon           }
2300c1cad2e7SMatthew G. Knepley           cells[(counter * 3) + 0] = global - 1 + pointIndexStart;
2301c1cad2e7SMatthew G. Knepley 
23025552b385SBrandon           if (islite) {
23035552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 1], &globalA));
23045552b385SBrandon           } else {
23059566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 1], &globalA));
23065552b385SBrandon           }
2307c1cad2e7SMatthew G. Knepley           cells[(counter * 3) + 1] = globalA - 1 + pointIndexStart;
2308c1cad2e7SMatthew G. Knepley 
23095552b385SBrandon           if (islite) {
23105552b385SBrandon             PetscCall(EGlite_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 2], &globalB));
23115552b385SBrandon           } else {
23129566063dSJacob Faibussowitsch             PetscCall(EG_localToGlobal(tessArray[b], fID, ptris[(t * 3) + 2], &globalB));
23135552b385SBrandon           }
2314c1cad2e7SMatthew G. Knepley           cells[(counter * 3) + 2] = globalB - 1 + pointIndexStart;
2315c1cad2e7SMatthew G. Knepley 
23169566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(triFaceIDLabelMap, counter, &TFLiter, &TFLfound));
23179566063dSJacob Faibussowitsch           PetscCall(PetscHMapIFind(triBodyIDLabelMap, counter, &TBLiter, &TBLfound));
2318c1cad2e7SMatthew G. Knepley 
23199566063dSJacob Faibussowitsch           if (!TFLfound) PetscCall(PetscHMapISet(triFaceIDLabelMap, counter, fID));
23209566063dSJacob Faibussowitsch           if (!TBLfound) PetscCall(PetscHMapISet(triBodyIDLabelMap, counter, b));
2321c1cad2e7SMatthew G. Knepley 
2322c1cad2e7SMatthew G. Knepley           counter += 1;
2323c1cad2e7SMatthew G. Knepley         }
2324c1cad2e7SMatthew G. Knepley       }
23255552b385SBrandon       if (islite) {
23265552b385SBrandon         EGlite_free(fobjs);
23275552b385SBrandon       } else {
2328c1cad2e7SMatthew G. Knepley         EG_free(fobjs);
2329c1cad2e7SMatthew G. Knepley       }
2330c1cad2e7SMatthew G. Knepley     }
23315552b385SBrandon     PetscCall(PetscFree(tessArray));
23325552b385SBrandon   }
2333c1cad2e7SMatthew G. Knepley 
2334c1cad2e7SMatthew G. Knepley   //Build DMPlex
23359566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromCellListPetsc(PETSC_COMM_WORLD, dim, totalNumTris, totalNumPoints, numCorners, PETSC_TRUE, cells, cdim, coords, &dm));
23369566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coords, cells));
2337c1cad2e7SMatthew G. Knepley 
2338c1cad2e7SMatthew G. Knepley   // Embed EGADS model in DM
2339c1cad2e7SMatthew G. Knepley   {
2340c1cad2e7SMatthew G. Knepley     PetscContainer modelObj, contextObj;
2341c1cad2e7SMatthew G. Knepley 
23429566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &modelObj));
23439566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(modelObj, model));
23445552b385SBrandon     if (islite) {
23455552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(modelObj, (PetscCtxDestroyFn *)DMPlexEGADSliteDestroy_Private));
23465552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Model", (PetscObject)modelObj));
23475552b385SBrandon     } else {
23485552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(modelObj, (PetscCtxDestroyFn *)DMPlexEGADSDestroy_Private));
23499566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Model", (PetscObject)modelObj));
23505552b385SBrandon     }
23519566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&modelObj));
2352c1cad2e7SMatthew G. Knepley 
23539566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &contextObj));
23549566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(contextObj, context));
23555552b385SBrandon 
23565552b385SBrandon     if (islite) {
23575552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(contextObj, (PetscCtxDestroyFn *)DMPlexEGADSliteClose_Private));
23585552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADSlite Context", (PetscObject)contextObj));
23595552b385SBrandon     } else {
23605552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(contextObj, (PetscCtxDestroyFn *)DMPlexEGADSClose_Private));
23619566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "EGADS Context", (PetscObject)contextObj));
23625552b385SBrandon     }
23639566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&contextObj));
2364c1cad2e7SMatthew G. Knepley   }
2365c1cad2e7SMatthew G. Knepley 
2366c1cad2e7SMatthew G. Knepley   // Label Points
23679566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Body ID"));
23689566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
23699566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Face ID"));
23709566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
23719566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Edge ID"));
23729566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
23739566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "EGADS Vertex ID"));
23749566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
2375c1cad2e7SMatthew G. Knepley 
2376c1cad2e7SMatthew G. Knepley   /* Get Number of DAG Nodes at each level */
2377c1cad2e7SMatthew G. Knepley   int fStart, fEnd, eStart, eEnd, nStart, nEnd;
2378c1cad2e7SMatthew G. Knepley 
23799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &fStart, &fEnd));
23809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &eStart, &eEnd));
23819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 2, &nStart, &nEnd));
2382c1cad2e7SMatthew G. Knepley 
2383c1cad2e7SMatthew G. Knepley   /* Set DMLabels for NODES */
2384c1cad2e7SMatthew G. Knepley   for (int n = nStart; n < nEnd; ++n) {
2385c1cad2e7SMatthew G. Knepley     int           pTypeVal, pIndexVal, pBodyVal;
2386c1cad2e7SMatthew G. Knepley     PetscHashIter PTLiter, PILiter, PBLiter;
2387c1cad2e7SMatthew G. Knepley     PetscBool     PTLfound, PILfound, PBLfound;
2388c1cad2e7SMatthew G. Knepley 
2389c1cad2e7SMatthew G. Knepley     //Converted to Hash Tables
23909566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(pTypeLabelMap, n - nStart, &PTLiter, &PTLfound));
23915552b385SBrandon     PetscCheck(PTLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in pTypeLabelMap", n);
23929566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(pTypeLabelMap, n - nStart, &pTypeVal));
2393c1cad2e7SMatthew G. Knepley 
23949566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(pIndexLabelMap, n - nStart, &PILiter, &PILfound));
23955552b385SBrandon     PetscCheck(PILfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in pIndexLabelMap", n);
23969566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(pIndexLabelMap, n - nStart, &pIndexVal));
2397c1cad2e7SMatthew G. Knepley 
23989566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(pBodyIndexLabelMap, n - nStart, &PBLiter, &PBLfound));
23995552b385SBrandon     PetscCheck(PBLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in pBodyLabelMap", n);
24009566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(pBodyIndexLabelMap, n - nStart, &pBodyVal));
2401c1cad2e7SMatthew G. Knepley 
24029566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(bodyLabel, n, pBodyVal));
24039566063dSJacob Faibussowitsch     if (pTypeVal == 0) PetscCall(DMLabelSetValue(vertexLabel, n, pIndexVal));
24049566063dSJacob Faibussowitsch     if (pTypeVal > 0) PetscCall(DMLabelSetValue(edgeLabel, n, pIndexVal));
24059566063dSJacob Faibussowitsch     if (pTypeVal < 0) PetscCall(DMLabelSetValue(faceLabel, n, pIndexVal));
2406c1cad2e7SMatthew G. Knepley   }
2407c1cad2e7SMatthew G. Knepley 
2408c1cad2e7SMatthew G. Knepley   /* Set DMLabels for Edges - Based on the DMLabels of the EDGE's NODES */
2409c1cad2e7SMatthew G. Knepley   for (int e = eStart; e < eEnd; ++e) {
2410c1cad2e7SMatthew G. Knepley     int bodyID_0, vertexID_0, vertexID_1, edgeID_0, edgeID_1, faceID_0, faceID_1;
2411c1cad2e7SMatthew G. Knepley 
24129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, e, &cone));
24139566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(bodyLabel, cone[0], &bodyID_0)); // Do I need to check the other end?
24149566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(vertexLabel, cone[0], &vertexID_0));
24159566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(vertexLabel, cone[1], &vertexID_1));
24169566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(edgeLabel, cone[0], &edgeID_0));
24179566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(edgeLabel, cone[1], &edgeID_1));
24189566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(faceLabel, cone[0], &faceID_0));
24199566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(faceLabel, cone[1], &faceID_1));
2420c1cad2e7SMatthew G. Knepley 
24219566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(bodyLabel, e, bodyID_0));
2422c1cad2e7SMatthew G. Knepley 
24239566063dSJacob Faibussowitsch     if (edgeID_0 == edgeID_1) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_0));
24249566063dSJacob Faibussowitsch     else if (vertexID_0 > 0 && edgeID_1 > 0) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_1));
24259566063dSJacob Faibussowitsch     else if (vertexID_1 > 0 && edgeID_0 > 0) PetscCall(DMLabelSetValue(edgeLabel, e, edgeID_0));
2426c1cad2e7SMatthew G. Knepley     else { /* Do Nothing */ }
2427c1cad2e7SMatthew G. Knepley   }
2428c1cad2e7SMatthew G. Knepley 
2429c1cad2e7SMatthew G. Knepley   /* Set DMLabels for Cells */
2430c1cad2e7SMatthew G. Knepley   for (int f = fStart; f < fEnd; ++f) {
2431c1cad2e7SMatthew G. Knepley     int           edgeID_0;
2432c1cad2e7SMatthew G. Knepley     PetscInt      triBodyVal, triFaceVal;
2433c1cad2e7SMatthew G. Knepley     PetscHashIter TFLiter, TBLiter;
2434c1cad2e7SMatthew G. Knepley     PetscBool     TFLfound, TBLfound;
2435c1cad2e7SMatthew G. Knepley 
2436c1cad2e7SMatthew G. Knepley     // Convert to Hash Table
24379566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(triFaceIDLabelMap, f - fStart, &TFLiter, &TFLfound));
24385552b385SBrandon     PetscCheck(TFLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in triFaceIDLabelMap", f);
24399566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(triFaceIDLabelMap, f - fStart, &triFaceVal));
2440c1cad2e7SMatthew G. Knepley 
24419566063dSJacob Faibussowitsch     PetscCall(PetscHMapIFind(triBodyIDLabelMap, f - fStart, &TBLiter, &TBLfound));
24425552b385SBrandon     PetscCheck(TBLfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "DAG Point %" PetscInt_FMT " not found in triBodyIDLabelMap", f);
24439566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGet(triBodyIDLabelMap, f - fStart, &triBodyVal));
2444c1cad2e7SMatthew G. Knepley 
24459566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(bodyLabel, f, triBodyVal));
24469566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(faceLabel, f, triFaceVal));
2447c1cad2e7SMatthew G. Knepley 
2448c1cad2e7SMatthew G. Knepley     /* Finish Labeling previously unlabeled DMPlex Edges - Assumes Triangular Cell (3 Edges Max) */
24499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, f, &cone));
2450c1cad2e7SMatthew G. Knepley 
2451c1cad2e7SMatthew G. Knepley     for (int jj = 0; jj < 3; ++jj) {
24529566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(edgeLabel, cone[jj], &edgeID_0));
2453c1cad2e7SMatthew G. Knepley 
2454c1cad2e7SMatthew G. Knepley       if (edgeID_0 < 0) {
24559566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(bodyLabel, cone[jj], triBodyVal));
24569566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(faceLabel, cone[jj], triFaceVal));
2457c1cad2e7SMatthew G. Knepley       }
2458c1cad2e7SMatthew G. Knepley     }
2459c1cad2e7SMatthew G. Knepley   }
2460c1cad2e7SMatthew G. Knepley 
2461c1cad2e7SMatthew G. Knepley   *newdm = dm;
24623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2463c1cad2e7SMatthew G. Knepley }
24647bee2925SMatthew Knepley #endif
24657bee2925SMatthew Knepley 
24665552b385SBrandon /*@C
24675552b385SBrandon   DMPlexInflateToGeomModelUseXYZ - 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.
2468c1cad2e7SMatthew G. Knepley 
246920f4b53cSBarry Smith   Collective
2470c1cad2e7SMatthew G. Knepley 
2471c1cad2e7SMatthew G. Knepley   Input Parameter:
2472a1cb98faSBarry Smith . dm - The uninflated `DM` object representing the mesh
2473c1cad2e7SMatthew G. Knepley 
2474c1cad2e7SMatthew G. Knepley   Level: intermediate
2475c1cad2e7SMatthew G. Knepley 
24761cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexCreateEGADS()`
2477c1cad2e7SMatthew G. Knepley @*/
2478ce78bad3SBarry Smith PetscErrorCode DMPlexInflateToGeomModelUseXYZ(DM dm) PeNS
2479d71ae5a4SJacob Faibussowitsch {
2480ce78bad3SBarry Smith   // please don't fucking write code like this with #ifdef all of the place!
2481c1cad2e7SMatthew G. Knepley #if defined(PETSC_HAVE_EGADS)
2482c1cad2e7SMatthew G. Knepley   /* EGADS Variables */
24835552b385SBrandon   ego    model, geom, body, face, edge, vertex;
2484c1cad2e7SMatthew G. Knepley   ego   *bodies;
2485c1cad2e7SMatthew G. Knepley   int    Nb, oclass, mtype, *senses;
24865552b385SBrandon   double result[4];
2487c1cad2e7SMatthew G. Knepley   /* PETSc Variables */
2488c1cad2e7SMatthew G. Knepley   DM             cdm;
2489c1cad2e7SMatthew G. Knepley   PetscContainer modelObj;
2490c1cad2e7SMatthew G. Knepley   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
2491c1cad2e7SMatthew G. Knepley   Vec            coordinates;
2492c1cad2e7SMatthew G. Knepley   PetscScalar   *coords;
2493c1cad2e7SMatthew G. Knepley   PetscInt       bodyID, faceID, edgeID, vertexID;
2494c1cad2e7SMatthew G. Knepley   PetscInt       cdim, d, vStart, vEnd, v;
24955552b385SBrandon   PetscBool      islite = PETSC_FALSE;
2496c1cad2e7SMatthew G. Knepley #endif
2497c1cad2e7SMatthew G. Knepley 
2498c1cad2e7SMatthew G. Knepley   PetscFunctionBegin;
2499c1cad2e7SMatthew G. Knepley #if defined(PETSC_HAVE_EGADS)
25009566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
25015552b385SBrandon   if (!modelObj) {
25025552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
25035552b385SBrandon     islite = PETSC_TRUE;
25045552b385SBrandon   }
25053ba16761SJacob Faibussowitsch   if (!modelObj) PetscFunctionReturn(PETSC_SUCCESS);
25069566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
25079566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
25089566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
25099566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
25109566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
25119566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
25129566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
2513c1cad2e7SMatthew G. Knepley 
25149566063dSJacob Faibussowitsch   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
25155552b385SBrandon 
25165552b385SBrandon   if (islite) {
25175552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
25185552b385SBrandon   } else {
25199566063dSJacob Faibussowitsch     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
25205552b385SBrandon   }
2521c1cad2e7SMatthew G. Knepley 
25229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
25239566063dSJacob Faibussowitsch   PetscCall(VecGetArrayWrite(coordinates, &coords));
2524c1cad2e7SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
2525c1cad2e7SMatthew G. Knepley     PetscScalar *vcoords;
2526c1cad2e7SMatthew G. Knepley 
25279566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(bodyLabel, v, &bodyID));
25289566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(faceLabel, v, &faceID));
25299566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(edgeLabel, v, &edgeID));
25309566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(vertexLabel, v, &vertexID));
2531c1cad2e7SMatthew G. Knepley 
25325552b385SBrandon     PetscCheck(bodyID < Nb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Body %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bodyID, Nb);
25335552b385SBrandon     body = bodies[bodyID];
25345552b385SBrandon 
25355552b385SBrandon     PetscCall(DMPlexPointLocalRef(cdm, v, coords, (void *)&vcoords));
25365552b385SBrandon     if (vertexID > 0) {
25375552b385SBrandon       if (islite) {
25385552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, NODE, vertexID, &vertex));
25395552b385SBrandon         PetscCall(EGlite_evaluate(vertex, NULL, result));
25405552b385SBrandon       } else {
25415552b385SBrandon         PetscCall(EG_objectBodyTopo(body, NODE, vertexID, &vertex));
25425552b385SBrandon         PetscCall(EG_evaluate(vertex, NULL, result));
25435552b385SBrandon       }
25445552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
25455552b385SBrandon     } else if (edgeID > 0) {
25465552b385SBrandon       /* Snap to EDGE at nearest location */
25475552b385SBrandon       double params[1];
25485552b385SBrandon       if (islite) {
25495552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &edge));
25505552b385SBrandon         PetscCall(EGlite_invEvaluate(edge, vcoords, params, result));
25515552b385SBrandon       } // Get (x,y,z) of nearest point on EDGE
25525552b385SBrandon       else {
25535552b385SBrandon         PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &edge));
25545552b385SBrandon         PetscCall(EG_invEvaluate(edge, vcoords, params, result));
25555552b385SBrandon       }
25565552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
25575552b385SBrandon     } else if (faceID > 0) {
25585552b385SBrandon       /* Snap to FACE at nearest location */
25595552b385SBrandon       double params[2];
25605552b385SBrandon       if (islite) {
25615552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &face));
25625552b385SBrandon         PetscCall(EGlite_invEvaluate(face, vcoords, params, result));
25635552b385SBrandon       } // Get (x,y,z) of nearest point on FACE
25645552b385SBrandon       else {
25655552b385SBrandon         PetscCall(EG_objectBodyTopo(body, FACE, faceID, &face));
25665552b385SBrandon         PetscCall(EG_invEvaluate(face, vcoords, params, result));
25675552b385SBrandon       }
25685552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
25695552b385SBrandon     }
25705552b385SBrandon   }
25715552b385SBrandon   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
25725552b385SBrandon   /* Clear out global coordinates */
25735552b385SBrandon   PetscCall(VecDestroy(&dm->coordinates[0].x));
25745552b385SBrandon #endif
25755552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
25765552b385SBrandon }
25775552b385SBrandon 
25785552b385SBrandon #if defined(PETSC_HAVE_EGADS)
25795552b385SBrandon // This replaces the model in-place
2580ce78bad3SBarry Smith PetscErrorCode ConvertGeomModelToAllBSplines(PetscBool islite, ego *model) PeNS
25815552b385SBrandon {
25825552b385SBrandon   /* EGADS/EGADSlite Variables */
25835552b385SBrandon   ego  context = NULL, geom, *bodies, *fobjs;
25845552b385SBrandon   int  oclass, mtype;
25855552b385SBrandon   int *senses;
25865552b385SBrandon   int  Nb, Nf;
25875552b385SBrandon 
25885552b385SBrandon   PetscFunctionBegin;
25895552b385SBrandon   // Get the number of bodies and body objects in the model
25905552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getTopology, (*model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
25915552b385SBrandon   else PetscCallEGADS(EG_getTopology, (*model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
25925552b385SBrandon 
25935552b385SBrandon   // Get all Faces on the body    <-- Only working with 1 body at the moment.
25945552b385SBrandon   ego body = bodies[0];
25955552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
25965552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
25975552b385SBrandon   ego newGeom[Nf];
25985552b385SBrandon   ego newFaces[Nf];
25995552b385SBrandon 
26005552b385SBrandon   // Convert the 1st Face to a BSpline Geometry
26015552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
26025552b385SBrandon     ego     face = fobjs[ii];
26035552b385SBrandon     ego     gRef, gPrev, gNext, *lobjs;
26045552b385SBrandon     int     goclass, gmtype, *gpinfo;
26055552b385SBrandon     int     Nl, *lsenses;
26065552b385SBrandon     double *gprv;
26075552b385SBrandon     char   *gClass = (char *)"", *gType = (char *)"";
26085552b385SBrandon 
26095552b385SBrandon     /* Shape Optimization is NOT available for EGADSlite geometry files. */
26105552b385SBrandon     /*     Note :: islite options are left below in case future versions of EGADSlite includes this capability */
26115552b385SBrandon     PetscCheck(!islite, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert geometric entities to all BSplines for geometries defined by EGADSlite (.egadslite)! Please use another geometry file format STEP, IGES, EGADS or BRep");
26125552b385SBrandon 
26135552b385SBrandon     if (islite) {
26145552b385SBrandon       PetscCallEGADS(EGlite_getTopology, (face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses)); // Get FACES Geometry object (geom_
26155552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));            // Get geometry object info
26165552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (geom, &goclass, &gmtype, &gRef, &gPrev, &gNext));
26175552b385SBrandon     } // Get geometry info
26185552b385SBrandon     else {
26195552b385SBrandon       PetscCallEGADS(EG_getTopology, (face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses)); // Get FACES Geometry object (geom_
26205552b385SBrandon       PetscCallEGADS(EG_getGeometry, (geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));            // Get geometry object info
26215552b385SBrandon       PetscCallEGADS(EG_getInfo, (geom, &goclass, &gmtype, &gRef, &gPrev, &gNext));
26225552b385SBrandon     } // Get geometry info
26235552b385SBrandon 
26245552b385SBrandon     PetscCall(DMPlex_EGADS_GeomDecode_Internal(goclass, gmtype, &gClass, &gType)); // Decode Geometry integers
26255552b385SBrandon 
26265552b385SBrandon     // Convert current FACE to a BSpline Surface
26275552b385SBrandon     ego     bspline;
26285552b385SBrandon     ego     bRef, bPrev, bNext;
26295552b385SBrandon     int     boclass, bmtype, *bpinfo;
26305552b385SBrandon     double *bprv;
26315552b385SBrandon     char   *bClass = (char *)"", *bType = (char *)"";
26325552b385SBrandon 
26335552b385SBrandon     PetscCallEGADS(EG_convertToBSpline, (face, &bspline)); // Does not have an EGlite_ version
26345552b385SBrandon 
26355552b385SBrandon     if (islite) {
26365552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (bspline, &boclass, &bmtype, &bRef, &bpinfo, &bprv)); // Get geometry object info
26375552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (bspline, &boclass, &bmtype, &bRef, &bPrev, &bNext));
26385552b385SBrandon     } // Get geometry info
26395552b385SBrandon     else {
26405552b385SBrandon       PetscCallEGADS(EG_getGeometry, (bspline, &boclass, &bmtype, &bRef, &bpinfo, &bprv)); // Get geometry object info
26415552b385SBrandon       PetscCallEGADS(EG_getInfo, (bspline, &boclass, &bmtype, &bRef, &bPrev, &bNext));
26425552b385SBrandon     } // Get geometry info
26435552b385SBrandon 
26445552b385SBrandon     PetscCall(DMPlex_EGADS_GeomDecode_Internal(boclass, bmtype, &bClass, &bType)); // Decode Geometry integers
26455552b385SBrandon 
26465552b385SBrandon     // Get Context from FACE
26475552b385SBrandon     context = NULL;
26485552b385SBrandon     PetscCallEGADS(EG_getContext, (face, &context)); // Does not have an EGlite_ version
26495552b385SBrandon 
26505552b385SBrandon     // Silence WARNING Regarding OPENCASCADE 7.5
26515552b385SBrandon     if (islite) PetscCallEGADS(EGlite_setOutLevel, (context, 0));
26525552b385SBrandon     else PetscCallEGADS(EG_setOutLevel, (context, 0));
26535552b385SBrandon 
26545552b385SBrandon     ego newgeom;
26555552b385SBrandon     PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, bprv, &newgeom)); // Does not have an EGlite_ version
26565552b385SBrandon 
26575552b385SBrandon     PetscCallEGADS(EG_deleteObject, (bspline));
26585552b385SBrandon 
26595552b385SBrandon     // Create new FACE based on new SURFACE geometry
26605552b385SBrandon     double data[4];
26615552b385SBrandon     int    periodic;
26625552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getRange, (newgeom, data, &periodic));
26635552b385SBrandon     else PetscCallEGADS(EG_getRange, (newgeom, data, &periodic));
26645552b385SBrandon 
26655552b385SBrandon     ego newface;
26665552b385SBrandon     PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, data, &newface)); // Does not have an EGlite_ version
26675552b385SBrandon     //PetscCallEGADS(EG_deleteObject, (newgeom));
26685552b385SBrandon     //PetscCallEGADS(EG_deleteObject, (newface));
26695552b385SBrandon     newFaces[ii] = newface;
26705552b385SBrandon     newGeom[ii]  = newgeom;
26715552b385SBrandon 
26725552b385SBrandon     // Reinstate WARNING Regarding OPENCASCADE 7.5
26735552b385SBrandon     if (islite) PetscCallEGADS(EGlite_setOutLevel, (context, 1));
26745552b385SBrandon     else PetscCallEGADS(EG_setOutLevel, (context, 1));
26755552b385SBrandon   }
26765552b385SBrandon 
26775552b385SBrandon   // Sew New Faces together to get a new model
26785552b385SBrandon   ego newmodel;
26795552b385SBrandon   PetscCallEGADS(EG_sewFaces, (Nf, newFaces, 0.0, 0, &newmodel)); // Does not have an EGlite_ version
26805552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
26815552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newFaces[ii]));
26825552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newGeom[ii]));
26835552b385SBrandon   }
26845552b385SBrandon   PetscCallEGADS(EG_deleteObject, (*model));
26855552b385SBrandon   *model = newmodel;
26865552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
26875552b385SBrandon }
26885552b385SBrandon #endif
26895552b385SBrandon 
26905552b385SBrandon /*@C
26915552b385SBrandon   DMPlexCreateGeomFromFile - Create a `DMPLEX` mesh from an EGADS, IGES, or STEP file.
26925552b385SBrandon 
26935552b385SBrandon   Collective
26945552b385SBrandon 
26955552b385SBrandon   Input Parameters:
26965552b385SBrandon + comm     - The MPI communicator
26975552b385SBrandon . filename - The name of the EGADS, IGES, or STEP file
26985552b385SBrandon - islite   - Flag for EGADSlite support
26995552b385SBrandon 
27005552b385SBrandon   Output Parameter:
27015552b385SBrandon . dm - The `DM` object representing the mesh
27025552b385SBrandon 
27035552b385SBrandon   Level: beginner
27045552b385SBrandon 
27055552b385SBrandon .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexCreateEGADS()`, `DMPlexCreateEGADSliteFromFile()`
27065552b385SBrandon @*/
2707ce78bad3SBarry Smith PetscErrorCode DMPlexCreateGeomFromFile(MPI_Comm comm, const char filename[], DM *dm, PetscBool islite) PeNS
27085552b385SBrandon {
27095552b385SBrandon   /* PETSc Variables */
27105552b385SBrandon   PetscMPIInt rank;
27115552b385SBrandon   PetscBool   printModel = PETSC_FALSE, tessModel = PETSC_FALSE, newModel = PETSC_FALSE;
27125552b385SBrandon   PetscBool   shapeOpt = PETSC_FALSE;
27135552b385SBrandon 
27145552b385SBrandon #if defined(PETSC_HAVE_EGADS)
27155552b385SBrandon   ego context = NULL, model = NULL;
27165552b385SBrandon #endif
27175552b385SBrandon 
27185552b385SBrandon   PetscFunctionBegin;
27195552b385SBrandon   PetscAssertPointer(filename, 2);
27205552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_print_model", &printModel, NULL));
27215552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_tess_model", &tessModel, NULL));
27225552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_new_model", &newModel, NULL));
27235552b385SBrandon   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_geom_shape_opt", &shapeOpt, NULL));
27245552b385SBrandon   PetscCallMPI(MPI_Comm_rank(comm, &rank));
27255552b385SBrandon #if defined(PETSC_HAVE_EGADS)
27265552b385SBrandon   if (rank == 0) {
27275552b385SBrandon     /* EGADSlite files cannot be used for Shape Optimization Work. It lacks the ability to make new geometry. */
27285552b385SBrandon     /* Must use EGADS, STEP, IGES or BRep files to perform this work.                                         */
27295552b385SBrandon     if (islite) {
27305552b385SBrandon       PetscCallEGADS(EGlite_open, (&context));
27315552b385SBrandon       PetscCallEGADS(EGlite_loadModel, (context, 0, filename, &model));
27325552b385SBrandon       if (shapeOpt) PetscCall(ConvertGeomModelToAllBSplines(islite, &model));
27335552b385SBrandon       if (printModel) PetscCall(DMPlexGeomPrintModel_Internal(model, islite));
27345552b385SBrandon     } else {
27355552b385SBrandon       PetscCallEGADS(EG_open, (&context));
27365552b385SBrandon       PetscCallEGADS(EG_loadModel, (context, 0, filename, &model));
27375552b385SBrandon       if (shapeOpt) PetscCall(ConvertGeomModelToAllBSplines(islite, &model));
27385552b385SBrandon       if (printModel) PetscCall(DMPlexGeomPrintModel_Internal(model, islite));
27395552b385SBrandon     }
27405552b385SBrandon   }
27415552b385SBrandon   if (tessModel) PetscCall(DMPlexCreateGeom_Tess_Internal(comm, context, model, dm, islite));
27425552b385SBrandon   else if (newModel) PetscCall(DMPlexCreateGeom_Internal(comm, context, model, dm, islite));
27435552b385SBrandon   else {
27445552b385SBrandon     PetscCall(DMPlexCreateGeom(comm, context, model, dm, islite));
27455552b385SBrandon   }
27465552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
27475552b385SBrandon #else
27485552b385SBrandon   SETERRQ(comm, PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
27495552b385SBrandon #endif
27505552b385SBrandon }
27515552b385SBrandon 
27525552b385SBrandon #if defined(PETSC_HAVE_EGADS)
27535552b385SBrandon /*@C
27545552b385SBrandon   DMPlex_Surface_Grad - Exposes the Geometry's Control Points and Weights and Calculates the Mesh Topology Boundary Nodes Gradient
27555552b385SBrandon                         with respect the associated geometry's Control Points and Weights.
27565552b385SBrandon 
27575552b385SBrandon                         // ----- Depreciated ---- See DMPlexGeomDataAndGrads ------ //
27585552b385SBrandon 
27595552b385SBrandon   Collective
27605552b385SBrandon 
27615552b385SBrandon   Input Parameters:
27625552b385SBrandon . dm      - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
27635552b385SBrandon 
27645552b385SBrandon   Output Parameter:
27655552b385SBrandon . dm       - The DM object representing the mesh with PetscContainers containing the EGADS geometry model, Array-Hash Table Geometry Control Point Pair, Array-Hash Table Geometry Weights Pair and Matrix-Hash Table Surface Gradient Pair
27665552b385SBrandon 
27675552b385SBrandon   Level: intermediate
27685552b385SBrandon 
27695552b385SBrandon .seealso:
27705552b385SBrandon @*/
27715552b385SBrandon PetscErrorCode DMPlex_Surface_Grad(DM dm)
27725552b385SBrandon {
27735552b385SBrandon   ego            model, geom, *bodies, *fobjs;
27745552b385SBrandon   PetscContainer modelObj;
27755552b385SBrandon   int            oclass, mtype, *senses;
27765552b385SBrandon   int            Nb, Nf;
27775552b385SBrandon   PetscHMapI     faceCntrlPtRow_Start = NULL, faceCPWeightsRow_Start = NULL;
27785552b385SBrandon   PetscHMapI     pointSurfGradRow_Start = NULL;
27795552b385SBrandon   Mat            pointSurfGrad;
27805552b385SBrandon   IS             faceLabelValues, edgeLabelValues, vertexLabelValues;
27815552b385SBrandon   PetscInt       faceLabelSize, edgeLabelSize, vertexLabelSize;
27825552b385SBrandon   PetscBool      islite = PETSC_FALSE;
27835552b385SBrandon 
27845552b385SBrandon   PetscFunctionBegin;
27855552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
27865552b385SBrandon   if (!modelObj) {
27875552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
27885552b385SBrandon     islite = PETSC_TRUE;
27895552b385SBrandon     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, " Cannot provide geometric data or associated calculated gradients for geometries defined by EGADSlite (.egadslite)! \n Please use another geometry file format STEP, IGES, EGADS or BRep");
27905552b385SBrandon   }
27915552b385SBrandon 
27925552b385SBrandon   // Get attached EGADS model (pointer)
27935552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
27945552b385SBrandon 
27955552b385SBrandon   // Get the bodies in the model
27965552b385SBrandon   if (islite) {
27975552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
27985552b385SBrandon   } else {
27995552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
28005552b385SBrandon   }
28015552b385SBrandon 
28025552b385SBrandon   ego body = bodies[0]; // Only operate on 1st body. Model should only have 1 body.
28035552b385SBrandon 
28045552b385SBrandon   // Get the total number of FACEs in the model
28055552b385SBrandon   if (islite) {
28065552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
28075552b385SBrandon   } else {
28085552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
28095552b385SBrandon   }
28105552b385SBrandon 
28115552b385SBrandon   // Get the total number of points and IDs in the DMPlex with a "EGADS Face Label"
28125552b385SBrandon   // This will provide the total number of DMPlex points on the boundary of the geometry
28135552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Face ID", &faceLabelValues));
28145552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Face ID", &faceLabelSize));
28155552b385SBrandon 
28165552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Edge ID", &edgeLabelValues));
28175552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Edge ID", &edgeLabelSize));
28185552b385SBrandon 
28195552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Vertex ID", &vertexLabelValues));
28205552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Vertex ID", &vertexLabelSize));
28215552b385SBrandon 
28225552b385SBrandon   const PetscInt *faceIndices, *edgeIndices, *vertexIndices;
28235552b385SBrandon   PetscCall(ISGetIndices(faceLabelValues, &faceIndices));
28245552b385SBrandon   PetscCall(ISGetIndices(edgeLabelValues, &edgeIndices));
28255552b385SBrandon   PetscCall(ISGetIndices(vertexLabelValues, &vertexIndices));
28265552b385SBrandon 
28275552b385SBrandon   // Get the points associated with each FACE, EDGE and VERTEX label in the DM
28285552b385SBrandon   PetscInt totalNumPoints = 0;
28295552b385SBrandon   for (int ii = 0; ii < faceLabelSize; ++ii) {
28305552b385SBrandon     // Cycle through FACE labels
28315552b385SBrandon     PetscInt size;
28325552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Face ID", faceIndices[ii], &size));
28335552b385SBrandon     totalNumPoints += size;
28345552b385SBrandon   }
28355552b385SBrandon   PetscCall(ISRestoreIndices(faceLabelValues, &faceIndices));
28365552b385SBrandon   PetscCall(ISDestroy(&faceLabelValues));
28375552b385SBrandon 
28385552b385SBrandon   for (int ii = 0; ii < edgeLabelSize; ++ii) {
28395552b385SBrandon     // Cycle Through EDGE Labels
28405552b385SBrandon     PetscInt size;
28415552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Edge ID", edgeIndices[ii], &size));
28425552b385SBrandon     totalNumPoints += size;
28435552b385SBrandon   }
28445552b385SBrandon   PetscCall(ISRestoreIndices(edgeLabelValues, &edgeIndices));
28455552b385SBrandon   PetscCall(ISDestroy(&edgeLabelValues));
28465552b385SBrandon 
28475552b385SBrandon   for (int ii = 0; ii < vertexLabelSize; ++ii) {
28485552b385SBrandon     // Cycle Through VERTEX Labels
28495552b385SBrandon     PetscInt size;
28505552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Vertex ID", vertexIndices[ii], &size));
28515552b385SBrandon     totalNumPoints += size;
28525552b385SBrandon   }
28535552b385SBrandon   PetscCall(ISRestoreIndices(vertexLabelValues, &vertexIndices));
28545552b385SBrandon   PetscCall(ISDestroy(&vertexLabelValues));
28555552b385SBrandon 
28565552b385SBrandon   int     maxNumCPs   = 0;
28575552b385SBrandon   int     totalNumCPs = 0;
28585552b385SBrandon   ego     bRef, bPrev, bNext, fgeom, *lobjs;
28595552b385SBrandon   int     id, boclass, bmtype, *bpinfo;
28605552b385SBrandon   int     foclass, fmtype, Nl, *lsenses;
28615552b385SBrandon   double *bprv;
28625552b385SBrandon   double  fdata[4];
28635552b385SBrandon 
28645552b385SBrandon   // Create Hash Tables
28655552b385SBrandon   PetscInt cntr = 0, wcntr = 0;
28665552b385SBrandon   PetscCall(PetscHMapICreate(&faceCntrlPtRow_Start));
28675552b385SBrandon   PetscCall(PetscHMapICreate(&faceCPWeightsRow_Start));
28685552b385SBrandon 
28695552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
28705552b385SBrandon     // Need to get the maximum number of Control Points defining the FACEs
28715552b385SBrandon     ego face = fobjs[ii];
28725552b385SBrandon     int maxNumCPs_temp;
28735552b385SBrandon 
28745552b385SBrandon     if (islite) {
28755552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
28765552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
28775552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
28785552b385SBrandon       PetscCall(EGlite_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
28795552b385SBrandon     } else {
28805552b385SBrandon       id = EG_indexBodyTopo(body, face);
28815552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
28825552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
28835552b385SBrandon       PetscCall(EG_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
28845552b385SBrandon     }
28855552b385SBrandon 
28865552b385SBrandon     maxNumCPs_temp = bpinfo[2] * bpinfo[5];
28875552b385SBrandon     totalNumCPs += bpinfo[2] * bpinfo[5];
28885552b385SBrandon 
28895552b385SBrandon     if (maxNumCPs_temp > maxNumCPs) { maxNumCPs = maxNumCPs_temp; }
28905552b385SBrandon   }
28915552b385SBrandon 
28925552b385SBrandon   PetscInt *cpCoordDataLengthPtr, *wDataLengthPtr;
28935552b385SBrandon   PetscInt  cpCoordDataLength = 3 * totalNumCPs;
28945552b385SBrandon   PetscInt  wDataLength       = totalNumCPs;
28955552b385SBrandon   cpCoordDataLengthPtr        = &cpCoordDataLength;
28965552b385SBrandon   wDataLengthPtr              = &wDataLength;
28975552b385SBrandon   PetscScalar *cntrlPtCoords, *cntrlPtWeights;
28985552b385SBrandon   PetscMalloc1(cpCoordDataLength, &cntrlPtCoords);
28995552b385SBrandon   PetscMalloc1(wDataLength, &cntrlPtWeights);
29005552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
29015552b385SBrandon     // Need to Populate Control Point Coordinates and Weight Vectors
29025552b385SBrandon     ego           face = fobjs[ii];
29035552b385SBrandon     PetscHashIter hashKeyIter, wHashKeyIter;
29045552b385SBrandon     PetscBool     hashKeyFound, wHashKeyFound;
29055552b385SBrandon 
29065552b385SBrandon     if (islite) {
29075552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
29085552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
29095552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
29105552b385SBrandon       PetscCall(EGlite_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
29115552b385SBrandon     } else {
29125552b385SBrandon       id = EG_indexBodyTopo(body, face);
29135552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
29145552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
29155552b385SBrandon       PetscCall(EG_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
29165552b385SBrandon     }
29175552b385SBrandon 
29185552b385SBrandon     // Store Face ID to 1st Row of Control Point Vector
29195552b385SBrandon     PetscCall(PetscHMapIFind(faceCntrlPtRow_Start, id, &hashKeyIter, &hashKeyFound));
29205552b385SBrandon 
29215552b385SBrandon     if (!hashKeyFound) { PetscCall(PetscHMapISet(faceCntrlPtRow_Start, id, cntr)); }
29225552b385SBrandon 
29235552b385SBrandon     int offsetCoord = bpinfo[3] + bpinfo[6];
29245552b385SBrandon     for (int jj = 0; jj < 3 * bpinfo[2] * bpinfo[5]; ++jj) {
29255552b385SBrandon       cntrlPtCoords[cntr] = bprv[offsetCoord + jj];
29265552b385SBrandon       cntr += 1;
29275552b385SBrandon     }
29285552b385SBrandon 
29295552b385SBrandon     // Store Face ID to 1st Row of Control Point Weight Vector
29305552b385SBrandon     PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, id, &wHashKeyIter, &wHashKeyFound));
29315552b385SBrandon 
29325552b385SBrandon     if (!wHashKeyFound) { PetscCall(PetscHMapISet(faceCPWeightsRow_Start, id, wcntr)); }
29335552b385SBrandon 
29345552b385SBrandon     int offsetWeight = bpinfo[3] + bpinfo[6] + (3 * bpinfo[2] * bpinfo[5]);
29355552b385SBrandon     for (int jj = 0; jj < bpinfo[2] * bpinfo[5]; ++jj) {
29365552b385SBrandon       cntrlPtWeights[wcntr] = bprv[offsetWeight + jj];
29375552b385SBrandon       wcntr += 1;
29385552b385SBrandon     }
29395552b385SBrandon   }
29405552b385SBrandon 
29415552b385SBrandon   // Attach Control Point and Weight Data to DM
29425552b385SBrandon   {
29435552b385SBrandon     PetscContainer cpOrgObj, cpCoordObj, cpCoordLengthObj;
29445552b385SBrandon     PetscContainer wOrgObj, wValObj, wDataLengthObj;
29455552b385SBrandon 
29465552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpOrgObj));
29475552b385SBrandon     PetscCall(PetscContainerSetPointer(cpOrgObj, faceCntrlPtRow_Start));
29485552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Hash Table", (PetscObject)cpOrgObj));
29495552b385SBrandon     PetscCall(PetscContainerDestroy(&cpOrgObj));
29505552b385SBrandon 
29515552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpCoordObj));
29525552b385SBrandon     PetscCall(PetscContainerSetPointer(cpCoordObj, cntrlPtCoords));
29535552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinates", (PetscObject)cpCoordObj));
29545552b385SBrandon     PetscCall(PetscContainerDestroy(&cpCoordObj));
29555552b385SBrandon 
29565552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpCoordLengthObj));
29575552b385SBrandon     PetscCall(PetscContainerSetPointer(cpCoordLengthObj, cpCoordDataLengthPtr));
29585552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject)cpCoordLengthObj));
29595552b385SBrandon     PetscCall(PetscContainerDestroy(&cpCoordLengthObj));
29605552b385SBrandon 
29615552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wOrgObj));
29625552b385SBrandon     PetscCall(PetscContainerSetPointer(wOrgObj, faceCPWeightsRow_Start));
29635552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject)wOrgObj));
29645552b385SBrandon     PetscCall(PetscContainerDestroy(&wOrgObj));
29655552b385SBrandon 
29665552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wValObj));
29675552b385SBrandon     PetscCall(PetscContainerSetPointer(wValObj, cntrlPtWeights));
29685552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data", (PetscObject)wValObj));
29695552b385SBrandon     PetscCall(PetscContainerDestroy(&wValObj));
29705552b385SBrandon 
29715552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wDataLengthObj));
29725552b385SBrandon     PetscCall(PetscContainerSetPointer(wDataLengthObj, wDataLengthPtr));
29735552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data Length", (PetscObject)wDataLengthObj));
29745552b385SBrandon     PetscCall(PetscContainerDestroy(&wDataLengthObj));
29755552b385SBrandon   }
29765552b385SBrandon 
29775552b385SBrandon   // Define Matrix to store  Surface Gradient information dx_i/dCPj_i
29785552b385SBrandon   PetscInt       gcntr   = 0;
29795552b385SBrandon   const PetscInt rowSize = 3 * maxNumCPs * totalNumPoints;
29805552b385SBrandon   const PetscInt colSize = 4 * Nf;
29815552b385SBrandon 
29825552b385SBrandon   // Create Point Surface Gradient Matrix
29835552b385SBrandon   MatCreate(PETSC_COMM_WORLD, &pointSurfGrad);
29845552b385SBrandon   MatSetSizes(pointSurfGrad, PETSC_DECIDE, PETSC_DECIDE, rowSize, colSize);
29855552b385SBrandon   MatSetType(pointSurfGrad, MATAIJ);
29865552b385SBrandon   MatSetUp(pointSurfGrad);
29875552b385SBrandon 
29885552b385SBrandon   // Create Hash Table to store Point's stare row in surfaceGrad[][]
29895552b385SBrandon   PetscCall(PetscHMapICreate(&pointSurfGradRow_Start));
29905552b385SBrandon 
29915552b385SBrandon   // Get Coordinates for the DMPlex point
29925552b385SBrandon   DM           cdm;
29935552b385SBrandon   PetscInt     dE, Nv;
29945552b385SBrandon   Vec          coordinatesLocal;
29955552b385SBrandon   PetscScalar *coords = NULL;
29965552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
29975552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &dE));
29985552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
29995552b385SBrandon 
30005552b385SBrandon   // CYCLE THROUGH FACEs
30015552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
30025552b385SBrandon     ego             face = fobjs[ii];
30035552b385SBrandon     ego            *eobjs, *nobjs;
30045552b385SBrandon     PetscInt        fid, Ne, Nn;
30055552b385SBrandon     DMLabel         faceLabel, edgeLabel, nodeLabel;
30065552b385SBrandon     PetscHMapI      currFaceUniquePoints = NULL;
30075552b385SBrandon     IS              facePoints, edgePoints, nodePoints;
30085552b385SBrandon     const PetscInt *fIndices, *eIndices, *nIndices;
30095552b385SBrandon     PetscInt        fSize, eSize, nSize;
30105552b385SBrandon     PetscHashIter   fHashKeyIter, eHashKeyIter, nHashKeyIter, pHashKeyIter;
30115552b385SBrandon     PetscBool       fHashKeyFound, eHashKeyFound, nHashKeyFound, pHashKeyFound;
30125552b385SBrandon     PetscInt        cfCntr = 0;
30135552b385SBrandon 
30145552b385SBrandon     // Get Geometry Object for the Current FACE
30155552b385SBrandon     if (islite) {
30165552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
30175552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
30185552b385SBrandon     } else {
30195552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
30205552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
30215552b385SBrandon     }
30225552b385SBrandon 
30235552b385SBrandon     // Get all EDGE and NODE objects attached to the current FACE
30245552b385SBrandon     if (islite) {
30255552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
30265552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, NODE, &Nn, &nobjs));
30275552b385SBrandon     } else {
30285552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
30295552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, NODE, &Nn, &nobjs));
30305552b385SBrandon     }
30315552b385SBrandon 
30325552b385SBrandon     // Get all DMPlex Points that have DMLabel "EGADS Face ID" and store them in a Hash Table for later use
30335552b385SBrandon     if (islite) {
30345552b385SBrandon       fid = EGlite_indexBodyTopo(body, face);
30355552b385SBrandon     } else {
30365552b385SBrandon       fid = EG_indexBodyTopo(body, face);
30375552b385SBrandon     }
30385552b385SBrandon 
30395552b385SBrandon     PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
30405552b385SBrandon     PetscCall(DMLabelGetStratumIS(faceLabel, fid, &facePoints));
30415552b385SBrandon     PetscCall(ISGetIndices(facePoints, &fIndices));
30425552b385SBrandon     PetscCall(ISGetSize(facePoints, &fSize));
30435552b385SBrandon 
30445552b385SBrandon     PetscCall(PetscHMapICreate(&currFaceUniquePoints));
30455552b385SBrandon 
30465552b385SBrandon     for (int jj = 0; jj < fSize; ++jj) {
30475552b385SBrandon       PetscCall(PetscHMapIFind(currFaceUniquePoints, fIndices[jj], &fHashKeyIter, &fHashKeyFound));
30485552b385SBrandon 
30495552b385SBrandon       if (!fHashKeyFound) {
30505552b385SBrandon         PetscCall(PetscHMapISet(currFaceUniquePoints, fIndices[jj], cfCntr));
30515552b385SBrandon         cfCntr += 1;
30525552b385SBrandon       }
30535552b385SBrandon 
30545552b385SBrandon       PetscCall(PetscHMapIFind(pointSurfGradRow_Start, fIndices[jj], &pHashKeyIter, &pHashKeyFound));
30555552b385SBrandon 
30565552b385SBrandon       if (!pHashKeyFound) {
30575552b385SBrandon         PetscCall(PetscHMapISet(pointSurfGradRow_Start, fIndices[jj], gcntr));
30585552b385SBrandon         gcntr += 3 * maxNumCPs;
30595552b385SBrandon       }
30605552b385SBrandon     }
30615552b385SBrandon     PetscCall(ISRestoreIndices(facePoints, &fIndices));
30625552b385SBrandon     PetscCall(ISDestroy(&facePoints));
30635552b385SBrandon 
30645552b385SBrandon     // Get all DMPlex Points that have DMLable "EGADS Edge ID" attached to the current FACE and store them in a Hash Table for later use.
30655552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
30665552b385SBrandon       ego       edge = eobjs[jj];
30675552b385SBrandon       PetscBool containLabelValue;
30685552b385SBrandon 
30695552b385SBrandon       if (islite) {
30705552b385SBrandon         id = EGlite_indexBodyTopo(body, edge);
30715552b385SBrandon       } else {
30725552b385SBrandon         id = EG_indexBodyTopo(body, edge);
30735552b385SBrandon       }
30745552b385SBrandon 
30755552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
30765552b385SBrandon       PetscCall(DMLabelHasValue(edgeLabel, id, &containLabelValue));
30775552b385SBrandon 
30785552b385SBrandon       if (containLabelValue) {
30795552b385SBrandon         PetscCall(DMLabelGetStratumIS(edgeLabel, id, &edgePoints));
30805552b385SBrandon         PetscCall(ISGetIndices(edgePoints, &eIndices));
30815552b385SBrandon         PetscCall(ISGetSize(edgePoints, &eSize));
30825552b385SBrandon 
30835552b385SBrandon         for (int kk = 0; kk < eSize; ++kk) {
30845552b385SBrandon           PetscCall(PetscHMapIFind(currFaceUniquePoints, eIndices[kk], &eHashKeyIter, &eHashKeyFound));
30855552b385SBrandon 
30865552b385SBrandon           if (!eHashKeyFound) {
30875552b385SBrandon             PetscCall(PetscHMapISet(currFaceUniquePoints, eIndices[kk], cfCntr));
30885552b385SBrandon             cfCntr += 1;
30895552b385SBrandon           }
30905552b385SBrandon 
30915552b385SBrandon           PetscCall(PetscHMapIFind(pointSurfGradRow_Start, eIndices[kk], &pHashKeyIter, &pHashKeyFound));
30925552b385SBrandon 
30935552b385SBrandon           if (!pHashKeyFound) {
30945552b385SBrandon             PetscCall(PetscHMapISet(pointSurfGradRow_Start, eIndices[kk], gcntr));
30955552b385SBrandon             gcntr += 3 * maxNumCPs;
30965552b385SBrandon           }
30975552b385SBrandon         }
30985552b385SBrandon         PetscCall(ISRestoreIndices(edgePoints, &eIndices));
30995552b385SBrandon         PetscCall(ISDestroy(&edgePoints));
31005552b385SBrandon       }
31015552b385SBrandon     }
31025552b385SBrandon 
31035552b385SBrandon     // Get all DMPlex Points that have DMLabel "EGADS Vertex ID" attached to the current FACE and store them in a Hash Table for later use.
31045552b385SBrandon     for (int jj = 0; jj < Nn; ++jj) {
31055552b385SBrandon       ego node = nobjs[jj];
31065552b385SBrandon 
31075552b385SBrandon       if (islite) {
31085552b385SBrandon         id = EGlite_indexBodyTopo(body, node);
31095552b385SBrandon       } else {
31105552b385SBrandon         id = EG_indexBodyTopo(body, node);
31115552b385SBrandon       }
31125552b385SBrandon 
31135552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &nodeLabel));
31145552b385SBrandon       PetscCall(DMLabelGetStratumIS(nodeLabel, id, &nodePoints));
31155552b385SBrandon       PetscCall(ISGetIndices(nodePoints, &nIndices));
31165552b385SBrandon       PetscCall(ISGetSize(nodePoints, &nSize));
31175552b385SBrandon 
31185552b385SBrandon       for (int kk = 0; kk < nSize; ++kk) {
31195552b385SBrandon         PetscCall(PetscHMapIFind(currFaceUniquePoints, nIndices[kk], &nHashKeyIter, &nHashKeyFound));
31205552b385SBrandon 
31215552b385SBrandon         if (!nHashKeyFound) {
31225552b385SBrandon           PetscCall(PetscHMapISet(currFaceUniquePoints, nIndices[kk], cfCntr));
31235552b385SBrandon           cfCntr += 1;
31245552b385SBrandon         }
31255552b385SBrandon 
31265552b385SBrandon         PetscCall(PetscHMapIFind(pointSurfGradRow_Start, nIndices[kk], &pHashKeyIter, &pHashKeyFound));
31275552b385SBrandon         if (!pHashKeyFound) {
31285552b385SBrandon           PetscCall(PetscHMapISet(pointSurfGradRow_Start, nIndices[kk], gcntr));
31295552b385SBrandon           gcntr += 3 * maxNumCPs;
31305552b385SBrandon         }
31315552b385SBrandon       }
31325552b385SBrandon       PetscCall(ISRestoreIndices(nodePoints, &nIndices));
31335552b385SBrandon       PetscCall(ISDestroy(&nodePoints));
31345552b385SBrandon     }
31355552b385SBrandon 
31365552b385SBrandon     // Get the Total Number of entries in the Hash Table
31375552b385SBrandon     PetscInt currFaceUPSize;
31385552b385SBrandon     PetscCall(PetscHMapIGetSize(currFaceUniquePoints, &currFaceUPSize));
31395552b385SBrandon 
31405552b385SBrandon     // Get Keys
31415552b385SBrandon     PetscInt currFaceUPKeys[currFaceUPSize], off = 0;
31425552b385SBrandon     PetscCall(PetscHMapIGetKeys(currFaceUniquePoints, &off, currFaceUPKeys));
31435552b385SBrandon 
31445552b385SBrandon     // Cycle through all points on the current FACE
31455552b385SBrandon     for (int jj = 0; jj < currFaceUPSize; ++jj) {
31465552b385SBrandon       PetscInt currPointID = currFaceUPKeys[jj];
31475552b385SBrandon       PetscCall(DMPlexVecGetClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
31485552b385SBrandon 
31495552b385SBrandon       // Get UV position of FACE
31505552b385SBrandon       double params[2], range[4], eval[18];
31515552b385SBrandon       int    peri;
31525552b385SBrandon 
31535552b385SBrandon       if (islite) {
31545552b385SBrandon         PetscCall(EGlite_getRange(face, range, &peri));
31555552b385SBrandon       } else {
31565552b385SBrandon         PetscCall(EG_getRange(face, range, &peri));
31575552b385SBrandon       }
31585552b385SBrandon 
31595552b385SBrandon       PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, face, range, 0, dE, params, islite));
31605552b385SBrandon 
31615552b385SBrandon       if (islite) {
31625552b385SBrandon         PetscCall(EGlite_evaluate(face, params, eval));
31635552b385SBrandon       } else {
31645552b385SBrandon         PetscCall(EG_evaluate(face, params, eval));
31655552b385SBrandon       }
31665552b385SBrandon 
31675552b385SBrandon       // Make a new SURFACE Geometry by changing the location of the Control Points
31685552b385SBrandon       int    prvSize = bpinfo[3] + bpinfo[6] + (4 * bpinfo[2] * bpinfo[5]);
31695552b385SBrandon       double nbprv[prvSize];
31705552b385SBrandon 
31715552b385SBrandon       // Cycle through each Control Point
31725552b385SBrandon       double deltaCoord = 1.0E-4;
31735552b385SBrandon       int    offset     = bpinfo[3] + bpinfo[6];
31745552b385SBrandon       int    wOffset    = offset + (3 * bpinfo[2] * bpinfo[5]);
31755552b385SBrandon       for (int ii = 0; ii < bpinfo[2] * bpinfo[5]; ++ii) {
31765552b385SBrandon         // Cycle through each direction (x, then y, then z)
31775552b385SBrandon         for (int kk = 0; kk < 4; ++kk) {
31785552b385SBrandon           // Reinitialize nbprv[] values because we only want to change one value at a time
31795552b385SBrandon           for (int mm = 0; mm < prvSize; ++mm) { nbprv[mm] = bprv[mm]; }
31805552b385SBrandon 
31815552b385SBrandon           if (kk == 0) { //X
31825552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0] + deltaCoord;
31835552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
31845552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
31855552b385SBrandon           } else if (kk == 1) { //Y
31865552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
31875552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1] + deltaCoord;
31885552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
31895552b385SBrandon           } else if (kk == 2) { //Z
31905552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
31915552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
31925552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2] + deltaCoord;
31935552b385SBrandon           } else if (kk == 3) { // Weights
31945552b385SBrandon             nbprv[wOffset + ii] = bprv[wOffset + ii] + deltaCoord;
31955552b385SBrandon           } else {
31965552b385SBrandon             // currently do nothing
31975552b385SBrandon           }
31985552b385SBrandon 
31995552b385SBrandon           // Create New Surface Based on New Control Points or Weights
32005552b385SBrandon           ego newgeom, context;
32015552b385SBrandon           if (islite) {
32025552b385SBrandon             PetscCall(EGlite_open(&context));
32035552b385SBrandon             PetscCall(EGlite_setOutLevel(context, 0));
32045552b385SBrandon           } else {
32055552b385SBrandon             PetscCall(EG_open(&context));
32065552b385SBrandon             PetscCall(EG_setOutLevel(context, 0));
32075552b385SBrandon           }
32085552b385SBrandon 
32095552b385SBrandon           PetscCall(EG_makeGeometry(context, SURFACE, BSPLINE, NULL, bpinfo, nbprv, &newgeom)); // Does not have an EGlite_ version KNOWN_ISSUE
32105552b385SBrandon 
32115552b385SBrandon           if (islite) {
32125552b385SBrandon             PetscCall(EGlite_setOutLevel(context, 1));
32135552b385SBrandon           } else {
32145552b385SBrandon             PetscCall(EG_setOutLevel(context, 1));
32155552b385SBrandon           }
32165552b385SBrandon 
32175552b385SBrandon           // Evaluate new (x, y, z) Point Position based on new Surface Definition
32185552b385SBrandon           double newCoords[18];
32195552b385SBrandon           if (islite) {
32205552b385SBrandon             PetscCall(EGlite_getRange(newgeom, range, &peri));
32215552b385SBrandon           } else {
32225552b385SBrandon             PetscCall(EG_getRange(newgeom, range, &peri));
32235552b385SBrandon           }
32245552b385SBrandon 
32255552b385SBrandon           PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, newgeom, range, 0, dE, params, islite));
32265552b385SBrandon 
32275552b385SBrandon           if (islite) {
32285552b385SBrandon             PetscCall(EGlite_evaluate(newgeom, params, newCoords));
32295552b385SBrandon           } else {
32305552b385SBrandon             PetscCall(EG_evaluate(newgeom, params, newCoords));
32315552b385SBrandon           }
32325552b385SBrandon 
32335552b385SBrandon           // Now Calculate the Surface Gradient for the change in x-component Control Point
32345552b385SBrandon           PetscScalar dxdCx = (newCoords[0] - coords[0]) / deltaCoord;
32355552b385SBrandon           PetscScalar dxdCy = (newCoords[1] - coords[1]) / deltaCoord;
32365552b385SBrandon           PetscScalar dxdCz = (newCoords[2] - coords[2]) / deltaCoord;
32375552b385SBrandon 
32385552b385SBrandon           // Store Gradient Information in surfaceGrad[][] Matrix
32395552b385SBrandon           PetscInt startRow;
32405552b385SBrandon           PetscCall(PetscHMapIGet(pointSurfGradRow_Start, currPointID, &startRow));
32415552b385SBrandon 
32425552b385SBrandon           // Store Results in Petsc Matrix
32435552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 0, ((fid - 1) * 4) + kk, dxdCx, INSERT_VALUES));
32445552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 1, ((fid - 1) * 4) + kk, dxdCy, INSERT_VALUES));
32455552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 2, ((fid - 1) * 4) + kk, dxdCz, INSERT_VALUES));
32465552b385SBrandon         }
32475552b385SBrandon         offset += 3;
32485552b385SBrandon       }
32495552b385SBrandon       PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
32505552b385SBrandon     }
32515552b385SBrandon   }
32525552b385SBrandon 
32535552b385SBrandon   // Assemble Point Surface Grad Matrix
32545552b385SBrandon   MatAssemblyBegin(pointSurfGrad, MAT_FINAL_ASSEMBLY);
32555552b385SBrandon   MatAssemblyEnd(pointSurfGrad, MAT_FINAL_ASSEMBLY);
32565552b385SBrandon 
32575552b385SBrandon   // Attach Surface Gradient Hash Table and Matrix to DM
32585552b385SBrandon   {
32595552b385SBrandon     PetscContainer surfGradOrgObj, surfGradObj;
32605552b385SBrandon 
32615552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &surfGradOrgObj));
32625552b385SBrandon     PetscCall(PetscContainerSetPointer(surfGradOrgObj, pointSurfGradRow_Start));
32635552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject)surfGradOrgObj));
32645552b385SBrandon     PetscCall(PetscContainerDestroy(&surfGradOrgObj));
32655552b385SBrandon 
32665552b385SBrandon     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &surfGradObj));
32675552b385SBrandon     PetscCall(PetscContainerSetPointer(surfGradObj, pointSurfGrad));
32685552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Matrix", (PetscObject)surfGradObj));
32695552b385SBrandon     PetscCall(PetscContainerDestroy(&surfGradObj));
32705552b385SBrandon   }
32715552b385SBrandon   if (islite) EGlite_free(fobjs);
32725552b385SBrandon   else EG_free(fobjs);
32735552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
32745552b385SBrandon }
32755552b385SBrandon 
32765552b385SBrandon static PetscErrorCode DestroyHashMap(void **p)
32775552b385SBrandon {
32785552b385SBrandon   PetscFunctionBegin;
32795552b385SBrandon   PetscCall(PetscHMapIDestroy((PetscHMapI *)p));
32805552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
32815552b385SBrandon }
32825552b385SBrandon #endif
32835552b385SBrandon 
32845552b385SBrandon /*@C
32855552b385SBrandon   DMPlexGeomDataAndGrads - Exposes Control Points and Control Point Weights defining the underlying geometry allowing user manipulation of the geometry.
32865552b385SBrandon 
32875552b385SBrandon   Collective
32885552b385SBrandon 
32895552b385SBrandon   Input Parameters:
32905552b385SBrandon + dm           - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
32915552b385SBrandon - fullGeomGrad - PetscBool flag. Determines how the Surface Area and Volume Gradients wrt to Control Points and Control Point Weights are calculated.
32925552b385SBrandon                       PETSC_FALSE :: Surface Area Gradient wrt Control Points and Control Point Weights are calculated using the change in the local
32935552b385SBrandon                                      FACE changes (not the entire body). Volume Gradients are not calculated. Faster computations.
32945552b385SBrandon                       PETSC_TRUE  :: Surface Area Gradietn wrt to Control Points and Control Point Weights are calculated using the change observed in
32955552b385SBrandon                                      the entire solid body. Volume Gradients are calculated. Slower computation due to the need to generate a new solid
32965552b385SBrandon                                      body geometry for every Control Point and Control Point Weight change.
32975552b385SBrandon 
32985552b385SBrandon   Output Parameter:
32995552b385SBrandon . dm - The updated DM object representing the mesh with PetscContainers containing the Control Point, Control Point Weight and Gradient Data.
33005552b385SBrandon 
33015552b385SBrandon   Level: intermediate
33025552b385SBrandon 
33035552b385SBrandon   Note:
33045552b385SBrandon   Calculates the DM Point location, surface area and volume gradients wrt to Control Point and Control Point Weights using Finite Difference (small perturbation of Control Point coordinates or Control Point Weight value).
33055552b385SBrandon 
33065552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexModifyEGADSGeomModel()`
33075552b385SBrandon @*/
3308ce78bad3SBarry Smith PetscErrorCode DMPlexGeomDataAndGrads(DM dm, PetscBool fullGeomGrad) PeNS
33095552b385SBrandon {
33105552b385SBrandon #if defined(PETSC_HAVE_EGADS)
33115552b385SBrandon   /* PETSc Variables */
33125552b385SBrandon   PetscContainer modelObj;
33135552b385SBrandon   PetscHMapI     faceCntrlPtRow_Start = NULL, faceCPWeightsRow_Start = NULL;
33145552b385SBrandon   PetscHMapI     pointSurfGradRow_Start = NULL;
33155552b385SBrandon   Mat            pointSurfGrad, cpEquiv;
33165552b385SBrandon   IS             faceLabelValues, edgeLabelValues, vertexLabelValues;
33175552b385SBrandon   PetscInt       faceLabelSize, edgeLabelSize, vertexLabelSize;
33185552b385SBrandon   PetscBool      islite = PETSC_FALSE;
33195552b385SBrandon   /* EGADS Variables */
33205552b385SBrandon   ego model, geom, *bodies, *fobjs = NULL;
33215552b385SBrandon   int oclass, mtype, *senses;
33225552b385SBrandon   int Nb, Nf;
33235552b385SBrandon #endif
33245552b385SBrandon 
33255552b385SBrandon   PetscFunctionBegin;
33265552b385SBrandon #if defined(PETSC_HAVE_EGADS)
33275552b385SBrandon 
33285552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
33295552b385SBrandon   if (!modelObj) {
33305552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
33315552b385SBrandon     PetscCheck(modelObj, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Input DM must have attached EGADS Geometry Model");
33325552b385SBrandon     islite = PETSC_TRUE;
33335552b385SBrandon     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot provide geometric data or associated calculated gradients for geometries defined by EGADSlite (.egadslite)!\nPlease use another geometry file format STEP, IGES, EGADS or BRep");
33345552b385SBrandon   }
33355552b385SBrandon 
33365552b385SBrandon   // Get attached EGADS model (pointer)
33375552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
33385552b385SBrandon 
33395552b385SBrandon   // Get the bodies in the model
33405552b385SBrandon   if (islite) {
33415552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
33425552b385SBrandon   } else {
33435552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
33445552b385SBrandon   }
33455552b385SBrandon 
33465552b385SBrandon   ego body = bodies[0]; // Only operate on 1st body. Model should only have 1 body.
33475552b385SBrandon 
33485552b385SBrandon   // Get the total number of FACEs in the model
33495552b385SBrandon   if (islite) {
33505552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
33515552b385SBrandon   } else {
33525552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, FACE, &Nf, &fobjs));
33535552b385SBrandon   }
33545552b385SBrandon 
33555552b385SBrandon   // Get the total number of points and IDs in the DMPlex with a "EGADS Face Label"
33565552b385SBrandon   // This will provide the total number of DMPlex points on the boundary of the geometry
33575552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Face ID", &faceLabelValues));
33585552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Face ID", &faceLabelSize));
33595552b385SBrandon 
33605552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Edge ID", &edgeLabelValues));
33615552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Edge ID", &edgeLabelSize));
33625552b385SBrandon 
33635552b385SBrandon   PetscCall(DMGetLabelIdIS(dm, "EGADS Vertex ID", &vertexLabelValues));
33645552b385SBrandon   PetscCall(DMGetLabelSize(dm, "EGADS Vertex ID", &vertexLabelSize));
33655552b385SBrandon 
33665552b385SBrandon   const PetscInt *faceIndices, *edgeIndices, *vertexIndices;
33675552b385SBrandon   PetscCall(ISGetIndices(faceLabelValues, &faceIndices));
33685552b385SBrandon   PetscCall(ISGetIndices(edgeLabelValues, &edgeIndices));
33695552b385SBrandon   PetscCall(ISGetIndices(vertexLabelValues, &vertexIndices));
33705552b385SBrandon 
33715552b385SBrandon   // Get the points associated with each FACE, EDGE and VERTEX label in the DM
33725552b385SBrandon   PetscInt totalNumPoints = 0;
33735552b385SBrandon   for (int f = 0; f < faceLabelSize; ++f) {
33745552b385SBrandon     // Cycle through FACE labels
33755552b385SBrandon     PetscInt size;
33765552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Face ID", faceIndices[f], &size));
33775552b385SBrandon     totalNumPoints += size;
33785552b385SBrandon   }
33795552b385SBrandon   PetscCall(ISRestoreIndices(faceLabelValues, &faceIndices));
33805552b385SBrandon   PetscCall(ISDestroy(&faceLabelValues));
33815552b385SBrandon 
33825552b385SBrandon   for (int e = 0; e < edgeLabelSize; ++e) {
33835552b385SBrandon     // Cycle Through EDGE Labels
33845552b385SBrandon     PetscInt size;
33855552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Edge ID", edgeIndices[e], &size));
33865552b385SBrandon     totalNumPoints += size;
33875552b385SBrandon   }
33885552b385SBrandon   PetscCall(ISRestoreIndices(edgeLabelValues, &edgeIndices));
33895552b385SBrandon   PetscCall(ISDestroy(&edgeLabelValues));
33905552b385SBrandon 
33915552b385SBrandon   for (int ii = 0; ii < vertexLabelSize; ++ii) {
33925552b385SBrandon     // Cycle Through VERTEX Labels
33935552b385SBrandon     PetscInt size;
33945552b385SBrandon     PetscCall(DMGetStratumSize(dm, "EGADS Vertex ID", vertexIndices[ii], &size));
33955552b385SBrandon     totalNumPoints += size;
33965552b385SBrandon   }
33975552b385SBrandon   PetscCall(ISRestoreIndices(vertexLabelValues, &vertexIndices));
33985552b385SBrandon   PetscCall(ISDestroy(&vertexLabelValues));
33995552b385SBrandon 
34005552b385SBrandon   int     maxNumCPs   = 0;
34015552b385SBrandon   int     totalNumCPs = 0;
34025552b385SBrandon   ego     bRef, bPrev, bNext, fgeom, *lobjs;
34035552b385SBrandon   int     id, boclass, bmtype, *bpinfo;
34045552b385SBrandon   int     foclass, fmtype, Nl, *lsenses;
34055552b385SBrandon   double *bprv;
34065552b385SBrandon   double  fdata[4];
34075552b385SBrandon 
34085552b385SBrandon   // Create Hash Tables
34095552b385SBrandon   PetscInt cntr = 0, wcntr = 0, vcntr = 0;
34105552b385SBrandon   PetscCall(PetscHMapICreate(&faceCntrlPtRow_Start));
34115552b385SBrandon   PetscCall(PetscHMapICreate(&faceCPWeightsRow_Start));
34125552b385SBrandon 
34135552b385SBrandon   for (int f = 0; f < Nf; ++f) {
34145552b385SBrandon     // Need to get the maximum number of Control Points defining the FACEs
34155552b385SBrandon     ego face = fobjs[f];
34165552b385SBrandon     int maxNumCPs_temp;
34175552b385SBrandon 
34185552b385SBrandon     if (islite) {
34195552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
34205552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
34215552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
34225552b385SBrandon       PetscCall(EGlite_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
34235552b385SBrandon     } else {
34245552b385SBrandon       id = EG_indexBodyTopo(body, face);
34255552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
34265552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
34275552b385SBrandon       PetscCall(EG_getInfo(fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
34285552b385SBrandon     }
34295552b385SBrandon     maxNumCPs_temp = bpinfo[2] * bpinfo[5];
34305552b385SBrandon     totalNumCPs += bpinfo[2] * bpinfo[5];
34315552b385SBrandon 
34325552b385SBrandon     if (maxNumCPs_temp > maxNumCPs) { maxNumCPs = maxNumCPs_temp; }
34335552b385SBrandon   }
34345552b385SBrandon 
34355552b385SBrandon   PetscInt *cpCoordDataLengthPtr, *wDataLengthPtr;
34365552b385SBrandon   PetscInt  cpCoordDataLength = 3 * totalNumCPs;
34375552b385SBrandon   PetscInt  wDataLength       = totalNumCPs;
34385552b385SBrandon   cpCoordDataLengthPtr        = &cpCoordDataLength;
34395552b385SBrandon   wDataLengthPtr              = &wDataLength;
34405552b385SBrandon 
34415552b385SBrandon   Vec          cntrlPtCoordsVec, cntrlPtWeightsVec;
34425552b385SBrandon   PetscScalar *cntrlPtCoords, *cntrlPtWeights;
34435552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, cpCoordDataLength, &cntrlPtCoordsVec));
34445552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, wDataLength, &cntrlPtWeightsVec));
34455552b385SBrandon 
34465552b385SBrandon   // For dSA/dCPi
34475552b385SBrandon   Vec          gradSACPVec, gradSAWVec, gradVCPVec, gradVWVec;
34485552b385SBrandon   PetscScalar *gradSACP, *gradSAW, *gradVCP, *gradVW;
34495552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, cpCoordDataLength, &gradSACPVec));
34505552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, wDataLength, &gradSAWVec));
34515552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, cpCoordDataLength, &gradVCPVec));
34525552b385SBrandon   PetscCall(VecCreateSeq(PETSC_COMM_SELF, wDataLength, &gradVWVec));
34535552b385SBrandon 
34545552b385SBrandon   // Control Point - Vertex/Edge/Face Relationship
34555552b385SBrandon   PetscInt *cp_vertex, *cp_edge, *cp_face;
34565552b385SBrandon   PetscInt *w_vertex, *w_edge, *w_face;
34575552b385SBrandon   PetscCall(PetscMalloc1(totalNumCPs, &cp_vertex));
34585552b385SBrandon   PetscCall(PetscMalloc1(totalNumCPs, &cp_edge));
34595552b385SBrandon   PetscCall(PetscMalloc1(totalNumCPs, &cp_face));
34605552b385SBrandon   PetscCall(PetscMalloc1(wDataLength, &w_vertex));
34615552b385SBrandon   PetscCall(PetscMalloc1(wDataLength, &w_edge));
34625552b385SBrandon   PetscCall(PetscMalloc1(wDataLength, &w_face));
34635552b385SBrandon 
34645552b385SBrandon   for (int f = 0; f < Nf; ++f) {
34655552b385SBrandon     // Need to Populate Control Point Coordinates and Weight Vectors
34665552b385SBrandon     ego           face = fobjs[f];
34675552b385SBrandon     ego          *vobjs, *eobjs;
34685552b385SBrandon     int           offsetCoord, offsetWeight;
34695552b385SBrandon     PetscInt      Nv, Ne, wRowStart = 0;
34705552b385SBrandon     PetscHashIter hashKeyIter, wHashKeyIter;
34715552b385SBrandon     PetscBool     hashKeyFound, wHashKeyFound;
34725552b385SBrandon 
34735552b385SBrandon     if (islite) {
34745552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
34755552b385SBrandon       PetscCallEGADS(EGlite_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
34765552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
34775552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
34785552b385SBrandon       PetscCallEGADS(EGlite_getBodyTopos, (body, face, NODE, &Nv, &vobjs));
34795552b385SBrandon     } else {
34805552b385SBrandon       id = EG_indexBodyTopo(body, face);
34815552b385SBrandon       PetscCallEGADS(EG_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
34825552b385SBrandon       PetscCallEGADS(EG_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
34835552b385SBrandon       PetscCallEGADS(EG_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
34845552b385SBrandon       PetscCallEGADS(EG_getBodyTopos, (body, face, NODE, &Nv, &vobjs));
34855552b385SBrandon     }
34865552b385SBrandon 
34875552b385SBrandon     // Store Face ID to 1st Row of Control Point Vector
34885552b385SBrandon     PetscCall(PetscHMapIFind(faceCntrlPtRow_Start, id, &hashKeyIter, &hashKeyFound));
34895552b385SBrandon 
34905552b385SBrandon     if (!hashKeyFound) PetscCall(PetscHMapISet(faceCntrlPtRow_Start, id, cntr));
34915552b385SBrandon 
34925552b385SBrandon     PetscCall(VecGetArrayWrite(cntrlPtCoordsVec, &cntrlPtCoords));
34935552b385SBrandon     offsetCoord = bpinfo[3] + bpinfo[6];
34945552b385SBrandon     for (int jj = 0; jj < 3 * bpinfo[2] * bpinfo[5]; ++jj) {
34955552b385SBrandon       cntrlPtCoords[cntr] = bprv[offsetCoord + jj];
34965552b385SBrandon       cntr += 1;
34975552b385SBrandon     }
34985552b385SBrandon 
34995552b385SBrandon     // Store Face ID to 1st Row of Control Point Weight Vector
35005552b385SBrandon     PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, id, &wHashKeyIter, &wHashKeyFound));
35015552b385SBrandon 
35025552b385SBrandon     if (!wHashKeyFound) {
35035552b385SBrandon       PetscCall(PetscHMapISet(faceCPWeightsRow_Start, id, wcntr));
35045552b385SBrandon       wRowStart = wcntr;
35055552b385SBrandon     }
35065552b385SBrandon 
35075552b385SBrandon     PetscCall(VecGetArrayWrite(cntrlPtWeightsVec, &cntrlPtWeights));
35085552b385SBrandon     offsetWeight = bpinfo[3] + bpinfo[6] + (3 * bpinfo[2] * bpinfo[5]);
35095552b385SBrandon     for (int jj = 0; jj < bpinfo[2] * bpinfo[5]; ++jj) {
35105552b385SBrandon       cntrlPtWeights[wcntr] = bprv[offsetWeight + jj];
35115552b385SBrandon       cp_face[wcntr]        = id;
35125552b385SBrandon       w_face[wcntr]         = id;
35135552b385SBrandon       wcntr += 1;
35145552b385SBrandon     }
35155552b385SBrandon     PetscCall(VecRestoreArrayWrite(cntrlPtWeightsVec, &cntrlPtWeights));
35165552b385SBrandon 
3517*bfe80ac4SPierre Jolivet     // Associate Control Points with Vertex IDs
35185552b385SBrandon     PetscScalar xcp, ycp, zcp;
35195552b385SBrandon     offsetCoord = bpinfo[3] + bpinfo[6];
35205552b385SBrandon     for (int jj = 0; jj < 3 * bpinfo[2] * bpinfo[5]; jj += 3) {
35215552b385SBrandon       xcp = bprv[offsetCoord + jj + 0];
35225552b385SBrandon       ycp = bprv[offsetCoord + jj + 1];
35235552b385SBrandon       zcp = bprv[offsetCoord + jj + 2];
35245552b385SBrandon 
35255552b385SBrandon       //Initialize Control Point and Weight to Vertex ID relationship to -1
35265552b385SBrandon       cp_vertex[vcntr] = -1;
35275552b385SBrandon       w_vertex[vcntr]  = -1;
35285552b385SBrandon       cp_edge[vcntr]   = -1;
35295552b385SBrandon       w_edge[vcntr]    = -1;
35305552b385SBrandon 
35315552b385SBrandon       for (int kk = 0; kk < Nv; ++kk) {
35325552b385SBrandon         int         vid;
35335552b385SBrandon         double      vCoords[3];
35345552b385SBrandon         PetscScalar vDelta;
35355552b385SBrandon         ego         vertex = vobjs[kk];
35365552b385SBrandon 
35375552b385SBrandon         if (islite) {
35385552b385SBrandon           vid = EGlite_indexBodyTopo(body, vertex);
35395552b385SBrandon           PetscCallEGADS(EGlite_evaluate, (vertex, NULL, vCoords));
35405552b385SBrandon         } else {
35415552b385SBrandon           vid = EG_indexBodyTopo(body, vertex);
35425552b385SBrandon           PetscCallEGADS(EG_evaluate, (vertex, NULL, vCoords));
35435552b385SBrandon         }
35445552b385SBrandon         vDelta = PetscSqrtReal(PetscSqr(vCoords[0] - xcp) + PetscSqr(vCoords[1] - ycp) + PetscSqr(vCoords[2] - zcp));
35455552b385SBrandon 
35465552b385SBrandon         if (vDelta < 1.0E-15) {
35475552b385SBrandon           cp_vertex[vcntr] = vid;
35485552b385SBrandon           w_vertex[vcntr]  = vid;
35495552b385SBrandon         }
35505552b385SBrandon       }
35515552b385SBrandon       vcntr += 1;
35525552b385SBrandon     }
35535552b385SBrandon     // These two line could be replaced with DMPlexFreeGeomObject()
35545552b385SBrandon     if (islite) EGlite_free(vobjs);
35555552b385SBrandon     else EG_free(vobjs);
35565552b385SBrandon 
35575552b385SBrandon     // Associate Control Points with Edge IDs
35585552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, face, EDGE, &Ne, &eobjs));
35595552b385SBrandon     else PetscCallEGADS(EG_getBodyTopos, (body, face, EDGE, &Ne, &eobjs));
35605552b385SBrandon 
35615552b385SBrandon     int cpV1, cpV2;
35625552b385SBrandon     int minID, maxID;
35635552b385SBrandon 
35645552b385SBrandon     // Along vmin axis
35655552b385SBrandon     minID = wRowStart;
35665552b385SBrandon     maxID = wRowStart + (bpinfo[2] - 1);
35675552b385SBrandon     cpV1  = cp_vertex[minID];
35685552b385SBrandon     cpV2  = cp_vertex[maxID];
35695552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
35705552b385SBrandon       ego edge = eobjs[jj];
35715552b385SBrandon       ego egeom, *nobjs;
35725552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
35735552b385SBrandon       int n1ID, n2ID, eid;
35745552b385SBrandon 
35755552b385SBrandon       if (islite) {
35765552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
35775552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
35785552b385SBrandon       } else {
35795552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
35805552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
35815552b385SBrandon       }
35825552b385SBrandon 
35835552b385SBrandon       if (emtype != DEGENERATE) {
35845552b385SBrandon         // Get IDs for current Edge's End Vertices
35855552b385SBrandon         if (islite) {
35865552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
35875552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
35885552b385SBrandon         } else {
35895552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
35905552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
35915552b385SBrandon         }
35925552b385SBrandon 
35935552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
35945552b385SBrandon           for (int kk = minID + 1; kk < maxID; ++kk) {
35955552b385SBrandon             cp_edge[kk] = eid;
35965552b385SBrandon             w_edge[kk]  = eid;
35975552b385SBrandon           }
35985552b385SBrandon         }
35995552b385SBrandon       }
36005552b385SBrandon     }
36015552b385SBrandon 
36025552b385SBrandon     // Along vmax axis
36035552b385SBrandon     minID = wRowStart + (bpinfo[2] * (bpinfo[5] - 1));
36045552b385SBrandon     maxID = wRowStart + (bpinfo[2] * bpinfo[5] - 1);
36055552b385SBrandon 
36065552b385SBrandon     cpV1 = cp_vertex[minID];
36075552b385SBrandon     cpV2 = cp_vertex[maxID];
36085552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
36095552b385SBrandon       ego edge = eobjs[jj];
36105552b385SBrandon       ego egeom, *nobjs;
36115552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
36125552b385SBrandon       int n1ID, n2ID, eid;
36135552b385SBrandon 
36145552b385SBrandon       if (islite) {
36155552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
36165552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36175552b385SBrandon       } else {
36185552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
36195552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36205552b385SBrandon       }
36215552b385SBrandon 
36225552b385SBrandon       if (emtype != DEGENERATE) {
36235552b385SBrandon         // Get IDs for current Edge's End Vertices
36245552b385SBrandon         if (islite) {
36255552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
36265552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
36275552b385SBrandon         } else {
36285552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
36295552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
36305552b385SBrandon         }
36315552b385SBrandon 
36325552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
36335552b385SBrandon           for (int kk = minID + 1; kk < maxID - 1; ++kk) {
36345552b385SBrandon             cp_edge[kk] = eid;
36355552b385SBrandon             w_edge[kk]  = eid;
36365552b385SBrandon           }
36375552b385SBrandon         }
36385552b385SBrandon       }
36395552b385SBrandon     }
36405552b385SBrandon 
36415552b385SBrandon     // Along umin axis
36425552b385SBrandon     minID = wRowStart;
36435552b385SBrandon     maxID = wRowStart + (bpinfo[2] * (bpinfo[5] - 1));
36445552b385SBrandon 
36455552b385SBrandon     cpV1 = cp_vertex[minID];
36465552b385SBrandon     cpV2 = cp_vertex[maxID];
36475552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
36485552b385SBrandon       ego edge = eobjs[jj];
36495552b385SBrandon       ego egeom, *nobjs;
36505552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
36515552b385SBrandon       int n1ID, n2ID, eid;
36525552b385SBrandon 
36535552b385SBrandon       if (islite) {
36545552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
36555552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36565552b385SBrandon       } else {
36575552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
36585552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36595552b385SBrandon       }
36605552b385SBrandon 
36615552b385SBrandon       if (emtype != DEGENERATE) {
36625552b385SBrandon         // Get IDs for current Edge's End Vertices
36635552b385SBrandon         if (islite) {
36645552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
36655552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
36665552b385SBrandon         } else {
36675552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
36685552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
36695552b385SBrandon         }
36705552b385SBrandon 
36715552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
36725552b385SBrandon           for (int kk = minID + bpinfo[2]; kk < maxID; kk += bpinfo[2]) {
36735552b385SBrandon             cp_edge[kk] = eid;
36745552b385SBrandon             w_edge[kk]  = eid;
36755552b385SBrandon           }
36765552b385SBrandon         }
36775552b385SBrandon       }
36785552b385SBrandon     }
36795552b385SBrandon 
36805552b385SBrandon     // Along umax axis
36815552b385SBrandon     minID = wRowStart + (bpinfo[2] - 1);
36825552b385SBrandon     maxID = wRowStart + (bpinfo[2] * bpinfo[5]) - 1;
36835552b385SBrandon     cpV1  = cp_vertex[minID];
36845552b385SBrandon     cpV2  = cp_vertex[maxID];
36855552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
36865552b385SBrandon       ego edge = eobjs[jj];
36875552b385SBrandon       ego egeom, *nobjs;
36885552b385SBrandon       int eoclass, emtype, Nn, *nsenses;
36895552b385SBrandon       int n1ID, n2ID, eid;
36905552b385SBrandon 
36915552b385SBrandon       if (islite) {
36925552b385SBrandon         eid = EGlite_indexBodyTopo(body, edge);
36935552b385SBrandon         PetscCallEGADS(EGlite_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36945552b385SBrandon       } else {
36955552b385SBrandon         eid = EG_indexBodyTopo(body, edge);
36965552b385SBrandon         PetscCallEGADS(EG_getTopology, (edge, &egeom, &eoclass, &emtype, NULL, &Nn, &nobjs, &nsenses));
36975552b385SBrandon       }
36985552b385SBrandon 
36995552b385SBrandon       if (emtype != DEGENERATE) {
37005552b385SBrandon         // Get IDs for current Edge's End Vertices
37015552b385SBrandon         if (islite) {
37025552b385SBrandon           n1ID = EGlite_indexBodyTopo(body, nobjs[0]);
37035552b385SBrandon           n2ID = EGlite_indexBodyTopo(body, nobjs[1]);
37045552b385SBrandon         } else {
37055552b385SBrandon           n1ID = EG_indexBodyTopo(body, nobjs[0]);
37065552b385SBrandon           n2ID = EG_indexBodyTopo(body, nobjs[1]);
37075552b385SBrandon         }
37085552b385SBrandon 
37095552b385SBrandon         if ((cpV1 == n1ID || cpV1 == n2ID) && (cpV2 == n1ID || cpV2 == n2ID)) {
37105552b385SBrandon           for (int kk = minID + bpinfo[2]; kk < maxID; kk += bpinfo[2]) {
37115552b385SBrandon             cp_edge[kk] = eid;
37125552b385SBrandon             w_edge[kk]  = eid;
37135552b385SBrandon           }
37145552b385SBrandon         }
37155552b385SBrandon       }
37165552b385SBrandon     }
37175552b385SBrandon     // These two lines could be replaced with DMPlexFreeGeomObject()
37185552b385SBrandon     if (islite) EGlite_free(eobjs);
37195552b385SBrandon     else EG_free(eobjs);
37205552b385SBrandon   }
37215552b385SBrandon 
3722*bfe80ac4SPierre Jolivet   // Determine Control Point Equivalence Matrix relating Control Points between Surfaces
37235552b385SBrandon   //     Note: The Weights will also be tied together in the same manner
37245552b385SBrandon   //           Also can use the Weight Hash Table for Row Start ID of each Face
37255552b385SBrandon   const PetscInt cpRowSize = totalNumCPs;
37265552b385SBrandon   const PetscInt cpColSize = cpRowSize;
37275552b385SBrandon   PetscInt      *maxNumRelatePtr;
37285552b385SBrandon   PetscInt       maxNumRelate = 0;
37295552b385SBrandon 
37305552b385SBrandon   // Create Point Surface Gradient Matrix
37315552b385SBrandon   PetscCall(MatCreate(PETSC_COMM_WORLD, &cpEquiv));
37325552b385SBrandon   PetscCall(MatSetSizes(cpEquiv, PETSC_DECIDE, PETSC_DECIDE, cpRowSize, cpColSize));
37335552b385SBrandon   PetscCall(MatSetType(cpEquiv, MATAIJ));
37345552b385SBrandon   PetscCall(MatSetUp(cpEquiv));
37355552b385SBrandon 
37365552b385SBrandon   for (int ii = 0; ii < totalNumCPs; ++ii) {
37375552b385SBrandon     PetscScalar x1, y1, z1;
37385552b385SBrandon     PetscInt    maxRelateTemp = 0;
37395552b385SBrandon 
37405552b385SBrandon     x1 = cntrlPtCoords[(3 * ii) + 0];
37415552b385SBrandon     y1 = cntrlPtCoords[(3 * ii) + 1];
37425552b385SBrandon     z1 = cntrlPtCoords[(3 * ii) + 2];
37435552b385SBrandon 
37445552b385SBrandon     for (int jj = 0; jj < totalNumCPs; ++jj) {
37455552b385SBrandon       PetscScalar x2, y2, z2;
37465552b385SBrandon       PetscScalar cpDelta, eqFactor;
37475552b385SBrandon       x2 = cntrlPtCoords[(3 * jj) + 0];
37485552b385SBrandon       y2 = cntrlPtCoords[(3 * jj) + 1];
37495552b385SBrandon       z2 = cntrlPtCoords[(3 * jj) + 2];
37505552b385SBrandon 
37515552b385SBrandon       cpDelta = PetscSqrtReal(PetscSqr(x2 - x1) + PetscSqr(y2 - y1) + PetscSqr(z2 - z1));
37525552b385SBrandon       if (cpDelta < 1.0E-15) {
37535552b385SBrandon         eqFactor = 1.0;
37545552b385SBrandon         maxRelateTemp += 1;
37555552b385SBrandon       } else {
37565552b385SBrandon         eqFactor = 0.0;
37575552b385SBrandon       }
37585552b385SBrandon 
37595552b385SBrandon       // Store Results in Petsc Matrix
37605552b385SBrandon       PetscCall(MatSetValue(cpEquiv, ii, jj, eqFactor, INSERT_VALUES));
37615552b385SBrandon     }
37625552b385SBrandon     if (maxRelateTemp > maxNumRelate) maxNumRelate = maxRelateTemp;
37635552b385SBrandon   }
37645552b385SBrandon   maxNumRelatePtr = &maxNumRelate;
37655552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtCoordsVec, &cntrlPtCoords));
37665552b385SBrandon 
37675552b385SBrandon   // Assemble Point Surface Grad Matrix
37685552b385SBrandon   PetscCall(MatAssemblyBegin(cpEquiv, MAT_FINAL_ASSEMBLY));
37695552b385SBrandon   PetscCall(MatAssemblyEnd(cpEquiv, MAT_FINAL_ASSEMBLY));
37705552b385SBrandon 
37715552b385SBrandon   // Attach Control Point and Weight Data to DM
37725552b385SBrandon   {
37735552b385SBrandon     PetscContainer cpOrgObj, cpCoordLengthObj;
37745552b385SBrandon     PetscContainer wOrgObj, wDataLengthObj;
37755552b385SBrandon     PetscContainer cp_faceObj, cp_edgeObj, cp_vertexObj;
37765552b385SBrandon     PetscContainer w_faceObj, w_edgeObj, w_vertexObj;
37775552b385SBrandon     PetscContainer maxNumRelateObj;
37785552b385SBrandon 
37795552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Hash Table", (PetscObject *)&cpOrgObj));
37805552b385SBrandon     if (!cpOrgObj) {
37815552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpOrgObj));
37825552b385SBrandon       PetscCall(PetscContainerSetPointer(cpOrgObj, faceCntrlPtRow_Start));
37835552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Hash Table", (PetscObject)cpOrgObj));
37845552b385SBrandon       PetscCall(PetscContainerDestroy(&cpOrgObj));
37855552b385SBrandon     } else {
37865552b385SBrandon       PetscCall(PetscContainerSetPointer(cpOrgObj, faceCntrlPtRow_Start));
37875552b385SBrandon     }
37885552b385SBrandon 
37895552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinates", (PetscObject)cntrlPtCoordsVec));
37905552b385SBrandon     PetscCall(VecDestroy(&cntrlPtCoordsVec));
37915552b385SBrandon 
37925552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject *)&cpCoordLengthObj));
37935552b385SBrandon     if (!cpCoordLengthObj) {
37945552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cpCoordLengthObj));
37955552b385SBrandon       PetscCall(PetscContainerSetPointer(cpCoordLengthObj, cpCoordDataLengthPtr));
37965552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject)cpCoordLengthObj));
37975552b385SBrandon       PetscCall(PetscContainerDestroy(&cpCoordLengthObj));
37985552b385SBrandon     } else {
37995552b385SBrandon       PetscCall(PetscContainerSetPointer(cpCoordLengthObj, cpCoordDataLengthPtr));
38005552b385SBrandon     }
38015552b385SBrandon 
38025552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject *)&wOrgObj));
38035552b385SBrandon     if (!wOrgObj) {
38045552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wOrgObj));
38055552b385SBrandon       PetscCall(PetscContainerSetPointer(wOrgObj, faceCPWeightsRow_Start));
38065552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject)wOrgObj));
38075552b385SBrandon       PetscCall(PetscContainerDestroy(&wOrgObj));
38085552b385SBrandon     } else {
38095552b385SBrandon       PetscCall(PetscContainerSetPointer(wOrgObj, faceCPWeightsRow_Start));
38105552b385SBrandon     }
38115552b385SBrandon 
38125552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data", (PetscObject)cntrlPtWeightsVec));
38135552b385SBrandon     PetscCall(VecDestroy(&cntrlPtWeightsVec));
38145552b385SBrandon 
38155552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&wDataLengthObj));
38165552b385SBrandon     if (!wDataLengthObj) {
38175552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &wDataLengthObj));
38185552b385SBrandon       PetscCall(PetscContainerSetPointer(wDataLengthObj, wDataLengthPtr));
38195552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight Data Length", (PetscObject)wDataLengthObj));
38205552b385SBrandon       PetscCall(PetscContainerDestroy(&wDataLengthObj));
38215552b385SBrandon     } else {
38225552b385SBrandon       PetscCall(PetscContainerSetPointer(wDataLengthObj, wDataLengthPtr));
38235552b385SBrandon     }
38245552b385SBrandon 
3825*bfe80ac4SPierre Jolivet     PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Equivalency Matrix", (PetscObject)cpEquiv));
38265552b385SBrandon 
38275552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Maximum Number Control Point Equivalency", (PetscObject *)&maxNumRelateObj));
38285552b385SBrandon     if (!maxNumRelateObj) {
38295552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &maxNumRelateObj));
38305552b385SBrandon       PetscCall(PetscContainerSetPointer(maxNumRelateObj, maxNumRelatePtr));
38315552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Maximum Number Control Point Equivalency", (PetscObject)maxNumRelateObj));
38325552b385SBrandon       PetscCall(PetscContainerDestroy(&maxNumRelateObj));
38335552b385SBrandon     } else {
38345552b385SBrandon       PetscCall(PetscContainerSetPointer(maxNumRelateObj, maxNumRelatePtr));
38355552b385SBrandon     }
38365552b385SBrandon 
38375552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Face Map", (PetscObject *)&cp_faceObj));
38385552b385SBrandon     if (!cp_faceObj) {
38395552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cp_faceObj));
38405552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_faceObj, cp_face));
38415552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(cp_faceObj, PetscCtxDestroyDefault));
38425552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point - Face Map", (PetscObject)cp_faceObj));
38435552b385SBrandon       PetscCall(PetscContainerDestroy(&cp_faceObj));
38445552b385SBrandon     } else {
38455552b385SBrandon       void *tmp;
38465552b385SBrandon 
38475552b385SBrandon       PetscCall(PetscContainerGetPointer(cp_faceObj, &tmp));
38485552b385SBrandon       PetscCall(PetscFree(tmp));
38495552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_faceObj, cp_face));
38505552b385SBrandon     }
38515552b385SBrandon 
38525552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Face Map", (PetscObject *)&w_faceObj));
38535552b385SBrandon     if (!w_faceObj) {
38545552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &w_faceObj));
38555552b385SBrandon       PetscCall(PetscContainerSetPointer(w_faceObj, w_face));
38565552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(w_faceObj, PetscCtxDestroyDefault));
38575552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight - Face Map", (PetscObject)w_faceObj));
38585552b385SBrandon       PetscCall(PetscContainerDestroy(&w_faceObj));
38595552b385SBrandon     } else {
38605552b385SBrandon       void *tmp;
38615552b385SBrandon 
38625552b385SBrandon       PetscCall(PetscContainerGetPointer(w_faceObj, &tmp));
38635552b385SBrandon       PetscCall(PetscFree(tmp));
38645552b385SBrandon       PetscCall(PetscContainerSetPointer(w_faceObj, w_face));
38655552b385SBrandon     }
38665552b385SBrandon 
38675552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Edge Map", (PetscObject *)&cp_edgeObj));
38685552b385SBrandon     if (!cp_edgeObj) {
38695552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cp_edgeObj));
38705552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_edgeObj, cp_edge));
38715552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(cp_edgeObj, PetscCtxDestroyDefault));
38725552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point - Edge Map", (PetscObject)cp_edgeObj));
38735552b385SBrandon       PetscCall(PetscContainerDestroy(&cp_edgeObj));
38745552b385SBrandon     } else {
38755552b385SBrandon       void *tmp;
38765552b385SBrandon 
38775552b385SBrandon       PetscCall(PetscContainerGetPointer(cp_edgeObj, &tmp));
38785552b385SBrandon       PetscCall(PetscFree(tmp));
38795552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_edgeObj, cp_edge));
38805552b385SBrandon     }
38815552b385SBrandon 
38825552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Edge Map", (PetscObject *)&w_edgeObj));
38835552b385SBrandon     if (!w_edgeObj) {
38845552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &w_edgeObj));
38855552b385SBrandon       PetscCall(PetscContainerSetPointer(w_edgeObj, w_edge));
38865552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(w_edgeObj, PetscCtxDestroyDefault));
38875552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight - Edge Map", (PetscObject)w_edgeObj));
38885552b385SBrandon       PetscCall(PetscContainerDestroy(&w_edgeObj));
38895552b385SBrandon     } else {
38905552b385SBrandon       void *tmp;
38915552b385SBrandon 
38925552b385SBrandon       PetscCall(PetscContainerGetPointer(w_edgeObj, &tmp));
38935552b385SBrandon       PetscCall(PetscFree(tmp));
38945552b385SBrandon       PetscCall(PetscContainerSetPointer(w_edgeObj, w_edge));
38955552b385SBrandon     }
38965552b385SBrandon 
38975552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Vertex Map", (PetscObject *)&cp_vertexObj));
38985552b385SBrandon     if (!cp_vertexObj) {
38995552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &cp_vertexObj));
39005552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_vertexObj, cp_vertex));
39015552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(cp_vertexObj, PetscCtxDestroyDefault));
39025552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point - Vertex Map", (PetscObject)cp_vertexObj));
39035552b385SBrandon       PetscCall(PetscContainerDestroy(&cp_vertexObj));
39045552b385SBrandon     } else {
39055552b385SBrandon       void *tmp;
39065552b385SBrandon 
39075552b385SBrandon       PetscCall(PetscContainerGetPointer(cp_vertexObj, &tmp));
39085552b385SBrandon       PetscCall(PetscFree(tmp));
39095552b385SBrandon       PetscCall(PetscContainerSetPointer(cp_vertexObj, cp_vertex));
39105552b385SBrandon     }
39115552b385SBrandon 
39125552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Vertex Map", (PetscObject *)&w_vertexObj));
39135552b385SBrandon     if (!w_vertexObj) {
39145552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &w_vertexObj));
39155552b385SBrandon       PetscCall(PetscContainerSetPointer(w_vertexObj, w_vertex));
39165552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(w_vertexObj, PetscCtxDestroyDefault));
39175552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Control Point Weight - Vertex Map", (PetscObject)w_vertexObj));
39185552b385SBrandon       PetscCall(PetscContainerDestroy(&w_vertexObj));
39195552b385SBrandon     } else {
39205552b385SBrandon       void *tmp;
39215552b385SBrandon 
39225552b385SBrandon       PetscCall(PetscContainerGetPointer(w_vertexObj, &tmp));
39235552b385SBrandon       PetscCall(PetscFree(tmp));
39245552b385SBrandon       PetscCall(PetscContainerSetPointer(w_vertexObj, w_vertex));
39255552b385SBrandon     }
39265552b385SBrandon   }
39275552b385SBrandon 
39285552b385SBrandon   // Define Matrix to store  Geometry Gradient information dGeom_i/dCPj_i
39295552b385SBrandon   PetscInt       gcntr   = 0;
39305552b385SBrandon   const PetscInt rowSize = 3 * maxNumCPs * totalNumPoints;
39315552b385SBrandon   const PetscInt colSize = 4 * Nf;
39325552b385SBrandon 
39335552b385SBrandon   // Create Point Surface Gradient Matrix
39345552b385SBrandon   PetscCall(MatCreate(PETSC_COMM_WORLD, &pointSurfGrad));
39355552b385SBrandon   PetscCall(MatSetSizes(pointSurfGrad, PETSC_DECIDE, PETSC_DECIDE, rowSize, colSize));
39365552b385SBrandon   PetscCall(MatSetType(pointSurfGrad, MATAIJ));
39375552b385SBrandon   PetscCall(MatSetUp(pointSurfGrad));
39385552b385SBrandon 
39395552b385SBrandon   // Create Hash Table to store Point's stare row in surfaceGrad[][]
39405552b385SBrandon   PetscCall(PetscHMapICreate(&pointSurfGradRow_Start));
39415552b385SBrandon 
39425552b385SBrandon   // Get Coordinates for the DMPlex point
39435552b385SBrandon   DM           cdm;
39445552b385SBrandon   PetscInt     dE, Nv;
39455552b385SBrandon   Vec          coordinatesLocal;
39465552b385SBrandon   PetscScalar *coords = NULL;
39475552b385SBrandon 
39485552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
39495552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &dE));
39505552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
39515552b385SBrandon 
39525552b385SBrandon   // CYCLE THROUGH FACEs
39535552b385SBrandon   PetscScalar maxGrad = 0.;
39545552b385SBrandon   PetscCall(VecGetArrayWrite(gradSACPVec, &gradSACP));
39555552b385SBrandon   PetscCall(VecGetArrayWrite(gradSAWVec, &gradSAW));
39565552b385SBrandon   PetscCall(VecGetArrayWrite(gradVCPVec, &gradVCP));
39575552b385SBrandon   PetscCall(VecGetArrayWrite(gradVWVec, &gradVW));
39585552b385SBrandon   for (int f = 0; f < Nf; ++f) {
39595552b385SBrandon     ego             face = fobjs[f];
39605552b385SBrandon     ego            *eobjs, *nobjs;
39615552b385SBrandon     PetscInt        fid, Ne, Nn;
39625552b385SBrandon     DMLabel         faceLabel, edgeLabel, nodeLabel;
39635552b385SBrandon     PetscHMapI      currFaceUniquePoints = NULL;
39645552b385SBrandon     IS              facePoints, edgePoints, nodePoints;
39655552b385SBrandon     const PetscInt *fIndices, *eIndices, *nIndices;
39665552b385SBrandon     PetscInt        fSize, eSize, nSize;
39675552b385SBrandon     PetscHashIter   fHashKeyIter, eHashKeyIter, nHashKeyIter, pHashKeyIter;
39685552b385SBrandon     PetscBool       fHashKeyFound, eHashKeyFound, nHashKeyFound, pHashKeyFound;
39695552b385SBrandon     PetscInt        cfCntr = 0;
39705552b385SBrandon 
39715552b385SBrandon     // Get Geometry Object for the Current FACE
39725552b385SBrandon     if (islite) {
39735552b385SBrandon       PetscCall(EGlite_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
39745552b385SBrandon       PetscCall(EGlite_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
39755552b385SBrandon     } else {
39765552b385SBrandon       PetscCall(EG_getTopology(face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
39775552b385SBrandon       PetscCall(EG_getGeometry(fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
39785552b385SBrandon     }
39795552b385SBrandon 
39805552b385SBrandon     // Get all EDGE and NODE objects attached to the current FACE
39815552b385SBrandon     if (islite) {
39825552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
39835552b385SBrandon       PetscCall(EGlite_getBodyTopos(body, face, NODE, &Nn, &nobjs));
39845552b385SBrandon     } else {
39855552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, EDGE, &Ne, &eobjs));
39865552b385SBrandon       PetscCall(EG_getBodyTopos(body, face, NODE, &Nn, &nobjs));
39875552b385SBrandon     }
39885552b385SBrandon 
39895552b385SBrandon     // Get all DMPlex Points that have DMLabel "EGADS Face ID" and store them in a Hash Table for later use
39905552b385SBrandon     if (islite) {
39915552b385SBrandon       fid = EGlite_indexBodyTopo(body, face);
39925552b385SBrandon     } else {
39935552b385SBrandon       fid = EG_indexBodyTopo(body, face);
39945552b385SBrandon     }
39955552b385SBrandon 
39965552b385SBrandon     PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
39975552b385SBrandon     PetscCall(DMLabelGetStratumIS(faceLabel, fid, &facePoints));
39985552b385SBrandon     PetscCall(ISGetIndices(facePoints, &fIndices));
39995552b385SBrandon     PetscCall(ISGetSize(facePoints, &fSize));
40005552b385SBrandon 
40015552b385SBrandon     PetscCall(PetscHMapICreate(&currFaceUniquePoints));
40025552b385SBrandon 
40035552b385SBrandon     for (int jj = 0; jj < fSize; ++jj) {
40045552b385SBrandon       PetscCall(PetscHMapIFind(currFaceUniquePoints, fIndices[jj], &fHashKeyIter, &fHashKeyFound));
40055552b385SBrandon 
40065552b385SBrandon       if (!fHashKeyFound) {
40075552b385SBrandon         PetscCall(PetscHMapISet(currFaceUniquePoints, fIndices[jj], cfCntr));
40085552b385SBrandon         cfCntr += 1;
40095552b385SBrandon       }
40105552b385SBrandon 
40115552b385SBrandon       PetscCall(PetscHMapIFind(pointSurfGradRow_Start, fIndices[jj], &pHashKeyIter, &pHashKeyFound));
40125552b385SBrandon 
40135552b385SBrandon       if (!pHashKeyFound) {
40145552b385SBrandon         PetscCall(PetscHMapISet(pointSurfGradRow_Start, fIndices[jj], gcntr));
40155552b385SBrandon         gcntr += 3 * maxNumCPs;
40165552b385SBrandon       }
40175552b385SBrandon     }
40185552b385SBrandon     PetscCall(ISRestoreIndices(facePoints, &fIndices));
40195552b385SBrandon     PetscCall(ISDestroy(&facePoints));
40205552b385SBrandon 
40215552b385SBrandon     // Get all DMPlex Points that have DMLable "EGADS Edge ID" attached to the current FACE and store them in a Hash Table for later use.
40225552b385SBrandon     for (int jj = 0; jj < Ne; ++jj) {
40235552b385SBrandon       ego       edge = eobjs[jj];
40245552b385SBrandon       PetscBool containLabelValue;
40255552b385SBrandon 
40265552b385SBrandon       if (islite) {
40275552b385SBrandon         id = EGlite_indexBodyTopo(body, edge);
40285552b385SBrandon       } else {
40295552b385SBrandon         id = EG_indexBodyTopo(body, edge);
40305552b385SBrandon       }
40315552b385SBrandon 
40325552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
40335552b385SBrandon       PetscCall(DMLabelHasValue(edgeLabel, id, &containLabelValue));
40345552b385SBrandon 
40355552b385SBrandon       if (containLabelValue) {
40365552b385SBrandon         PetscCall(DMLabelGetStratumIS(edgeLabel, id, &edgePoints));
40375552b385SBrandon         PetscCall(ISGetIndices(edgePoints, &eIndices));
40385552b385SBrandon         PetscCall(ISGetSize(edgePoints, &eSize));
40395552b385SBrandon 
40405552b385SBrandon         for (int kk = 0; kk < eSize; ++kk) {
40415552b385SBrandon           PetscCall(PetscHMapIFind(currFaceUniquePoints, eIndices[kk], &eHashKeyIter, &eHashKeyFound));
40425552b385SBrandon 
40435552b385SBrandon           if (!eHashKeyFound) {
40445552b385SBrandon             PetscCall(PetscHMapISet(currFaceUniquePoints, eIndices[kk], cfCntr));
40455552b385SBrandon             cfCntr += 1;
40465552b385SBrandon           }
40475552b385SBrandon 
40485552b385SBrandon           PetscCall(PetscHMapIFind(pointSurfGradRow_Start, eIndices[kk], &pHashKeyIter, &pHashKeyFound));
40495552b385SBrandon 
40505552b385SBrandon           if (!pHashKeyFound) {
40515552b385SBrandon             PetscCall(PetscHMapISet(pointSurfGradRow_Start, eIndices[kk], gcntr));
40525552b385SBrandon             gcntr += 3 * maxNumCPs;
40535552b385SBrandon           }
40545552b385SBrandon         }
40555552b385SBrandon         PetscCall(ISRestoreIndices(edgePoints, &eIndices));
40565552b385SBrandon         PetscCall(ISDestroy(&edgePoints));
40575552b385SBrandon       }
40585552b385SBrandon     }
40595552b385SBrandon 
40605552b385SBrandon     // Get all DMPlex Points that have DMLabel "EGADS Vertex ID" attached to the current FACE and store them in a Hash Table for later use.
40615552b385SBrandon     for (int jj = 0; jj < Nn; ++jj) {
40625552b385SBrandon       ego node = nobjs[jj];
40635552b385SBrandon 
40645552b385SBrandon       if (islite) {
40655552b385SBrandon         id = EGlite_indexBodyTopo(body, node);
40665552b385SBrandon       } else {
40675552b385SBrandon         id = EG_indexBodyTopo(body, node);
40685552b385SBrandon       }
40695552b385SBrandon 
40705552b385SBrandon       PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &nodeLabel));
40715552b385SBrandon       PetscCall(DMLabelGetStratumIS(nodeLabel, id, &nodePoints));
40725552b385SBrandon       PetscCall(ISGetIndices(nodePoints, &nIndices));
40735552b385SBrandon       PetscCall(ISGetSize(nodePoints, &nSize));
40745552b385SBrandon 
40755552b385SBrandon       for (int kk = 0; kk < nSize; ++kk) {
40765552b385SBrandon         PetscCall(PetscHMapIFind(currFaceUniquePoints, nIndices[kk], &nHashKeyIter, &nHashKeyFound));
40775552b385SBrandon 
40785552b385SBrandon         if (!nHashKeyFound) {
40795552b385SBrandon           PetscCall(PetscHMapISet(currFaceUniquePoints, nIndices[kk], cfCntr));
40805552b385SBrandon           cfCntr += 1;
40815552b385SBrandon         }
40825552b385SBrandon 
40835552b385SBrandon         PetscCall(PetscHMapIFind(pointSurfGradRow_Start, nIndices[kk], &pHashKeyIter, &pHashKeyFound));
40845552b385SBrandon         if (!pHashKeyFound) {
40855552b385SBrandon           PetscCall(PetscHMapISet(pointSurfGradRow_Start, nIndices[kk], gcntr));
40865552b385SBrandon           gcntr += 3 * maxNumCPs;
40875552b385SBrandon         }
40885552b385SBrandon       }
40895552b385SBrandon       PetscCall(ISRestoreIndices(nodePoints, &nIndices));
40905552b385SBrandon       PetscCall(ISDestroy(&nodePoints));
40915552b385SBrandon     }
40925552b385SBrandon 
40935552b385SBrandon     // Get the Total Number of entries in the Hash Table
40945552b385SBrandon     PetscInt currFaceUPSize;
40955552b385SBrandon     PetscCall(PetscHMapIGetSize(currFaceUniquePoints, &currFaceUPSize));
40965552b385SBrandon 
40975552b385SBrandon     // Get Keys
40985552b385SBrandon     PetscInt currFaceUPKeys[currFaceUPSize], off = 0;
40995552b385SBrandon     PetscCall(PetscHMapIGetKeys(currFaceUniquePoints, &off, currFaceUPKeys));
41005552b385SBrandon     PetscCall(PetscHMapIDestroy(&currFaceUniquePoints));
41015552b385SBrandon 
41025552b385SBrandon     // Get Current Face Surface Area
41035552b385SBrandon     PetscScalar fSA, faceData[14];
41045552b385SBrandon     PetscCall(EG_getMassProperties(face, faceData)); // This doesn't have a EGlite version. Will it work for EGADSlite files??  KNOWN_ISSUE
41055552b385SBrandon     fSA = faceData[1];
41065552b385SBrandon 
41075552b385SBrandon     // Get Start Row in cpEquiv Matrix
41085552b385SBrandon     PetscHashIter Witer;
41095552b385SBrandon     PetscBool     Wfound;
41105552b385SBrandon     PetscInt      faceWStartRow;
41115552b385SBrandon     PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, fid, &Witer, &Wfound));
41125552b385SBrandon     PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Weights Hash Table");
41135552b385SBrandon     PetscCall(PetscHMapIGet(faceCPWeightsRow_Start, fid, &faceWStartRow));
41145552b385SBrandon 
41155552b385SBrandon     // Cycle through all points on the current FACE
41165552b385SBrandon     for (int jj = 0; jj < currFaceUPSize; ++jj) {
41175552b385SBrandon       PetscInt currPointID = currFaceUPKeys[jj];
41185552b385SBrandon       PetscCall(DMPlexVecGetClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
41195552b385SBrandon 
41205552b385SBrandon       // Get UV position of FACE
41215552b385SBrandon       double params[2], range[4], eval[18];
41225552b385SBrandon       int    peri;
41235552b385SBrandon 
41245552b385SBrandon       if (islite) PetscCall(EGlite_getRange(face, range, &peri));
41255552b385SBrandon       else PetscCall(EG_getRange(face, range, &peri));
41265552b385SBrandon 
41275552b385SBrandon       PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, face, range, 0, dE, params, islite));
41285552b385SBrandon 
41295552b385SBrandon       if (islite) PetscCall(EGlite_evaluate(face, params, eval));
41305552b385SBrandon       else PetscCall(EG_evaluate(face, params, eval));
41315552b385SBrandon 
41325552b385SBrandon       // Make a new SURFACE Geometry by changing the location of the Control Points
41335552b385SBrandon       int    prvSize = bpinfo[3] + bpinfo[6] + (4 * bpinfo[2] * bpinfo[5]);
41345552b385SBrandon       double nbprv[prvSize];
41355552b385SBrandon 
41365552b385SBrandon       // Cycle through each Control Point
41375552b385SBrandon       double denomNew, denomOld;
41385552b385SBrandon       double deltaCoord = 1.0E-4;
41395552b385SBrandon       int    offset     = bpinfo[3] + bpinfo[6];
41405552b385SBrandon       int    wOffset    = offset + (3 * bpinfo[2] * bpinfo[5]);
41415552b385SBrandon       for (int ii = 0; ii < bpinfo[2] * bpinfo[5]; ++ii) {
41425552b385SBrandon         PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d", f, jj, ii);
41435552b385SBrandon   #if 0
41445552b385SBrandon         // Cycle through each direction (x, then y, then z)
41455552b385SBrandon         if (jj == 0) {
41465552b385SBrandon           // Get the Number Control Points that are the same as the current points
41475552b385SBrandon           //    We are looking for repeated Control Points
41485552b385SBrandon           PetscInt commonCPcntr = 0;
41495552b385SBrandon           for (int mm = 0; mm < bpinfo[2]*bpinfo[5]; ++mm) {
41505552b385SBrandon             PetscScalar matValue;
41515552b385SBrandon             PetscCall(MatGetValue(cpEquiv, faceWStartRow + ii, faceWStartRow + mm, &matValue));
41525552b385SBrandon 
41535552b385SBrandon             if (matValue > 0.0) commonCPcntr += 1;
41545552b385SBrandon           }
41555552b385SBrandon         }
41565552b385SBrandon   #endif
41575552b385SBrandon 
41585552b385SBrandon         for (int kk = 0; kk < 4; ++kk) {
41595552b385SBrandon           // Reinitialize nbprv[] values because we only want to change one value at a time
41605552b385SBrandon           for (int mm = 0; mm < prvSize; ++mm) { nbprv[mm] = bprv[mm]; }
41615552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
41625552b385SBrandon 
41635552b385SBrandon           if (kk == 0) { //X
41645552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0] + deltaCoord;
41655552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
41665552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
41675552b385SBrandon             denomNew          = nbprv[offset + 0];
41685552b385SBrandon             denomOld          = bprv[offset + 0];
41695552b385SBrandon           } else if (kk == 1) { //Y
41705552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
41715552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1] + deltaCoord;
41725552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2];
41735552b385SBrandon             denomNew          = nbprv[offset + 1];
41745552b385SBrandon             denomOld          = bprv[offset + 1];
41755552b385SBrandon           } else if (kk == 2) { //Z
41765552b385SBrandon             nbprv[offset + 0] = bprv[offset + 0];
41775552b385SBrandon             nbprv[offset + 1] = bprv[offset + 1];
41785552b385SBrandon             nbprv[offset + 2] = bprv[offset + 2] + deltaCoord;
41795552b385SBrandon             denomNew          = nbprv[offset + 2];
41805552b385SBrandon             denomOld          = bprv[offset + 2];
41815552b385SBrandon           } else if (kk == 3) { // Weights
41825552b385SBrandon             nbprv[wOffset + ii] = bprv[wOffset + ii] + deltaCoord;
41835552b385SBrandon             denomNew            = nbprv[wOffset + ii];
41845552b385SBrandon             denomOld            = bprv[wOffset + ii];
41855552b385SBrandon           } else {
41865552b385SBrandon             // currently do nothing
41875552b385SBrandon           }
41885552b385SBrandon 
41895552b385SBrandon           // Create New Surface Based on New Control Points or Weights
41905552b385SBrandon           ego newgeom, context;
41915552b385SBrandon           PetscCallEGADS(EG_getContext, (face, &context));                                             // This does not have an EGlite_ version KNOWN_ISSUE
41925552b385SBrandon           PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, nbprv, &newgeom)); // This does not have an EGlite_ version KNOWN_ISSUE
41935552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
41945552b385SBrandon 
41955552b385SBrandon           // Evaluate new (x, y, z) Point Position based on new Surface Definition
41965552b385SBrandon           double newCoords[18];
41975552b385SBrandon           if (islite) PetscCall(EGlite_getRange(newgeom, range, &peri));
41985552b385SBrandon           else PetscCall(EG_getRange(newgeom, range, &peri));
41995552b385SBrandon 
42005552b385SBrandon           PetscCall(DMPlex_Geom_FACE_XYZtoUV_Internal(coords, face, range, 0, dE, params, islite));
42015552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
42025552b385SBrandon 
42035552b385SBrandon           if (islite) PetscCall(EGlite_evaluate(newgeom, params, newCoords));
42045552b385SBrandon           else PetscCall(EG_evaluate(newgeom, params, newCoords));
42055552b385SBrandon 
42065552b385SBrandon           // Calculate Surface Area Gradients wrt Control Points and Weights using the local discrete FACE only
42075552b385SBrandon           //      NOTE 1: Will not provide Volume Gradient wrt to Control Points and Weights.
42085552b385SBrandon           //      NOTE 2: This is faster than below where an entire new solid geometry is created for each
42095552b385SBrandon           //              Control Point and Weight gradient
42105552b385SBrandon           if (!fullGeomGrad) {
42115552b385SBrandon             // Create new FACE based on new SURFACE geometry
42125552b385SBrandon             if (jj == 0) { // only for 1st DMPlex Point because we only per CP or Weight
42135552b385SBrandon               double newFaceRange[4];
42145552b385SBrandon               int    newFacePeri;
42155552b385SBrandon               if (islite) PetscCall(EGlite_getRange(newgeom, newFaceRange, &newFacePeri));
42165552b385SBrandon               else PetscCall(EG_getRange(newgeom, newFaceRange, &newFacePeri));
42175552b385SBrandon 
42185552b385SBrandon               ego newface;
42195552b385SBrandon               PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, newFaceRange, &newface)); // Does not have EGlite version KNOWN_ISSUE
42205552b385SBrandon               PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
42215552b385SBrandon 
42225552b385SBrandon               // Get New Face Surface Area
42235552b385SBrandon               PetscScalar newfSA, newFaceData[14];
42245552b385SBrandon               PetscCall(EG_getMassProperties(newface, newFaceData)); // Does not have EGlite version KNOWN_ISSUE
42255552b385SBrandon               newfSA = newFaceData[1];
42265552b385SBrandon               PetscCallEGADS(EG_deleteObject, (newface));
42275552b385SBrandon               PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face %d is corrupted: %d %d %d", f, jj, ii, kk);
42285552b385SBrandon 
42295552b385SBrandon               // Update Control Points
42305552b385SBrandon               PetscHashIter CPiter, Witer;
42315552b385SBrandon               PetscBool     CPfound, Wfound;
42325552b385SBrandon               PetscInt      faceCPStartRow, faceWStartRow;
42335552b385SBrandon 
42345552b385SBrandon               PetscScalar dSAdCPi;
42355552b385SBrandon               dSAdCPi = (newfSA - fSA) / (denomNew - denomOld);
42365552b385SBrandon 
42375552b385SBrandon               if (kk < 3) {
42385552b385SBrandon                 PetscCall(PetscHMapIFind(faceCntrlPtRow_Start, fid, &CPiter, &CPfound));
42395552b385SBrandon                 PetscCheck(CPfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Hash Table");
42405552b385SBrandon                 PetscCall(PetscHMapIGet(faceCntrlPtRow_Start, fid, &faceCPStartRow));
42415552b385SBrandon 
42425552b385SBrandon                 gradSACP[faceCPStartRow + (ii * 3) + kk] = dSAdCPi;
42435552b385SBrandon 
42445552b385SBrandon                 if (PetscAbsReal(dSAdCPi) > maxGrad) maxGrad = PetscAbsReal(dSAdCPi);
42455552b385SBrandon 
42465552b385SBrandon               } else if (kk == 3) {
42475552b385SBrandon                 PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, fid, &Witer, &Wfound));
42485552b385SBrandon                 PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Hash Table");
42495552b385SBrandon                 PetscCall(PetscHMapIGet(faceCPWeightsRow_Start, fid, &faceWStartRow));
42505552b385SBrandon 
42515552b385SBrandon                 gradSAW[faceWStartRow + ii] = dSAdCPi;
42525552b385SBrandon 
42535552b385SBrandon               } else {
42545552b385SBrandon                 // Do Nothing
42555552b385SBrandon               }
42565552b385SBrandon             }
42575552b385SBrandon           }
42585552b385SBrandon           PetscCallEGADS(EG_deleteObject, (newgeom));
42595552b385SBrandon 
42605552b385SBrandon           // Now Calculate the Surface Gradient for the change in x-component Control Point
42615552b385SBrandon           PetscScalar dxdCx = (newCoords[0] - coords[0]) / deltaCoord;
42625552b385SBrandon           PetscScalar dxdCy = (newCoords[1] - coords[1]) / deltaCoord;
42635552b385SBrandon           PetscScalar dxdCz = (newCoords[2] - coords[2]) / deltaCoord;
42645552b385SBrandon 
42655552b385SBrandon           // Store Gradient Information in surfaceGrad[][] Matrix
42665552b385SBrandon           PetscInt startRow;
42675552b385SBrandon           PetscCall(PetscHMapIGet(pointSurfGradRow_Start, currPointID, &startRow));
42685552b385SBrandon 
42695552b385SBrandon           // Store Results in Petsc Matrix
42705552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 0, ((fid - 1) * 4) + kk, dxdCx, INSERT_VALUES));
42715552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 1, ((fid - 1) * 4) + kk, dxdCy, INSERT_VALUES));
42725552b385SBrandon           PetscCall(MatSetValue(pointSurfGrad, startRow + (ii * 3) + 2, ((fid - 1) * 4) + kk, dxdCz, INSERT_VALUES));
42735552b385SBrandon 
42745552b385SBrandon           //PetscCallEGADS(EG_deleteObject, (newgeom));
42755552b385SBrandon           PetscCheck(face->blind, PETSC_COMM_SELF, PETSC_ERR_LIB, "Face is corrupted");
42765552b385SBrandon         }
42775552b385SBrandon         offset += 3;
42785552b385SBrandon       }
42795552b385SBrandon       PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinatesLocal, currPointID, &Nv, &coords));
42805552b385SBrandon     }
42815552b385SBrandon   }
42825552b385SBrandon 
42835552b385SBrandon   // Assemble Point Surface Grad Matrix
42845552b385SBrandon   PetscCall(MatAssemblyBegin(pointSurfGrad, MAT_FINAL_ASSEMBLY));
42855552b385SBrandon   PetscCall(MatAssemblyEnd(pointSurfGrad, MAT_FINAL_ASSEMBLY));
42865552b385SBrandon 
42875552b385SBrandon   if (fullGeomGrad) {
42885552b385SBrandon     // Calculate Surface Area and Volume Control Point and Control Point Weight Gradients
42895552b385SBrandon     //    Note: This is much slower than above due to a new solid geometry being created for
42905552b385SBrandon     //          each change in Control Point and Control Point Weight. However, this method
42915552b385SBrandon     //          will provide the Volume Gradient.
42925552b385SBrandon 
42935552b385SBrandon     // Get Current Face Surface Area
42945552b385SBrandon     PetscScalar bodyVol, bodySA, bodyData[14];
4295*bfe80ac4SPierre Jolivet     PetscCall(EG_getMassProperties(body, bodyData)); // Does not have an EGlite version KNOWN_ISSUE
42965552b385SBrandon     bodyVol = bodyData[0];
42975552b385SBrandon     bodySA  = bodyData[1];
42985552b385SBrandon 
42995552b385SBrandon     // Cycle through Control Points
43005552b385SBrandon     for (int ii = 0; ii < totalNumCPs; ++ii) { // ii should also be the row in cpEquiv for the Control Point
43015552b385SBrandon       // Cycle through X, Y, Z, W changes
43025552b385SBrandon       for (int jj = 0; jj < 4; ++jj) {
43035552b385SBrandon         // Cycle Through Faces
43045552b385SBrandon         double denomNew = 0.0, denomOld = 0.0;
43055552b385SBrandon         double deltaCoord = 1.0E-4;
43065552b385SBrandon         ego    newGeom[Nf];
43075552b385SBrandon         ego    newFaces[Nf];
43085552b385SBrandon         for (int kk = 0; kk < Nf; ++kk) {
43095552b385SBrandon           ego      face;
43105552b385SBrandon           PetscInt currFID = kk + 1;
43115552b385SBrandon 
43125552b385SBrandon           if (islite) {
43135552b385SBrandon             // Get Current FACE
43145552b385SBrandon             PetscCallEGADS(EGlite_objectBodyTopo, (body, FACE, currFID, &face));
43155552b385SBrandon 
43165552b385SBrandon             // Get Geometry Object for the Current FACE
43175552b385SBrandon             PetscCallEGADS(EGlite_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
43185552b385SBrandon             PetscCallEGADS(EGlite_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
43195552b385SBrandon           } else {
43205552b385SBrandon             // Get Current FACE
43215552b385SBrandon             PetscCallEGADS(EG_objectBodyTopo, (body, FACE, currFID, &face));
43225552b385SBrandon 
43235552b385SBrandon             // Get Geometry Object for the Current FACE
43245552b385SBrandon             PetscCallEGADS(EG_getTopology, (face, &fgeom, &foclass, &fmtype, fdata, &Nl, &lobjs, &lsenses));
43255552b385SBrandon             PetscCallEGADS(EG_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
43265552b385SBrandon           }
43275552b385SBrandon 
43285552b385SBrandon           // Make a new SURFACE Geometry by changing the location of the Control Points
43295552b385SBrandon           int    prvSize = bpinfo[3] + bpinfo[6] + (4 * bpinfo[2] * bpinfo[5]);
43305552b385SBrandon           double nbprv[prvSize];
43315552b385SBrandon 
43325552b385SBrandon           // Reinitialize nbprv[] values because we only want to change one value at a time
43335552b385SBrandon           for (int mm = 0; mm < prvSize; ++mm) nbprv[mm] = bprv[mm];
43345552b385SBrandon 
43355552b385SBrandon           // Get Control Point Row and Column Start for cpEquiv
43365552b385SBrandon           PetscHashIter Witer;
43375552b385SBrandon           PetscBool     Wfound;
43385552b385SBrandon           PetscInt      faceWStartRow;
43395552b385SBrandon           PetscCall(PetscHMapIFind(faceCPWeightsRow_Start, currFID, &Witer, &Wfound));
43405552b385SBrandon           PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Weights Hash Table");
43415552b385SBrandon           PetscCall(PetscHMapIGet(faceCPWeightsRow_Start, currFID, &faceWStartRow));
43425552b385SBrandon 
43435552b385SBrandon           // Modify the Current Control Point on this FACE and All Other FACES
43445552b385SBrandon           // IMPORTANT!!! If you do not move all identical Control Points on other FACES
43455552b385SBrandon           //              you will not generate a solid body. You will generate a set of
43465552b385SBrandon           //              disconnected surfaces that have gap(s) between them.
43475552b385SBrandon           int offset  = bpinfo[3] + bpinfo[6];
43485552b385SBrandon           int wOffset = offset + (3 * bpinfo[2] * bpinfo[5]);
43495552b385SBrandon           for (int mm = 0; mm < bpinfo[2] * bpinfo[5]; ++mm) {
43505552b385SBrandon             PetscScalar matValue;
43515552b385SBrandon             PetscCall(MatGetValue(cpEquiv, ii, faceWStartRow + mm, &matValue));
43525552b385SBrandon 
43535552b385SBrandon             if (matValue > 0.0) {
43545552b385SBrandon               if (jj == 0) { //X
43555552b385SBrandon                 nbprv[offset + (3 * mm) + 0] = bprv[offset + (3 * mm) + 0] + deltaCoord;
43565552b385SBrandon                 nbprv[offset + (3 * mm) + 1] = bprv[offset + (3 * mm) + 1];
43575552b385SBrandon                 nbprv[offset + (3 * mm) + 2] = bprv[offset + (3 * mm) + 2];
43585552b385SBrandon                 denomNew                     = nbprv[offset + (3 * mm) + 0];
43595552b385SBrandon                 denomOld                     = bprv[offset + (3 * mm) + 0];
43605552b385SBrandon               } else if (jj == 1) { //Y
43615552b385SBrandon                 nbprv[offset + (3 * mm) + 0] = bprv[offset + (3 * mm) + 0];
43625552b385SBrandon                 nbprv[offset + (3 * mm) + 1] = bprv[offset + (3 * mm) + 1] + deltaCoord;
43635552b385SBrandon                 nbprv[offset + (3 * mm) + 2] = bprv[offset + (3 * mm) + 2];
43645552b385SBrandon                 denomNew                     = nbprv[offset + (3 * mm) + 1];
43655552b385SBrandon                 denomOld                     = bprv[offset + (3 * mm) + 1];
43665552b385SBrandon               } else if (jj == 2) { //Z
43675552b385SBrandon                 nbprv[offset + (3 * mm) + 0] = bprv[offset + (3 * mm) + 0];
43685552b385SBrandon                 nbprv[offset + (3 * mm) + 1] = bprv[offset + (3 * mm) + 1];
43695552b385SBrandon                 nbprv[offset + (3 * mm) + 2] = bprv[offset + (3 * mm) + 2] + deltaCoord;
43705552b385SBrandon                 denomNew                     = nbprv[offset + (3 * mm) + 2];
43715552b385SBrandon                 denomOld                     = bprv[offset + (3 * mm) + 2];
43725552b385SBrandon               } else if (jj == 3) { // Weights
43735552b385SBrandon                 nbprv[wOffset + mm] = bprv[wOffset + mm] + deltaCoord;
43745552b385SBrandon                 denomNew            = nbprv[wOffset + mm];
43755552b385SBrandon                 denomOld            = bprv[wOffset + mm];
43765552b385SBrandon               } else {
43775552b385SBrandon                 // currently do nothing
43785552b385SBrandon               }
43795552b385SBrandon             }
43805552b385SBrandon           }
43815552b385SBrandon 
43825552b385SBrandon           // Create New Surface Based on New Control Points or Weights
43835552b385SBrandon           ego newgeom, context;
43845552b385SBrandon           PetscCallEGADS(EG_getContext, (face, &context));                                             // Does not have an EGlite_ versions   KNOWN_ISSUE
43855552b385SBrandon           PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, nbprv, &newgeom)); // Does not have an EGlite_ version KNOWN_ISSUE
43865552b385SBrandon 
43875552b385SBrandon           // Create New FACE based on modified geometry
43885552b385SBrandon           double newFaceRange[4];
43895552b385SBrandon           int    newFacePeri;
43905552b385SBrandon           if (islite) PetscCallEGADS(EGlite_getRange, (newgeom, newFaceRange, &newFacePeri));
43915552b385SBrandon           else PetscCallEGADS(EG_getRange, (newgeom, newFaceRange, &newFacePeri));
43925552b385SBrandon 
43935552b385SBrandon           ego newface;
43945552b385SBrandon           PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, newFaceRange, &newface)); // Does not have an EGlite_ version KNOWN_ISSUE
43955552b385SBrandon 
43965552b385SBrandon           // store new face for later assembly
43975552b385SBrandon           newGeom[kk]  = newgeom;
43985552b385SBrandon           newFaces[kk] = newface;
43995552b385SBrandon         }
44005552b385SBrandon 
44015552b385SBrandon         // X-WANT TO BUILD THE NEW GEOMETRY, X-GET NEW SA AND PERFORM dSA/dCPi CALCS HERE <---
44025552b385SBrandon         // Sew New Faces together to get a new model
44035552b385SBrandon         ego newmodel;
44045552b385SBrandon         PetscCall(EG_sewFaces(Nf, newFaces, 0.0, 0, &newmodel)); // Does not have an EGlite_ version KNOWN_ISSUE
44055552b385SBrandon 
44065552b385SBrandon         // Get Surface Area and Volume of New/Updated Solid Body
44075552b385SBrandon         PetscScalar newData[14];
44085552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getTopology, (newmodel, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
44095552b385SBrandon         else PetscCallEGADS(EG_getTopology, (newmodel, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
44105552b385SBrandon 
44115552b385SBrandon         ego nbody = bodies[0];
44125552b385SBrandon         PetscCall(EG_getMassProperties(nbody, newData)); // Does not have an EGlite_ version   KNOWN_ISSUE
44135552b385SBrandon 
44145552b385SBrandon         PetscScalar dSAdCPi, dVdCPi;
44155552b385SBrandon         PetscScalar nbodyVol = newData[0], nbodySA = newData[1];
44165552b385SBrandon 
44175552b385SBrandon         // Calculate Gradients wrt to Control Points and Control Points Weights depending on jj value
44185552b385SBrandon         dSAdCPi = (nbodySA - bodySA) / (denomNew - denomOld);
44195552b385SBrandon         dVdCPi  = (nbodyVol - bodyVol) / (denomNew - denomOld);
44205552b385SBrandon 
44215552b385SBrandon         if (jj < 3) {
44225552b385SBrandon           // Gradienst wrt to Control Points
44235552b385SBrandon           gradSACP[(ii * 3) + jj] = dSAdCPi;
44245552b385SBrandon           gradVCP[(ii * 3) + jj]  = dVdCPi;
44255552b385SBrandon         } else if (jj == 3) {
44265552b385SBrandon           // Gradients wrt to Control Point Weights
44275552b385SBrandon           gradSAW[ii] = dSAdCPi;
44285552b385SBrandon           gradVW[ii]  = dVdCPi;
44295552b385SBrandon         } else {
44305552b385SBrandon           // Do Nothing
44315552b385SBrandon         }
44325552b385SBrandon         PetscCallEGADS(EG_deleteObject, (newmodel));
44335552b385SBrandon         for (int kk = 0; kk < Nf; ++kk) {
44345552b385SBrandon           PetscCallEGADS(EG_deleteObject, (newFaces[kk]));
44355552b385SBrandon           PetscCallEGADS(EG_deleteObject, (newGeom[kk]));
44365552b385SBrandon         }
44375552b385SBrandon       }
44385552b385SBrandon     }
44395552b385SBrandon   }
44405552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradSACPVec, &gradSACP));
44415552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradSAWVec, &gradSAW));
44425552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradVCPVec, &gradVCP));
44435552b385SBrandon   PetscCall(VecRestoreArrayWrite(gradVWVec, &gradVW));
44445552b385SBrandon   PetscCall(MatDestroy(&cpEquiv));
44455552b385SBrandon 
44465552b385SBrandon   // Attach Surface Gradient Hash Table and Matrix to DM
44475552b385SBrandon   {
44485552b385SBrandon     PetscContainer surfGradOrgObj;
44495552b385SBrandon 
44505552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject *)&surfGradOrgObj));
44515552b385SBrandon     if (!surfGradOrgObj) {
44525552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &surfGradOrgObj));
44535552b385SBrandon       PetscCall(PetscContainerSetPointer(surfGradOrgObj, pointSurfGradRow_Start));
44545552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(surfGradOrgObj, DestroyHashMap));
44555552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject)surfGradOrgObj));
44565552b385SBrandon       PetscCall(PetscContainerDestroy(&surfGradOrgObj));
44575552b385SBrandon     } else {
44585552b385SBrandon       PetscCall(PetscContainerSetPointer(surfGradOrgObj, pointSurfGradRow_Start));
44595552b385SBrandon     }
44605552b385SBrandon 
44615552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Gradient Matrix", (PetscObject)pointSurfGrad));
44625552b385SBrandon     PetscCall(MatDestroy(&pointSurfGrad));
44635552b385SBrandon 
44645552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Area Control Point Gradient", (PetscObject)gradSACPVec));
44655552b385SBrandon     PetscCall(VecDestroy(&gradSACPVec));
44665552b385SBrandon 
44675552b385SBrandon     PetscCall(PetscObjectCompose((PetscObject)dm, "Surface Area Weights Gradient", (PetscObject)gradSAWVec));
44685552b385SBrandon     PetscCall(VecDestroy(&gradSAWVec));
44695552b385SBrandon 
44705552b385SBrandon     if (fullGeomGrad) {
44715552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Volume Control Point Gradient", (PetscObject)gradVCPVec));
44725552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Volume Weights Gradient", (PetscObject)gradVWVec));
44735552b385SBrandon     }
44745552b385SBrandon     PetscCall(VecDestroy(&gradVCPVec));
44755552b385SBrandon     PetscCall(VecDestroy(&gradVWVec));
44765552b385SBrandon   }
44775552b385SBrandon 
44785552b385SBrandon   // Could be replaced with DMPlexFreeGeomObject()
44795552b385SBrandon   if (islite) EGlite_free(fobjs);
44805552b385SBrandon   else EG_free(fobjs);
44815552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
44825552b385SBrandon #else
44835552b385SBrandon   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
44845552b385SBrandon #endif
44855552b385SBrandon }
44865552b385SBrandon 
44875552b385SBrandon /*@C
44885552b385SBrandon   DMPlexModifyGeomModel - Generates a new EGADS geometry model based in user provided Control Points and Control Points Weights. Optionally, the function will inflate the DM to the new geometry and save the new geometry to a file.
44895552b385SBrandon 
44905552b385SBrandon   Collective
44915552b385SBrandon 
44925552b385SBrandon   Input Parameters:
44935552b385SBrandon + dm          - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
44945552b385SBrandon . comm        - MPI_Comm object
44955552b385SBrandon . newCP       - C Array of [x, y, z] New/Updated Control Point Coordinates defining the geometry (See DMPlexGeomDataAndGrads() for format)
44965552b385SBrandon . newW        - C Array of New/Updated Control Point Weights associated with the Control Points defining the new geometry (See DMPlexGemGrads() for format)
44975552b385SBrandon . autoInflate - PetscBool Flag denoting if the user would like to inflate the DM points to the new geometry.
44985552b385SBrandon . saveGeom    - PetscBool Flag denoting if the user would iike to save the new geometry to a file.
44995552b385SBrandon - stpName     - Char Array indicating the name of the file to save the new geometry to. Extension must be included and will denote type of file written.
45005552b385SBrandon                       *.stp or *.step = STEP File
45015552b385SBrandon                       *.igs or *.iges = IGES File
45025552b385SBrandon                               *.egads = EGADS File
45035552b385SBrandon                                *.brep = BRep File (OpenCASCADE File)
45045552b385SBrandon 
45055552b385SBrandon   Output Parameter:
45065552b385SBrandon . dm - The updated DM object representing the mesh with PetscContainers containing the updated/modified geometry
45075552b385SBrandon 
45085552b385SBrandon   Level: intermediate
45095552b385SBrandon 
45105552b385SBrandon   Note:
45115552b385SBrandon   Functionality not available for DMPlexes with attached EGADSlite geometry files (.egadslite).
45125552b385SBrandon 
45135552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexGeomDataAndGrads()`
45145552b385SBrandon @*/
4515ce78bad3SBarry Smith PetscErrorCode DMPlexModifyGeomModel(DM dm, MPI_Comm comm, PetscScalar newCP[], PetscScalar newW[], PetscBool autoInflate, PetscBool saveGeom, const char *stpName) PeNS
45165552b385SBrandon {
45175552b385SBrandon #if defined(PETSC_HAVE_EGADS)
45185552b385SBrandon   /* EGADS/EGADSlite variables */
45195552b385SBrandon   ego context, model, geom, *bodies, *lobjs, *fobjs;
45205552b385SBrandon   int oclass, mtype, *senses, *lsenses;
45215552b385SBrandon   int Nb, Nf, Nl, id;
45225552b385SBrandon   /* PETSc variables */
45235552b385SBrandon   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
45245552b385SBrandon   PetscContainer modelObj, cpHashTableObj, wHashTableObj;
45255552b385SBrandon   PetscHMapI     cpHashTable = NULL, wHashTable = NULL;
45265552b385SBrandon   PetscBool      islite = PETSC_FALSE;
45275552b385SBrandon #endif
45285552b385SBrandon 
45295552b385SBrandon #if defined(PETSC_HAVE_EGADS)
45305552b385SBrandon   PetscFunctionBegin;
45315552b385SBrandon   // Look to see if DM has a Container with either a EGADS or EGADSlite Model
45325552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
45335552b385SBrandon   if (!modelObj) {
45345552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
45355552b385SBrandon     islite = PETSC_TRUE;
45365552b385SBrandon   }
45375552b385SBrandon   PetscCheck(!islite, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot modify geometries defined by EGADSlite (.egadslite)! Please use another geometry file format STEP, IGES, EGADS or BRep");
45385552b385SBrandon   PetscCheck(modelObj, PETSC_COMM_SELF, PETSC_ERR_SUP, "DM does not have a EGADS Geometry Model attached to it!");
45395552b385SBrandon 
45405552b385SBrandon   // Get attached EGADS model (pointer)
45415552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
45425552b385SBrandon 
45435552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
45445552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Hash Table", (PetscObject *)&cpHashTableObj));
45455552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject *)&wHashTableObj));
45465552b385SBrandon 
45475552b385SBrandon   PetscCheck(cpHashTableObj && wHashTableObj, PETSC_COMM_SELF, PETSC_ERR_SUP, "DM does not have required Geometry Data attached! Please run DMPlexGeomDataAndGrads() Function first.");
45485552b385SBrandon 
45495552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
45505552b385SBrandon   PetscCall(PetscContainerGetPointer(cpHashTableObj, (void **)&cpHashTable));
45515552b385SBrandon   PetscCall(PetscContainerGetPointer(wHashTableObj, (void **)&wHashTable));
45525552b385SBrandon 
45535552b385SBrandon   // Get the number of bodies and body objects in the model
45545552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getTopology, (model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
45555552b385SBrandon   else PetscCallEGADS(EG_getTopology, (model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
45565552b385SBrandon 
45575552b385SBrandon   // Get all Faces on the body
45585552b385SBrandon   ego body = bodies[0];
45595552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
45605552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
45615552b385SBrandon 
45625552b385SBrandon   ego newGeom[Nf];
45635552b385SBrandon   ego newFaces[Nf];
45645552b385SBrandon 
45655552b385SBrandon   // Update Control Point and Weight definitions for each surface
45665552b385SBrandon   for (int jj = 0; jj < Nf; ++jj) {
45675552b385SBrandon     ego     face = fobjs[jj];
45685552b385SBrandon     ego     bRef, bPrev, bNext;
45695552b385SBrandon     ego     fgeom;
45705552b385SBrandon     int     offset;
45715552b385SBrandon     int     boclass, bmtype, *bpinfo;
45725552b385SBrandon     double *bprv;
45735552b385SBrandon 
45745552b385SBrandon     // Get FACE ID and other Geometry Data
45755552b385SBrandon     if (islite) {
45765552b385SBrandon       id = EGlite_indexBodyTopo(body, face);
45775552b385SBrandon       PetscCallEGADS(EGlite_getTopology, (face, &fgeom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
45785552b385SBrandon       PetscCallEGADS(EGlite_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
45795552b385SBrandon       PetscCallEGADS(EGlite_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
45805552b385SBrandon     } else {
45815552b385SBrandon       id = EG_indexBodyTopo(body, face);
45825552b385SBrandon       PetscCallEGADS(EG_getTopology, (face, &fgeom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
45835552b385SBrandon       PetscCallEGADS(EG_getGeometry, (fgeom, &boclass, &bmtype, &bRef, &bpinfo, &bprv));
45845552b385SBrandon       PetscCallEGADS(EG_getInfo, (fgeom, &boclass, &bmtype, &bRef, &bPrev, &bNext));
45855552b385SBrandon     }
45865552b385SBrandon 
45875552b385SBrandon     // Update Control Points
45885552b385SBrandon     PetscHashIter CPiter, Witer;
45895552b385SBrandon     PetscBool     CPfound, Wfound;
45905552b385SBrandon     PetscInt      faceCPStartRow, faceWStartRow;
45915552b385SBrandon 
45925552b385SBrandon     PetscCall(PetscHMapIFind(cpHashTable, id, &CPiter, &CPfound));
45935552b385SBrandon     PetscCheck(CPfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Hash Table");
45945552b385SBrandon     PetscCall(PetscHMapIGet(cpHashTable, id, &faceCPStartRow));
45955552b385SBrandon 
45965552b385SBrandon     PetscCall(PetscHMapIFind(wHashTable, id, &Witer, &Wfound));
45975552b385SBrandon     PetscCheck(Wfound, PETSC_COMM_SELF, PETSC_ERR_SUP, "FACE ID not found in Control Point Weights Hash Table");
45985552b385SBrandon     PetscCall(PetscHMapIGet(wHashTable, id, &faceWStartRow));
45995552b385SBrandon 
46005552b385SBrandon     // UPDATE CONTROL POINTS Locations
46015552b385SBrandon     offset = bpinfo[3] + bpinfo[6];
46025552b385SBrandon     for (int ii = 0; ii < 3 * bpinfo[2] * bpinfo[5]; ++ii) { bprv[offset + ii] = newCP[faceCPStartRow + ii]; }
46035552b385SBrandon 
46045552b385SBrandon     // UPDATE CONTROL POINT WEIGHTS
46055552b385SBrandon     offset = bpinfo[3] + bpinfo[6] + 3 * bpinfo[2] * bpinfo[5];
46065552b385SBrandon     for (int ii = 0; ii < bpinfo[2] * bpinfo[5]; ++ii) { bprv[offset + ii] = newW[faceWStartRow + ii]; }
46075552b385SBrandon 
46085552b385SBrandon     // Get Context from FACE
46095552b385SBrandon     context = NULL;
46105552b385SBrandon     PetscCallEGADS(EG_getContext, (face, &context)); // Does not have an EGlite_ version  KNOWN_ISSUE
46115552b385SBrandon 
46125552b385SBrandon     // Create New Surface
46135552b385SBrandon     ego newgeom;
46145552b385SBrandon     PetscCallEGADS(EG_makeGeometry, (context, SURFACE, BSPLINE, NULL, bpinfo, bprv, &newgeom)); // Does not have an EGlite_ version KNOWN_ISSUE
46155552b385SBrandon 
46165552b385SBrandon     // Create new FACE based on new SURFACE geometry
46175552b385SBrandon     double data[4];
46185552b385SBrandon     int    periodic;
46195552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getRange, (newgeom, data, &periodic));
46205552b385SBrandon     else PetscCallEGADS(EG_getRange, (newgeom, data, &periodic));
46215552b385SBrandon 
46225552b385SBrandon     ego newface;
46235552b385SBrandon     PetscCallEGADS(EG_makeFace, (newgeom, SFORWARD, data, &newface)); // Does not have an EGlite_ version KNOWN_ISSUE
46245552b385SBrandon     newGeom[jj]  = newgeom;
46255552b385SBrandon     newFaces[jj] = newface;
46265552b385SBrandon   }
46275552b385SBrandon   // Could be replaced by DMPlexFreeGeomObject
46285552b385SBrandon   if (islite) EGlite_free(fobjs);
46295552b385SBrandon   else EG_free(fobjs);
46305552b385SBrandon 
46315552b385SBrandon   // Sew New Faces together to get a new model
46325552b385SBrandon   ego newmodel;
46335552b385SBrandon   PetscCall(EG_sewFaces(Nf, newFaces, 0.0, 0, &newmodel)); // Does not have an EGlite_ version   KNOWN_ISSUE
46345552b385SBrandon   for (PetscInt f = 0; f < Nf; ++f) {
46355552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newFaces[f]));
46365552b385SBrandon     PetscCallEGADS(EG_deleteObject, (newGeom[f]));
46375552b385SBrandon   }
46385552b385SBrandon 
46395552b385SBrandon   // Get the total number of NODEs on the original geometry. (This will be the same for the new geometry)
46405552b385SBrandon   int  totalNumNode;
46415552b385SBrandon   ego *nobjTotal;
46425552b385SBrandon   if (islite) {
46435552b385SBrandon     PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, NODE, &totalNumNode, &nobjTotal));
46445552b385SBrandon     EGlite_free(nobjTotal);
46455552b385SBrandon   } else {
46465552b385SBrandon     PetscCallEGADS(EG_getBodyTopos, (body, NULL, NODE, &totalNumNode, &nobjTotal));
46475552b385SBrandon     EG_free(nobjTotal);
46485552b385SBrandon   } // Could be replaced with DMPlexFreeGeomObject
46495552b385SBrandon 
46505552b385SBrandon   // Initialize vector to store equivalent NODE indices between the 2 geometries
46515552b385SBrandon   // FORMAT :: vector index is the Original Geometry's NODE ID, the vector Value is the New Geometry's NODE ID
46525552b385SBrandon   int nodeIDEquiv[totalNumNode + 1];
46535552b385SBrandon 
46545552b385SBrandon   // Now we need to Map the NODE and EDGE IDs from each Model
46555552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
46565552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (body, NULL, FACE, &Nf, &fobjs));
46575552b385SBrandon 
46585552b385SBrandon   // New CAD
46595552b385SBrandon   ego *newbodies, newgeomtest, *nfobjs;
46605552b385SBrandon   int  nNf, newNb, newoclass, newmtype, *newsenses;
46615552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getTopology, (newmodel, &newgeomtest, &newoclass, &newmtype, NULL, &newNb, &newbodies, &newsenses));
46625552b385SBrandon   else PetscCallEGADS(EG_getTopology, (newmodel, &newgeomtest, &newoclass, &newmtype, NULL, &newNb, &newbodies, &newsenses));
46635552b385SBrandon 
46645552b385SBrandon   ego newbody = newbodies[0];
46655552b385SBrandon   if (islite) PetscCallEGADS(EGlite_getBodyTopos, (newbody, NULL, FACE, &nNf, &nfobjs));
46665552b385SBrandon   else PetscCallEGADS(EG_getBodyTopos, (newbody, NULL, FACE, &nNf, &nfobjs));
46675552b385SBrandon 
46685552b385SBrandon   PetscCheck(newNb == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "ERROR :: newNb > 1 || newNb = %d", newNb);
46695552b385SBrandon 
46705552b385SBrandon   // Find Equivalent Nodes
46715552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
46725552b385SBrandon     double fdata[4];
46735552b385SBrandon     int    peri;
46745552b385SBrandon 
46755552b385SBrandon     // Get Current FACE [u, v] Ranges
46765552b385SBrandon     if (islite) PetscCallEGADS(EGlite_getRange, (fobjs[ii], fdata, &peri));
46775552b385SBrandon     else PetscCallEGADS(EG_getRange, (fobjs[ii], fdata, &peri));
46785552b385SBrandon 
46795552b385SBrandon     // Equate NODE IDs between 2 FACEs by working through (u, v) limits of FACE
46805552b385SBrandon     for (int jj = 0; jj < 2; ++jj) {
46815552b385SBrandon       for (int kk = 2; kk < 4; ++kk) {
46825552b385SBrandon         double params[2] = {fdata[jj], fdata[kk]};
46835552b385SBrandon         double eval[18];
46845552b385SBrandon         if (islite) PetscCallEGADS(EGlite_evaluate, (fobjs[ii], params, eval));
46855552b385SBrandon         else PetscCallEGADS(EG_evaluate, (fobjs[ii], params, eval));
46865552b385SBrandon 
46875552b385SBrandon         // Original Body
46885552b385SBrandon         ego *nobjsOrigFace;
46895552b385SBrandon         int  origNn;
46905552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getBodyTopos, (body, fobjs[ii], NODE, &origNn, &nobjsOrigFace));
46915552b385SBrandon         else PetscCallEGADS(EG_getBodyTopos, (body, fobjs[ii], NODE, &origNn, &nobjsOrigFace));
46925552b385SBrandon 
46935552b385SBrandon         double minVal = 1.0E10;
46945552b385SBrandon         double evalCheck[18];
46955552b385SBrandon         int    equivOrigNodeID = -1;
46965552b385SBrandon         for (int mm = 0; mm < origNn; ++mm) {
46975552b385SBrandon           double delta = 1.0E10;
46985552b385SBrandon           if (islite) PetscCallEGADS(EGlite_evaluate, (nobjsOrigFace[mm], NULL, evalCheck));
46995552b385SBrandon           else PetscCallEGADS(EG_evaluate, (nobjsOrigFace[mm], NULL, evalCheck));
47005552b385SBrandon 
47015552b385SBrandon           delta = PetscSqrtReal(PetscSqr(evalCheck[0] - eval[0]) + PetscSqr(evalCheck[1] - eval[1]) + PetscSqr(evalCheck[2] - eval[2]));
47025552b385SBrandon 
47035552b385SBrandon           if (delta < minVal) {
47045552b385SBrandon             if (islite) equivOrigNodeID = EGlite_indexBodyTopo(body, nobjsOrigFace[mm]);
47055552b385SBrandon             else equivOrigNodeID = EG_indexBodyTopo(body, nobjsOrigFace[mm]);
47065552b385SBrandon 
47075552b385SBrandon             minVal = delta;
47085552b385SBrandon           }
47095552b385SBrandon         }
47105552b385SBrandon         // Could be replaced with DMPlexFreeGeomObject
47115552b385SBrandon         if (islite) EGlite_free(nobjsOrigFace);
47125552b385SBrandon         else EG_free(nobjsOrigFace);
47135552b385SBrandon 
47145552b385SBrandon         // New Body
47155552b385SBrandon         ego *nobjsNewFace;
47165552b385SBrandon         int  newNn;
47175552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getBodyTopos, (newbody, nfobjs[ii], NODE, &newNn, &nobjsNewFace));
47185552b385SBrandon         else PetscCallEGADS(EG_getBodyTopos, (newbody, nfobjs[ii], NODE, &newNn, &nobjsNewFace));
47195552b385SBrandon 
47205552b385SBrandon         minVal             = 1.0E10;
47215552b385SBrandon         int equivNewNodeID = -1;
47225552b385SBrandon         for (int mm = 0; mm < newNn; ++mm) {
47235552b385SBrandon           double delta = 1.0E10;
47245552b385SBrandon           if (islite) PetscCallEGADS(EGlite_evaluate, (nobjsNewFace[mm], NULL, evalCheck));
47255552b385SBrandon           else PetscCallEGADS(EG_evaluate, (nobjsNewFace[mm], NULL, evalCheck));
47265552b385SBrandon 
47275552b385SBrandon           delta = PetscSqrtReal(PetscSqr(evalCheck[0] - eval[0]) + PetscSqr(evalCheck[1] - eval[1]) + PetscSqr(evalCheck[2] - eval[2]));
47285552b385SBrandon 
47295552b385SBrandon           if (delta < minVal) {
47305552b385SBrandon             if (islite) equivNewNodeID = EGlite_indexBodyTopo(newbody, nobjsNewFace[mm]);
47315552b385SBrandon             else equivNewNodeID = EG_indexBodyTopo(newbody, nobjsNewFace[mm]);
47325552b385SBrandon 
47335552b385SBrandon             minVal = delta;
47345552b385SBrandon           }
47355552b385SBrandon         }
47365552b385SBrandon         if (islite) EGlite_free(nobjsNewFace);
47375552b385SBrandon         else EG_free(nobjsNewFace);
47385552b385SBrandon 
47395552b385SBrandon         // Store equivalent NODE IDs
47405552b385SBrandon         nodeIDEquiv[equivOrigNodeID] = equivNewNodeID;
47415552b385SBrandon       }
47425552b385SBrandon     }
47435552b385SBrandon   }
47445552b385SBrandon 
47455552b385SBrandon   // Find Equivalent EDGEs
47465552b385SBrandon   //   Get total number of EDGEs on Original Geometry
47475552b385SBrandon   int  totalNumEdge;
47485552b385SBrandon   ego *eobjsOrig;
47495552b385SBrandon   if (islite) {
47505552b385SBrandon     PetscCallEGADS(EGlite_getBodyTopos, (body, NULL, EDGE, &totalNumEdge, &eobjsOrig));
47515552b385SBrandon     EGlite_free(eobjsOrig);
47525552b385SBrandon   } else {
47535552b385SBrandon     PetscCallEGADS(EG_getBodyTopos, (body, NULL, EDGE, &totalNumEdge, &eobjsOrig));
47545552b385SBrandon     EG_free(eobjsOrig);
47555552b385SBrandon   }
47565552b385SBrandon 
47575552b385SBrandon   //   Get total number of EDGEs on New Geometry
47585552b385SBrandon   int  totalNumEdgeNew;
47595552b385SBrandon   ego *eobjsNew;
47605552b385SBrandon   if (islite) {
47615552b385SBrandon     PetscCallEGADS(EGlite_getBodyTopos, (newbody, NULL, EDGE, &totalNumEdgeNew, &eobjsNew));
47625552b385SBrandon     EGlite_free(eobjsNew);
47635552b385SBrandon   } else {
47645552b385SBrandon     PetscCallEGADS(EG_getBodyTopos, (newbody, NULL, EDGE, &totalNumEdgeNew, &eobjsNew));
47655552b385SBrandon     EG_free(eobjsNew);
47665552b385SBrandon   }
47675552b385SBrandon 
47685552b385SBrandon   // Initialize EDGE ID equivalent vector
47695552b385SBrandon   // FORMAT :: vector index is the Original Geometry's EDGE ID, the vector Value is the New Geometry's EDGE ID
47705552b385SBrandon   int edgeIDEquiv[totalNumEdge + 1];
47715552b385SBrandon 
47725552b385SBrandon   // Find Equivalent EDGEs
47735552b385SBrandon   for (int ii = 0; ii < Nf; ++ii) {
47745552b385SBrandon     // Get Original Geometry EDGE's NODEs
47755552b385SBrandon     int numOrigEdge, numNewEdge;
47765552b385SBrandon     if (islite) {
47775552b385SBrandon       PetscCallEGADS(EGlite_getBodyTopos, (body, fobjs[ii], EDGE, &numOrigEdge, &eobjsOrig));
47785552b385SBrandon       PetscCallEGADS(EGlite_getBodyTopos, (newbody, nfobjs[ii], EDGE, &numNewEdge, &eobjsNew));
47795552b385SBrandon     } else {
47805552b385SBrandon       PetscCallEGADS(EG_getBodyTopos, (body, fobjs[ii], EDGE, &numOrigEdge, &eobjsOrig));
47815552b385SBrandon       PetscCallEGADS(EG_getBodyTopos, (newbody, nfobjs[ii], EDGE, &numNewEdge, &eobjsNew));
47825552b385SBrandon     }
47835552b385SBrandon 
47845552b385SBrandon     // new loop below
47855552b385SBrandon     for (int nn = 0; nn < numOrigEdge; ++nn) {
47865552b385SBrandon       ego origEdge = eobjsOrig[nn];
47875552b385SBrandon       ego geomEdgeOrig, *nobjsOrig;
47885552b385SBrandon       int oclassEdgeOrig, mtypeEdgeOrig;
47895552b385SBrandon       int NnOrig, *nsensesEdgeOrig;
47905552b385SBrandon 
47915552b385SBrandon       if (islite) PetscCallEGADS(EGlite_getTopology, (origEdge, &geomEdgeOrig, &oclassEdgeOrig, &mtypeEdgeOrig, NULL, &NnOrig, &nobjsOrig, &nsensesEdgeOrig));
47925552b385SBrandon       else PetscCallEGADS(EG_getTopology, (origEdge, &geomEdgeOrig, &oclassEdgeOrig, &mtypeEdgeOrig, NULL, &NnOrig, &nobjsOrig, &nsensesEdgeOrig));
47935552b385SBrandon 
47945552b385SBrandon       PetscBool isSame = PETSC_FALSE;
47955552b385SBrandon       for (int jj = 0; jj < numNewEdge; ++jj) {
47965552b385SBrandon         ego newEdge = eobjsNew[jj];
47975552b385SBrandon         ego geomEdgeNew, *nobjsNew;
47985552b385SBrandon         int oclassEdgeNew, mtypeEdgeNew;
47995552b385SBrandon         int NnNew, *nsensesEdgeNew;
48005552b385SBrandon 
48015552b385SBrandon         if (islite) PetscCallEGADS(EGlite_getTopology, (newEdge, &geomEdgeNew, &oclassEdgeNew, &mtypeEdgeNew, NULL, &NnNew, &nobjsNew, &nsensesEdgeNew));
48025552b385SBrandon         else PetscCallEGADS(EG_getTopology, (newEdge, &geomEdgeNew, &oclassEdgeNew, &mtypeEdgeNew, NULL, &NnNew, &nobjsNew, &nsensesEdgeNew));
48035552b385SBrandon 
48045552b385SBrandon         if (mtypeEdgeOrig == mtypeEdgeNew) {
48055552b385SBrandon           // Only operate if the EDGE types are the same
48065552b385SBrandon           for (int kk = 0; kk < NnNew; ++kk) {
48075552b385SBrandon             int nodeIDOrigGeom, nodeIDNewGeom;
48085552b385SBrandon             if (islite) {
48095552b385SBrandon               nodeIDOrigGeom = EGlite_indexBodyTopo(body, nobjsOrig[kk]);
48105552b385SBrandon               nodeIDNewGeom  = EGlite_indexBodyTopo(newbody, nobjsNew[kk]);
48115552b385SBrandon             } else {
48125552b385SBrandon               nodeIDOrigGeom = EG_indexBodyTopo(body, nobjsOrig[kk]);
48135552b385SBrandon               nodeIDNewGeom  = EG_indexBodyTopo(newbody, nobjsNew[kk]);
48145552b385SBrandon             }
48155552b385SBrandon 
48165552b385SBrandon             if (nodeIDNewGeom == nodeIDEquiv[nodeIDOrigGeom]) {
48175552b385SBrandon               isSame = PETSC_TRUE;
48185552b385SBrandon             } else {
48195552b385SBrandon               isSame = PETSC_FALSE;
48205552b385SBrandon               kk     = NnNew; // skip ahead because first NODE failed test and order is important
48215552b385SBrandon             }
48225552b385SBrandon           }
48235552b385SBrandon 
48245552b385SBrandon           if (isSame == PETSC_TRUE) {
48255552b385SBrandon             int edgeIDOrig, edgeIDNew;
48265552b385SBrandon             if (islite) {
48275552b385SBrandon               edgeIDOrig = EGlite_indexBodyTopo(body, origEdge);
48285552b385SBrandon               edgeIDNew  = EGlite_indexBodyTopo(newbody, newEdge);
48295552b385SBrandon             } else {
48305552b385SBrandon               edgeIDOrig = EG_indexBodyTopo(body, origEdge);
48315552b385SBrandon               edgeIDNew  = EG_indexBodyTopo(newbody, newEdge);
48325552b385SBrandon             }
48335552b385SBrandon 
48345552b385SBrandon             edgeIDEquiv[edgeIDOrig] = edgeIDNew;
48355552b385SBrandon             jj                      = numNewEdge;
48365552b385SBrandon           }
48375552b385SBrandon         }
48385552b385SBrandon       }
48395552b385SBrandon     }
48405552b385SBrandon     if (islite) {
48415552b385SBrandon       EGlite_free(eobjsOrig);
48425552b385SBrandon       EGlite_free(eobjsNew);
48435552b385SBrandon     } else {
48445552b385SBrandon       EG_free(eobjsOrig);
48455552b385SBrandon       EG_free(eobjsNew);
48465552b385SBrandon     }
48475552b385SBrandon   }
48485552b385SBrandon   if (islite) {
48495552b385SBrandon     EGlite_free(fobjs);
48505552b385SBrandon     EGlite_free(nfobjs);
48515552b385SBrandon   } else {
48525552b385SBrandon     EG_free(fobjs);
48535552b385SBrandon     EG_free(nfobjs);
48545552b385SBrandon   }
48555552b385SBrandon 
48565552b385SBrandon   // Modify labels to point to the IDs on the new Geometry
48575552b385SBrandon   IS isNodeID, isEdgeID;
48585552b385SBrandon 
48595552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
48605552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
48615552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
48625552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
48635552b385SBrandon 
48645552b385SBrandon   PetscCall(ISCreateGeneral(comm, totalNumNode + 1, nodeIDEquiv, PETSC_COPY_VALUES, &isNodeID));
48655552b385SBrandon   PetscCall(ISCreateGeneral(comm, totalNumEdge + 1, edgeIDEquiv, PETSC_COPY_VALUES, &isEdgeID));
48665552b385SBrandon   /* Do not perform check. Np may != Nv due to Degenerate Geometry which is not stored in labels.               */
48675552b385SBrandon   /* We do not know in advance which IDs have been omitted. This may also change due to geometry modifications. */
48685552b385SBrandon   PetscCall(DMLabelRewriteValues(vertexLabel, isNodeID));
48695552b385SBrandon   PetscCall(DMLabelRewriteValues(edgeLabel, isEdgeID));
48705552b385SBrandon   PetscCall(ISDestroy(&isNodeID));
48715552b385SBrandon   PetscCall(ISDestroy(&isEdgeID));
48725552b385SBrandon 
48735552b385SBrandon   // Attempt to point to the new geometry
48745552b385SBrandon   PetscCallEGADS(EG_deleteObject, (model));
48755552b385SBrandon   PetscCall(PetscContainerSetPointer(modelObj, newmodel));
48765552b385SBrandon 
48775552b385SBrandon   // save updated model to file
48785552b385SBrandon   if (saveGeom == PETSC_TRUE && stpName != NULL) PetscCall(EG_saveModel(newmodel, stpName));
48795552b385SBrandon 
48805552b385SBrandon   // Inflate Mesh to EGADS Model
48815552b385SBrandon   if (autoInflate == PETSC_TRUE) PetscCall(DMPlexInflateToGeomModel(dm, PETSC_TRUE));
48825552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
48835552b385SBrandon #else
48845552b385SBrandon   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This method requires EGADS support. Reconfigure using --download-egads");
48855552b385SBrandon #endif
48865552b385SBrandon }
48875552b385SBrandon 
48885552b385SBrandon /*@C
48895552b385SBrandon   DMPlexGetGeomModelTUV - Gets the [t] (EDGES) and [u, v] (FACES) geometry parameters of DM points that are associated geometry relationships. Requires a DM with a EGADS model attached.
48905552b385SBrandon 
48915552b385SBrandon   Collective
48925552b385SBrandon 
48935552b385SBrandon   Input Parameter:
48945552b385SBrandon . dm - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
48955552b385SBrandon 
48965552b385SBrandon   Level: intermediate
48975552b385SBrandon 
48985552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexGeomDataAndGrads()`
48995552b385SBrandon @*/
4900ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelTUV(DM dm) PeNS
49015552b385SBrandon {
49025552b385SBrandon #if defined(PETSC_HAVE_EGADS)
49035552b385SBrandon   /* EGADS Variables */
49045552b385SBrandon   ego    model, geom, body, face, edge;
49055552b385SBrandon   ego   *bodies;
49065552b385SBrandon   int    Nb, oclass, mtype, *senses;
49075552b385SBrandon   double result[4];
49085552b385SBrandon   /* PETSc Variables */
49095552b385SBrandon   DM             cdm;
49105552b385SBrandon   PetscContainer modelObj;
49115552b385SBrandon   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
49125552b385SBrandon   Vec            coordinates;
49135552b385SBrandon   PetscScalar   *coords;
49145552b385SBrandon   PetscInt       bodyID, faceID, edgeID, vertexID;
49155552b385SBrandon   PetscInt       cdim, vStart, vEnd, v;
49165552b385SBrandon   PetscBool      islite = PETSC_FALSE;
49175552b385SBrandon #endif
49185552b385SBrandon 
49195552b385SBrandon   PetscFunctionBegin;
49205552b385SBrandon #if defined(PETSC_HAVE_EGADS)
49215552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
49225552b385SBrandon   if (!modelObj) {
49235552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
49245552b385SBrandon     islite = PETSC_TRUE;
49255552b385SBrandon   }
49265552b385SBrandon   if (!modelObj) PetscFunctionReturn(0);
49275552b385SBrandon 
49285552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &cdim));
49295552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
49305552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
49315552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
49325552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
49335552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
49345552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
49355552b385SBrandon 
49365552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
49375552b385SBrandon 
49385552b385SBrandon   if (islite) PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
49395552b385SBrandon   else PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
49405552b385SBrandon 
49415552b385SBrandon   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
49425552b385SBrandon   PetscCall(VecGetArrayWrite(coordinates, &coords));
49435552b385SBrandon 
49445552b385SBrandon   // Define t, u, v arrays to be stored in a PetscContainer after populated
49455552b385SBrandon   PetscScalar *t_point, *u_point, *v_point;
49465552b385SBrandon   PetscCall(PetscMalloc1(vEnd - vStart, &t_point));
49475552b385SBrandon   PetscCall(PetscMalloc1(vEnd - vStart, &u_point));
49485552b385SBrandon   PetscCall(PetscMalloc1(vEnd - vStart, &v_point));
49495552b385SBrandon 
49505552b385SBrandon   for (v = vStart; v < vEnd; ++v) {
49515552b385SBrandon     PetscScalar *vcoords;
49525552b385SBrandon 
49535552b385SBrandon     PetscCall(DMLabelGetValue(bodyLabel, v, &bodyID));
49545552b385SBrandon     PetscCall(DMLabelGetValue(faceLabel, v, &faceID));
49555552b385SBrandon     PetscCall(DMLabelGetValue(edgeLabel, v, &edgeID));
49565552b385SBrandon     PetscCall(DMLabelGetValue(vertexLabel, v, &vertexID));
49575552b385SBrandon 
49585552b385SBrandon     // TODO Figure out why this is unknown sometimes
49595552b385SBrandon     if (bodyID < 0 && Nb == 1) bodyID = 0;
49605552b385SBrandon     PetscCheck(bodyID >= 0 && bodyID < Nb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Body %" PetscInt_FMT " for vertex %" PetscInt_FMT " is not in [0, %d)", bodyID, v, Nb);
4961c1cad2e7SMatthew G. Knepley     body = bodies[bodyID];
4962c1cad2e7SMatthew G. Knepley 
49639566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(cdm, v, coords, (void *)&vcoords));
4964c1cad2e7SMatthew G. Knepley     if (edgeID > 0) {
4965c1cad2e7SMatthew G. Knepley       /* Snap to EDGE at nearest location */
4966c1cad2e7SMatthew G. Knepley       double params[1];
49675552b385SBrandon 
49685552b385SBrandon       if (islite) {
49695552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &edge));
49705552b385SBrandon         PetscCall(EGlite_invEvaluate(edge, vcoords, params, result));
49715552b385SBrandon       } // Get (t) of nearest point on EDGE
49725552b385SBrandon       else {
49739566063dSJacob Faibussowitsch         PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &edge));
49745552b385SBrandon         PetscCall(EG_invEvaluate(edge, vcoords, params, result));
49755552b385SBrandon       } // Get (t) of nearest point on EDGE
49765552b385SBrandon 
49775552b385SBrandon       t_point[v - vStart] = params[0];
49785552b385SBrandon       u_point[v - vStart] = 0.0;
49795552b385SBrandon       v_point[v - vStart] = 0.0;
4980c1cad2e7SMatthew G. Knepley     } else if (faceID > 0) {
4981c1cad2e7SMatthew G. Knepley       /* Snap to FACE at nearest location */
4982c1cad2e7SMatthew G. Knepley       double params[2];
49835552b385SBrandon 
49845552b385SBrandon       if (islite) {
49855552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &face));
49865552b385SBrandon         PetscCall(EGlite_invEvaluate(face, vcoords, params, result));
49875552b385SBrandon       } // Get (x,y,z) of nearest point on FACE
49885552b385SBrandon       else {
49899566063dSJacob Faibussowitsch         PetscCall(EG_objectBodyTopo(body, FACE, faceID, &face));
49905552b385SBrandon         PetscCall(EG_invEvaluate(face, vcoords, params, result));
49915552b385SBrandon       } // Get (x,y,z) of nearest point on FACE
49925552b385SBrandon 
49935552b385SBrandon       t_point[v - vStart] = 0.0;
49945552b385SBrandon       u_point[v - vStart] = params[0];
49955552b385SBrandon       v_point[v - vStart] = params[1];
49965552b385SBrandon     } else {
49975552b385SBrandon       t_point[v - vStart] = 0.0;
49985552b385SBrandon       u_point[v - vStart] = 0.0;
49995552b385SBrandon       v_point[v - vStart] = 0.0;
50005552b385SBrandon     }
50015552b385SBrandon   }
50025552b385SBrandon   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
50035552b385SBrandon   /* Clear out global coordinates */
50045552b385SBrandon   PetscCall(VecDestroy(&dm->coordinates[0].x));
50055552b385SBrandon 
50065552b385SBrandon   /* Store in PetscContainters */
50075552b385SBrandon   {
50085552b385SBrandon     PetscContainer t_pointObj, u_pointObj, v_pointObj;
50095552b385SBrandon 
50105552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Edge t Parameter", (PetscObject *)&t_pointObj));
50115552b385SBrandon     if (!t_pointObj) {
50125552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &t_pointObj));
50135552b385SBrandon       PetscCall(PetscContainerSetPointer(t_pointObj, t_point));
50145552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Point - Edge t Parameter", (PetscObject)t_pointObj));
50155552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(t_pointObj, PetscCtxDestroyDefault));
50165552b385SBrandon       PetscCall(PetscContainerDestroy(&t_pointObj));
50175552b385SBrandon     } else {
50185552b385SBrandon       void *old;
50195552b385SBrandon 
50205552b385SBrandon       PetscCall(PetscContainerGetPointer(t_pointObj, &old));
50215552b385SBrandon       PetscCall(PetscFree(old));
50225552b385SBrandon       PetscCall(PetscContainerSetPointer(t_pointObj, t_point));
50235552b385SBrandon     }
50245552b385SBrandon 
50255552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face u Parameter", (PetscObject *)&u_pointObj));
50265552b385SBrandon     if (!u_pointObj) {
50275552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &u_pointObj));
50285552b385SBrandon       PetscCall(PetscContainerSetPointer(u_pointObj, u_point));
50295552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Point - Face u Parameter", (PetscObject)u_pointObj));
50305552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(u_pointObj, PetscCtxDestroyDefault));
50315552b385SBrandon       PetscCall(PetscContainerDestroy(&u_pointObj));
50325552b385SBrandon     } else {
50335552b385SBrandon       void *old;
50345552b385SBrandon 
50355552b385SBrandon       PetscCall(PetscContainerGetPointer(u_pointObj, &old));
50365552b385SBrandon       PetscCall(PetscFree(old));
50375552b385SBrandon       PetscCall(PetscContainerSetPointer(u_pointObj, u_point));
50385552b385SBrandon     }
50395552b385SBrandon 
50405552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face v Parameter", (PetscObject *)&v_pointObj));
50415552b385SBrandon     if (!v_pointObj) {
50425552b385SBrandon       PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &v_pointObj));
50435552b385SBrandon       PetscCall(PetscContainerSetPointer(v_pointObj, v_point));
50445552b385SBrandon       PetscCall(PetscObjectCompose((PetscObject)dm, "Point - Face v Parameter", (PetscObject)v_pointObj));
50455552b385SBrandon       PetscCall(PetscContainerSetCtxDestroy(v_pointObj, PetscCtxDestroyDefault));
50465552b385SBrandon       PetscCall(PetscContainerDestroy(&v_pointObj));
50475552b385SBrandon     } else {
50485552b385SBrandon       void *old;
50495552b385SBrandon 
50505552b385SBrandon       PetscCall(PetscContainerGetPointer(v_pointObj, &old));
50515552b385SBrandon       PetscCall(PetscFree(old));
50525552b385SBrandon       PetscCall(PetscContainerSetPointer(v_pointObj, v_point));
50535552b385SBrandon     }
50545552b385SBrandon   }
50555552b385SBrandon #endif
50565552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
50575552b385SBrandon }
50585552b385SBrandon 
50595552b385SBrandon /*@C
50605552b385SBrandon   DMPlexInflateToGeomModelUseTUV - Inflates the DM to the associated underlying geometry using the [t] {EDGES) and [u, v] (FACES} associated parameters. Requires a DM with an EGADS model attached and a previous call to DMPlexGetGeomModelTUV().
50615552b385SBrandon 
50625552b385SBrandon   Collective
50635552b385SBrandon 
50645552b385SBrandon   Input Parameter:
50655552b385SBrandon . dm - The DM object representing the mesh with PetscContainer containing an EGADS geometry model
50665552b385SBrandon 
50675552b385SBrandon   Level: intermediate
50685552b385SBrandon 
50695552b385SBrandon   Note:
50705552b385SBrandon   The updated DM object inflated to the associated underlying geometry. This updates the [x, y, z] coordinates of DM points associated with geometry.
50715552b385SBrandon 
50725552b385SBrandon .seealso: `DMPLEX`, `DMCreate()`, `DMPlexCreateGeom()`, `DMPlexGeomDataAndGrads()`, `DMPlexGetGeomModelTUV()`
50735552b385SBrandon @*/
5074ce78bad3SBarry Smith PetscErrorCode DMPlexInflateToGeomModelUseTUV(DM dm) PeNS
50755552b385SBrandon {
50765552b385SBrandon #if defined(PETSC_HAVE_EGADS)
50775552b385SBrandon   /* EGADS Variables */
50785552b385SBrandon   ego    model, geom, body, face, edge, vertex;
50795552b385SBrandon   ego   *bodies;
50805552b385SBrandon   int    Nb, oclass, mtype, *senses;
50815552b385SBrandon   double result[18], params[2];
50825552b385SBrandon   /* PETSc Variables */
50835552b385SBrandon   DM             cdm;
50845552b385SBrandon   PetscContainer modelObj;
50855552b385SBrandon   PetscContainer t_pointObj, u_pointObj, v_pointObj;
50865552b385SBrandon   DMLabel        bodyLabel, faceLabel, edgeLabel, vertexLabel;
50875552b385SBrandon   Vec            coordinates;
50885552b385SBrandon   PetscScalar   *coords;
50895552b385SBrandon   PetscScalar   *t_point, *u_point, *v_point;
50905552b385SBrandon   PetscInt       bodyID, faceID, edgeID, vertexID;
50915552b385SBrandon   PetscInt       cdim, d, vStart, vEnd, v;
50925552b385SBrandon   PetscBool      islite = PETSC_FALSE;
50935552b385SBrandon #endif
50945552b385SBrandon 
50955552b385SBrandon   PetscFunctionBegin;
50965552b385SBrandon #if defined(PETSC_HAVE_EGADS)
50975552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
50985552b385SBrandon   if (!modelObj) {
50995552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
51005552b385SBrandon     islite = PETSC_TRUE;
51015552b385SBrandon   }
51025552b385SBrandon 
51035552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Edge t Parameter", (PetscObject *)&t_pointObj));
51045552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face u Parameter", (PetscObject *)&u_pointObj));
51055552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Point - Face v Parameter", (PetscObject *)&v_pointObj));
51065552b385SBrandon 
51075552b385SBrandon   if (!modelObj) PetscFunctionReturn(PETSC_SUCCESS);
51085552b385SBrandon   if (!t_pointObj) PetscFunctionReturn(PETSC_SUCCESS);
51095552b385SBrandon   if (!u_pointObj) PetscFunctionReturn(PETSC_SUCCESS);
51105552b385SBrandon   if (!v_pointObj) PetscFunctionReturn(PETSC_SUCCESS);
51115552b385SBrandon 
51125552b385SBrandon   PetscCall(DMGetCoordinateDim(dm, &cdim));
51135552b385SBrandon   PetscCall(DMGetCoordinateDM(dm, &cdm));
51145552b385SBrandon   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
51155552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
51165552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
51175552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Edge ID", &edgeLabel));
51185552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Vertex ID", &vertexLabel));
51195552b385SBrandon 
51205552b385SBrandon   PetscCall(PetscContainerGetPointer(t_pointObj, (void **)&t_point));
51215552b385SBrandon   PetscCall(PetscContainerGetPointer(u_pointObj, (void **)&u_point));
51225552b385SBrandon   PetscCall(PetscContainerGetPointer(v_pointObj, (void **)&v_point));
51235552b385SBrandon 
51245552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
51255552b385SBrandon 
51265552b385SBrandon   if (islite) {
51275552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
51285552b385SBrandon   } else {
51295552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, &Nb, &bodies, &senses));
51305552b385SBrandon   }
51315552b385SBrandon 
51325552b385SBrandon   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
51335552b385SBrandon   PetscCall(VecGetArrayWrite(coordinates, &coords));
51345552b385SBrandon 
51355552b385SBrandon   for (v = vStart; v < vEnd; ++v) {
51365552b385SBrandon     PetscScalar *vcoords;
51375552b385SBrandon 
51385552b385SBrandon     PetscCall(DMLabelGetValue(bodyLabel, v, &bodyID));
51395552b385SBrandon     PetscCall(DMLabelGetValue(faceLabel, v, &faceID));
51405552b385SBrandon     PetscCall(DMLabelGetValue(edgeLabel, v, &edgeID));
51415552b385SBrandon     PetscCall(DMLabelGetValue(vertexLabel, v, &vertexID));
51425552b385SBrandon 
51435552b385SBrandon     // TODO Figure out why this is unknown sometimes
51445552b385SBrandon     if (bodyID < 0 && Nb == 1) bodyID = 0;
51455552b385SBrandon     PetscCheck(bodyID >= 0 && bodyID < Nb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Body %" PetscInt_FMT " for vertex %" PetscInt_FMT " is not in [0, %d)", bodyID, v, Nb);
51465552b385SBrandon     body = bodies[bodyID];
51475552b385SBrandon 
51485552b385SBrandon     PetscCall(DMPlexPointLocalRef(cdm, v, coords, (void *)&vcoords));
51495552b385SBrandon     if (vertexID > 0) {
51505552b385SBrandon       /* Snap to Vertices */
51515552b385SBrandon       if (islite) {
51525552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, NODE, vertexID, &vertex));
51535552b385SBrandon         PetscCall(EGlite_evaluate(vertex, NULL, result));
51545552b385SBrandon       } else {
51555552b385SBrandon         PetscCall(EG_objectBodyTopo(body, NODE, vertexID, &vertex));
51565552b385SBrandon         PetscCall(EG_evaluate(vertex, NULL, result));
51575552b385SBrandon       }
51585552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
51595552b385SBrandon     } else if (edgeID > 0) {
51605552b385SBrandon       /* Snap to EDGE */
51615552b385SBrandon       params[0] = t_point[v - vStart];
51625552b385SBrandon       if (islite) {
51635552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, EDGE, edgeID, &edge));
51645552b385SBrandon         PetscCall(EGlite_evaluate(edge, params, result));
51655552b385SBrandon       } else {
51665552b385SBrandon         PetscCall(EG_objectBodyTopo(body, EDGE, edgeID, &edge));
51675552b385SBrandon         PetscCall(EG_evaluate(edge, params, result));
51685552b385SBrandon       }
51695552b385SBrandon       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
51705552b385SBrandon     } else if (faceID > 0) {
51715552b385SBrandon       /* Snap to FACE */
51725552b385SBrandon       params[0] = u_point[v - vStart];
51735552b385SBrandon       params[1] = v_point[v - vStart];
51745552b385SBrandon       if (islite) {
51755552b385SBrandon         PetscCall(EGlite_objectBodyTopo(body, FACE, faceID, &face));
51765552b385SBrandon         PetscCall(EGlite_evaluate(face, params, result));
51775552b385SBrandon       } else {
51785552b385SBrandon         PetscCall(EG_objectBodyTopo(body, FACE, faceID, &face));
51795552b385SBrandon         PetscCall(EG_evaluate(face, params, result));
51805552b385SBrandon       }
5181c1cad2e7SMatthew G. Knepley       for (d = 0; d < cdim; ++d) vcoords[d] = result[d];
5182c1cad2e7SMatthew G. Knepley     }
5183c1cad2e7SMatthew G. Knepley   }
51849566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
5185c1cad2e7SMatthew G. Knepley   /* Clear out global coordinates */
51866858538eSMatthew G. Knepley   PetscCall(VecDestroy(&dm->coordinates[0].x));
5187c1cad2e7SMatthew G. Knepley #endif
51883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5189c1cad2e7SMatthew G. Knepley }
5190c1cad2e7SMatthew G. Knepley 
5191cc4c1da9SBarry Smith /*@
51925552b385SBrandon   DMPlexInflateToGeomModel - Wrapper function allowing two methods for inflating refined meshes to the underlying geometric domain.
51937bee2925SMatthew Knepley 
51947bee2925SMatthew Knepley   Collective
51957bee2925SMatthew Knepley 
51967bee2925SMatthew Knepley   Input Parameters:
51975552b385SBrandon + dm     - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
51985552b385SBrandon - useTUV - PetscBool indicating if the user would like to inflate the DMPlex to the underlying geometry
51995552b385SBrandon            using (t) for nodes on EDGEs and (u, v) for nodes on FACEs or using the nodes (x, y, z) coordinates
52005552b385SBrandon            and shortest distance routine.
52015552b385SBrandon             If useTUV = PETSC_TRUE, use the (t) or (u, v) parameters to inflate the DMPlex to the CAD geometry.
52025552b385SBrandon             If useTUV = PETSC_FALSE, use the nodes (x, y, z) coordinates and the shortest disctance routine.
52035552b385SBrandon 
52045552b385SBrandon   Notes:
52055552b385SBrandon   DM with nodal coordinates modified so that they lie on the EDGEs and FACEs of the underlying geometry.
52065552b385SBrandon 
52075552b385SBrandon   (t) and (u, v) parameters for all DMPlex nodes on EDGEs and FACEs are stored in arrays within PetscContainers attached to the DM.
52085552b385SBrandon   The containers have names "Point - Edge t Parameter", "Point - Face u Parameter", and "Point - Face v Parameter".
52095552b385SBrandon   The arrays are organized by Point 0-based ID (i.e. [v-vstart] as defined in the DMPlex.
52105552b385SBrandon 
52115552b385SBrandon   Level: intermediate
52125552b385SBrandon 
52135552b385SBrandon .seealso: `DMPlexGetGeomModelTUV()`, `DMPlexInflateToGeomModelUseTUV()`, `DMPlexInflateToGeomModelUseXYZ()`
52145552b385SBrandon @*/
5215ce78bad3SBarry Smith PetscErrorCode DMPlexInflateToGeomModel(DM dm, PetscBool useTUV) PeNS
52165552b385SBrandon {
52175552b385SBrandon   PetscFunctionBeginHot;
52185552b385SBrandon   if (useTUV) {
52195552b385SBrandon     PetscCall(DMPlexGetGeomModelTUV(dm));
52205552b385SBrandon     PetscCall(DMPlexInflateToGeomModelUseTUV(dm));
52215552b385SBrandon   } else {
52225552b385SBrandon     PetscCall(DMPlexInflateToGeomModelUseXYZ(dm));
52235552b385SBrandon   }
52245552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
52255552b385SBrandon }
52265552b385SBrandon 
52275552b385SBrandon #ifdef PETSC_HAVE_EGADS
52285552b385SBrandon /*@C
5229*bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodies - Returns an array of `PetscGeom` BODY objects attached to the referenced geometric model entity as well as the number of BODYs.
52305552b385SBrandon 
52315552b385SBrandon   Collective
52325552b385SBrandon 
52335552b385SBrandon   Input Parameter:
52345552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
52355552b385SBrandon 
52365552b385SBrandon   Output Parameters:
52375552b385SBrandon + bodies    - Array of PetscGeom BODY objects referenced by the geometric model.
52385552b385SBrandon - numBodies - Number of BODYs referenced by the geometric model. Also the size of **bodies array.
52395552b385SBrandon 
52405552b385SBrandon   Level: intermediate
52415552b385SBrandon 
52425552b385SBrandon .seealso:
52435552b385SBrandon @*/
5244ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodies(DM dm, PetscGeom **bodies, PetscInt *numBodies) PeNS
52455552b385SBrandon {
52465552b385SBrandon   PetscFunctionBeginHot;
52475552b385SBrandon   PetscContainer modelObj;
52485552b385SBrandon   PetscBool      islite = PETSC_FALSE;
52495552b385SBrandon   ego            model, geom;
52505552b385SBrandon   int            oclass, mtype;
52515552b385SBrandon   int           *senses;
52525552b385SBrandon 
52535552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
52545552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
52555552b385SBrandon   if (!modelObj) {
52565552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
52575552b385SBrandon     islite = PETSC_TRUE;
52585552b385SBrandon   }
52595552b385SBrandon 
52605552b385SBrandon   // Get attached EGADS or EGADSlite model (pointer)
52615552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
52625552b385SBrandon 
52635552b385SBrandon   if (islite) {
52645552b385SBrandon     PetscCall(EGlite_getTopology(model, &geom, &oclass, &mtype, NULL, numBodies, bodies, &senses));
52655552b385SBrandon   } else {
52665552b385SBrandon     PetscCall(EG_getTopology(model, &geom, &oclass, &mtype, NULL, numBodies, bodies, &senses));
52675552b385SBrandon   }
52685552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
52695552b385SBrandon }
52705552b385SBrandon 
52715552b385SBrandon /*@C
5272*bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodyShells - Returns an array of `PetscGeom` SHELL objects attached to the referenced BODY geometric entity as well as the number of SHELLs.
52735552b385SBrandon 
52745552b385SBrandon   Collective
52755552b385SBrandon 
52765552b385SBrandon   Input Parameters:
52775552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
52785552b385SBrandon - body - PetscGeom BODY object containing the SHELL objects of interest.
52795552b385SBrandon 
52805552b385SBrandon   Output Parameters:
52815552b385SBrandon + shells    - Array of PetscGeom SHELL objects referenced by the PetscGeom BODY object
52825552b385SBrandon - numShells - Number of SHELLs referenced by the PetscGeom BODY object. Also the size of **shells array.
52835552b385SBrandon 
52845552b385SBrandon   Level: intermediate
52855552b385SBrandon 
52865552b385SBrandon .seealso:
52875552b385SBrandon @*/
5288ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodyShells(DM dm, PetscGeom body, PetscGeom **shells, PetscInt *numShells) PeNS
52895552b385SBrandon {
52905552b385SBrandon   PetscFunctionBeginHot;
52915552b385SBrandon   #ifdef PETSC_HAVE_EGADS
52925552b385SBrandon   PetscContainer modelObj;
52935552b385SBrandon   PetscBool      islite = PETSC_FALSE;
52945552b385SBrandon 
52955552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
52965552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
52975552b385SBrandon   if (!modelObj) {
52985552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
52995552b385SBrandon     islite = PETSC_TRUE;
53005552b385SBrandon   }
53015552b385SBrandon 
53025552b385SBrandon   if (islite) {
53035552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, SHELL, numShells, shells));
53045552b385SBrandon   } else {
53055552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, SHELL, numShells, shells));
53065552b385SBrandon   }
53075552b385SBrandon   #endif
53085552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
53095552b385SBrandon }
53105552b385SBrandon 
53115552b385SBrandon /*@C
5312*bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodyFaces - Returns an array of `PetscGeom` FACE objects attached to the referenced BODY geometric entity as well as the number of FACEs.
53135552b385SBrandon 
53145552b385SBrandon   Collective
53155552b385SBrandon 
53165552b385SBrandon   Input Parameters:
53175552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
53185552b385SBrandon - body - PetscGeom BODY object containing the FACE objects of interest.
53195552b385SBrandon 
53205552b385SBrandon   Output Parameters:
53215552b385SBrandon + faces    - Array of PetscGeom FACE objects referenced by the PetscGeom BODY object
53225552b385SBrandon - numFaces - Number of FACEs referenced by the PetscGeom BODY object. Also the size of **faces array.
53235552b385SBrandon 
53245552b385SBrandon   Level: intermediate
53255552b385SBrandon 
53265552b385SBrandon .seealso:
53275552b385SBrandon @*/
5328ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodyFaces(DM dm, PetscGeom body, PetscGeom **faces, PetscInt *numFaces) PeNS
53295552b385SBrandon {
53305552b385SBrandon   PetscFunctionBeginHot;
53315552b385SBrandon   #ifdef PETSC_HAVE_EGADS
53325552b385SBrandon   PetscContainer modelObj;
53335552b385SBrandon   PetscBool      islite = PETSC_FALSE;
53345552b385SBrandon 
53355552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
53365552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
53375552b385SBrandon   if (!modelObj) {
53385552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
53395552b385SBrandon     islite = PETSC_TRUE;
53405552b385SBrandon   }
53415552b385SBrandon 
53425552b385SBrandon   if (islite) {
53435552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, FACE, numFaces, faces));
53445552b385SBrandon   } else {
53455552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, FACE, numFaces, faces));
53465552b385SBrandon   }
53475552b385SBrandon   #endif
53485552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
53495552b385SBrandon }
53505552b385SBrandon 
53515552b385SBrandon /*@C
5352*bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodyLoops - Returns an array of `PetscGeom` Loop objects attached to the referenced BODY geometric entity as well as the number of LOOPs.
53535552b385SBrandon 
53545552b385SBrandon   Collective
53555552b385SBrandon 
53565552b385SBrandon   Input Parameters:
53575552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
53585552b385SBrandon - body - PetscGeom BODY object containing the LOOP objects of interest.
53595552b385SBrandon 
53605552b385SBrandon   Output Parameters:
53615552b385SBrandon + loops    - Array of PetscGeom FACE objects referenced by the PetscGeom SHELL object
53625552b385SBrandon - numLoops - Number of LOOPs referenced by the PetscGeom BODY object. Also the size of **loops array.
53635552b385SBrandon 
53645552b385SBrandon   Level: intermediate
53655552b385SBrandon 
53665552b385SBrandon .seealso:
53675552b385SBrandon @*/
5368ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodyLoops(DM dm, PetscGeom body, PetscGeom **loops, PetscInt *numLoops) PeNS
53695552b385SBrandon {
53705552b385SBrandon   PetscFunctionBeginHot;
53715552b385SBrandon   #ifdef PETSC_HAVE_EGADS
53725552b385SBrandon   PetscContainer modelObj;
53735552b385SBrandon   PetscBool      islite = PETSC_FALSE;
53745552b385SBrandon 
53755552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
53765552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
53775552b385SBrandon   if (!modelObj) {
53785552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
53795552b385SBrandon     islite = PETSC_TRUE;
53805552b385SBrandon   }
53815552b385SBrandon 
53825552b385SBrandon   if (islite) {
53835552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, LOOP, numLoops, loops));
53845552b385SBrandon   } else {
53855552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, LOOP, numLoops, loops));
53865552b385SBrandon   }
53875552b385SBrandon   #endif
53885552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
53895552b385SBrandon }
53905552b385SBrandon 
53915552b385SBrandon /*@C
5392*bfe80ac4SPierre Jolivet   DMPlexGetGeomModelShellFaces - Returns an array of `PetscGeom` FACE objects attached to the referenced SHELL geometric entity as well as the number of FACEs.
53935552b385SBrandon 
53945552b385SBrandon   Collective
53955552b385SBrandon 
53965552b385SBrandon   Input Parameters:
53975552b385SBrandon + dm    - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
53985552b385SBrandon . body  - PetscGeom BODY object containing the FACE objects of interest.
53995552b385SBrandon - shell - PetscGeom SHELL object with FACEs of interest.
54005552b385SBrandon 
54015552b385SBrandon   Output Parameters:
54025552b385SBrandon + faces    - Array of PetscGeom FACE objects referenced by the PetscGeom SHELL object
54035552b385SBrandon - numFaces - Number of FACEs referenced by the PetscGeom SHELL object. Also the size of **faces array.
54045552b385SBrandon 
54055552b385SBrandon   Level: intermediate
54065552b385SBrandon 
54075552b385SBrandon .seealso:
54085552b385SBrandon @*/
5409ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelShellFaces(DM dm, PetscGeom body, PetscGeom shell, PetscGeom **faces, PetscInt *numFaces) PeNS
54105552b385SBrandon {
54115552b385SBrandon   PetscFunctionBeginHot;
54125552b385SBrandon   #ifdef PETSC_HAVE_EGADS
54135552b385SBrandon   PetscContainer modelObj;
54145552b385SBrandon   PetscBool      islite = PETSC_FALSE;
54155552b385SBrandon 
54165552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
54175552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
54185552b385SBrandon   if (!modelObj) {
54195552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
54205552b385SBrandon     islite = PETSC_TRUE;
54215552b385SBrandon   }
54225552b385SBrandon 
54235552b385SBrandon   if (islite) {
54245552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, shell, FACE, numFaces, faces));
54255552b385SBrandon   } else {
54265552b385SBrandon     PetscCall(EG_getBodyTopos(body, shell, FACE, numFaces, faces));
54275552b385SBrandon   }
54285552b385SBrandon   #endif
54295552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
54305552b385SBrandon }
54315552b385SBrandon 
54325552b385SBrandon /*@C
5433*bfe80ac4SPierre Jolivet   DMPlexGetGeomModelFaceLoops - Returns an array of `PetscGeom` LOOP objects attached to the referenced FACE geometric entity as well as the number of LOOPs.
54345552b385SBrandon 
54355552b385SBrandon   Collective
54365552b385SBrandon 
54375552b385SBrandon   Input Parameters:
54385552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
54395552b385SBrandon . body - PetscGeom BODY object containing the LOOP objects of interest.
54405552b385SBrandon - face - PetscGeom FACE object with LOOPs of interest.
54415552b385SBrandon 
54425552b385SBrandon   Output Parameters:
54435552b385SBrandon + loops    - Array of PetscGeom LOOP objects referenced by the PetscGeom FACE object
54445552b385SBrandon - numLoops - Number of LOOPs referenced by the PetscGeom FACE object. Also the size of **loops array.
54455552b385SBrandon 
54465552b385SBrandon   Level: intermediate
54475552b385SBrandon 
54485552b385SBrandon .seealso:
54495552b385SBrandon @*/
5450ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelFaceLoops(DM dm, PetscGeom body, PetscGeom face, PetscGeom **loops, PetscInt *numLoops) PeNS
54515552b385SBrandon {
54525552b385SBrandon   PetscFunctionBeginHot;
54535552b385SBrandon   #ifdef PETSC_HAVE_EGADS
54545552b385SBrandon   PetscContainer modelObj;
54555552b385SBrandon   PetscBool      islite = PETSC_FALSE;
54565552b385SBrandon 
54575552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
54585552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
54595552b385SBrandon   if (!modelObj) {
54605552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
54615552b385SBrandon     islite = PETSC_TRUE;
54625552b385SBrandon   }
54635552b385SBrandon 
54645552b385SBrandon   if (islite) {
54655552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, face, LOOP, numLoops, loops));
54665552b385SBrandon   } else {
54675552b385SBrandon     PetscCall(EG_getBodyTopos(body, face, LOOP, numLoops, loops));
54685552b385SBrandon   }
54695552b385SBrandon   #endif
54705552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
54715552b385SBrandon }
54725552b385SBrandon 
54735552b385SBrandon /*@C
5474*bfe80ac4SPierre Jolivet   DMPlexGetGeomModelFaceEdges - Returns an array of `PetscGeom` EDGE objects attached to the referenced FACE geometric entity as well as the number of EDGEs.
54755552b385SBrandon 
54765552b385SBrandon   Collective
54775552b385SBrandon 
54785552b385SBrandon   Input Parameters:
54795552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
54805552b385SBrandon . body - PetscGeom Body object containing the EDGE objects of interest.
54815552b385SBrandon - face - PetscGeom FACE object with EDGEs of interest.
54825552b385SBrandon 
54835552b385SBrandon   Output Parameters:
54845552b385SBrandon + edges    - Array of PetscGeom EDGE objects referenced by the PetscGeom FACE object
54855552b385SBrandon - numEdges - Number of EDGEs referenced by the PetscGeom FACE object. Also the size of **edges array.
54865552b385SBrandon 
54875552b385SBrandon   Level: intermediate
54885552b385SBrandon 
54895552b385SBrandon .seealso:
54905552b385SBrandon @*/
5491ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelFaceEdges(DM dm, PetscGeom body, PetscGeom face, PetscGeom **edges, PetscInt *numEdges) PeNS
54925552b385SBrandon {
54935552b385SBrandon   PetscFunctionBeginHot;
54945552b385SBrandon   #ifdef PETSC_HAVE_EGADS
54955552b385SBrandon   PetscContainer modelObj;
54965552b385SBrandon   PetscBool      islite = PETSC_FALSE;
54975552b385SBrandon 
54985552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
54995552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
55005552b385SBrandon   if (!modelObj) {
55015552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
55025552b385SBrandon     islite = PETSC_TRUE;
55035552b385SBrandon   }
55045552b385SBrandon 
55055552b385SBrandon   if (islite) {
55065552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, face, EDGE, numEdges, edges));
55075552b385SBrandon   } else {
55085552b385SBrandon     PetscCall(EG_getBodyTopos(body, face, EDGE, numEdges, edges));
55095552b385SBrandon   }
55105552b385SBrandon   #endif
55115552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
55125552b385SBrandon }
55135552b385SBrandon 
55145552b385SBrandon /*@C
5515*bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodyEdges - Returns an array of `PetscGeom` EDGE objects attached to the referenced BODY geometric entity as well as the number of EDGEs.
55165552b385SBrandon 
55175552b385SBrandon   Collective
55185552b385SBrandon 
55195552b385SBrandon   Input Parameters:
55205552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
55215552b385SBrandon - body - PetscGeom body object of interest.
55225552b385SBrandon 
55235552b385SBrandon   Output Parameters:
55245552b385SBrandon + edges    - Array of PetscGeom EDGE objects referenced by the PetscGeom BODY object
55255552b385SBrandon - numEdges - Number of EDGEs referenced by the PetscGeom BODY object. Also the size of **edges array.
55265552b385SBrandon 
55275552b385SBrandon   Level: intermediate
55285552b385SBrandon 
55295552b385SBrandon .seealso:
55305552b385SBrandon @*/
5531ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodyEdges(DM dm, PetscGeom body, PetscGeom **edges, PetscInt *numEdges) PeNS
55325552b385SBrandon {
55335552b385SBrandon   PetscFunctionBeginHot;
55345552b385SBrandon   #ifdef PETSC_HAVE_EGADS
55355552b385SBrandon   PetscContainer modelObj;
55365552b385SBrandon   PetscBool      islite = PETSC_FALSE;
55375552b385SBrandon 
55385552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
55395552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
55405552b385SBrandon   if (!modelObj) {
55415552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
55425552b385SBrandon     islite = PETSC_TRUE;
55435552b385SBrandon   }
55445552b385SBrandon 
55455552b385SBrandon   if (islite) {
55465552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, EDGE, numEdges, edges));
55475552b385SBrandon   } else {
55485552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, EDGE, numEdges, edges));
55495552b385SBrandon   }
55505552b385SBrandon   #endif
55515552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
55525552b385SBrandon }
55535552b385SBrandon 
55545552b385SBrandon /*@C
5555*bfe80ac4SPierre Jolivet   DMPlexGetGeomModelBodyNodes - Returns an array of `PetscGeom` NODE objects attached to the referenced BODY geometric entity as well as the number of NODES.
55565552b385SBrandon 
55575552b385SBrandon   Collective
55585552b385SBrandon 
55595552b385SBrandon   Input Parameters:
55605552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
55615552b385SBrandon - body - PetscGeom body object of interest.
55625552b385SBrandon 
55635552b385SBrandon   Output Parameters:
55645552b385SBrandon + nodes    - Array of PetscGeom NODE objects referenced by the PetscGeom BODY object
55655552b385SBrandon - numNodes - Number of NODEs referenced by the PetscGeom BODY object. Also the size of **nodes array.
55665552b385SBrandon 
55675552b385SBrandon   Level: intermediate
55685552b385SBrandon 
55695552b385SBrandon .seealso:
55705552b385SBrandon @*/
5571ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelBodyNodes(DM dm, PetscGeom body, PetscGeom **nodes, PetscInt *numNodes) PeNS
55725552b385SBrandon {
55735552b385SBrandon   PetscFunctionBeginHot;
55745552b385SBrandon   #ifdef PETSC_HAVE_EGADS
55755552b385SBrandon   PetscContainer modelObj;
55765552b385SBrandon   PetscBool      islite = PETSC_FALSE;
55775552b385SBrandon 
55785552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
55795552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
55805552b385SBrandon   if (!modelObj) {
55815552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
55825552b385SBrandon     islite = PETSC_TRUE;
55835552b385SBrandon   }
55845552b385SBrandon 
55855552b385SBrandon   if (islite) {
55865552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, NULL, NODE, numNodes, nodes));
55875552b385SBrandon   } else {
55885552b385SBrandon     PetscCall(EG_getBodyTopos(body, NULL, NODE, numNodes, nodes));
55895552b385SBrandon   }
55905552b385SBrandon   #endif
55915552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
55925552b385SBrandon }
55935552b385SBrandon 
55945552b385SBrandon /*@C
5595*bfe80ac4SPierre Jolivet   DMPlexGetGeomModelEdgeNodes - Returns an array of `PetscGeom` NODE objects attached to the referenced EDGE geometric entity as well as the number of NODES.
55965552b385SBrandon 
55975552b385SBrandon   Collective
55985552b385SBrandon 
55995552b385SBrandon   Input Parameters:
56005552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
56015552b385SBrandon . body - PetscGeom body object containing the EDGE object of interest.
56025552b385SBrandon - edge - PetscGeom EDGE object with NODEs of interest.
56035552b385SBrandon 
56045552b385SBrandon   Output Parameters:
56055552b385SBrandon + nodes    - Array of PetscGeom NODE objects referenced by the PetscGeom EDGE object
56065552b385SBrandon - numNodes - Number of Nodes referenced by the PetscGeom EDGE object. Also the size of **nodes array.
56075552b385SBrandon 
56085552b385SBrandon   Level: intermediate
56095552b385SBrandon 
56105552b385SBrandon .seealso:
56115552b385SBrandon @*/
5612ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomModelEdgeNodes(DM dm, PetscGeom body, PetscGeom edge, PetscGeom **nodes, PetscInt *numNodes) PeNS
56135552b385SBrandon {
56145552b385SBrandon   PetscFunctionBeginHot;
56155552b385SBrandon   #ifdef PETSC_HAVE_EGADS
56165552b385SBrandon   PetscContainer modelObj;
56175552b385SBrandon   PetscBool      islite = PETSC_FALSE;
56185552b385SBrandon 
56195552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
56205552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
56215552b385SBrandon   if (!modelObj) {
56225552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
56235552b385SBrandon     islite = PETSC_TRUE;
56245552b385SBrandon   }
56255552b385SBrandon 
56265552b385SBrandon   if (islite) {
56275552b385SBrandon     PetscCall(EGlite_getBodyTopos(body, edge, NODE, numNodes, nodes));
56285552b385SBrandon   } else {
56295552b385SBrandon     PetscCall(EG_getBodyTopos(body, edge, NODE, numNodes, nodes));
56305552b385SBrandon   }
56315552b385SBrandon   #endif
56325552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
56335552b385SBrandon }
56345552b385SBrandon 
56355552b385SBrandon /*@C
56365552b385SBrandon   DMPlexGetGeomID - Returns ID number of the entity in the geometric (CAD) model
56375552b385SBrandon 
56385552b385SBrandon   Collective
56395552b385SBrandon 
56405552b385SBrandon   Input Parameters:
56415552b385SBrandon + dm      - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
56425552b385SBrandon . body    - PetscGeom body object containing the lower level entity the ID number is being requested.
56435552b385SBrandon - topoObj - PetscGeom SHELL, FACE, LOOP, EDGE, or NODE object for which ID number is being requested.
56447bee2925SMatthew Knepley 
56457bee2925SMatthew Knepley   Output Parameter:
56465552b385SBrandon . id - ID number of the entity
56477bee2925SMatthew Knepley 
56485552b385SBrandon   Level: intermediate
56497bee2925SMatthew Knepley 
56505552b385SBrandon .seealso:
56517bee2925SMatthew Knepley @*/
5652ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomID(DM dm, PetscGeom body, PetscGeom topoObj, PetscInt *id) PeNS
5653d71ae5a4SJacob Faibussowitsch {
56545552b385SBrandon   PetscFunctionBeginHot;
56555552b385SBrandon   #ifdef PETSC_HAVE_EGADS
56565552b385SBrandon   PetscContainer modelObj;
56575552b385SBrandon   PetscBool      islite = PETSC_FALSE;
56585552b385SBrandon   int            topoID;
56595552b385SBrandon 
56605552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
56615552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
56625552b385SBrandon   if (!modelObj) {
56635552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
56645552b385SBrandon     islite = PETSC_TRUE;
56655552b385SBrandon   }
56665552b385SBrandon 
56675552b385SBrandon   // Get Topology Object's ID
56685552b385SBrandon   if (islite) {
56695552b385SBrandon     topoID = EGlite_indexBodyTopo(body, topoObj);
56705552b385SBrandon   } else {
56715552b385SBrandon     topoID = EG_indexBodyTopo(body, topoObj);
56725552b385SBrandon   }
56735552b385SBrandon 
56745552b385SBrandon   *id = topoID;
56757bee2925SMatthew Knepley   #endif
56765552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
56775552b385SBrandon }
56785552b385SBrandon 
56795552b385SBrandon /*@C
56805552b385SBrandon   DMPlexGetGeomObject - Returns Geometry Object using the objects ID in the geometric (CAD) model
56815552b385SBrandon 
56825552b385SBrandon   Collective
56835552b385SBrandon 
56845552b385SBrandon   Input Parameters:
56855552b385SBrandon + dm       - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
56865552b385SBrandon . body     - PetscGeom body object containing the lower level entity the referenced by the ID.
56875552b385SBrandon . geomType - Keyword SHELL, FACE, LOOP, EDGE, or NODE of the geometry type for which ID number is being requested.
56885552b385SBrandon - geomID   - ID number of the geometry entity being requested.
56895552b385SBrandon 
56905552b385SBrandon   Output Parameter:
56915552b385SBrandon . geomObj - Geometry Object referenced by the ID number requested.
56925552b385SBrandon 
56935552b385SBrandon   Level: intermediate
56945552b385SBrandon 
56955552b385SBrandon .seealso:
56965552b385SBrandon @*/
5697ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomObject(DM dm, PetscGeom body, PetscInt geomType, PetscInt geomID, PetscGeom *geomObj) PeNS
56985552b385SBrandon {
56995552b385SBrandon   PetscFunctionBeginHot;
57005552b385SBrandon   #ifdef PETSC_HAVE_EGADS
57015552b385SBrandon   PetscContainer modelObj;
57025552b385SBrandon   PetscBool      islite = PETSC_FALSE;
57035552b385SBrandon 
57045552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
57055552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
57065552b385SBrandon   if (!modelObj) {
57075552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
57085552b385SBrandon     islite = PETSC_TRUE;
57095552b385SBrandon   }
57105552b385SBrandon 
57115552b385SBrandon   // Get Topology Object's ID
57125552b385SBrandon   if (islite) {
57135552b385SBrandon     PetscCall(EGlite_objectBodyTopo(body, geomType, geomID, geomObj));
57145552b385SBrandon   } else {
57155552b385SBrandon     PetscCall(EG_objectBodyTopo(body, geomType, geomID, geomObj));
57165552b385SBrandon   }
57175552b385SBrandon   #endif
57185552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
57195552b385SBrandon }
57205552b385SBrandon 
57215552b385SBrandon /*@C
57225552b385SBrandon   DMPlexGetGeomFaceNumOfControlPoints - Returns the total number of Control Points (and associated Weights) defining a FACE of a Geometry
57235552b385SBrandon 
57245552b385SBrandon   Not collective
57255552b385SBrandon 
57265552b385SBrandon   Input Parameters:
57275552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
57285552b385SBrandon - face - PetscGeom FACE object
57295552b385SBrandon 
57305552b385SBrandon   Output Parameter:
57315552b385SBrandon . numCntrlPnts - Number of Control Points (and Weights) defining the FACE
57325552b385SBrandon 
57335552b385SBrandon   Level: intermediate
57345552b385SBrandon 
57355552b385SBrandon .seealso:
57365552b385SBrandon @*/
5737ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomFaceNumOfControlPoints(DM dm, PetscGeom face, PetscInt *numCntrlPnts) PeNS
57385552b385SBrandon {
57395552b385SBrandon   PetscFunctionBeginHot;
57405552b385SBrandon   #ifdef PETSC_HAVE_EGADS
57415552b385SBrandon   PetscContainer modelObj;
57425552b385SBrandon   PetscBool      islite = PETSC_FALSE;
57435552b385SBrandon   PetscGeom      geom, gRef;
57445552b385SBrandon   PetscGeom     *lobjs;
57455552b385SBrandon   int            Nl, oclass, mtype, goclass, gmtype;
57465552b385SBrandon   int           *lsenses, *gpinfo;
57475552b385SBrandon   double        *gprv;
57485552b385SBrandon 
57495552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
57505552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
57515552b385SBrandon   if (!modelObj) {
57525552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
57535552b385SBrandon     islite = PETSC_TRUE;
57545552b385SBrandon   }
57555552b385SBrandon 
57565552b385SBrandon   // Get Total Number of Control Points on FACE
57575552b385SBrandon   if (islite) {
57585552b385SBrandon     PetscCall(EGlite_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
57595552b385SBrandon     PetscCall(EGlite_getGeometry(geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));
57605552b385SBrandon   } else {
57615552b385SBrandon     PetscCall(EG_getTopology(face, &geom, &oclass, &mtype, NULL, &Nl, &lobjs, &lsenses));
57625552b385SBrandon     PetscCall(EG_getGeometry(geom, &goclass, &gmtype, &gRef, &gpinfo, &gprv));
57635552b385SBrandon   }
57645552b385SBrandon 
57655552b385SBrandon   *numCntrlPnts = gpinfo[2] * gpinfo[5];
57665552b385SBrandon   #endif
57675552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
57685552b385SBrandon }
57695552b385SBrandon 
57705552b385SBrandon /*@C
57715552b385SBrandon   DMPlexGetGeomBodyMassProperties - Returns the Volume, Surface Area, Center of Gravity, and Inertia about the Body's Center of Gravity
57725552b385SBrandon 
57735552b385SBrandon   Not collective
57745552b385SBrandon 
57755552b385SBrandon   Input Parameters:
57765552b385SBrandon + dm   - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
57775552b385SBrandon - body - PetscGeom BODY object
57785552b385SBrandon 
57795552b385SBrandon   Output Parameters:
57805552b385SBrandon + volume           - Volume of the CAD Body attached to the DM Plex
57815552b385SBrandon . surfArea         - Surface Area of the CAD Body attached to the DM Plex
57825552b385SBrandon . centerOfGravity  - Array with the Center of Gravity coordinates of the CAD Body attached to the DM Plex [x, y, z]
57835552b385SBrandon . COGszie          - Size of centerOfGravity[] Array
57845552b385SBrandon . inertiaMatrixCOG - Array containing the Inertia about the Body's Center of Gravity [Ixx, Ixy, Ixz, Iyx, Iyy, Iyz, Izx, Izy, Izz]
57855552b385SBrandon - IMCOGsize        - Size of inertiaMatrixCOG[] Array
57865552b385SBrandon 
57875552b385SBrandon   Level: intermediate
57885552b385SBrandon 
57895552b385SBrandon .seealso:
57905552b385SBrandon @*/
5791ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomBodyMassProperties(DM dm, PetscGeom body, PetscScalar *volume, PetscScalar *surfArea, PetscScalar **centerOfGravity, PetscInt *COGsize, PetscScalar **inertiaMatrixCOG, PetscInt *IMCOGsize) PeNS
57925552b385SBrandon {
57935552b385SBrandon   PetscFunctionBeginHot;
57945552b385SBrandon   #ifdef PETSC_HAVE_EGADS
57955552b385SBrandon   PetscContainer modelObj;
57965552b385SBrandon   PetscBool      islite = PETSC_FALSE;
57975552b385SBrandon   PetscScalar    geomData[14];
57985552b385SBrandon 
57995552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
58005552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
58015552b385SBrandon   if (!modelObj) {
58025552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
58035552b385SBrandon     islite = PETSC_TRUE;
58045552b385SBrandon     PetscCheck(modelObj, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot provide geometric mass properties for geometries defined by EGADSlite (.egadslite)! Please use another geometry file format STEP, IGES, EGADS or BRep");
58055552b385SBrandon   }
58065552b385SBrandon 
58075552b385SBrandon   if (islite) {
58085552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, " WARNING!! This functionality is not supported for EGADSlite files. \n"));
58095552b385SBrandon     PetscCall(PetscPrintf(PETSC_COMM_SELF, " All returned values are equal to 0 \n"));
58105552b385SBrandon   } else {
58115552b385SBrandon     PetscCall(EG_getMassProperties(body, geomData));
58125552b385SBrandon   }
58135552b385SBrandon 
58145552b385SBrandon   PetscCall(PetscMalloc2(3, centerOfGravity, 9, inertiaMatrixCOG));
58155552b385SBrandon 
58165552b385SBrandon   if (!islite) {
58175552b385SBrandon     *volume   = geomData[0];
58185552b385SBrandon     *surfArea = geomData[1];
58195552b385SBrandon     for (int ii = 2; ii < 5; ++ii) { (*centerOfGravity)[ii - 2] = geomData[ii]; }
58205552b385SBrandon     *COGsize = 3;
58215552b385SBrandon     for (int ii = 5; ii < 14; ++ii) { (*inertiaMatrixCOG)[ii - 5] = geomData[ii]; }
58225552b385SBrandon     *IMCOGsize = 9;
58235552b385SBrandon   } else {
58245552b385SBrandon     *volume   = 0.;
58255552b385SBrandon     *surfArea = 0.;
58265552b385SBrandon     for (int ii = 2; ii < 5; ++ii) { (*centerOfGravity)[ii - 2] = 0.; }
58275552b385SBrandon     *COGsize = 0;
58285552b385SBrandon     for (int ii = 5; ii < 14; ++ii) { (*inertiaMatrixCOG)[ii - 5] = 0.; }
58295552b385SBrandon     *IMCOGsize = 0;
58305552b385SBrandon   }
58315552b385SBrandon   #endif
58325552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
58335552b385SBrandon }
58345552b385SBrandon 
5835ce78bad3SBarry Smith PetscErrorCode DMPlexRestoreGeomBodyMassProperties(DM dm, PetscGeom body, PetscScalar *volume, PetscScalar *surfArea, PetscScalar **centerOfGravity, PetscInt *COGsize, PetscScalar **inertiaMatrixCOG, PetscInt *IMCOGsize) PeNS
58365552b385SBrandon {
58375552b385SBrandon   PetscFunctionBegin;
58385552b385SBrandon   PetscCall(PetscFree2(*centerOfGravity, *inertiaMatrixCOG));
58395552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
58405552b385SBrandon }
58415552b385SBrandon 
58425552b385SBrandon /*@C
58435552b385SBrandon   DMPlexFreeGeomObject - Frees PetscGeom Objects
58445552b385SBrandon 
58455552b385SBrandon   Not collective
58465552b385SBrandon 
58475552b385SBrandon   Input Parameters:
58485552b385SBrandon + dm      - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
58495552b385SBrandon - geomObj - PetscGeom object
58505552b385SBrandon 
58515552b385SBrandon   Level: intermediate
58525552b385SBrandon 
58535552b385SBrandon .seealso:
58545552b385SBrandon @*/
5855ce78bad3SBarry Smith PetscErrorCode DMPlexFreeGeomObject(DM dm, PetscGeom *geomObj) PeNS
58565552b385SBrandon {
58575552b385SBrandon   PetscFunctionBeginHot;
58585552b385SBrandon   #ifdef PETSC_HAVE_EGADS
58595552b385SBrandon   PetscContainer modelObj;
58605552b385SBrandon   PetscBool      islite = PETSC_FALSE;
58615552b385SBrandon 
58625552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
58635552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
58645552b385SBrandon   if (!modelObj) {
58655552b385SBrandon     PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
58665552b385SBrandon     islite = PETSC_TRUE;
58675552b385SBrandon   }
58685552b385SBrandon 
58695552b385SBrandon   if (islite) {
58705552b385SBrandon     EGlite_free(geomObj);
58715552b385SBrandon   } else {
58725552b385SBrandon     EG_free(geomObj);
58735552b385SBrandon   }
58745552b385SBrandon   #endif
58755552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
58765552b385SBrandon }
58775552b385SBrandon 
58785552b385SBrandon /*@C
58795552b385SBrandon   DMPlexGetGeomCntrlPntAndWeightData - Gets Control Point and Associated Weight Data for the Geometry attached to the DMPlex
58805552b385SBrandon 
58815552b385SBrandon   Not collective
58825552b385SBrandon 
58835552b385SBrandon   Input Parameter:
58845552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
58855552b385SBrandon 
58865552b385SBrandon   Output Parameters:
58875552b385SBrandon + cpHashTable       - Hash Table containing the relationship between FACE ID and Control Point IDs.
58885552b385SBrandon . cpCoordDataLength - Length of cpCoordData Array.
58895552b385SBrandon . cpCoordData       - Array holding the Geometry Control Point Coordinate Data.
58905552b385SBrandon . maxNumEquiv       - Maximum Number of Equivalent Control Points (Control Points with the same coordinates but different IDs).
58915552b385SBrandon . cpEquiv           - Matrix with a size(Number of Control Points, Number or Control Points) which stores a value of 1.0 in locations where Control Points with different IDS (row or column) have the same coordinates
58925552b385SBrandon . wHashTable        - Hash Table containing the relationship between FACE ID and Control Point Weight.
58935552b385SBrandon . wDataLength       - Length of wData Array.
58945552b385SBrandon - wData             - Array holding the Weight for an associated Geometry Control Point.
58955552b385SBrandon 
58965552b385SBrandon   Note:
58975552b385SBrandon   Must Call DMPLexGeomDataAndGrads() before calling this function.
58985552b385SBrandon 
58995552b385SBrandon   Level: intermediate
59005552b385SBrandon 
59015552b385SBrandon .seealso:
59025552b385SBrandon @*/
5903ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeomCntrlPntAndWeightData(DM dm, PetscHMapI *cpHashTable, PetscInt *cpCoordDataLength, PetscScalar **cpCoordData, PetscInt *maxNumEquiv, Mat *cpEquiv, PetscHMapI *wHashTable, PetscInt *wDataLength, PetscScalar **wData) PeNS
59045552b385SBrandon {
59055552b385SBrandon   PetscContainer modelObj, cpHashTableObj, wHashTableObj, cpCoordDataLengthObj, wDataLengthObj, maxNumRelateObj;
59065552b385SBrandon   Vec            cntrlPtCoordsVec, cntrlPtWeightsVec;
59075552b385SBrandon   PetscInt      *cpCoordDataLengthPtr, *wDataLengthPtr, *maxNumEquivPtr;
59085552b385SBrandon   PetscHMapI     cpHashTableTemp, wHashTableTemp;
59095552b385SBrandon 
59105552b385SBrandon   PetscFunctionBeginHot;
59115552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
59125552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
59135552b385SBrandon   if (!modelObj) { PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj)); }
59145552b385SBrandon 
59155552b385SBrandon   if (!modelObj) { PetscFunctionReturn(PETSC_SUCCESS); }
59165552b385SBrandon 
59175552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
59185552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Hash Table", (PetscObject *)&cpHashTableObj));
59195552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinates", (PetscObject *)&cntrlPtCoordsVec));
59205552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject *)&cpCoordDataLengthObj));
59215552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject *)&wHashTableObj));
59225552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data", (PetscObject *)&cntrlPtWeightsVec));
59235552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&wDataLengthObj));
5924*bfe80ac4SPierre Jolivet   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Equivalency Matrix", (PetscObject *)cpEquiv));
59255552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Maximum Number Control Point Equivalency", (PetscObject *)&maxNumRelateObj));
59265552b385SBrandon 
59275552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
59285552b385SBrandon   PetscCall(PetscContainerGetPointer(cpHashTableObj, (void **)&cpHashTableTemp));
59295552b385SBrandon   PetscCall(PetscContainerGetPointer(cpCoordDataLengthObj, (void **)&cpCoordDataLengthPtr));
59305552b385SBrandon   PetscCall(PetscContainerGetPointer(wHashTableObj, (void **)&wHashTableTemp));
59315552b385SBrandon   PetscCall(PetscContainerGetPointer(wDataLengthObj, (void **)&wDataLengthPtr));
59325552b385SBrandon   PetscCall(PetscContainerGetPointer(maxNumRelateObj, (void **)&maxNumEquivPtr));
59335552b385SBrandon 
59345552b385SBrandon   *cpCoordDataLength = *cpCoordDataLengthPtr;
59355552b385SBrandon   *wDataLength       = *wDataLengthPtr;
59365552b385SBrandon   *maxNumEquiv       = *maxNumEquivPtr;
59375552b385SBrandon   *cpHashTable       = cpHashTableTemp;
59385552b385SBrandon   *wHashTable        = wHashTableTemp;
59395552b385SBrandon   PetscCall(VecGetArrayWrite(cntrlPtCoordsVec, cpCoordData));
59405552b385SBrandon   PetscCall(VecGetArrayWrite(cntrlPtWeightsVec, wData));
59415552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
59425552b385SBrandon }
59435552b385SBrandon 
59445552b385SBrandon PetscErrorCode DMPlexRestoreGeomCntrlPntAndWeightData(DM dm, PetscHMapI *cpHashTable, PetscInt *cpCoordDataLength, PetscScalar **cpCoordData, PetscInt *maxNumEquiv, Mat *cpEquiv, PetscHMapI *wHashTable, PetscInt *wDataLength, PetscScalar **wData)
59455552b385SBrandon {
59465552b385SBrandon   Vec cntrlPtCoordsVec, cntrlPtWeightsVec;
59475552b385SBrandon 
59485552b385SBrandon   PetscFunctionBeginHot;
59495552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinates", (PetscObject *)&cntrlPtCoordsVec));
59505552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtCoordsVec, cpCoordData));
59515552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data", (PetscObject *)&cntrlPtWeightsVec));
59525552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtWeightsVec, wData));
59535552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
59545552b385SBrandon }
59555552b385SBrandon 
59565552b385SBrandon /*@C
59575552b385SBrandon   DMPlexGetGeomGradData - Gets Point, Surface and Volume Gradients with respect to changes in Control Points and their associated Weights for the Geometry attached to the DMPlex .
59585552b385SBrandon 
59595552b385SBrandon   Not collective
59605552b385SBrandon 
59615552b385SBrandon   Input Parameter:
59625552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
59635552b385SBrandon 
59645552b385SBrandon   Output Parameters:
59655552b385SBrandon + cpSurfGradHashTable - Hash Table Relating the Control Point ID to the the Row in the cpSurfGrad Matrix
59665552b385SBrandon . cpSurfGrad          - Matrix containing the Surface Gradient with respect to the Control Point Data. Data is ranged where the Row corresponds to Control Point ID and the Columns are associated with the Geometric FACE.
59675552b385SBrandon . cpArraySize         - The size of arrays gradSACP and gradVolCP and is equal to 3 * total number of Control Points in the Geometry
59685552b385SBrandon . gradSACP            - Array containing the Surface Area Gradient with respect to Control Point Data. Data is arranged by Control Point ID * 3 where 3 is for the coordinate dimension.
5969*bfe80ac4SPierre Jolivet . gradVolCP           - Array containing the Volume Gradient with respect to Control Point Data. Data is arranged by Control Point ID * 3 where 3 is for the coordinate dimension.
59705552b385SBrandon . wArraySize          - The size of arrayws gradSAW and gradVolW and is equal to the total number of Control Points in the Geometry.
59715552b385SBrandon . gradSAW             - Array containing the Surface Area Gradient with respect to Control Point Weight. Data is arranged by Control Point ID.
59725552b385SBrandon - gradVolW            - Array containing the Volume Gradient with respect to Control Point Weight. Data is arranged by Control Point ID.
59735552b385SBrandon 
59745552b385SBrandon   Notes:
59755552b385SBrandon   Must Call DMPLexGeomDataAndGrads() before calling this function.
59765552b385SBrandon 
59775552b385SBrandon   gradVolCP and gradVolW are only available when DMPlexGeomDataAndGrads() is called with fullGeomGrad = PETSC_TRUE.
59785552b385SBrandon 
59795552b385SBrandon   Level: intermediate
59805552b385SBrandon 
59815552b385SBrandon .seealso: DMPlexGeomDataAndGrads
59825552b385SBrandon @*/
59835552b385SBrandon PetscErrorCode DMPlexGetGeomGradData(DM dm, PetscHMapI *cpSurfGradHashTable, Mat *cpSurfGrad, PetscInt *cpArraySize, PetscScalar **gradSACP, PetscScalar **gradVolCP, PetscInt *wArraySize, PetscScalar **gradSAW, PetscScalar **gradVolW)
59845552b385SBrandon {
59855552b385SBrandon   PetscContainer modelObj, cpSurfGradHashTableObj, cpArraySizeObj, wArraySizeObj;
59865552b385SBrandon   Vec            gradSACPVec, gradVolCPVec, gradSAWVec, gradVolWVec;
59875552b385SBrandon   PetscInt      *cpArraySizePtr, *wArraySizePtr;
59885552b385SBrandon   PetscHMapI     cpSurfGradHashTableTemp;
59895552b385SBrandon 
59905552b385SBrandon   PetscFunctionBeginHot;
59915552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
59925552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
59935552b385SBrandon   if (!modelObj) { PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj)); }
59945552b385SBrandon 
59955552b385SBrandon   if (!modelObj) { PetscFunctionReturn(PETSC_SUCCESS); }
59965552b385SBrandon 
59975552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
59985552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Gradient Hash Table", (PetscObject *)&cpSurfGradHashTableObj));
59995552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Gradient Matrix", (PetscObject *)cpSurfGrad));
60005552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject *)&cpArraySizeObj));
60015552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Control Point Gradient", (PetscObject *)&gradSACPVec));
60025552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Control Point Gradient", (PetscObject *)&gradVolCPVec));
60035552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&wArraySizeObj));
60045552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Weights Gradient", (PetscObject *)&gradSAWVec));
60055552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Weights Gradient", (PetscObject *)&gradVolWVec));
60065552b385SBrandon 
60075552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
60085552b385SBrandon   if (cpSurfGradHashTableObj) {
60095552b385SBrandon     PetscCall(PetscContainerGetPointer(cpSurfGradHashTableObj, (void **)&cpSurfGradHashTableTemp));
60105552b385SBrandon     *cpSurfGradHashTable = cpSurfGradHashTableTemp;
60115552b385SBrandon   }
60125552b385SBrandon 
60135552b385SBrandon   if (cpArraySizeObj) {
60145552b385SBrandon     PetscCall(PetscContainerGetPointer(cpArraySizeObj, (void **)&cpArraySizePtr));
60155552b385SBrandon     *cpArraySize = *cpArraySizePtr;
60165552b385SBrandon   }
60175552b385SBrandon 
60185552b385SBrandon   if (gradSACPVec) PetscCall(VecGetArrayWrite(gradSACPVec, gradSACP));
60195552b385SBrandon   if (gradVolCPVec) PetscCall(VecGetArrayWrite(gradVolCPVec, gradVolCP));
60205552b385SBrandon   if (gradSAWVec) PetscCall(VecGetArrayWrite(gradSAWVec, gradSAW));
60215552b385SBrandon   if (gradVolWVec) PetscCall(VecGetArrayWrite(gradVolWVec, gradVolW));
60225552b385SBrandon 
60235552b385SBrandon   if (wArraySizeObj) {
60245552b385SBrandon     PetscCall(PetscContainerGetPointer(wArraySizeObj, (void **)&wArraySizePtr));
60255552b385SBrandon     *wArraySize = *wArraySizePtr;
60265552b385SBrandon   }
60275552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
60285552b385SBrandon }
60295552b385SBrandon 
60305552b385SBrandon PetscErrorCode DMPlexRestoreGeomGradData(DM dm, PetscHMapI *cpSurfGradHashTable, Mat *cpSurfGrad, PetscInt *cpArraySize, PetscScalar **gradSACP, PetscScalar **gradVolCP, PetscInt *wArraySize, PetscScalar **gradSAW, PetscScalar **gradVolW)
60315552b385SBrandon {
60325552b385SBrandon   Vec gradSACPVec, gradVolCPVec, gradSAWVec, gradVolWVec;
60337bee2925SMatthew Knepley 
60347bee2925SMatthew Knepley   PetscFunctionBegin;
60355552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Control Point Gradient", (PetscObject *)&gradSACPVec));
60365552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Control Point Gradient", (PetscObject *)&gradVolCPVec));
60375552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Surface Area Weights Gradient", (PetscObject *)&gradSAWVec));
60385552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Volume Weights Gradient", (PetscObject *)&gradVolWVec));
60395552b385SBrandon 
60405552b385SBrandon   if (gradSACPVec) PetscCall(VecRestoreArrayWrite(gradSACPVec, gradSACP));
60415552b385SBrandon   if (gradVolCPVec) PetscCall(VecRestoreArrayWrite(gradVolCPVec, gradVolCP));
60425552b385SBrandon   if (gradSAWVec) PetscCall(VecRestoreArrayWrite(gradSAWVec, gradSAW));
60435552b385SBrandon   if (gradVolWVec) PetscCall(VecRestoreArrayWrite(gradVolWVec, gradVolW));
60443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60457bee2925SMatthew Knepley }
60465552b385SBrandon 
60475552b385SBrandon /*@C
60485552b385SBrandon   DMPlexGetGeomCntrlPntMaps - Gets arrays which maps Control Point IDs to their associated Geometry FACE, EDGE, and VERTEX.
60495552b385SBrandon 
60505552b385SBrandon   Not collective
60515552b385SBrandon 
60525552b385SBrandon   Input Parameter:
60535552b385SBrandon . dm - The DMPlex object with an attached PetscContainer storing a CAD Geometry object
60545552b385SBrandon 
60555552b385SBrandon   Output Parameters:
60565552b385SBrandon + numCntrlPnts            - Number of Control Points defining the Geometry attached to the DMPlex
60575552b385SBrandon . cntrlPntFaceMap         - Array containing the FACE ID for the Control Point. Array index corresponds to Control Point ID.
60585552b385SBrandon . cntrlPntWeightFaceMap   - Array containing the FACE ID for the Control Point Weight. Array index corresponds to Control Point ID.
60595552b385SBrandon . cntrlPntEdgeMap         - Array containing the EDGE ID for the Control Point. Array index corresponds to Control Point ID.
60605552b385SBrandon . cntrlPntWeightEdgeMap   - Array containing the EDGE ID for the Control Point Weight. Array index corresponds to Control Point ID.
60615552b385SBrandon . cntrlPntVertexMap       - Array containing the VERTEX ID for the Control Point. Array index corresponds to Control Point ID.
60625552b385SBrandon - cntrlPntWeightVertexMap - Array containing the VERTEX ID for the Control Point Weight. Array index corresponds to Control Point ID.
60635552b385SBrandon 
60645552b385SBrandon   Note:
60655552b385SBrandon   Arrays are initialized to -1. Array elements with a -1 value indicates that the Control Point or Control Point Weight not associated with the referenced Geometric entity in the array name.
60665552b385SBrandon 
60675552b385SBrandon   Level: intermediate
60685552b385SBrandon 
60695552b385SBrandon .seealso: DMPlexGeomDataAndGrads
60705552b385SBrandon @*/
60715552b385SBrandon PetscErrorCode DMPlexGetGeomCntrlPntMaps(DM dm, PetscInt *numCntrlPnts, PetscInt **cntrlPntFaceMap, PetscInt **cntrlPntWeightFaceMap, PetscInt **cntrlPntEdgeMap, PetscInt **cntrlPntWeightEdgeMap, PetscInt **cntrlPntVertexMap, PetscInt **cntrlPntWeightVertexMap)
60725552b385SBrandon {
60735552b385SBrandon   PetscFunctionBeginHot;
60745552b385SBrandon   #ifdef PETSC_HAVE_EGADS
60755552b385SBrandon   PetscContainer modelObj, numCntrlPntsObj, cntrlPntFaceMapObj, cntrlPntWeightFaceMapObj, cntrlPntEdgeMapObj, cntrlPntWeightEdgeMapObj, cntrlPntVertexMapObj, cntrlPntWeightVertexMapObj;
60765552b385SBrandon   PetscInt      *numCntrlPntsPtr, *cntrlPntFaceMapPtr, *cntrlPntWeightFaceMapPtr, *cntrlPntEdgeMapPtr, *cntrlPntWeightEdgeMapPtr, *cntrlPntVertexMapPtr, *cntrlPntWeightVertexMapPtr;
60775552b385SBrandon 
60785552b385SBrandon   /* Determine which type of EGADS model is attached to the DM */
60795552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
60805552b385SBrandon   if (!modelObj) { PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj)); }
60815552b385SBrandon 
60825552b385SBrandon   if (!modelObj) { PetscFunctionReturn(PETSC_SUCCESS); }
60835552b385SBrandon 
60845552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
60855552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&numCntrlPntsObj));
60865552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Face Map", (PetscObject *)&cntrlPntFaceMapObj));
60875552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Face Map", (PetscObject *)&cntrlPntWeightFaceMapObj));
60885552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Edge Map", (PetscObject *)&cntrlPntEdgeMapObj));
60895552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Edge Map", (PetscObject *)&cntrlPntWeightEdgeMapObj));
60905552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point - Vertex Map", (PetscObject *)&cntrlPntVertexMapObj));
60915552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight - Vertex Map", (PetscObject *)&cntrlPntWeightVertexMapObj));
60925552b385SBrandon 
60935552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
60945552b385SBrandon   if (numCntrlPntsObj) {
60955552b385SBrandon     PetscCall(PetscContainerGetPointer(numCntrlPntsObj, (void **)&numCntrlPntsPtr));
60965552b385SBrandon     *numCntrlPnts = *numCntrlPntsPtr;
60975552b385SBrandon   }
60985552b385SBrandon 
60995552b385SBrandon   if (cntrlPntFaceMapObj) {
61005552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntFaceMapObj, (void **)&cntrlPntFaceMapPtr));
61015552b385SBrandon     *cntrlPntFaceMap = cntrlPntFaceMapPtr;
61025552b385SBrandon   }
61035552b385SBrandon 
61045552b385SBrandon   if (cntrlPntWeightFaceMapObj) {
61055552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntWeightFaceMapObj, (void **)&cntrlPntWeightFaceMapPtr));
61065552b385SBrandon     *cntrlPntWeightFaceMap = cntrlPntWeightFaceMapPtr;
61075552b385SBrandon   }
61085552b385SBrandon 
61095552b385SBrandon   if (cntrlPntEdgeMapObj) {
61105552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntEdgeMapObj, (void **)&cntrlPntEdgeMapPtr));
61115552b385SBrandon     *cntrlPntEdgeMap = cntrlPntEdgeMapPtr;
61125552b385SBrandon   }
61135552b385SBrandon 
61145552b385SBrandon   if (cntrlPntWeightEdgeMapObj) {
61155552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntWeightEdgeMapObj, (void **)&cntrlPntWeightEdgeMapPtr));
61165552b385SBrandon     *cntrlPntWeightEdgeMap = cntrlPntWeightEdgeMapPtr;
61175552b385SBrandon   }
61185552b385SBrandon 
61195552b385SBrandon   if (cntrlPntVertexMapObj) {
61205552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntVertexMapObj, (void **)&cntrlPntVertexMapPtr));
61215552b385SBrandon     *cntrlPntVertexMap = cntrlPntVertexMapPtr;
61225552b385SBrandon   }
61235552b385SBrandon 
61245552b385SBrandon   if (cntrlPntWeightVertexMapObj) {
61255552b385SBrandon     PetscCall(PetscContainerGetPointer(cntrlPntWeightVertexMapObj, (void **)&cntrlPntWeightVertexMapPtr));
61265552b385SBrandon     *cntrlPntWeightVertexMap = cntrlPntWeightVertexMapPtr;
61275552b385SBrandon   }
61285552b385SBrandon 
61295552b385SBrandon   #endif
61305552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
61315552b385SBrandon }
61325552b385SBrandon 
61335552b385SBrandon #endif
6134